Skip to content

Instantly share code, notes, and snippets.

@Alexintosh
Last active March 17, 2023 18:48

Revisions

  1. Alexintosh revised this gist Mar 17, 2023. 1 changed file with 44 additions and 0 deletions.
    44 changes: 44 additions & 0 deletions AtomicGuard.sol
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,7 @@
    pragma solidity 0.8.13;

    import "hardhat/console.sol";

    contract AtomicityGuard {

    // address => block => status
    @@ -20,6 +22,48 @@ contract AtomicityGuard {
    }
    }

    contract BufferGuard is AtomicityGuard {

    // address => block => status
    uint256 private blockBuffer;
    uint256 private constant _ENTERED = 1;

    mapping(address => uint256) lastSeen;

    constructor(uint256 _buff) {
    blockBuffer = _buff;
    }

    modifier buffered() {
    console.log(lastSeen[msg.sender]);
    console.log(block.number);
    _buffered();
    _;
    }

    function _buffered() private nonAtomic {
    // On the first call to nonReentrant, _status will be _NOT_ENTERED
    if(lastSeen[msg.sender] > 0) {
    require(block.number > lastSeen[msg.sender] + blockBuffer, "BufferGuard: not buffered");
    }

    lastSeen[msg.sender] = block.number;
    }
    }

    contract ImplementorBuffered is BufferGuard {

    constructor() BufferGuard(10) {}

    function deposit() external buffered {

    }

    function withdraw() external buffered {

    }
    }

    contract Implementor is AtomicityGuard {

    function deposit() external nonAtomic {
  2. Alexintosh created this gist Mar 17, 2023.
    66 changes: 66 additions & 0 deletions AtomicGuard.sol
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,66 @@
    pragma solidity 0.8.13;

    contract AtomicityGuard {

    // address => block => status
    uint256 private constant _ENTERED = 1;

    mapping(address => mapping( uint256 => uint256)) ledger;

    modifier nonAtomic() {
    _nonAtomicBefore();
    _;
    }

    function _nonAtomicBefore() private {
    // On the first call to nonReentrant, _status will be _NOT_ENTERED
    require(ledger[msg.sender][block.number] != _ENTERED, "AtomicityGuard: same block");

    ledger[msg.sender][block.number] = _ENTERED;
    }
    }

    contract Implementor is AtomicityGuard {

    function deposit() external nonAtomic {

    }

    function withdraw() external nonAtomic {

    }
    }

    interface IImplementor {
    function deposit() external;
    function withdraw() external;
    }

    contract Exploiter {
    IImplementor c;

    constructor (address _i) {
    c = IImplementor(_i);
    }

    function atomic() external {
    c.deposit();
    c.withdraw();
    }

    function nonatomicDeposit() external {
    c.deposit();
    }

    function nonatomicWithdraw() external {
    c.withdraw();
    }
    }

    contract Exploiter2 {
    constructor (address _i) {
    IImplementor(_i).deposit();
    IImplementor(_i).withdraw();
    selfdestruct(payable(msg.sender));
    }
    }