ETH Price: $3,100.32 (-1.87%)

Contract

0x7E681F029b3c2FFA79c637963180E0D78626fB24
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x60c06040167415652023-03-02 14:47:35628 days ago1677768455IN
 Create: MorphoAaveV2SubProxy
0 ETH0.0490813229.15368022

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MorphoAaveV2SubProxy

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 10000 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2023-03-02
*/

// SPDX-License-Identifier: MIT

pragma solidity =0.8.10;





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 {
    //insufficient balance
    error InsufficientBalance(uint256 available, uint256 required);
    //unable to send value, recipient may have reverted
    error SendingValueFail();
    //insufficient balance for call
    error InsufficientBalanceForCall(uint256 available, uint256 required);
    //call to non-contract
    error NonContractCall();
    
    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 {
        uint256 balance = address(this).balance;
        if (balance < amount){
            revert InsufficientBalance(balance, amount);
        }

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{value: amount}("");
        if (!(success)){
            revert SendingValueFail();
        }
    }

    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) {
        uint256 balance = address(this).balance;
        if (balance < value){
            revert InsufficientBalanceForCall(balance, value);
        }
        return _functionCallWithValue(target, data, value, errorMessage);
    }

    function _functionCallWithValue(
        address target,
        bytes memory data,
        uint256 weiValue,
        string memory errorMessage
    ) private returns (bytes memory) {
        if (!(isContract(target))){
            revert NonContractCall();
        }

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





abstract contract IDFSRegistry {
 
    function getAddr(bytes4 _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;
}





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;

    error SenderNotAdmin();

    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 {
        if (admin != msg.sender){
            revert SenderNotAdmin();
        }
        owner = _owner;
    }

    /// @notice Admin is able to set new admin
    /// @param _admin Address of multisig that becomes new admin
    function changeAdmin(address _admin) public {
        if (admin != msg.sender){
            revert SenderNotAdmin();
        }
        admin = _admin;
    }

}








contract AdminAuth is AuthHelper {
    using SafeERC20 for IERC20;

    AdminVault public constant adminVault = AdminVault(ADMIN_VAULT_ADDR);

    error SenderNotOwner();
    error SenderNotAdmin();

    modifier onlyOwner() {
        if (adminVault.owner() != msg.sender){
            revert SenderNotOwner();
        }
        _;
    }

    modifier onlyAdmin() {
        if (adminVault.admin() != msg.sender){
            revert SenderNotAdmin();
        }
        _;
    }

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





abstract contract DSGuard {
    function canCall(
        address src_,
        address dst_,
        bytes4 sig
    ) public view virtual returns (bool);

    function permit(
        bytes32 src,
        bytes32 dst,
        bytes32 sig
    ) public virtual;

    function forbid(
        bytes32 src,
        bytes32 dst,
        bytes32 sig
    ) public virtual;

    function permit(
        address src,
        address dst,
        bytes32 sig
    ) public virtual;

    function forbid(
        address src,
        address dst,
        bytes32 sig
    ) public virtual;
}

abstract contract DSGuardFactory {
    function newGuard() public virtual returns (DSGuard guard);
}





abstract contract DSAuthority {
    function canCall(
        address src,
        address dst,
        bytes4 sig
    ) public view virtual returns (bool);
}





contract DSAuthEvents {
    event LogSetAuthority(address indexed authority);
    event LogSetOwner(address indexed owner);
}

contract DSAuth is DSAuthEvents {
    DSAuthority public authority;
    address public owner;

    constructor() {
        owner = msg.sender;
        emit LogSetOwner(msg.sender);
    }

    function setOwner(address owner_) public auth {
        owner = owner_;
        emit LogSetOwner(owner);
    }

    function setAuthority(DSAuthority authority_) public auth {
        authority = authority_;
        emit LogSetAuthority(address(authority));
    }

    modifier auth {
        require(isAuthorized(msg.sender, msg.sig), "Not authorized");
        _;
    }

    function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
        if (src == address(this)) {
            return true;
        } else if (src == owner) {
            return true;
        } else if (authority == DSAuthority(address(0))) {
            return false;
        } else {
            return authority.canCall(src, address(this), sig);
        }
    }
}






contract ProxyPermission is AuthHelper {

    bytes4 public constant EXECUTE_SELECTOR = bytes4(keccak256("execute(address,bytes)"));

    /// @notice Called in the context of DSProxy to authorize an address
    /// @param _contractAddr Address which will be authorized
    function givePermission(address _contractAddr) public {
        address currAuthority = address(DSAuth(address(this)).authority());
        DSGuard guard = DSGuard(currAuthority);

        if (currAuthority == address(0)) {
            guard = DSGuardFactory(FACTORY_ADDRESS).newGuard();
            DSAuth(address(this)).setAuthority(DSAuthority(address(guard)));
        }

        if (!guard.canCall(_contractAddr, address(this), EXECUTE_SELECTOR)) {
            guard.permit(_contractAddr, address(this), EXECUTE_SELECTOR);
        }
    }

    /// @notice Called in the context of DSProxy to remove authority of an address
    /// @param _contractAddr Auth address which will be removed from authority list
    function removePermission(address _contractAddr) public {
        address currAuthority = address(DSAuth(address(this)).authority());

        // if there is no authority, that means that contract doesn't have permission
        if (currAuthority == address(0)) {
            return;
        }

        DSGuard guard = DSGuard(currAuthority);
        guard.forbid(_contractAddr, address(this), EXECUTE_SELECTOR);
    }
}





contract DFSRegistry is AdminAuth {
    error EntryAlreadyExistsError(bytes4);
    error EntryNonExistentError(bytes4);
    error EntryNotInChangeError(bytes4);
    error ChangeNotReadyError(uint256,uint256);
    error EmptyPrevAddrError(bytes4);
    error AlreadyInContractChangeError(bytes4);
    error AlreadyInWaitPeriodChangeError(bytes4);

    event AddNewContract(address,bytes4,address,uint256);
    event RevertToPreviousAddress(address,bytes4,address,address);
    event StartContractChange(address,bytes4,address,address);
    event ApproveContractChange(address,bytes4,address,address);
    event CancelContractChange(address,bytes4,address,address);
    event StartWaitPeriodChange(address,bytes4,uint256);
    event ApproveWaitPeriodChange(address,bytes4,uint256,uint256);
    event CancelWaitPeriodChange(address,bytes4,uint256,uint256);

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

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

    mapping(bytes4 => address) public pendingAddresses;
    mapping(bytes4 => 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(bytes4 _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(bytes4 _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(
        bytes4 _id,
        address _contractAddr,
        uint256 _waitPeriod
    ) public onlyOwner {
        if (entries[_id].exists){
            revert EntryAlreadyExistsError(_id);
        }

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

        emit AddNewContract(msg.sender, _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(bytes4 _id) public onlyOwner {
        if (!(entries[_id].exists)){
            revert EntryNonExistentError(_id);
        }
        if (previousAddresses[_id] == address(0)){
            revert EmptyPrevAddrError(_id);
        }

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

        emit RevertToPreviousAddress(msg.sender, _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(bytes4 _id, address _newContractAddr) public onlyOwner {
        if (!entries[_id].exists){
            revert EntryNonExistentError(_id);
        }
        if (entries[_id].inWaitPeriodChange){
            revert AlreadyInWaitPeriodChangeError(_id);
        }

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

        pendingAddresses[_id] = _newContractAddr;

        emit StartContractChange(msg.sender, _id, entries[_id].contractAddr, _newContractAddr);
    }

    /// @notice Changes new contract address, correct time must have passed
    /// @param _id Id of contract
    function approveContractChange(bytes4 _id) public onlyOwner {
        if (!entries[_id].exists){
            revert EntryNonExistentError(_id);
        }
        if (!entries[_id].inContractChange){
            revert EntryNotInChangeError(_id);
        }
        if (block.timestamp < (entries[_id].changeStartTime + entries[_id].waitPeriod)){// solhint-disable-line
            revert ChangeNotReadyError(block.timestamp, (entries[_id].changeStartTime + entries[_id].waitPeriod));
        }

        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;

        emit ApproveContractChange(msg.sender, _id, oldContractAddr, entries[_id].contractAddr);
    }

    /// @notice Cancel pending change
    /// @param _id Id of contract
    function cancelContractChange(bytes4 _id) public onlyOwner {
        if (!entries[_id].exists){
            revert EntryNonExistentError(_id);
        }
        if (!entries[_id].inContractChange){
            revert EntryNotInChangeError(_id);
        }

        address oldContractAddr = pendingAddresses[_id];

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

        emit CancelContractChange(msg.sender, _id, oldContractAddr, entries[_id].contractAddr);
    }

    /// @notice Starts the change for waitPeriod
    /// @param _id Id of contract
    /// @param _newWaitPeriod New wait time
    function startWaitPeriodChange(bytes4 _id, uint256 _newWaitPeriod) public onlyOwner {
        if (!entries[_id].exists){
            revert EntryNonExistentError(_id);
        }
        if (entries[_id].inContractChange){
            revert AlreadyInContractChangeError(_id);
        }

        pendingWaitTimes[_id] = _newWaitPeriod;

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

        emit StartWaitPeriodChange(msg.sender, _id, _newWaitPeriod);
    }

    /// @notice Changes new wait period, correct time must have passed
    /// @param _id Id of contract
    function approveWaitPeriodChange(bytes4 _id) public onlyOwner {
        if (!entries[_id].exists){
            revert EntryNonExistentError(_id);
        }
        if (!entries[_id].inWaitPeriodChange){
            revert EntryNotInChangeError(_id);
        }
        if (block.timestamp < (entries[_id].changeStartTime + entries[_id].waitPeriod)){ // solhint-disable-line
            revert ChangeNotReadyError(block.timestamp, (entries[_id].changeStartTime + entries[_id].waitPeriod));
        }

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

        pendingWaitTimes[_id] = 0;

        emit ApproveWaitPeriodChange(msg.sender, _id, oldWaitTime, entries[_id].waitPeriod);
    }

    /// @notice Cancel wait period change
    /// @param _id Id of contract
    function cancelWaitPeriodChange(bytes4 _id) public onlyOwner {
        if (!entries[_id].exists){
            revert EntryNonExistentError(_id);
        }
        if (!entries[_id].inWaitPeriodChange){
            revert EntryNotInChangeError(_id);
        }

        uint256 oldWaitPeriod = pendingWaitTimes[_id];

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

        emit CancelWaitPeriodChange(msg.sender, _id, oldWaitPeriod, entries[_id].waitPeriod);
    }
}





contract StrategyModel {
        
    /// @dev Group of strategies bundled together so user can sub to multiple strategies at once
    /// @param creator Address of the user who created the bundle
    /// @param strategyIds Array of strategy ids stored in StrategyStorage
    struct StrategyBundle {
        address creator;
        uint64[] strategyIds;
    }

    /// @dev Template/Class which defines a Strategy
    /// @param name Name of the strategy useful for logging what strategy is executing
    /// @param creator Address of the user which created the strategy
    /// @param triggerIds Array of identifiers for trigger - bytes4(keccak256(TriggerName))
    /// @param actionIds Array of identifiers for actions - bytes4(keccak256(ActionName))
    /// @param paramMapping Describes how inputs to functions are piped from return/subbed values
    /// @param continuous If the action is repeated (continuos) or one time
    struct Strategy {
        string name;
        address creator;
        bytes4[] triggerIds;
        bytes4[] actionIds;
        uint8[][] paramMapping;
        bool continuous;
    }

    /// @dev List of actions grouped as a recipe
    /// @param name Name of the recipe useful for logging what recipe is executing
    /// @param callData Array of calldata inputs to each action
    /// @param subData Used only as part of strategy, subData injected from StrategySub.subData
    /// @param actionIds Array of identifiers for actions - bytes4(keccak256(ActionName))
    /// @param paramMapping Describes how inputs to functions are piped from return/subbed values
    struct Recipe {
        string name;
        bytes[] callData;
        bytes32[] subData;
        bytes4[] actionIds;
        uint8[][] paramMapping;
    }

    /// @dev Actual data of the sub we store on-chain
    /// @dev In order to save on gas we store a keccak256(StrategySub) and verify later on
    /// @param userProxy Address of the users smart wallet/proxy
    /// @param isEnabled Toggle if the subscription is active
    /// @param strategySubHash Hash of the StrategySub data the user inputted
    struct StoredSubData {
        bytes20 userProxy; // address but put in bytes20 for gas savings
        bool isEnabled;
        bytes32 strategySubHash;
    }

    /// @dev Instance of a strategy, user supplied data
    /// @param strategyOrBundleId Id of the strategy or bundle, depending on the isBundle bool
    /// @param isBundle If true the id points to bundle, if false points directly to strategyId
    /// @param triggerData User supplied data needed for checking trigger conditions
    /// @param subData User supplied data used in recipe
    struct StrategySub {
        uint64 strategyOrBundleId;
        bool isBundle;
        bytes[] triggerData;
        bytes32[] subData;
    }
}






contract StrategyStorage is StrategyModel, AdminAuth {

    Strategy[] public strategies;
    bool public openToPublic = false;

    error NoAuthToCreateStrategy(address,bool);
    event StrategyCreated(uint256 indexed strategyId);

    modifier onlyAuthCreators {
        if (adminVault.owner() != msg.sender && openToPublic == false) {
            revert NoAuthToCreateStrategy(msg.sender, openToPublic);
        }

        _;
    }

    /// @notice Creates a new strategy and writes the data in an array
    /// @dev Can only be called by auth addresses if it's not open to public
    /// @param _name Name of the strategy useful for logging what strategy is executing
    /// @param _triggerIds Array of identifiers for trigger - bytes4(keccak256(TriggerName))
    /// @param _actionIds Array of identifiers for actions - bytes4(keccak256(ActionName))
    /// @param _paramMapping Describes how inputs to functions are piped from return/subbed values
    /// @param _continuous If the action is repeated (continuos) or one time
    function createStrategy(
        string memory _name,
        bytes4[] memory _triggerIds,
        bytes4[] memory _actionIds,
        uint8[][] memory _paramMapping,
        bool _continuous
    ) public onlyAuthCreators returns (uint256) {
        strategies.push(Strategy({
                name: _name,
                creator: msg.sender,
                triggerIds: _triggerIds,
                actionIds: _actionIds,
                paramMapping: _paramMapping,
                continuous : _continuous
        }));

        emit StrategyCreated(strategies.length - 1);

        return strategies.length - 1;
    }

    /// @notice Switch to determine if bundles can be created by anyone
    /// @dev Callable only by the owner
    /// @param _openToPublic Flag if true anyone can create bundles
    function changeEditPermission(bool _openToPublic) public onlyOwner {
        openToPublic = _openToPublic;
    }

    ////////////////////////////// VIEW METHODS /////////////////////////////////

    function getStrategy(uint _strategyId) public view returns (Strategy memory) {
        return strategies[_strategyId];
    }
    function getStrategyCount() public view returns (uint256) {
        return strategies.length;
    }

    function getPaginatedStrategies(uint _page, uint _perPage) public view returns (Strategy[] memory) {
        Strategy[] memory strategiesPerPage = new Strategy[](_perPage);

        uint start = _page * _perPage;
        uint end = start + _perPage;

        end = (end > strategies.length) ? strategies.length : end;

        uint count = 0;
        for (uint i = start; i < end; i++) {
            strategiesPerPage[count] = strategies[i];
            count++;
        }

        return strategiesPerPage;
    }

}





contract MainnetCoreAddresses {
    address internal constant REGISTRY_ADDR = 0x287778F121F134C66212FB16c9b53eC991D32f5b;
    address internal constant PROXY_AUTH_ADDR = 0x149667b6FAe2c63D1B4317C716b0D0e4d3E2bD70;
    address internal constant DEFISAVER_LOGGER = 0xcE7a977Cac4a481bc84AC06b2Da0df614e621cf3;

    address internal constant SUB_STORAGE_ADDR = 0x1612fc28Ee0AB882eC99842Cde0Fc77ff0691e90;
    address internal constant BUNDLE_STORAGE_ADDR = 0x223c6aDE533851Df03219f6E3D8B763Bd47f84cf;
    address internal constant STRATEGY_STORAGE_ADDR = 0xF52551F95ec4A2B4299DcC42fbbc576718Dbf933;

    address constant internal RECIPE_EXECUTOR_ADDR = 0x1D6DEdb49AF91A11B5C5F34954FD3E8cC4f03A86;
}





contract CoreHelper is MainnetCoreAddresses {
}









contract BundleStorage is StrategyModel, AdminAuth, CoreHelper {

    DFSRegistry public constant registry = DFSRegistry(REGISTRY_ADDR);

    StrategyBundle[] public bundles;
    bool public openToPublic = false;

    error NoAuthToCreateBundle(address,bool);
    error DiffTriggersInBundle(uint64[]);

    event BundleCreated(uint256 indexed bundleId);

    modifier onlyAuthCreators {
        if (adminVault.owner() != msg.sender && openToPublic == false) {
            revert NoAuthToCreateBundle(msg.sender, openToPublic);
        }

        _;
    }

    /// @dev Checks if the triggers in strategies are the same (order also relevant)
    /// @dev If the caller is not owner we do additional checks, we skip those checks for gas savings
    modifier sameTriggers(uint64[] memory _strategyIds) {
        if (msg.sender != adminVault.owner()) {
            Strategy memory firstStrategy = StrategyStorage(STRATEGY_STORAGE_ADDR).getStrategy(_strategyIds[0]);

            bytes32 firstStrategyTriggerHash = keccak256(abi.encode(firstStrategy.triggerIds));

            for (uint256 i = 1; i < _strategyIds.length; ++i) {
                Strategy memory s = StrategyStorage(STRATEGY_STORAGE_ADDR).getStrategy(_strategyIds[i]);

                if (firstStrategyTriggerHash != keccak256(abi.encode(s.triggerIds))) {
                    revert DiffTriggersInBundle(_strategyIds);
                }
            }
        }

        _;
    }

    /// @notice Adds a new bundle to array
    /// @dev Can only be called by auth addresses if it's not open to public
    /// @dev Strategies need to have the same number of triggers and ids exists
    /// @param _strategyIds Array of strategyIds that go into a bundle
    function createBundle(
        uint64[] memory _strategyIds
    ) public onlyAuthCreators sameTriggers(_strategyIds) returns (uint256) {

        bundles.push(StrategyBundle({
            creator: msg.sender,
            strategyIds: _strategyIds
        }));

        emit BundleCreated(bundles.length - 1);

        return bundles.length - 1;
    }

    /// @notice Switch to determine if bundles can be created by anyone
    /// @dev Callable only by the owner
    /// @param _openToPublic Flag if true anyone can create bundles
    function changeEditPermission(bool _openToPublic) public onlyOwner {
        openToPublic = _openToPublic;
    }

    ////////////////////////////// VIEW METHODS /////////////////////////////////

    function getStrategyId(uint256 _bundleId, uint256 _strategyIndex) public view returns (uint256) {
        return bundles[_bundleId].strategyIds[_strategyIndex];
    }

    function getBundle(uint _bundleId) public view returns (StrategyBundle memory) {
        return bundles[_bundleId];
    }
    function getBundleCount() public view returns (uint256) {
        return bundles.length;
    }

    function getPaginatedBundles(uint _page, uint _perPage) public view returns (StrategyBundle[] memory) {
        StrategyBundle[] memory bundlesPerPage = new StrategyBundle[](_perPage);
        uint start = _page * _perPage;
        uint end = start + _perPage;

        end = (end > bundles.length) ? bundles.length : end;

        uint count = 0;
        for (uint i = start; i < end; i++) {
            bundlesPerPage[count] = bundles[i];
            count++;
        }

        return bundlesPerPage;
    }

}









contract SubStorage is StrategyModel, AdminAuth, CoreHelper {
    error SenderNotSubOwnerError(address, uint256);
    error SubIdOutOfRange(uint256, bool);

    event Subscribe(uint256 indexed subId, address indexed proxy, bytes32 indexed subHash, StrategySub subStruct);
    event UpdateData(uint256 indexed subId, bytes32 indexed subHash, StrategySub subStruct);
    event ActivateSub(uint256 indexed subId);
    event DeactivateSub(uint256 indexed subId);

    DFSRegistry public constant registry = DFSRegistry(REGISTRY_ADDR);

    StoredSubData[] public strategiesSubs;

    /// @notice Checks if subId is init. and if the sender is the owner
    modifier onlySubOwner(uint256 _subId) {
        if (address(strategiesSubs[_subId].userProxy) != msg.sender) {
            revert SenderNotSubOwnerError(msg.sender, _subId);
        }
        _;
    }

    /// @notice Checks if the id is valid (points to a stored bundle/sub)
    modifier isValidId(uint256 _id, bool _isBundle) {
        if (_isBundle) {
            if (_id > (BundleStorage(BUNDLE_STORAGE_ADDR).getBundleCount() - 1)) {
                revert SubIdOutOfRange(_id, _isBundle);
            }
        } else {
            if (_id > (StrategyStorage(STRATEGY_STORAGE_ADDR).getStrategyCount() - 1)) {
                revert SubIdOutOfRange(_id, _isBundle);
            }
        }

        _;
    }

    /// @notice Adds users info and records StoredSubData, logs StrategySub
    /// @dev To save on gas we don't store the whole struct but rather the hash of the struct
    /// @param _sub Subscription struct of the user (is not stored on chain, only the hash)
    function subscribeToStrategy(
        StrategySub memory _sub
    ) public isValidId(_sub.strategyOrBundleId, _sub.isBundle) returns (uint256) {

        bytes32 subStorageHash = keccak256(abi.encode(_sub));

        strategiesSubs.push(StoredSubData(
            bytes20(msg.sender),
            true,
            subStorageHash
        ));

        uint256 currentId = strategiesSubs.length - 1;

        emit Subscribe(currentId, msg.sender, subStorageHash, _sub);

        return currentId;
    }

    /// @notice Updates the users subscription data
    /// @dev Only callable by proxy who created the sub.
    /// @param _subId Id of the subscription to update
    /// @param _sub Subscription struct of the user (needs whole struct so we can hash it)
    function updateSubData(
        uint256 _subId,
        StrategySub calldata _sub
    ) public onlySubOwner(_subId) isValidId(_sub.strategyOrBundleId, _sub.isBundle)  {
        StoredSubData storage storedSubData = strategiesSubs[_subId];

        bytes32 subStorageHash = keccak256(abi.encode(_sub));

        storedSubData.strategySubHash = subStorageHash;

        emit UpdateData(_subId, subStorageHash, _sub);
    }

    /// @notice Enables the subscription for execution if disabled
    /// @dev Must own the sub. to be able to enable it
    /// @param _subId Id of subscription to enable
    function activateSub(
        uint _subId
    ) public onlySubOwner(_subId) {
        StoredSubData storage sub = strategiesSubs[_subId];

        sub.isEnabled = true;

        emit ActivateSub(_subId);
    }

    /// @notice Disables the subscription (will not be able to execute the strategy for the user)
    /// @dev Must own the sub. to be able to disable it
    /// @param _subId Id of subscription to disable
    function deactivateSub(
        uint _subId
    ) public onlySubOwner(_subId) {
        StoredSubData storage sub = strategiesSubs[_subId];

        sub.isEnabled = false;

        emit DeactivateSub(_subId);
    }

    ///////////////////// VIEW ONLY FUNCTIONS ////////////////////////////

    function getSub(uint _subId) public view returns (StoredSubData memory) {
        return strategiesSubs[_subId];
    }

    function getSubsCount() public view returns (uint256) {
        return strategiesSubs.length;
    }
}







contract MorphoAaveV2SubProxy is StrategyModel, AdminAuth, ProxyPermission, CoreHelper {
    uint64 public immutable REPAY_BUNDLE_ID;
    uint64 public immutable BOOST_BUNDLE_ID;

    constructor(uint64 _repayBundleId, uint64 _boostBundleId) {
        REPAY_BUNDLE_ID = _repayBundleId;
        BOOST_BUNDLE_ID = _boostBundleId;
    }

    enum RatioState { OVER, UNDER }

    /// @dev 5% offset acceptable
    uint256 internal constant RATIO_OFFSET = 50000000000000000;

    error WrongSubParams(uint256 minRatio, uint256 maxRatio);
    error RangeTooClose(uint256 ratio, uint256 targetRatio);

    struct MorphoAaveV2SubData {
        uint128 minRatio;
        uint128 maxRatio;
        uint128 targetRatioBoost;
        uint128 targetRatioRepay;
        bool boostEnabled;
    }

    /// @notice Parses input data and subscribes user to repay and boost bundles
    /// @dev Gives DSProxy permission if needed and registers a new sub
    /// @dev If boostEnabled = false it will only create a repay bundle
    /// @dev User can't just sub a boost bundle without repay
    function subToMorphoAaveV2Automation(
        MorphoAaveV2SubData calldata _subData
    ) public {
        givePermission(PROXY_AUTH_ADDR);
        StrategySub memory repaySub = formatRepaySub(_subData, address(this));

        SubStorage(SUB_STORAGE_ADDR).subscribeToStrategy(repaySub);
        if (_subData.boostEnabled) {
            _validateSubData(_subData);

            StrategySub memory boostSub = formatBoostSub(_subData, address(this));
            SubStorage(SUB_STORAGE_ADDR).subscribeToStrategy(boostSub);
        }
    }

    /// @notice Calls SubStorage to update the users subscription data
    /// @dev Updating sub data will activate it as well
    /// @dev If we don't have a boost subId send as 0
    function updateSubData(
        uint32 _subId1,
        uint32 _subId2,
        MorphoAaveV2SubData calldata _subData
    ) public {

        // update repay as we must have a subId, it's ok if it's the same data
        StrategySub memory repaySub = formatRepaySub(_subData, address(this));
        SubStorage(SUB_STORAGE_ADDR).updateSubData(_subId1, repaySub);
        SubStorage(SUB_STORAGE_ADDR).activateSub(_subId1);

        if (_subData.boostEnabled) {
            _validateSubData(_subData);

            StrategySub memory boostSub = formatBoostSub(_subData, address(this));

            // if we don't have a boost bundleId, create one
            if (_subId2 == 0) {
                SubStorage(SUB_STORAGE_ADDR).subscribeToStrategy(boostSub);
            } else {
                SubStorage(SUB_STORAGE_ADDR).updateSubData(_subId2, boostSub);
                SubStorage(SUB_STORAGE_ADDR).activateSub(_subId2);
            }
        } else {
            if (_subId2 != 0) {
                SubStorage(SUB_STORAGE_ADDR).deactivateSub(_subId2);
            }
        }
    }

    /// @notice Activates Repay sub and if exists a Boost sub
    function activateSub(
        uint32 _subId1,
        uint32 _subId2
    ) public {
        SubStorage(SUB_STORAGE_ADDR).activateSub(_subId1);

        if (_subId2 != 0) {
            SubStorage(SUB_STORAGE_ADDR).activateSub(_subId2);
        }
    }

    /// @notice Deactivates Repay sub and if exists a Boost sub
    function deactivateSub(
        uint32 _subId1,
        uint32 _subId2
    ) public {
        SubStorage(SUB_STORAGE_ADDR).deactivateSub(_subId1);

        if (_subId2 != 0) {
            SubStorage(SUB_STORAGE_ADDR).deactivateSub(_subId2);
        }
    }


    ///////////////////////////////// HELPER FUNCTIONS /////////////////////////////////

    function _validateSubData(MorphoAaveV2SubData memory _subData) internal pure {
        if (_subData.minRatio > _subData.maxRatio) {
            revert WrongSubParams(_subData.minRatio, _subData.maxRatio);
        }

        if ((_subData.maxRatio - RATIO_OFFSET) < _subData.targetRatioRepay) {
            revert RangeTooClose(_subData.maxRatio, _subData.targetRatioRepay);
        }

        if ((_subData.minRatio + RATIO_OFFSET) > _subData.targetRatioBoost) {
            revert RangeTooClose(_subData.minRatio, _subData.targetRatioBoost);
        }
    }

    /// @notice Formats a StrategySub struct to a Repay bundle from the input data of the specialized morphoAaveV2 sub
    function formatRepaySub(MorphoAaveV2SubData memory _subData, address _proxy) public view returns (StrategySub memory repaySub) {
        repaySub.strategyOrBundleId = REPAY_BUNDLE_ID;
        repaySub.isBundle = true;

        // format data for ratio trigger if currRatio < minRatio = true
        bytes memory triggerData = abi.encode(_proxy, uint256(_subData.minRatio), uint8(RatioState.UNDER));
        repaySub.triggerData =  new bytes[](1);
        repaySub.triggerData[0] = triggerData;

        repaySub.subData =  new bytes32[](2);
        repaySub.subData[0] = bytes32(uint256(1)); // ratioState = repay
        repaySub.subData[1] = bytes32(uint256(_subData.targetRatioRepay)); // targetRatio
    }

    /// @notice Formats a StrategySub struct to a Boost bundle from the input data of the specialized morphoAaveV2 sub
    function formatBoostSub(MorphoAaveV2SubData memory _subData, address _proxy) public view returns (StrategySub memory boostSub) {
        boostSub.strategyOrBundleId = BOOST_BUNDLE_ID;
        boostSub.isBundle = true;

        // format data for ratio trigger if currRatio > maxRatio = true
        bytes memory triggerData = abi.encode(_proxy, uint256(_subData.maxRatio), uint8(RatioState.OVER));
        boostSub.triggerData =  new bytes[](1);
        boostSub.triggerData[0] = triggerData;

        boostSub.subData =  new bytes32[](2);
        boostSub.subData[0] = bytes32(uint256(0)); // ratioState = boost
        boostSub.subData[1] = bytes32(uint256(_subData.targetRatioBoost)); // targetRatio
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint64","name":"_repayBundleId","type":"uint64"},{"internalType":"uint64","name":"_boostBundleId","type":"uint64"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"NonContractCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"ratio","type":"uint256"},{"internalType":"uint256","name":"targetRatio","type":"uint256"}],"name":"RangeTooClose","type":"error"},{"inputs":[],"name":"SenderNotAdmin","type":"error"},{"inputs":[],"name":"SenderNotOwner","type":"error"},{"inputs":[{"internalType":"uint256","name":"minRatio","type":"uint256"},{"internalType":"uint256","name":"maxRatio","type":"uint256"}],"name":"WrongSubParams","type":"error"},{"inputs":[],"name":"BOOST_BUNDLE_ID","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXECUTE_SELECTOR","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REPAY_BUNDLE_ID","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_subId1","type":"uint32"},{"internalType":"uint32","name":"_subId2","type":"uint32"}],"name":"activateSub","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"adminVault","outputs":[{"internalType":"contract AdminVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_subId1","type":"uint32"},{"internalType":"uint32","name":"_subId2","type":"uint32"}],"name":"deactivateSub","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"minRatio","type":"uint128"},{"internalType":"uint128","name":"maxRatio","type":"uint128"},{"internalType":"uint128","name":"targetRatioBoost","type":"uint128"},{"internalType":"uint128","name":"targetRatioRepay","type":"uint128"},{"internalType":"bool","name":"boostEnabled","type":"bool"}],"internalType":"struct MorphoAaveV2SubProxy.MorphoAaveV2SubData","name":"_subData","type":"tuple"},{"internalType":"address","name":"_proxy","type":"address"}],"name":"formatBoostSub","outputs":[{"components":[{"internalType":"uint64","name":"strategyOrBundleId","type":"uint64"},{"internalType":"bool","name":"isBundle","type":"bool"},{"internalType":"bytes[]","name":"triggerData","type":"bytes[]"},{"internalType":"bytes32[]","name":"subData","type":"bytes32[]"}],"internalType":"struct StrategyModel.StrategySub","name":"boostSub","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"minRatio","type":"uint128"},{"internalType":"uint128","name":"maxRatio","type":"uint128"},{"internalType":"uint128","name":"targetRatioBoost","type":"uint128"},{"internalType":"uint128","name":"targetRatioRepay","type":"uint128"},{"internalType":"bool","name":"boostEnabled","type":"bool"}],"internalType":"struct MorphoAaveV2SubProxy.MorphoAaveV2SubData","name":"_subData","type":"tuple"},{"internalType":"address","name":"_proxy","type":"address"}],"name":"formatRepaySub","outputs":[{"components":[{"internalType":"uint64","name":"strategyOrBundleId","type":"uint64"},{"internalType":"bool","name":"isBundle","type":"bool"},{"internalType":"bytes[]","name":"triggerData","type":"bytes[]"},{"internalType":"bytes32[]","name":"subData","type":"bytes32[]"}],"internalType":"struct StrategyModel.StrategySub","name":"repaySub","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_contractAddr","type":"address"}],"name":"givePermission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"kill","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_contractAddr","type":"address"}],"name":"removePermission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"minRatio","type":"uint128"},{"internalType":"uint128","name":"maxRatio","type":"uint128"},{"internalType":"uint128","name":"targetRatioBoost","type":"uint128"},{"internalType":"uint128","name":"targetRatioRepay","type":"uint128"},{"internalType":"bool","name":"boostEnabled","type":"bool"}],"internalType":"struct MorphoAaveV2SubProxy.MorphoAaveV2SubData","name":"_subData","type":"tuple"}],"name":"subToMorphoAaveV2Automation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_subId1","type":"uint32"},{"internalType":"uint32","name":"_subId2","type":"uint32"},{"components":[{"internalType":"uint128","name":"minRatio","type":"uint128"},{"internalType":"uint128","name":"maxRatio","type":"uint128"},{"internalType":"uint128","name":"targetRatioBoost","type":"uint128"},{"internalType":"uint128","name":"targetRatioRepay","type":"uint128"},{"internalType":"bool","name":"boostEnabled","type":"bool"}],"internalType":"struct MorphoAaveV2SubProxy.MorphoAaveV2SubData","name":"_subData","type":"tuple"}],"name":"updateSubData","outputs":[],"stateMutability":"nonpayable","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"}]

60c06040523480156200001157600080fd5b5060405162001e7d38038062001e7d833981016040819052620000349162000069565b6001600160401b039182166080521660a052620000a1565b80516001600160401b03811681146200006457600080fd5b919050565b600080604083850312156200007d57600080fd5b62000088836200004c565b915062000098602084016200004c565b90509250929050565b60805160a051611da8620000d5600039600081816102210152610ae001526000818161010901526107e80152611da86000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80639f6197b71161008c578063e074bb4711610066578063e074bb4714610269578063f0c56eed1461027c578063f20311f01461028f578063fd6bf387146102a257600080fd5b80639f6197b71461021c578063c579d49014610243578063cb8076391461025657600080fd5b806341c0e1b5116100c857806341c0e1b51461015c5780637210cf961461016457806385d63353146101845780638cedca71146101dc57600080fd5b80632fc044de146100ef578063369465a1146101045780633d391f7014610149575b600080fd5b6101026100fd366004611838565b6102b5565b005b61012b7f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020015b60405180910390f35b61010261015736600461188d565b6103cf565b6101026106da565b61017761017236600461199a565b6107c4565b6040516101409190611b3f565b6101ab7f1cff79cde515a86f6cc1adbebe8ae25888905561371faf11c8102211f56b487081565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610140565b6101f773ccf3d848e08b94478ed8f46ffead3008faf581fd81565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610140565b61012b7f000000000000000000000000000000000000000000000000000000000000000081565b610102610251366004611b52565b610939565b61017761026436600461199a565b610abc565b61010261027736600461188d565b610c1f565b61010261028a366004611bab565b610d34565b61010261029d366004611bef565b6110e8565b6101026102b0366004611838565b611281565b6040517fe33cace600000000000000000000000000000000000000000000000000000000815263ffffffff83166004820152731612fc28ee0ab882ec99842cde0fc77ff0691e909063e33cace690602401600060405180830381600087803b15801561032057600080fd5b505af1158015610334573d6000803e3d6000fd5b505050508063ffffffff166000146103cb576040517fe33cace600000000000000000000000000000000000000000000000000000000815263ffffffff82166004820152731612fc28ee0ab882ec99842cde0fc77ff0691e909063e33cace6906024015b600060405180830381600087803b1580156103b257600080fd5b505af11580156103c6573d6000803e3d6000fd5b505050505b5050565b60003073ffffffffffffffffffffffffffffffffffffffff1663bf7e214f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561041c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104409190611c0b565b90508073ffffffffffffffffffffffffffffffffffffffff811661056657735a15566417e6c1c9546523066500bddbc53f88c773ffffffffffffffffffffffffffffffffffffffff166365688cc96040518163ffffffff1660e01b81526004016020604051808303816000875af11580156104bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e39190611c0b565b6040517f7a9e5e4b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201529091503090637a9e5e4b90602401600060405180830381600087803b15801561054d57600080fd5b505af1158015610561573d6000803e3d6000fd5b505050505b6040517fb700961300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301523060248301527f1cff79cd00000000000000000000000000000000000000000000000000000000604483015282169063b700961390606401602060405180830381865afa1580156105fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106229190611c28565b6106d5576040517fcbeea68c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301523060248301527f1cff79cd00000000000000000000000000000000000000000000000000000000604483015282169063cbeea68c906064015b600060405180830381600087803b1580156106bc57600080fd5b505af11580156106d0573d6000803e3d6000fd5b505050505b505050565b3373ffffffffffffffffffffffffffffffffffffffff1673ccf3d848e08b94478ed8f46ffead3008faf581fd73ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610750573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107749190611c0b565b73ffffffffffffffffffffffffffffffffffffffff16146107c1576040517fa6c827a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33ff5b6040805160808082018352606082840181905280830181905267ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168352600160208085018290528751865173ffffffffffffffffffffffffffffffffffffffff8916928101929092526fffffffffffffffffffffffffffffffff16818701528083018290528551808203909301835292830181815260c0840190955292939092909160a0015b60608152602001906001900390816108735750506040830181905280518291906000906108a2576108a2611c45565b60209081029190910101526040805160028082526060820190925290816020016020820280368337505050606083018190528051600191906000906108e9576108e9611c45565b60200260200101818152505083606001516fffffffffffffffffffffffffffffffff1660001b826060015160018151811061092657610926611c45565b6020026020010181815250505092915050565b3373ffffffffffffffffffffffffffffffffffffffff1673ccf3d848e08b94478ed8f46ffead3008faf581fd73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d39190611c0b565b73ffffffffffffffffffffffffffffffffffffffff1614610a20576040517f19494c8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff84161415610a9b5760405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f19350505050158015610a95573d6000803e3d6000fd5b50505050565b6106d573ffffffffffffffffffffffffffffffffffffffff84168383611368565b6040805160808082018352606082840181905280830181905267ffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001683526001602080850182905287810151865173ffffffffffffffffffffffffffffffffffffffff8916928101929092526fffffffffffffffffffffffffffffffff16818701526000818401528551808203909301835292830181815260c0840190955292939092909160a0015b6060815260200190600190039081610b6d575050604083018190528051829190600090610b9c57610b9c611c45565b60209081029190910101526040805160028082526060820190925290816020016020820280368337505050606083018190528051600091908290610be257610be2611c45565b60200260200101818152505083604001516fffffffffffffffffffffffffffffffff1660001b826060015160018151811061092657610926611c45565b60003073ffffffffffffffffffffffffffffffffffffffff1663bf7e214f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c909190611c0b565b905073ffffffffffffffffffffffffffffffffffffffff8116610cb1575050565b6040517f2bc3217d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301523060248301527f1cff79cd000000000000000000000000000000000000000000000000000000006044830152829190821690632bc3217d906064016106a2565b6000610d4e610d4836849003840184611c74565b306107c4565b6040517ff14283c2000000000000000000000000000000000000000000000000000000008152909150731612fc28ee0ab882ec99842cde0fc77ff0691e909063f14283c290610da39087908590600401611c90565b600060405180830381600087803b158015610dbd57600080fd5b505af1158015610dd1573d6000803e3d6000fd5b50506040517f3fb387bd00000000000000000000000000000000000000000000000000000000815263ffffffff87166004820152731612fc28ee0ab882ec99842cde0fc77ff0691e909250633fb387bd9150602401600060405180830381600087803b158015610e4057600080fd5b505af1158015610e54573d6000803e3d6000fd5b50610e699250505060a0830160808401611caf565b1561105357610e85610e8036849003840184611c74565b6113f5565b6000610e9f610e9936859003850185611c74565b30610abc565b905063ffffffff8416610f45576040517f3ab9a078000000000000000000000000000000000000000000000000000000008152731612fc28ee0ab882ec99842cde0fc77ff0691e9090633ab9a07890610efc908490600401611b3f565b6020604051808303816000875af1158015610f1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3f9190611ccc565b5061104d565b6040517ff14283c2000000000000000000000000000000000000000000000000000000008152731612fc28ee0ab882ec99842cde0fc77ff0691e909063f14283c290610f979087908590600401611c90565b600060405180830381600087803b158015610fb157600080fd5b505af1158015610fc5573d6000803e3d6000fd5b50506040517f3fb387bd00000000000000000000000000000000000000000000000000000000815263ffffffff87166004820152731612fc28ee0ab882ec99842cde0fc77ff0691e909250633fb387bd9150602401600060405180830381600087803b15801561103457600080fd5b505af1158015611048573d6000803e3d6000fd5b505050505b50610a95565b63ffffffff831615610a95576040517fe33cace600000000000000000000000000000000000000000000000000000000815263ffffffff84166004820152731612fc28ee0ab882ec99842cde0fc77ff0691e909063e33cace690602401600060405180830381600087803b1580156110ca57600080fd5b505af11580156110de573d6000803e3d6000fd5b5050505050505050565b61110573149667b6fae2c63d1b4317c716b0d0e4d3e2bd706103cf565b6000611119610d4836849003840184611c74565b6040517f3ab9a078000000000000000000000000000000000000000000000000000000008152909150731612fc28ee0ab882ec99842cde0fc77ff0691e9090633ab9a0789061116c908490600401611b3f565b6020604051808303816000875af115801561118b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111af9190611ccc565b506111c060a0830160808401611caf565b156103cb576111d7610e8036849003840184611c74565b60006111eb610e9936859003850185611c74565b6040517f3ab9a078000000000000000000000000000000000000000000000000000000008152909150731612fc28ee0ab882ec99842cde0fc77ff0691e9090633ab9a0789061123e908490600401611b3f565b6020604051808303816000875af115801561125d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a959190611ccc565b6040517f3fb387bd00000000000000000000000000000000000000000000000000000000815263ffffffff83166004820152731612fc28ee0ab882ec99842cde0fc77ff0691e9090633fb387bd90602401600060405180830381600087803b1580156112ec57600080fd5b505af1158015611300573d6000803e3d6000fd5b505050508063ffffffff166000146103cb576040517f3fb387bd00000000000000000000000000000000000000000000000000000000815263ffffffff82166004820152731612fc28ee0ab882ec99842cde0fc77ff0691e9090633fb387bd90602401610398565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526106d59084906115bf565b80602001516fffffffffffffffffffffffffffffffff1681600001516fffffffffffffffffffffffffffffffff16111561148357805160208201516040517f866a0beb0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff9283166004820152911660248201526044015b60405180910390fd5b80606001516fffffffffffffffffffffffffffffffff1666b1a2bc2ec5000082602001516fffffffffffffffffffffffffffffffff166114c39190611d14565b101561152157602081015160608201516040517f25a5396b0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff92831660048201529116602482015260440161147a565b80604001516fffffffffffffffffffffffffffffffff1666b1a2bc2ec5000082600001516fffffffffffffffffffffffffffffffff166115619190611d2b565b11156115bc57805160408083015190517f25a5396b0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff92831660048201529116602482015260440161147a565b50565b6000611621826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166116cb9092919063ffffffff16565b8051909150156106d5578080602001905181019061163f9190611c28565b6106d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161147a565b60606116da84846000856116e2565b949350505050565b60606116ed856117e6565b611723576040517f304619b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161174c9190611d43565b60006040518083038185875af1925050503d8060008114611789576040519150601f19603f3d011682016040523d82523d6000602084013e61178e565b606091505b509150915081156117a25791506116da9050565b8051156117b25780518082602001fd5b836040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161147a9190611d5f565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906116da575050151592915050565b803563ffffffff8116811461183357600080fd5b919050565b6000806040838503121561184b57600080fd5b6118548361181f565b91506118626020840161181f565b90509250929050565b73ffffffffffffffffffffffffffffffffffffffff811681146115bc57600080fd5b60006020828403121561189f57600080fd5b81356118aa8161186b565b9392505050565b80356fffffffffffffffffffffffffffffffff8116811461183357600080fd5b80151581146115bc57600080fd5b600060a082840312156118f157600080fd5b60405160a0810181811067ffffffffffffffff8211171561193b577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405290508061194a836118b1565b8152611958602084016118b1565b6020820152611969604084016118b1565b604082015261197a606084016118b1565b6060820152608083013561198d816118d1565b6080919091015292915050565b60008060c083850312156119ad57600080fd5b6119b784846118df565b915060a08301356119c78161186b565b809150509250929050565b60005b838110156119ed5781810151838201526020016119d5565b83811115610a955750506000910152565b60008151808452611a168160208601602086016119d2565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600081518084526020808501945080840160005b83811015611a7857815187529582019590820190600101611a5c565b509495945050505050565b60006080830167ffffffffffffffff835116845260208084015115158186015260408401516080604087015282815180855260a08801915060a08160051b8901019450838301925060005b81811015611b1a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60898703018352611b088685516119fe565b95509284019291840191600101611ace565b505050505060608301518482036060860152611b368282611a48565b95945050505050565b6020815260006118aa6020830184611a83565b600080600060608486031215611b6757600080fd5b8335611b728161186b565b92506020840135611b828161186b565b929592945050506040919091013590565b600060a08284031215611ba557600080fd5b50919050565b600080600060e08486031215611bc057600080fd5b611bc98461181f565b9250611bd76020850161181f565b9150611be68560408601611b93565b90509250925092565b600060a08284031215611c0157600080fd5b6118aa8383611b93565b600060208284031215611c1d57600080fd5b81516118aa8161186b565b600060208284031215611c3a57600080fd5b81516118aa816118d1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060a08284031215611c8657600080fd5b6118aa83836118df565b63ffffffff831681526040602082015260006116da6040830184611a83565b600060208284031215611cc157600080fd5b81356118aa816118d1565b600060208284031215611cde57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015611d2657611d26611ce5565b500390565b60008219821115611d3e57611d3e611ce5565b500190565b60008251611d558184602087016119d2565b9190910192915050565b6020815260006118aa60208301846119fe56fea2646970667358221220e90197807ac04e764cbd235cac1ab25c54b25aa1feec2ec9538c9b4866a6b5d064736f6c634300080a0033000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100ea5760003560e01c80639f6197b71161008c578063e074bb4711610066578063e074bb4714610269578063f0c56eed1461027c578063f20311f01461028f578063fd6bf387146102a257600080fd5b80639f6197b71461021c578063c579d49014610243578063cb8076391461025657600080fd5b806341c0e1b5116100c857806341c0e1b51461015c5780637210cf961461016457806385d63353146101845780638cedca71146101dc57600080fd5b80632fc044de146100ef578063369465a1146101045780633d391f7014610149575b600080fd5b6101026100fd366004611838565b6102b5565b005b61012b7f000000000000000000000000000000000000000000000000000000000000000e81565b60405167ffffffffffffffff90911681526020015b60405180910390f35b61010261015736600461188d565b6103cf565b6101026106da565b61017761017236600461199a565b6107c4565b6040516101409190611b3f565b6101ab7f1cff79cde515a86f6cc1adbebe8ae25888905561371faf11c8102211f56b487081565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610140565b6101f773ccf3d848e08b94478ed8f46ffead3008faf581fd81565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610140565b61012b7f000000000000000000000000000000000000000000000000000000000000000f81565b610102610251366004611b52565b610939565b61017761026436600461199a565b610abc565b61010261027736600461188d565b610c1f565b61010261028a366004611bab565b610d34565b61010261029d366004611bef565b6110e8565b6101026102b0366004611838565b611281565b6040517fe33cace600000000000000000000000000000000000000000000000000000000815263ffffffff83166004820152731612fc28ee0ab882ec99842cde0fc77ff0691e909063e33cace690602401600060405180830381600087803b15801561032057600080fd5b505af1158015610334573d6000803e3d6000fd5b505050508063ffffffff166000146103cb576040517fe33cace600000000000000000000000000000000000000000000000000000000815263ffffffff82166004820152731612fc28ee0ab882ec99842cde0fc77ff0691e909063e33cace6906024015b600060405180830381600087803b1580156103b257600080fd5b505af11580156103c6573d6000803e3d6000fd5b505050505b5050565b60003073ffffffffffffffffffffffffffffffffffffffff1663bf7e214f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561041c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104409190611c0b565b90508073ffffffffffffffffffffffffffffffffffffffff811661056657735a15566417e6c1c9546523066500bddbc53f88c773ffffffffffffffffffffffffffffffffffffffff166365688cc96040518163ffffffff1660e01b81526004016020604051808303816000875af11580156104bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e39190611c0b565b6040517f7a9e5e4b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201529091503090637a9e5e4b90602401600060405180830381600087803b15801561054d57600080fd5b505af1158015610561573d6000803e3d6000fd5b505050505b6040517fb700961300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301523060248301527f1cff79cd00000000000000000000000000000000000000000000000000000000604483015282169063b700961390606401602060405180830381865afa1580156105fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106229190611c28565b6106d5576040517fcbeea68c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301523060248301527f1cff79cd00000000000000000000000000000000000000000000000000000000604483015282169063cbeea68c906064015b600060405180830381600087803b1580156106bc57600080fd5b505af11580156106d0573d6000803e3d6000fd5b505050505b505050565b3373ffffffffffffffffffffffffffffffffffffffff1673ccf3d848e08b94478ed8f46ffead3008faf581fd73ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610750573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107749190611c0b565b73ffffffffffffffffffffffffffffffffffffffff16146107c1576040517fa6c827a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33ff5b6040805160808082018352606082840181905280830181905267ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000e168352600160208085018290528751865173ffffffffffffffffffffffffffffffffffffffff8916928101929092526fffffffffffffffffffffffffffffffff16818701528083018290528551808203909301835292830181815260c0840190955292939092909160a0015b60608152602001906001900390816108735750506040830181905280518291906000906108a2576108a2611c45565b60209081029190910101526040805160028082526060820190925290816020016020820280368337505050606083018190528051600191906000906108e9576108e9611c45565b60200260200101818152505083606001516fffffffffffffffffffffffffffffffff1660001b826060015160018151811061092657610926611c45565b6020026020010181815250505092915050565b3373ffffffffffffffffffffffffffffffffffffffff1673ccf3d848e08b94478ed8f46ffead3008faf581fd73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d39190611c0b565b73ffffffffffffffffffffffffffffffffffffffff1614610a20576040517f19494c8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff84161415610a9b5760405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f19350505050158015610a95573d6000803e3d6000fd5b50505050565b6106d573ffffffffffffffffffffffffffffffffffffffff84168383611368565b6040805160808082018352606082840181905280830181905267ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000f1683526001602080850182905287810151865173ffffffffffffffffffffffffffffffffffffffff8916928101929092526fffffffffffffffffffffffffffffffff16818701526000818401528551808203909301835292830181815260c0840190955292939092909160a0015b6060815260200190600190039081610b6d575050604083018190528051829190600090610b9c57610b9c611c45565b60209081029190910101526040805160028082526060820190925290816020016020820280368337505050606083018190528051600091908290610be257610be2611c45565b60200260200101818152505083604001516fffffffffffffffffffffffffffffffff1660001b826060015160018151811061092657610926611c45565b60003073ffffffffffffffffffffffffffffffffffffffff1663bf7e214f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c909190611c0b565b905073ffffffffffffffffffffffffffffffffffffffff8116610cb1575050565b6040517f2bc3217d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301523060248301527f1cff79cd000000000000000000000000000000000000000000000000000000006044830152829190821690632bc3217d906064016106a2565b6000610d4e610d4836849003840184611c74565b306107c4565b6040517ff14283c2000000000000000000000000000000000000000000000000000000008152909150731612fc28ee0ab882ec99842cde0fc77ff0691e909063f14283c290610da39087908590600401611c90565b600060405180830381600087803b158015610dbd57600080fd5b505af1158015610dd1573d6000803e3d6000fd5b50506040517f3fb387bd00000000000000000000000000000000000000000000000000000000815263ffffffff87166004820152731612fc28ee0ab882ec99842cde0fc77ff0691e909250633fb387bd9150602401600060405180830381600087803b158015610e4057600080fd5b505af1158015610e54573d6000803e3d6000fd5b50610e699250505060a0830160808401611caf565b1561105357610e85610e8036849003840184611c74565b6113f5565b6000610e9f610e9936859003850185611c74565b30610abc565b905063ffffffff8416610f45576040517f3ab9a078000000000000000000000000000000000000000000000000000000008152731612fc28ee0ab882ec99842cde0fc77ff0691e9090633ab9a07890610efc908490600401611b3f565b6020604051808303816000875af1158015610f1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3f9190611ccc565b5061104d565b6040517ff14283c2000000000000000000000000000000000000000000000000000000008152731612fc28ee0ab882ec99842cde0fc77ff0691e909063f14283c290610f979087908590600401611c90565b600060405180830381600087803b158015610fb157600080fd5b505af1158015610fc5573d6000803e3d6000fd5b50506040517f3fb387bd00000000000000000000000000000000000000000000000000000000815263ffffffff87166004820152731612fc28ee0ab882ec99842cde0fc77ff0691e909250633fb387bd9150602401600060405180830381600087803b15801561103457600080fd5b505af1158015611048573d6000803e3d6000fd5b505050505b50610a95565b63ffffffff831615610a95576040517fe33cace600000000000000000000000000000000000000000000000000000000815263ffffffff84166004820152731612fc28ee0ab882ec99842cde0fc77ff0691e909063e33cace690602401600060405180830381600087803b1580156110ca57600080fd5b505af11580156110de573d6000803e3d6000fd5b5050505050505050565b61110573149667b6fae2c63d1b4317c716b0d0e4d3e2bd706103cf565b6000611119610d4836849003840184611c74565b6040517f3ab9a078000000000000000000000000000000000000000000000000000000008152909150731612fc28ee0ab882ec99842cde0fc77ff0691e9090633ab9a0789061116c908490600401611b3f565b6020604051808303816000875af115801561118b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111af9190611ccc565b506111c060a0830160808401611caf565b156103cb576111d7610e8036849003840184611c74565b60006111eb610e9936859003850185611c74565b6040517f3ab9a078000000000000000000000000000000000000000000000000000000008152909150731612fc28ee0ab882ec99842cde0fc77ff0691e9090633ab9a0789061123e908490600401611b3f565b6020604051808303816000875af115801561125d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a959190611ccc565b6040517f3fb387bd00000000000000000000000000000000000000000000000000000000815263ffffffff83166004820152731612fc28ee0ab882ec99842cde0fc77ff0691e9090633fb387bd90602401600060405180830381600087803b1580156112ec57600080fd5b505af1158015611300573d6000803e3d6000fd5b505050508063ffffffff166000146103cb576040517f3fb387bd00000000000000000000000000000000000000000000000000000000815263ffffffff82166004820152731612fc28ee0ab882ec99842cde0fc77ff0691e9090633fb387bd90602401610398565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526106d59084906115bf565b80602001516fffffffffffffffffffffffffffffffff1681600001516fffffffffffffffffffffffffffffffff16111561148357805160208201516040517f866a0beb0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff9283166004820152911660248201526044015b60405180910390fd5b80606001516fffffffffffffffffffffffffffffffff1666b1a2bc2ec5000082602001516fffffffffffffffffffffffffffffffff166114c39190611d14565b101561152157602081015160608201516040517f25a5396b0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff92831660048201529116602482015260440161147a565b80604001516fffffffffffffffffffffffffffffffff1666b1a2bc2ec5000082600001516fffffffffffffffffffffffffffffffff166115619190611d2b565b11156115bc57805160408083015190517f25a5396b0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff92831660048201529116602482015260440161147a565b50565b6000611621826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166116cb9092919063ffffffff16565b8051909150156106d5578080602001905181019061163f9190611c28565b6106d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161147a565b60606116da84846000856116e2565b949350505050565b60606116ed856117e6565b611723576040517f304619b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161174c9190611d43565b60006040518083038185875af1925050503d8060008114611789576040519150601f19603f3d011682016040523d82523d6000602084013e61178e565b606091505b509150915081156117a25791506116da9050565b8051156117b25780518082602001fd5b836040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161147a9190611d5f565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906116da575050151592915050565b803563ffffffff8116811461183357600080fd5b919050565b6000806040838503121561184b57600080fd5b6118548361181f565b91506118626020840161181f565b90509250929050565b73ffffffffffffffffffffffffffffffffffffffff811681146115bc57600080fd5b60006020828403121561189f57600080fd5b81356118aa8161186b565b9392505050565b80356fffffffffffffffffffffffffffffffff8116811461183357600080fd5b80151581146115bc57600080fd5b600060a082840312156118f157600080fd5b60405160a0810181811067ffffffffffffffff8211171561193b577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405290508061194a836118b1565b8152611958602084016118b1565b6020820152611969604084016118b1565b604082015261197a606084016118b1565b6060820152608083013561198d816118d1565b6080919091015292915050565b60008060c083850312156119ad57600080fd5b6119b784846118df565b915060a08301356119c78161186b565b809150509250929050565b60005b838110156119ed5781810151838201526020016119d5565b83811115610a955750506000910152565b60008151808452611a168160208601602086016119d2565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600081518084526020808501945080840160005b83811015611a7857815187529582019590820190600101611a5c565b509495945050505050565b60006080830167ffffffffffffffff835116845260208084015115158186015260408401516080604087015282815180855260a08801915060a08160051b8901019450838301925060005b81811015611b1a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60898703018352611b088685516119fe565b95509284019291840191600101611ace565b505050505060608301518482036060860152611b368282611a48565b95945050505050565b6020815260006118aa6020830184611a83565b600080600060608486031215611b6757600080fd5b8335611b728161186b565b92506020840135611b828161186b565b929592945050506040919091013590565b600060a08284031215611ba557600080fd5b50919050565b600080600060e08486031215611bc057600080fd5b611bc98461181f565b9250611bd76020850161181f565b9150611be68560408601611b93565b90509250925092565b600060a08284031215611c0157600080fd5b6118aa8383611b93565b600060208284031215611c1d57600080fd5b81516118aa8161186b565b600060208284031215611c3a57600080fd5b81516118aa816118d1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060a08284031215611c8657600080fd5b6118aa83836118df565b63ffffffff831681526040602082015260006116da6040830184611a83565b600060208284031215611cc157600080fd5b81356118aa816118d1565b600060208284031215611cde57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015611d2657611d26611ce5565b500390565b60008219821115611d3e57611d3e611ce5565b500190565b60008251611d558184602087016119d2565b9190910192915050565b6020815260006118aa60208301846119fe56fea2646970667358221220e90197807ac04e764cbd235cac1ab25c54b25aa1feec2ec9538c9b4866a6b5d064736f6c634300080a0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f

-----Decoded View---------------
Arg [0] : _repayBundleId (uint64): 14
Arg [1] : _boostBundleId (uint64): 15

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000000000000000000000000000000000000000000e
Arg [1] : 000000000000000000000000000000000000000000000000000000000000000f


Deployed Bytecode Sourcemap

37396:5993:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40752:265;;;;;;:::i;:::-;;:::i;:::-;;37490:39;;;;;;;;617:18:1;605:31;;;587:50;;575:2;560:18;37490:39:0;;;;;;;;13917:555;;;;;;:::i;:::-;;:::i;11503:85::-;;;:::i;41817:721::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;13686:85::-;;13735:35;13686:85;;;;;5456:66:1;5444:79;;;5426:98;;5414:2;5399:18;13686:85:0;5282:248:1;10674:68:0;;9491:42;10674:68;;;;;5729:42:1;5717:55;;;5699:74;;5687:2;5672:18;10674:68:0;5535:244:1;37536:39:0;;;;;11141:316;;;;;;:::i;:::-;;:::i;42666:720::-;;;;;;:::i;:::-;;:::i;14649:428::-;;;;;;:::i;:::-;;:::i;39239:1110::-;;;;;;:::i;:::-;;:::i;38498:549::-;;;;;;:::i;:::-;;:::i;40420:259::-;;;;;;:::i;:::-;;:::i;40752:265::-;40850:51;;;;;7273:10:1;7261:23;;40850:51:0;;;7243:42:1;29438::0;;40850;;7216:18:1;;40850:51:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40918:7;:12;;40929:1;40918:12;40914:96;;40947:51;;;;;7273:10:1;7261:23;;40947:51:0;;;7243:42:1;29438::0;;40947;;7216:18:1;;40947:51:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40914:96;40752:265;;:::o;13917:555::-;13982:21;14029:4;14014:31;;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;13982:66;-1:-1:-1;13982:66:0;14114:27;;;14110:188;;9584:42;14166:40;;;:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;14223:63;;;;;5729:42:1;5717:55;;14223:63:0;;;5699:74:1;14158:50:0;;-1:-1:-1;14238:4:0;;14223:34;;5672:18:1;;14223:63:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14110:188;14315:61;;;;;:13;8371:15:1;;;14315:61:0;;;8353:34:1;14352:4:0;8403:18:1;;;8396:43;8475:79;8455:18;;;8448:107;14315:13:0;;;;;8265:18:1;;14315:61:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;14310:155;;14393:60;;;;;:12;8371:15:1;;;14393:60:0;;;8353:34:1;14429:4:0;8403:18:1;;;8396:43;8475:79;8455:18;;;8448:107;14393:12:0;;;;;8265:18:1;;14393:60:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14310:155;13971:501;;13917:555;:::o;11503:85::-;11015:10;10993:32;;9491:42;10993:16;;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:32;;;10989:87;;11048:16;;;;;;;;;;;;;;10989:87;11568:10:::1;11547:33;41817:721:::0;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;41955:45:0;41985:15;41955:45;;;42031:4;-1:-1:-1;;;;42011:24:0;;;42175:17;;42148:71;;9964:42:1;9952:55;;42148:71:0;;;9934:74:1;;;;42167:26:0;;10024:18:1;;;10017:34;10067:18;;;10060:45;;;42148:71:0;;;;;;;;;;9907:18:1;;;42254:14:0;;;;;;;;;-1:-1:-1;;42148:71:0;;9907:18:1;;42254:14:0;;;;;;;;;;;;;;;;-1:-1:-1;;42230:20:0;;;:38;;;42279:23;;42305:11;;42230:38;42300:1;;42279:23;;;;:::i;:::-;;;;;;;;;;:37;42349:16;;;42363:1;42349:16;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;42329:16:0;;;:36;;;42376:19;;42414:1;;42329:36;42398:19;;42376;;;;:::i;:::-;;;;;;:41;;;;;42488:8;:25;;;42480:34;;42472:43;;42450:8;:16;;;42467:1;42450:19;;;;;;;;:::i;:::-;;;;;;:65;;;;;41944:594;41817:721;;;;:::o;11141:316::-;10869:10;10847:32;;9491:42;10847:16;;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:32;;;10843:87;;10902:16;;;;;;;;;;;;;;10843:87;11263:42:::1;11253:52;::::0;::::1;;11249:201;;;11322:36;::::0;:27:::1;::::0;::::1;::::0;:36;::::1;;;::::0;11350:7;;11322:36:::1;::::0;;;11350:7;11322:27;:36;::::1;;;;;;;;;;;;;::::0;::::1;;;;;;13971:501:::0;;13917:555;:::o;11249:201::-:1;11391:47;:27;::::0;::::1;11419:9:::0;11430:7;11391:27:::1;:47::i;42666:720::-:0;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;42804:45:0;42834:15;42804:45;;;42880:4;-1:-1:-1;;;;42860:24:0;;;43024:17;;;;42997:70;;9964:42:1;9952:55;;42997:70:0;;;9934:74:1;;;;43016:26:0;;10024:18:1;;;10017:34;-1:-1:-1;10067:18:1;;;10060:45;42997:70:0;;;;;;;;;;9907:18:1;;;43102:14:0;;;;;;;;;-1:-1:-1;;42997:70:0;;9907:18:1;;43102:14:0;;;;;;;;;;;;;;;;-1:-1:-1;;43078:20:0;;;:38;;;43127:23;;43153:11;;43078:38;43148:1;;43127:23;;;;:::i;:::-;;;;;;;;;;:37;43197:16;;;43211:1;43197:16;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;43177:16:0;;;:36;;;43224:19;;43262:1;;43177:36;43262:1;;43224:19;;;;:::i;:::-;;;;;;:41;;;;;43336:8;:25;;;43328:34;;43320:43;;43298:8;:16;;;43315:1;43298:19;;;;;;;;:::i;14649:428::-;14716:21;14763:4;14748:31;;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;14716:66;-1:-1:-1;14886:27:0;;;14882:66;;14930:7;14649:428;:::o;14882:66::-;15009:60;;;;;:12;8371:15:1;;;15009:60:0;;;8353:34:1;15045:4:0;8403:18:1;;;8396:43;8475:79;8455:18;;;8448:107;14984:13:0;;15009:12;;;;;;8265:18:1;;15009:60:0;8092:469:1;39239:1110:0;39467:27;39497:39;;;;;;;;39512:8;39497:39;:::i;:::-;39530:4;39497:14;:39::i;:::-;39547:61;;;;;39467:69;;-1:-1:-1;29438:42:0;;39547;;:61;;39590:7;;39467:69;;39547:61;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;39619:49:0;;;;;7273:10:1;7261:23;;39619:49:0;;;7243:42:1;29438::0;;-1:-1:-1;39619:40:0;;-1:-1:-1;7216:18:1;;39619:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;39685:21:0;;-1:-1:-1;;;39685:21:0;;;;;;;:::i;:::-;39681:661;;;39723:26;;;;;;;;39740:8;39723:26;:::i;:::-;:16;:26::i;:::-;39766:27;39796:39;;;;;;;;39811:8;39796:39;:::i;:::-;39829:4;39796:14;:39::i;:::-;39766:69;-1:-1:-1;39918:12:0;;;39914:281;;39951:58;;;;;29438:42;;39951:48;;:58;;40000:8;;39951:58;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;39914:281;;;40050:61;;;;;29438:42;;40050;;:61;;40093:7;;40102:8;;40050:61;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;40130:49:0;;;;;7273:10:1;7261:23;;40130:49:0;;;7243:42:1;29438::0;;-1:-1:-1;40130:40:0;;-1:-1:-1;7216:18:1;;40130:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;39914:281;39708:498;39681:661;;;40231:12;;;;40227:104;;40264:51;;;;;7273:10:1;7261:23;;40264:51:0;;;7243:42:1;29438::0;;40264;;7216:18:1;;40264:51:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;39374:975;39239:1110;;;:::o;38498:549::-;38608:31;29248:42;38608:14;:31::i;:::-;38650:27;38680:39;;;;;;;;38695:8;38680:39;:::i;:::-;38732:58;;;;;38650:69;;-1:-1:-1;29438:42:0;;38732:48;;:58;;38650:69;;38732:58;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;38805:21:0;;;;;;;;:::i;:::-;38801:239;;;38843:26;;;;;;;;38860:8;38843:26;:::i;:::-;38886:27;38916:39;;;;;;;;38931:8;38916:39;:::i;:::-;38970:58;;;;;38886:69;;-1:-1:-1;29438:42:0;;38970:48;;:58;;38886:69;;38970:58;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;40420:259::-;40516:49;;;;;7273:10:1;7261:23;;40516:49:0;;;7243:42:1;29438::0;;40516:40;;7216:18:1;;40516:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40582:7;:12;;40593:1;40582:12;40578:94;;40611:49;;;;;7273:10:1;7261:23;;40611:49:0;;;7243:42:1;29438::0;;40611:40;;7216:18:1;;40611:49:0;7098:193:1;6605:211:0;6749:58;;;11563:42:1;11551:55;;6749:58:0;;;11533:74:1;11623:18;;;;11616:34;;;6749:58:0;;;;;;;;;;11506:18:1;;;;6749:58:0;;;;;;;;;;6772:23;6749:58;;;6722:86;;6742:5;;6722:19;:86::i;41119:570::-;41231:8;:17;;;41211:37;;:8;:17;;;:37;;;41207:129;;;41287:17;;41306;;;;41272:52;;;;;11845:34:1;11906:15;;;41272:52:0;;;11888:34:1;11958:15;;11938:18;;;11931:43;11808:18;;41272:52:0;;;;;;;;41207:129;41389:8;:25;;;41352:62;;37859:17;41353:8;:17;;;:32;;;;;;:::i;:::-;41352:62;41348:161;;;41452:17;;;;41471:25;;;;41438:59;;;;;11845:34:1;11906:15;;;41438:59:0;;;11888:34:1;11958:15;;11938:18;;;11931:43;11808:18;;41438:59:0;11661:319:1;41348:161:0;41562:8;:25;;;41525:62;;37859:17;41526:8;:17;;;:32;;;;;;:::i;:::-;41525:62;41521:161;;;41625:17;;41644:25;;;;;41611:59;;;;;11845:34:1;11906:15;;;41611:59:0;;;11888:34:1;11958:15;;11938:18;;;11931:43;11808:18;;41611:59:0;11661:319:1;41521:161:0;41119:570;:::o;8355:468::-;8436:23;8462:106;8504:4;8462:106;;;;;;;;;;;;;;;;;8470:5;8462:27;;;;:106;;;;;:::i;:::-;8583:17;;8436:132;;-1:-1:-1;8583:21:0;8579:237;;8738:10;8727:30;;;;;;;;;;;;:::i;:::-;8719:85;;;;;;;12639:2:1;8719:85:0;;;12621:21:1;12678:2;12658:18;;;12651:30;12717:34;12697:18;;;12690:62;12788:12;12768:18;;;12761:40;12818:19;;8719:85:0;12437:406:1;2627:230:0;2764:12;2796:53;2819:6;2827:4;2833:1;2836:12;2796:22;:53::i;:::-;2789:60;2627:230;-1:-1:-1;;;;2627:230:0:o;3577:1036::-;3750:12;3781:18;3792:6;3781:10;:18::i;:::-;3775:77;;3823:17;;;;;;;;;;;;;;3775:77;3925:12;3939:23;3966:6;:11;;3985:8;3995:4;3966:34;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3924:76;;;;4015:7;4011:595;;;4046:10;-1:-1:-1;4039:17:0;;-1:-1:-1;4039:17:0;4011:595;4160:17;;:21;4156:439;;4423:10;4417:17;4484:15;4471:10;4467:2;4463:19;4456:44;4156:439;4566:12;4559:20;;;;;;;;;;;:::i;1337:641::-;1397:4;1878:20;;1708:66;1927:23;;;;;;:42;;-1:-1:-1;;1954:15:0;;;1919:51;-1:-1:-1;;1337:641:0:o;14:163:1:-;81:20;;141:10;130:22;;120:33;;110:61;;167:1;164;157:12;110:61;14:163;;;:::o;182:256::-;248:6;256;309:2;297:9;288:7;284:23;280:32;277:52;;;325:1;322;315:12;277:52;348:28;366:9;348:28;:::i;:::-;338:38;;395:37;428:2;417:9;413:18;395:37;:::i;:::-;385:47;;182:256;;;;;:::o;648:154::-;734:42;727:5;723:54;716:5;713:65;703:93;;792:1;789;782:12;807:247;866:6;919:2;907:9;898:7;894:23;890:32;887:52;;;935:1;932;925:12;887:52;974:9;961:23;993:31;1018:5;993:31;:::i;:::-;1043:5;807:247;-1:-1:-1;;;807:247:1:o;1248:188::-;1316:20;;1376:34;1365:46;;1355:57;;1345:85;;1426:1;1423;1416:12;1441:118;1527:5;1520:13;1513:21;1506:5;1503:32;1493:60;;1549:1;1546;1539:12;1564:932;1630:5;1678:4;1666:9;1661:3;1657:19;1653:30;1650:50;;;1696:1;1693;1686:12;1650:50;1729:2;1723:9;1771:4;1763:6;1759:17;1842:6;1830:10;1827:22;1806:18;1794:10;1791:34;1788:62;1785:242;;;1883:77;1880:1;1873:88;1984:4;1981:1;1974:15;2012:4;2009:1;2002:15;1785:242;2043:2;2036:22;2076:6;-1:-1:-1;2076:6:1;2106:29;2125:9;2106:29;:::i;:::-;2098:6;2091:45;2169:38;2203:2;2192:9;2188:18;2169:38;:::i;:::-;2164:2;2156:6;2152:15;2145:63;2241:38;2275:2;2264:9;2260:18;2241:38;:::i;:::-;2236:2;2228:6;2224:15;2217:63;2313:38;2347:2;2336:9;2332:18;2313:38;:::i;:::-;2308:2;2300:6;2296:15;2289:63;2404:3;2393:9;2389:19;2376:33;2418:30;2440:7;2418:30;:::i;:::-;2476:3;2464:16;;;;2457:33;1564:932;;-1:-1:-1;;1564:932:1:o;2501:388::-;2606:6;2614;2667:3;2655:9;2646:7;2642:23;2638:33;2635:53;;;2684:1;2681;2674:12;2635:53;2707:57;2756:7;2745:9;2707:57;:::i;:::-;2697:67;;2814:3;2803:9;2799:19;2786:33;2828:31;2853:5;2828:31;:::i;:::-;2878:5;2868:15;;;2501:388;;;;;:::o;2894:258::-;2966:1;2976:113;2990:6;2987:1;2984:13;2976:113;;;3066:11;;;3060:18;3047:11;;;3040:39;3012:2;3005:10;2976:113;;;3107:6;3104:1;3101:13;3098:48;;;-1:-1:-1;;3142:1:1;3124:16;;3117:27;2894:258::o;3157:316::-;3198:3;3236:5;3230:12;3263:6;3258:3;3251:19;3279:63;3335:6;3328:4;3323:3;3319:14;3312:4;3305:5;3301:16;3279:63;:::i;:::-;3387:2;3375:15;3392:66;3371:88;3362:98;;;;3462:4;3358:109;;3157:316;-1:-1:-1;;3157:316:1:o;3478:435::-;3531:3;3569:5;3563:12;3596:6;3591:3;3584:19;3622:4;3651:2;3646:3;3642:12;3635:19;;3688:2;3681:5;3677:14;3709:1;3719:169;3733:6;3730:1;3727:13;3719:169;;;3794:13;;3782:26;;3828:12;;;;3863:15;;;;3755:1;3748:9;3719:169;;;-1:-1:-1;3904:3:1;;3478:435;-1:-1:-1;;;;;3478:435:1:o;3918:1084::-;3972:3;4011:4;4006:3;4002:14;4055:18;4047:5;4041:12;4037:37;4032:3;4025:50;4094:4;4159:2;4152:5;4148:14;4142:21;4135:29;4128:37;4123:2;4118:3;4114:12;4107:59;4212:4;4205:5;4201:16;4195:23;4250:4;4243;4238:3;4234:14;4227:28;4277:4;4310:12;4304:19;4345:6;4339:4;4332:20;4379:3;4374;4370:13;4361:22;;4436:3;4426:6;4423:1;4419:14;4414:3;4410:24;4406:34;4392:48;;4481:2;4467:12;4463:21;4449:35;;4502:1;4512:313;4526:6;4523:1;4520:13;4512:313;;;4611:66;4605:3;4597:6;4593:16;4589:89;4582:5;4575:104;4702:39;4734:6;4725;4719:13;4702:39;:::i;:::-;4692:49;-1:-1:-1;4764:15:1;;;;4801:14;;;;4548:1;4541:9;4512:313;;;4516:3;;;;;4873:4;4866:5;4862:16;4856:23;4923:3;4915:6;4911:16;4904:4;4899:3;4895:14;4888:40;4944:52;4989:6;4973:14;4944:52;:::i;:::-;4937:59;3918:1084;-1:-1:-1;;;;;3918:1084:1:o;5007:270::-;5194:2;5183:9;5176:21;5157:4;5214:57;5267:2;5256:9;5252:18;5244:6;5214:57;:::i;5784:456::-;5861:6;5869;5877;5930:2;5918:9;5909:7;5905:23;5901:32;5898:52;;;5946:1;5943;5936:12;5898:52;5985:9;5972:23;6004:31;6029:5;6004:31;:::i;:::-;6054:5;-1:-1:-1;6111:2:1;6096:18;;6083:32;6124:33;6083:32;6124:33;:::i;:::-;5784:456;;6176:7;;-1:-1:-1;;;6230:2:1;6215:18;;;;6202:32;;5784:456::o;6245:168::-;6317:5;6362:3;6353:6;6348:3;6344:16;6340:26;6337:46;;;6379:1;6376;6369:12;6337:46;-1:-1:-1;6401:6:1;6245:168;-1:-1:-1;6245:168:1:o;6418:407::-;6532:6;6540;6548;6601:3;6589:9;6580:7;6576:23;6572:33;6569:53;;;6618:1;6615;6608:12;6569:53;6641:28;6659:9;6641:28;:::i;:::-;6631:38;;6688:37;6721:2;6710:9;6706:18;6688:37;:::i;:::-;6678:47;;6744:75;6811:7;6806:2;6795:9;6791:18;6744:75;:::i;:::-;6734:85;;6418:407;;;;;:::o;6830:263::-;6928:6;6981:3;6969:9;6960:7;6956:23;6952:33;6949:53;;;6998:1;6995;6988:12;6949:53;7021:66;7079:7;7068:9;7021:66;:::i;7296:270::-;7385:6;7438:2;7426:9;7417:7;7413:23;7409:32;7406:52;;;7454:1;7451;7444:12;7406:52;7486:9;7480:16;7505:31;7530:5;7505:31;:::i;8566:245::-;8633:6;8686:2;8674:9;8665:7;8661:23;8657:32;8654:52;;;8702:1;8699;8692:12;8654:52;8734:9;8728:16;8753:28;8775:5;8753:28;:::i;10116:184::-;10168:77;10165:1;10158:88;10265:4;10262:1;10255:15;10289:4;10286:1;10279:15;10305:252;10401:6;10454:3;10442:9;10433:7;10429:23;10425:33;10422:53;;;10471:1;10468;10461:12;10422:53;10494:57;10543:7;10532:9;10494:57;:::i;10562:357::-;10788:10;10780:6;10776:23;10765:9;10758:42;10836:2;10831;10820:9;10816:18;10809:30;10739:4;10856:57;10909:2;10898:9;10894:18;10886:6;10856:57;:::i;10924:241::-;10980:6;11033:2;11021:9;11012:7;11008:23;11004:32;11001:52;;;11049:1;11046;11039:12;11001:52;11088:9;11075:23;11107:28;11129:5;11107:28;:::i;11170:184::-;11240:6;11293:2;11281:9;11272:7;11268:23;11264:32;11261:52;;;11309:1;11306;11299:12;11261:52;-1:-1:-1;11332:16:1;;11170:184;-1:-1:-1;11170:184:1:o;11985:::-;12037:77;12034:1;12027:88;12134:4;12131:1;12124:15;12158:4;12155:1;12148:15;12174:125;12214:4;12242:1;12239;12236:8;12233:34;;;12247:18;;:::i;:::-;-1:-1:-1;12284:9:1;;12174:125::o;12304:128::-;12344:3;12375:1;12371:6;12368:1;12365:13;12362:39;;;12381:18;;:::i;:::-;-1:-1:-1;12417:9:1;;12304:128::o;12848:274::-;12977:3;13015:6;13009:13;13031:53;13077:6;13072:3;13065:4;13057:6;13053:17;13031:53;:::i;:::-;13100:16;;;;;12848:274;-1:-1:-1;;12848:274:1:o;13127:219::-;13276:2;13265:9;13258:21;13239:4;13296:44;13336:2;13325:9;13321:18;13313:6;13296:44;:::i

Swarm Source

ipfs://e90197807ac04e764cbd235cac1ab25c54b25aa1feec2ec9538c9b4866a6b5d0

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.