ETH Price: $3,295.15 (-1.05%)

Contract

0x6dd655f10d4b9E242aE186D9050B68F725c76d76
 
Transaction Hash
Method
Block
From
To
Schedule Unstake214628662024-12-23 4:41:113 hrs ago1734928871IN
API3 DAO: Single Staking Pool
0 ETH0.000667884.91599712
Schedule Unstake214625972024-12-23 3:47:114 hrs ago1734925631IN
API3 DAO: Single Staking Pool
0 ETH0.000793855.84319545
Unstake214621532024-12-23 2:17:235 hrs ago1734920243IN
API3 DAO: Single Staking Pool
0 ETH0.00051936.04744931
Withdraw Regular214615972024-12-23 0:25:357 hrs ago1734913535IN
API3 DAO: Single Staking Pool
0 ETH0.001751635.12143072
Schedule Unstake214612772024-12-22 23:20:478 hrs ago1734909647IN
API3 DAO: Single Staking Pool
0 ETH0.000722735.31926449
Withdraw Regular214611742024-12-22 22:59:598 hrs ago1734908399IN
API3 DAO: Single Staking Pool
0 ETH0.001726634.67096453
Unstake214610932024-12-22 22:43:479 hrs ago1734907427IN
API3 DAO: Single Staking Pool
0 ETH0.000445925.19298269
Withdraw Regular214610682024-12-22 22:38:479 hrs ago1734907127IN
API3 DAO: Single Staking Pool
0 ETH0.002396026.43653863
Schedule Unstake214607532024-12-22 21:35:1110 hrs ago1734903311IN
API3 DAO: Single Staking Pool
0 ETH0.000848736.2471423
Deposit Regular214603242024-12-22 20:08:3511 hrs ago1734898115IN
API3 DAO: Single Staking Pool
0 ETH0.000671679.40534149
Unstake And With...214598352024-12-22 18:30:1113 hrs ago1734892211IN
API3 DAO: Single Staking Pool
0 ETH0.001939896.49910133
Withdraw Regular214592972024-12-22 16:41:5915 hrs ago1734885719IN
API3 DAO: Single Staking Pool
0 ETH0.003019728.33650182
Unstake214587332024-12-22 14:48:3517 hrs ago1734878915IN
API3 DAO: Single Staking Pool
0 ETH0.000834069.71297471
Schedule Unstake214587102024-12-22 14:43:5917 hrs ago1734878639IN
API3 DAO: Single Staking Pool
0 ETH0.001202248.84999458
Unstake And With...214587062024-12-22 14:43:1117 hrs ago1734878591IN
API3 DAO: Single Staking Pool
0 ETH0.002461419.48307537
Schedule Unstake214586442024-12-22 14:30:3517 hrs ago1734877835IN
API3 DAO: Single Staking Pool
0 ETH0.001222739
Schedule Unstake214585592024-12-22 14:13:2317 hrs ago1734876803IN
API3 DAO: Single Staking Pool
0 ETH0.001003567.3868049
Schedule Unstake214583772024-12-22 13:36:5918 hrs ago1734874619IN
API3 DAO: Single Staking Pool
0 ETH0.000974557.17455726
Withdraw Regular214574922024-12-22 10:38:4721 hrs ago1734863927IN
API3 DAO: Single Staking Pool
0 ETH0.002228676.02928398
Unstake214574722024-12-22 10:34:4721 hrs ago1734863687IN
API3 DAO: Single Staking Pool
0 ETH0.000451665.25982591
Withdraw Regular214571702024-12-22 9:33:5922 hrs ago1734860039IN
API3 DAO: Single Staking Pool
0 ETH0.001890375.21873631
Deposit And Stak...214558562024-12-22 5:09:5926 hrs ago1734844199IN
API3 DAO: Single Staking Pool
0 ETH0.000858237.15946855
Deposit And Stak...214556072024-12-22 4:19:4727 hrs ago1734841187IN
API3 DAO: Single Staking Pool
0 ETH0.000640245.34151593
Withdraw Regular214555922024-12-22 4:16:4727 hrs ago1734841007IN
API3 DAO: Single Staking Pool
0 ETH0.001937565.34900232
Schedule Unstake214535672024-12-21 21:28:5934 hrs ago1734816539IN
API3 DAO: Single Staking Pool
0 ETH0.001196818.80921907
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Api3Pool

Compiler Version
v0.8.4+commit.c7e474f2

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2021-07-08
*/

// Sources flattened with hardhat v2.4.0 https://hardhat.org

// File contracts/auxiliary/interfaces/v0.8.4/IERC20Aux.sol


pragma solidity 0.8.4;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20Aux {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}


// File contracts/auxiliary/interfaces/v0.8.4/IApi3Token.sol

pragma solidity 0.8.4;

interface IApi3Token is IERC20Aux {
    event MinterStatusUpdated(
        address indexed minterAddress,
        bool minterStatus
        );

    event BurnerStatusUpdated(
        address indexed burnerAddress,
        bool burnerStatus
        );

    function updateMinterStatus(
        address minterAddress,
        bool minterStatus
        )
        external;

    function updateBurnerStatus(bool burnerStatus)
        external;

    function mint(
        address account,
        uint256 amount
        )
        external;

    function burn(uint256 amount)
        external;

    function getMinterStatus(address minterAddress)
        external
        view
        returns (bool minterStatus);

    function getBurnerStatus(address burnerAddress)
        external
        view
        returns (bool burnerStatus);
}


// File contracts/interfaces/IStateUtils.sol

pragma solidity 0.8.4;

interface IStateUtils {
    event SetDaoApps(
        address agentAppPrimary,
        address agentAppSecondary,
        address votingAppPrimary,
        address votingAppSecondary
        );

    event SetClaimsManagerStatus(
        address indexed claimsManager,
        bool indexed status
        );

    event SetStakeTarget(uint256 stakeTarget);

    event SetMaxApr(uint256 maxApr);

    event SetMinApr(uint256 minApr);

    event SetUnstakeWaitPeriod(uint256 unstakeWaitPeriod);

    event SetAprUpdateStep(uint256 aprUpdateStep);

    event SetProposalVotingPowerThreshold(uint256 proposalVotingPowerThreshold);

    event UpdatedLastProposalTimestamp(
        address indexed user,
        uint256 lastProposalTimestamp,
        address votingApp
        );

    function setDaoApps(
        address _agentAppPrimary,
        address _agentAppSecondary,
        address _votingAppPrimary,
        address _votingAppSecondary
        )
        external;

    function setClaimsManagerStatus(
        address claimsManager,
        bool status
        )
        external;

    function setStakeTarget(uint256 _stakeTarget)
        external;

    function setMaxApr(uint256 _maxApr)
        external;

    function setMinApr(uint256 _minApr)
        external;

    function setUnstakeWaitPeriod(uint256 _unstakeWaitPeriod)
        external;

    function setAprUpdateStep(uint256 _aprUpdateStep)
        external;

    function setProposalVotingPowerThreshold(uint256 _proposalVotingPowerThreshold)
        external;

    function updateLastProposalTimestamp(address userAddress)
        external;

    function isGenesisEpoch()
        external
        view
        returns (bool);
}


// File contracts/StateUtils.sol

pragma solidity 0.8.4;


/// @title Contract that keeps state variables
contract StateUtils is IStateUtils {
    struct Checkpoint {
        uint32 fromBlock;
        uint224 value;
    }

    struct AddressCheckpoint {
        uint32 fromBlock;
        address _address;
    }

    struct Reward {
        uint32 atBlock;
        uint224 amount;
        uint256 totalSharesThen;
        uint256 totalStakeThen;
    }

    struct User {
        Checkpoint[] shares;
        Checkpoint[] delegatedTo;
        AddressCheckpoint[] delegates;
        uint256 unstaked;
        uint256 vesting;
        uint256 unstakeAmount;
        uint256 unstakeShares;
        uint256 unstakeScheduledFor;
        uint256 lastDelegationUpdateTimestamp;
        uint256 lastProposalTimestamp;
    }

    struct LockedCalculation {
        uint256 initialIndEpoch;
        uint256 nextIndEpoch;
        uint256 locked;
    }

    /// @notice Length of the epoch in which the staking reward is paid out
    /// once. It is hardcoded as 7 days.
    /// @dev In addition to regulating reward payments, this variable is used
    /// for two additional things:
    /// (1) After a user makes a proposal, they cannot make a second one
    /// before `EPOCH_LENGTH` has passed
    /// (2) After a user updates their delegation status, they have to wait
    /// `EPOCH_LENGTH` before updating it again
    uint256 public constant EPOCH_LENGTH = 1 weeks;

    /// @notice Number of epochs before the staking rewards get unlocked.
    /// Hardcoded as 52 epochs, which approximately corresponds to a year with
    /// an `EPOCH_LENGTH` of 1 week.
    uint256 public constant REWARD_VESTING_PERIOD = 52;

    // All percentage values are represented as 1e18 = 100%
    uint256 internal constant ONE_PERCENT = 1e18 / 100;
    uint256 internal constant HUNDRED_PERCENT = 1e18;

    // To assert that typecasts do not overflow
    uint256 internal constant MAX_UINT32 = 2**32 - 1;
    uint256 internal constant MAX_UINT224 = 2**224 - 1;

    /// @notice Epochs are indexed as `block.timestamp / EPOCH_LENGTH`.
    /// `genesisEpoch` is the index of the epoch in which the pool is deployed.
    /// @dev No reward gets paid and proposals are not allowed in the genesis
    /// epoch
    uint256 public immutable genesisEpoch;

    /// @notice API3 token contract
    IApi3Token public immutable api3Token;

    /// @notice TimelockManager contract
    address public immutable timelockManager;

    /// @notice Address of the primary Agent app of the API3 DAO
    /// @dev Primary Agent can be operated through the primary Api3Voting app.
    /// The primary Api3Voting app requires a higher quorum by default, and the
    /// primary Agent is more privileged.
    address public agentAppPrimary;

    /// @notice Address of the secondary Agent app of the API3 DAO
    /// @dev Secondary Agent can be operated through the secondary Api3Voting
    /// app. The secondary Api3Voting app requires a lower quorum by default,
    /// and the primary Agent is less privileged.
    address public agentAppSecondary;

    /// @notice Address of the primary Api3Voting app of the API3 DAO
    /// @dev Used to operate the primary Agent
    address public votingAppPrimary;

    /// @notice Address of the secondary Api3Voting app of the API3 DAO
    /// @dev Used to operate the secondary Agent
    address public votingAppSecondary;

    /// @notice Mapping that keeps the claims manager statuses of addresses
    /// @dev A claims manager is a contract that is authorized to pay out
    /// claims from the staking pool, effectively slashing the stakers. The
    /// statuses are kept as a mapping to support multiple claims managers.
    mapping(address => bool) public claimsManagerStatus;

    /// @notice Records of rewards paid in each epoch
    /// @dev `.atBlock` of a past epoch's reward record being `0` means no
    /// reward was paid for that epoch
    mapping(uint256 => Reward) public epochIndexToReward;

    /// @notice Epoch index of the most recent reward
    uint256 public epochIndexOfLastReward;

    /// @notice Total number of tokens staked at the pool
    uint256 public totalStake;

    /// @notice Stake target the pool will aim to meet in percentages of the
    /// total token supply. The staking rewards increase if the total staked
    /// amount is below this, and vice versa.
    /// @dev Default value is 50% of the total API3 token supply. This
    /// parameter is governable by the DAO.
    uint256 public stakeTarget = ONE_PERCENT * 50;

    /// @notice Minimum APR (annual percentage rate) the pool will pay as
    /// staking rewards in percentages
    /// @dev Default value is 2.5%. This parameter is governable by the DAO.
    uint256 public minApr = ONE_PERCENT * 25 / 10;

    /// @notice Maximum APR (annual percentage rate) the pool will pay as
    /// staking rewards in percentages
    /// @dev Default value is 75%. This parameter is governable by the DAO.
    uint256 public maxApr = ONE_PERCENT * 75;

    /// @notice Steps in which APR will be updated in percentages
    /// @dev Default value is 1%. This parameter is governable by the DAO.
    uint256 public aprUpdateStep = ONE_PERCENT;

    /// @notice Users need to schedule an unstake and wait for
    /// `unstakeWaitPeriod` before being able to unstake. This is to prevent
    /// the stakers from frontrunning insurance claims by unstaking to evade
    /// them, or repeatedly unstake/stake to work around the proposal spam
    /// protection. The tokens awaiting to be unstaked during this period do
    /// not grant voting power or rewards.
    /// @dev This parameter is governable by the DAO, and the DAO is expected
    /// to set this to a value that is large enough to allow insurance claims
    /// to be resolved.
    uint256 public unstakeWaitPeriod = EPOCH_LENGTH;

    /// @notice Minimum voting power the users must have to be able to make
    /// proposals (in percentages)
    /// @dev Delegations count towards voting power.
    /// Default value is 0.1%. This parameter is governable by the DAO.
    uint256 public proposalVotingPowerThreshold = ONE_PERCENT / 10;

    /// @notice APR that will be paid next epoch
    /// @dev This value will reach an equilibrium based on the stake target.
    /// Every epoch (week), APR/52 of the total staked tokens will be added to
    /// the pool, effectively distributing them to the stakers.
    uint256 public apr = (maxApr + minApr) / 2;

    /// @notice User records
    mapping(address => User) public users;

    // Keeps the total number of shares of the pool
    Checkpoint[] public poolShares;

    // Keeps user states used in `withdrawPrecalculated()` calls
    mapping(address => LockedCalculation) public userToLockedCalculation;

    // Kept to prevent third parties from frontrunning the initialization
    // `setDaoApps()` call and grief the deployment
    address private deployer;

    /// @dev Reverts if the caller is not an API3 DAO Agent
    modifier onlyAgentApp() {
        require(
            msg.sender == agentAppPrimary || msg.sender == agentAppSecondary,
            "Pool: Caller not agent"
            );
        _;
    }

    /// @dev Reverts if the caller is not the primary API3 DAO Agent
    modifier onlyAgentAppPrimary() {
        require(
            msg.sender == agentAppPrimary,
            "Pool: Caller not primary agent"
            );
        _;
    }

    /// @dev Reverts if the caller is not an API3 DAO Api3Voting app
    modifier onlyVotingApp() {
        require(
            msg.sender == votingAppPrimary || msg.sender == votingAppSecondary,
            "Pool: Caller not voting app"
            );
        _;
    }

    /// @param api3TokenAddress API3 token contract address
    /// @param timelockManagerAddress Timelock manager contract address
    constructor(
        address api3TokenAddress,
        address timelockManagerAddress
        )
    {
        require(
            api3TokenAddress != address(0),
            "Pool: Invalid Api3Token"
            );
        require(
            timelockManagerAddress != address(0),
            "Pool: Invalid TimelockManager"
            );
        deployer = msg.sender;
        api3Token = IApi3Token(api3TokenAddress);
        timelockManager = timelockManagerAddress;
        // Initialize the share price at 1
        updateCheckpointArray(poolShares, 1);
        totalStake = 1;
        // Set the current epoch as the genesis epoch and skip its reward
        // payment
        uint256 currentEpoch = block.timestamp / EPOCH_LENGTH;
        genesisEpoch = currentEpoch;
        epochIndexOfLastReward = currentEpoch;
    }

    /// @notice Called after deployment to set the addresses of the DAO apps
    /// @dev This can also be called later on by the primary Agent to update
    /// all app addresses as a means of an upgrade
    /// @param _agentAppPrimary Address of the primary Agent
    /// @param _agentAppSecondary Address of the secondary Agent
    /// @param _votingAppPrimary Address of the primary Api3Voting app
    /// @param _votingAppSecondary Address of the secondary Api3Voting app
    function setDaoApps(
        address _agentAppPrimary,
        address _agentAppSecondary,
        address _votingAppPrimary,
        address _votingAppSecondary
        )
        external
        override
    {
        // solhint-disable-next-line reason-string
        require(
            msg.sender == agentAppPrimary
                || (agentAppPrimary == address(0) && msg.sender == deployer),
            "Pool: Caller not primary agent or deployer initializing values"
            );
        require(
            _agentAppPrimary != address(0)
                && _agentAppSecondary != address(0)
                && _votingAppPrimary != address(0)
                && _votingAppSecondary != address(0),
            "Pool: Invalid DAO apps"
            );
        agentAppPrimary = _agentAppPrimary;
        agentAppSecondary = _agentAppSecondary;
        votingAppPrimary = _votingAppPrimary;
        votingAppSecondary = _votingAppSecondary;
        emit SetDaoApps(
            agentAppPrimary,
            agentAppSecondary,
            votingAppPrimary,
            votingAppSecondary
            );
    }

    /// @notice Called by the primary DAO Agent to set the authorization status
    /// of a claims manager contract
    /// @dev The claims manager is a trusted contract that is allowed to
    /// withdraw as many tokens as it wants from the pool to pay out insurance
    /// claims.
    /// Only the primary Agent can do this because it is a critical operation.
    /// WARNING: A compromised contract being given claims manager status may
    /// result in loss of staked funds. If a proposal has been made to call
    /// this method to set a contract as a claims manager, you are recommended
    /// to review the contract yourself and/or refer to the audit reports to
    /// understand the implications.
    /// @param claimsManager Claims manager contract address
    /// @param status Authorization status
    function setClaimsManagerStatus(
        address claimsManager,
        bool status
        )
        external
        override
        onlyAgentAppPrimary()
    {
        claimsManagerStatus[claimsManager] = status;
        emit SetClaimsManagerStatus(
            claimsManager,
            status
            );
    }

    /// @notice Called by the DAO Agent to set the stake target
    /// @param _stakeTarget Stake target
    function setStakeTarget(uint256 _stakeTarget)
        external
        override
        onlyAgentApp()
    {
        require(
            _stakeTarget <= HUNDRED_PERCENT,
            "Pool: Invalid percentage value"
            );
        stakeTarget = _stakeTarget;
        emit SetStakeTarget(_stakeTarget);
    }

    /// @notice Called by the DAO Agent to set the maximum APR
    /// @param _maxApr Maximum APR
    function setMaxApr(uint256 _maxApr)
        external
        override
        onlyAgentApp()
    {
        require(
            _maxApr >= minApr,
            "Pool: Max APR smaller than min"
            );
        maxApr = _maxApr;
        emit SetMaxApr(_maxApr);
    }

    /// @notice Called by the DAO Agent to set the minimum APR
    /// @param _minApr Minimum APR
    function setMinApr(uint256 _minApr)
        external
        override
        onlyAgentApp()
    {
        require(
            _minApr <= maxApr,
            "Pool: Min APR larger than max"
            );
        minApr = _minApr;
        emit SetMinApr(_minApr);
    }

    /// @notice Called by the primary DAO Agent to set the unstake waiting
    /// period
    /// @dev This may want to be increased to provide more time for insurance
    /// claims to be resolved.
    /// Even when the insurance functionality is not implemented, the minimum
    /// valid value is `EPOCH_LENGTH` to prevent users from unstaking,
    /// withdrawing and staking with another address to work around the
    /// proposal spam protection.
    /// Only the primary Agent can do this because it is a critical operation.
    /// @param _unstakeWaitPeriod Unstake waiting period
    function setUnstakeWaitPeriod(uint256 _unstakeWaitPeriod)
        external
        override
        onlyAgentAppPrimary()
    {
        require(
            _unstakeWaitPeriod >= EPOCH_LENGTH,
            "Pool: Period shorter than epoch"
            );
        unstakeWaitPeriod = _unstakeWaitPeriod;
        emit SetUnstakeWaitPeriod(_unstakeWaitPeriod);
    }

    /// @notice Called by the primary DAO Agent to set the APR update steps
    /// @dev aprUpdateStep can be 0% or 100%+.
    /// Only the primary Agent can do this because it is a critical operation.
    /// @param _aprUpdateStep APR update steps
    function setAprUpdateStep(uint256 _aprUpdateStep)
        external
        override
        onlyAgentAppPrimary()
    {
        aprUpdateStep = _aprUpdateStep;
        emit SetAprUpdateStep(_aprUpdateStep);
    }

    /// @notice Called by the primary DAO Agent to set the voting power
    /// threshold for proposals
    /// @dev Only the primary Agent can do this because it is a critical
    /// operation.
    /// @param _proposalVotingPowerThreshold Voting power threshold for
    /// proposals
    function setProposalVotingPowerThreshold(uint256 _proposalVotingPowerThreshold)
        external
        override
        onlyAgentAppPrimary()
    {
        require(
            _proposalVotingPowerThreshold >= ONE_PERCENT / 10
                && _proposalVotingPowerThreshold <= ONE_PERCENT * 10,
            "Pool: Threshold outside limits");
        proposalVotingPowerThreshold = _proposalVotingPowerThreshold;
        emit SetProposalVotingPowerThreshold(_proposalVotingPowerThreshold);
    }

    /// @notice Called by a DAO Api3Voting app at proposal creation-time to
    /// update the timestamp of the user's last proposal
    /// @param userAddress User address
    function updateLastProposalTimestamp(address userAddress)
        external
        override
        onlyVotingApp()
    {
        users[userAddress].lastProposalTimestamp = block.timestamp;
        emit UpdatedLastProposalTimestamp(
            userAddress,
            block.timestamp,
            msg.sender
            );
    }

    /// @notice Called to check if we are in the genesis epoch
    /// @dev Voting apps use this to prevent proposals from being made in the
    /// genesis epoch
    /// @return If the current epoch is the genesis epoch
    function isGenesisEpoch()
        external
        view
        override
        returns (bool)
    {
        return block.timestamp / EPOCH_LENGTH == genesisEpoch;
    }

    /// @notice Called internally to update a checkpoint array by pushing a new
    /// checkpoint
    /// @dev We assume `block.number` will always fit in a uint32 and `value`
    /// will always fit in a uint224. `value` will either be a raw token amount
    /// or a raw pool share amount so this assumption will be correct in
    /// practice with a token with 18 decimals, 1e8 initial total supply and no
    /// hyperinflation.
    /// @param checkpointArray Checkpoint array
    /// @param value Value to be used to create the new checkpoint
    function updateCheckpointArray(
        Checkpoint[] storage checkpointArray,
        uint256 value
        )
        internal
    {
        assert(block.number <= MAX_UINT32);
        assert(value <= MAX_UINT224);
        checkpointArray.push(Checkpoint({
            fromBlock: uint32(block.number),
            value: uint224(value)
            }));
    }

    /// @notice Called internally to update an address-checkpoint array by
    /// pushing a new checkpoint
    /// @dev We assume `block.number` will always fit in a uint32
    /// @param addressCheckpointArray Address-checkpoint array
    /// @param _address Address to be used to create the new checkpoint
    function updateAddressCheckpointArray(
        AddressCheckpoint[] storage addressCheckpointArray,
        address _address
        )
        internal
    {
        assert(block.number <= MAX_UINT32);
        addressCheckpointArray.push(AddressCheckpoint({
            fromBlock: uint32(block.number),
            _address: _address
            }));
    }
}


// File contracts/interfaces/IGetterUtils.sol

pragma solidity 0.8.4;

interface IGetterUtils is IStateUtils {
    function userVotingPowerAt(
        address userAddress,
        uint256 _block
        )
        external
        view
        returns (uint256);

    function userVotingPower(address userAddress)
        external
        view
        returns (uint256);

    function totalSharesAt(uint256 _block)
        external
        view
        returns (uint256);

    function totalShares()
        external
        view
        returns (uint256);

    function userSharesAt(
        address userAddress,
        uint256 _block
        )
        external
        view
        returns (uint256);

    function userShares(address userAddress)
        external
        view
        returns (uint256);

    function userStake(address userAddress)
        external
        view
        returns (uint256);

    function delegatedToUserAt(
        address userAddress,
        uint256 _block
        )
        external
        view
        returns (uint256);

    function delegatedToUser(address userAddress)
        external
        view
        returns (uint256);

    function userDelegateAt(
        address userAddress,
        uint256 _block
        )
        external
        view
        returns (address);

    function userDelegate(address userAddress)
        external
        view
        returns (address);

    function userLocked(address userAddress)
        external
        view
        returns (uint256);

    function getUser(address userAddress)
        external
        view
        returns (
            uint256 unstaked,
            uint256 vesting,
            uint256 unstakeShares,
            uint256 unstakeAmount,
            uint256 unstakeScheduledFor,
            uint256 lastDelegationUpdateTimestamp,
            uint256 lastProposalTimestamp
            );
}


// File contracts/GetterUtils.sol

pragma solidity 0.8.4;


/// @title Contract that implements getters
abstract contract GetterUtils is StateUtils, IGetterUtils {
    /// @notice Called to get the voting power of a user at a specific block
    /// @param userAddress User address
    /// @param _block Block number for which the query is being made for
    /// @return Voting power of the user at the block
    function userVotingPowerAt(
        address userAddress,
        uint256 _block
        )
        public
        view
        override
        returns (uint256)
    {
        // Users that have a delegate have no voting power
        if (userDelegateAt(userAddress, _block) != address(0))
        {
            return 0;
        }
        return userSharesAt(userAddress, _block)
            + delegatedToUserAt(userAddress, _block);
    }

    /// @notice Called to get the current voting power of a user
    /// @param userAddress User address
    /// @return Current voting power of the user
    function userVotingPower(address userAddress)
        external
        view
        override
        returns (uint256)
    {
        return userVotingPowerAt(userAddress, block.number);
    }

    /// @notice Called to get the total pool shares at a specific block
    /// @dev Total pool shares also corresponds to total voting power
    /// @param _block Block number for which the query is being made for
    /// @return Total pool shares at the block
    function totalSharesAt(uint256 _block)
        public
        view
        override
        returns (uint256)
    {
        return getValueAt(poolShares, _block);
    }

    /// @notice Called to get the current total pool shares
    /// @dev Total pool shares also corresponds to total voting power
    /// @return Current total pool shares
    function totalShares()
        public
        view
        override
        returns (uint256)
    {
        return totalSharesAt(block.number);
    }

    /// @notice Called to get the pool shares of a user at a specific block
    /// @param userAddress User address
    /// @param _block Block number for which the query is being made for
    /// @return Pool shares of the user at the block
    function userSharesAt(
        address userAddress,
        uint256 _block
        )
        public
        view
        override
        returns (uint256)
    {
        return getValueAt(users[userAddress].shares, _block);
    }

    /// @notice Called to get the current pool shares of a user
    /// @param userAddress User address
    /// @return Current pool shares of the user
    function userShares(address userAddress)
        public
        view
        override
        returns (uint256)
    {
        return userSharesAt(userAddress, block.number);
    }

    /// @notice Called to get the current staked tokens of the user
    /// @param userAddress User address
    /// @return Current staked tokens of the user
    function userStake(address userAddress)
        public
        view
        override
        returns (uint256)
    {
        return userShares(userAddress) * totalStake / totalShares();
    }

    /// @notice Called to get the voting power delegated to a user at a
    /// specific block
    /// @param userAddress User address
    /// @param _block Block number for which the query is being made for
    /// @return Voting power delegated to the user at the block
    function delegatedToUserAt(
        address userAddress,
        uint256 _block
        )
        public
        view
        override
        returns (uint256)
    {
        return getValueAt(users[userAddress].delegatedTo, _block);
    }

    /// @notice Called to get the current voting power delegated to a user
    /// @param userAddress User address
    /// @return Current voting power delegated to the user
    function delegatedToUser(address userAddress)
        public
        view
        override
        returns (uint256)
    {
        return delegatedToUserAt(userAddress, block.number);
    }

    /// @notice Called to get the delegate of the user at a specific block
    /// @param userAddress User address
    /// @param _block Block number
    /// @return Delegate of the user at the specific block
    function userDelegateAt(
        address userAddress,
        uint256 _block
        )
        public
        view
        override
        returns (address)
    {
        return getAddressAt(users[userAddress].delegates, _block);
    }

    /// @notice Called to get the current delegate of the user
    /// @param userAddress User address
    /// @return Current delegate of the user
    function userDelegate(address userAddress)
        public
        view
        override
        returns (address)
    {
        return userDelegateAt(userAddress, block.number);
    }

    /// @notice Called to get the current locked tokens of the user
    /// @param userAddress User address
    /// @return locked Current locked tokens of the user
    function userLocked(address userAddress)
        public
        view
        override
        returns (uint256 locked)
    {
        Checkpoint[] storage _userShares = users[userAddress].shares;
        uint256 currentEpoch = block.timestamp / EPOCH_LENGTH;
        uint256 oldestLockedEpoch = getOldestLockedEpoch();
        uint256 indUserShares = _userShares.length;
        for (
                uint256 indEpoch = currentEpoch;
                indEpoch >= oldestLockedEpoch;
                indEpoch--
            )
        {
            // The user has never staked at this point, we can exit early
            if (indUserShares == 0)
            {
                break;
            }
            Reward storage lockedReward = epochIndexToReward[indEpoch];
            if (lockedReward.atBlock != 0)
            {
                for (; indUserShares > 0; indUserShares--)
                {
                    Checkpoint storage userShare = _userShares[indUserShares - 1];
                    if (userShare.fromBlock <= lockedReward.atBlock)
                    {
                        locked += lockedReward.amount * userShare.value / lockedReward.totalSharesThen;
                        break;
                    }
                }
            }
        }
    }

    /// @notice Called to get the details of a user
    /// @param userAddress User address
    /// @return unstaked Amount of unstaked API3 tokens
    /// @return vesting Amount of API3 tokens locked by vesting
    /// @return unstakeAmount Amount scheduled to unstake
    /// @return unstakeShares Shares revoked to unstake
    /// @return unstakeScheduledFor Time unstaking is scheduled for
    /// @return lastDelegationUpdateTimestamp Time of last delegation update
    /// @return lastProposalTimestamp Time when the user made their most
    /// recent proposal
    function getUser(address userAddress)
        external
        view
        override
        returns (
            uint256 unstaked,
            uint256 vesting,
            uint256 unstakeAmount,
            uint256 unstakeShares,
            uint256 unstakeScheduledFor,
            uint256 lastDelegationUpdateTimestamp,
            uint256 lastProposalTimestamp
            )
    {
        User storage user = users[userAddress];
        unstaked = user.unstaked;
        vesting = user.vesting;
        unstakeAmount = user.unstakeAmount;
        unstakeShares = user.unstakeShares;
        unstakeScheduledFor = user.unstakeScheduledFor;
        lastDelegationUpdateTimestamp = user.lastDelegationUpdateTimestamp;
        lastProposalTimestamp = user.lastProposalTimestamp;
    }

    /// @notice Called to get the value of a checkpoint array at a specific
    /// block using binary search
    /// @dev Adapted from
    /// https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L431
    /// @param checkpoints Checkpoints array
    /// @param _block Block number for which the query is being made
    /// @return Value of the checkpoint array at the block
    function getValueAt(
        Checkpoint[] storage checkpoints,
        uint256 _block
        )
        internal
        view
        returns (uint256)
    {
        if (checkpoints.length == 0)
            return 0;

        // Shortcut for the actual value
        if (_block >= checkpoints[checkpoints.length -1].fromBlock)
            return checkpoints[checkpoints.length - 1].value;
        if (_block < checkpoints[0].fromBlock)
            return 0;

        // Limit the search to the last 1024 elements if the value being
        // searched falls within that window
        uint min = 0;
        if (
            checkpoints.length > 1024
                && checkpoints[checkpoints.length - 1024].fromBlock < _block
            )
        {
            min = checkpoints.length - 1024;
        }

        // Binary search of the value in the array
        uint max = checkpoints.length - 1;
        while (max > min) {
            uint mid = (max + min + 1) / 2;
            if (checkpoints[mid].fromBlock <= _block) {
                min = mid;
            } else {
                max = mid - 1;
            }
        }
        return checkpoints[min].value;
    }

    /// @notice Called to get the value of an address-checkpoint array at a
    /// specific block using binary search
    /// @dev Adapted from
    /// https://github.com/aragon/minime/blob/1d5251fc88eee5024ff318d95bc9f4c5de130430/contracts/MiniMeToken.sol#L431
    /// @param checkpoints Address-checkpoint array
    /// @param _block Block number for which the query is being made
    /// @return Value of the address-checkpoint array at the block
    function getAddressAt(
        AddressCheckpoint[] storage checkpoints,
        uint256 _block
        )
        private
        view
        returns (address)
    {
        if (checkpoints.length == 0)
            return address(0);

        // Shortcut for the actual value
        if (_block >= checkpoints[checkpoints.length -1].fromBlock)
            return checkpoints[checkpoints.length - 1]._address;
        if (_block < checkpoints[0].fromBlock)
            return address(0);

        // Limit the search to the last 1024 elements if the value being
        // searched falls within that window
        uint min = 0;
        if (
            checkpoints.length > 1024
                && checkpoints[checkpoints.length - 1024].fromBlock < _block
            )
        {
            min = checkpoints.length - 1024;
        }

        // Binary search of the value in the array
        uint max = checkpoints.length - 1;
        while (max > min) {
            uint mid = (max + min + 1) / 2;
            if (checkpoints[mid].fromBlock <= _block) {
                min = mid;
            } else {
                max = mid - 1;
            }
        }
        return checkpoints[min]._address;
    }

    /// @notice Called internally to get the index of the oldest epoch whose
    /// reward should be locked in the current epoch
    /// @return oldestLockedEpoch Index of the oldest epoch with locked rewards
    function getOldestLockedEpoch()
        internal
        view
        returns (uint256 oldestLockedEpoch)
    {
        uint256 currentEpoch = block.timestamp / EPOCH_LENGTH;
        oldestLockedEpoch = currentEpoch - REWARD_VESTING_PERIOD + 1;
        if (oldestLockedEpoch < genesisEpoch + 1)
        {
            oldestLockedEpoch = genesisEpoch + 1;
        }
    }
}


// File contracts/interfaces/IRewardUtils.sol

pragma solidity 0.8.4;

interface IRewardUtils is IGetterUtils {
    event MintedReward(
        uint256 indexed epochIndex,
        uint256 amount,
        uint256 newApr,
        uint256 totalStake
        );

    function mintReward()
        external;
}


// File contracts/RewardUtils.sol

pragma solidity 0.8.4;


/// @title Contract that implements reward payments
abstract contract RewardUtils is GetterUtils, IRewardUtils {
    /// @notice Called to mint the staking reward
    /// @dev Skips past epochs for which rewards have not been paid for.
    /// Skips the reward payment if the pool is not authorized to mint tokens.
    /// Neither of these conditions will occur in practice.
    function mintReward()
        public
        override
    {
        uint256 currentEpoch = block.timestamp / EPOCH_LENGTH;
        // This will be skipped in most cases because someone else will have
        // triggered the payment for this epoch
        if (epochIndexOfLastReward < currentEpoch)
        {
            if (api3Token.getMinterStatus(address(this)))
            {
                uint256 rewardAmount = totalStake * apr * EPOCH_LENGTH / 365 days / HUNDRED_PERCENT;
                assert(block.number <= MAX_UINT32);
                assert(rewardAmount <= MAX_UINT224);
                epochIndexToReward[currentEpoch] = Reward({
                    atBlock: uint32(block.number),
                    amount: uint224(rewardAmount),
                    totalSharesThen: totalShares(),
                    totalStakeThen: totalStake
                    });
                api3Token.mint(address(this), rewardAmount);
                totalStake += rewardAmount;
                updateCurrentApr();
                emit MintedReward(
                    currentEpoch,
                    rewardAmount,
                    apr,
                    totalStake
                    );
            }
            epochIndexOfLastReward = currentEpoch;
        }
    }

    /// @notice Updates the current APR
    /// @dev Called internally after paying out the reward
    function updateCurrentApr()
        internal
    {
        uint256 totalStakePercentage = totalStake
            * HUNDRED_PERCENT
            / api3Token.totalSupply();
        if (totalStakePercentage > stakeTarget)
        {
            apr = apr > aprUpdateStep ? apr - aprUpdateStep : 0;
        }
        else
        {
            apr += aprUpdateStep;
        }
        if (apr > maxApr) {
            apr = maxApr;
        }
        else if (apr < minApr) {
            apr = minApr;
        }
    }
}


// File contracts/interfaces/IDelegationUtils.sol

pragma solidity 0.8.4;

interface IDelegationUtils is IRewardUtils {
    event Delegated(
        address indexed user,
        address indexed delegate,
        uint256 shares,
        uint256 totalDelegatedTo
        );

    event Undelegated(
        address indexed user,
        address indexed delegate,
        uint256 shares,
        uint256 totalDelegatedTo
        );

    event UpdatedDelegation(
        address indexed user,
        address indexed delegate,
        bool delta,
        uint256 shares,
        uint256 totalDelegatedTo
        );

    function delegateVotingPower(address delegate) 
        external;

    function undelegateVotingPower()
        external;

    
}


// File contracts/DelegationUtils.sol

pragma solidity 0.8.4;


/// @title Contract that implements voting power delegation
abstract contract DelegationUtils is RewardUtils, IDelegationUtils {
    /// @notice Called by the user to delegate voting power
    /// @param delegate User address the voting power will be delegated to
    function delegateVotingPower(address delegate) 
        external
        override
    {
        mintReward();
        require(
            delegate != address(0) && delegate != msg.sender,
            "Pool: Invalid delegate"
            );
        // Delegating users cannot use their voting power, so we are
        // verifying that the delegate is not currently delegating. However,
        // the delegate may delegate after they have been delegated to.
        require(
            userDelegate(delegate) == address(0),
            "Pool: Delegate is delegating"
            );
        User storage user = users[msg.sender];
        // Do not allow frequent delegation updates as that can be used to spam
        // proposals
        require(
            user.lastDelegationUpdateTimestamp + EPOCH_LENGTH < block.timestamp,
            "Pool: Updated delegate recently"
            );
        user.lastDelegationUpdateTimestamp = block.timestamp;

        uint256 userShares = userShares(msg.sender);
        require(
            userShares != 0,
            "Pool: Have no shares to delegate"
            );

        address previousDelegate = userDelegate(msg.sender);
        require(
            previousDelegate != delegate,
            "Pool: Already delegated"
            );
        if (previousDelegate != address(0)) {
            // Need to revoke previous delegation
            updateCheckpointArray(
                users[previousDelegate].delegatedTo,
                delegatedToUser(previousDelegate) - userShares
                );
        }

        // Assign the new delegation
        uint256 delegatedToUpdate = delegatedToUser(delegate) + userShares;
        updateCheckpointArray(
            users[delegate].delegatedTo,
            delegatedToUpdate
            );

        // Record the new delegate for the user
        updateAddressCheckpointArray(
            user.delegates,
            delegate
            );
        emit Delegated(
            msg.sender,
            delegate,
            userShares,
            delegatedToUpdate
            );
    }

    /// @notice Called by the user to undelegate voting power
    function undelegateVotingPower()
        external
        override
    {
        mintReward();
        User storage user = users[msg.sender];
        address previousDelegate = userDelegate(msg.sender);
        require(
            previousDelegate != address(0),
            "Pool: Not delegated"
            );
        require(
            user.lastDelegationUpdateTimestamp + EPOCH_LENGTH < block.timestamp,
            "Pool: Updated delegate recently"
            );
        user.lastDelegationUpdateTimestamp = block.timestamp;

        uint256 userShares = userShares(msg.sender);
        uint256 delegatedToUpdate = delegatedToUser(previousDelegate) - userShares;
        updateCheckpointArray(
            users[previousDelegate].delegatedTo,
            delegatedToUpdate
            );
        updateAddressCheckpointArray(
            user.delegates,
            address(0)
            );
        emit Undelegated(
            msg.sender,
            previousDelegate,
            userShares,
            delegatedToUpdate
            );
    }

    /// @notice Called internally when the user shares are updated to update
    /// the delegated voting power
    /// @dev User shares only get updated while staking or scheduling unstaking
    /// @param shares Amount of shares that will be added/removed
    /// @param delta Whether the shares will be added/removed (add for `true`,
    /// and vice versa)
    function updateDelegatedVotingPower(
        uint256 shares,
        bool delta
        )
        internal
    {
        address delegate = userDelegate(msg.sender);
        if (delegate == address(0))
        {
            return;
        }
        uint256 currentDelegatedTo = delegatedToUser(delegate);
        uint256 delegatedToUpdate = delta
            ? currentDelegatedTo + shares
            : currentDelegatedTo - shares;
        updateCheckpointArray(
            users[delegate].delegatedTo,
            delegatedToUpdate
            );
        emit UpdatedDelegation(
            msg.sender,
            delegate,
            delta,
            shares,
            delegatedToUpdate
            );
    }
}


// File contracts/interfaces/ITransferUtils.sol

pragma solidity 0.8.4;

interface ITransferUtils is IDelegationUtils{
    event Deposited(
        address indexed user,
        uint256 amount,
        uint256 userUnstaked
        );

    event Withdrawn(
        address indexed user,
        uint256 amount,
        uint256 userUnstaked
        );

    event CalculatingUserLocked(
        address indexed user,
        uint256 nextIndEpoch,
        uint256 oldestLockedEpoch
        );

    event CalculatedUserLocked(
        address indexed user,
        uint256 amount
        );

    function depositRegular(uint256 amount)
        external;

    function withdrawRegular(uint256 amount)
        external;

    function precalculateUserLocked(
        address userAddress,
        uint256 noEpochsPerIteration
        )
        external
        returns (bool finished);

    function withdrawPrecalculated(uint256 amount)
        external;
}


// File contracts/TransferUtils.sol

pragma solidity 0.8.4;


/// @title Contract that implements token transfer functionality
abstract contract TransferUtils is DelegationUtils, ITransferUtils {
    /// @notice Called by the user to deposit tokens
    /// @dev The user should approve the pool to spend at least `amount` tokens
    /// before calling this.
    /// The method is named `depositRegular()` to prevent potential confusion.
    /// See `deposit()` for more context.
    /// @param amount Amount to be deposited
    function depositRegular(uint256 amount)
        public
        override
    {
        mintReward();
        uint256 unstakedUpdate = users[msg.sender].unstaked + amount;
        users[msg.sender].unstaked = unstakedUpdate;
        // Should never return false because the API3 token uses the
        // OpenZeppelin implementation
        assert(api3Token.transferFrom(msg.sender, address(this), amount));
        emit Deposited(
            msg.sender,
            amount,
            unstakedUpdate
            );
    }

    /// @notice Called by the user to withdraw tokens to their wallet
    /// @dev The user should call `userLocked()` beforehand to ensure that
    /// they have at least `amount` unlocked tokens to withdraw.
    /// The method is named `withdrawRegular()` to be consistent with the name
    /// `depositRegular()`. See `depositRegular()` for more context.
    /// @param amount Amount to be withdrawn
    function withdrawRegular(uint256 amount)
        public
        override
    {
        mintReward();
        withdraw(amount, userLocked(msg.sender));
    }

    /// @notice Called to calculate the locked tokens of a user by making
    /// multiple transactions
    /// @dev If the user updates their `user.shares` by staking/unstaking too
    /// frequently (50+/week) in the last `REWARD_VESTING_PERIOD`, the
    /// `userLocked()` call gas cost may exceed the block gas limit. In that
    /// case, the user may call this method multiple times to have their locked
    /// tokens calculated and use `withdrawPrecalculated()` to withdraw.
    /// @param userAddress User address
    /// @param noEpochsPerIteration Number of epochs per iteration
    /// @return finished Calculation has finished in this call
    function precalculateUserLocked(
        address userAddress,
        uint256 noEpochsPerIteration
        )
        external
        override
        returns (bool finished)
    {
        mintReward();
        require(
            noEpochsPerIteration > 0,
            "Pool: Zero iteration window"
            );
        uint256 currentEpoch = block.timestamp / EPOCH_LENGTH;
        LockedCalculation storage lockedCalculation = userToLockedCalculation[userAddress];
        // Reset the state if there was no calculation made in this epoch
        if (lockedCalculation.initialIndEpoch != currentEpoch)
        {
            lockedCalculation.initialIndEpoch = currentEpoch;
            lockedCalculation.nextIndEpoch = currentEpoch;
            lockedCalculation.locked = 0;
        }
        uint256 indEpoch = lockedCalculation.nextIndEpoch;
        uint256 locked = lockedCalculation.locked;
        uint256 oldestLockedEpoch = getOldestLockedEpoch();
        for (; indEpoch >= oldestLockedEpoch; indEpoch--)
        {
            if (lockedCalculation.nextIndEpoch >= indEpoch + noEpochsPerIteration)
            {
                lockedCalculation.nextIndEpoch = indEpoch;
                lockedCalculation.locked = locked;
                emit CalculatingUserLocked(
                    userAddress,
                    indEpoch,
                    oldestLockedEpoch
                    );
                return false;
            }
            Reward storage lockedReward = epochIndexToReward[indEpoch];
            if (lockedReward.atBlock != 0)
            {
                uint256 userSharesThen = userSharesAt(userAddress, lockedReward.atBlock);
                locked += lockedReward.amount * userSharesThen / lockedReward.totalSharesThen;
            }
        }
        lockedCalculation.nextIndEpoch = indEpoch;
        lockedCalculation.locked = locked;
        emit CalculatedUserLocked(userAddress, locked);
        return true;
    }

    /// @notice Called by the user to withdraw after their locked token amount
    /// is calculated with repeated calls to `precalculateUserLocked()`
    /// @dev Only use `precalculateUserLocked()` and this method if
    /// `withdrawRegular()` hits the block gas limit
    /// @param amount Amount to be withdrawn
    function withdrawPrecalculated(uint256 amount)
        external
        override
    {
        mintReward();
        uint256 currentEpoch = block.timestamp / EPOCH_LENGTH;
        LockedCalculation storage lockedCalculation = userToLockedCalculation[msg.sender];
        require(
            lockedCalculation.initialIndEpoch == currentEpoch,
            "Pool: Calculation not up to date"
            );
        require(
            lockedCalculation.nextIndEpoch < getOldestLockedEpoch(),
            "Pool: Calculation not complete"
            );
        withdraw(amount, lockedCalculation.locked);
    }

    /// @notice Called internally after the amount of locked tokens of the user
    /// is determined
    /// @param amount Amount to be withdrawn
    /// @param userLocked Amount of locked tokens of the user
    function withdraw(
        uint256 amount,
        uint256 userLocked
        )
        private
    {
        User storage user = users[msg.sender];
        // Check if the user has `amount` unlocked tokens to withdraw
        uint256 lockedAndVesting = userLocked + user.vesting;
        uint256 userTotalFunds = user.unstaked + userStake(msg.sender);
        require(
            userTotalFunds >= lockedAndVesting + amount,
            "Pool: Not enough unlocked funds"
            );
        require(
            user.unstaked >= amount,
            "Pool: Not enough unstaked funds"
            );
        // Carry on with the withdrawal
        uint256 unstakedUpdate = user.unstaked - amount;
        user.unstaked = unstakedUpdate;
        // Should never return false because the API3 token uses the
        // OpenZeppelin implementation
        assert(api3Token.transfer(msg.sender, amount));
        emit Withdrawn(
            msg.sender,
            amount,
            unstakedUpdate
            );
    }
}


// File contracts/interfaces/IStakeUtils.sol

pragma solidity 0.8.4;

interface IStakeUtils is ITransferUtils{
    event Staked(
        address indexed user,
        uint256 amount,
        uint256 mintedShares,
        uint256 userUnstaked,
        uint256 userShares,
        uint256 totalShares,
        uint256 totalStake
        );

    event ScheduledUnstake(
        address indexed user,
        uint256 amount,
        uint256 shares,
        uint256 scheduledFor,
        uint256 userShares
        );

    event Unstaked(
        address indexed user,
        uint256 amount,
        uint256 userUnstaked,
        uint256 totalShares,
        uint256 totalStake
        );

    function stake(uint256 amount)
        external;

    function depositAndStake(uint256 amount)
        external;

    function scheduleUnstake(uint256 amount)
        external;

    function unstake(address userAddress)
        external
        returns (uint256);

    function unstakeAndWithdraw()
        external;
}


// File contracts/StakeUtils.sol

pragma solidity 0.8.4;


/// @title Contract that implements staking functionality
abstract contract StakeUtils is TransferUtils, IStakeUtils {
    /// @notice Called to stake tokens to receive pools in the share
    /// @param amount Amount of tokens to stake
    function stake(uint256 amount)
        public
        override
    {
        mintReward();
        User storage user = users[msg.sender];
        require(
            user.unstaked >= amount,
            "Pool: Amount exceeds unstaked"
            );
        uint256 userUnstakedUpdate = user.unstaked - amount;
        user.unstaked = userUnstakedUpdate;
        uint256 totalSharesNow = totalShares();
        uint256 sharesToMint = amount * totalSharesNow / totalStake;
        uint256 userSharesUpdate = userShares(msg.sender) + sharesToMint;
        updateCheckpointArray(
            user.shares,
            userSharesUpdate
            );
        uint256 totalSharesUpdate = totalSharesNow + sharesToMint;
        updateCheckpointArray(
            poolShares,
            totalSharesUpdate
            );
        totalStake += amount;
        updateDelegatedVotingPower(sharesToMint, true);
        emit Staked(
            msg.sender,
            amount,
            sharesToMint,
            userUnstakedUpdate,
            userSharesUpdate,
            totalSharesUpdate,
            totalStake
            );
    }

    /// @notice Convenience method to deposit and stake in a single transaction
    /// @param amount Amount to be deposited and staked
    function depositAndStake(uint256 amount)
        external
        override
    {
        depositRegular(amount);
        stake(amount);
    }

    /// @notice Called by the user to schedule unstaking of their tokens
    /// @dev While scheduling an unstake, `shares` get deducted from the user,
    /// meaning that they will not receive rewards or voting power for them any
    /// longer.
    /// At unstaking-time, the user unstakes either the amount of tokens
    /// scheduled to unstake, or the amount of tokens `shares` corresponds to
    /// at unstaking-time, whichever is smaller. This corresponds to tokens
    /// being scheduled to be unstaked not receiving any rewards, but being
    /// subject to claim payouts.
    /// In the instance that a claim has been paid out before an unstaking is
    /// executed, the user may potentially receive rewards during
    /// `unstakeWaitPeriod` (but not if there has not been a claim payout) but
    /// the amount of tokens that they can unstake will not be able to exceed
    /// the amount they scheduled the unstaking for.
    /// @param amount Amount of tokens scheduled to unstake
    function scheduleUnstake(uint256 amount)
        external
        override
    {
        mintReward();
        uint256 userSharesNow = userShares(msg.sender);
        uint256 totalSharesNow = totalShares();
        uint256 userStaked = userSharesNow * totalStake / totalSharesNow;
        require(
            userStaked >= amount,
            "Pool: Amount exceeds staked"
            );

        User storage user = users[msg.sender];
        require(
            user.unstakeScheduledFor == 0,
            "Pool: Unexecuted unstake exists"
            );

        uint256 sharesToUnstake = amount * totalSharesNow / totalStake;
        // This will only happen if the user wants to schedule an unstake for a
        // few Wei
        require(sharesToUnstake > 0, "Pool: Unstake amount too small");
        uint256 unstakeScheduledFor = block.timestamp + unstakeWaitPeriod;
        user.unstakeScheduledFor = unstakeScheduledFor;
        user.unstakeAmount = amount;
        user.unstakeShares = sharesToUnstake;
        uint256 userSharesUpdate = userSharesNow - sharesToUnstake;
        updateCheckpointArray(
            user.shares,
            userSharesUpdate
            );
        updateDelegatedVotingPower(sharesToUnstake, false);
        emit ScheduledUnstake(
            msg.sender,
            amount,
            sharesToUnstake,
            unstakeScheduledFor,
            userSharesUpdate
            );
    }

    /// @notice Called to execute a pre-scheduled unstake
    /// @dev Anyone can execute a matured unstake. This is to allow the user to
    /// use bots, etc. to execute their unstaking as soon as possible.
    /// @param userAddress User address
    /// @return Amount of tokens that are unstaked
    function unstake(address userAddress)
        public
        override
        returns (uint256)
    {
        mintReward();
        User storage user = users[userAddress];
        require(
            user.unstakeScheduledFor != 0,
            "Pool: No unstake scheduled"
            );
        require(
            user.unstakeScheduledFor < block.timestamp,
            "Pool: Unstake not mature yet"
            );
        uint256 totalShares = totalShares();
        uint256 unstakeAmount = user.unstakeAmount;
        uint256 unstakeAmountByShares = user.unstakeShares * totalStake / totalShares;
        // If there was a claim payout in between the scheduling and the actual
        // unstake then the amount might be lower than expected at scheduling
        // time
        if (unstakeAmount > unstakeAmountByShares)
        {
            unstakeAmount = unstakeAmountByShares;
        }
        uint256 userUnstakedUpdate = user.unstaked + unstakeAmount;
        user.unstaked = userUnstakedUpdate;

        uint256 totalSharesUpdate = totalShares - user.unstakeShares;
        updateCheckpointArray(
            poolShares,
            totalSharesUpdate
            );
        totalStake -= unstakeAmount;

        user.unstakeAmount = 0;
        user.unstakeShares = 0;
        user.unstakeScheduledFor = 0;
        emit Unstaked(
            userAddress,
            unstakeAmount,
            userUnstakedUpdate,
            totalSharesUpdate,
            totalStake
            );
        return unstakeAmount;
    }

    /// @notice Convenience method to execute an unstake and withdraw to the
    /// user's wallet in a single transaction
    /// @dev The withdrawal will revert if the user has less than
    /// `unstakeAmount` tokens that are withdrawable
    function unstakeAndWithdraw()
        external
        override
    {
        withdrawRegular(unstake(msg.sender));
    }
}


// File contracts/interfaces/IClaimUtils.sol

pragma solidity 0.8.4;

interface IClaimUtils is IStakeUtils {
    event PaidOutClaim(
        address indexed recipient,
        uint256 amount,
        uint256 totalStake
        );

    function payOutClaim(
        address recipient,
        uint256 amount
        )
        external;
}


// File contracts/ClaimUtils.sol

pragma solidity 0.8.4;


/// @title Contract that implements the insurance claim payout functionality
abstract contract ClaimUtils is StakeUtils, IClaimUtils {
    /// @dev Reverts if the caller is not a claims manager
    modifier onlyClaimsManager() {
        require(
            claimsManagerStatus[msg.sender],
            "Pool: Caller not claims manager"
            );
        _;
    }

    /// @notice Called by a claims manager to pay out an insurance claim
    /// @dev The claims manager is a trusted contract that is allowed to
    /// withdraw as many tokens as it wants from the pool to pay out insurance
    /// claims. Any kind of limiting logic (e.g., maximum amount of tokens that
    /// can be withdrawn) is implemented at its end and is out of the scope of
    /// this contract.
    /// This will revert if the pool does not have enough staked funds.
    /// @param recipient Recipient of the claim
    /// @param amount Amount of tokens that will be paid out
    function payOutClaim(
        address recipient,
        uint256 amount
        )
        external
        override
        onlyClaimsManager()
    {
        mintReward();
        // totalStake should not go lower than 1
        require(
            totalStake > amount,
            "Pool: Amount exceeds total stake"
            );
        totalStake -= amount;
        // Should never return false because the API3 token uses the
        // OpenZeppelin implementation
        assert(api3Token.transfer(recipient, amount));
        emit PaidOutClaim(
            recipient,
            amount,
            totalStake
            );
    }
}


// File contracts/interfaces/ITimelockUtils.sol

pragma solidity 0.8.4;

interface ITimelockUtils is IClaimUtils {
    event DepositedByTimelockManager(
        address indexed user,
        uint256 amount,
        uint256 userUnstaked
        );

    event DepositedVesting(
        address indexed user,
        uint256 amount,
        uint256 start,
        uint256 end,
        uint256 userUnstaked,
        uint256 userVesting
        );

    event VestedTimelock(
        address indexed user,
        uint256 amount,
        uint256 userVesting
        );

    function deposit(
        address source,
        uint256 amount,
        address userAddress
        )
        external;

    function depositWithVesting(
        address source,
        uint256 amount,
        address userAddress,
        uint256 releaseStart,
        uint256 releaseEnd
        )
        external;

    function updateTimelockStatus(address userAddress)
        external;
}


// File contracts/TimelockUtils.sol

pragma solidity 0.8.4;


/// @title Contract that implements vesting functionality
/// @dev The TimelockManager contract interfaces with this contract to transfer
/// API3 tokens that are locked under a vesting schedule.
/// This contract keeps its own type definitions, event declarations and state
/// variables for them to be easier to remove for a subDAO where they will
/// likely not be used.
abstract contract TimelockUtils is ClaimUtils, ITimelockUtils {
    struct Timelock {
        uint256 totalAmount;
        uint256 remainingAmount;
        uint256 releaseStart;
        uint256 releaseEnd;
    }

    /// @notice Maps user addresses to timelocks
    /// @dev This implies that a user cannot have multiple timelocks
    /// transferred from the TimelockManager contract. This is acceptable
    /// because TimelockManager is implemented in a way to not allow multiple
    /// timelocks per user.
    mapping(address => Timelock) public userToTimelock;

    /// @notice Called by the TimelockManager contract to deposit tokens on
    /// behalf of a user
    /// @dev This method is only usable by `TimelockManager.sol`.
    /// It is named as `deposit()` and not `depositAsTimelockManager()` for
    /// example, because the TimelockManager is already deployed and expects
    /// the `deposit(address,uint256,address)` interface.
    /// @param source Token transfer source
    /// @param amount Amount to be deposited
    /// @param userAddress User that the tokens will be deposited for
    function deposit(
        address source,
        uint256 amount,
        address userAddress
        )
        external
        override
    {
        require(
            msg.sender == timelockManager,
            "Pool: Caller not TimelockManager"
            );
        uint256 unstakedUpdate = users[userAddress].unstaked + amount;
        users[userAddress].unstaked = unstakedUpdate;
        // Should never return false because the API3 token uses the
        // OpenZeppelin implementation
        assert(api3Token.transferFrom(source, address(this), amount));
        emit DepositedByTimelockManager(
            userAddress,
            amount,
            unstakedUpdate
            );
    }

    /// @notice Called by the TimelockManager contract to deposit tokens on
    /// behalf of a user on a linear vesting schedule
    /// @dev Refer to `TimelockManager.sol` to see how this is used
    /// @param source Token source
    /// @param amount Token amount
    /// @param userAddress Address of the user who will receive the tokens
    /// @param releaseStart Vesting schedule starting time
    /// @param releaseEnd Vesting schedule ending time
    function depositWithVesting(
        address source,
        uint256 amount,
        address userAddress,
        uint256 releaseStart,
        uint256 releaseEnd
        )
        external
        override
    {
        require(
            msg.sender == timelockManager,
            "Pool: Caller not TimelockManager"
            );
        require(
            userToTimelock[userAddress].remainingAmount == 0,
            "Pool: User has active timelock"
            );
        require(
            releaseEnd > releaseStart,
            "Pool: Timelock start after end"
            );
        require(
            amount != 0,
            "Pool: Timelock amount zero"
            );
        uint256 unstakedUpdate = users[userAddress].unstaked + amount;
        users[userAddress].unstaked = unstakedUpdate;
        uint256 vestingUpdate = users[userAddress].vesting + amount;
        users[userAddress].vesting = vestingUpdate;
        userToTimelock[userAddress] = Timelock({
            totalAmount: amount,
            remainingAmount: amount,
            releaseStart: releaseStart,
            releaseEnd: releaseEnd
            });
        // Should never return false because the API3 token uses the
        // OpenZeppelin implementation
        assert(api3Token.transferFrom(source, address(this), amount));
        emit DepositedVesting(
            userAddress,
            amount,
            releaseStart,
            releaseEnd,
            unstakedUpdate,
            vestingUpdate
            );
    }

    /// @notice Called to release tokens vested by the timelock
    /// @param userAddress Address of the user whose timelock status will be
    /// updated
    function updateTimelockStatus(address userAddress)
        external
        override
    {
        Timelock storage timelock = userToTimelock[userAddress];
        require(
            block.timestamp > timelock.releaseStart,
            "Pool: Release not started yet"
            );
        require(
            timelock.remainingAmount > 0,
            "Pool: Timelock already released"
            );
        uint256 totalUnlocked;
        if (block.timestamp >= timelock.releaseEnd)
        {
            totalUnlocked = timelock.totalAmount;
        }
        else
        {
            uint256 passedTime = block.timestamp - timelock.releaseStart;
            uint256 totalTime = timelock.releaseEnd - timelock.releaseStart;
            totalUnlocked = timelock.totalAmount * passedTime / totalTime;
        }
        uint256 previouslyUnlocked = timelock.totalAmount - timelock.remainingAmount;
        uint256 newlyUnlocked = totalUnlocked - previouslyUnlocked;
        User storage user = users[userAddress];
        uint256 vestingUpdate = user.vesting - newlyUnlocked;
        user.vesting = vestingUpdate;
        timelock.remainingAmount -= newlyUnlocked;
        emit VestedTimelock(
            userAddress,
            newlyUnlocked,
            vestingUpdate
            );
    }
}


// File contracts/interfaces/IApi3Pool.sol

pragma solidity 0.8.4;

interface IApi3Pool is ITimelockUtils {
}


// File contracts/Api3Pool.sol

pragma solidity 0.8.4;


/// @title API3 pool contract
/// @notice Users can stake API3 tokens at the pool contract to be granted
/// shares. These shares are exposed to the Aragon-based DAO, giving the user
/// voting power at the DAO. Staking pays out weekly rewards that get unlocked
/// after a year, and staked funds are used to collateralize an insurance
/// product that is outside the scope of this contract.
/// @dev Functionalities of the contract are distributed to files that form a
/// chain of inheritance:
/// (1) Api3Pool.sol
/// (2) TimelockUtils.sol
/// (3) ClaimUtils.sol
/// (4) StakeUtils.sol
/// (5) TransferUtils.sol
/// (6) DelegationUtils.sol
/// (7) RewardUtils.sol
/// (8) GetterUtils.sol
/// (9) StateUtils.sol
contract Api3Pool is TimelockUtils, IApi3Pool {
    /// @param api3TokenAddress API3 token contract address
    /// @param timelockManagerAddress Timelock manager contract address
    constructor(
        address api3TokenAddress,
        address timelockManagerAddress
        )
        StateUtils(
            api3TokenAddress,
            timelockManagerAddress
            )
    {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"api3TokenAddress","type":"address"},{"internalType":"address","name":"timelockManagerAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CalculatedUserLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"nextIndEpoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldestLockedEpoch","type":"uint256"}],"name":"CalculatingUserLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalDelegatedTo","type":"uint256"}],"name":"Delegated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"userUnstaked","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"userUnstaked","type":"uint256"}],"name":"DepositedByTimelockManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"start","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"end","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"userUnstaked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"userVesting","type":"uint256"}],"name":"DepositedVesting","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"epochIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newApr","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalStake","type":"uint256"}],"name":"MintedReward","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalStake","type":"uint256"}],"name":"PaidOutClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"scheduledFor","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"userShares","type":"uint256"}],"name":"ScheduledUnstake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"aprUpdateStep","type":"uint256"}],"name":"SetAprUpdateStep","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"claimsManager","type":"address"},{"indexed":true,"internalType":"bool","name":"status","type":"bool"}],"name":"SetClaimsManagerStatus","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"agentAppPrimary","type":"address"},{"indexed":false,"internalType":"address","name":"agentAppSecondary","type":"address"},{"indexed":false,"internalType":"address","name":"votingAppPrimary","type":"address"},{"indexed":false,"internalType":"address","name":"votingAppSecondary","type":"address"}],"name":"SetDaoApps","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxApr","type":"uint256"}],"name":"SetMaxApr","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minApr","type":"uint256"}],"name":"SetMinApr","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"proposalVotingPowerThreshold","type":"uint256"}],"name":"SetProposalVotingPowerThreshold","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"stakeTarget","type":"uint256"}],"name":"SetStakeTarget","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"unstakeWaitPeriod","type":"uint256"}],"name":"SetUnstakeWaitPeriod","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintedShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"userUnstaked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"userShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalStake","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalDelegatedTo","type":"uint256"}],"name":"Undelegated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"userUnstaked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalStake","type":"uint256"}],"name":"Unstaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"bool","name":"delta","type":"bool"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalDelegatedTo","type":"uint256"}],"name":"UpdatedDelegation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"lastProposalTimestamp","type":"uint256"},{"indexed":false,"internalType":"address","name":"votingApp","type":"address"}],"name":"UpdatedLastProposalTimestamp","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"userVesting","type":"uint256"}],"name":"VestedTimelock","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"userUnstaked","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"EPOCH_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARD_VESTING_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"agentAppPrimary","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"agentAppSecondary","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"api3Token","outputs":[{"internalType":"contract IApi3Token","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"apr","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aprUpdateStep","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimsManagerStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegate","type":"address"}],"name":"delegateVotingPower","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"delegatedToUser","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"},{"internalType":"uint256","name":"_block","type":"uint256"}],"name":"delegatedToUserAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"source","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"userAddress","type":"address"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositAndStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositRegular","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"source","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"userAddress","type":"address"},{"internalType":"uint256","name":"releaseStart","type":"uint256"},{"internalType":"uint256","name":"releaseEnd","type":"uint256"}],"name":"depositWithVesting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"epochIndexOfLastReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"epochIndexToReward","outputs":[{"internalType":"uint32","name":"atBlock","type":"uint32"},{"internalType":"uint224","name":"amount","type":"uint224"},{"internalType":"uint256","name":"totalSharesThen","type":"uint256"},{"internalType":"uint256","name":"totalStakeThen","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"genesisEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"getUser","outputs":[{"internalType":"uint256","name":"unstaked","type":"uint256"},{"internalType":"uint256","name":"vesting","type":"uint256"},{"internalType":"uint256","name":"unstakeAmount","type":"uint256"},{"internalType":"uint256","name":"unstakeShares","type":"uint256"},{"internalType":"uint256","name":"unstakeScheduledFor","type":"uint256"},{"internalType":"uint256","name":"lastDelegationUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"lastProposalTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isGenesisEpoch","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxApr","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minApr","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"payOutClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolShares","outputs":[{"internalType":"uint32","name":"fromBlock","type":"uint32"},{"internalType":"uint224","name":"value","type":"uint224"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"},{"internalType":"uint256","name":"noEpochsPerIteration","type":"uint256"}],"name":"precalculateUserLocked","outputs":[{"internalType":"bool","name":"finished","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proposalVotingPowerThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"scheduleUnstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_aprUpdateStep","type":"uint256"}],"name":"setAprUpdateStep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"claimsManager","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"setClaimsManagerStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_agentAppPrimary","type":"address"},{"internalType":"address","name":"_agentAppSecondary","type":"address"},{"internalType":"address","name":"_votingAppPrimary","type":"address"},{"internalType":"address","name":"_votingAppSecondary","type":"address"}],"name":"setDaoApps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxApr","type":"uint256"}],"name":"setMaxApr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minApr","type":"uint256"}],"name":"setMinApr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalVotingPowerThreshold","type":"uint256"}],"name":"setProposalVotingPowerThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakeTarget","type":"uint256"}],"name":"setStakeTarget","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_unstakeWaitPeriod","type":"uint256"}],"name":"setUnstakeWaitPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakeTarget","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timelockManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_block","type":"uint256"}],"name":"totalSharesAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"undelegateVotingPower","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"unstake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unstakeAndWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unstakeWaitPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"updateLastProposalTimestamp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"updateTimelockStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"userDelegate","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"},{"internalType":"uint256","name":"_block","type":"uint256"}],"name":"userDelegateAt","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"userLocked","outputs":[{"internalType":"uint256","name":"locked","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"userShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"},{"internalType":"uint256","name":"_block","type":"uint256"}],"name":"userSharesAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"userStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userToLockedCalculation","outputs":[{"internalType":"uint256","name":"initialIndEpoch","type":"uint256"},{"internalType":"uint256","name":"nextIndEpoch","type":"uint256"},{"internalType":"uint256","name":"locked","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userToTimelock","outputs":[{"internalType":"uint256","name":"totalAmount","type":"uint256"},{"internalType":"uint256","name":"remainingAmount","type":"uint256"},{"internalType":"uint256","name":"releaseStart","type":"uint256"},{"internalType":"uint256","name":"releaseEnd","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"userVotingPower","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"},{"internalType":"uint256","name":"_block","type":"uint256"}],"name":"userVotingPowerAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"users","outputs":[{"internalType":"uint256","name":"unstaked","type":"uint256"},{"internalType":"uint256","name":"vesting","type":"uint256"},{"internalType":"uint256","name":"unstakeAmount","type":"uint256"},{"internalType":"uint256","name":"unstakeShares","type":"uint256"},{"internalType":"uint256","name":"unstakeScheduledFor","type":"uint256"},{"internalType":"uint256","name":"lastDelegationUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"lastProposalTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"votingAppPrimary","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"votingAppSecondary","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawPrecalculated","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawRegular","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60e060405262000018662386f26fc10000603262000317565b600855600a62000031662386f26fc10000601962000317565b6200003d9190620002f6565b60095562000054662386f26fc10000604b62000317565b600a55662386f26fc10000600b5562093a80600c55600a662386f26fc100006200007f9190620002f6565b600d556002600954600a54620000969190620002db565b620000a29190620002f6565b600e55348015620000b257600080fd5b5060405162003eef38038062003eef833981016040819052620000d591620002a4565b81816001600160a01b038216620001335760405162461bcd60e51b815260206004820152601760248201527f506f6f6c3a20496e76616c69642041706933546f6b656e00000000000000000060448201526064015b60405180910390fd5b6001600160a01b0381166200018b5760405162461bcd60e51b815260206004820152601d60248201527f506f6f6c3a20496e76616c69642054696d656c6f636b4d616e6167657200000060448201526064016200012a565b601280546001600160a01b031916331790556001600160601b0319606083811b821660a05282901b1660c052620001c560106001620001ef565b60016007556000620001db62093a8042620002f6565b6080819052600655506200034f9350505050565b63ffffffff4311156200021257634e487b7160e01b600052600160045260246000fd5b6001600160e01b038111156200023857634e487b7160e01b600052600160045260246000fd5b6040805180820190915263ffffffff43811682526001600160e01b0392831660208084019182528554600181018755600096875295209251905190931664010000000002921691909117910155565b80516001600160a01b03811681146200029f57600080fd5b919050565b60008060408385031215620002b7578182fd5b620002c28362000287565b9150620002d26020840162000287565b90509250929050565b60008219821115620002f157620002f162000339565b500190565b6000826200031257634e487b7160e01b81526012600452602481fd5b500490565b600081600019048311821515161562000334576200033462000339565b500290565b634e487b7160e01b600052601160045260246000fd5b60805160a05160601c60c05160601c613b0f620003e0600039600081816108b6015281816114df01526128cc0152600081816105be01528181610c3e01528181610df2015281816111fa0152818161173d01528181611b7a015281816129a601528181612f4001526136fd01526000818161087c01528181611c4c0152818161334a015261337c0152613b0f6000f3fe608060405234801561001057600080fd5b50600436106103c45760003560e01c80638b8e39d6116101ff578063cd3bde951161011a578063ea26afd7116100ad578063f68308c71161007c578063f68308c7146109c4578063f6a485c1146109d7578063fc5da2aa146109ea578063fcde28cc146109fd57600080fd5b8063ea26afd714610978578063f2888dbb1461098b578063f3ff955a1461099e578063f45346dc146109b157600080fd5b8063e3b34174116100e9578063e3b3417414610936578063e67729b714610949578063e685dee01461095c578063e7460a521461096f57600080fd5b8063cd3bde95146108fe578063db6f162e14610911578063de69b3aa1461091a578063df60d8041461092d57600080fd5b8063ac4746ab11610192578063bba0538411610161578063bba053841461089e578063bf5669bd146108b1578063bf577a00146108d8578063cad2ab25146108eb57600080fd5b8063ac4746ab14610851578063b330fc531461085b578063b3609b531461086e578063b70e6be61461087757600080fd5b8063a4fb6ff7116101ce578063a4fb6ff7146107c8578063a694fc3a146107db578063a78c6ddc146107ee578063a87430ba1461080157600080fd5b80638b8e39d61461073f5780638dd04faa1461079457806392093b361461079c5780639745f563146107a557600080fd5b806356d4a7fe116102ef5780636f77926b116102825780637fd63875116102515780637fd63875146106f85780637fd75f261461070b5780638794eb4f1461071e5780638b0e9f3f1461073657600080fd5b80636f77926b14610619578063756b2a8b146106a557806375c385d6146106b8578063784b3c5d146106ef57600080fd5b8063613d517d116102be578063613d517d146105b9578063634cc198146105e0578063681a9ad7146105f357806368e5585d1461060657600080fd5b806356d4a7fe1461058257806357ded9c9146105955780635856130a1461059e57806359fe8539146105a657600080fd5b8063344965e2116103675780633c37d05a116103365780633c37d05a146104e85780634091fd3f146104f05780634eb05c47146105665780634f8a137f1461056f57600080fd5b8063344965e21461049957806336b1b6a4146104ac5780633a98ef39146104cd5780633b490a5d146104d557600080fd5b8063174f57af116103a3578063174f57af146104585780632304f24a146104605780632b2c2262146104735780632cacc0cb1461048657600080fd5b8062609187146103c95780630825af75146103f9578063106d08df14610443575b600080fd5b6002546103dc906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6104286104073660046137fa565b60116020526000908152604090208054600182015460029092015490919083565b604080519384526020840192909252908201526060016103f0565b61045661045136600461396a565b610a10565b005b610456610c0e565b61045661046e3660046137fa565b610ec0565b61045661048136600461396a565b61109f565b61045661049436600461389d565b611105565b6001546103dc906001600160a01b031681565b6104bf6104ba3660046137fa565b6112e2565b6040519081526020016103f0565b6104bf6112f4565b6104bf6104e336600461396a565b611304565b610456611311565b6105376104fe36600461396a565b60056020526000908152604090208054600182015460029092015463ffffffff821692600160201b9092046001600160e01b0316919084565b6040805163ffffffff90951685526001600160e01b0390931660208501529183015260608201526080016103f0565b6104bf60085481565b6104bf61057d36600461389d565b61148c565b610456610590366004613901565b6114d4565b6104bf600e5481565b6104bf603481565b6104566105b436600461396a565b61182a565b6103dc7f000000000000000000000000000000000000000000000000000000000000000081565b6104566105ee3660046137fa565b61183c565b6000546103dc906001600160a01b031681565b6104bf6106143660046137fa565b61190b565b6106706106273660046137fa565b6001600160a01b03166000908152600f60205260409020600381015460048201546005830154600684015460078501546008860154600990960154949693959294919390929190565b604080519788526020880196909652948601939093526060850191909152608084015260a083015260c082015260e0016103f0565b6104566106b336600461396a565b611935565b6106cb6106c636600461396a565b6119fb565b6040805163ffffffff90931683526001600160e01b039091166020830152016103f0565b6104bf60095481565b61045661070636600461396a565b611a33565b61045661071936600461396a565b611b10565b610726611c48565b60405190151581526020016103f0565b6104bf60075481565b61077461074d3660046137fa565b60136020526000908152604090208054600182015460028301546003909301549192909184565b6040805194855260208501939093529183015260608201526080016103f0565b610456611c7e565b6104bf600a5481565b6107266107b33660046137fa565b60046020526000908152604090205460ff1681565b6104bf6107d63660046137fa565b611c8c565b6104566107e936600461396a565b611c98565b6104566107fc366004613814565b611dfe565b61067061080f3660046137fa565b600f6020528060005260406000206000915090508060030154908060040154908060050154908060060154908060070154908060080154908060090154905087565b6104bf62093a8081565b6103dc6108693660046137fa565b611fcf565b6104bf600d5481565b6104bf7f000000000000000000000000000000000000000000000000000000000000000081565b6104bf6108ac3660046137fa565b611fdb565b6103dc7f000000000000000000000000000000000000000000000000000000000000000081565b6104bf6108e636600461389d565b612115565b6103dc6108f936600461389d565b61213a565b61045661090c36600461396a565b61215f565b6104bf600b5481565b6104bf6109283660046137fa565b612246565b6104bf60065481565b61045661094436600461396a565b612252565b61045661095736600461396a565b612318565b6003546103dc906001600160a01b031681565b6104bf600c5481565b61045661098636600461396a565b612332565b6104bf6109993660046137fa565b6123fe565b6104566109ac3660046137fa565b6125d2565b6104566109bf3660046138c6565b6128c1565b6104566109d2366004613867565b612a86565b6107266109e536600461389d565b612b04565b6104bf6109f836600461389d565b612d11565b610456610a0b36600461396a565b612d33565b610a18610c0e565b6000610a2333612246565b90506000610a2f6112f4565b905060008160075484610a429190613a68565b610a4c9190613a19565b905083811015610aa35760405162461bcd60e51b815260206004820152601b60248201527f506f6f6c3a20416d6f756e742065786365656473207374616b6564000000000060448201526064015b60405180910390fd5b336000908152600f60205260409020600781015415610b045760405162461bcd60e51b815260206004820152601f60248201527f506f6f6c3a20556e657865637574656420756e7374616b6520657869737473006044820152606401610a9a565b600754600090610b148588613a68565b610b1e9190613a19565b905060008111610b705760405162461bcd60e51b815260206004820152601e60248201527f506f6f6c3a20556e7374616b6520616d6f756e7420746f6f20736d616c6c00006044820152606401610a9a565b6000600c5442610b809190613a01565b60078401819055600584018890556006840183905590506000610ba38388613a87565b9050610baf8482612de5565b610bba836000612e7a565b60408051898152602081018590529081018390526060810182905233907f251830cd12788c7474148132132ab205112e7b9bba739f0e69c8d4a6a54e21599060800160405180910390a25050505050505050565b6000610c1d62093a8042613a19565b9050806006541015610ebd5760405163bbb30c5d60e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063bbb30c5d9060240160206040518083038186803b158015610c8857600080fd5b505afa158015610c9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc0919061394e565b15610eb7576000670de0b6b3a76400006301e1338062093a80600e54600754610ce99190613a68565b610cf39190613a68565b610cfd9190613a19565b610d079190613a19565b905063ffffffff431115610d2b57634e487b7160e01b600052600160045260246000fd5b6001600160e01b03811115610d5057634e487b7160e01b600052600160045260246000fd5b60405180608001604052804363ffffffff168152602001826001600160e01b03168152602001610d7e6112f4565b81526007546020918201526000848152600582526040908190208351928401516001600160e01b0316600160201b0263ffffffff909316929092178255828101516001830155606090920151600290910155516340c10f1960e01b8152306004820152602481018290526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906340c10f1990604401600060405180830381600087803b158015610e3657600080fd5b505af1158015610e4a573d6000803e3d6000fd5b505050508060076000828254610e609190613a01565b90915550610e6e9050612f3c565b600e5460075460408051848152602081019390935282015282907f6e0fc10bac330e97bc2fd6c13cbb1c1189ddb48a8ce96395650ba8f2bd28f6fc9060600160405180910390a2505b60068190555b50565b6001600160a01b038116600090815260136020526040902060028101544211610f2b5760405162461bcd60e51b815260206004820152601d60248201527f506f6f6c3a2052656c65617365206e6f742073746172746564207965740000006044820152606401610a9a565b6000816001015411610f7f5760405162461bcd60e51b815260206004820152601f60248201527f506f6f6c3a2054696d656c6f636b20616c72656164792072656c6561736564006044820152606401610a9a565b600081600301544210610f9457508054610fe0565b6000826002015442610fa69190613a87565b9050600083600201548460030154610fbe9190613a87565b905080828560000154610fd19190613a68565b610fdb9190613a19565b925050505b60018201548254600091610ff391613a87565b905060006110018284613a87565b6001600160a01b0386166000908152600f6020526040812060048101549293509161102d908490613a87565b90508082600401819055508286600101600082825461104c9190613a87565b909155505060408051848152602081018390526001600160a01b038916917fdd8c2c092b990b8e3ae25447982d1c2f7f08c6b9bf7303986a4279f946ebd2ea91015b60405180910390a250505050505050565b6000546001600160a01b031633146110c95760405162461bcd60e51b8152600401610a9a906139ca565b600b8190556040518181527f9825cec2fb9b95eff07739ba941019e5f162bb5d2e266f53583f485282c5ea96906020015b60405180910390a150565b3360009081526004602052604090205460ff166111645760405162461bcd60e51b815260206004820152601f60248201527f506f6f6c3a2043616c6c6572206e6f7420636c61696d73206d616e61676572006044820152606401610a9a565b61116c610c0e565b80600754116111bd5760405162461bcd60e51b815260206004820181905260248201527f506f6f6c3a20416d6f756e74206578636565647320746f74616c207374616b656044820152606401610a9a565b80600760008282546111cf9190613a87565b909155505060405163a9059cbb60e01b81526001600160a01b038381166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b15801561123e57600080fd5b505af1158015611252573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611276919061394e565b61129057634e487b7160e01b600052600160045260246000fd5b816001600160a01b03167f330aad591dd914c6baddcfa6d34f5c8f8a16996d7e0c1c203e4345cb445adfbd826007546040516112d6929190918252602082015260400190565b60405180910390a25050565b60006112ee824361148c565b92915050565b60006112ff43611304565b905090565b60006112ee601083613069565b611319610c0e565b336000818152600f602052604081209161133290611fcf565b90506001600160a01b0381166113805760405162461bcd60e51b8152602060048201526013602482015272141bdbdb0e88139bdd0819195b1959d85d1959606a1b6044820152606401610a9a565b4262093a8083600801546113949190613a01565b106113e15760405162461bcd60e51b815260206004820152601f60248201527f506f6f6c3a20557064617465642064656c656761746520726563656e746c79006044820152606401610a9a565b42600883015560006113f233612246565b905060008161140084611c8c565b61140a9190613a87565b6001600160a01b0384166000908152600f602052604090209091506114329060010182612de5565b611440846002016000613299565b60408051838152602081018390526001600160a01b0385169133917f3aace7340547de7b9156593a7652dc07ee900cea3fd8f82cb6c9d38b40829802910160405180910390a350505050565b600080611499848461213a565b6001600160a01b0316146114af575060006112ee565b6114b98383612115565b6114c38484612d11565b6114cd9190613a01565b9392505050565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461154c5760405162461bcd60e51b815260206004820181905260248201527f506f6f6c3a2043616c6c6572206e6f742054696d656c6f636b4d616e616765726044820152606401610a9a565b6001600160a01b038316600090815260136020526040902060010154156115b55760405162461bcd60e51b815260206004820152601e60248201527f506f6f6c3a205573657220686173206163746976652074696d656c6f636b00006044820152606401610a9a565b8181116116045760405162461bcd60e51b815260206004820152601e60248201527f506f6f6c3a2054696d656c6f636b20737461727420616674657220656e6400006044820152606401610a9a565b836116515760405162461bcd60e51b815260206004820152601a60248201527f506f6f6c3a2054696d656c6f636b20616d6f756e74207a65726f0000000000006044820152606401610a9a565b6001600160a01b0383166000908152600f6020526040812060030154611678908690613a01565b6001600160a01b0385166000908152600f602052604081206003810183905560040154919250906116aa908790613a01565b6001600160a01b038681166000818152600f60209081526040808320600490810187905581516080810183528d81528084018e81528184018d8152606083018d8152978752601390955294839020905181559351600185015591516002840155925160039092019190915590516323b872dd60e01b81528a831691810191909152306024820152604481018990529192507f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90606401602060405180830381600087803b15801561178157600080fd5b505af1158015611795573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b9919061394e565b6117d357634e487b7160e01b600052600160045260246000fd5b604080518781526020810186905290810184905260608101839052608081018290526001600160a01b038616907f14ab87851ecf43dc38c282e0307cd24257a3d01d0265ae2ba28764befac8c6cc9060a00161108e565b61183381611b10565b610ebd81611c98565b6002546001600160a01b031633148061185f57506003546001600160a01b031633145b6118ab5760405162461bcd60e51b815260206004820152601b60248201527f506f6f6c3a2043616c6c6572206e6f7420766f74696e672061707000000000006044820152606401610a9a565b6001600160a01b0381166000818152600f6020908152604091829020426009909101819055825190815233918101919091527fceaef3a8d9336089c649bcf1ea9dd1ae52f5c42ea01f8707ecdd57ea773aa3ee910160405180910390a250565b60006119156112f4565b60075461192184612246565b61192b9190613a68565b6112ee9190613a19565b6000546001600160a01b031633148061195857506001546001600160a01b031633145b6119745760405162461bcd60e51b8152600401610a9a9061399a565b600a548111156119c65760405162461bcd60e51b815260206004820152601d60248201527f506f6f6c3a204d696e20415052206c6172676572207468616e206d61780000006044820152606401610a9a565b60098190556040518181527f73b1a5670aa918e2286672e7dd760a6710d209683665bd8843a04f8710a2be24906020016110fa565b60108181548110611a0b57600080fd5b60009182526020909120015463ffffffff81169150600160201b90046001600160e01b031682565b6000546001600160a01b03163314611a5d5760405162461bcd60e51b8152600401610a9a906139ca565b611a6f600a662386f26fc10000613a19565b8110158015611a8f5750611a8b662386f26fc10000600a613a68565b8111155b611adb5760405162461bcd60e51b815260206004820152601e60248201527f506f6f6c3a205468726573686f6c64206f757473696465206c696d69747300006044820152606401610a9a565b600d8190556040518181527f3658b89a2695dcc4dd2433dc2d79647860cf037c444e112eeddd04063abfb3b6906020016110fa565b611b18610c0e565b336000908152600f6020526040812060030154611b36908390613a01565b336000818152600f602052604090819020600301839055516323b872dd60e01b81526004810191909152306024820152604481018490529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90606401602060405180830381600087803b158015611bbe57600080fd5b505af1158015611bd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bf6919061394e565b611c1057634e487b7160e01b600052600160045260246000fd5b604080518381526020810183905233917f73a19dd210f1a7f902193214c0ee91dd35ee5b4d920cba8d519eca65a7b488ca91016112d6565b60007f0000000000000000000000000000000000000000000000000000000000000000611c7862093a8042613a19565b14905090565b611c8a610957336123fe565b565b60006112ee8243612115565b611ca0610c0e565b336000908152600f602052604090206003810154821115611d035760405162461bcd60e51b815260206004820152601d60248201527f506f6f6c3a20416d6f756e74206578636565647320756e7374616b65640000006044820152606401610a9a565b6000828260030154611d159190613a87565b6003830181905590506000611d286112f4565b905060006007548286611d3b9190613a68565b611d459190613a19565b9050600081611d5333612246565b611d5d9190613a01565b9050611d698582612de5565b6000611d758385613a01565b9050611d82601082612de5565b8660076000828254611d949190613a01565b90915550611da59050836001612e7a565b6007546040805189815260208101869052908101879052606081018490526080810183905260a081019190915233907fc16be9a586414a157dd46b4d023aa9997a025dd1cbbaa67ac0c1b8273a5eaf559060c00161108e565b6000546001600160a01b0316331480611e3557506000546001600160a01b0316158015611e3557506012546001600160a01b031633145b611ea75760405162461bcd60e51b815260206004820152603e60248201527f506f6f6c3a2043616c6c6572206e6f74207072696d617279206167656e74206f60448201527f72206465706c6f79657220696e697469616c697a696e672076616c75657300006064820152608401610a9a565b6001600160a01b03841615801590611ec757506001600160a01b03831615155b8015611edb57506001600160a01b03821615155b8015611eef57506001600160a01b03811615155b611f345760405162461bcd60e51b8152602060048201526016602482015275506f6f6c3a20496e76616c69642044414f206170707360501b6044820152606401610a9a565b600080546001600160a01b038681166001600160a01b031992831681179093556001805487831690841681179091556002805487841690851681179091556003805493871693909416831790935560408051948552602085019190915283019190915260608201527f71b1ce304e98c2a645f0c32f4c9e3ae4d5dbe6717a8c17ccefb0083635afdc159060800160405180910390a150505050565b60006112ee824361213a565b6001600160a01b0381166000908152600f602052604081208161200162093a8042613a19565b9050600061200d61331b565b8354909150825b82811061210b57816120255761210b565b6000818152600560205260409020805463ffffffff16156120f8575b82156120f857600086612055600186613a87565b8154811061207357634e487b7160e01b600052603260045260246000fd5b6000918252602090912083549101805490925063ffffffff9182169116116120e5576001820154815483546120c0916001600160e01b03600160201b918290048116929190910416613a39565b6001600160e01b03166120d39190613a19565b6120dd9089613a01565b9750506120f8565b50826120f081613a9e565b935050612041565b508061210381613a9e565b915050612014565b5050505050919050565b6001600160a01b0382166000908152600f602052604081206114cd9060010183613069565b6001600160a01b0382166000908152600f602052604081206114cd90600201836133a9565b612167610c0e565b600061217662093a8042613a19565b33600090815260116020526040902080549192509082146121d95760405162461bcd60e51b815260206004820181905260248201527f506f6f6c3a2043616c63756c6174696f6e206e6f7420757020746f20646174656044820152606401610a9a565b6121e161331b565b8160010154106122335760405162461bcd60e51b815260206004820152601e60248201527f506f6f6c3a2043616c63756c6174696f6e206e6f7420636f6d706c65746500006044820152606401610a9a565b6122418382600201546135d9565b505050565b60006112ee8243612d11565b6000546001600160a01b031633148061227557506001546001600160a01b031633145b6122915760405162461bcd60e51b8152600401610a9a9061399a565b6009548110156122e35760405162461bcd60e51b815260206004820152601e60248201527f506f6f6c3a204d61782041505220736d616c6c6572207468616e206d696e00006044820152606401610a9a565b600a8190556040518181527f9bfee4483872bc31d94cf9864f4992fdbe3b588515c9f98f952c41a46720bc11906020016110fa565b612320610c0e565b610ebd8161232d33611fdb565b6135d9565b6000546001600160a01b031633148061235557506001546001600160a01b031633145b6123715760405162461bcd60e51b8152600401610a9a9061399a565b670de0b6b3a76400008111156123c95760405162461bcd60e51b815260206004820152601e60248201527f506f6f6c3a20496e76616c69642070657263656e746167652076616c756500006044820152606401610a9a565b60088190556040518181527f30df07121af80c9a50a8fcfddf8aa9f537a550edb930294c6370d4c05632ba15906020016110fa565b6000612408610c0e565b6001600160a01b0382166000908152600f6020526040902060078101546124715760405162461bcd60e51b815260206004820152601a60248201527f506f6f6c3a204e6f20756e7374616b65207363686564756c65640000000000006044820152606401610a9a565b428160070154106124c45760405162461bcd60e51b815260206004820152601c60248201527f506f6f6c3a20556e7374616b65206e6f74206d617475726520796574000000006044820152606401610a9a565b60006124ce6112f4565b905060008260050154905060008260075485600601546124ee9190613a68565b6124f89190613a19565b905080821115612506578091505b60008285600301546125189190613a01565b6003860181905560068601549091506000906125349086613a87565b9050612541601082612de5565b83600760008282546125539190613a87565b90915550506000600587018190556006870181905560078088019190915554604080518681526020810185905290810183905260608101919091526001600160a01b038916907fdcfd2b4017d03f7e541021db793b2f9b31e4acdee005f789e52853c390e3e9629060800160405180910390a250919695505050505050565b6125da610c0e565b6001600160a01b038116158015906125fb57506001600160a01b0381163314155b6126405760405162461bcd60e51b8152602060048201526016602482015275506f6f6c3a20496e76616c69642064656c656761746560501b6044820152606401610a9a565b600061264b82611fcf565b6001600160a01b0316146126a15760405162461bcd60e51b815260206004820152601c60248201527f506f6f6c3a2044656c65676174652069732064656c65676174696e67000000006044820152606401610a9a565b336000908152600f60205260409020600881015442906126c59062093a8090613a01565b106127125760405162461bcd60e51b815260206004820152601f60248201527f506f6f6c3a20557064617465642064656c656761746520726563656e746c79006044820152606401610a9a565b426008820155600061272333612246565b9050806127725760405162461bcd60e51b815260206004820181905260248201527f506f6f6c3a2048617665206e6f2073686172657320746f2064656c65676174656044820152606401610a9a565b600061277d33611fcf565b9050836001600160a01b0316816001600160a01b031614156127e15760405162461bcd60e51b815260206004820152601760248201527f506f6f6c3a20416c72656164792064656c6567617465640000000000000000006044820152606401610a9a565b6001600160a01b03811615612828576001600160a01b0381166000908152600f60205260409020612828906001018361281984611c8c565b6128239190613a87565b612de5565b60008261283486611c8c565b61283e9190613a01565b6001600160a01b0386166000908152600f602052604090209091506128669060010182612de5565b6128738460020186613299565b60408051848152602081018390526001600160a01b0387169133917f24d7bda8602b916d64417f0dbfe2e2e88ec9b1157bd9f596dfdb91ba26624e0491015b60405180910390a35050505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146129395760405162461bcd60e51b815260206004820181905260248201527f506f6f6c3a2043616c6c6572206e6f742054696d656c6f636b4d616e616765726044820152606401610a9a565b6001600160a01b0381166000908152600f6020526040812060030154612960908490613a01565b6001600160a01b038381166000908152600f602052604090819020600301839055516323b872dd60e01b81528682166004820152306024820152604481018690529192507f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90606401602060405180830381600087803b1580156129ea57600080fd5b505af11580156129fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a22919061394e565b612a3c57634e487b7160e01b600052600160045260246000fd5b60408051848152602081018390526001600160a01b038416917fd0d7fef3966369afd08c0683ee833a06f6b91787b85a26fa3ef3004ae37484c2910160405180910390a250505050565b6000546001600160a01b03163314612ab05760405162461bcd60e51b8152600401610a9a906139ca565b6001600160a01b038216600081815260046020526040808220805460ff191685151590811790915590519092917fbf0d659300b2b4f4ddd43c45c5f2a7deafbf3e8bc8617173b6ef8937b19ca32191a35050565b6000612b0e610c0e565b60008211612b5e5760405162461bcd60e51b815260206004820152601b60248201527f506f6f6c3a205a65726f20697465726174696f6e2077696e646f7700000000006044820152606401610a9a565b6000612b6d62093a8042613a19565b6001600160a01b03851660009081526011602052604090208054919250908214612ba35781815560018101829055600060028201555b600181015460028201546000612bb761331b565b90505b808310612cb757612bcb8784613a01565b846001015410612c3557600184018390556002840182905560408051848152602081018390526001600160a01b038a16917f6fc96dcc266501f61e68f71d8d27031f9c1a0122e03a723bc967b4163465f971910160405180910390a26000955050505050506112ee565b6000838152600560205260409020805463ffffffff1615612ca4578054600090612c66908b9063ffffffff16612d11565b6001830154835491925090612c8c908390600160201b90046001600160e01b0316613a68565b612c969190613a19565b612ca09085613a01565b9350505b5082612caf81613a9e565b935050612bba565b60018401839055600284018290556040518281526001600160a01b038916907fc348e77597c15c5ce7cb14e48ad08c01b889caf1d1fc2958cf3e6e1dd96836ee9060200160405180910390a2506001979650505050505050565b6001600160a01b0382166000908152600f602052604081206114cd9083613069565b6000546001600160a01b03163314612d5d5760405162461bcd60e51b8152600401610a9a906139ca565b62093a80811015612db05760405162461bcd60e51b815260206004820152601f60248201527f506f6f6c3a20506572696f642073686f72746572207468616e2065706f6368006044820152606401610a9a565b600c8190556040518181527f74c87fa8b1e9d1840c40ff666c878e91e081cb2b15fa68a62e584f07fd4ebff2906020016110fa565b63ffffffff431115612e0757634e487b7160e01b600052600160045260246000fd5b6001600160e01b03811115612e2c57634e487b7160e01b600052600160045260246000fd5b6040805180820190915263ffffffff43811682526001600160e01b03928316602080840191825285546001810187556000968752952092519051909316600160201b02921691909117910155565b6000612e8533611fcf565b90506001600160a01b038116612e9a57505050565b6000612ea582611c8c565b9050600083612ebd57612eb88583613a87565b612ec7565b612ec78583613a01565b6001600160a01b0384166000908152600f60205260409020909150612eef9060010182612de5565b604080518515158152602081018790529081018290526001600160a01b0384169033907ff310def5b4718cefe3603eb46259d8061fd58003695cf952de94c53e14dbb309906060016128b2565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f9757600080fd5b505afa158015612fab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fcf9190613982565b670de0b6b3a7640000600754612fe59190613a68565b612fef9190613a19565b905060085481111561302557600b54600e541161300d57600061301d565b600b54600e5461301d9190613a87565b600e5561303f565b600b54600e60008282546130399190613a01565b90915550505b600a54600e54111561305457600a54600e5550565b600954600e541015610ebd57600954600e5550565b815460009061307a575060006112ee565b8254839061308a90600190613a87565b815481106130a857634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16821061311157825483906130d090600190613a87565b815481106130ee57634e487b7160e01b600052603260045260246000fd5b600091825260209091200154600160201b90046001600160e01b031690506112ee565b8260008154811061313257634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16821015613153575060006112ee565b82546000906104001080156131a857508354839085906131769061040090613a87565b8154811061319457634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16105b156131bf5783546131bc9061040090613a87565b90505b83546000906131d090600190613a87565b90505b8181111561325457600060026131e98484613a01565b6131f4906001613a01565b6131fe9190613a19565b90508486828154811061322157634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16116132405780925061324e565b61324b600182613a87565b91505b506131d3565b84828154811061327457634e487b7160e01b600052603260045260246000fd5b600091825260209091200154600160201b90046001600160e01b031695945050505050565b63ffffffff4311156132bb57634e487b7160e01b600052600160045260246000fd5b6040805180820190915263ffffffff43811682526001600160a01b03928316602080840191825285546001810187556000968752952092519290940180549451909316600160201b026001600160c01b0319909416911617919091179055565b60008061332b62093a8042613a19565b9050613338603482613a87565b613343906001613a01565b91506133707f00000000000000000000000000000000000000000000000000000000000000006001613a01565b8210156133a5576133a27f00000000000000000000000000000000000000000000000000000000000000006001613a01565b91505b5090565b81546000906133ba575060006112ee565b825483906133ca90600190613a87565b815481106133e857634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff168210613451578254839061341090600190613a87565b8154811061342e57634e487b7160e01b600052603260045260246000fd5b600091825260209091200154600160201b90046001600160a01b031690506112ee565b8260008154811061347257634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16821015613493575060006112ee565b82546000906104001080156134e857508354839085906134b69061040090613a87565b815481106134d457634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16105b156134ff5783546134fc9061040090613a87565b90505b835460009061351090600190613a87565b90505b8181111561359457600060026135298484613a01565b613534906001613a01565b61353e9190613a19565b90508486828154811061356157634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16116135805780925061358e565b61358b600182613a87565b91505b50613513565b8482815481106135b457634e487b7160e01b600052603260045260246000fd5b600091825260209091200154600160201b90046001600160a01b031695945050505050565b336000908152600f6020526040812060048101549091906135fa9084613a01565b905060006136073361190b565b83600301546136169190613a01565b90506136228583613a01565b8110156136715760405162461bcd60e51b815260206004820152601f60248201527f506f6f6c3a204e6f7420656e6f75676820756e6c6f636b65642066756e6473006044820152606401610a9a565b84836003015410156136c55760405162461bcd60e51b815260206004820152601f60248201527f506f6f6c3a204e6f7420656e6f75676820756e7374616b65642066756e6473006044820152606401610a9a565b60008584600301546136d79190613a87565b6003850181905560405163a9059cbb60e01b8152336004820152602481018890529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb90604401602060405180830381600087803b15801561374957600080fd5b505af115801561375d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613781919061394e565b61379b57634e487b7160e01b600052600160045260246000fd5b604080518781526020810183905233917f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc6910160405180910390a2505050505050565b80356001600160a01b03811681146137f557600080fd5b919050565b60006020828403121561380b578081fd5b6114cd826137de565b60008060008060808587031215613829578283fd5b613832856137de565b9350613840602086016137de565b925061384e604086016137de565b915061385c606086016137de565b905092959194509250565b60008060408385031215613879578182fd5b613882836137de565b9150602083013561389281613acb565b809150509250929050565b600080604083850312156138af578182fd5b6138b8836137de565b946020939093013593505050565b6000806000606084860312156138da578283fd5b6138e3846137de565b9250602084013591506138f8604085016137de565b90509250925092565b600080600080600060a08688031215613918578081fd5b613921866137de565b945060208601359350613936604087016137de565b94979396509394606081013594506080013592915050565b60006020828403121561395f578081fd5b81516114cd81613acb565b60006020828403121561397b578081fd5b5035919050565b600060208284031215613993578081fd5b5051919050565b602080825260169082015275141bdbdb0e8810d85b1b195c881b9bdd081859d95b9d60521b604082015260600190565b6020808252601e908201527f506f6f6c3a2043616c6c6572206e6f74207072696d617279206167656e740000604082015260600190565b60008219821115613a1457613a14613ab5565b500190565b600082613a3457634e487b7160e01b81526012600452602481fd5b500490565b60006001600160e01b0382811684821681151582840482111615613a5f57613a5f613ab5565b02949350505050565b6000816000190483118215151615613a8257613a82613ab5565b500290565b600082821015613a9957613a99613ab5565b500390565b600081613aad57613aad613ab5565b506000190190565b634e487b7160e01b600052601160045260246000fd5b8015158114610ebd57600080fdfea2646970667358221220dab22d0b89f8e4222d6d396b8e9eff20e527eeba97d049ec9d7bf982050a7ce564736f6c634300080400330000000000000000000000000b38210ea11411557c13457d4da7dc6ea731b88a000000000000000000000000faef86994a37f1c8b2a5c73648f07dd4eff02baa

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106103c45760003560e01c80638b8e39d6116101ff578063cd3bde951161011a578063ea26afd7116100ad578063f68308c71161007c578063f68308c7146109c4578063f6a485c1146109d7578063fc5da2aa146109ea578063fcde28cc146109fd57600080fd5b8063ea26afd714610978578063f2888dbb1461098b578063f3ff955a1461099e578063f45346dc146109b157600080fd5b8063e3b34174116100e9578063e3b3417414610936578063e67729b714610949578063e685dee01461095c578063e7460a521461096f57600080fd5b8063cd3bde95146108fe578063db6f162e14610911578063de69b3aa1461091a578063df60d8041461092d57600080fd5b8063ac4746ab11610192578063bba0538411610161578063bba053841461089e578063bf5669bd146108b1578063bf577a00146108d8578063cad2ab25146108eb57600080fd5b8063ac4746ab14610851578063b330fc531461085b578063b3609b531461086e578063b70e6be61461087757600080fd5b8063a4fb6ff7116101ce578063a4fb6ff7146107c8578063a694fc3a146107db578063a78c6ddc146107ee578063a87430ba1461080157600080fd5b80638b8e39d61461073f5780638dd04faa1461079457806392093b361461079c5780639745f563146107a557600080fd5b806356d4a7fe116102ef5780636f77926b116102825780637fd63875116102515780637fd63875146106f85780637fd75f261461070b5780638794eb4f1461071e5780638b0e9f3f1461073657600080fd5b80636f77926b14610619578063756b2a8b146106a557806375c385d6146106b8578063784b3c5d146106ef57600080fd5b8063613d517d116102be578063613d517d146105b9578063634cc198146105e0578063681a9ad7146105f357806368e5585d1461060657600080fd5b806356d4a7fe1461058257806357ded9c9146105955780635856130a1461059e57806359fe8539146105a657600080fd5b8063344965e2116103675780633c37d05a116103365780633c37d05a146104e85780634091fd3f146104f05780634eb05c47146105665780634f8a137f1461056f57600080fd5b8063344965e21461049957806336b1b6a4146104ac5780633a98ef39146104cd5780633b490a5d146104d557600080fd5b8063174f57af116103a3578063174f57af146104585780632304f24a146104605780632b2c2262146104735780632cacc0cb1461048657600080fd5b8062609187146103c95780630825af75146103f9578063106d08df14610443575b600080fd5b6002546103dc906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6104286104073660046137fa565b60116020526000908152604090208054600182015460029092015490919083565b604080519384526020840192909252908201526060016103f0565b61045661045136600461396a565b610a10565b005b610456610c0e565b61045661046e3660046137fa565b610ec0565b61045661048136600461396a565b61109f565b61045661049436600461389d565b611105565b6001546103dc906001600160a01b031681565b6104bf6104ba3660046137fa565b6112e2565b6040519081526020016103f0565b6104bf6112f4565b6104bf6104e336600461396a565b611304565b610456611311565b6105376104fe36600461396a565b60056020526000908152604090208054600182015460029092015463ffffffff821692600160201b9092046001600160e01b0316919084565b6040805163ffffffff90951685526001600160e01b0390931660208501529183015260608201526080016103f0565b6104bf60085481565b6104bf61057d36600461389d565b61148c565b610456610590366004613901565b6114d4565b6104bf600e5481565b6104bf603481565b6104566105b436600461396a565b61182a565b6103dc7f0000000000000000000000000b38210ea11411557c13457d4da7dc6ea731b88a81565b6104566105ee3660046137fa565b61183c565b6000546103dc906001600160a01b031681565b6104bf6106143660046137fa565b61190b565b6106706106273660046137fa565b6001600160a01b03166000908152600f60205260409020600381015460048201546005830154600684015460078501546008860154600990960154949693959294919390929190565b604080519788526020880196909652948601939093526060850191909152608084015260a083015260c082015260e0016103f0565b6104566106b336600461396a565b611935565b6106cb6106c636600461396a565b6119fb565b6040805163ffffffff90931683526001600160e01b039091166020830152016103f0565b6104bf60095481565b61045661070636600461396a565b611a33565b61045661071936600461396a565b611b10565b610726611c48565b60405190151581526020016103f0565b6104bf60075481565b61077461074d3660046137fa565b60136020526000908152604090208054600182015460028301546003909301549192909184565b6040805194855260208501939093529183015260608201526080016103f0565b610456611c7e565b6104bf600a5481565b6107266107b33660046137fa565b60046020526000908152604090205460ff1681565b6104bf6107d63660046137fa565b611c8c565b6104566107e936600461396a565b611c98565b6104566107fc366004613814565b611dfe565b61067061080f3660046137fa565b600f6020528060005260406000206000915090508060030154908060040154908060050154908060060154908060070154908060080154908060090154905087565b6104bf62093a8081565b6103dc6108693660046137fa565b611fcf565b6104bf600d5481565b6104bf7f0000000000000000000000000000000000000000000000000000000000000a8081565b6104bf6108ac3660046137fa565b611fdb565b6103dc7f000000000000000000000000faef86994a37f1c8b2a5c73648f07dd4eff02baa81565b6104bf6108e636600461389d565b612115565b6103dc6108f936600461389d565b61213a565b61045661090c36600461396a565b61215f565b6104bf600b5481565b6104bf6109283660046137fa565b612246565b6104bf60065481565b61045661094436600461396a565b612252565b61045661095736600461396a565b612318565b6003546103dc906001600160a01b031681565b6104bf600c5481565b61045661098636600461396a565b612332565b6104bf6109993660046137fa565b6123fe565b6104566109ac3660046137fa565b6125d2565b6104566109bf3660046138c6565b6128c1565b6104566109d2366004613867565b612a86565b6107266109e536600461389d565b612b04565b6104bf6109f836600461389d565b612d11565b610456610a0b36600461396a565b612d33565b610a18610c0e565b6000610a2333612246565b90506000610a2f6112f4565b905060008160075484610a429190613a68565b610a4c9190613a19565b905083811015610aa35760405162461bcd60e51b815260206004820152601b60248201527f506f6f6c3a20416d6f756e742065786365656473207374616b6564000000000060448201526064015b60405180910390fd5b336000908152600f60205260409020600781015415610b045760405162461bcd60e51b815260206004820152601f60248201527f506f6f6c3a20556e657865637574656420756e7374616b6520657869737473006044820152606401610a9a565b600754600090610b148588613a68565b610b1e9190613a19565b905060008111610b705760405162461bcd60e51b815260206004820152601e60248201527f506f6f6c3a20556e7374616b6520616d6f756e7420746f6f20736d616c6c00006044820152606401610a9a565b6000600c5442610b809190613a01565b60078401819055600584018890556006840183905590506000610ba38388613a87565b9050610baf8482612de5565b610bba836000612e7a565b60408051898152602081018590529081018390526060810182905233907f251830cd12788c7474148132132ab205112e7b9bba739f0e69c8d4a6a54e21599060800160405180910390a25050505050505050565b6000610c1d62093a8042613a19565b9050806006541015610ebd5760405163bbb30c5d60e01b81523060048201527f0000000000000000000000000b38210ea11411557c13457d4da7dc6ea731b88a6001600160a01b03169063bbb30c5d9060240160206040518083038186803b158015610c8857600080fd5b505afa158015610c9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc0919061394e565b15610eb7576000670de0b6b3a76400006301e1338062093a80600e54600754610ce99190613a68565b610cf39190613a68565b610cfd9190613a19565b610d079190613a19565b905063ffffffff431115610d2b57634e487b7160e01b600052600160045260246000fd5b6001600160e01b03811115610d5057634e487b7160e01b600052600160045260246000fd5b60405180608001604052804363ffffffff168152602001826001600160e01b03168152602001610d7e6112f4565b81526007546020918201526000848152600582526040908190208351928401516001600160e01b0316600160201b0263ffffffff909316929092178255828101516001830155606090920151600290910155516340c10f1960e01b8152306004820152602481018290526001600160a01b037f0000000000000000000000000b38210ea11411557c13457d4da7dc6ea731b88a16906340c10f1990604401600060405180830381600087803b158015610e3657600080fd5b505af1158015610e4a573d6000803e3d6000fd5b505050508060076000828254610e609190613a01565b90915550610e6e9050612f3c565b600e5460075460408051848152602081019390935282015282907f6e0fc10bac330e97bc2fd6c13cbb1c1189ddb48a8ce96395650ba8f2bd28f6fc9060600160405180910390a2505b60068190555b50565b6001600160a01b038116600090815260136020526040902060028101544211610f2b5760405162461bcd60e51b815260206004820152601d60248201527f506f6f6c3a2052656c65617365206e6f742073746172746564207965740000006044820152606401610a9a565b6000816001015411610f7f5760405162461bcd60e51b815260206004820152601f60248201527f506f6f6c3a2054696d656c6f636b20616c72656164792072656c6561736564006044820152606401610a9a565b600081600301544210610f9457508054610fe0565b6000826002015442610fa69190613a87565b9050600083600201548460030154610fbe9190613a87565b905080828560000154610fd19190613a68565b610fdb9190613a19565b925050505b60018201548254600091610ff391613a87565b905060006110018284613a87565b6001600160a01b0386166000908152600f6020526040812060048101549293509161102d908490613a87565b90508082600401819055508286600101600082825461104c9190613a87565b909155505060408051848152602081018390526001600160a01b038916917fdd8c2c092b990b8e3ae25447982d1c2f7f08c6b9bf7303986a4279f946ebd2ea91015b60405180910390a250505050505050565b6000546001600160a01b031633146110c95760405162461bcd60e51b8152600401610a9a906139ca565b600b8190556040518181527f9825cec2fb9b95eff07739ba941019e5f162bb5d2e266f53583f485282c5ea96906020015b60405180910390a150565b3360009081526004602052604090205460ff166111645760405162461bcd60e51b815260206004820152601f60248201527f506f6f6c3a2043616c6c6572206e6f7420636c61696d73206d616e61676572006044820152606401610a9a565b61116c610c0e565b80600754116111bd5760405162461bcd60e51b815260206004820181905260248201527f506f6f6c3a20416d6f756e74206578636565647320746f74616c207374616b656044820152606401610a9a565b80600760008282546111cf9190613a87565b909155505060405163a9059cbb60e01b81526001600160a01b038381166004830152602482018390527f0000000000000000000000000b38210ea11411557c13457d4da7dc6ea731b88a169063a9059cbb90604401602060405180830381600087803b15801561123e57600080fd5b505af1158015611252573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611276919061394e565b61129057634e487b7160e01b600052600160045260246000fd5b816001600160a01b03167f330aad591dd914c6baddcfa6d34f5c8f8a16996d7e0c1c203e4345cb445adfbd826007546040516112d6929190918252602082015260400190565b60405180910390a25050565b60006112ee824361148c565b92915050565b60006112ff43611304565b905090565b60006112ee601083613069565b611319610c0e565b336000818152600f602052604081209161133290611fcf565b90506001600160a01b0381166113805760405162461bcd60e51b8152602060048201526013602482015272141bdbdb0e88139bdd0819195b1959d85d1959606a1b6044820152606401610a9a565b4262093a8083600801546113949190613a01565b106113e15760405162461bcd60e51b815260206004820152601f60248201527f506f6f6c3a20557064617465642064656c656761746520726563656e746c79006044820152606401610a9a565b42600883015560006113f233612246565b905060008161140084611c8c565b61140a9190613a87565b6001600160a01b0384166000908152600f602052604090209091506114329060010182612de5565b611440846002016000613299565b60408051838152602081018390526001600160a01b0385169133917f3aace7340547de7b9156593a7652dc07ee900cea3fd8f82cb6c9d38b40829802910160405180910390a350505050565b600080611499848461213a565b6001600160a01b0316146114af575060006112ee565b6114b98383612115565b6114c38484612d11565b6114cd9190613a01565b9392505050565b336001600160a01b037f000000000000000000000000faef86994a37f1c8b2a5c73648f07dd4eff02baa161461154c5760405162461bcd60e51b815260206004820181905260248201527f506f6f6c3a2043616c6c6572206e6f742054696d656c6f636b4d616e616765726044820152606401610a9a565b6001600160a01b038316600090815260136020526040902060010154156115b55760405162461bcd60e51b815260206004820152601e60248201527f506f6f6c3a205573657220686173206163746976652074696d656c6f636b00006044820152606401610a9a565b8181116116045760405162461bcd60e51b815260206004820152601e60248201527f506f6f6c3a2054696d656c6f636b20737461727420616674657220656e6400006044820152606401610a9a565b836116515760405162461bcd60e51b815260206004820152601a60248201527f506f6f6c3a2054696d656c6f636b20616d6f756e74207a65726f0000000000006044820152606401610a9a565b6001600160a01b0383166000908152600f6020526040812060030154611678908690613a01565b6001600160a01b0385166000908152600f602052604081206003810183905560040154919250906116aa908790613a01565b6001600160a01b038681166000818152600f60209081526040808320600490810187905581516080810183528d81528084018e81528184018d8152606083018d8152978752601390955294839020905181559351600185015591516002840155925160039092019190915590516323b872dd60e01b81528a831691810191909152306024820152604481018990529192507f0000000000000000000000000b38210ea11411557c13457d4da7dc6ea731b88a16906323b872dd90606401602060405180830381600087803b15801561178157600080fd5b505af1158015611795573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b9919061394e565b6117d357634e487b7160e01b600052600160045260246000fd5b604080518781526020810186905290810184905260608101839052608081018290526001600160a01b038616907f14ab87851ecf43dc38c282e0307cd24257a3d01d0265ae2ba28764befac8c6cc9060a00161108e565b61183381611b10565b610ebd81611c98565b6002546001600160a01b031633148061185f57506003546001600160a01b031633145b6118ab5760405162461bcd60e51b815260206004820152601b60248201527f506f6f6c3a2043616c6c6572206e6f7420766f74696e672061707000000000006044820152606401610a9a565b6001600160a01b0381166000818152600f6020908152604091829020426009909101819055825190815233918101919091527fceaef3a8d9336089c649bcf1ea9dd1ae52f5c42ea01f8707ecdd57ea773aa3ee910160405180910390a250565b60006119156112f4565b60075461192184612246565b61192b9190613a68565b6112ee9190613a19565b6000546001600160a01b031633148061195857506001546001600160a01b031633145b6119745760405162461bcd60e51b8152600401610a9a9061399a565b600a548111156119c65760405162461bcd60e51b815260206004820152601d60248201527f506f6f6c3a204d696e20415052206c6172676572207468616e206d61780000006044820152606401610a9a565b60098190556040518181527f73b1a5670aa918e2286672e7dd760a6710d209683665bd8843a04f8710a2be24906020016110fa565b60108181548110611a0b57600080fd5b60009182526020909120015463ffffffff81169150600160201b90046001600160e01b031682565b6000546001600160a01b03163314611a5d5760405162461bcd60e51b8152600401610a9a906139ca565b611a6f600a662386f26fc10000613a19565b8110158015611a8f5750611a8b662386f26fc10000600a613a68565b8111155b611adb5760405162461bcd60e51b815260206004820152601e60248201527f506f6f6c3a205468726573686f6c64206f757473696465206c696d69747300006044820152606401610a9a565b600d8190556040518181527f3658b89a2695dcc4dd2433dc2d79647860cf037c444e112eeddd04063abfb3b6906020016110fa565b611b18610c0e565b336000908152600f6020526040812060030154611b36908390613a01565b336000818152600f602052604090819020600301839055516323b872dd60e01b81526004810191909152306024820152604481018490529091506001600160a01b037f0000000000000000000000000b38210ea11411557c13457d4da7dc6ea731b88a16906323b872dd90606401602060405180830381600087803b158015611bbe57600080fd5b505af1158015611bd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bf6919061394e565b611c1057634e487b7160e01b600052600160045260246000fd5b604080518381526020810183905233917f73a19dd210f1a7f902193214c0ee91dd35ee5b4d920cba8d519eca65a7b488ca91016112d6565b60007f0000000000000000000000000000000000000000000000000000000000000a80611c7862093a8042613a19565b14905090565b611c8a610957336123fe565b565b60006112ee8243612115565b611ca0610c0e565b336000908152600f602052604090206003810154821115611d035760405162461bcd60e51b815260206004820152601d60248201527f506f6f6c3a20416d6f756e74206578636565647320756e7374616b65640000006044820152606401610a9a565b6000828260030154611d159190613a87565b6003830181905590506000611d286112f4565b905060006007548286611d3b9190613a68565b611d459190613a19565b9050600081611d5333612246565b611d5d9190613a01565b9050611d698582612de5565b6000611d758385613a01565b9050611d82601082612de5565b8660076000828254611d949190613a01565b90915550611da59050836001612e7a565b6007546040805189815260208101869052908101879052606081018490526080810183905260a081019190915233907fc16be9a586414a157dd46b4d023aa9997a025dd1cbbaa67ac0c1b8273a5eaf559060c00161108e565b6000546001600160a01b0316331480611e3557506000546001600160a01b0316158015611e3557506012546001600160a01b031633145b611ea75760405162461bcd60e51b815260206004820152603e60248201527f506f6f6c3a2043616c6c6572206e6f74207072696d617279206167656e74206f60448201527f72206465706c6f79657220696e697469616c697a696e672076616c75657300006064820152608401610a9a565b6001600160a01b03841615801590611ec757506001600160a01b03831615155b8015611edb57506001600160a01b03821615155b8015611eef57506001600160a01b03811615155b611f345760405162461bcd60e51b8152602060048201526016602482015275506f6f6c3a20496e76616c69642044414f206170707360501b6044820152606401610a9a565b600080546001600160a01b038681166001600160a01b031992831681179093556001805487831690841681179091556002805487841690851681179091556003805493871693909416831790935560408051948552602085019190915283019190915260608201527f71b1ce304e98c2a645f0c32f4c9e3ae4d5dbe6717a8c17ccefb0083635afdc159060800160405180910390a150505050565b60006112ee824361213a565b6001600160a01b0381166000908152600f602052604081208161200162093a8042613a19565b9050600061200d61331b565b8354909150825b82811061210b57816120255761210b565b6000818152600560205260409020805463ffffffff16156120f8575b82156120f857600086612055600186613a87565b8154811061207357634e487b7160e01b600052603260045260246000fd5b6000918252602090912083549101805490925063ffffffff9182169116116120e5576001820154815483546120c0916001600160e01b03600160201b918290048116929190910416613a39565b6001600160e01b03166120d39190613a19565b6120dd9089613a01565b9750506120f8565b50826120f081613a9e565b935050612041565b508061210381613a9e565b915050612014565b5050505050919050565b6001600160a01b0382166000908152600f602052604081206114cd9060010183613069565b6001600160a01b0382166000908152600f602052604081206114cd90600201836133a9565b612167610c0e565b600061217662093a8042613a19565b33600090815260116020526040902080549192509082146121d95760405162461bcd60e51b815260206004820181905260248201527f506f6f6c3a2043616c63756c6174696f6e206e6f7420757020746f20646174656044820152606401610a9a565b6121e161331b565b8160010154106122335760405162461bcd60e51b815260206004820152601e60248201527f506f6f6c3a2043616c63756c6174696f6e206e6f7420636f6d706c65746500006044820152606401610a9a565b6122418382600201546135d9565b505050565b60006112ee8243612d11565b6000546001600160a01b031633148061227557506001546001600160a01b031633145b6122915760405162461bcd60e51b8152600401610a9a9061399a565b6009548110156122e35760405162461bcd60e51b815260206004820152601e60248201527f506f6f6c3a204d61782041505220736d616c6c6572207468616e206d696e00006044820152606401610a9a565b600a8190556040518181527f9bfee4483872bc31d94cf9864f4992fdbe3b588515c9f98f952c41a46720bc11906020016110fa565b612320610c0e565b610ebd8161232d33611fdb565b6135d9565b6000546001600160a01b031633148061235557506001546001600160a01b031633145b6123715760405162461bcd60e51b8152600401610a9a9061399a565b670de0b6b3a76400008111156123c95760405162461bcd60e51b815260206004820152601e60248201527f506f6f6c3a20496e76616c69642070657263656e746167652076616c756500006044820152606401610a9a565b60088190556040518181527f30df07121af80c9a50a8fcfddf8aa9f537a550edb930294c6370d4c05632ba15906020016110fa565b6000612408610c0e565b6001600160a01b0382166000908152600f6020526040902060078101546124715760405162461bcd60e51b815260206004820152601a60248201527f506f6f6c3a204e6f20756e7374616b65207363686564756c65640000000000006044820152606401610a9a565b428160070154106124c45760405162461bcd60e51b815260206004820152601c60248201527f506f6f6c3a20556e7374616b65206e6f74206d617475726520796574000000006044820152606401610a9a565b60006124ce6112f4565b905060008260050154905060008260075485600601546124ee9190613a68565b6124f89190613a19565b905080821115612506578091505b60008285600301546125189190613a01565b6003860181905560068601549091506000906125349086613a87565b9050612541601082612de5565b83600760008282546125539190613a87565b90915550506000600587018190556006870181905560078088019190915554604080518681526020810185905290810183905260608101919091526001600160a01b038916907fdcfd2b4017d03f7e541021db793b2f9b31e4acdee005f789e52853c390e3e9629060800160405180910390a250919695505050505050565b6125da610c0e565b6001600160a01b038116158015906125fb57506001600160a01b0381163314155b6126405760405162461bcd60e51b8152602060048201526016602482015275506f6f6c3a20496e76616c69642064656c656761746560501b6044820152606401610a9a565b600061264b82611fcf565b6001600160a01b0316146126a15760405162461bcd60e51b815260206004820152601c60248201527f506f6f6c3a2044656c65676174652069732064656c65676174696e67000000006044820152606401610a9a565b336000908152600f60205260409020600881015442906126c59062093a8090613a01565b106127125760405162461bcd60e51b815260206004820152601f60248201527f506f6f6c3a20557064617465642064656c656761746520726563656e746c79006044820152606401610a9a565b426008820155600061272333612246565b9050806127725760405162461bcd60e51b815260206004820181905260248201527f506f6f6c3a2048617665206e6f2073686172657320746f2064656c65676174656044820152606401610a9a565b600061277d33611fcf565b9050836001600160a01b0316816001600160a01b031614156127e15760405162461bcd60e51b815260206004820152601760248201527f506f6f6c3a20416c72656164792064656c6567617465640000000000000000006044820152606401610a9a565b6001600160a01b03811615612828576001600160a01b0381166000908152600f60205260409020612828906001018361281984611c8c565b6128239190613a87565b612de5565b60008261283486611c8c565b61283e9190613a01565b6001600160a01b0386166000908152600f602052604090209091506128669060010182612de5565b6128738460020186613299565b60408051848152602081018390526001600160a01b0387169133917f24d7bda8602b916d64417f0dbfe2e2e88ec9b1157bd9f596dfdb91ba26624e0491015b60405180910390a35050505050565b336001600160a01b037f000000000000000000000000faef86994a37f1c8b2a5c73648f07dd4eff02baa16146129395760405162461bcd60e51b815260206004820181905260248201527f506f6f6c3a2043616c6c6572206e6f742054696d656c6f636b4d616e616765726044820152606401610a9a565b6001600160a01b0381166000908152600f6020526040812060030154612960908490613a01565b6001600160a01b038381166000908152600f602052604090819020600301839055516323b872dd60e01b81528682166004820152306024820152604481018690529192507f0000000000000000000000000b38210ea11411557c13457d4da7dc6ea731b88a16906323b872dd90606401602060405180830381600087803b1580156129ea57600080fd5b505af11580156129fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a22919061394e565b612a3c57634e487b7160e01b600052600160045260246000fd5b60408051848152602081018390526001600160a01b038416917fd0d7fef3966369afd08c0683ee833a06f6b91787b85a26fa3ef3004ae37484c2910160405180910390a250505050565b6000546001600160a01b03163314612ab05760405162461bcd60e51b8152600401610a9a906139ca565b6001600160a01b038216600081815260046020526040808220805460ff191685151590811790915590519092917fbf0d659300b2b4f4ddd43c45c5f2a7deafbf3e8bc8617173b6ef8937b19ca32191a35050565b6000612b0e610c0e565b60008211612b5e5760405162461bcd60e51b815260206004820152601b60248201527f506f6f6c3a205a65726f20697465726174696f6e2077696e646f7700000000006044820152606401610a9a565b6000612b6d62093a8042613a19565b6001600160a01b03851660009081526011602052604090208054919250908214612ba35781815560018101829055600060028201555b600181015460028201546000612bb761331b565b90505b808310612cb757612bcb8784613a01565b846001015410612c3557600184018390556002840182905560408051848152602081018390526001600160a01b038a16917f6fc96dcc266501f61e68f71d8d27031f9c1a0122e03a723bc967b4163465f971910160405180910390a26000955050505050506112ee565b6000838152600560205260409020805463ffffffff1615612ca4578054600090612c66908b9063ffffffff16612d11565b6001830154835491925090612c8c908390600160201b90046001600160e01b0316613a68565b612c969190613a19565b612ca09085613a01565b9350505b5082612caf81613a9e565b935050612bba565b60018401839055600284018290556040518281526001600160a01b038916907fc348e77597c15c5ce7cb14e48ad08c01b889caf1d1fc2958cf3e6e1dd96836ee9060200160405180910390a2506001979650505050505050565b6001600160a01b0382166000908152600f602052604081206114cd9083613069565b6000546001600160a01b03163314612d5d5760405162461bcd60e51b8152600401610a9a906139ca565b62093a80811015612db05760405162461bcd60e51b815260206004820152601f60248201527f506f6f6c3a20506572696f642073686f72746572207468616e2065706f6368006044820152606401610a9a565b600c8190556040518181527f74c87fa8b1e9d1840c40ff666c878e91e081cb2b15fa68a62e584f07fd4ebff2906020016110fa565b63ffffffff431115612e0757634e487b7160e01b600052600160045260246000fd5b6001600160e01b03811115612e2c57634e487b7160e01b600052600160045260246000fd5b6040805180820190915263ffffffff43811682526001600160e01b03928316602080840191825285546001810187556000968752952092519051909316600160201b02921691909117910155565b6000612e8533611fcf565b90506001600160a01b038116612e9a57505050565b6000612ea582611c8c565b9050600083612ebd57612eb88583613a87565b612ec7565b612ec78583613a01565b6001600160a01b0384166000908152600f60205260409020909150612eef9060010182612de5565b604080518515158152602081018790529081018290526001600160a01b0384169033907ff310def5b4718cefe3603eb46259d8061fd58003695cf952de94c53e14dbb309906060016128b2565b60007f0000000000000000000000000b38210ea11411557c13457d4da7dc6ea731b88a6001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f9757600080fd5b505afa158015612fab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fcf9190613982565b670de0b6b3a7640000600754612fe59190613a68565b612fef9190613a19565b905060085481111561302557600b54600e541161300d57600061301d565b600b54600e5461301d9190613a87565b600e5561303f565b600b54600e60008282546130399190613a01565b90915550505b600a54600e54111561305457600a54600e5550565b600954600e541015610ebd57600954600e5550565b815460009061307a575060006112ee565b8254839061308a90600190613a87565b815481106130a857634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16821061311157825483906130d090600190613a87565b815481106130ee57634e487b7160e01b600052603260045260246000fd5b600091825260209091200154600160201b90046001600160e01b031690506112ee565b8260008154811061313257634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16821015613153575060006112ee565b82546000906104001080156131a857508354839085906131769061040090613a87565b8154811061319457634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16105b156131bf5783546131bc9061040090613a87565b90505b83546000906131d090600190613a87565b90505b8181111561325457600060026131e98484613a01565b6131f4906001613a01565b6131fe9190613a19565b90508486828154811061322157634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16116132405780925061324e565b61324b600182613a87565b91505b506131d3565b84828154811061327457634e487b7160e01b600052603260045260246000fd5b600091825260209091200154600160201b90046001600160e01b031695945050505050565b63ffffffff4311156132bb57634e487b7160e01b600052600160045260246000fd5b6040805180820190915263ffffffff43811682526001600160a01b03928316602080840191825285546001810187556000968752952092519290940180549451909316600160201b026001600160c01b0319909416911617919091179055565b60008061332b62093a8042613a19565b9050613338603482613a87565b613343906001613a01565b91506133707f0000000000000000000000000000000000000000000000000000000000000a806001613a01565b8210156133a5576133a27f0000000000000000000000000000000000000000000000000000000000000a806001613a01565b91505b5090565b81546000906133ba575060006112ee565b825483906133ca90600190613a87565b815481106133e857634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff168210613451578254839061341090600190613a87565b8154811061342e57634e487b7160e01b600052603260045260246000fd5b600091825260209091200154600160201b90046001600160a01b031690506112ee565b8260008154811061347257634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16821015613493575060006112ee565b82546000906104001080156134e857508354839085906134b69061040090613a87565b815481106134d457634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16105b156134ff5783546134fc9061040090613a87565b90505b835460009061351090600190613a87565b90505b8181111561359457600060026135298484613a01565b613534906001613a01565b61353e9190613a19565b90508486828154811061356157634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16116135805780925061358e565b61358b600182613a87565b91505b50613513565b8482815481106135b457634e487b7160e01b600052603260045260246000fd5b600091825260209091200154600160201b90046001600160a01b031695945050505050565b336000908152600f6020526040812060048101549091906135fa9084613a01565b905060006136073361190b565b83600301546136169190613a01565b90506136228583613a01565b8110156136715760405162461bcd60e51b815260206004820152601f60248201527f506f6f6c3a204e6f7420656e6f75676820756e6c6f636b65642066756e6473006044820152606401610a9a565b84836003015410156136c55760405162461bcd60e51b815260206004820152601f60248201527f506f6f6c3a204e6f7420656e6f75676820756e7374616b65642066756e6473006044820152606401610a9a565b60008584600301546136d79190613a87565b6003850181905560405163a9059cbb60e01b8152336004820152602481018890529091507f0000000000000000000000000b38210ea11411557c13457d4da7dc6ea731b88a6001600160a01b03169063a9059cbb90604401602060405180830381600087803b15801561374957600080fd5b505af115801561375d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613781919061394e565b61379b57634e487b7160e01b600052600160045260246000fd5b604080518781526020810183905233917f92ccf450a286a957af52509bc1c9939d1a6a481783e142e41e2499f0bb66ebc6910160405180910390a2505050505050565b80356001600160a01b03811681146137f557600080fd5b919050565b60006020828403121561380b578081fd5b6114cd826137de565b60008060008060808587031215613829578283fd5b613832856137de565b9350613840602086016137de565b925061384e604086016137de565b915061385c606086016137de565b905092959194509250565b60008060408385031215613879578182fd5b613882836137de565b9150602083013561389281613acb565b809150509250929050565b600080604083850312156138af578182fd5b6138b8836137de565b946020939093013593505050565b6000806000606084860312156138da578283fd5b6138e3846137de565b9250602084013591506138f8604085016137de565b90509250925092565b600080600080600060a08688031215613918578081fd5b613921866137de565b945060208601359350613936604087016137de565b94979396509394606081013594506080013592915050565b60006020828403121561395f578081fd5b81516114cd81613acb565b60006020828403121561397b578081fd5b5035919050565b600060208284031215613993578081fd5b5051919050565b602080825260169082015275141bdbdb0e8810d85b1b195c881b9bdd081859d95b9d60521b604082015260600190565b6020808252601e908201527f506f6f6c3a2043616c6c6572206e6f74207072696d617279206167656e740000604082015260600190565b60008219821115613a1457613a14613ab5565b500190565b600082613a3457634e487b7160e01b81526012600452602481fd5b500490565b60006001600160e01b0382811684821681151582840482111615613a5f57613a5f613ab5565b02949350505050565b6000816000190483118215151615613a8257613a82613ab5565b500290565b600082821015613a9957613a99613ab5565b500390565b600081613aad57613aad613ab5565b506000190190565b634e487b7160e01b600052601160045260246000fd5b8015158114610ebd57600080fdfea2646970667358221220dab22d0b89f8e4222d6d396b8e9eff20e527eeba97d049ec9d7bf982050a7ce564736f6c63430008040033

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

0000000000000000000000000b38210ea11411557c13457d4da7dc6ea731b88a000000000000000000000000faef86994a37f1c8b2a5c73648f07dd4eff02baa

-----Decoded View---------------
Arg [0] : api3TokenAddress (address): 0x0b38210ea11411557c13457D4dA7dC6ea731B88a
Arg [1] : timelockManagerAddress (address): 0xFaef86994a37F1c8b2A5c73648F07dd4eFF02baA

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000b38210ea11411557c13457d4da7dc6ea731b88a
Arg [1] : 000000000000000000000000faef86994a37f1c8b2a5c73648f07dd4eff02baa


Deployed Bytecode Sourcemap

70605:399:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9005:31;;;;;-1:-1:-1;;;;;9005:31:0;;;;;;-1:-1:-1;;;;;3058:32:1;;;3040:51;;3028:2;3013:18;9005:31:0;;;;;;;;12584:68;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18485:25:1;;;18541:2;18526:18;;18519:34;;;;18569:18;;;18562:34;18473:2;18458:18;12584:68:0;18440:162:1;56998:1470:0;;;;;;:::i;:::-;;:::i;:::-;;38069:1307;;;:::i;68351:1332::-;;;;;;:::i;:::-;;:::i;19879:219::-;;;;;;:::i;:::-;;:::i;62153:662::-;;;;;;:::i;:::-;;:::i;8845:32::-;;;;;-1:-1:-1;;;;;8845:32:0;;;26508:198;;;;;;:::i;:::-;;:::i;:::-;;;17715:25:1;;;17703:2;17688:18;26508:198:0;17670:76:1;27338:156:0;;;:::i;26980:175::-;;;;;;:::i;:::-;;:::i;43372:1088::-;;;:::i;9747:52::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;9747:52:0;;;-1:-1:-1;;;;;9747:52:0;;;;;;;;;21176:10:1;21164:23;;;21146:42;;-1:-1:-1;;;;;21224:32:1;;;21219:2;21204:18;;21197:60;21273:18;;;21266:34;21331:2;21316:18;;21309:34;21133:3;21118:19;9747:52:0;21100:249:1;10322:45:0;;;;;;25888:455;;;;;;:::i;:::-;;:::i;66613:1570::-;;;;;;:::i;:::-;;:::i;12299:42::-;;;;;;7394:50;;7442:2;7394:50;;55829:147;;;;;;:::i;:::-;;:::i;8122:37::-;;;;;21091:341;;;;;;:::i;:::-;;:::i;8529:30::-;;;;;-1:-1:-1;;;;;8529:30:0;;;28505:198;;;;;;:::i;:::-;;:::i;32507:807::-;;;;;;:::i;:::-;-1:-1:-1;;;;;32935:18:0;32627:16;32935:18;;;:5;:18;;;;;32975:13;;;;33009:12;;;;33048:18;;;;33093;;;;33144:24;;;;33211:34;;;;33280:26;;;;;32975:13;;33009:12;;33048:18;;33093;;33144:24;;33211:34;33280:26;32507:807;;;;;20326:25:1;;;20382:2;20367:18;;20360:34;;;;20410:18;;;20403:34;;;;20468:2;20453:18;;20446:34;;;;20511:3;20496:19;;20489:35;20555:3;20540:19;;20533:35;20599:3;20584:19;;20577:35;20313:3;20298:19;32507:807:0;20280:338:1;18356:281:0;;;;;;:::i;:::-;;:::i;12479:30::-;;;;;;:::i;:::-;;:::i;:::-;;;;20825:10:1;20813:23;;;20795:42;;-1:-1:-1;;;;;20873:32:1;;;20868:2;20853:18;;20846:60;20768:18;12479:30:0;20750:162:1;10569:45:0;;;;;;20398:509;;;;;;:::i;:::-;;:::i;47125:536::-;;;;;;:::i;:::-;;:::i;21665:177::-;;;:::i;:::-;;;4396:14:1;;4389:22;4371:41;;4359:2;4344:18;21665:177:0;4326:92:1;9968:25:0;;;;;;64810:50;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18838:25:1;;;18894:2;18879:18;;18872:34;;;;18922:18;;;18915:34;18980:2;18965:18;;18958:34;18825:3;18810:19;64810:50:0;18792:206:1;60614:126:0;;;:::i;10815:40::-;;;;;;9516:51;;;;;;:::i;:::-;;;;;;;;;;;;;;;;29422:196;;;;;;:::i;:::-;;:::i;54521:1162::-;;;;;;:::i;:::-;;:::i;15101:1147::-;;;;;;:::i;:::-;;:::i;12380:37::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7146:46;;7185:7;7146:46;;30244:190;;;;;;:::i;:::-;;:::i;11955:62::-;;;;;;8039:37;;;;;30610:1311;;;;;;:::i;:::-;;:::i;8210:40::-;;;;;28988:249;;;;;;:::i;:::-;;:::i;29839:246::-;;;;;;:::i;:::-;;:::i;51251:624::-;;;;;;:::i;:::-;;:::i;11007:42::-;;;;;;28150:186;;;;;;:::i;:::-;;:::i;9863:37::-;;;;;;17966:282;;;;;;:::i;:::-;;:::i;48078:162::-;;;;;;:::i;:::-;;:::i;9168:33::-;;;;;-1:-1:-1;;;;;9168:33:0;;;11659:47;;;;;;17532:326;;;;;;:::i;:::-;;:::i;58781:1579::-;;;;;;:::i;:::-;;:::i;41148:2153::-;;;;;;:::i;:::-;;:::i;65415:725::-;;;;;;:::i;:::-;;:::i;17084:333::-;;;;;;:::i;:::-;;:::i;48911:2010::-;;;;;;:::i;:::-;;:::i;27748:239::-;;;;;;:::i;:::-;;:::i;19245:373::-;;;;;;:::i;:::-;;:::i;56998:1470::-;57091:12;:10;:12::i;:::-;57114:21;57138:22;57149:10;57138;:22::i;:::-;57114:46;;57171:22;57196:13;:11;:13::i;:::-;57171:38;;57220:18;57270:14;57257:10;;57241:13;:26;;;;:::i;:::-;:43;;;;:::i;:::-;57220:64;;57331:6;57317:10;:20;;57295:101;;;;-1:-1:-1;;;57295:101:0;;11335:2:1;57295:101:0;;;11317:21:1;11374:2;11354:18;;;11347:30;11413:29;11393:18;;;11386:57;11460:18;;57295:101:0;;;;;;;;;57435:10;57409:17;57429;;;:5;:17;;;;;57479:24;;;;:29;57457:114;;;;-1:-1:-1;;;57457:114:0;;15617:2:1;57457:114:0;;;15599:21:1;15656:2;15636:18;;;15629:30;15695:33;15675:18;;;15668:61;15746:18;;57457:114:0;15589:181:1;57457:114:0;57636:10;;57584:23;;57610;57619:14;57610:6;:23;:::i;:::-;:36;;;;:::i;:::-;57584:62;;57784:1;57766:15;:19;57758:62;;;;-1:-1:-1;;;57758:62:0;;14193:2:1;57758:62:0;;;14175:21:1;14232:2;14212:18;;;14205:30;14271:32;14251:18;;;14244:60;14321:18;;57758:62:0;14165:180:1;57758:62:0;57831:27;57879:17;;57861:15;:35;;;;:::i;:::-;57907:24;;;:46;;;57964:18;;;:27;;;58002:18;;;:36;;;57831:65;-1:-1:-1;;58076:31:0;58023:15;58076:13;:31;:::i;:::-;58049:58;-1:-1:-1;58118:93:0;58154:4;58049:58;58118:21;:93::i;:::-;58222:50;58249:15;58266:5;58222:26;:50::i;:::-;58288:172;;;18838:25:1;;;18894:2;18879:18;;18872:34;;;18922:18;;;18915:34;;;18980:2;18965:18;;18958:34;;;58319:10:0;;58288:172;;18825:3:1;18810:19;58288:172:0;;;;;;;56998:1470;;;;;;;;:::o;38069:1307::-;38141:20;38164:30;7185:7;38164:15;:30;:::i;:::-;38141:53;;38361:12;38336:22;;:37;38332:1037;;;38403:40;;-1:-1:-1;;;38403:40:0;;38437:4;38403:40;;;3040:51:1;38403:9:0;-1:-1:-1;;;;;38403:25:0;;;;3013:18:1;;38403:40:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;38399:907;;;38477:20;7615:4;38534:8;7185:7;38513:3;;38500:10;;:16;;;;:::i;:::-;:31;;;;:::i;:::-;:42;;;;:::i;:::-;:60;;;;:::i;:::-;38477:83;;7716:9;38586:12;:26;;38579:34;;-1:-1:-1;;;38579:34:0;;;;;;;;;-1:-1:-1;;;;;38639:12:0;:27;;38632:35;;-1:-1:-1;;;38632:35:0;;;;;;;;;38721:237;;;;;;;;38767:12;38721:237;;;;;;38819:12;-1:-1:-1;;;;;38721:237:0;;;;;38872:13;:11;:13::i;:::-;38721:237;;38924:10;;38721:237;;;;;-1:-1:-1;38686:32:0;;;:18;:32;;;;;;;:272;;;;;;-1:-1:-1;;;;;38686:272:0;-1:-1:-1;;;38686:272:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;38977:43;-1:-1:-1;;;38977:43:0;;39000:4;38686:272;38977:43;;4126:51:1;4193:18;;;4186:34;;;-1:-1:-1;;;;;38977:9:0;:14;;;;4099:18:1;;38977:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;39053:12;39039:10;;:26;;;;;;;:::i;:::-;;;;-1:-1:-1;39084:18:0;;-1:-1:-1;39084:16:0;:18::i;:::-;39231:3;;39257:10;;39126:164;;;18485:25:1;;;18541:2;18526:18;;18519:34;;;;18569:18;;18562:34;39161:12:0;;39126:164;;18473:2:1;18458:18;39126:164:0;;;;;;;38399:907;;39320:22;:37;;;38332:1037;38069:1307;:::o;68351:1332::-;-1:-1:-1;;;;;68482:27:0;;68454:25;68482:27;;;:14;:27;;;;;68560:21;;;;68542:15;:39;68520:122;;;;-1:-1:-1;;;68520:122:0;;13126:2:1;68520:122:0;;;13108:21:1;13165:2;13145:18;;;13138:30;13204:31;13184:18;;;13177:59;13253:18;;68520:122:0;13098:179:1;68520:122:0;68702:1;68675:8;:24;;;:28;68653:113;;;;-1:-1:-1;;;68653:113:0;;7335:2:1;68653:113:0;;;7317:21:1;7374:2;7354:18;;;7347:30;7413:33;7393:18;;;7386:61;7464:18;;68653:113:0;7307:181:1;68653:113:0;68777:21;68832:8;:19;;;68813:15;:38;68809:381;;-1:-1:-1;68893:20:0;;68809:381;;;68964:18;69003:8;:21;;;68985:15;:39;;;;:::i;:::-;68964:60;;69039:17;69081:8;:21;;;69059:8;:19;;;:43;;;;:::i;:::-;69039:63;;69169:9;69156:10;69133:8;:20;;;:33;;;;:::i;:::-;:45;;;;:::i;:::-;69117:61;;68809:381;;;69252:24;;;;69229:20;;69200:26;;69229:47;;;:::i;:::-;69200:76;-1:-1:-1;69287:21:0;69311:34;69200:76;69311:13;:34;:::i;:::-;-1:-1:-1;;;;;69376:18:0;;69356:17;69376:18;;;:5;:18;;;;;69429:12;;;;69287:58;;-1:-1:-1;69376:18:0;69429:28;;69287:58;;69429:28;:::i;:::-;69405:52;;69483:13;69468:4;:12;;:28;;;;69535:13;69507:8;:24;;;:41;;;;;;;:::i;:::-;;;;-1:-1:-1;;69564:111:0;;;18204:25:1;;;18260:2;18245:18;;18238:34;;;-1:-1:-1;;;;;69564:111:0;;;;;18177:18:1;69564:111:0;;;;;;;;68351:1332;;;;;;;:::o;19879:219::-;13234:15;;-1:-1:-1;;;;;13234:15:0;13220:10;:29;13198:113;;;;-1:-1:-1;;;13198:113:0;;;;;;;:::i;:::-;20012:13:::1;:30:::0;;;20058:32:::1;::::0;17715:25:1;;;20058:32:0::1;::::0;17703:2:1;17688:18;20058:32:0::1;;;;;;;;19879:219:::0;:::o;62153:662::-;61454:10;61434:31;;;;:19;:31;;;;;;;;61412:116;;;;-1:-1:-1;;;61412:116:0;;5536:2:1;61412:116:0;;;5518:21:1;5575:2;5555:18;;;5548:30;5614:33;5594:18;;;5587:61;5665:18;;61412:116:0;5508:181:1;61412:116:0;62319:12:::1;:10;:12::i;:::-;62427:6;62414:10;;:19;62392:105;;;::::0;-1:-1:-1;;;62392:105:0;;8050:2:1;62392:105:0::1;::::0;::::1;8032:21:1::0;;;8069:18;;;8062:30;8128:34;8108:18;;;8101:62;8180:18;;62392:105:0::1;8022:182:1::0;62392:105:0::1;62522:6;62508:10;;:20;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;62656:37:0::1;::::0;-1:-1:-1;;;62656:37:0;;-1:-1:-1;;;;;4144:32:1;;;62656:37:0::1;::::0;::::1;4126:51:1::0;4193:18;;;4186:34;;;62656:9:0::1;:18;::::0;::::1;::::0;4099::1;;62656:37:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;62649:45;;-1:-1:-1::0;;;62649:45:0::1;;;;;;;;;62737:9;-1:-1:-1::0;;;;;62710:97:0::1;;62761:6;62782:10;;62710:97;;;;;;18204:25:1::0;;;18260:2;18245:18;;18238:34;18192:2;18177:18;;18159:119;62710:97:0::1;;;;;;;;62153:662:::0;;:::o;26508:198::-;26622:7;26654:44;26672:11;26685:12;26654:17;:44::i;:::-;26647:51;26508:198;-1:-1:-1;;26508:198:0:o;27338:156::-;27427:7;27459:27;27473:12;27459:13;:27::i;:::-;27452:34;;27338:156;:::o;26980:175::-;27085:7;27117:30;27128:10;27140:6;27117:10;:30::i;43372:1088::-;43457:12;:10;:12::i;:::-;43506:10;43480:17;43500;;;:5;:17;;;;;;43555:24;;:12;:24::i;:::-;43528:51;-1:-1:-1;;;;;;43612:30:0;;43590:103;;;;-1:-1:-1;;;43590:103:0;;8411:2:1;43590:103:0;;;8393:21:1;8450:2;8430:18;;;8423:30;-1:-1:-1;;;8469:18:1;;;8462:49;8528:18;;43590:103:0;8383:169:1;43590:103:0;43778:15;7185:7;43726:4;:34;;;:49;;;;:::i;:::-;:67;43704:152;;;;-1:-1:-1;;;43704:152:0;;16693:2:1;43704:152:0;;;16675:21:1;16732:2;16712:18;;;16705:30;16771:33;16751:18;;;16744:61;16822:18;;43704:152:0;16665:181:1;43704:152:0;43904:15;43867:34;;;:52;43932:18;43953:22;43964:10;43953;:22::i;:::-;43932:43;;43986:25;44050:10;44014:33;44030:16;44014:15;:33::i;:::-;:46;;;;:::i;:::-;-1:-1:-1;;;;;44107:23:0;;;;;;:5;:23;;;;;43986:74;;-1:-1:-1;44071:118:0;;44107:35;;43986:74;44071:21;:118::i;:::-;44200:97;44243:4;:14;;44280:1;44200:28;:97::i;:::-;44313:139;;;18204:25:1;;;18260:2;18245:18;;18238:34;;;-1:-1:-1;;;;;44313:139:0;;;44339:10;;44313:139;;18177:18:1;44313:139:0;;;;;;;43372:1088;;;;:::o;25888:455::-;26047:7;;26136:35;26151:11;26164:6;26136:14;:35::i;:::-;-1:-1:-1;;;;;26136:49:0;;26132:99;;-1:-1:-1;26218:1:0;26211:8;;26132:99;26297:38;26315:11;26328:6;26297:17;:38::i;:::-;26248:33;26261:11;26274:6;26248:12;:33::i;:::-;:87;;;;:::i;:::-;26241:94;25888:455;-1:-1:-1;;;25888:455:0:o;66613:1570::-;66866:10;-1:-1:-1;;;;;66880:15:0;66866:29;;66844:115;;;;-1:-1:-1;;;66844:115:0;;10615:2:1;66844:115:0;;;10597:21:1;;;10634:18;;;10627:30;10693:34;10673:18;;;10666:62;10745:18;;66844:115:0;10587:182:1;66844:115:0;-1:-1:-1;;;;;66992:27:0;;;;;;:14;:27;;;;;:43;;;:48;66970:132;;;;-1:-1:-1;;;66970:132:0;;6615:2:1;66970:132:0;;;6597:21:1;6654:2;6634:18;;;6627:30;6693:32;6673:18;;;6666:60;6743:18;;66970:132:0;6587:180:1;66970:132:0;67148:12;67135:10;:25;67113:109;;;;-1:-1:-1;;;67113:109:0;;9900:2:1;67113:109:0;;;9882:21:1;9939:2;9919:18;;;9912:30;9978:32;9958:18;;;9951:60;10028:18;;67113:109:0;9872:180:1;67113:109:0;67255:11;67233:91;;;;-1:-1:-1;;;67233:91:0;;14903:2:1;67233:91:0;;;14885:21:1;14942:2;14922:18;;;14915:30;14981:28;14961:18;;;14954:56;15027:18;;67233:91:0;14875:176:1;67233:91:0;-1:-1:-1;;;;;67360:18:0;;67335:22;67360:18;;;:5;:18;;;;;:27;;;:36;;67390:6;;67360:36;:::i;:::-;-1:-1:-1;;;;;67407:18:0;;;;;;:5;:18;;;;;:27;;;:44;;;67486:26;;;67335:61;;-1:-1:-1;67407:18:0;67486:35;;67515:6;;67486:35;:::i;:::-;-1:-1:-1;;;;;67532:18:0;;;;;;;:5;:18;;;;;;;;:26;;;;:42;;;67615:175;;;;;;;;;;;;;;;;;;;;;;;;;;;;67585:27;;;:14;:27;;;;;;;:205;;;;;;;;;;;;;;;;;;;;;;;;;;67918:53;;-1:-1:-1;;;67918:53:0;;3830:15:1;;;67918:53:0;;;3812:34:1;;;;67957:4:0;3862:18:1;;;3855:43;3914:18;;;3907:34;;;67532:42:0;;-1:-1:-1;67918:9:0;:22;;;;3747:18:1;;67918:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;67911:61;;-1:-1:-1;;;67911:61:0;;;;;;;;;67988:187;;;19262:25:1;;;19318:2;19303:18;;19296:34;;;19346:18;;;19339:34;;;19404:2;19389:18;;19382:34;;;19447:3;19432:19;;19425:35;;;-1:-1:-1;;;;;67988:187:0;;;;;19249:3:1;19234:19;67988:187:0;19216:250:1;55829:147:0;55922:22;55937:6;55922:14;:22::i;:::-;55955:13;55961:6;55955:5;:13::i;21091:341::-;13481:16;;-1:-1:-1;;;;;13481:16:0;13467:10;:30;;:66;;-1:-1:-1;13515:18:0;;-1:-1:-1;;;;;13515:18:0;13501:10;:32;13467:66;13445:147;;;;-1:-1:-1;;;13445:147:0;;10259:2:1;13445:147:0;;;10241:21:1;10298:2;10278:18;;;10271:30;10337:29;10317:18;;;10310:57;10384:18;;13445:147:0;10231:177:1;13445:147:0;-1:-1:-1;;;;;21226:18:0;::::1;;::::0;;;:5:::1;:18;::::0;;;;;;;;21269:15:::1;21226:40;::::0;;::::1;:58:::0;;;21300:124;;17925:25:1;;;21399:10:0::1;17966:18:1::0;;;17959:60;;;;21300:124:0::1;::::0;17898:18:1;21300:124:0::1;;;;;;;21091:341:::0;:::o;28505:198::-;28611:7;28682:13;:11;:13::i;:::-;28669:10;;28643:23;28654:11;28643:10;:23::i;:::-;:36;;;;:::i;:::-;:52;;;;:::i;18356:281::-;12954:15;;-1:-1:-1;;;;;12954:15:0;12940:10;:29;;:64;;-1:-1:-1;12987:17:0;;-1:-1:-1;;;;;12987:17:0;12973:10;:31;12940:64;12918:140;;;;-1:-1:-1;;;12918:140:0;;;;;;;:::i;:::-;18501:6:::1;;18490:7;:17;;18468:100;;;::::0;-1:-1:-1;;;18468:100:0;;17053:2:1;18468:100:0::1;::::0;::::1;17035:21:1::0;17092:2;17072:18;;;17065:30;17131:31;17111:18;;;17104:59;17180:18;;18468:100:0::1;17025:179:1::0;18468:100:0::1;18579:6;:16:::0;;;18611:18:::1;::::0;17715:25:1;;;18611:18:0::1;::::0;17703:2:1;17688:18;18611::0::1;17670:76:1::0;12479:30:0;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;12479:30:0;;-1:-1:-1;;;;;12479:30:0;;:::o;20398:509::-;13234:15;;-1:-1:-1;;;;;13234:15:0;13220:10;:29;13198:113;;;;-1:-1:-1;;;13198:113:0;;;;;;;:::i;:::-;20616:16:::1;20630:2;7554:10;20616:16;:::i;:::-;20583:29;:49;;:119;;;;-1:-1:-1::0;20686:16:0::1;7554:10;20700:2;20686:16;:::i;:::-;20653:29;:49;;20583:119;20561:189;;;::::0;-1:-1:-1;;;20561:189:0;;12406:2:1;20561:189:0::1;::::0;::::1;12388:21:1::0;12445:2;12425:18;;;12418:30;12484:32;12464:18;;;12457:60;12534:18;;20561:189:0::1;12378:180:1::0;20561:189:0::1;20761:28;:60:::0;;;20837:62:::1;::::0;17715:25:1;;;20837:62:0::1;::::0;17703:2:1;17688:18;20837:62:0::1;17670:76:1::0;47125:536:0;47215:12;:10;:12::i;:::-;47269:10;47238:22;47263:17;;;:5;:17;;;;;:26;;;:35;;47292:6;;47263:35;:::i;:::-;47315:10;47309:17;;;;:5;:17;;;;;;;:26;;:43;;;47480:57;-1:-1:-1;;;47480:57:0;;;;;3812:34:1;;;;47523:4:0;3862:18:1;;;3855:43;3914:18;;;3907:34;;;47309:43:0;;-1:-1:-1;;;;;;47480:9:0;:22;;;;3747:18:1;;47480:57:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;47473:65;;-1:-1:-1;;;47473:65:0;;;;;;;;;47554:99;;;18204:25:1;;;18260:2;18245:18;;18238:34;;;47578:10:0;;47554:99;;18177:18:1;47554:99:0;18159:119:1;21665:177:0;21759:4;21822:12;21788:30;7185:7;21788:15;:30;:::i;:::-;:46;21781:53;;21665:177;:::o;60614:126::-;60696:36;60712:19;60720:10;60712:7;:19::i;60696:36::-;60614:126::o;29422:196::-;29534:7;29566:44;29584:11;29597:12;29566:17;:44::i;54521:1162::-;54602:12;:10;:12::i;:::-;54651:10;54625:17;54645;;;:5;:17;;;;;54695:13;;;;:23;-1:-1:-1;54695:23:0;54673:106;;;;-1:-1:-1;;;54673:106:0;;11691:2:1;54673:106:0;;;11673:21:1;11730:2;11710:18;;;11703:30;11769:31;11749:18;;;11742:59;11818:18;;54673:106:0;11663:179:1;54673:106:0;54790:26;54835:6;54819:4;:13;;;:22;;;;:::i;:::-;54852:13;;;:34;;;54790:51;-1:-1:-1;54897:22:0;54922:13;:11;:13::i;:::-;54897:38;;54946:20;54995:10;;54978:14;54969:6;:23;;;;:::i;:::-;:36;;;;:::i;:::-;54946:59;;55016:24;55068:12;55043:22;55054:10;55043;:22::i;:::-;:37;;;;:::i;:::-;55016:64;-1:-1:-1;55091:93:0;55127:4;55016:64;55091:21;:93::i;:::-;55195:25;55223:29;55240:12;55223:14;:29;:::i;:::-;55195:57;;55263:93;55299:10;55324:17;55263:21;:93::i;:::-;55381:6;55367:10;;:20;;;;;;;:::i;:::-;;;;-1:-1:-1;55398:46:0;;-1:-1:-1;55425:12:0;55439:4;55398:26;:46::i;:::-;55650:10;;55460:215;;;19758:25:1;;;19814:2;19799:18;;19792:34;;;19842:18;;;19835:34;;;19900:2;19885:18;;19878:34;;;19943:3;19928:19;;19921:35;;;19987:3;19972:19;;19965:35;;;;55481:10:0;;55460:215;;19745:3:1;19730:19;55460:215:0;19712:294:1;15101:1147:0;15418:15;;-1:-1:-1;;;;;15418:15:0;15404:10;:29;;:107;;-1:-1:-1;15482:1:0;15455:15;-1:-1:-1;;;;;15455:15:0;:29;:55;;;;-1:-1:-1;15502:8:0;;-1:-1:-1;;;;;15502:8:0;15488:10;:22;15455:55;15382:223;;;;-1:-1:-1;;;15382:223:0;;9469:2:1;15382:223:0;;;9451:21:1;9508:2;9488:18;;;9481:30;9547:34;9527:18;;;9520:62;9618:32;9598:18;;;9591:60;9668:19;;15382:223:0;9441:252:1;15382:223:0;-1:-1:-1;;;;;15638:30:0;;;;;;:83;;-1:-1:-1;;;;;;15689:32:0;;;;15638:83;:135;;;;-1:-1:-1;;;;;;15742:31:0;;;;15638:135;:189;;;;-1:-1:-1;;;;;;15794:33:0;;;;15638:189;15616:265;;;;-1:-1:-1;;;15616:265:0;;8759:2:1;15616:265:0;;;8741:21:1;8798:2;8778:18;;;8771:30;-1:-1:-1;;;8817:18:1;;;8810:52;8879:18;;15616:265:0;8731:172:1;15616:265:0;15892:15;:34;;-1:-1:-1;;;;;15892:34:0;;;-1:-1:-1;;;;;;15892:34:0;;;;;;;;-1:-1:-1;15937:38:0;;;;;;;;;;;;;15986:16;:36;;;;;;;;;;;;;16033:18;:40;;;;;;;;;;;;;;16089:151;;;3371:34:1;;;3436:2;3421:18;;3414:43;;;;3473:18;;3466:43;;;;3540:2;3525:18;;3518:43;16089:151:0;;3320:3:1;3305:19;16089:151:0;;;;;;;15101:1147;;;;:::o;30244:190::-;30353:7;30385:41;30400:11;30413:12;30385:14;:41::i;30610:1311::-;-1:-1:-1;;;;;30784:18:0;;30717:14;30784:18;;;:5;:18;;;;;30717:14;30843:30;7185:7;30843:15;:30;:::i;:::-;30820:53;;30884:25;30912:22;:20;:22::i;:::-;30969:18;;30884:50;;-1:-1:-1;31040:12:0;30998:916;31083:17;31071:8;:29;30998:916;;31248:18;31244:77;;31300:5;;31244:77;31335:27;31365:28;;;:18;:28;;;;;31412:20;;;;:25;31408:495;;31471:417;31478:17;;31471:417;;31554:28;31585:11;31597:17;31613:1;31597:13;:17;:::i;:::-;31585:30;;;;;;-1:-1:-1;;;31585:30:0;;;;;;;;;;;;;;;;;31665:20;;31585:30;;31642:19;;31585:30;;-1:-1:-1;31665:20:0;;;;31642:19;;:43;31638:231;;31785:28;;;;31767:15;;31745:19;;:37;;-1:-1:-1;;;;;;;;31767:15:0;;;;;;;31745:19;;;;;:37;:::i;:::-;-1:-1:-1;;;;;31745:68:0;;;;;:::i;:::-;31735:78;;;;:::i;:::-;;;31840:5;;;31638:231;-1:-1:-1;31497:15:0;;;;:::i;:::-;;;;31471:417;;;-1:-1:-1;31119:10:0;;;;:::i;:::-;;;;30998:916;;;;30610:1311;;;;;;;:::o;28988:249::-;-1:-1:-1;;;;;29190:18:0;;29147:7;29190:18;;;:5;:18;;;;;29179:50;;29190:30;;29222:6;29179:10;:50::i;29839:246::-;-1:-1:-1;;;;;30040:18:0;;29995:7;30040:18;;;:5;:18;;;;;30027:50;;30040:28;;30070:6;30027:12;:50::i;51251:624::-;51350:12;:10;:12::i;:::-;51373:20;51396:30;7185:7;51396:15;:30;:::i;:::-;51507:10;51437:43;51483:35;;;:23;:35;;;;;51551:33;;51373:53;;-1:-1:-1;51483:35:0;51551:49;;51529:135;;;;-1:-1:-1;;;51529:135:0;;6974:2:1;51529:135:0;;;6956:21:1;;;6993:18;;;6986:30;7052:34;7032:18;;;7025:62;7104:18;;51529:135:0;6946:182:1;51529:135:0;51730:22;:20;:22::i;:::-;51697:17;:30;;;:55;51675:139;;;;-1:-1:-1;;;51675:139:0;;10976:2:1;51675:139:0;;;10958:21:1;11015:2;10995:18;;;10988:30;11054:32;11034:18;;;11027:60;11104:18;;51675:139:0;10948:180:1;51675:139:0;51825:42;51834:6;51842:17;:24;;;51825:8;:42::i;:::-;51251:624;;;:::o;28150:186::-;28257:7;28289:39;28302:11;28315:12;28289;:39::i;17966:282::-;12954:15;;-1:-1:-1;;;;;12954:15:0;12940:10;:29;;:64;;-1:-1:-1;12987:17:0;;-1:-1:-1;;;;;12987:17:0;12973:10;:31;12940:64;12918:140;;;;-1:-1:-1;;;12918:140:0;;;;;;;:::i;:::-;18111:6:::1;;18100:7;:17;;18078:101;;;::::0;-1:-1:-1;;;18078:101:0;;5896:2:1;18078:101:0::1;::::0;::::1;5878:21:1::0;5935:2;5915:18;;;5908:30;5974:32;5954:18;;;5947:60;6024:18;;18078:101:0::1;5868:180:1::0;18078:101:0::1;18190:6;:16:::0;;;18222:18:::1;::::0;17715:25:1;;;18222:18:0::1;::::0;17703:2:1;17688:18;18222::0::1;17670:76:1::0;48078:162:0;48169:12;:10;:12::i;:::-;48192:40;48201:6;48209:22;48220:10;48209;:22::i;:::-;48192:8;:40::i;17532:326::-;12954:15;;-1:-1:-1;;;;;12954:15:0;12940:10;:29;;:64;;-1:-1:-1;12987:17:0;;-1:-1:-1;;;;;12987:17:0;12973:10;:31;12940:64;12918:140;;;;-1:-1:-1;;;12918:140:0;;;;;;;:::i;:::-;7615:4:::1;17676:12;:31;;17654:115;;;::::0;-1:-1:-1;;;17654:115:0;;9110:2:1;17654:115:0::1;::::0;::::1;9092:21:1::0;9149:2;9129:18;;;9122:30;9188:32;9168:18;;;9161:60;9238:18;;17654:115:0::1;9082:180:1::0;17654:115:0::1;17780:11;:26:::0;;;17822:28:::1;::::0;17715:25:1;;;17822:28:0::1;::::0;17703:2:1;17688:18;17822:28:0::1;17670:76:1::0;58781:1579:0;58871:7;58896:12;:10;:12::i;:::-;-1:-1:-1;;;;;58939:18:0;;58919:17;58939:18;;;:5;:18;;;;;58990:24;;;;58968:109;;;;-1:-1:-1;;;58968:109:0;;7695:2:1;58968:109:0;;;7677:21:1;7734:2;7714:18;;;7707:30;7773:28;7753:18;;;7746:56;7819:18;;58968:109:0;7667:176:1;58968:109:0;59137:15;59110:4;:24;;;:42;59088:124;;;;-1:-1:-1;;;59088:124:0;;13836:2:1;59088:124:0;;;13818:21:1;13875:2;13855:18;;;13848:30;13914;13894:18;;;13887:58;13962:18;;59088:124:0;13808:178:1;59088:124:0;59223:19;59245:13;:11;:13::i;:::-;59223:35;;59269:21;59293:4;:18;;;59269:42;;59322:29;59388:11;59375:10;;59354:4;:18;;;:31;;;;:::i;:::-;:45;;;;:::i;:::-;59322:77;;59607:21;59591:13;:37;59587:116;;;59670:21;59654:37;;59587:116;59713:26;59758:13;59742:4;:13;;;:29;;;;:::i;:::-;59782:13;;;:34;;;59871:18;;;;59713:58;;-1:-1:-1;59829:25:0;;59857:32;;:11;:32;:::i;:::-;59829:60;;59900:93;59936:10;59961:17;59900:21;:93::i;:::-;60018:13;60004:10;;:27;;;;;;;:::i;:::-;;;;-1:-1:-1;;60065:1:0;60044:18;;;:22;;;60077:18;;;:22;;;60110:24;;;;:28;;;;60296:10;60154:167;;;18838:25:1;;;18894:2;18879:18;;18872:34;;;18922:18;;;18915:34;;;18980:2;18965:18;;18958:34;;;;-1:-1:-1;;;;;60154:167:0;;;;;18825:3:1;18810:19;60154:167:0;;;;;;;-1:-1:-1;60339:13:0;;58781:1579;-1:-1:-1;;;;;;58781:1579:0:o;41148:2153::-;41248:12;:10;:12::i;:::-;-1:-1:-1;;;;;41293:22:0;;;;;;:48;;-1:-1:-1;;;;;;41319:22:0;;41331:10;41319:22;;41293:48;41271:124;;;;-1:-1:-1;;;41271:124:0;;14552:2:1;41271:124:0;;;14534:21:1;14591:2;14571:18;;;14564:30;-1:-1:-1;;;14610:18:1;;;14603:52;14672:18;;41271:124:0;14524:172:1;41271:124:0;41683:1;41649:22;41662:8;41649:12;:22::i;:::-;-1:-1:-1;;;;;41649:36:0;;41627:118;;;;-1:-1:-1;;;41627:118:0;;12049:2:1;41627:118:0;;;12031:21:1;12088:2;12068:18;;;12061:30;12127;12107:18;;;12100:58;12175:18;;41627:118:0;12021:178:1;41627:118:0;41782:10;41756:17;41776;;;:5;:17;;;;;41929:34;;;;41981:15;;41929:49;;7185:7;;41929:49;:::i;:::-;:67;41907:152;;;;-1:-1:-1;;;41907:152:0;;16693:2:1;41907:152:0;;;16675:21:1;16732:2;16712:18;;;16705:30;16771:33;16751:18;;;16744:61;16822:18;;41907:152:0;16665:181:1;41907:152:0;42107:15;42070:34;;;:52;42135:18;42156:22;42167:10;42156;:22::i;:::-;42135:43;-1:-1:-1;42211:15:0;42189:101;;;;-1:-1:-1;;;42189:101:0;;12765:2:1;42189:101:0;;;12747:21:1;;;12784:18;;;12777:30;12843:34;12823:18;;;12816:62;12895:18;;42189:101:0;12737:182:1;42189:101:0;42303:24;42330;42343:10;42330:12;:24::i;:::-;42303:51;;42407:8;-1:-1:-1;;;;;42387:28:0;:16;-1:-1:-1;;;;;42387:28:0;;;42365:105;;;;-1:-1:-1;;;42365:105:0;;13484:2:1;42365:105:0;;;13466:21:1;13523:2;13503:18;;;13496:30;13562:25;13542:18;;;13535:53;13605:18;;42365:105:0;13456:173:1;42365:105:0;-1:-1:-1;;;;;42485:30:0;;;42481:273;;-1:-1:-1;;;;;42623:23:0;;;;;;:5;:23;;;;;42583:159;;42623:35;;42713:10;42677:33;42629:16;42677:15;:33::i;:::-;:46;;;;:::i;:::-;42583:21;:159::i;:::-;42804:25;42860:10;42832:25;42848:8;42832:15;:25::i;:::-;:38;;;;:::i;:::-;-1:-1:-1;;;;;42917:15:0;;;;;;:5;:15;;;;;42804:66;;-1:-1:-1;42881:110:0;;42917:27;;42804:66;42881:21;:110::i;:::-;43053:95;43096:4;:14;;43125:8;43053:28;:95::i;:::-;43164:129;;;18204:25:1;;;18260:2;18245:18;;18238:34;;;-1:-1:-1;;;;;43164:129:0;;;43188:10;;43164:129;;18177:18:1;43164:129:0;;;;;;;;41148:2153;;;;;:::o;65415:725::-;65597:10;-1:-1:-1;;;;;65611:15:0;65597:29;;65575:115;;;;-1:-1:-1;;;65575:115:0;;10615:2:1;65575:115:0;;;10597:21:1;;;10634:18;;;10627:30;10693:34;10673:18;;;10666:62;10745:18;;65575:115:0;10587:182:1;65575:115:0;-1:-1:-1;;;;;65726:18:0;;65701:22;65726:18;;;:5;:18;;;;;:27;;;:36;;65756:6;;65726:36;:::i;:::-;-1:-1:-1;;;;;65773:18:0;;;;;;;:5;:18;;;;;;;:27;;:44;;;65945:53;-1:-1:-1;;;65945:53:0;;3830:15:1;;;65945:53:0;;;3812:34:1;65984:4:0;3862:18:1;;;3855:43;3914:18;;;3907:34;;;65773:44:0;;-1:-1:-1;65945:9:0;:22;;;;3747:18:1;;65945:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;65938:61;;-1:-1:-1;;;65938:61:0;;;;;;;;;66015:117;;;18204:25:1;;;18260:2;18245:18;;18238:34;;;-1:-1:-1;;;;;66015:117:0;;;;;18177:18:1;66015:117:0;;;;;;;65415:725;;;;:::o;17084:333::-;13234:15;;-1:-1:-1;;;;;13234:15:0;13220:10;:29;13198:113;;;;-1:-1:-1;;;13198:113:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;17264:34:0;::::1;;::::0;;;:19:::1;:34;::::0;;;;;:43;;-1:-1:-1;;17264:43:0::1;::::0;::::1;;::::0;;::::1;::::0;;;17323:86;;17264:43;;:34;17323:86:::1;::::0;::::1;17084:333:::0;;:::o;48911:2010::-;49077:13;49108:12;:10;:12::i;:::-;49176:1;49153:20;:24;49131:105;;;;-1:-1:-1;;;49131:105:0;;15977:2:1;49131:105:0;;;15959:21:1;16016:2;15996:18;;;15989:30;16055:29;16035:18;;;16028:57;16102:18;;49131:105:0;15949:177:1;49131:105:0;49247:20;49270:30;7185:7;49270:15;:30;:::i;:::-;-1:-1:-1;;;;;49357:36:0;;49311:43;49357:36;;;:23;:36;;;;;49483:33;;49247:53;;-1:-1:-1;49357:36:0;49483:49;;49479:242;;49558:48;;;49621:30;;;:45;;;49558:33;49681:24;;;:28;49479:242;49750:30;;;;49808:24;;;;49731:16;49871:22;:20;:22::i;:::-;49843:50;;49904:835;49923:17;49911:8;:29;49904:835;;50016:31;50027:20;50016:8;:31;:::i;:::-;49982:17;:30;;;:65;49978:416;;50081:30;;;:41;;;50141:24;;;:33;;;50198:149;;;18204:25:1;;;18260:2;18245:18;;18238:34;;;-1:-1:-1;;;;;50198:149:0;;;;;18177:18:1;50198:149:0;;;;;;;50373:5;50366:12;;;;;;;;;49978:416;50408:27;50438:28;;;:18;:28;;;;;50485:20;;;;:25;50481:247;;50595:20;;50544:22;;50569:47;;50582:11;;50595:20;;50569:12;:47::i;:::-;50684:28;;;;50645:19;;50544:72;;-1:-1:-1;50684:28:0;50645:36;;50544:72;;-1:-1:-1;;;50645:19:0;;-1:-1:-1;;;;;50645:19:0;:36;:::i;:::-;:67;;;;:::i;:::-;50635:77;;;;:::i;:::-;;;50481:247;;-1:-1:-1;49942:10:0;;;;:::i;:::-;;;;49904:835;;;50749:30;;;:41;;;50801:24;;;:33;;;50850:41;;17715:25:1;;;-1:-1:-1;;;;;50850:41:0;;;;;17703:2:1;17688:18;50850:41:0;;;;;;;-1:-1:-1;50909:4:0;;48911:2010;-1:-1:-1;;;;;;;48911:2010:0:o;27748:239::-;-1:-1:-1;;;;;27945:18:0;;27902:7;27945:18;;;:5;:18;;;;;27934:45;;27972:6;27934:10;:45::i;19245:373::-;13234:15;;-1:-1:-1;;;;;13234:15:0;13220:10;:29;13198:113;;;;-1:-1:-1;;;13198:113:0;;;;;;;:::i;:::-;7185:7:::1;19408:18;:34;;19386:119;;;::::0;-1:-1:-1;;;19386:119:0;;17411:2:1;19386:119:0::1;::::0;::::1;17393:21:1::0;17450:2;17430:18;;;17423:30;17489:33;17469:18;;;17462:61;17540:18;;19386:119:0::1;17383:181:1::0;19386:119:0::1;19516:17;:38:::0;;;19570:40:::1;::::0;17715:25:1;;;19570:40:0::1;::::0;17703:2:1;17688:18;19570:40:0::1;17670:76:1::0;22408:370:0;7716:9;22562:12;:26;;22555:34;;-1:-1:-1;;;22555:34:0;;;;;;;;;-1:-1:-1;;;;;22607:5:0;:20;;22600:28;;-1:-1:-1;;;22600:28:0;;;;;;;;;22660:109;;;;;;;;;;22704:12;22660:109;;;;-1:-1:-1;;;;;22660:109:0;;;;;;;;;;22639:131;;;;;;;-1:-1:-1;22639:131:0;;;;;;;;;;;;-1:-1:-1;;;22639:131:0;;;;;;;;;;22408:370::o;44835:743::-;44962:16;44981:24;44994:10;44981:12;:24::i;:::-;44962:43;-1:-1:-1;;;;;;45020:22:0;;45016:70;;45068:7;44835:743;;:::o;45016:70::-;45096:26;45125:25;45141:8;45125:15;:25::i;:::-;45096:54;;45161:25;45189:5;:91;;45253:27;45274:6;45253:18;:27;:::i;:::-;45189:91;;;45210:27;45231:6;45210:18;:27;:::i;:::-;-1:-1:-1;;;;;45327:15:0;;;;;;:5;:15;;;;;45161:119;;-1:-1:-1;45291:110:0;;45327:27;;45161:119;45291:21;:110::i;:::-;45417:153;;;4644:14:1;;4637:22;4619:41;;4691:2;4676:18;;4669:34;;;4719:18;;;4712:34;;;-1:-1:-1;;;;;45417:153:0;;;45449:10;;45417:153;;4607:2:1;4592:18;45417:153:0;4574:178:1;39485:528:0;39547:28;39635:9;-1:-1:-1;;;;;39635:21:0;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7615:4;39578:10;;:41;;;;:::i;:::-;:80;;;;:::i;:::-;39547:111;;39696:11;;39673:20;:34;39669:198;;;39745:13;;39739:3;;:19;:45;;39783:1;39739:45;;;39767:13;;39761:3;;:19;;;;:::i;:::-;39733:3;:51;39669:198;;;39842:13;;39835:3;;:20;;;;;;;:::i;:::-;;;;-1:-1:-1;;39669:198:0;39887:6;;39881:3;;:12;39877:129;;;39916:6;;39910:3;:12;38069:1307;:::o;39877:129::-;39959:6;;39953:3;;:12;39949:57;;;39988:6;;39982:3;:12;39485:528;:::o;33756:1215::-;33934:18;;33905:7;;33930:50;;-1:-1:-1;33979:1:0;33972:8;;33930:50;34061:18;;34049:11;;34061:21;;34081:1;;34061:21;:::i;:::-;34049:34;;;;;;-1:-1:-1;;;34049:34:0;;;;;;;;;;;;;;;;;;:44;;;34039:54;;34035:121;;34127:18;;34115:11;;34127:22;;34148:1;;34127:22;:::i;:::-;34115:35;;;;;;-1:-1:-1;;;34115:35:0;;;;;;;;;;;;;;;;;;:41;-1:-1:-1;;;34115:41:0;;-1:-1:-1;;;;;34115:41:0;;-1:-1:-1;34108:48:0;;34035:121;34180:11;34192:1;34180:14;;;;;;-1:-1:-1;;;34180:14:0;;;;;;;;;;;;;;;;;;:24;;;34171:33;;34167:60;;;-1:-1:-1;34226:1:0;34219:8;;34167:60;34401:18;;34360:8;;34422:4;-1:-1:-1;34401:103:0;;;;-1:-1:-1;34459:18:0;;34498:6;;34447:11;;34459:25;;34480:4;;34459:25;:::i;:::-;34447:38;;;;;;-1:-1:-1;;;34447:38:0;;;;;;;;;;;;;;;;;;:48;;;:57;34401:103;34383:204;;;34550:18;;:25;;34571:4;;34550:25;:::i;:::-;34544:31;;34383:204;34662:18;;34651:8;;34662:22;;34683:1;;34662:22;:::i;:::-;34651:33;;34695:229;34708:3;34702;:9;34695:229;;;34728:8;34757:1;34740:9;34746:3;34740;:9;:::i;:::-;:13;;34752:1;34740:13;:::i;:::-;34739:19;;;;:::i;:::-;34728:30;;34807:6;34777:11;34789:3;34777:16;;;;;;-1:-1:-1;;;34777:16:0;;;;;;;;;;;;;;;;;;:26;;;:36;34773:140;;34840:3;34834:9;;34773:140;;;34890:7;34896:1;34890:3;:7;:::i;:::-;34884:13;;34773:140;34695:229;;;;34941:11;34953:3;34941:16;;;;;;-1:-1:-1;;;34941:16:0;;;;;;;;;;;;;;;;;;:22;-1:-1:-1;;;34941:22:0;;-1:-1:-1;;;;;34941:22:0;;33756:1215;-1:-1:-1;;;;;33756:1215:0:o;23100:366::-;7716:9;23278:12;:26;;23271:34;;-1:-1:-1;;;23271:34:0;;;;;;;;;23344:113;;;;;;;;;;23395:12;23344:113;;;;-1:-1:-1;;;;;23344:113:0;;;;;;;;;;23316:142;;;;;;;-1:-1:-1;23316:142:0;;;;;;;;;;;;;;;;;;-1:-1:-1;;;23316:142:0;-1:-1:-1;;;;;;23316:142:0;;;;;;;;;;;;23100:366::o;36905:381::-;36987:25;;37053:30;7185:7;37053:15;:30;:::i;:::-;37030:53;-1:-1:-1;37114:36:0;7442:2;37030:53;37114:36;:::i;:::-;:40;;37153:1;37114:40;:::i;:::-;37094:60;-1:-1:-1;37189:16:0;:12;37204:1;37189:16;:::i;:::-;37169:17;:36;37165:114;;;37251:16;:12;37266:1;37251:16;:::i;:::-;37231:36;;37165:114;36905:381;;:::o;35437:1247::-;35623:18;;35594:7;;35619:59;;-1:-1:-1;35676:1:0;35661:17;;35619:59;35759:18;;35747:11;;35759:21;;35779:1;;35759:21;:::i;:::-;35747:34;;;;;;-1:-1:-1;;;35747:34:0;;;;;;;;;;;;;;;;;;:44;;;35737:54;;35733:124;;35825:18;;35813:11;;35825:22;;35846:1;;35825:22;:::i;:::-;35813:35;;;;;;-1:-1:-1;;;35813:35:0;;;;;;;;;;;;;;;;;;:44;-1:-1:-1;;;35813:44:0;;-1:-1:-1;;;;;35813:44:0;;-1:-1:-1;35806:51:0;;35733:124;35881:11;35893:1;35881:14;;;;;;-1:-1:-1;;;35881:14:0;;;;;;;;;;;;;;;;;;:24;;;35872:33;;35868:69;;;-1:-1:-1;35935:1:0;35920:17;;35868:69;36111:18;;36070:8;;36132:4;-1:-1:-1;36111:103:0;;;;-1:-1:-1;36169:18:0;;36208:6;;36157:11;;36169:25;;36190:4;;36169:25;:::i;:::-;36157:38;;;;;;-1:-1:-1;;;36157:38:0;;;;;;;;;;;;;;;;;;:48;;;:57;36111:103;36093:204;;;36260:18;;:25;;36281:4;;36260:25;:::i;:::-;36254:31;;36093:204;36372:18;;36361:8;;36372:22;;36393:1;;36372:22;:::i;:::-;36361:33;;36405:229;36418:3;36412;:9;36405:229;;;36438:8;36467:1;36450:9;36456:3;36450;:9;:::i;:::-;:13;;36462:1;36450:13;:::i;:::-;36449:19;;;;:::i;:::-;36438:30;;36517:6;36487:11;36499:3;36487:16;;;;;;-1:-1:-1;;;36487:16:0;;;;;;;;;;;;;;;;;;:26;;;:36;36483:140;;36550:3;36544:9;;36483:140;;;36600:7;36606:1;36600:3;:7;:::i;:::-;36594:13;;36483:140;36405:229;;;;36651:11;36663:3;36651:16;;;;;;-1:-1:-1;;;36651:16:0;;;;;;;;;;;;;;;;;;:25;-1:-1:-1;;;36651:25:0;;-1:-1:-1;;;;;36651:25:0;;35437:1247;-1:-1:-1;;;;;35437:1247:0:o;52096:1048::-;52238:10;52212:17;52232;;;:5;:17;;;;;52371:12;;;;52232:17;;52212;52358:25;;:10;:25;:::i;:::-;52331:52;;52394:22;52435:21;52445:10;52435:9;:21::i;:::-;52419:4;:13;;;:37;;;;:::i;:::-;52394:62;-1:-1:-1;52507:25:0;52526:6;52507:16;:25;:::i;:::-;52489:14;:43;;52467:128;;;;-1:-1:-1;;;52467:128:0;;16333:2:1;52467:128:0;;;16315:21:1;16372:2;16352:18;;;16345:30;16411:33;16391:18;;;16384:61;16462:18;;52467:128:0;16305:181:1;52467:128:0;52645:6;52628:4;:13;;;:23;;52606:108;;;;-1:-1:-1;;;52606:108:0;;6255:2:1;52606:108:0;;;6237:21:1;6294:2;6274:18;;;6267:30;6333:33;6313:18;;;6306:61;6384:18;;52606:108:0;6227:181:1;52606:108:0;52766:22;52807:6;52791:4;:13;;;:22;;;;:::i;:::-;52824:13;;;:30;;;52982:38;;-1:-1:-1;;;52982:38:0;;53001:10;52982:38;;;4126:51:1;4193:18;;;4186:34;;;52824:30:0;;-1:-1:-1;52982:9:0;-1:-1:-1;;;;;52982:18:0;;;;4099::1;;52982:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;52975:46;;-1:-1:-1;;;52975:46:0;;;;;;;;;53037:99;;;18204:25:1;;;18260:2;18245:18;;18238:34;;;53061:10:0;;53037:99;;18177:18:1;53037:99:0;;;;;;;52096:1048;;;;;;:::o;14:173:1:-;82:20;;-1:-1:-1;;;;;131:31:1;;121:42;;111:2;;177:1;174;167:12;111:2;63:124;;;:::o;192:196::-;251:6;304:2;292:9;283:7;279:23;275:32;272:2;;;325:6;317;310:22;272:2;353:29;372:9;353:29;:::i;393:419::-;479:6;487;495;503;556:3;544:9;535:7;531:23;527:33;524:2;;;578:6;570;563:22;524:2;606:29;625:9;606:29;:::i;:::-;596:39;;654:38;688:2;677:9;673:18;654:38;:::i;:::-;644:48;;711:38;745:2;734:9;730:18;711:38;:::i;:::-;701:48;;768:38;802:2;791:9;787:18;768:38;:::i;:::-;758:48;;514:298;;;;;;;:::o;817:325::-;882:6;890;943:2;931:9;922:7;918:23;914:32;911:2;;;964:6;956;949:22;911:2;992:29;1011:9;992:29;:::i;:::-;982:39;;1071:2;1060:9;1056:18;1043:32;1084:28;1106:5;1084:28;:::i;:::-;1131:5;1121:15;;;901:241;;;;;:::o;1147:264::-;1215:6;1223;1276:2;1264:9;1255:7;1251:23;1247:32;1244:2;;;1297:6;1289;1282:22;1244:2;1325:29;1344:9;1325:29;:::i;:::-;1315:39;1401:2;1386:18;;;;1373:32;;-1:-1:-1;;;1234:177:1:o;1416:338::-;1493:6;1501;1509;1562:2;1550:9;1541:7;1537:23;1533:32;1530:2;;;1583:6;1575;1568:22;1530:2;1611:29;1630:9;1611:29;:::i;:::-;1601:39;;1687:2;1676:9;1672:18;1659:32;1649:42;;1710:38;1744:2;1733:9;1729:18;1710:38;:::i;:::-;1700:48;;1520:234;;;;;:::o;1759:476::-;1854:6;1862;1870;1878;1886;1939:3;1927:9;1918:7;1914:23;1910:33;1907:2;;;1961:6;1953;1946:22;1907:2;1989:29;2008:9;1989:29;:::i;:::-;1979:39;;2065:2;2054:9;2050:18;2037:32;2027:42;;2088:38;2122:2;2111:9;2107:18;2088:38;:::i;:::-;1897:338;;;;-1:-1:-1;2078:48:1;;2173:2;2158:18;;2145:32;;-1:-1:-1;2224:3:1;2209:19;2196:33;;1897:338;-1:-1:-1;;1897:338:1:o;2240:255::-;2307:6;2360:2;2348:9;2339:7;2335:23;2331:32;2328:2;;;2381:6;2373;2366:22;2328:2;2418:9;2412:16;2437:28;2459:5;2437:28;:::i;2500:190::-;2559:6;2612:2;2600:9;2591:7;2587:23;2583:32;2580:2;;;2633:6;2625;2618:22;2580:2;-1:-1:-1;2661:23:1;;2570:120;-1:-1:-1;2570:120:1:o;2695:194::-;2765:6;2818:2;2806:9;2797:7;2793:23;2789:32;2786:2;;;2839:6;2831;2824:22;2786:2;-1:-1:-1;2867:16:1;;2776:113;-1:-1:-1;2776:113:1:o;4983:346::-;5185:2;5167:21;;;5224:2;5204:18;;;5197:30;-1:-1:-1;;;5258:2:1;5243:18;;5236:52;5320:2;5305:18;;5157:172::o;15056:354::-;15258:2;15240:21;;;15297:2;15277:18;;;15270:30;15336:32;15331:2;15316:18;;15309:60;15401:2;15386:18;;15230:180::o;21354:128::-;21394:3;21425:1;21421:6;21418:1;21415:13;21412:2;;;21431:18;;:::i;:::-;-1:-1:-1;21467:9:1;;21402:80::o;21487:217::-;21527:1;21553;21543:2;;-1:-1:-1;;;21578:31:1;;21632:4;21629:1;21622:15;21660:4;21585:1;21650:15;21543:2;-1:-1:-1;21689:9:1;;21533:171::o;21709:272::-;21749:7;-1:-1:-1;;;;;21820:10:1;;;21850;;;21883:11;;21876:19;21905:12;;;21897:21;;21872:47;21869:2;;;21922:18;;:::i;:::-;21962:13;;21761:220;-1:-1:-1;;;;21761:220:1:o;21986:168::-;22026:7;22092:1;22088;22084:6;22080:14;22077:1;22074:21;22069:1;22062:9;22055:17;22051:45;22048:2;;;22099:18;;:::i;:::-;-1:-1:-1;22139:9:1;;22038:116::o;22159:125::-;22199:4;22227:1;22224;22221:8;22218:2;;;22232:18;;:::i;:::-;-1:-1:-1;22269:9:1;;22208:76::o;22289:136::-;22328:3;22356:5;22346:2;;22365:18;;:::i;:::-;-1:-1:-1;;;22401:18:1;;22336:89::o;22430:127::-;22491:10;22486:3;22482:20;22479:1;22472:31;22522:4;22519:1;22512:15;22546:4;22543:1;22536:15;22562:118;22648:5;22641:13;22634:21;22627:5;22624:32;22614:2;;22670:1;22667;22660:12

Swarm Source

ipfs://dab22d0b89f8e4222d6d396b8e9eff20e527eeba97d049ec9d7bf982050a7ce5

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.