ETH Price: $2,447.80 (+0.72%)

Transaction Decoder

Block:
14266780 at Feb-24-2022 05:02:25 AM +UTC
Transaction Fee:
0.005040110672077626 ETH $12.34
Gas Used:
37,286 Gas / 135.174346191 Gwei

Emitted Events:

69 DharmaGasReserve.Call( target=0x67e1b186e6da49917922c040fd07be1827978ce7, amount=10343297491553321561, data=0x, ok=True, returnData=0x )

Account State Difference:

  Address   Before After State Difference Code
0x55F20393...Fed386dBf 10.343297491553321561 Eth0 Eth10.343297491553321561
0x67e1b186...827978CE7 26.741831454404852682 Eth37.085128945958174243 Eth10.343297491553321561
0x7e4A8391...6628B19Fa
(Dharma: Deployer)
0.651443771156257049 Eth
Nonce: 1464
0.646403660484179423 Eth
Nonce: 1465
0.005040110672077626
(Ethermine)
1,948.875499954828416175 Eth1,948.875581984028416175 Eth0.0000820292

Execution Trace

DharmaGasReserve.callAny( target=0x67e1b186e6dA49917922C040FD07bE1827978CE7, amount=10343297491553321561, data=0x ) => ( ok=True, returnData=0x )
  • ETH 10.343297491553321561 0x67e1b186e6da49917922c040fd07be1827978ce7.CALL( )
    pragma solidity 0.5.17;
    
    
    interface DharmaGasReserveInterface {
        // events
        event EtherReceived(address sender, uint256 amount);
        event Pulled(address indexed gasAccount, uint256 amount);
        event AddedGasAccount(address gasAccount);
        event RemovedGasAccount(address gasAccount);
        event NewPullAmount(uint256 pullAmount);
        event NewRateLimit(uint256 interval);
        event Call(address target, uint256 amount, bytes data, bool ok, bytes returnData);
    
        // only callable by designated "gas accounts"
        function pullGas() external;
    
        // only callable by owner
        function addGasAccount(address gasAccount) external;
        function removeGasAccount(address gasAccount) external;
        function setPullAmount(uint256 amount) external;
        function setRateLimit(uint256 interval) external;
        function callAny(
            address payable target, uint256 amount, bytes calldata data
        ) external returns (bool ok, bytes memory returnData);
    
        // view functions
        function getGasAccounts() external view returns (address[] memory);
        function getPullAmount() external view returns (uint256);
        function getRateLimit() external view returns (uint256);
        function getLastPullTime(address gasAccount) external view returns (uint256);
    }
    
    
    contract TwoStepOwnable {
      address private _owner;
    
      address private _newPotentialOwner;
    
      event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
      );
    
      /**
       * @dev Initialize contract by setting transaction submitter as initial owner.
       */
      constructor() internal {
        _owner = tx.origin;
        emit OwnershipTransferred(address(0), _owner);
      }
    
      /**
       * @dev Returns the address of the current owner.
       */
      function owner() public view returns (address) {
        return _owner;
      }
    
      /**
       * @dev Throws if called by any account other than the owner.
       */
      modifier onlyOwner() {
        require(isOwner(), "TwoStepOwnable: caller is not the owner.");
        _;
      }
    
      /**
       * @dev Returns true if the caller is the current owner.
       */
      function isOwner() public view returns (bool) {
        return msg.sender == _owner;
      }
    
      /**
       * @dev Allows a new account (`newOwner`) to accept ownership.
       * Can only be called by the current owner.
       */
      function transferOwnership(address newOwner) public onlyOwner {
        require(
          newOwner != address(0),
          "TwoStepOwnable: new potential owner is the zero address."
        );
    
        _newPotentialOwner = newOwner;
      }
    
      /**
       * @dev Cancel a transfer of ownership to a new account.
       * Can only be called by the current owner.
       */
      function cancelOwnershipTransfer() public onlyOwner {
        delete _newPotentialOwner;
      }
    
      /**
       * @dev Transfers ownership of the contract to the caller.
       * Can only be called by a new potential owner set by the current owner.
       */
      function acceptOwnership() public {
        require(
          msg.sender == _newPotentialOwner,
          "TwoStepOwnable: current owner must set caller as new potential owner."
        );
    
        delete _newPotentialOwner;
    
        emit OwnershipTransferred(_owner, msg.sender);
    
        _owner = msg.sender;
      }
    }
    
    
    contract DharmaGasReserve is DharmaGasReserveInterface, TwoStepOwnable {
        // Track all authorized gas accounts.
        address[] private _gasAccounts;
    
        // Indexes start at 1, as 0 signifies non-inclusion
        mapping (address => uint256) private _gasAccountIndexes;
        
        mapping (address => uint256) private _lastPullTime;
        
        uint256 private _pullAmount;
        uint256 private _rateLimit;
    
        constructor(address[] memory initialGasAccounts) public {
            _setPullAmount(3 ether);
            _setRateLimit(1 hours);
            for (uint256 i; i < initialGasAccounts.length; i++) {
                address gasAccount = initialGasAccounts[i];
                _addGasAccount(gasAccount);
            }
        }
    
        function () external payable {
            if (msg.value > 0) {
                emit EtherReceived(msg.sender, msg.value);
            }
        }
    
        function pullGas() external {
            require(
                _gasAccountIndexes[msg.sender] != 0,
                "Only authorized gas accounts may pull from this contract."
            );
            
            require(
                msg.sender.balance < _pullAmount,
                "Gas account balance is not yet below the pull amount."
            );
    
            require(
                now > _lastPullTime[msg.sender] + _rateLimit,
                "Gas account is currently rate-limited."
            );
            _lastPullTime[msg.sender] = now;
    
            uint256 pullAmount = _pullAmount;
            
            require(
                address(this).balance >= pullAmount,
                "Insufficient funds held by the reserve."
            );
            
            (bool ok, ) = msg.sender.call.value(pullAmount)("");
            if (!ok) {
                assembly {
                    returndatacopy(0, 0, returndatasize)
                    revert(0, returndatasize)
                }
            }
    
            emit Pulled(msg.sender, pullAmount);
        }
    
        function addGasAccount(address gasAccount) external onlyOwner {
            _addGasAccount(gasAccount);
        }
    
        function removeGasAccount(address gasAccount) external onlyOwner {
            _removeGasAccount(gasAccount);
        }
    
        function setPullAmount(uint256 amount) external onlyOwner {
            _setPullAmount(amount);
        }
    
        function setRateLimit(uint256 interval) external onlyOwner {
            _setRateLimit(interval);
        }
    
        function callAny(
            address payable target, uint256 amount, bytes calldata data
        ) external onlyOwner returns (bool ok, bytes memory returnData) {
            // Call the specified target and supply the specified data.
            (ok, returnData) = target.call.value(amount)(data);
    
            emit Call(target, amount, data, ok, returnData);
        }
    
        function getGasAccounts() external view returns (address[] memory) {
            return _gasAccounts;
        }
    
        function getPullAmount() external view returns (uint256) {
            return  _pullAmount;
        }
    
        function getRateLimit() external view returns (uint256) {
            return _rateLimit;
        }
    
        function getLastPullTime(address gasAccount) external view returns (uint256) {
            return _lastPullTime[gasAccount];
        }
    
        function _addGasAccount(address gasAccount) internal {
            require(
                _gasAccountIndexes[gasAccount] == 0,
                "Gas account matching the provided account already exists."
            );
            _gasAccounts.push(gasAccount);
            _gasAccountIndexes[gasAccount] = _gasAccounts.length;
    
            emit AddedGasAccount(gasAccount);
        }
        
        function _removeGasAccount(address gasAccount) internal {
            uint256 removedGasAccountIndex = _gasAccountIndexes[gasAccount];
            require(
                removedGasAccountIndex != 0,
                "No gas account found matching the provided account."
            );
    
            // swap account to remove with the last one then pop from the array.
            address lastGasAccount = _gasAccounts[_gasAccounts.length - 1];
            _gasAccounts[removedGasAccountIndex - 1] = lastGasAccount;
            _gasAccountIndexes[lastGasAccount] = removedGasAccountIndex;
            _gasAccounts.pop();
            delete _gasAccountIndexes[gasAccount];
    
            emit RemovedGasAccount(gasAccount); 
        }
        
        function _setPullAmount(uint256 amount) internal {
            _pullAmount = amount;
    
            emit NewPullAmount(amount);
        }
        
        function _setRateLimit(uint256 interval) internal {
            _rateLimit = interval;
    
            emit NewRateLimit(interval);
        }
    }