ETH Price: $2,381.01 (-3.66%)

Contract

0x81c69A428fDB21bBaB8A7434fF511382058c29dC
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x60806040134235542021-10-15 15:53:521083 days ago1634313232IN
 Create: FLBalancer
0 ETH0.20673675109.80031788

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
FLBalancer

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-10-15
*/

// SPDX-License-Identifier: MIT

pragma solidity =0.7.6;

pragma experimental ABIEncoderV2;





interface IAsset {
}

interface IVault{

    function joinPool(
        bytes32 poolId,
        address sender,
        address recipient,
        JoinPoolRequest memory request
    ) external payable;

    struct JoinPoolRequest {
        IAsset[] assets;
        uint256[] maxAmountsIn;
        bytes userData;
        bool fromInternalBalance;
    }

    function exitPool(
        bytes32 poolId,
        address sender,
        address payable recipient,
        ExitPoolRequest memory request
    ) external;

    struct ExitPoolRequest {
        IAsset[] assets;
        uint256[] minAmountsOut;
        bytes userData;
        bool toInternalBalance;
    }

    function getPoolTokens(bytes32 poolId)
    external
    view
    returns (
        address[] memory tokens,
        uint256[] memory balances,
        uint256 lastChangeBlock
    );
}





contract MainnetBalancerV2Addresses {
    address internal constant VAULT_ADDR = 0xBA12222222228d8Ba445958a75a0704d566BF2C8;
    address internal constant MERKLE_REEDEM_ADDR = 0x6d19b2bF3A36A61530909Ae65445a906D98A2Fa8;
    address internal constant balToken = 0xba100000625a3754423978a60c9317c58a424e3D;

}






contract BalancerV2Helper is MainnetBalancerV2Addresses{
    IVault public constant vault = IVault(VAULT_ADDR);
    string public constant ADDR_MUST_NOT_BE_ZERO = "Address to which tokens will be sent to can't be burn address";

    function _getPoolAddress(bytes32 poolId) internal pure returns (address) {
        // 12 byte logical shift left to remove the nonce and specialization setting. We don't need to mask,
        // since the logical shift already sets the upper bits to zero.
        return address(uint256(poolId) >> (12 * 8));
    }
}





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 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);

    function decimals() external view returns (uint256 digits);

    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);
    }
}





contract StrategyData {
    struct Template {
        string name;
        bytes32[] triggerIds;
        bytes32[] actionIds;
        uint8[][] paramMapping;
    }

    struct Task {
        string name;
        bytes[][] callData;
        bytes[][] subData;
        bytes32[] actionIds;
        uint8[][] paramMapping;
    }

    struct Strategy {
        uint templateId;
        address proxy;
        bytes[][] subData;
        bytes[][] triggerData;
        bool active;

        uint posInUserArr;
    }
}




interface IFlashLoanRecipient {
    /**
     * @dev When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the recipient.
     *
     * At the time of the call, the Vault will have transferred `amounts` for `tokens` to the recipient. Before this
     * call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token back to the
     * Vault, or else the entire flash loan will revert.
     *
     * `userData` is the same value passed in the `IVault.flashLoan` call.
     */
    function receiveFlashLoan(
        address[] memory tokens,
        uint256[] memory amounts,
        uint256[] memory feeAmounts,
        bytes memory userData
    ) external;
}




interface IFlashLoans {
    function flashLoan(
        address recipient,
        address[] memory tokens,
        uint256[] memory amounts,
        bytes memory userData
    ) external;
}





abstract contract IDSProxy {
    // function execute(bytes memory _code, bytes memory _data)
    //     public
    //     payable
    //     virtual
    //     returns (address, bytes32);

    function execute(address _target, bytes memory _data) public payable virtual returns (bytes32);

    function setCache(address _cacheAddr) public payable virtual returns (bool);

    function owner() public view virtual returns (address);
}





abstract contract IFLParamGetter {
    function getFlashLoanParams(bytes memory _data)
        public
        view
        virtual
        returns (
            address[] memory tokens,
            uint256[] memory amount,
            uint256[] memory modes
        );
}





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();
    }
}





abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor () {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}











contract FLBalancer is ActionBase, ReentrancyGuard, IFlashLoanRecipient, BalancerV2Helper {
    using TokenUtils for address;
    using SafeMath for uint256;

    /// @dev Function sig of TaskExecutor._executeActionsFromFL()
    bytes4 public constant CALLBACK_SELECTOR = 0xd6741b9e;
    bytes32 constant TASK_EXECUTOR_ID = keccak256("TaskExecutor");

    bytes32 public constant CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");

    struct Params {
        address[] tokens;           // Tokens to flash borrow
        uint256[] amounts;          // Token amounts
        address flParamGetterAddr;  // On-chain contract used for piping FL action parameters 
        bytes flParamGetterData;    // Data to supply to flParamGetter
    }

    function executeAction(
        bytes[] memory _callData,
        bytes[] memory,
        uint8[] memory,
        bytes32[] memory
    ) public override payable returns (bytes32) {
        Params memory params = parseInputs(_callData);

        if (params.flParamGetterAddr != address(0)) {
            (params.tokens, params.amounts,) =
                IFLParamGetter(params.flParamGetterAddr).getFlashLoanParams(params.flParamGetterData);
        }

        bytes memory taskData = _callData[_callData.length - 1];

        uint256 amount = _flBalancer(params, taskData);
        return bytes32(amount);
    }

    // solhint-disable-next-line no-empty-blocks
    function executeActionDirect(bytes[] memory _callData) public override payable {}

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

    /// @notice Gets a FL from Balancer and returns back the execution to the action address
    function _flBalancer(Params memory _params, bytes memory _taskData) internal returns (uint256) {
        IFlashLoans(VAULT_ADDR).flashLoan(
            address(this),
            _params.tokens,
            _params.amounts,
            _taskData
        );

        logger.Log(
            address(this),
            msg.sender,
            "FLBalancer",
            abi.encode(
                _params
            )
        );

        return _params.amounts[0];
    }

    /// @notice Balancer FL callback function that formats and calls back TaskExecutor
    function receiveFlashLoan(
        address[] memory _tokens,
        uint256[] memory _amounts,
        uint256[] memory _feeAmounts,
        bytes memory _userData
    ) external override nonReentrant {
        require(msg.sender == VAULT_ADDR, "Untrusted lender");
        (StrategyData.Task memory currTask, address proxy) = abi.decode(_userData, (StrategyData.Task, address));

        for (uint256 i = 0; i < _tokens.length; i++) {
            _tokens[i].withdrawTokens(proxy, _amounts[i]);
        }
        address payable taskExecutor = payable(registry.getAddr(TASK_EXECUTOR_ID));

        // call Action execution
        IDSProxy(proxy).execute{value: address(this).balance}(
            taskExecutor,
            abi.encodeWithSelector(CALLBACK_SELECTOR, currTask, _amounts[0].add(_feeAmounts[0]))
        );

        for (uint256 i = 0; i < _tokens.length; i++) {
            uint256 paybackAmount = _amounts[i].add(_feeAmounts[i]);
            
            require(_tokens[i].getBalance(address(this)) == paybackAmount, "Wrong payback amount");

            _tokens[i].withdrawTokens(address(VAULT_ADDR), paybackAmount);
        }
    }

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

Contract Security Audit

Contract ABI

[{"inputs":[],"name":"ADDR_MUST_NOT_BE_ZERO","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CALLBACK_SELECTOR","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CALLBACK_SUCCESS","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"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":"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":"","type":"bytes[]"},{"internalType":"uint8[]","name":"","type":"uint8[]"},{"internalType":"bytes32[]","name":"","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":"kill","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"logger","outputs":[{"internalType":"contract DefisaverLogger","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"_callData","type":"bytes[]"}],"name":"parseInputs","outputs":[{"components":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"address","name":"flParamGetterAddr","type":"address"},{"internalType":"bytes","name":"flParamGetterData","type":"bytes"}],"internalType":"struct FLBalancer.Params","name":"params","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokens","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"_feeAmounts","type":"uint256[]"},{"internalType":"bytes","name":"_userData","type":"bytes"}],"name":"receiveFlashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"contract DFSRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract IVault","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"}]

608060405234801561001057600080fd5b5060016000556120c0806100256000396000f3fe60806040526004361061016a5760003560e01c80639864dcdd116100cb578063e910afb21161007f578063f829822d11610059578063f829822d1461035f578063f8e2fb0014610374578063fbfa77cf146103895761016a565b8063e910afb214610308578063f04f27071461032a578063f24ccbfe1461034a5761016a565b8063c579d490116100b0578063c579d490146102c0578063ca5ff780146102e0578063d3c2e7ed146102f35761016a565b80639864dcdd146102895780639ce3e9191461029e5761016a565b806341c0e1b5116101225780638237e538116101075780638237e5381461023d5780638bcb62161461025f5780638cedca71146102745761016a565b806341c0e1b5146102065780637b1039991461021b5761016a565b80631afd15be116101535780631afd15be146101c7578063247492f8146101dc5780632fa13cb8146101f15761016a565b80630336fd901461016f5780630f2eee42146101a5575b600080fd5b34801561017b57600080fd5b5061018f61018a366004611639565b61039e565b60405161019c9190611e54565b60405180910390f35b3480156101b157600080fd5b506101ba6103d4565b60405161019c9190611f87565b6101da6101d5366004611639565b6103d9565b005b3480156101e857600080fd5b506101ba6103dc565b3480156101fd57600080fd5b506101ba6103e1565b34801561021257600080fd5b506101da6103e6565b34801561022757600080fd5b506102306104a7565b60405161019c9190611b22565b34801561024957600080fd5b506102526104bf565b60405161019c9190611c2d565b34801561026b57600080fd5b506101ba6104e3565b34801561028057600080fd5b506102306104e8565b34801561029557600080fd5b506101ba610500565b3480156102aa57600080fd5b506102b3610505565b60405161019c9190611c36565b3480156102cc57600080fd5b506101da6102db36600461146e565b610529565b6102526102ee36600461166c565b610658565b3480156102ff57600080fd5b506101ba610741565b34801561031457600080fd5b5061031d610746565b60405161019c9190611c63565b34801561033657600080fd5b506101da610345366004611532565b61077f565b34801561035657600080fd5b50610230610afe565b34801561036b57600080fd5b5061031d610b16565b34801561038057600080fd5b5061031d610b32565b34801561039557600080fd5b50610230610b6b565b6103a66110ac565b816000815181106103b357fe5b60200260200101518060200190518101906103ce919061179d565b92915050565b608081565b50565b600090565b600081565b336001600160a01b031673ccf3d848e08b94478ed8f46ffead3008faf581fd6001600160a01b031663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b15801561043d57600080fd5b505afa158015610451573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104759190611452565b6001600160a01b0316146104a45760405162461bcd60e51b815260040161049b90611d1b565b60405180910390fd5b33ff5b73d6049e1f5f3eff1f921f5532af1a1632ba23929c81565b7f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd981565b600181565b73ccf3d848e08b94478ed8f46ffead3008faf581fd81565b607f81565b7fd6741b9e0000000000000000000000000000000000000000000000000000000081565b336001600160a01b031673ccf3d848e08b94478ed8f46ffead3008faf581fd6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561058057600080fd5b505afa158015610594573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b89190611452565b6001600160a01b0316146105de5760405162461bcd60e51b815260040161049b90611cad565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b038416141561063f576040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015610639573d6000803e3d6000fd5b50610653565b6106536001600160a01b0384168383610b83565b505050565b6000806106648661039e565b60408101519091506001600160a01b03161561070b5780604001516001600160a01b0316630ae1cc8e82606001516040518263ffffffff1660e01b81526004016106ae9190611c63565b60006040518083038186803b1580156106c657600080fd5b505afa1580156106da573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261070291908101906114ae565b50602083015281525b60008660018851038151811061071d57fe5b6020026020010151905060006107338383610c06565b93505050505b949350505050565b60ff81565b6040518060400160405280601881526020017f57726f6e672072657475726e20696e6465782076616c7565000000000000000081525081565b600260005414156107a25760405162461bcd60e51b815260040161049b90611e1d565b60026000553373ba12222222228d8ba445958a75a0704d566bf2c8146107da5760405162461bcd60e51b815260040161049b90611ce4565b600080828060200190518101906107f1919061185f565b9150915060005b865181101561084e576108458287838151811061081157fe5b602002602001015189848151811061082557fe5b60200260200101516001600160a01b0316610d4c9092919063ffffffff16565b506001016107f8565b506040517f4ccee9b600000000000000000000000000000000000000000000000000000000815260009073d6049e1f5f3eff1f921f5532af1a1632ba23929c90634ccee9b6906108c2907fcec38b05fe06a488e2de01744d7ff3b8ac89eb607661ed3d7a4b16544d0c7a7290600401611c2d565b60206040518083038186803b1580156108da57600080fd5b505afa1580156108ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109129190611452565b9050816001600160a01b0316631cff79cd478363d6741b9e60e01b876109698b60008151811061093e57fe5b60200260200101518d60008151811061095357fe5b6020026020010151610e1290919063ffffffff16565b60405160240161097a929190611ebf565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009485161790525160e086901b90921682526109ed9291600401611b36565b6020604051808303818588803b158015610a0657600080fd5b505af1158015610a1a573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610a3f9190611785565b5060005b8751811015610aef576000610a71878381518110610a5d57fe5b602002602001015189848151811061095357fe5b905080610aa3308b8581518110610a8457fe5b60200260200101516001600160a01b0316610e3e90919063ffffffff16565b14610ac05760405162461bcd60e51b815260040161049b90611d52565b610ae573ba12222222228d8ba445958a75a0704d566bf2c8828b858151811061082557fe5b5050600101610a43565b50506001600055505050505050565b735c55b921f590a89c1ebe84df170e655a82b6212681565b6040518060600160405280603d815260200161204e603d913981565b6040518060400160405280601581526020017f57726f6e672073756220696e6465782076616c7565000000000000000000000081525081565b73ba12222222228d8ba445958a75a0704d566bf2c881565b6106538363a9059cbb60e01b8484604051602401610ba2929190611c14565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610f12565b815160208301516040517f5c38449e00000000000000000000000000000000000000000000000000000000815260009273ba12222222228d8ba445958a75a0704d566bf2c892635c38449e92610c6492309290918890600401611bc1565b600060405180830381600087803b158015610c7e57600080fd5b505af1158015610c92573d6000803e3d6000fd5b50505050735c55b921f590a89c1ebe84df170e655a82b621266001600160a01b031663d061ce50303386604051602001610ccc9190611e54565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401610cf993929190611b58565b600060405180830381600087803b158015610d1357600080fd5b505af1158015610d27573d6000803e3d6000fd5b505050508260200151600081518110610d3c57fe5b6020026020010151905092915050565b6000600019821415610d6557610d628430610e3e565b91505b6001600160a01b03831615801590610d8657506001600160a01b0383163014155b8015610d9157508115155b15610e0b576001600160a01b03841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610dd357610dce6001600160a01b0385168484610b83565b610e0b565b6040516001600160a01b0384169083156108fc029084906000818181858888f19350505050158015610e09573d6000803e3d6000fd5b505b5092915050565b600082820183811015610e375760405162461bcd60e51b815260040161049b90611c76565b9392505050565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415610e7657506001600160a01b038116316103ce565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b038416906370a0823190610ebb908590600401611b22565b60206040518083038186803b158015610ed357600080fd5b505afa158015610ee7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0b9190611785565b90506103ce565b6000610f67826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610fa19092919063ffffffff16565b8051909150156106535780806020019051810190610f859190611765565b6106535760405162461bcd60e51b815260040161049b90611dc0565b606061073984846000856060610fb68561106e565b610fd25760405162461bcd60e51b815260040161049b90611d89565b600080866001600160a01b03168587604051610fee9190611b06565b60006040518083038185875af1925050503d806000811461102b576040519150601f19603f3d011682016040523d82523d6000602084013e611030565b606091505b509150915081156110445791506107399050565b8051156110545780518082602001fd5b8360405162461bcd60e51b815260040161049b9190611c63565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906110a257508115155b925050505b919050565b6040518060800160405280606081526020016060815260200160006001600160a01b03168152602001606081525090565b80516110a781612029565b600082601f8301126110f8578081fd5b8151602061110d61110883611fb9565b611f95565b8281528181019085830183850287018401881015611129578586fd5b855b8581101561115057815161113e81612029565b8452928401929084019060010161112b565b5090979650505050505050565b600082601f83011261116d578081fd5b8151602061117d61110883611fb9565b82815281810190858301855b85811015611150578151880189603f8201126111a3578788fd5b858101516111b361110882611fb9565b81815287810190604084018b5b848110156111ea576111d88f6040845189010161140f565b8452928a0192908a01906001016111c0565b505087525050509284019290840190600101611189565b600082601f830112611211578081fd5b8151602061122161110883611fb9565b82815281810190858301855b85811015611150578151880189603f820112611247578788fd5b85810151604061125961110883611fb9565b828152888101908483018a8502860184018f1015611275578c8dfd5b8c95505b848610156112a3578051935061128e8461203e565b83835260019590950194918a01918a01611279565b50885250505093850193509084019060010161122d565b600082601f8301126112ca578081fd5b813560206112da61110883611fb9565b82815281810190858301838502870184018810156112f6578586fd5b855b85811015611150578135845292840192908401906001016112f8565b600082601f830112611324578081fd5b8151602061133461110883611fb9565b8281528181019085830183850287018401881015611350578586fd5b855b8581101561115057815184529284019290840190600101611352565b600082601f83011261137e578081fd5b8135602061138e61110883611fb9565b82815281810190858301855b85811015611150576113b1898684358b01016113c3565b8452928401929084019060010161139a565b600082601f8301126113d3578081fd5b81356113e161110882611fd7565b8181528460208386010111156113f5578283fd5b816020850160208301379081016020019190915292915050565b600082601f83011261141f578081fd5b815161142d61110882611fd7565b818152846020838601011115611441578283fd5b610739826020830160208701611ff9565b600060208284031215611463578081fd5b8151610e3781612029565b600080600060608486031215611482578182fd5b833561148d81612029565b9250602084013561149d81612029565b929592945050506040919091013590565b6000806000606084860312156114c2578081fd5b835167ffffffffffffffff808211156114d9578283fd5b6114e5878388016110e8565b945060208601519150808211156114fa578283fd5b61150687838801611314565b9350604086015191508082111561151b578283fd5b5061152886828701611314565b9150509250925092565b60008060008060808587031215611547578182fd5b843567ffffffffffffffff8082111561155e578384fd5b818701915087601f830112611571578384fd5b8135602061158161110883611fb9565b82815281810190858301838502870184018d101561159d578889fd5b8896505b848710156115c85780356115b481612029565b8352600196909601959183019183016115a1565b50985050880135925050808211156115de578384fd5b6115ea888389016112ba565b945060408701359150808211156115ff578384fd5b61160b888389016112ba565b93506060870135915080821115611620578283fd5b5061162d878288016113c3565b91505092959194509250565b60006020828403121561164a578081fd5b813567ffffffffffffffff811115611660578182fd5b6107398482850161136e565b60008060008060808587031215611681578182fd5b843567ffffffffffffffff80821115611698578384fd5b6116a48883890161136e565b95506020915081870135818111156116ba578485fd5b6116c689828a0161136e565b9550506040870135818111156116da578485fd5b8701601f810189136116ea578485fd5b80356116f861110882611fb9565b81815284810190838601868402850187018d1015611714578889fd5b8894505b8385101561173f57803561172b8161203e565b835260019490940193918601918601611718565b5096505050506060870135915080821115611758578283fd5b5061162d878288016112ba565b600060208284031215611776578081fd5b81518015158114610e37578182fd5b600060208284031215611796578081fd5b5051919050565b6000602082840312156117ae578081fd5b815167ffffffffffffffff808211156117c5578283fd5b90830190608082860312156117d8578283fd5b6117e26080611f95565b8251828111156117f0578485fd5b6117fc878286016110e8565b825250602083015182811115611810578485fd5b61181c87828601611314565b60208301525061182e604084016110dd565b6040820152606083015182811115611844578485fd5b6118508782860161140f565b60608301525095945050505050565b60008060408385031215611871578182fd5b825167ffffffffffffffff80821115611888578384fd5b9084019060a0828703121561189b578384fd5b6118a560a0611f95565b8251828111156118b3578586fd5b6118bf8882860161140f565b8252506020830151828111156118d3578586fd5b6118df8882860161115d565b6020830152506040830151828111156118f6578586fd5b6119028882860161115d565b604083015250606083015182811115611919578586fd5b61192588828601611314565b60608301525060808301518281111561193c578586fd5b61194888828601611201565b608083015250935061195f915050602084016110dd565b90509250929050565b6000815180845260208085019450808401835b838110156119a05781516001600160a01b03168752958201959082019060010161197b565b509495945050505050565b6000815180845260208085018081965082840281019150828601855b85811015611a30578284038952815180518086529086019086860190878102870188018a5b82811015611a1a57601f19898303018452611a08828651611ada565b948a0194938a019391506001016119ec565b509b88019b9650505091850191506001016119c7565b5091979650505050505050565b6000815180845260208085018081965082840281019150828601855b85811015611a30578284038952815180518086529086019086860190895b81811015611a9657835160ff1683529288019291880191600101611a77565b50509986019994505090840190600101611a59565b6000815180845260208085019450808401835b838110156119a057815187529582019590820190600101611abe565b60008151808452611af2816020860160208601611ff9565b601f01601f19169290920160200192915050565b60008251611b18818460208701611ff9565b9190910192915050565b6001600160a01b0391909116815260200190565b60006001600160a01b0384168252604060208301526107396040830184611ada565b60006001600160a01b03808616835280851660208401525060806040830152600a60808301527f464c42616c616e6365720000000000000000000000000000000000000000000060a083015260c06060830152611bb860c0830184611ada565b95945050505050565b60006001600160a01b038616825260806020830152611be36080830186611968565b8281036040840152611bf58186611aab565b90508281036060840152611c098185611ada565b979650505050505050565b6001600160a01b03929092168252602082015260400190565b90815260200190565b7fffffffff0000000000000000000000000000000000000000000000000000000091909116815260200190565b600060208252610e376020830184611ada565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526014908201527f6d73672e73656e646572206e6f74206f776e6572000000000000000000000000604082015260600190565b60208082526010908201527f556e74727573746564206c656e64657200000000000000000000000000000000604082015260600190565b60208082526014908201527f6d73672e73656e646572206e6f742061646d696e000000000000000000000000604082015260600190565b60208082526014908201527f57726f6e67207061796261636b20616d6f756e74000000000000000000000000604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60408201527f6f74207375636365656400000000000000000000000000000000000000000000606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b600060208252825160806020840152611e7060a0840182611968565b90506020840151601f1980858403016040860152611e8e8383611aab565b92506001600160a01b036040870151166060860152606086015191508085840301608086015250611bb88282611ada565b600060408252835160a06040840152611edb60e0840182611ada565b9050602080860151603f1980868503016060870152611efa84836119ab565b93506040880151915080868503016080870152611f1784836119ab565b6060890151878203830160a089015280518083529085019550869350908401905b80841015611f585785518252948401946001939093019290840190611f38565b5060808901519450818782030160c0880152611f748186611a3d565b9550505050848185015250509392505050565b60ff91909116815260200190565b60405181810167ffffffffffffffff81118282101715611fb157fe5b604052919050565b600067ffffffffffffffff821115611fcd57fe5b5060209081020190565b600067ffffffffffffffff821115611feb57fe5b50601f01601f191660200190565b60005b83811015612014578181015183820152602001611ffc565b83811115612023576000848401525b50505050565b6001600160a01b03811681146103d957600080fd5b60ff811681146103d957600080fdfe4164647265737320746f20776869636820746f6b656e732077696c6c2062652073656e7420746f2063616e2774206265206275726e2061646472657373a2646970667358221220dc0d57af7bcbf21b199502f46c9e9c1a33599febc23524eb21d14ebe3fe160b364736f6c63430007060033

Deployed Bytecode

0x60806040526004361061016a5760003560e01c80639864dcdd116100cb578063e910afb21161007f578063f829822d11610059578063f829822d1461035f578063f8e2fb0014610374578063fbfa77cf146103895761016a565b8063e910afb214610308578063f04f27071461032a578063f24ccbfe1461034a5761016a565b8063c579d490116100b0578063c579d490146102c0578063ca5ff780146102e0578063d3c2e7ed146102f35761016a565b80639864dcdd146102895780639ce3e9191461029e5761016a565b806341c0e1b5116101225780638237e538116101075780638237e5381461023d5780638bcb62161461025f5780638cedca71146102745761016a565b806341c0e1b5146102065780637b1039991461021b5761016a565b80631afd15be116101535780631afd15be146101c7578063247492f8146101dc5780632fa13cb8146101f15761016a565b80630336fd901461016f5780630f2eee42146101a5575b600080fd5b34801561017b57600080fd5b5061018f61018a366004611639565b61039e565b60405161019c9190611e54565b60405180910390f35b3480156101b157600080fd5b506101ba6103d4565b60405161019c9190611f87565b6101da6101d5366004611639565b6103d9565b005b3480156101e857600080fd5b506101ba6103dc565b3480156101fd57600080fd5b506101ba6103e1565b34801561021257600080fd5b506101da6103e6565b34801561022757600080fd5b506102306104a7565b60405161019c9190611b22565b34801561024957600080fd5b506102526104bf565b60405161019c9190611c2d565b34801561026b57600080fd5b506101ba6104e3565b34801561028057600080fd5b506102306104e8565b34801561029557600080fd5b506101ba610500565b3480156102aa57600080fd5b506102b3610505565b60405161019c9190611c36565b3480156102cc57600080fd5b506101da6102db36600461146e565b610529565b6102526102ee36600461166c565b610658565b3480156102ff57600080fd5b506101ba610741565b34801561031457600080fd5b5061031d610746565b60405161019c9190611c63565b34801561033657600080fd5b506101da610345366004611532565b61077f565b34801561035657600080fd5b50610230610afe565b34801561036b57600080fd5b5061031d610b16565b34801561038057600080fd5b5061031d610b32565b34801561039557600080fd5b50610230610b6b565b6103a66110ac565b816000815181106103b357fe5b60200260200101518060200190518101906103ce919061179d565b92915050565b608081565b50565b600090565b600081565b336001600160a01b031673ccf3d848e08b94478ed8f46ffead3008faf581fd6001600160a01b031663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b15801561043d57600080fd5b505afa158015610451573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104759190611452565b6001600160a01b0316146104a45760405162461bcd60e51b815260040161049b90611d1b565b60405180910390fd5b33ff5b73d6049e1f5f3eff1f921f5532af1a1632ba23929c81565b7f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd981565b600181565b73ccf3d848e08b94478ed8f46ffead3008faf581fd81565b607f81565b7fd6741b9e0000000000000000000000000000000000000000000000000000000081565b336001600160a01b031673ccf3d848e08b94478ed8f46ffead3008faf581fd6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561058057600080fd5b505afa158015610594573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b89190611452565b6001600160a01b0316146105de5760405162461bcd60e51b815260040161049b90611cad565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b038416141561063f576040516001600160a01b0383169082156108fc029083906000818181858888f19350505050158015610639573d6000803e3d6000fd5b50610653565b6106536001600160a01b0384168383610b83565b505050565b6000806106648661039e565b60408101519091506001600160a01b03161561070b5780604001516001600160a01b0316630ae1cc8e82606001516040518263ffffffff1660e01b81526004016106ae9190611c63565b60006040518083038186803b1580156106c657600080fd5b505afa1580156106da573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261070291908101906114ae565b50602083015281525b60008660018851038151811061071d57fe5b6020026020010151905060006107338383610c06565b93505050505b949350505050565b60ff81565b6040518060400160405280601881526020017f57726f6e672072657475726e20696e6465782076616c7565000000000000000081525081565b600260005414156107a25760405162461bcd60e51b815260040161049b90611e1d565b60026000553373ba12222222228d8ba445958a75a0704d566bf2c8146107da5760405162461bcd60e51b815260040161049b90611ce4565b600080828060200190518101906107f1919061185f565b9150915060005b865181101561084e576108458287838151811061081157fe5b602002602001015189848151811061082557fe5b60200260200101516001600160a01b0316610d4c9092919063ffffffff16565b506001016107f8565b506040517f4ccee9b600000000000000000000000000000000000000000000000000000000815260009073d6049e1f5f3eff1f921f5532af1a1632ba23929c90634ccee9b6906108c2907fcec38b05fe06a488e2de01744d7ff3b8ac89eb607661ed3d7a4b16544d0c7a7290600401611c2d565b60206040518083038186803b1580156108da57600080fd5b505afa1580156108ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109129190611452565b9050816001600160a01b0316631cff79cd478363d6741b9e60e01b876109698b60008151811061093e57fe5b60200260200101518d60008151811061095357fe5b6020026020010151610e1290919063ffffffff16565b60405160240161097a929190611ebf565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009485161790525160e086901b90921682526109ed9291600401611b36565b6020604051808303818588803b158015610a0657600080fd5b505af1158015610a1a573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610a3f9190611785565b5060005b8751811015610aef576000610a71878381518110610a5d57fe5b602002602001015189848151811061095357fe5b905080610aa3308b8581518110610a8457fe5b60200260200101516001600160a01b0316610e3e90919063ffffffff16565b14610ac05760405162461bcd60e51b815260040161049b90611d52565b610ae573ba12222222228d8ba445958a75a0704d566bf2c8828b858151811061082557fe5b5050600101610a43565b50506001600055505050505050565b735c55b921f590a89c1ebe84df170e655a82b6212681565b6040518060600160405280603d815260200161204e603d913981565b6040518060400160405280601581526020017f57726f6e672073756220696e6465782076616c7565000000000000000000000081525081565b73ba12222222228d8ba445958a75a0704d566bf2c881565b6106538363a9059cbb60e01b8484604051602401610ba2929190611c14565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610f12565b815160208301516040517f5c38449e00000000000000000000000000000000000000000000000000000000815260009273ba12222222228d8ba445958a75a0704d566bf2c892635c38449e92610c6492309290918890600401611bc1565b600060405180830381600087803b158015610c7e57600080fd5b505af1158015610c92573d6000803e3d6000fd5b50505050735c55b921f590a89c1ebe84df170e655a82b621266001600160a01b031663d061ce50303386604051602001610ccc9190611e54565b6040516020818303038152906040526040518463ffffffff1660e01b8152600401610cf993929190611b58565b600060405180830381600087803b158015610d1357600080fd5b505af1158015610d27573d6000803e3d6000fd5b505050508260200151600081518110610d3c57fe5b6020026020010151905092915050565b6000600019821415610d6557610d628430610e3e565b91505b6001600160a01b03831615801590610d8657506001600160a01b0383163014155b8015610d9157508115155b15610e0b576001600160a01b03841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610dd357610dce6001600160a01b0385168484610b83565b610e0b565b6040516001600160a01b0384169083156108fc029084906000818181858888f19350505050158015610e09573d6000803e3d6000fd5b505b5092915050565b600082820183811015610e375760405162461bcd60e51b815260040161049b90611c76565b9392505050565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415610e7657506001600160a01b038116316103ce565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b038416906370a0823190610ebb908590600401611b22565b60206040518083038186803b158015610ed357600080fd5b505afa158015610ee7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f0b9190611785565b90506103ce565b6000610f67826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610fa19092919063ffffffff16565b8051909150156106535780806020019051810190610f859190611765565b6106535760405162461bcd60e51b815260040161049b90611dc0565b606061073984846000856060610fb68561106e565b610fd25760405162461bcd60e51b815260040161049b90611d89565b600080866001600160a01b03168587604051610fee9190611b06565b60006040518083038185875af1925050503d806000811461102b576040519150601f19603f3d011682016040523d82523d6000602084013e611030565b606091505b509150915081156110445791506107399050565b8051156110545780518082602001fd5b8360405162461bcd60e51b815260040161049b9190611c63565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906110a257508115155b925050505b919050565b6040518060800160405280606081526020016060815260200160006001600160a01b03168152602001606081525090565b80516110a781612029565b600082601f8301126110f8578081fd5b8151602061110d61110883611fb9565b611f95565b8281528181019085830183850287018401881015611129578586fd5b855b8581101561115057815161113e81612029565b8452928401929084019060010161112b565b5090979650505050505050565b600082601f83011261116d578081fd5b8151602061117d61110883611fb9565b82815281810190858301855b85811015611150578151880189603f8201126111a3578788fd5b858101516111b361110882611fb9565b81815287810190604084018b5b848110156111ea576111d88f6040845189010161140f565b8452928a0192908a01906001016111c0565b505087525050509284019290840190600101611189565b600082601f830112611211578081fd5b8151602061122161110883611fb9565b82815281810190858301855b85811015611150578151880189603f820112611247578788fd5b85810151604061125961110883611fb9565b828152888101908483018a8502860184018f1015611275578c8dfd5b8c95505b848610156112a3578051935061128e8461203e565b83835260019590950194918a01918a01611279565b50885250505093850193509084019060010161122d565b600082601f8301126112ca578081fd5b813560206112da61110883611fb9565b82815281810190858301838502870184018810156112f6578586fd5b855b85811015611150578135845292840192908401906001016112f8565b600082601f830112611324578081fd5b8151602061133461110883611fb9565b8281528181019085830183850287018401881015611350578586fd5b855b8581101561115057815184529284019290840190600101611352565b600082601f83011261137e578081fd5b8135602061138e61110883611fb9565b82815281810190858301855b85811015611150576113b1898684358b01016113c3565b8452928401929084019060010161139a565b600082601f8301126113d3578081fd5b81356113e161110882611fd7565b8181528460208386010111156113f5578283fd5b816020850160208301379081016020019190915292915050565b600082601f83011261141f578081fd5b815161142d61110882611fd7565b818152846020838601011115611441578283fd5b610739826020830160208701611ff9565b600060208284031215611463578081fd5b8151610e3781612029565b600080600060608486031215611482578182fd5b833561148d81612029565b9250602084013561149d81612029565b929592945050506040919091013590565b6000806000606084860312156114c2578081fd5b835167ffffffffffffffff808211156114d9578283fd5b6114e5878388016110e8565b945060208601519150808211156114fa578283fd5b61150687838801611314565b9350604086015191508082111561151b578283fd5b5061152886828701611314565b9150509250925092565b60008060008060808587031215611547578182fd5b843567ffffffffffffffff8082111561155e578384fd5b818701915087601f830112611571578384fd5b8135602061158161110883611fb9565b82815281810190858301838502870184018d101561159d578889fd5b8896505b848710156115c85780356115b481612029565b8352600196909601959183019183016115a1565b50985050880135925050808211156115de578384fd5b6115ea888389016112ba565b945060408701359150808211156115ff578384fd5b61160b888389016112ba565b93506060870135915080821115611620578283fd5b5061162d878288016113c3565b91505092959194509250565b60006020828403121561164a578081fd5b813567ffffffffffffffff811115611660578182fd5b6107398482850161136e565b60008060008060808587031215611681578182fd5b843567ffffffffffffffff80821115611698578384fd5b6116a48883890161136e565b95506020915081870135818111156116ba578485fd5b6116c689828a0161136e565b9550506040870135818111156116da578485fd5b8701601f810189136116ea578485fd5b80356116f861110882611fb9565b81815284810190838601868402850187018d1015611714578889fd5b8894505b8385101561173f57803561172b8161203e565b835260019490940193918601918601611718565b5096505050506060870135915080821115611758578283fd5b5061162d878288016112ba565b600060208284031215611776578081fd5b81518015158114610e37578182fd5b600060208284031215611796578081fd5b5051919050565b6000602082840312156117ae578081fd5b815167ffffffffffffffff808211156117c5578283fd5b90830190608082860312156117d8578283fd5b6117e26080611f95565b8251828111156117f0578485fd5b6117fc878286016110e8565b825250602083015182811115611810578485fd5b61181c87828601611314565b60208301525061182e604084016110dd565b6040820152606083015182811115611844578485fd5b6118508782860161140f565b60608301525095945050505050565b60008060408385031215611871578182fd5b825167ffffffffffffffff80821115611888578384fd5b9084019060a0828703121561189b578384fd5b6118a560a0611f95565b8251828111156118b3578586fd5b6118bf8882860161140f565b8252506020830151828111156118d3578586fd5b6118df8882860161115d565b6020830152506040830151828111156118f6578586fd5b6119028882860161115d565b604083015250606083015182811115611919578586fd5b61192588828601611314565b60608301525060808301518281111561193c578586fd5b61194888828601611201565b608083015250935061195f915050602084016110dd565b90509250929050565b6000815180845260208085019450808401835b838110156119a05781516001600160a01b03168752958201959082019060010161197b565b509495945050505050565b6000815180845260208085018081965082840281019150828601855b85811015611a30578284038952815180518086529086019086860190878102870188018a5b82811015611a1a57601f19898303018452611a08828651611ada565b948a0194938a019391506001016119ec565b509b88019b9650505091850191506001016119c7565b5091979650505050505050565b6000815180845260208085018081965082840281019150828601855b85811015611a30578284038952815180518086529086019086860190895b81811015611a9657835160ff1683529288019291880191600101611a77565b50509986019994505090840190600101611a59565b6000815180845260208085019450808401835b838110156119a057815187529582019590820190600101611abe565b60008151808452611af2816020860160208601611ff9565b601f01601f19169290920160200192915050565b60008251611b18818460208701611ff9565b9190910192915050565b6001600160a01b0391909116815260200190565b60006001600160a01b0384168252604060208301526107396040830184611ada565b60006001600160a01b03808616835280851660208401525060806040830152600a60808301527f464c42616c616e6365720000000000000000000000000000000000000000000060a083015260c06060830152611bb860c0830184611ada565b95945050505050565b60006001600160a01b038616825260806020830152611be36080830186611968565b8281036040840152611bf58186611aab565b90508281036060840152611c098185611ada565b979650505050505050565b6001600160a01b03929092168252602082015260400190565b90815260200190565b7fffffffff0000000000000000000000000000000000000000000000000000000091909116815260200190565b600060208252610e376020830184611ada565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526014908201527f6d73672e73656e646572206e6f74206f776e6572000000000000000000000000604082015260600190565b60208082526010908201527f556e74727573746564206c656e64657200000000000000000000000000000000604082015260600190565b60208082526014908201527f6d73672e73656e646572206e6f742061646d696e000000000000000000000000604082015260600190565b60208082526014908201527f57726f6e67207061796261636b20616d6f756e74000000000000000000000000604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60408201527f6f74207375636365656400000000000000000000000000000000000000000000606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b600060208252825160806020840152611e7060a0840182611968565b90506020840151601f1980858403016040860152611e8e8383611aab565b92506001600160a01b036040870151166060860152606086015191508085840301608086015250611bb88282611ada565b600060408252835160a06040840152611edb60e0840182611ada565b9050602080860151603f1980868503016060870152611efa84836119ab565b93506040880151915080868503016080870152611f1784836119ab565b6060890151878203830160a089015280518083529085019550869350908401905b80841015611f585785518252948401946001939093019290840190611f38565b5060808901519450818782030160c0880152611f748186611a3d565b9550505050848185015250509392505050565b60ff91909116815260200190565b60405181810167ffffffffffffffff81118282101715611fb157fe5b604052919050565b600067ffffffffffffffff821115611fcd57fe5b5060209081020190565b600067ffffffffffffffff821115611feb57fe5b50601f01601f191660200190565b60005b83811015612014578181015183820152602001611ffc565b83811115612023576000848401525b50505050565b6001600160a01b03811681146103d957600080fd5b60ff811681146103d957600080fdfe4164647265737320746f20776869636820746f6b656e732077696c6c2062652073656e7420746f2063616e2774206265206275726e2061646472657373a2646970667358221220dc0d57af7bcbf21b199502f46c9e9c1a33599febc23524eb21d14ebe3fe160b364736f6c63430007060033

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
[ Download: CSV Export  ]

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.