ETH Price: $3,385.94 (+0.86%)

Contract

0xa329263fFac25F86E03481Ec39307bbf5DbeDD83
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Advanced mode:
Parent Transaction Hash Block
From
To
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
GUniWithdraw

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2021-11-15
*/

// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;

pragma experimental ABIEncoderV2;





abstract contract IDFSRegistry {
 
    function getAddr(bytes32 _id) public view virtual returns (address);

    function addNewContract(
        bytes32 _id,
        address _contractAddr,
        uint256 _waitPeriod
    ) public virtual;

    function startContractChange(bytes32 _id, address _newContractAddr) public virtual;

    function approveContractChange(bytes32 _id) public virtual;

    function cancelContractChange(bytes32 _id) public virtual;

    function changeWaitPeriod(bytes32 _id, uint256 _newWaitPeriod) public virtual;
}





interface IERC20 {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint256 digits);
    function totalSupply() external view returns (uint256 supply);

    function balanceOf(address _owner) external view returns (uint256 balance);

    function transfer(address _to, uint256 _value) external returns (bool success);

    function transferFrom(
        address _from,
        address _to,
        uint256 _value
    ) external returns (bool success);

    function approve(address _spender, uint256 _value) external returns (bool success);

    function allowance(address _owner, address _spender) external view returns (uint256 remaining);

    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}





library Address {
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            codehash := extcodehash(account)
        }
        return (codehash != accountHash && codehash != 0x0);
    }

    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return _functionCallWithValue(target, data, 0, errorMessage);
    }

    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return
            functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        return _functionCallWithValue(target, data, value, errorMessage);
    }

    function _functionCallWithValue(
        address target,
        bytes memory data,
        uint256 weiValue,
        string memory errorMessage
    ) private returns (bytes memory) {
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{value: weiValue}(data);
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}





library SafeMath {
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}







library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(
            token,
            abi.encodeWithSelector(token.transferFrom.selector, from, to, value)
        );
    }

    /// @dev Edited so it always first approves 0 and then the value, because of non standard tokens
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        _callOptionalReturn(
            token,
            abi.encodeWithSelector(token.approve.selector, spender, newAllowance)
        );
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(
            value,
            "SafeERC20: decreased allowance below zero"
        );
        _callOptionalReturn(
            token,
            abi.encodeWithSelector(token.approve.selector, spender, newAllowance)
        );
    }

    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        bytes memory returndata = address(token).functionCall(
            data,
            "SafeERC20: low-level call failed"
        );
        if (returndata.length > 0) {
            // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}





contract MainnetAuthAddresses {
    address internal constant ADMIN_VAULT_ADDR = 0xCCf3d848e08b94478Ed8f46fFead3008faF581fD;
    address internal constant FACTORY_ADDRESS = 0x5a15566417e6C1c9546523066500bDDBc53F88C7;
    address internal constant ADMIN_ADDR = 0x25eFA336886C74eA8E282ac466BdCd0199f85BB9; // USED IN ADMIN VAULT CONSTRUCTOR
}





contract AuthHelper is MainnetAuthAddresses {
}





contract AdminVault is AuthHelper {
    address public owner;
    address public admin;

    constructor() {
        owner = msg.sender;
        admin = ADMIN_ADDR;
    }

    /// @notice Admin is able to change owner
    /// @param _owner Address of new owner
    function changeOwner(address _owner) public {
        require(admin == msg.sender, "msg.sender not admin");
        owner = _owner;
    }

    /// @notice Admin is able to set new admin
    /// @param _admin Address of multisig that becomes new admin
    function changeAdmin(address _admin) public {
        require(admin == msg.sender, "msg.sender not admin");
        admin = _admin;
    }

}








contract AdminAuth is AuthHelper {
    using SafeERC20 for IERC20;

    AdminVault public constant adminVault = AdminVault(ADMIN_VAULT_ADDR);

    modifier onlyOwner() {
        require(adminVault.owner() == msg.sender, "msg.sender not owner");
        _;
    }

    modifier onlyAdmin() {
        require(adminVault.admin() == msg.sender, "msg.sender not admin");
        _;
    }

    /// @notice withdraw stuck funds
    function withdrawStuckFunds(address _token, address _receiver, uint256 _amount) public onlyOwner {
        if (_token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) {
            payable(_receiver).transfer(_amount);
        } else {
            IERC20(_token).safeTransfer(_receiver, _amount);
        }
    }

    /// @notice Destroy the contract
    function kill() public onlyAdmin {
        selfdestruct(payable(msg.sender));
    }
}





contract DefisaverLogger {
    event LogEvent(
        address indexed contractAddress,
        address indexed caller,
        string indexed logName,
        bytes data
    );

    // solhint-disable-next-line func-name-mixedcase
    function Log(
        address _contract,
        address _caller,
        string memory _logName,
        bytes memory _data
    ) public {
        emit LogEvent(_contract, _caller, _logName, _data);
    }
}





contract MainnetCoreAddresses {
    address internal constant DEFI_SAVER_LOGGER_ADDR = 0x5c55B921f590a89C1Ebe84dF170E655a82b62126;
    address internal constant REGISTRY_ADDR = 0xD6049E1F5F3EfF1F921f5532aF1A1632bA23929C;
    address internal constant PROXY_AUTH_ADDR = 0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF;
}





contract CoreHelper is MainnetCoreAddresses {
}







contract DFSRegistry is AdminAuth, CoreHelper {
    DefisaverLogger public constant logger = DefisaverLogger(
        DEFI_SAVER_LOGGER_ADDR
    );

    string public constant ERR_ENTRY_ALREADY_EXISTS = "Entry id already exists";
    string public constant ERR_ENTRY_NON_EXISTENT = "Entry id doesn't exists";
    string public constant ERR_ENTRY_NOT_IN_CHANGE = "Entry not in change process";
    string public constant ERR_WAIT_PERIOD_SHORTER = "New wait period must be bigger";
    string public constant ERR_CHANGE_NOT_READY = "Change not ready yet";
    string public constant ERR_EMPTY_PREV_ADDR = "Previous addr is 0";
    string public constant ERR_ALREADY_IN_CONTRACT_CHANGE = "Already in contract change";
    string public constant ERR_ALREADY_IN_WAIT_PERIOD_CHANGE = "Already in wait period change";

    struct Entry {
        address contractAddr;
        uint256 waitPeriod;
        uint256 changeStartTime;
        bool inContractChange;
        bool inWaitPeriodChange;
        bool exists;
    }

    mapping(bytes32 => Entry) public entries;
    mapping(bytes32 => address) public previousAddresses;

    mapping(bytes32 => address) public pendingAddresses;
    mapping(bytes32 => uint256) public pendingWaitTimes;

    /// @notice Given an contract id returns the registered address
    /// @dev Id is keccak256 of the contract name
    /// @param _id Id of contract
    function getAddr(bytes32 _id) public view returns (address) {
        return entries[_id].contractAddr;
    }

    /// @notice Helper function to easily query if id is registered
    /// @param _id Id of contract
    function isRegistered(bytes32 _id) public view returns (bool) {
        return entries[_id].exists;
    }

    /////////////////////////// OWNER ONLY FUNCTIONS ///////////////////////////

    /// @notice Adds a new contract to the registry
    /// @param _id Id of contract
    /// @param _contractAddr Address of the contract
    /// @param _waitPeriod Amount of time to wait before a contract address can be changed
    function addNewContract(
        bytes32 _id,
        address _contractAddr,
        uint256 _waitPeriod
    ) public onlyOwner {
        require(!entries[_id].exists, ERR_ENTRY_ALREADY_EXISTS);

        entries[_id] = Entry({
            contractAddr: _contractAddr,
            waitPeriod: _waitPeriod,
            changeStartTime: 0,
            inContractChange: false,
            inWaitPeriodChange: false,
            exists: true
        });

        // Remember tha address so we can revert back to old addr if needed
        previousAddresses[_id] = _contractAddr;

        logger.Log(
            address(this),
            msg.sender,
            "AddNewContract",
            abi.encode(_id, _contractAddr, _waitPeriod)
        );
    }

    /// @notice Reverts to the previous address immediately
    /// @dev In case the new version has a fault, a quick way to fallback to the old contract
    /// @param _id Id of contract
    function revertToPreviousAddress(bytes32 _id) public onlyOwner {
        require(entries[_id].exists, ERR_ENTRY_NON_EXISTENT);
        require(previousAddresses[_id] != address(0), ERR_EMPTY_PREV_ADDR);

        address currentAddr = entries[_id].contractAddr;
        entries[_id].contractAddr = previousAddresses[_id];

        logger.Log(
            address(this),
            msg.sender,
            "RevertToPreviousAddress",
            abi.encode(_id, currentAddr, previousAddresses[_id])
        );
    }

    /// @notice Starts an address change for an existing entry
    /// @dev Can override a change that is currently in progress
    /// @param _id Id of contract
    /// @param _newContractAddr Address of the new contract
    function startContractChange(bytes32 _id, address _newContractAddr) public onlyOwner {
        require(entries[_id].exists, ERR_ENTRY_NON_EXISTENT);
        require(!entries[_id].inWaitPeriodChange, ERR_ALREADY_IN_WAIT_PERIOD_CHANGE);

        entries[_id].changeStartTime = block.timestamp; // solhint-disable-line
        entries[_id].inContractChange = true;

        pendingAddresses[_id] = _newContractAddr;

        logger.Log(
            address(this),
            msg.sender,
            "StartContractChange",
            abi.encode(_id, entries[_id].contractAddr, _newContractAddr)
        );
    }

    /// @notice Changes new contract address, correct time must have passed
    /// @param _id Id of contract
    function approveContractChange(bytes32 _id) public onlyOwner {
        require(entries[_id].exists, ERR_ENTRY_NON_EXISTENT);
        require(entries[_id].inContractChange, ERR_ENTRY_NOT_IN_CHANGE);
        require(
            block.timestamp >= (entries[_id].changeStartTime + entries[_id].waitPeriod), // solhint-disable-line
            ERR_CHANGE_NOT_READY
        );

        address oldContractAddr = entries[_id].contractAddr;
        entries[_id].contractAddr = pendingAddresses[_id];
        entries[_id].inContractChange = false;
        entries[_id].changeStartTime = 0;

        pendingAddresses[_id] = address(0);
        previousAddresses[_id] = oldContractAddr;

        logger.Log(
            address(this),
            msg.sender,
            "ApproveContractChange",
            abi.encode(_id, oldContractAddr, entries[_id].contractAddr)
        );
    }

    /// @notice Cancel pending change
    /// @param _id Id of contract
    function cancelContractChange(bytes32 _id) public onlyOwner {
        require(entries[_id].exists, ERR_ENTRY_NON_EXISTENT);
        require(entries[_id].inContractChange, ERR_ENTRY_NOT_IN_CHANGE);

        address oldContractAddr = pendingAddresses[_id];

        pendingAddresses[_id] = address(0);
        entries[_id].inContractChange = false;
        entries[_id].changeStartTime = 0;

        logger.Log(
            address(this),
            msg.sender,
            "CancelContractChange",
            abi.encode(_id, oldContractAddr, entries[_id].contractAddr)
        );
    }

    /// @notice Starts the change for waitPeriod
    /// @param _id Id of contract
    /// @param _newWaitPeriod New wait time
    function startWaitPeriodChange(bytes32 _id, uint256 _newWaitPeriod) public onlyOwner {
        require(entries[_id].exists, ERR_ENTRY_NON_EXISTENT);
        require(!entries[_id].inContractChange, ERR_ALREADY_IN_CONTRACT_CHANGE);

        pendingWaitTimes[_id] = _newWaitPeriod;

        entries[_id].changeStartTime = block.timestamp; // solhint-disable-line
        entries[_id].inWaitPeriodChange = true;

        logger.Log(
            address(this),
            msg.sender,
            "StartWaitPeriodChange",
            abi.encode(_id, _newWaitPeriod)
        );
    }

    /// @notice Changes new wait period, correct time must have passed
    /// @param _id Id of contract
    function approveWaitPeriodChange(bytes32 _id) public onlyOwner {
        require(entries[_id].exists, ERR_ENTRY_NON_EXISTENT);
        require(entries[_id].inWaitPeriodChange, ERR_ENTRY_NOT_IN_CHANGE);
        require(
            block.timestamp >= (entries[_id].changeStartTime + entries[_id].waitPeriod), // solhint-disable-line
            ERR_CHANGE_NOT_READY
        );

        uint256 oldWaitTime = entries[_id].waitPeriod;
        entries[_id].waitPeriod = pendingWaitTimes[_id];
        
        entries[_id].inWaitPeriodChange = false;
        entries[_id].changeStartTime = 0;

        pendingWaitTimes[_id] = 0;

        logger.Log(
            address(this),
            msg.sender,
            "ApproveWaitPeriodChange",
            abi.encode(_id, oldWaitTime, entries[_id].waitPeriod)
        );
    }

    /// @notice Cancel wait period change
    /// @param _id Id of contract
    function cancelWaitPeriodChange(bytes32 _id) public onlyOwner {
        require(entries[_id].exists, ERR_ENTRY_NON_EXISTENT);
        require(entries[_id].inWaitPeriodChange, ERR_ENTRY_NOT_IN_CHANGE);

        uint256 oldWaitPeriod = pendingWaitTimes[_id];

        pendingWaitTimes[_id] = 0;
        entries[_id].inWaitPeriodChange = false;
        entries[_id].changeStartTime = 0;

        logger.Log(
            address(this),
            msg.sender,
            "CancelWaitPeriodChange",
            abi.encode(_id, oldWaitPeriod, entries[_id].waitPeriod)
        );
    }
}





contract MainnetActionsUtilAddresses {
    address internal constant DFS_REG_CONTROLLER_ADDR = 0xF8f8B3C98Cf2E63Df3041b73f80F362a4cf3A576;
    address internal constant REGISTRY_ADDR = 0xD6049E1F5F3EfF1F921f5532aF1A1632bA23929C;
    address internal constant DFS_LOGGER_ADDR = 0x5c55B921f590a89C1Ebe84dF170E655a82b62126;
}





contract ActionsUtilHelper is MainnetActionsUtilAddresses {
}







abstract contract ActionBase is AdminAuth, ActionsUtilHelper {
    DFSRegistry public constant registry = DFSRegistry(REGISTRY_ADDR);

    DefisaverLogger public constant logger = DefisaverLogger(
        DFS_LOGGER_ADDR
    );

    string public constant ERR_SUB_INDEX_VALUE = "Wrong sub index value";
    string public constant ERR_RETURN_INDEX_VALUE = "Wrong return index value";

    /// @dev Subscription params index range [128, 255]
    uint8 public constant SUB_MIN_INDEX_VALUE = 128;
    uint8 public constant SUB_MAX_INDEX_VALUE = 255;

    /// @dev Return params index range [1, 127]
    uint8 public constant RETURN_MIN_INDEX_VALUE = 1;
    uint8 public constant RETURN_MAX_INDEX_VALUE = 127;

    /// @dev If the input value should not be replaced
    uint8 public constant NO_PARAM_MAPPING = 0;

    /// @dev We need to parse Flash loan actions in a different way
    enum ActionType { FL_ACTION, STANDARD_ACTION, CUSTOM_ACTION }

    /// @notice Parses inputs and runs the implemented action through a proxy
    /// @dev Is called by the TaskExecutor chaining actions together
    /// @param _callData Array of input values each value encoded as bytes
    /// @param _subData Array of subscribed vales, replaces input values if specified
    /// @param _paramMapping Array that specifies how return and subscribed values are mapped in input
    /// @param _returnValues Returns values from actions before, which can be injected in inputs
    /// @return Returns a bytes32 value through DSProxy, each actions implements what that value is
    function executeAction(
        bytes[] memory _callData,
        bytes[] memory _subData,
        uint8[] memory _paramMapping,
        bytes32[] memory _returnValues
    ) public payable virtual returns (bytes32);

    /// @notice Parses inputs and runs the single implemented action through a proxy
    /// @dev Used to save gas when executing a single action directly
    function executeActionDirect(bytes[] memory _callData) public virtual payable;

    /// @notice Returns the type of action we are implementing
    function actionType() public pure virtual returns (uint8);


    //////////////////////////// HELPER METHODS ////////////////////////////

    /// @notice Given an uint256 input, injects return/sub values if specified
    /// @param _param The original input value
    /// @param _mapType Indicated the type of the input in paramMapping
    /// @param _subData Array of subscription data we can replace the input value with
    /// @param _returnValues Array of subscription data we can replace the input value with
    function _parseParamUint(
        uint _param,
        uint8 _mapType,
        bytes[] memory _subData,
        bytes32[] memory _returnValues
    ) internal pure returns (uint) {
        if (isReplaceable(_mapType)) {
            if (isReturnInjection(_mapType)) {
                _param = uint(_returnValues[getReturnIndex(_mapType)]);
            } else {
                _param = abi.decode(_subData[getSubIndex(_mapType)], (uint));
            }
        }

        return _param;
    }


    /// @notice Given an addr input, injects return/sub values if specified
    /// @param _param The original input value
    /// @param _mapType Indicated the type of the input in paramMapping
    /// @param _subData Array of subscription data we can replace the input value with
    /// @param _returnValues Array of subscription data we can replace the input value with
    function _parseParamAddr(
        address _param,
        uint8 _mapType,
        bytes[] memory _subData,
        bytes32[] memory _returnValues
    ) internal pure returns (address) {
        if (isReplaceable(_mapType)) {
            if (isReturnInjection(_mapType)) {
                _param = address(bytes20((_returnValues[getReturnIndex(_mapType)])));
            } else {
                _param = abi.decode(_subData[getSubIndex(_mapType)], (address));
            }
        }

        return _param;
    }

    /// @notice Given an bytes32 input, injects return/sub values if specified
    /// @param _param The original input value
    /// @param _mapType Indicated the type of the input in paramMapping
    /// @param _subData Array of subscription data we can replace the input value with
    /// @param _returnValues Array of subscription data we can replace the input value with
    function _parseParamABytes32(
        bytes32 _param,
        uint8 _mapType,
        bytes[] memory _subData,
        bytes32[] memory _returnValues
    ) internal pure returns (bytes32) {
        if (isReplaceable(_mapType)) {
            if (isReturnInjection(_mapType)) {
                _param = (_returnValues[getReturnIndex(_mapType)]);
            } else {
                _param = abi.decode(_subData[getSubIndex(_mapType)], (bytes32));
            }
        }

        return _param;
    }

    /// @notice Checks if the paramMapping value indicated that we need to inject values
    /// @param _type Indicated the type of the input
    function isReplaceable(uint8 _type) internal pure returns (bool) {
        return _type != NO_PARAM_MAPPING;
    }

    /// @notice Checks if the paramMapping value is in the return value range
    /// @param _type Indicated the type of the input
    function isReturnInjection(uint8 _type) internal pure returns (bool) {
        return (_type >= RETURN_MIN_INDEX_VALUE) && (_type <= RETURN_MAX_INDEX_VALUE);
    }

    /// @notice Transforms the paramMapping value to the index in return array value
    /// @param _type Indicated the type of the input
    function getReturnIndex(uint8 _type) internal pure returns (uint8) {
        require(isReturnInjection(_type), ERR_SUB_INDEX_VALUE);

        return (_type - RETURN_MIN_INDEX_VALUE);
    }

    /// @notice Transforms the paramMapping value to the index in sub array value
    /// @param _type Indicated the type of the input
    function getSubIndex(uint8 _type) internal pure returns (uint8) {
        require(_type >= SUB_MIN_INDEX_VALUE, ERR_RETURN_INDEX_VALUE);

        return (_type - SUB_MIN_INDEX_VALUE);
    }
}





abstract contract IWETH {
    function allowance(address, address) public virtual view returns (uint256);

    function balanceOf(address) public virtual view returns (uint256);

    function approve(address, uint256) public virtual;

    function transfer(address, uint256) public virtual returns (bool);

    function transferFrom(
        address,
        address,
        uint256
    ) public virtual returns (bool);

    function deposit() public payable virtual;

    function withdraw(uint256) public virtual;
}






library TokenUtils {
    using SafeERC20 for IERC20;

    address public constant WETH_ADDR = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    address public constant ETH_ADDR = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

    function approveToken(
        address _tokenAddr,
        address _to,
        uint256 _amount
    ) internal {
        if (_tokenAddr == ETH_ADDR) return;

        if (IERC20(_tokenAddr).allowance(address(this), _to) < _amount) {
            IERC20(_tokenAddr).safeApprove(_to, _amount);
        }
    }

    function pullTokensIfNeeded(
        address _token,
        address _from,
        uint256 _amount
    ) internal returns (uint256) {
        // handle max uint amount
        if (_amount == type(uint256).max) {
            _amount = getBalance(_token, _from);
        }

        if (_from != address(0) && _from != address(this) && _token != ETH_ADDR && _amount != 0) {
            IERC20(_token).safeTransferFrom(_from, address(this), _amount);
        }

        return _amount;
    }

    function withdrawTokens(
        address _token,
        address _to,
        uint256 _amount
    ) internal returns (uint256) {
        if (_amount == type(uint256).max) {
            _amount = getBalance(_token, address(this));
        }

        if (_to != address(0) && _to != address(this) && _amount != 0) {
            if (_token != ETH_ADDR) {
                IERC20(_token).safeTransfer(_to, _amount);
            } else {
                payable(_to).transfer(_amount);
            }
        }

        return _amount;
    }

    function depositWeth(uint256 _amount) internal {
        IWETH(WETH_ADDR).deposit{value: _amount}();
    }

    function withdrawWeth(uint256 _amount) internal {
        IWETH(WETH_ADDR).withdraw(_amount);
    }

    function getBalance(address _tokenAddr, address _acc) internal view returns (uint256) {
        if (_tokenAddr == ETH_ADDR) {
            return _acc.balance;
        } else {
            return IERC20(_tokenAddr).balanceOf(_acc);
        }
    }

    function getTokenDecimals(address _token) internal view returns (uint256) {
        if (_token == ETH_ADDR) return 18;

        return IERC20(_token).decimals();
    }
}





contract DSMath {
    function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x + y) >= x, "");
    }

    function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x - y) <= x, "");
    }

    function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require(y == 0 || (z = x * y) / y == x, "");
    }

    function div(uint256 x, uint256 y) internal pure returns (uint256 z) {
        return x / y;
    }

    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        return x <= y ? x : y;
    }

    function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
        return x >= y ? x : y;
    }

    function imin(int256 x, int256 y) internal pure returns (int256 z) {
        return x <= y ? x : y;
    }

    function imax(int256 x, int256 y) internal pure returns (int256 z) {
        return x >= y ? x : y;
    }

    uint256 constant WAD = 10**18;
    uint256 constant RAY = 10**27;

    function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = add(mul(x, y), WAD / 2) / WAD;
    }

    function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = add(mul(x, y), RAY / 2) / RAY;
    }

    function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = add(mul(x, WAD), y / 2) / y;
    }

    function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = add(mul(x, RAY), y / 2) / y;
    }

    // This famous algorithm is called "exponentiation by squaring"
    // and calculates x^n with x as fixed-point and n as regular unsigned.
    //
    // It's O(log n), instead of O(n) for naive repeated multiplication.
    //
    // These facts are why it works:
    //
    //  If n is even, then x^n = (x^2)^(n/2).
    //  If n is odd,  then x^n = x * x^(n-1),
    //   and applying the equation for even x gives
    //    x^n = x * (x^2)^((n-1) / 2).
    //
    //  Also, EVM division is flooring and
    //    floor[(n-1) / 2] = floor[n / 2].
    //
    function rpow(uint256 x, uint256 n) internal pure returns (uint256 z) {
        z = n % 2 != 0 ? x : RAY;

        for (n /= 2; n != 0; n /= 2) {
            x = rmul(x, x);

            if (n % 2 != 0) {
                z = rmul(z, x);
            }
        }
    }
}





contract MainnetGUniAddresses {
    address public constant G_UNI_ROUTER_02_ADDRESS = 0x14E6D67F824C3a7b4329d3228807f8654294e4bd;
}




interface IGUniRouter02 {
    function removeLiquidity(
        address pool,
        uint256 burnAmount,
        uint256 amount0Min,
        uint256 amount1Min,
        address receiver
    )
        external
        returns (
            uint256 amount0,
            uint256 amount1,
            uint128 liquidityBurned
        );

    function rebalanceAndAddLiquidity(
        address pool,
        uint256 amount0In,
        uint256 amount1In,
        uint256 amountSwap,
        bool zeroForOne,
        address[] memory swapActions,
        bytes[] memory swapDatas,
        uint256 amount0Min,
        uint256 amount1Min,
        address receiver
    )
        external
        returns (
            uint256 amount0,
            uint256 amount1,
            uint256 mintAmount
        );
    
    function addLiquidity(
        address pool,
        uint256 amount0Max,
        uint256 amount1Max,
        uint256 amount0Min,
        uint256 amount1Min,
        address receiver
    )
        external
        returns (
            uint256 amount0,
            uint256 amount1,
            uint256 mintAmount
        );
}






contract GUniHelper is MainnetGUniAddresses{
    IGUniRouter02 public constant gUniRouter = IGUniRouter02(G_UNI_ROUTER_02_ADDRESS);
}








contract GUniWithdraw is ActionBase, DSMath, GUniHelper {
    using TokenUtils for address;
    
    /// @param pool address of G-UNI pool to remove liquidity from
    /// @param burnAmount The number of G-UNI tokens to burn
    /// @param amount0Min Minimum amount of token0 received after burn (slippage protection)
    /// @param amount1Min Minimum amount of token1 received after burn (slippage protection)
    /// @param to The account to receive the underlying amounts of token0 and token1
    /// @param from Account from which to pull G-Uni LP tokens
    struct Params {
        address pool;
        uint256 burnAmount;
        uint256 amount0Min;
        uint256 amount1Min;
        address to;
        address from;
    }

    /// @inheritdoc ActionBase
    function executeAction(
        bytes[] memory _callData,
        bytes[] memory _subData,
        uint8[] memory _paramMapping,
        bytes32[] memory _returnValues
    ) public payable virtual override returns (bytes32) {
        Params memory inputData = parseInputs(_callData);

        inputData.burnAmount = _parseParamUint(inputData.burnAmount, _paramMapping[0], _subData, _returnValues);

        uint256 liquidityBurnt = gUniWithdraw(inputData);

        return bytes32(liquidityBurnt);
    }

    /// @inheritdoc ActionBase
    function executeActionDirect(bytes[] memory _callData) public payable override {
        Params memory inputData = parseInputs(_callData);

        gUniWithdraw(inputData);
    }

    /// @inheritdoc ActionBase
    function actionType() public pure virtual override returns (uint8) {
        return uint8(ActionType.STANDARD_ACTION);
    }

    //////////////////////////// ACTION LOGIC ////////////////////////////

    function gUniWithdraw(Params memory _inputData) internal returns (uint128) {
        require (_inputData.to != address(0x0), "Can not send to burn address");

        _inputData.burnAmount = _inputData.pool.pullTokensIfNeeded(_inputData.from, _inputData.burnAmount);

        _inputData.pool.approveToken(G_UNI_ROUTER_02_ADDRESS, _inputData.burnAmount);

        (uint256 amount0, uint256 amount1, uint128 liquidityBurnt) = gUniRouter.removeLiquidity(_inputData.pool, _inputData.burnAmount, _inputData.amount0Min, _inputData.amount1Min, _inputData.to);
        /// @dev amountToBurn will always be burnt, so no need to send back any leftovers 

        logger.Log(address(this), msg.sender, "GUniWithdraw", abi.encode(_inputData, amount0, amount1, liquidityBurnt));
        
        return liquidityBurnt;
    }

    function parseInputs(bytes[] memory _callData) internal pure returns (Params memory inputData) {
        inputData = abi.decode(_callData[0], (Params));
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"name":"ERR_RETURN_INDEX_VALUE","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ERR_SUB_INDEX_VALUE","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"G_UNI_ROUTER_02_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NO_PARAM_MAPPING","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RETURN_MAX_INDEX_VALUE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RETURN_MIN_INDEX_VALUE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SUB_MAX_INDEX_VALUE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SUB_MIN_INDEX_VALUE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"actionType","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"adminVault","outputs":[{"internalType":"contract AdminVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"_callData","type":"bytes[]"},{"internalType":"bytes[]","name":"_subData","type":"bytes[]"},{"internalType":"uint8[]","name":"_paramMapping","type":"uint8[]"},{"internalType":"bytes32[]","name":"_returnValues","type":"bytes32[]"}],"name":"executeAction","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"_callData","type":"bytes[]"}],"name":"executeActionDirect","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"gUniRouter","outputs":[{"internalType":"contract IGUniRouter02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kill","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"logger","outputs":[{"internalType":"contract DefisaverLogger","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"contract DFSRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawStuckFunds","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b5061166e806100206000396000f3fe60806040526004361061010e5760003560e01c8063910c238e116100a5578063ca5ff78011610074578063e910afb211610059578063e910afb21461025d578063f24ccbfe1461027f578063f8e2fb00146102945761010e565b8063ca5ff78014610228578063d3c2e7ed146102485761010e565b8063910c238e146101de5780639864dcdd146101f3578063b45151e1146101de578063c579d490146102085761010e565b806341c0e1b5116100e157806341c0e1b51461017d5780637b103999146101925780638bcb6216146101b45780638cedca71146101c95761010e565b80630f2eee42146101135780631afd15be1461013e578063247492f8146101535780632fa13cb814610168575b600080fd5b34801561011f57600080fd5b506101286102a9565b60405161013591906115a4565b60405180910390f35b61015161014c366004611028565b6102ae565b005b34801561015f57600080fd5b506101286102c9565b34801561017457600080fd5b506101286102ce565b34801561018957600080fd5b506101516102d3565b34801561019e57600080fd5b506101a7610394565b60405161013591906112bc565b3480156101c057600080fd5b506101286103ac565b3480156101d557600080fd5b506101a76103b1565b3480156101ea57600080fd5b506101a76103c9565b3480156101ff57600080fd5b506101286103e1565b34801561021457600080fd5b50610151610223366004610fe8565b6103e6565b61023b61023636600461105b565b610510565b60405161013591906113dc565b34801561025457600080fd5b50610128610571565b34801561026957600080fd5b50610272610576565b60405161013591906113e5565b34801561028b57600080fd5b506101a76105af565b3480156102a057600080fd5b506102726105c7565b608081565b60006102b982610600565b90506102c481610636565b505050565b600190565b600081565b336001600160a01b031673ccf3d848e08b94478ed8f46ffead3008faf581fd6001600160a01b031663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b15801561032a57600080fd5b505afa15801561033e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103629190610fcc565b6001600160a01b0316146103915760405162461bcd60e51b815260040161038890611466565b60405180910390fd5b33ff5b73d6049e1f5f3eff1f921f5532af1a1632ba23929c81565b600181565b73ccf3d848e08b94478ed8f46ffead3008faf581fd81565b7314e6d67f824c3a7b4329d3228807f8654294e4bd81565b607f81565b336001600160a01b031673ccf3d848e08b94478ed8f46ffead3008faf581fd6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561043d57600080fd5b505afa158015610451573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104759190610fcc565b6001600160a01b03161461049b5760405162461bcd60e51b81526004016103889061142f565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03841614156104fc576040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156104f6573d6000803e3d6000fd5b506102c4565b6102c46001600160a01b0384168383610823565b60008061051c86610600565b905061054281602001518560008151811061053357fe5b602002602001015187866108a6565b6020820152600061055282610636565b6fffffffffffffffffffffffffffffffff16925050505b949350505050565b60ff81565b6040518060400160405280601881526020017f57726f6e672072657475726e20696e6465782076616c7565000000000000000081525081565b735c55b921f590a89c1ebe84df170e655a82b6212681565b6040518060400160405280601581526020017f57726f6e672073756220696e6465782076616c7565000000000000000000000081525081565b610608610e5a565b8160008151811061061557fe5b60200260200101518060200190518101906106309190611185565b92915050565b60808101516000906001600160a01b03166106635760405162461bcd60e51b8152600401610388906113f8565b60a082015160208301518351610684926001600160a01b039091169161092b565b6020830181905282516106b8916001600160a01b03909116907314e6d67f824c3a7b4329d3228807f8654294e4bd906109ba565b815160208301516040808501516060860151608087015192517f59f842b2000000000000000000000000000000000000000000000000000000008152600095869586957314e6d67f824c3a7b4329d3228807f8654294e4bd956359f842b29561072795919290916004016113ac565b606060405180830381600087803b15801561074157600080fd5b505af1158015610755573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107799190611228565b925092509250735c55b921f590a89c1ebe84df170e655a82b621266001600160a01b031663d061ce503033888787876040516020016107bb9493929190611531565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016107e8939291906112ea565b600060405180830381600087803b15801561080257600080fd5b505af1158015610816573d6000803e3d6000fd5b5092979650505050505050565b6102c48363a9059cbb60e01b8484604051602401610842929190611393565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610a97565b60006108b184610b26565b15610922576108bf84610b2e565b156108ed57816108ce85610b4d565b60ff16815181106108db57fe5b602002602001015160001c9450610922565b826108f785610bb5565b60ff168151811061090457fe5b602002602001015180602001905181019061091f9190611210565b94505b50929392505050565b6000600019821415610944576109418484610c1a565b91505b6001600160a01b0383161580159061096557506001600160a01b0383163014155b801561098e57506001600160a01b03841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14155b801561099957508115155b156109b3576109b36001600160a01b038516843085610cee565b5092915050565b6001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14156109e4576102c4565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815281906001600160a01b0385169063dd62ed3e90610a2d90309087906004016112d0565b60206040518083038186803b158015610a4557600080fd5b505afa158015610a59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7d9190611210565b10156102c4576102c46001600160a01b0384168383610d15565b6000610aec826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610d549092919063ffffffff16565b8051909150156102c45780806020019051810190610b0a9190611165565b6102c45760405162461bcd60e51b8152600401610388906114d4565b60ff16151590565b6000600160ff831610801590610630575050607f60ff91909116111590565b6000610b5882610b2e565b6040518060400160405280601581526020017f57726f6e672073756220696e6465782076616c7565000000000000000000000081525090610bac5760405162461bcd60e51b815260040161038891906113e5565b50506000190190565b60408051808201909152601881527f57726f6e672072657475726e20696e6465782076616c756500000000000000006020820152600090608060ff84161015610c115760405162461bcd60e51b815260040161038891906113e5565b5050607f190190565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415610c5257506001600160a01b03811631610630565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b038416906370a0823190610c979085906004016112bc565b60206040518083038186803b158015610caf57600080fd5b505afa158015610cc3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce79190611210565b9392505050565b610d0f846323b872dd60e01b85858560405160240161084293929190611353565b50505050565b610d358363095ea7b360e01b846000604051602401610842929190611377565b6102c48363095ea7b360e01b8484604051602401610842929190611393565b606061056984846000856060610d6985610e21565b610d855760405162461bcd60e51b81526004016103889061149d565b600080866001600160a01b03168587604051610da191906112a0565b60006040518083038185875af1925050503d8060008114610dde576040519150601f19603f3d011682016040523d82523d6000602084013e610de3565b606091505b50915091508115610df75791506105699050565b805115610e075780518082602001fd5b8360405162461bcd60e51b815260040161038891906113e5565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610569575050151592915050565b6040518060c0016040528060006001600160a01b0316815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b031681525090565b600082601f830112610ebb578081fd5b81356020610ed0610ecb836115d6565b6115b2565b8281528181019085830183850287018401881015610eec578586fd5b855b85811015610f0a57813584529284019290840190600101610eee565b5090979650505050505050565b6000601f8381840112610f28578182fd5b82356020610f38610ecb836115d6565b82815281810190868301865b85811015610fbe57813589018a603f820112610f5e578889fd5b85810135604067ffffffffffffffff821115610f7657fe5b610f87828b01601f191689016115b2565b8281528d82848601011115610f9a578b8cfd5b828285018a83013791820188018b9052508552509284019290840190600101610f44565b509098975050505050505050565b600060208284031215610fdd578081fd5b8151610ce781611620565b600080600060608486031215610ffc578182fd5b833561100781611620565b9250602084013561101781611620565b929592945050506040919091013590565b600060208284031215611039578081fd5b813567ffffffffffffffff81111561104f578182fd5b61056984828501610f17565b60008060008060808587031215611070578081fd5b843567ffffffffffffffff80821115611087578283fd5b61109388838901610f17565b95506020915081870135818111156110a9578384fd5b6110b589828a01610f17565b9550506040870135818111156110c9578384fd5b8701601f810189136110d9578384fd5b80356110e7610ecb826115d6565b81815284810190838601868402850187018d1015611103578788fd5b8794505b8385101561113357803560ff8116811461111f578889fd5b835260019490940193918601918601611107565b509650505050606087013591508082111561114c578283fd5b5061115987828801610eab565b91505092959194509250565b600060208284031215611176578081fd5b81518015158114610ce7578182fd5b600060c08284031215611196578081fd5b60405160c0810181811067ffffffffffffffff821117156111b357fe5b60405282516111c181611620565b8082525060208301516020820152604083015160408201526060830151606082015260808301516111f181611620565b608082015260a083015161120481611620565b60a08201529392505050565b600060208284031215611221578081fd5b5051919050565b60008060006060848603121561123c578081fd5b835192506020840151915060408401516fffffffffffffffffffffffffffffffff81168114611269578182fd5b809150509250925092565b6000815180845261128c8160208601602086016115f4565b601f01601f19169290920160200192915050565b600082516112b28184602087016115f4565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b60006001600160a01b03808616835280851660208401525060806040830152600c60808301527f47556e695769746864726177000000000000000000000000000000000000000060a083015260c0606083015261134a60c0830184611274565b95945050505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0392909216825260ff16602082015260400190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039586168152602081019490945260408401929092526060830152909116608082015260a00190565b90815260200190565b600060208252610ce76020830184611274565b6020808252601c908201527f43616e206e6f742073656e6420746f206275726e206164647265737300000000604082015260600190565b60208082526014908201527f6d73672e73656e646572206e6f74206f776e6572000000000000000000000000604082015260600190565b60208082526014908201527f6d73672e73656e646572206e6f742061646d696e000000000000000000000000604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60408201527f6f74207375636365656400000000000000000000000000000000000000000000606082015260800190565b84516001600160a01b03908116825260208087015190830152604080870151908301526060808701519083015260808087015182169083015260a095860151169481019490945260c084019290925260e08301526fffffffffffffffffffffffffffffffff166101008201526101200190565b60ff91909116815260200190565b60405181810167ffffffffffffffff811182821017156115ce57fe5b604052919050565b600067ffffffffffffffff8211156115ea57fe5b5060209081020190565b60005b8381101561160f5781810151838201526020016115f7565b83811115610d0f5750506000910152565b6001600160a01b038116811461163557600080fd5b5056fea26469706673582212200d948554a76571517b6930167951bf039c8f87feae6d9ff1eeb90c7653d9619c64736f6c63430007060033

Deployed Bytecode

0x60806040526004361061010e5760003560e01c8063910c238e116100a5578063ca5ff78011610074578063e910afb211610059578063e910afb21461025d578063f24ccbfe1461027f578063f8e2fb00146102945761010e565b8063ca5ff78014610228578063d3c2e7ed146102485761010e565b8063910c238e146101de5780639864dcdd146101f3578063b45151e1146101de578063c579d490146102085761010e565b806341c0e1b5116100e157806341c0e1b51461017d5780637b103999146101925780638bcb6216146101b45780638cedca71146101c95761010e565b80630f2eee42146101135780631afd15be1461013e578063247492f8146101535780632fa13cb814610168575b600080fd5b34801561011f57600080fd5b506101286102a9565b60405161013591906115a4565b60405180910390f35b61015161014c366004611028565b6102ae565b005b34801561015f57600080fd5b506101286102c9565b34801561017457600080fd5b506101286102ce565b34801561018957600080fd5b506101516102d3565b34801561019e57600080fd5b506101a7610394565b60405161013591906112bc565b3480156101c057600080fd5b506101286103ac565b3480156101d557600080fd5b506101a76103b1565b3480156101ea57600080fd5b506101a76103c9565b3480156101ff57600080fd5b506101286103e1565b34801561021457600080fd5b50610151610223366004610fe8565b6103e6565b61023b61023636600461105b565b610510565b60405161013591906113dc565b34801561025457600080fd5b50610128610571565b34801561026957600080fd5b50610272610576565b60405161013591906113e5565b34801561028b57600080fd5b506101a76105af565b3480156102a057600080fd5b506102726105c7565b608081565b60006102b982610600565b90506102c481610636565b505050565b600190565b600081565b336001600160a01b031673ccf3d848e08b94478ed8f46ffead3008faf581fd6001600160a01b031663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b15801561032a57600080fd5b505afa15801561033e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103629190610fcc565b6001600160a01b0316146103915760405162461bcd60e51b815260040161038890611466565b60405180910390fd5b33ff5b73d6049e1f5f3eff1f921f5532af1a1632ba23929c81565b600181565b73ccf3d848e08b94478ed8f46ffead3008faf581fd81565b7314e6d67f824c3a7b4329d3228807f8654294e4bd81565b607f81565b336001600160a01b031673ccf3d848e08b94478ed8f46ffead3008faf581fd6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561043d57600080fd5b505afa158015610451573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104759190610fcc565b6001600160a01b03161461049b5760405162461bcd60e51b81526004016103889061142f565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03841614156104fc576040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156104f6573d6000803e3d6000fd5b506102c4565b6102c46001600160a01b0384168383610823565b60008061051c86610600565b905061054281602001518560008151811061053357fe5b602002602001015187866108a6565b6020820152600061055282610636565b6fffffffffffffffffffffffffffffffff16925050505b949350505050565b60ff81565b6040518060400160405280601881526020017f57726f6e672072657475726e20696e6465782076616c7565000000000000000081525081565b735c55b921f590a89c1ebe84df170e655a82b6212681565b6040518060400160405280601581526020017f57726f6e672073756220696e6465782076616c7565000000000000000000000081525081565b610608610e5a565b8160008151811061061557fe5b60200260200101518060200190518101906106309190611185565b92915050565b60808101516000906001600160a01b03166106635760405162461bcd60e51b8152600401610388906113f8565b60a082015160208301518351610684926001600160a01b039091169161092b565b6020830181905282516106b8916001600160a01b03909116907314e6d67f824c3a7b4329d3228807f8654294e4bd906109ba565b815160208301516040808501516060860151608087015192517f59f842b2000000000000000000000000000000000000000000000000000000008152600095869586957314e6d67f824c3a7b4329d3228807f8654294e4bd956359f842b29561072795919290916004016113ac565b606060405180830381600087803b15801561074157600080fd5b505af1158015610755573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107799190611228565b925092509250735c55b921f590a89c1ebe84df170e655a82b621266001600160a01b031663d061ce503033888787876040516020016107bb9493929190611531565b6040516020818303038152906040526040518463ffffffff1660e01b81526004016107e8939291906112ea565b600060405180830381600087803b15801561080257600080fd5b505af1158015610816573d6000803e3d6000fd5b5092979650505050505050565b6102c48363a9059cbb60e01b8484604051602401610842929190611393565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610a97565b60006108b184610b26565b15610922576108bf84610b2e565b156108ed57816108ce85610b4d565b60ff16815181106108db57fe5b602002602001015160001c9450610922565b826108f785610bb5565b60ff168151811061090457fe5b602002602001015180602001905181019061091f9190611210565b94505b50929392505050565b6000600019821415610944576109418484610c1a565b91505b6001600160a01b0383161580159061096557506001600160a01b0383163014155b801561098e57506001600160a01b03841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14155b801561099957508115155b156109b3576109b36001600160a01b038516843085610cee565b5092915050565b6001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14156109e4576102c4565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815281906001600160a01b0385169063dd62ed3e90610a2d90309087906004016112d0565b60206040518083038186803b158015610a4557600080fd5b505afa158015610a59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7d9190611210565b10156102c4576102c46001600160a01b0384168383610d15565b6000610aec826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610d549092919063ffffffff16565b8051909150156102c45780806020019051810190610b0a9190611165565b6102c45760405162461bcd60e51b8152600401610388906114d4565b60ff16151590565b6000600160ff831610801590610630575050607f60ff91909116111590565b6000610b5882610b2e565b6040518060400160405280601581526020017f57726f6e672073756220696e6465782076616c7565000000000000000000000081525090610bac5760405162461bcd60e51b815260040161038891906113e5565b50506000190190565b60408051808201909152601881527f57726f6e672072657475726e20696e6465782076616c756500000000000000006020820152600090608060ff84161015610c115760405162461bcd60e51b815260040161038891906113e5565b5050607f190190565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415610c5257506001600160a01b03811631610630565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b038416906370a0823190610c979085906004016112bc565b60206040518083038186803b158015610caf57600080fd5b505afa158015610cc3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce79190611210565b9392505050565b610d0f846323b872dd60e01b85858560405160240161084293929190611353565b50505050565b610d358363095ea7b360e01b846000604051602401610842929190611377565b6102c48363095ea7b360e01b8484604051602401610842929190611393565b606061056984846000856060610d6985610e21565b610d855760405162461bcd60e51b81526004016103889061149d565b600080866001600160a01b03168587604051610da191906112a0565b60006040518083038185875af1925050503d8060008114610dde576040519150601f19603f3d011682016040523d82523d6000602084013e610de3565b606091505b50915091508115610df75791506105699050565b805115610e075780518082602001fd5b8360405162461bcd60e51b815260040161038891906113e5565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610569575050151592915050565b6040518060c0016040528060006001600160a01b0316815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b031681525090565b600082601f830112610ebb578081fd5b81356020610ed0610ecb836115d6565b6115b2565b8281528181019085830183850287018401881015610eec578586fd5b855b85811015610f0a57813584529284019290840190600101610eee565b5090979650505050505050565b6000601f8381840112610f28578182fd5b82356020610f38610ecb836115d6565b82815281810190868301865b85811015610fbe57813589018a603f820112610f5e578889fd5b85810135604067ffffffffffffffff821115610f7657fe5b610f87828b01601f191689016115b2565b8281528d82848601011115610f9a578b8cfd5b828285018a83013791820188018b9052508552509284019290840190600101610f44565b509098975050505050505050565b600060208284031215610fdd578081fd5b8151610ce781611620565b600080600060608486031215610ffc578182fd5b833561100781611620565b9250602084013561101781611620565b929592945050506040919091013590565b600060208284031215611039578081fd5b813567ffffffffffffffff81111561104f578182fd5b61056984828501610f17565b60008060008060808587031215611070578081fd5b843567ffffffffffffffff80821115611087578283fd5b61109388838901610f17565b95506020915081870135818111156110a9578384fd5b6110b589828a01610f17565b9550506040870135818111156110c9578384fd5b8701601f810189136110d9578384fd5b80356110e7610ecb826115d6565b81815284810190838601868402850187018d1015611103578788fd5b8794505b8385101561113357803560ff8116811461111f578889fd5b835260019490940193918601918601611107565b509650505050606087013591508082111561114c578283fd5b5061115987828801610eab565b91505092959194509250565b600060208284031215611176578081fd5b81518015158114610ce7578182fd5b600060c08284031215611196578081fd5b60405160c0810181811067ffffffffffffffff821117156111b357fe5b60405282516111c181611620565b8082525060208301516020820152604083015160408201526060830151606082015260808301516111f181611620565b608082015260a083015161120481611620565b60a08201529392505050565b600060208284031215611221578081fd5b5051919050565b60008060006060848603121561123c578081fd5b835192506020840151915060408401516fffffffffffffffffffffffffffffffff81168114611269578182fd5b809150509250925092565b6000815180845261128c8160208601602086016115f4565b601f01601f19169290920160200192915050565b600082516112b28184602087016115f4565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b60006001600160a01b03808616835280851660208401525060806040830152600c60808301527f47556e695769746864726177000000000000000000000000000000000000000060a083015260c0606083015261134a60c0830184611274565b95945050505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0392909216825260ff16602082015260400190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039586168152602081019490945260408401929092526060830152909116608082015260a00190565b90815260200190565b600060208252610ce76020830184611274565b6020808252601c908201527f43616e206e6f742073656e6420746f206275726e206164647265737300000000604082015260600190565b60208082526014908201527f6d73672e73656e646572206e6f74206f776e6572000000000000000000000000604082015260600190565b60208082526014908201527f6d73672e73656e646572206e6f742061646d696e000000000000000000000000604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60408201527f6f74207375636365656400000000000000000000000000000000000000000000606082015260800190565b84516001600160a01b03908116825260208087015190830152604080870151908301526060808701519083015260808087015182169083015260a095860151169481019490945260c084019290925260e08301526fffffffffffffffffffffffffffffffff166101008201526101200190565b60ff91909116815260200190565b60405181810167ffffffffffffffff811182821017156115ce57fe5b604052919050565b600067ffffffffffffffff8211156115ea57fe5b5060209081020190565b60005b8381101561160f5781810151838201526020016115f7565b83811115610d0f5750506000910152565b6001600160a01b038116811461163557600080fd5b5056fea26469706673582212200d948554a76571517b6930167951bf039c8f87feae6d9ff1eeb90c7653d9619c64736f6c63430007060033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.