false
false
0

Contract Address Details

0xbfA12e4E1411B62EdA8B035d71735667422A6A9e

Contract Name
FtsoManager
Creator
0x493044–a7586e at 0xdeb3f3–1fdf93
Balance
0 SGB ( )
Tokens
Fetching tokens...
Transactions
33 Transactions
Transfers
0 Transfers
Gas Used
8,287,243
Last Balance Update
56584452
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
FtsoManager




Optimization enabled
true
Compiler version
v0.7.6+commit.7338295f




Optimization runs
200
EVM Version
default




Verified at
2021-09-17T13:58:11.135604Z

Constructor Arguments

5265776172642065706f6368206475726174696f6e20636f6e646974696f6e20696e76616c69645265776172642065706f636820737461727420636f6e646974696f6e20696e76616c6964000000000000000000000000493044fbbaa7f9f78379864fa88accaff6a7586e00000000000000000000000010000000000000000000000000000000000000020000000000000000000000001000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000006143aba100000000000000000000000000000000000000000000000000000000000000b4000000000000000000000000000000000000000000000000000000000000005a000000000000000000000000000000000000000000000000000000006145a63b0000000000000000000000000000000000000000000000000000000000093a800000000000000000000000000000000000000000000000000000000000000004

Arg [0] (address) : 0x206475726174696f6e20636f6e646974696f6e20
Arg [1] (address) : 0x642065706f636820737461727420636f6e646974
Arg [2] (address) : 0x0000000000000000000000493044fbbaa7f9f783
Arg [3] (uint256) : 54967161967105272774295421565322653183809673969712434805607800255944322973696
Arg [4] (uint256) : 748288838313422294120286634351032053969016814829568
Arg [5] (uint256) : 1122433257470133441180429951526105359095756193005568
Arg [6] (uint256) : 610538142335660755365900103581175507970488629865276197830656
Arg [7] (uint256) : 67345995448208006470825797091566321545745371580334080
Arg [8] (uint256) : 33672997724104003235412898545783160772872685790167040

              

Contract source code

// Sources flattened with hardhat v2.3.0 https://hardhat.org
pragma abicoder v2;

// File contracts/genesis/interface/IFtsoGenesis.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;


interface IFtsoGenesis {

    /**
     * @notice Submits price hash for current epoch - only price submitter
     * @param _sender               Sender address
     * @param _epochId              Target epoch id to which hashes are submitted
     * @param _hash                 Hashed price and random number
     * @notice Emits PriceHashSubmitted event.
     */
    function submitPriceHashSubmitter(address _sender, uint256 _epochId, bytes32 _hash) external;

    /**
     * @notice Reveals submitted price during epoch reveal period - only price submitter
     * @param _voter                Voter address
     * @param _epochId              Id of the epoch in which the price hash was submitted
     * @param _price                Submitted price in USD
     * @param _random               Submitted random number
     * @notice The hash of _price and _random must be equal to the submitted hash
     * @notice Emits PriceRevealed event
     */
    function revealPriceSubmitter(
        address _voter,
        uint256 _epochId,
        uint256 _price,
        uint256 _random,
        uint256 _wNatVP
    ) external;

    /**
     * @notice Get (and cache) wNat vote power for specified voter and given epoch id
     * @param _voter                Voter address
     * @param _epochId              Id of the epoch in which the price hash was submitted
     * @return wNat vote power
     */
    function wNatVotePowerCached(address _voter, uint256 _epochId) external returns (uint256);
}


// File contracts/userInterfaces/IFtso.sol

//
pragma solidity 0.7.6;

interface IFtso {
    enum PriceFinalizationType {
        // initial state
        NOT_FINALIZED,
        // median calculation used to decide price
        WEIGHTED_MEDIAN,
        // low turnout - price decided from average of trusted addresses
        TRUSTED_ADDRESSES,
        // low turnout + no votes from trusted addresses - price copied from previous epoch
        PREVIOUS_PRICE_COPIED,
        // price decided from average of trusted addresses - triggered due to an exception
        TRUSTED_ADDRESSES_EXCEPTION,
        // previous price copied - triggered due to an exception
        PREVIOUS_PRICE_COPIED_EXCEPTION
    }

    // events
    event PriceHashSubmitted(
        address indexed submitter, uint256 indexed epochId, bytes32 hash, uint256 timestamp
    );

    event PriceRevealed(
        address indexed voter, uint256 indexed epochId, uint256 price, uint256 random, uint256 timestamp,
        uint256 votePowerNat, uint256 votePowerAsset
    );

    event PriceFinalized(
        uint256 indexed epochId, uint256 price, bool rewardedFtso,
        uint256 lowRewardPrice, uint256 highRewardPrice, PriceFinalizationType finalizationType,
        uint256 timestamp
    );

    event PriceEpochInitializedOnFtso(
        uint256 indexed epochId, uint256 endTime, uint256 timestamp
    );

    event LowTurnout(
        uint256 indexed epochId,
        uint256 natTurnout,
        uint256 lowNatTurnoutThresholdBIPS,
        uint256 timestamp
    );

    /**
     * @notice Returns if FTSO is active
     */
    function active() external view returns (bool);

    /**
     * @notice Returns the FTSO symbol
     */
    function symbol() external view returns (string memory);

    /**
     * @notice Returns current epoch id
     */
    function getCurrentEpochId() external view returns (uint256);

    /**
     * @notice Returns id of the epoch which was opened for price submission at the specified timestamp
     * @param _timestamp            Timestamp as seconds from unix epoch
     */
    function getEpochId(uint256 _timestamp) external view returns (uint256);

    /**
     * @notice Returns random number of the specified epoch
     * @param _epochId              Id of the epoch
     */
    function getRandom(uint256 _epochId) external view returns (uint256);

    /**
     * @notice Returns asset price consented in specific epoch
     * @param _epochId              Id of the epoch
     * @return Price in USD multiplied by ASSET_PRICE_USD_DECIMALS
     */
    function getEpochPrice(uint256 _epochId) external view returns (uint256);

    /**
     * @notice Returns current epoch data
     * @return _epochId                 Current epoch id
     * @return _epochSubmitEndTime      End time of the current epoch price submission as seconds from unix epoch
     * @return _epochRevealEndTime      End time of the current epoch price reveal as seconds from unix epoch
     * @return _votePowerBlock          Vote power block for the current epoch
     * @return _fallbackMode            Current epoch in fallback mode - only votes from trusted addresses will be used
     * @dev half-closed intervals - end time not included
     */
    function getPriceEpochData() external view returns (
        uint256 _epochId,
        uint256 _epochSubmitEndTime,
        uint256 _epochRevealEndTime,
        uint256 _votePowerBlock,
        bool _fallbackMode
    );

    /**
     * @notice Returns current epoch data
     * @return _firstEpochStartTime         First epoch start time
     * @return _submitPeriod                Submit period in seconds
     * @return _revealPeriod                Reveal period in seconds
     */
    function getPriceEpochConfiguration() external view returns (
        uint256 _firstEpochStartTime,
        uint256 _submitPeriod,
        uint256 _revealPeriod
    );

    /**
     * @notice Returns asset price submitted by voter in specific epoch
     * @param _epochId              Id of the epoch
     * @param _voter                Address of the voter
     * @return Price in USD multiplied by ASSET_PRICE_USD_DECIMALS
     */
    function getEpochPriceForVoter(uint256 _epochId, address _voter) external view returns (uint256);

    /**
     * @notice Returns current asset price
     * @return _price               Price in USD multiplied by ASSET_PRICE_USD_DECIMALS
     * @return _timestamp           Time when price was updated for the last time
     */
    function getCurrentPrice() external view returns (uint256 _price, uint256 _timestamp);

    /**
     * @notice Returns current random number
     */
    function getCurrentRandom() external view returns (uint256);
}


// File @openzeppelin/contracts/token/ERC20/[email protected]

//

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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/userInterfaces/IGovernanceVotePower.sol

//
pragma solidity 0.7.6;

interface IGovernanceVotePower {
    /**
     * @notice Delegate all governance vote power of `msg.sender` to `_to`.
     * @param _to The address of the recipient
     **/
    function delegate(address _to) external;

    /**
     * @notice Undelegate all governance vote power that `msg.sender` has delegated.
     **/
    function undelegate() external;

    /**
    * @notice Get the governance vote power of `_who` at block `_blockNumber`
    * @param _who The address to get voting power.
    * @param _blockNumber The block number at which to fetch.
    * @return Governance vote power of `_who` at `_blockNumber`.
    */
    function votePowerOfAt(address _who, uint256 _blockNumber) external view returns(uint256);
}


// File contracts/userInterfaces/IVPContractEvents.sol

//
pragma solidity 0.7.6;

interface IVPContractEvents {
    /**
     * Event triggered when an account delegates or undelegates another account.
     * Definition: `votePowerFromTo(from, to)` is `changed` from `priorVotePower` to `newVotePower`.
     * For undelegation, `newVotePower` is 0.
     *
     * Note: the event is always emitted from VPToken's `writeVotePowerContract`.
     */
    event Delegate(address indexed from, address indexed to, uint256 priorVotePower, uint256 newVotePower);

    /**
     * Event triggered only when account `delegator` revokes delegation to `delegatee`
     * for a single block in the past (typically the current vote block).
     *
     * Note: the event is always emitted from VPToken's `writeVotePowerContract` and/or `readVotePowerContract`.
     */
    event Revoke(address indexed delegator, address indexed delegatee, uint256 votePower, uint256 blockNumber);
}


// File contracts/userInterfaces/IVPToken.sol

//
pragma solidity 0.7.6;



interface IVPToken is IERC20 {
    /**
     * @notice Delegate by percentage `_bips` of voting power to `_to` from `msg.sender`.
     * @param _to The address of the recipient
     * @param _bips The percentage of voting power to be delegated expressed in basis points (1/100 of one percent).
     *   Not cummulative - every call resets the delegation value (and value of 0 undelegates `to`).
     **/
    function delegate(address _to, uint256 _bips) external;

    /**
     * @notice Explicitly delegate `_amount` of voting power to `_to` from `msg.sender`.
     * @param _to The address of the recipient
     * @param _amount An explicit vote power amount to be delegated.
     *   Not cummulative - every call resets the delegation value (and value of 0 undelegates `to`).
     **/
    function delegateExplicit(address _to, uint _amount) external;

    /**
    * @notice Revoke all delegation from sender to `_who` at given block.
    *    Only affects the reads via `votePowerOfAtCached()` in the block `_blockNumber`.
    *    Block `_blockNumber` must be in the past.
    *    This method should be used only to prevent rogue delegate voting in the current voting block.
    *    To stop delegating use delegate/delegateExplicit with value of 0 or undelegateAll/undelegateAllExplicit.
    * @param _who Address of the delegatee
    * @param _blockNumber The block number at which to revoke delegation.
    */
    function revokeDelegationAt(address _who, uint _blockNumber) external;

    /**
     * @notice Undelegate all voting power for delegates of `msg.sender`
     *    Can only be used with percentage delegation.
     *    Does not reset delegation mode back to NOTSET.
     **/
    function undelegateAll() external;

    /**
     * @notice Undelegate all explicit vote power by amount delegates for `msg.sender`.
     *    Can only be used with explicit delegation.
     *    Does not reset delegation mode back to NOTSET.
     * @param _delegateAddresses Explicit delegation does not store delegatees' addresses,
     *   so the caller must supply them.
     * @return The amount still delegated (in case the list of delegates was incomplete).
     */
    function undelegateAllExplicit(address[] memory _delegateAddresses) external returns (uint256);


    /**
     * @dev Should be compatible with ERC20 method
     */
    function name() external view returns (string memory);

    /**
     * @dev Should be compatible with ERC20 method
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Should be compatible with ERC20 method
     */
    function decimals() external view returns (uint8);


    /**
     * @notice Total amount of tokens at a specific `_blockNumber`.
     * @param _blockNumber The block number when the totalSupply is queried
     * @return The total amount of tokens at `_blockNumber`
     **/
    function totalSupplyAt(uint _blockNumber) external view returns(uint256);

    /**
     * @dev Queries the token balance of `_owner` at a specific `_blockNumber`.
     * @param _owner The address from which the balance will be retrieved.
     * @param _blockNumber The block number when the balance is queried.
     * @return The balance at `_blockNumber`.
     **/
    function balanceOfAt(address _owner, uint _blockNumber) external view returns (uint256);


    /**
     * @notice Get the current total vote power.
     * @return The current total vote power (sum of all accounts' vote powers).
     */
    function totalVotePower() external view returns(uint256);

    /**
    * @notice Get the total vote power at block `_blockNumber`
    * @param _blockNumber The block number at which to fetch.
    * @return The total vote power at the block  (sum of all accounts' vote powers).
    */
    function totalVotePowerAt(uint _blockNumber) external view returns(uint256);

    /**
     * @notice Get the current vote power of `_owner`.
     * @param _owner The address to get voting power.
     * @return Current vote power of `_owner`.
     */
    function votePowerOf(address _owner) external view returns(uint256);

    /**
    * @notice Get the vote power of `_owner` at block `_blockNumber`
    * @param _owner The address to get voting power.
    * @param _blockNumber The block number at which to fetch.
    * @return Vote power of `_owner` at `_blockNumber`.
    */
    function votePowerOfAt(address _owner, uint256 _blockNumber) external view returns(uint256);


    /**
     * @notice Get the delegation mode for '_who'. This mode determines whether vote power is
     *  allocated by percentage or by explicit value. Once the delegation mode is set,
     *  it never changes, even if all delegations are removed.
     * @param _who The address to get delegation mode.
     * @return delegation mode: 0 = NOTSET, 1 = PERCENTAGE, 2 = AMOUNT (i.e. explicit)
     */
    function delegationModeOf(address _who) external view returns(uint256);

    /**
    * @notice Get current delegated vote power `_from` delegator delegated `_to` delegatee.
    * @param _from Address of delegator
    * @param _to Address of delegatee
    * @return The delegated vote power.
    */
    function votePowerFromTo(address _from, address _to) external view returns(uint256);

    /**
    * @notice Get delegated the vote power `_from` delegator delegated `_to` delegatee at `_blockNumber`.
    * @param _from Address of delegator
    * @param _to Address of delegatee
    * @param _blockNumber The block number at which to fetch.
    * @return The delegated vote power.
    */
    function votePowerFromToAt(address _from, address _to, uint _blockNumber) external view returns(uint256);

    /**
     * @notice Compute the current undelegated vote power of `_owner`
     * @param _owner The address to get undelegated voting power.
     * @return The unallocated vote power of `_owner`
     */
    function undelegatedVotePowerOf(address _owner) external view returns(uint256);

    /**
     * @notice Get the undelegated vote power of `_owner` at given block.
     * @param _owner The address to get undelegated voting power.
     * @param _blockNumber The block number at which to fetch.
     * @return The undelegated vote power of `_owner` (= owner's own balance minus all delegations from owner)
     */
    function undelegatedVotePowerOfAt(address _owner, uint256 _blockNumber) external view returns(uint256);

    /**
    * @notice Get the vote power delegation `delegationAddresses`
    *  and `_bips` of `_who`. Returned in two separate positional arrays.
    * @param _who The address to get delegations.
    * @return _delegateAddresses Positional array of delegation addresses.
    * @return _bips Positional array of delegation percents specified in basis points (1/100 or 1 percent)
    * @return _count The number of delegates.
    * @return _delegationMode The mode of the delegation (NOTSET=0, PERCENTAGE=1, AMOUNT=2).
    */
    function delegatesOf(address _who)
        external view
        returns (
            address[] memory _delegateAddresses,
            uint256[] memory _bips,
            uint256 _count,
            uint256 _delegationMode
        );

    /**
    * @notice Get the vote power delegation `delegationAddresses`
    *  and `pcts` of `_who`. Returned in two separate positional arrays.
    * @param _who The address to get delegations.
    * @param _blockNumber The block for which we want to know the delegations.
    * @return _delegateAddresses Positional array of delegation addresses.
    * @return _bips Positional array of delegation percents specified in basis points (1/100 or 1 percent)
    * @return _count The number of delegates.
    * @return _delegationMode The mode of the delegation (NOTSET=0, PERCENTAGE=1, AMOUNT=2).
    */
    function delegatesOfAt(address _who, uint256 _blockNumber)
        external view
        returns (
            address[] memory _delegateAddresses,
            uint256[] memory _bips,
            uint256 _count,
            uint256 _delegationMode
        );

    /**
     * Returns VPContract used for readonly operations (view methods).
     * The only non-view method that might be called on it is `revokeDelegationAt`.
     *
     * @notice `readVotePowerContract` is almost always equal to `writeVotePowerContract`
     * except during upgrade from one VPContract to a new version (which should happen
     * rarely or never and will be anounced before).
     *
     * @notice You shouldn't call any methods on VPContract directly, all are exposed
     * via VPToken (and state changing methods are forbidden from direct calls).
     * This is the reason why this method returns `IVPContractEvents` - it should only be used
     * for listening to events (`Revoke` only).
     */
    function readVotePowerContract() external view returns (IVPContractEvents);

    /**
     * Returns VPContract used for state changing operations (non-view methods).
     * The only non-view method that might be called on it is `revokeDelegationAt`.
     *
     * @notice `writeVotePowerContract` is almost always equal to `readVotePowerContract`
     * except during upgrade from one VPContract to a new version (which should happen
     * rarely or never and will be anounced before). In the case of upgrade,
     * `writeVotePowerContract` will be replaced first to establish delegations, and
     * after some perio (e.g. after a reward epoch ends) `readVotePowerContract` will be set equal to it.
     *
     * @notice You shouldn't call any methods on VPContract directly, all are exposed
     * via VPToken (and state changing methods are forbidden from direct calls).
     * This is the reason why this method returns `IVPContractEvents` - it should only be used
     * for listening to events (`Delegate` and `Revoke` only).
     */
    function writeVotePowerContract() external view returns (IVPContractEvents);

    /**
     * When set, allows token owners to participate in governance voting
     * and delegate governance vote power.
     */
    function governanceVotePower() external view returns (IGovernanceVotePower);
}


// File contracts/token/interface/IICleanable.sol

//
pragma solidity 0.7.6;

interface IICleanable {
    /**
     * Set the contract that is allowed to call history cleaning methods.
     */
    function setCleanerContract(address _cleanerContract) external;

    /**
     * Set the cleanup block number.
     * Historic data for the blocks before `cleanupBlockNumber` can be erased,
     * history before that block should never be used since it can be inconsistent.
     * In particular, cleanup block number must be before current vote power block.
     * @param _blockNumber The new cleanup block number.
     */
    function setCleanupBlockNumber(uint256 _blockNumber) external;

    /**
     * Set the contract that is allowed to set cleanupBlockNumber.
     * Usually this will be an instance of CleanupBlockNumberManager.
     */
    function setCleanupBlockNumberManager(address _cleanupBlockNumberManager) external;

    /**
     * Get the current cleanup block number.
     */
    function cleanupBlockNumber() external view returns (uint256);
}


// File contracts/token/interface/IIVPContract.sol

//
pragma solidity 0.7.6;



interface IIVPContract is IICleanable, IVPContractEvents {
    /**
     * Update vote powers when tokens are transfered.
     * Also update delegated vote powers for percentage delegation
     * and check for enough funds for explicit delegations.
     **/
    function updateAtTokenTransfer(
        address _from,
        address _to,
        uint256 _fromBalance,
        uint256 _toBalance,
        uint256 _amount
    ) external;

    /**
     * @notice Delegate `_bips` percentage of voting power to `_to` from `_from`
     * @param _from The address of the delegator
     * @param _to The address of the recipient
     * @param _balance The delegator's current balance
     * @param _bips The percentage of voting power to be delegated expressed in basis points (1/100 of one percent).
     *   Not cummulative - every call resets the delegation value (and value of 0 revokes delegation).
     **/
    function delegate(
        address _from,
        address _to,
        uint256 _balance,
        uint256 _bips
    ) external;

    /**
     * @notice Explicitly delegate `_amount` of voting power to `_to` from `msg.sender`.
     * @param _from The address of the delegator
     * @param _to The address of the recipient
     * @param _balance The delegator's current balance
     * @param _amount An explicit vote power amount to be delegated.
     *   Not cummulative - every call resets the delegation value (and value of 0 undelegates `to`).
     **/
    function delegateExplicit(
        address _from,
        address _to,
        uint256 _balance,
        uint _amount
    ) external;

    /**
     * @notice Revoke all delegation from sender to `_who` at given block.
     *    Only affects the reads via `votePowerOfAtCached()` in the block `_blockNumber`.
     *    Block `_blockNumber` must be in the past.
     *    This method should be used only to prevent rogue delegate voting in the current voting block.
     *    To stop delegating use delegate/delegateExplicit with value of 0 or undelegateAll/undelegateAllExplicit.
     * @param _from The address of the delegator
     * @param _who Address of the delegatee
     * @param _balance The delegator's current balance
     * @param _blockNumber The block number at which to revoke delegation.
     **/
    function revokeDelegationAt(
        address _from,
        address _who,
        uint256 _balance,
        uint _blockNumber
    ) external;

        /**
     * @notice Undelegate all voting power for delegates of `msg.sender`
     *    Can only be used with percentage delegation.
     *    Does not reset delegation mode back to NOTSET.
     * @param _from The address of the delegator
     **/
    function undelegateAll(
        address _from,
        uint256 _balance
    ) external;

    /**
     * @notice Undelegate all explicit vote power by amount delegates for `msg.sender`.
     *    Can only be used with explicit delegation.
     *    Does not reset delegation mode back to NOTSET.
     * @param _from The address of the delegator
     * @param _delegateAddresses Explicit delegation does not store delegatees' addresses,
     *   so the caller must supply them.
     * @return The amount still delegated (in case the list of delegates was incomplete).
     */
    function undelegateAllExplicit(
        address _from,
        address[] memory _delegateAddresses
    ) external returns (uint256);

    /**
    * @notice Get the vote power of `_who` at block `_blockNumber`
    *   Reads/updates cache and upholds revocations.
    * @param _who The address to get voting power.
    * @param _blockNumber The block number at which to fetch.
    * @return Vote power of `_who` at `_blockNumber`.
    */
    function votePowerOfAtCached(address _who, uint256 _blockNumber) external returns(uint256);

    /**
     * @notice Get the current vote power of `_who`.
     * @param _who The address to get voting power.
     * @return Current vote power of `_who`.
     */
    function votePowerOf(address _who) external view returns(uint256);

    /**
    * @notice Get the vote power of `_who` at block `_blockNumber`
    * @param _who The address to get voting power.
    * @param _blockNumber The block number at which to fetch.
    * @return Vote power of `_who` at `_blockNumber`.
    */
    function votePowerOfAt(address _who, uint256 _blockNumber) external view returns(uint256);

    /**
     * Return vote powers for several addresses in a batch.
     * @param _owners The list of addresses to fetch vote power of.
     * @param _blockNumber The block number at which to fetch.
     * @return A list of vote powers.
     */
    function batchVotePowerOfAt(
        address[] memory _owners,
        uint256 _blockNumber
    )
        external view returns(uint256[] memory);

    /**
    * @notice Get current delegated vote power `_from` delegator delegated `_to` delegatee.
    * @param _from Address of delegator
    * @param _to Address of delegatee
    * @param _balance The delegator's current balance
    * @return The delegated vote power.
    */
    function votePowerFromTo(
        address _from,
        address _to,
        uint256 _balance
    ) external view returns(uint256);

    /**
    * @notice Get delegated the vote power `_from` delegator delegated `_to` delegatee at `_blockNumber`.
    * @param _from Address of delegator
    * @param _to Address of delegatee
    * @param _balance The delegator's current balance
    * @param _blockNumber The block number at which to fetch.
    * @return The delegated vote power.
    */
    function votePowerFromToAt(
        address _from,
        address _to,
        uint256 _balance,
        uint _blockNumber
    ) external view returns(uint256);

    /**
     * @notice Compute the current undelegated vote power of `_owner`
     * @param _owner The address to get undelegated voting power.
     * @param _balance Owner's current balance
     * @return The unallocated vote power of `_owner`
     */
    function undelegatedVotePowerOf(
        address _owner,
        uint256 _balance
    ) external view returns(uint256);

    /**
     * @notice Get the undelegated vote power of `_owner` at given block.
     * @param _owner The address to get undelegated voting power.
     * @param _blockNumber The block number at which to fetch.
     * @return The undelegated vote power of `_owner` (= owner's own balance minus all delegations from owner)
     */
    function undelegatedVotePowerOfAt(
        address _owner,
        uint256 _balance,
        uint256 _blockNumber
    ) external view returns(uint256);

    /**
     * @notice Get the delegation mode for '_who'. This mode determines whether vote power is
     *  allocated by percentage or by explicit value.
     * @param _who The address to get delegation mode.
     * @return Delegation mode (NOTSET=0, PERCENTAGE=1, AMOUNT=2))
     */
    function delegationModeOf(address _who) external view returns (uint256);

    /**
    * @notice Get the vote power delegation `_delegateAddresses`
    *  and `pcts` of an `_owner`. Returned in two separate positional arrays.
    * @param _owner The address to get delegations.
    * @return _delegateAddresses Positional array of delegation addresses.
    * @return _bips Positional array of delegation percents specified in basis points (1/100 or 1 percent)
    * @return _count The number of delegates.
    * @return _delegationMode The mode of the delegation (NOTSET=0, PERCENTAGE=1, AMOUNT=2).
    */
    function delegatesOf(
        address _owner
    )
        external view
        returns (
            address[] memory _delegateAddresses,
            uint256[] memory _bips,
            uint256 _count,
            uint256 _delegationMode
        );

    /**
    * @notice Get the vote power delegation `delegationAddresses`
    *  and `pcts` of an `_owner`. Returned in two separate positional arrays.
    * @param _owner The address to get delegations.
    * @param _blockNumber The block for which we want to know the delegations.
    * @return _delegateAddresses Positional array of delegation addresses.
    * @return _bips Positional array of delegation percents specified in basis points (1/100 or 1 percent)
    * @return _count The number of delegates.
    * @return _delegationMode The mode of the delegation (NOTSET=0, PERCENTAGE=1, AMOUNT=2).
    */
    function delegatesOfAt(
        address _owner,
        uint256 _blockNumber
    )
        external view
        returns (
            address[] memory _delegateAddresses,
            uint256[] memory _bips,
            uint256 _count,
            uint256 _delegationMode
        );

    /**
     * The VPToken (or some other contract) that owns this VPContract.
     * All state changing methods may be called only from this address.
     * This is because original msg.sender is sent in `_from` parameter
     * and we must be sure that it cannot be faked by directly calling VPContract.
     * Owner token is also used in case of replacement to recover vote powers from balances.
     */
    function ownerToken() external view returns (IVPToken);

    /**
     * Return true if this IIVPContract is configured to be used as a replacement for other contract.
     * It means that vote powers are not necessarily correct at the initialization, therefore
     * every method that reads vote power must check whether it is initialized for that address and block.
     */
    function isReplacement() external view returns (bool);
}


// File contracts/token/interface/IIGovernanceVotePower.sol

//
pragma solidity 0.7.6;


interface IIGovernanceVotePower is IGovernanceVotePower {
    /**
     * Update vote powers when tokens are transfered.
     **/
    function updateAtTokenTransfer(
        address _from,
        address _to,
        uint256 _fromBalance,
        uint256 _toBalance,
        uint256 _amount
    ) external;

    /**
     * Set the cleanup block number.
     * Historic data for the blocks before `cleanupBlockNumber` can be erased,
     * history before that block should never be used since it can be inconsistent.
     * In particular, cleanup block number must be before current vote power block.
     * @param _blockNumber The new cleanup block number.
     */
    function setCleanupBlockNumber(uint256 _blockNumber) external;

    /**
     * Set the contract that is allowed to call history cleaning methods.
     */
    function setCleanerContract(address _cleanerContract) external;

   /**
    * @notice Get the token that this governance vote power contract belongs to.
    */
    function ownerToken() external view returns(IVPToken);
}


// File contracts/token/interface/IIVPToken.sol

//
pragma solidity 0.7.6;





interface IIVPToken is IVPToken, IICleanable {
    /**
     * Sets new governance vote power contract that allows token owners to participate in governance voting
     * and delegate governance vote power.
     */
    function setGovernanceVotePower(IIGovernanceVotePower _governanceVotePower) external;

    /**
    * @notice Get the total vote power at block `_blockNumber` using cache.
    *   It tries to read the cached value and if not found, reads the actual value and stores it in cache.
    *   Can only be used if `_blockNumber` is in the past, otherwise reverts.
    * @param _blockNumber The block number at which to fetch.
    * @return The total vote power at the block (sum of all accounts' vote powers).
    */
    function totalVotePowerAtCached(uint256 _blockNumber) external returns(uint256);

    /**
    * @notice Get the vote power of `_owner` at block `_blockNumber` using cache.
    *   It tries to read the cached value and if not found, reads the actual value and stores it in cache.
    *   Can only be used if _blockNumber is in the past, otherwise reverts.
    * @param _owner The address to get voting power.
    * @param _blockNumber The block number at which to fetch.
    * @return Vote power of `_owner` at `_blockNumber`.
    */
    function votePowerOfAtCached(address _owner, uint256 _blockNumber) external returns(uint256);

    /**
     * Return vote powers for several addresses in a batch.
     * @param _owners The list of addresses to fetch vote power of.
     * @param _blockNumber The block number at which to fetch.
     * @return A list of vote powers.
     */
    function batchVotePowerOfAt(
        address[] memory _owners,
        uint256 _blockNumber
    ) external view returns(uint256[] memory);
}


// File contracts/ftso/interface/IIFtso.sol

//
pragma solidity 0.7.6;



interface IIFtso is IFtso, IFtsoGenesis {

    /// function finalizePriceReveal
    /// called by reward manager only on correct timing.
    /// if price reveal period for epoch x ended. finalize.
    /// iterate list of price submissions
    /// find weighted median
    /// find adjucant 50% of price submissions.
    /// Allocate reward for any price submission which is same as a "winning" submission
    function finalizePriceEpoch(uint256 _epochId, bool _returnRewardData) external
        returns(
            address[] memory _eligibleAddresses,
            uint256[] memory _natWeights,
            uint256 _totalNatWeight
        );

    function averageFinalizePriceEpoch(uint256 _epochId) external;

    function forceFinalizePriceEpoch(uint256 _epochId) external;

    // activateFtso will be called by ftso manager once ftso is added
    // before this is done, FTSO can't run
    function activateFtso(
        uint256 _firstEpochStartTs,
        uint256 _epochPeriod,
        uint256 _revealPeriod
    ) external;

    function deactivateFtso() external;

    // update initial price and timestamp - only if not active
    function updateInitialPrice(uint256 _initialPriceUSD, uint256 _initialPriceTimestamp) external;

    function configureEpochs(
        uint256 _maxVotePowerNatThresholdFraction,
        uint256 _maxVotePowerAssetThresholdFraction,
        uint256 _lowAssetUSDThreshold,
        uint256 _highAssetUSDThreshold,
        uint256 _highAssetTurnoutThresholdBIPS,
        uint256 _lowNatTurnoutThresholdBIPS,
        address[] memory _trustedAddresses
    ) external;

    function setAsset(IIVPToken _asset) external;

    function setAssetFtsos(IIFtso[] memory _assetFtsos) external;

    // current vote power block will update per reward epoch.
    // the FTSO doesn't have notion of reward epochs.
    // reward manager only can set this data.
    function setVotePowerBlock(uint256 _blockNumber) external;

    function initializeCurrentEpochStateForReveal(uint256 _circulatingSupplyNat, bool _fallbackMode) external;

    /**
     * @notice Returns the FTSO asset
     * @dev Asset is null in case of multi-asset FTSO
     */
    function getAsset() external view returns (IIVPToken);

    /**
     * @notice Returns the Asset FTSOs
     * @dev AssetFtsos is not null only in case of multi-asset FTSO
     */
    function getAssetFtsos() external view returns (IIFtso[] memory);

    /**
     * @notice Returns current configuration of epoch state
     * @return _maxVotePowerNatThresholdFraction        High threshold for native token vote power per voter
     * @return _maxVotePowerAssetThresholdFraction      High threshold for asset vote power per voter
     * @return _lowAssetUSDThreshold            Threshold for low asset vote power
     * @return _highAssetUSDThreshold           Threshold for high asset vote power
     * @return _highAssetTurnoutThresholdBIPS   Threshold for high asset turnout
     * @return _lowNatTurnoutThresholdBIPS      Threshold for low nat turnout
     * @return _trustedAddresses                Trusted addresses - use their prices if low nat turnout is not achieved
     */
    function epochsConfiguration() external view
        returns (
            uint256 _maxVotePowerNatThresholdFraction,
            uint256 _maxVotePowerAssetThresholdFraction,
            uint256 _lowAssetUSDThreshold,
            uint256 _highAssetUSDThreshold,
            uint256 _highAssetTurnoutThresholdBIPS,
            uint256 _lowNatTurnoutThresholdBIPS,
            address[] memory _trustedAddresses
        );

    /**
     * @notice Returns parameters necessary for approximately replicating vote weighting.
     * @return _assets                  the list of Assets that are accounted in vote
     * @return _assetMultipliers        weight of each asset in (multiasset) ftso, mutiplied by TERA
     * @return _totalVotePowerNat       total native token vote power at block
     * @return _totalVotePowerAsset     total combined asset vote power at block
     * @return _assetWeightRatio        ratio of combined asset vp vs. native token vp (in BIPS)
     * @return _votePowerBlock          vote powewr block for given epoch
     */
    function getVoteWeightingParameters() external view
        returns (
            IIVPToken[] memory _assets,
            uint256[] memory _assetMultipliers,
            uint256 _totalVotePowerNat,
            uint256 _totalVotePowerAsset,
            uint256 _assetWeightRatio,
            uint256 _votePowerBlock
        );

    function wNat() external view returns (IIVPToken);
}


// File contracts/genesis/interface/IFtsoRegistryGenesis.sol

//
pragma solidity 0.7.6;

interface IFtsoRegistryGenesis {

    function getFtsos(uint256[] memory _indices) external view returns(IFtsoGenesis[] memory _ftsos);
}


// File contracts/userInterfaces/IPriceSubmitter.sol

//
pragma solidity 0.7.6;


interface IPriceSubmitter {
    /**
     * Event emitted when price hashes were submitted through PriceSubmitter.
     * @param submitter the address of the sender
     * @param epochId current price epoch id
     * @param ftsos array of ftsos that correspond to the indexes in call
     * @param hashes the submitted hashes
     * @param timestamp current block timestamp
     */
    event PriceHashesSubmitted(
        address indexed submitter,
        uint256 indexed epochId,
        IFtsoGenesis[] ftsos,
        bytes32[] hashes,
        uint256 timestamp
    );

    /**
     * Event emitted when prices were revealed through PriceSubmitter.
     * @param voter the address of the sender
     * @param epochId id of the epoch in which the price hash was submitted
     * @param ftsos array of ftsos that correspond to the indexes in the call
     * @param prices the submitted prices
     * @param timestamp current block timestamp
     */
    event PricesRevealed(
        address indexed voter,
        uint256 indexed epochId,
        IFtsoGenesis[] ftsos,
        uint256[] prices,
        uint256[] randoms,
        uint256 timestamp
    );

    /**
     * @notice Submits price hashes for current epoch
     * @param _epochId              Target epoch id to which hashes are submitted
     * @param _ftsoIndices          List of ftso indices
     * @param _hashes               List of hashed price and random number
     * @notice Emits PriceHashesSubmitted event
     */
    function submitPriceHashes(
        uint256 _epochId,
        uint256[] memory _ftsoIndices,
        bytes32[] memory _hashes
    ) external;

    /**
     * @notice Reveals submitted prices during epoch reveal period
     * @param _epochId              Id of the epoch in which the price hashes was submitted
     * @param _ftsoIndices          List of ftso indices
     * @param _prices               List of submitted prices in USD
     * @param _randoms              List of submitted random numbers
     * @notice The hash of _price and _random must be equal to the submitted hash
     * @notice Emits PricesRevealed event
     */
    function revealPrices(
        uint256 _epochId,
        uint256[] memory _ftsoIndices,
        uint256[] memory _prices,
        uint256[] memory _randoms
    ) external;

    /**
     * Returns bitmap of all ftso's for which `_voter` is allowed to submit prices/hashes.
     * If voter is allowed to vote for ftso at index (see *_FTSO_INDEX), the corrsponding
     * bit in the result will be 1.
     */
    function voterWhitelistBitmap(address _voter) external view returns (uint256);

    function getVoterWhitelister() external view returns (address);
    function getFtsoRegistry() external view returns (IFtsoRegistryGenesis);
    function getFtsoManager() external view returns (address);
}


// File contracts/userInterfaces/IFtsoManager.sol

//
pragma solidity 0.7.6;


interface IFtsoManager {

    event FtsoAdded(IIFtso ftso, bool add);
    event FallbackMode(bool fallbackMode);
    event FtsoFallbackMode(IIFtso ftso, bool fallbackMode);
    event RewardEpochFinalized(uint256 votepowerBlock, uint256 startBlock);
    event PriceEpochFinalized(address chosenFtso, uint256 rewardEpochId);
    event InitializingCurrentEpochStateForRevealFailed(IIFtso ftso, uint256 epochId);
    event FinalizingPriceEpochFailed(IIFtso ftso, uint256 epochId, IFtso.PriceFinalizationType failingType);
    event DistributingRewardsFailed(address ftso, uint256 epochId);

    function active() external view returns (bool);

    function getPriceSubmitter() external view returns (IPriceSubmitter);

    function getCurrentRewardEpoch() external view returns (uint256);

    function getRewardEpochVotePowerBlock(uint256 _rewardEpoch) external view returns (uint256);

    function getCurrentPriceEpochData() external view
        returns (
            uint256 _priceEpochId,
            uint256 _priceEpochStartTimestamp,
            uint256 _priceEpochEndTimestamp,
            uint256 _priceEpochRevealEndTimestamp,
            uint256 _currentTimestamp
        );

    function getFtsos() external view returns (IIFtso[] memory _ftsos);

    function getPriceEpochConfiguration() external view
        returns (
            uint256 _firstPriceEpochStartTs,
            uint256 _priceEpochDurationSeconds,
            uint256 _revealEpochDurationSeconds
        );

    function getFallbackMode() external view
        returns (
            bool _fallbackMode,
            IIFtso[] memory _ftsos,
            bool[] memory _ftsoInFallbackMode
        );
}


// File contracts/ftso/interface/IIFtsoManager.sol

//
pragma solidity 0.7.6;



interface IIFtsoManager is IFtsoManager {

    event ClosingExpiredRewardEpochFailed(uint256 _rewardEpoch);
    event CleanupBlockNumberManagerUnset();
    event CleanupBlockNumberManagerFailedForBlock(uint256 blockNumber);

    function activate() external;

    function setGovernanceParameters(
        uint256 _maxVotePowerNatThresholdFraction,
        uint256 _maxVotePowerAssetThresholdFraction,
        uint256 _lowAssetUSDThreshold,
        uint256 _highAssetUSDThreshold,
        uint256 _highAssetTurnoutThresholdBIPS,
        uint256 _lowNatTurnoutThresholdBIPS,
        uint256 _rewardExpiryOffsetSeconds,
        address[] memory _trustedAddresses
    ) external;

    function addFtso(IIFtso _ftso) external;

    function removeFtso(IIFtso _ftso) external;

    function replaceFtso(
        IIFtso _ftsoToRemove,
        IIFtso _ftsoToAdd,
        bool copyCurrentPrice,
        bool copyAssetOrAssetFtsos
    ) external;

    function setFtsoAsset(IIFtso _ftso, IIVPToken _asset) external;

    function setFtsoAssetFtsos(IIFtso _ftso, IIFtso[] memory _assetFtsos) external;

    function setFallbackMode(bool _fallbackMode) external;

    function setFtsoFallbackMode(IIFtso _ftso, bool _fallbackMode) external;
}


// File contracts/ftso/lib/FtsoManagerSettings.sol

//
pragma solidity 0.7.6;


/**
 * @title A library used for Ftso Manager settings management
 */
library FtsoManagerSettings {
    struct State {
        // struct holding settings related to FTSOs
        // configurable settings
        uint256 maxVotePowerNatThresholdFraction; // high threshold for native token vote power per voter
        uint256 maxVotePowerAssetThresholdFraction; // high threshold for asset vote power per voter
        uint256 lowAssetUSDThreshold; // threshold for low asset vote power (in scaled USD)
        uint256 highAssetUSDThreshold; // threshold for high asset vote power (in scaled USD)
        uint256 highAssetTurnoutThresholdBIPS; // threshold for high asset turnout (in BIPS)
        // actual vote power in (W)NATs / total native token circulating supply (in BIPS)
        uint256 lowNatTurnoutThresholdBIPS;
        uint256 rewardExpiryOffsetSeconds; // Reward epoch closed earlier than
                                           //block.timestamp - rewardExpiryOffsetSeconds expire
        address[] trustedAddresses; //trusted addresses will be used as a fallback mechanism for setting the price
        bool changed;
        bool initialized;
    }

    function _setState (
        State storage _state,
        uint256 _maxVotePowerNatThresholdFraction,
        uint256 _maxVotePowerAssetThresholdFraction,
        uint256 _lowAssetUSDThreshold,
        uint256 _highAssetUSDThreshold,
        uint256 _highAssetTurnoutThresholdBIPS,
        uint256 _lowNatTurnoutThresholdBIPS,
        uint256 _rewardExpiryOffsetSeconds,
        address[] memory _trustedAddresses
    )
        internal
    {
        if (_state.maxVotePowerNatThresholdFraction != _maxVotePowerNatThresholdFraction) {
            _state.changed = true;
            _state.maxVotePowerNatThresholdFraction = _maxVotePowerNatThresholdFraction;
        }
        if (_state.maxVotePowerAssetThresholdFraction != _maxVotePowerAssetThresholdFraction) {
            _state.changed = true;
            _state.maxVotePowerAssetThresholdFraction = _maxVotePowerAssetThresholdFraction;
        }
        if (_state.lowAssetUSDThreshold != _lowAssetUSDThreshold) {
            _state.changed = true;
            _state.lowAssetUSDThreshold = _lowAssetUSDThreshold;
        }
        if (_state.highAssetUSDThreshold != _highAssetUSDThreshold) {
            _state.changed = true;
            _state.highAssetUSDThreshold = _highAssetUSDThreshold;
        }
        if (_state.highAssetTurnoutThresholdBIPS != _highAssetTurnoutThresholdBIPS) {
            _state.changed = true;
            _state.highAssetTurnoutThresholdBIPS = _highAssetTurnoutThresholdBIPS;
        }
        if (_state.lowNatTurnoutThresholdBIPS != _lowNatTurnoutThresholdBIPS) {
            _state.changed = true;
            _state.lowNatTurnoutThresholdBIPS = _lowNatTurnoutThresholdBIPS;
        }
        if (_state.rewardExpiryOffsetSeconds != _rewardExpiryOffsetSeconds) {
            _state.changed = true;
            _state.rewardExpiryOffsetSeconds = _rewardExpiryOffsetSeconds;
        }
        if (_state.trustedAddresses.length != _trustedAddresses.length) {
            _state.trustedAddresses = _trustedAddresses;
            _state.changed = true;
        } else {
            for (uint i = 0; i < _trustedAddresses.length; i++) {
                if (_state.trustedAddresses[i] != _trustedAddresses[i]) {
                    _state.changed = true;
                    _state.trustedAddresses[i] = _trustedAddresses[i];
                }
            }
        }
        _state.initialized = true;
    }
}


// File contracts/governance/implementation/GovernedBase.sol

//
pragma solidity 0.7.6;


/**
 * @title Governed Base
 * @notice This abstract base class defines behaviors for a governed contract.
 * @dev This class is abstract so that specific behaviors can be defined for the constructor.
 *   Contracts should not be left ungoverned, but not all contract will have a constructor
 *   (for example those pre-defined in genesis).
 **/
abstract contract GovernedBase {
    address public governance;
    address public proposedGovernance;
    bool private initialised;

    event GovernanceProposed(address proposedGovernance);
    event GovernanceUpdated (address oldGovernance, address newGoveranance);

    modifier onlyGovernance () {
        require (msg.sender == governance, "only governance");
        _;
    }

    constructor(address _governance) {
        if (_governance != address(0)) {
            initialise(_governance);
        }
    }

    /**
     * @notice First of a two step process for turning over governance to another address.
     * @param _governance The address to propose to receive governance role.
     * @dev Must hold governance to propose another address.
     */
    function proposeGovernance(address _governance) external onlyGovernance {
        proposedGovernance = _governance;
        emit GovernanceProposed(_governance);
    }

    /**
     * @notice Once proposed, claimant can claim the governance role as the second of a two-step process.
     */
    function claimGovernance() external {
        require(msg.sender == proposedGovernance, "not claimaint");

        emit GovernanceUpdated(governance, proposedGovernance);
        governance = proposedGovernance;
        proposedGovernance = address(0);
    }

    /**
     * @notice In a one-step process, turn over governance to another address.
     * @dev Must hold governance to transfer.
     */
    function transferGovernance(address _governance) external onlyGovernance {
        emit GovernanceUpdated(governance, _governance);
        governance = _governance;
        proposedGovernance = address(0);
    }

    /**
     * @notice Initialize the governance address if not first initialized.
     */
    function initialise(address _governance) public virtual {
        require(initialised == false, "initialised != false");

        initialised = true;
        emit GovernanceUpdated(governance, _governance);
        governance = _governance;
        proposedGovernance = address(0);
    }
}


// File contracts/governance/implementation/GovernedAtGenesis.sol

//
pragma solidity 0.7.6;

/**
 * @title Governed At Genesis
 * @dev This contract enforces a fixed governance address when the constructor
 *  is not executed on a contract (for instance when directly loaded to the genesis block).
 *  This is required to fix governance on a contract when the network starts, at such point
 *  where theoretically no accounts yet exist, and leaving it ungoverned could result in a race
 *  to claim governance by an unauthorized address.
 **/
contract GovernedAtGenesis is GovernedBase {
    constructor(address _governance) GovernedBase(_governance) { }

    /**
     * @notice Set governance to a fixed address when constructor is not called.
     **/
    function initialiseFixedAddress() public virtual returns (address) {
        address governanceAddress = address(0xfffEc6C83c8BF5c3F4AE0cCF8c45CE20E4560BD7);

        super.initialise(governanceAddress);
        return governanceAddress;
    }

    /**
     * @notice Disallow initialise to be called
     * @param _governance The governance address for initial claiming
     **/
    // solhint-disable-next-line no-unused-vars
    function initialise(address _governance) public override pure {
        assert(false);
    }
}


// File contracts/genesis/interface/IInflationGenesis.sol

//
pragma solidity 0.7.6;


interface IInflationGenesis {
    /**
     * @notice Receive newly minted native tokens from the FlareDaemon.
     * @dev Assume that the amount received will be >= last topup requested across all services.
     *   If there is not enough balance sent to cover the topup request, expect library method will revert.
     *   Also assume that any balance received greater than the topup request calculated
     *   came from self-destructor sending a balance to this contract.
     */
    function receiveMinting() external payable;
}


// File contracts/genesis/interface/IFlareDaemonize.sol

//
pragma solidity 0.7.6;


/// Any contracts that want to recieve a trigger from Flare daemon should
///     implement IFlareDaemonize
interface IFlareDaemonize {

    /// Implement this function for recieving a trigger from FlareDaemon.
    function daemonize() external returns (bool);

    /// This function will be called after an error is caught in daemonize().
    /// It will switch the contract to a simpler fallback mode, which hopefully works when full mode doesn't.
    /// Not every contract needs to support fallback mode (FtsoManager does), so this method may be empty.
    /// Switching back to normal mode is left to the contract (typically a governed method call).
    /// This function may be called due to low-gas error, so it shouldn't use more than ~30.000 gas.
    /// @return true if switched to fallback mode, false if already in fallback mode or if falback not supported
    function switchToFallbackMode() external returns (bool);
}


// File @openzeppelin/contracts/math/[email protected]

//

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) return (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}


// File contracts/utils/implementation/SafePct.sol

//

pragma solidity 0.7.6;

/**
 * @dev Compute percentages safely without phantom overflows.
 *
 * Intermediate operations can overflow even when the result will always
 * fit into computed type. Developers usually
 * assume that overflows raise errors. `SafePct` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafePct {
    using SafeMath for uint256;
    /**
     * Requirements:
     *
     * - intermediate operations must revert on overflow
     */
    function mulDiv(uint256 x, uint256 y, uint256 z) internal pure returns (uint256) {
        require(z > 0, "Division by zero");

        if (x == 0) return 0;
        uint256 xy = x * y;
        if (xy / x == y) { // no overflow happened - same as in SafeMath mul
            return xy / z;
        }

        //slither-disable-next-line divide-before-multiply
        uint256 a = x / z;
        uint256 b = x % z; // x = a * z + b

        //slither-disable-next-line divide-before-multiply
        uint256 c = y / z;
        uint256 d = y % z; // y = c * z + d

        return (a.mul(c).mul(z)).add(a.mul(d)).add(b.mul(c)).add(b.mul(d).div(z));
    }
}


// File contracts/genesis/implementation/FlareDaemon.sol

//
// WARNING, WARNING, WARNING
// If you modify this contract, you need to re-install the binary into the validator
// genesis file for the chain you wish to run. See ./docs/CompilingContracts.md for more information.
// You have been warned. That is all.
pragma solidity 0.7.6;





/**
 * @title Flare Daemon contract
 * @notice This contract exists to coordinate regular daemon-like polling of contracts
 *   that are registered to receive said polling. The trigger method is called by the
 *   validator right at the end of block state transition.
 */
contract FlareDaemon is GovernedAtGenesis {
    using SafeMath for uint256;
    using SafePct for uint256;

    //====================================================================
    // Data Structures
    //====================================================================
    struct DaemonizedError {
        uint192 lastErrorBlock;
        uint64 numErrors;
        address fromContract;
        uint64 errorTypeIndex;
        string errorMessage;
    }

    struct LastErrorData {
        uint192 totalDaemonizedErrors;
        uint64 lastErrorTypeIndex;
    }

    struct Registration {
        IFlareDaemonize daemonizedContract;
        uint256 gasLimit;
    }

    string internal constant ERR_OUT_OF_BALANCE = "out of balance";
    string internal constant ERR_NOT_INFLATION = "not inflation";
    string internal constant ERR_TOO_MANY = "too many";
    string internal constant ERR_TOO_BIG = "too big";
    string internal constant ERR_TOO_OFTEN = "too often";
    string internal constant ERR_INFLATION_ZERO = "inflation zero";
    string internal constant ERR_BLOCK_NUMBER_SMALL = "block.number small";
    string internal constant INDEX_TOO_HIGH = "start index high";
    string internal constant UPDATE_GAP_TOO_SHORT = "time gap too short";
    string internal constant MAX_MINT_TOO_HIGH = "max mint too high";
    string internal constant MAX_MINT_IS_ZERO = "max mint is zero";
    string internal constant ERR_DUPLICATE_ADDRESS = "dup address";
    string internal constant ERR_ADDRESS_ZERO = "address zero";
    string internal constant ERR_OUT_OF_GAS = "out of gas";
    string internal constant ERR_INFLATION_MINT_RECEIVE_FAIL = "unknown error. receiveMinting";

    uint256 internal constant MAX_DAEMONIZE_CONTRACTS = 10;
    // Initial max mint request - 50 million native token
    uint256 internal constant MAX_MINTING_REQUEST_DEFAULT = 50000000 ether;
    // How often can inflation request minting from the validator - 23 hours constant
    uint256 internal constant MAX_MINTING_FREQUENCY_SEC = 23 hours;
    // How often can the maximal mint request amount be updated
    uint256 internal constant MAX_MINTING_REQUEST_FREQUENCY_SEC = 24 hours;
    // By how much can the maximum be increased (as a percentage of the previous maximum)
    uint256 internal constant MAX_MINTING_REQUEST_INCREASE_PERCENT = 110;
    // upper estimate of gas needed after error occurs in call to daemonizedContract.daemonize()
    uint256 internal constant MIN_GAS_LEFT_AFTER_DAEMONIZE = 300000;
    // lower estimate for gas needed for daemonize() call in trigger
    uint256 internal constant MIN_GAS_FOR_DAEMONIZE_CALL = 5000;

    IInflationGenesis public inflation;
    uint256 public systemLastTriggeredAt;
    uint256 public totalMintingRequestedWei;
    uint256 public totalMintingReceivedWei;
    uint256 public totalMintingWithdrawnWei;
    uint256 public totalSelfDestructReceivedWei;
    uint256 public maxMintingRequestWei;
    uint256 public lastMintRequestTs;
    uint256 public lastUpdateMaxMintRequestTs;
    LastErrorData public errorData;
    uint256 public blockHoldoff;

    uint256 private lastBalance;
    uint256 private expectedMintRequest;
    bool private initialized;

    // track deamonized contracts
    IFlareDaemonize[] internal daemonizeContracts;
    mapping (IFlareDaemonize => uint256) internal gasLimits;
    mapping (IFlareDaemonize => uint256) internal blockHoldoffsRemaining;

    // track daemonize errors
    mapping(bytes32 => DaemonizedError) internal daemonizedErrors;
    bytes32 [] internal daemonizeErrorHashes;

    event ContractDaemonized(address theContract, uint256 gasConsumed);
    event ContractDaemonizeErrored(address theContract, uint256 atBlock, string theMessage, uint256 gasConsumed);
    event ContractHeldOff(address theContract, uint256 blockHoldoffsRemaining);
    event ContractsSkippedOutOfGas(uint256 numberOfSkippedConstracts);
    event MintingRequestReceived(uint256 amountWei);
    event MintingRequestTriggered(uint256 amountWei);
    event MintingReceived(uint256 amountWei);
    event MintingWithdrawn(uint256 amountWei);
    event RegistrationUpdated(IFlareDaemonize theContract, bool add);
    event SelfDestructReceived(uint256 amountWei);
    event InflationSet(IInflationGenesis theNewContract, IInflationGenesis theOldContract);

    /**
     * @dev As there is not a constructor, this modifier exists to make sure the inflation
     *   contract is set for methods that require it.
     */
    modifier inflationSet {
        // Don't revert...just report.
        if (address(inflation) == address(0)) {
            addDaemonizeError(address(this), ERR_INFLATION_ZERO, 0);
        }
        _;
    }

    /**
     * @dev This modifier ensures that this contract's balance matches the expected balance.
     */
    modifier mustBalance {
        _;
        // We should be in balance - don't revert, just report...
        uint256 contractBalanceExpected = getExpectedBalance();
        if (contractBalanceExpected != address(this).balance) {
            addDaemonizeError(address(this), ERR_OUT_OF_BALANCE, 0);
        }
    }

    /**
     * @dev Access control to protect methods to allow only minters to call select methods
     *   (like transferring balance out).
     */
    modifier onlyInflation (address _inflation) {
        require (address(inflation) == _inflation, ERR_NOT_INFLATION);
        _;
    }

    /**
     * @dev Access control to protect trigger() method.
     * Please note that the sender address is the same as deployed FlareDaemon address in this case.
     */
    modifier onlySystemTrigger {
        require (msg.sender == 0x1000000000000000000000000000000000000002);
        _;
    }

    //====================================================================
    // Constructor for pre-compiled code
    //====================================================================

    /**
     * @dev This constructor should contain no code as this contract is pre-loaded into the genesis block.
     *   The super constructor is called for testing convenience.
     */
    constructor() GovernedAtGenesis(address(0)) {
        /* empty block */
    }

    //====================================================================
    // Functions
    //====================================================================

    /**
     * @notice Register contracts to be polled by the daemon process.
     * @param _registrations    An array of Registration structures of IFlareDaemonize contracts to daemonize
     *                          and gas limits for each contract.
     * @dev A gas limit of zero will set no limit for the contract but the validator has an overall
     *   limit for the trigger() method.
     * @dev If any registrations already exist, they will be unregistered.
     * @dev Contracts will be daemonized in the order in which presented via the _registrations array.
     */
    function registerToDaemonize(Registration[] calldata _registrations) external onlyGovernance {
        // Make sure there are not too many contracts to register.
        uint256 registrationsLength = _registrations.length;
        require(registrationsLength <= MAX_DAEMONIZE_CONTRACTS, ERR_TOO_MANY);

        // Unregister everything first
        _unregisterAll();

        // Loop over all contracts to register
        for (uint256 registrationIndex = 0; registrationIndex < registrationsLength; registrationIndex++) {
            // Address cannot be zero
            require(address(_registrations[registrationIndex].daemonizedContract) != address(0), ERR_ADDRESS_ZERO);

            uint256 daemonizeContractsLength = daemonizeContracts.length;
            // Make sure no dups...yes, inefficient. Registration should not be done often.
            for (uint256 i = 0; i < daemonizeContractsLength; i++) {
                require(_registrations[registrationIndex].daemonizedContract != daemonizeContracts[i],
                    ERR_DUPLICATE_ADDRESS); // already registered
            }
            // Store off the registered contract to daemonize, in the order presented.
            daemonizeContracts.push(_registrations[registrationIndex].daemonizedContract);
            // Record the gas limit for the contract.
            gasLimits[_registrations[registrationIndex].daemonizedContract] =
                _registrations[registrationIndex].gasLimit;
            // Clear any blocks being held off for the given contract, if any. Contracts may be re-presented
            // if only order is being modified, for example.
            blockHoldoffsRemaining[_registrations[registrationIndex].daemonizedContract] = 0;
            emit RegistrationUpdated (_registrations[registrationIndex].daemonizedContract, true);
        }
    }

    /**
     * @notice Queue up a minting request to send to the validator at next trigger.
     * @param _amountWei    The amount to mint.
     */
    function requestMinting(uint256 _amountWei) external onlyInflation(msg.sender) {
        require(_amountWei <= maxMintingRequestWei, ERR_TOO_BIG);
        require(_getNextMintRequestAllowedTs() < block.timestamp, ERR_TOO_OFTEN);
        if (_amountWei > 0) {
            lastMintRequestTs = block.timestamp;
            totalMintingRequestedWei = totalMintingRequestedWei.add(_amountWei);
            emit MintingRequestReceived(_amountWei);
        }
    }

    /**
     * @notice Set number of blocks that must elapse before a daemonized contract exceeding gas limit can have
     *   its daemonize() method called again.
     * @param _blockHoldoff    The number of blocks to holdoff.
     */
    function setBlockHoldoff(uint256 _blockHoldoff) external onlyGovernance {
        blockHoldoff = _blockHoldoff;
    }

    /**
     * @notice Set limit on how much can be minted per request.
     * @param _maxMintingRequestWei    The request maximum in wei.
     * @notice this number can't be udated too often
     */
    function setMaxMintingRequest(uint256 _maxMintingRequestWei) external onlyGovernance {
        // make sure increase amount is reasonable
        require(
            _maxMintingRequestWei <= (maxMintingRequestWei.mulDiv(MAX_MINTING_REQUEST_INCREASE_PERCENT,100)),
            MAX_MINT_TOO_HIGH
        );
        require(_maxMintingRequestWei > 0, MAX_MINT_IS_ZERO);
        // make sure enough time since last update
        require(
            block.timestamp > lastUpdateMaxMintRequestTs + MAX_MINTING_REQUEST_FREQUENCY_SEC,
            UPDATE_GAP_TOO_SHORT
        );

        maxMintingRequestWei = _maxMintingRequestWei;
        lastUpdateMaxMintRequestTs = block.timestamp;
    }

    /**
     * @notice Sets the inflation contract, which will receive minted inflation funds for funding to
     *   rewarding contracts.
     * @param _inflation   The inflation contract.
     */
    function setInflation(IInflationGenesis _inflation) external onlyGovernance {
        require(address(_inflation) != address(0), ERR_INFLATION_ZERO);
        emit InflationSet(_inflation, inflation);
        inflation = _inflation;
        if (maxMintingRequestWei == 0) {
            maxMintingRequestWei = MAX_MINTING_REQUEST_DEFAULT;
        }
    }

    /**
     * @notice The meat of this contract. Poll all registered contracts, calling the daemonize() method of each,
     *   in the order in which registered.
     * @return  _toMintWei     Return the amount to mint back to the validator. The asked for balance will show
     *                          up in the next block (it is actually added right before this block's state transition,
     *                          but well after this method call will see it.)
     * @dev This method watches for balances being added to this contract and handles appropriately - legit
     *   mint requests as made via requestMinting, and also self-destruct sending to this contract, should
     *   it happen for some reason.
     */
    //slither-disable-next-line reentrancy-eth      // method protected by reentrancy guard (see comment below)
    function trigger() external virtual inflationSet mustBalance onlySystemTrigger returns (uint256 _toMintWei) {
        return triggerInternal();
    }

    /**
     * @notice Unregister all contracts from being polled by the daemon process.
     */
    function unregisterAll() external onlyGovernance {
        _unregisterAll();
    }

    function getDaemonizedContractsData() external view
        returns(
            IFlareDaemonize[] memory _daemonizeContracts,
            uint256[] memory _gasLimits,
            uint256[] memory _blockHoldoffsRemaining
        )
    {
        uint256 len = daemonizeContracts.length;
        _daemonizeContracts = new IFlareDaemonize[](len);
        _gasLimits = new uint256[](len);
        _blockHoldoffsRemaining = new uint256[](len);

        for (uint256 i; i < len; i++) {
            IFlareDaemonize daemonizeContract = daemonizeContracts[i];
            _daemonizeContracts[i] = daemonizeContract;
            _gasLimits[i] = gasLimits[daemonizeContract];
            _blockHoldoffsRemaining[i] = blockHoldoffsRemaining[daemonizeContract];
        }
    }

    function getNextMintRequestAllowedTs() external view returns(uint256) {
        return _getNextMintRequestAllowedTs();
    }

    function showLastDaemonizedError () external view
        returns(
            uint256[] memory _lastErrorBlock,
            uint256[] memory _numErrors,
            string[] memory _errorString,
            address[] memory _erroringContract,
            uint256 _totalDaemonizedErrors
        )
    {
        return showDaemonizedErrors(errorData.lastErrorTypeIndex, 1);
    }

    /**
     * @notice Set the governance address to a hard-coded known address.
     * @dev This should be done at contract deployment time.
     * @return The governance address.
     */
    function initialiseFixedAddress() public override returns(address) {
        if (!initialized) {
            initialized = true;
            address governanceAddress = super.initialiseFixedAddress();
            return governanceAddress;
        } else {
            return governance;
        }
    }

    function showDaemonizedErrors (uint startIndex, uint numErrorTypesToShow) public view
        returns(
            uint256[] memory _lastErrorBlock,
            uint256[] memory _numErrors,
            string[] memory _errorString,
            address[] memory _erroringContract,
            uint256 _totalDaemonizedErrors
        )
    {
        require(startIndex < daemonizeErrorHashes.length, INDEX_TOO_HIGH);
        uint256 numReportElements =
            daemonizeErrorHashes.length >= startIndex + numErrorTypesToShow ?
            numErrorTypesToShow :
            daemonizeErrorHashes.length - startIndex;

        _lastErrorBlock = new uint256[] (numReportElements);
        _numErrors = new uint256[] (numReportElements);
        _errorString = new string[] (numReportElements);
        _erroringContract = new address[] (numReportElements);

        // we have error data error type.
        // error type is hash(error_string, source contract)
        // per error type we report how many times it happened.
        // what was last block it happened.
        // what is the error string.
        // what is the erroring contract
        for (uint i = 0; i < numReportElements; i++) {
            bytes32 hash = daemonizeErrorHashes[startIndex + i];

            _lastErrorBlock[i] = daemonizedErrors[hash].lastErrorBlock;
            _numErrors[i] = daemonizedErrors[hash].numErrors;
            _errorString[i] = daemonizedErrors[hash].errorMessage;
            _erroringContract[i] = daemonizedErrors[hash].fromContract;
        }
        _totalDaemonizedErrors = errorData.totalDaemonizedErrors;
    }

    /**
     * @notice Implementation of the trigger() method. The external wrapper has extra guard for msg.sender.
     */
    //slither-disable-next-line reentrancy-eth      // method protected by reentrancy guard (see comment below)
    function triggerInternal() internal returns (uint256 _toMintWei) {
        // only one trigger() call per block allowed
        // this also serves as reentrancy guard, since any re-entry will happen in the same block
        if(block.number == systemLastTriggeredAt) return 0;
        systemLastTriggeredAt = block.number;

        uint256 currentBalance = address(this).balance;

        // Did the validator or a self-destructor conjure some native token?
        if (currentBalance > lastBalance) {
            uint256 balanceExpected = lastBalance.add(expectedMintRequest);
            // Did we get what was last asked for?
            if (currentBalance == balanceExpected) {
                // Yes, so assume it all came from the validator.
                uint256 minted = expectedMintRequest;
                totalMintingReceivedWei = totalMintingReceivedWei.add(minted);
                emit MintingReceived(minted);
                //slither-disable-next-line arbitrary-send          // only sent to inflation, set by governance
                try inflation.receiveMinting{ value: minted }() {
                    totalMintingWithdrawnWei = totalMintingWithdrawnWei.add(minted);
                    emit MintingWithdrawn(minted);
                } catch Error(string memory message) {
                    addDaemonizeError(address(this), message, 0);
                } catch {
                    addDaemonizeError(address(this), ERR_INFLATION_MINT_RECEIVE_FAIL, 0);
                }
            } else if (currentBalance < balanceExpected) {
                // No, and if less, there are two possibilities: 1) the validator did not
                // send us what we asked (not possible unless a bug), or 2) an attacker
                // sent us something in between a request and a mint. Assume 2.
                uint256 selfDestructReceived = currentBalance.sub(lastBalance);
                totalSelfDestructReceivedWei = totalSelfDestructReceivedWei.add(selfDestructReceived);
                emit SelfDestructReceived(selfDestructReceived);
            } else {
                // No, so assume we got a minting request (perhaps zero...does not matter)
                // and some self-destruct proceeds (unlikely but can happen).
                totalMintingReceivedWei = totalMintingReceivedWei.add(expectedMintRequest);
                uint256 selfDestructReceived = currentBalance.sub(lastBalance).sub(expectedMintRequest);
                totalSelfDestructReceivedWei = totalSelfDestructReceivedWei.add(selfDestructReceived);
                emit MintingReceived(expectedMintRequest);
                emit SelfDestructReceived(selfDestructReceived);
                //slither-disable-next-line arbitrary-send          // only sent to inflation, set by governance
                try inflation.receiveMinting{ value: expectedMintRequest }() {
                    totalMintingWithdrawnWei = totalMintingWithdrawnWei.add(expectedMintRequest);
                    emit MintingWithdrawn(expectedMintRequest);
                } catch Error(string memory message) {
                    addDaemonizeError(address(this), message, 0);
                } catch {
                    addDaemonizeError(address(this), ERR_INFLATION_MINT_RECEIVE_FAIL, 0);
                }
            }
        }

        uint256 len = daemonizeContracts.length;

        // Perform trigger operations here
        for (uint256 i = 0; i < len; i++) {
            IFlareDaemonize daemonizedContract = daemonizeContracts[i];
            uint256 blockHoldoffRemainingForContract = blockHoldoffsRemaining[daemonizedContract];
            if (blockHoldoffRemainingForContract > 0) {
                blockHoldoffsRemaining[daemonizedContract] = blockHoldoffRemainingForContract - 1;
                emit ContractHeldOff(address(daemonizedContract), blockHoldoffRemainingForContract);
            } else {
                // Figure out what gas to limit call by
                uint256 gasLimit = gasLimits[daemonizedContract];
                uint256 startGas = gasleft();
                // End loop if there isn't enough gas left for any daemonize call
                if (startGas < MIN_GAS_LEFT_AFTER_DAEMONIZE + MIN_GAS_FOR_DAEMONIZE_CALL) {
                    emit ContractsSkippedOutOfGas(len - i);
                    break;
                }
                // Calculate the gas limit for the next call
                uint256 useGas = startGas - MIN_GAS_LEFT_AFTER_DAEMONIZE;
                if (gasLimit > 0 && gasLimit < useGas) {
                    useGas = gasLimit;
                }
                // Run daemonize for the contract, consume errors, and record
                try daemonizedContract.daemonize{gas: useGas}() {
                    emit ContractDaemonized(address(daemonizedContract), (startGas - gasleft()));
                // Catch all requires with messages
                } catch Error(string memory message) {
                    addDaemonizeError(address(daemonizedContract), message, (startGas - gasleft()));
                    daemonizedContract.switchToFallbackMode();
                // Catch everything else...out of gas, div by zero, asserts, etc.
                } catch {
                    uint256 endGas = gasleft();
                    // Interpret out of gas errors
                    if (gasLimit > 0 && startGas.sub(endGas) >= gasLimit) {
                        addDaemonizeError(address(daemonizedContract), ERR_OUT_OF_GAS, (startGas - endGas));
                        // When daemonize() fails with out-of-gas, try to fix it in two steps:
                        // 1) try to switch contract to fallback mode
                        //    (to allow the contract's daemonize() to recover in fallback mode in next block)
                        // 2) if constract is already in fallback mode or fallback mode is not supported
                        //    (switchToFallbackMode() returns false), start the holdoff for this contract
                        bool switchedToFallback = daemonizedContract.switchToFallbackMode();
                        if (!switchedToFallback) {
                            blockHoldoffsRemaining[daemonizedContract] = blockHoldoff;
                        }
                    } else {
                        // Don't know error cause...just log it as unknown
                        addDaemonizeError(address(daemonizedContract), "unknown", (startGas - endGas));
                        daemonizedContract.switchToFallbackMode();
                    }
                }
            }
        }

        // Get any requested minting and return to validator
        _toMintWei = getPendingMintRequest();
        if (_toMintWei > 0) {
            expectedMintRequest = _toMintWei;
            emit MintingRequestTriggered(_toMintWei);
        } else {
            expectedMintRequest = 0;
        }

        lastBalance = address(this).balance;
    }

    function addDaemonizeError(address daemonizedContract, string memory message, uint256 gasConsumed) internal {
        bytes32 errorStringHash = keccak256(abi.encode(daemonizedContract, message));

        DaemonizedError storage daemonizedError = daemonizedErrors[errorStringHash];
        if (daemonizedError.numErrors == 0) {
            // first time we recieve this error string.
            daemonizeErrorHashes.push(errorStringHash);
            daemonizedError.fromContract = daemonizedContract;
            // limit message length to fit in fixed number of storage words (to make gas usage predictable)
            daemonizedError.errorMessage = truncateString(message, 64);
            daemonizedError.errorTypeIndex = uint64(daemonizeErrorHashes.length - 1);
        }
        daemonizedError.numErrors += 1;
        daemonizedError.lastErrorBlock = uint192(block.number);
        emit ContractDaemonizeErrored(daemonizedContract, block.number, message, gasConsumed);

        errorData.totalDaemonizedErrors += 1;
        errorData.lastErrorTypeIndex = daemonizedError.errorTypeIndex;
    }

    /**
     * @notice Unregister all contracts from being polled by the daemon process.
     */
    function _unregisterAll() private {

        uint256 len = daemonizeContracts.length;

        for (uint256 i = 0; i < len; i++) {
            IFlareDaemonize daemonizedContract = daemonizeContracts[daemonizeContracts.length - 1];
            daemonizeContracts.pop();
            emit RegistrationUpdated (daemonizedContract, false);
        }
    }

    /**
     * @notice Net totals to obtain the expected balance of the contract.
     */
    function getExpectedBalance() private view returns(uint256 _balanceExpectedWei) {
        _balanceExpectedWei = totalMintingReceivedWei.
            sub(totalMintingWithdrawnWei).
            add(totalSelfDestructReceivedWei);
    }

    /**
     * @notice Net total received from total requested.
     */
    function getPendingMintRequest() private view returns(uint256 _mintRequestPendingWei) {
        _mintRequestPendingWei = totalMintingRequestedWei.sub(totalMintingReceivedWei);
    }


    function _getNextMintRequestAllowedTs() internal view returns (uint256) {
        return (lastMintRequestTs + MAX_MINTING_FREQUENCY_SEC);
    }

    function truncateString(string memory _str, uint256 _maxlength) private pure returns (string memory) {
        bytes memory strbytes = bytes(_str);
        if (strbytes.length <= _maxlength) {
            return _str;
        }
        bytes memory result = new bytes(_maxlength);
        for (uint256 i = 0; i < _maxlength; i++) {
            result[i] = strbytes[i];
        }
        return string(result);
    }
}


// File contracts/genesis/interface/IIPriceSubmitter.sol

//
pragma solidity 0.7.6;

interface IIPriceSubmitter is IPriceSubmitter {

    /**
     * Sets ftso registry, voter whitelist and ftso manager contracts.
     * Only governance can call this method.
     * If replacing the registry or the whitelist and the old one is not empty, make sure to replicate the state,
     * otherwise internal whitelist bitmaps won't match.
     */
    function setContractAddresses(
        IFtsoRegistryGenesis _ftsoRegistry,
        address _voterWhitelister,
        address _ftsoManager
    ) external;

    /**
     * Set trusted addresses that are always allowed to submit and reveal.
     * Only ftso manager can call this method.
     */
    function setTrustedAddresses(address[] memory _trustedAddresses) external;

    /**
     * Called from whitelister when new voter has been whitelisted.
     */
    function voterWhitelisted(address _voter, uint256 _ftsoIndex) external;

    /**
     * Called from whitelister when one or more voters have been removed.
     */
    function votersRemovedFromWhitelist(address[] memory _voters, uint256 _ftsoIndex) external;

    /**
     * Returns a list of trusted addresses that are always allowed to submit and reveal.
     */
    function getTrustedAddresses() external view returns (address[] memory);
}


// File contracts/governance/implementation/Governed.sol

//
pragma solidity 0.7.6;

/**
 * @title Governed
 * @dev For deployed, governed contracts, enforce a non-zero address at create time.
 **/
contract Governed is GovernedBase {
    constructor(address _governance) GovernedBase(_governance) {
        require(_governance != address(0), "_governance zero");
    }
}


// File contracts/inflation/interface/IISupply.sol

//
pragma solidity 0.7.6;


interface IISupply {

    /**
     * @notice Sets inflation contract. Only governance can call this method.
     */
    function setInflation(address _inflation) external;

    /**
     * @notice Updates authorized inflation and circulating supply - emits event if error
     * @param _inflationAuthorizedWei               Authorized inflation
     * @dev Also updates the burn address amount
    */
    function updateAuthorizedInflationAndCirculatingSupply(uint256 _inflationAuthorizedWei) external;

    /**
     * @notice Get approximate circulating supply for given block number from cache - only past block
     * @param _blockNumber                          Block number
     * @return _circulatingSupplyWei Return approximate circulating supply for last known block <= _blockNumber
    */
    function getCirculatingSupplyAtCached(uint256 _blockNumber) external returns(uint256 _circulatingSupplyWei);

    /**
     * @notice Get approximate circulating supply for given block number
     * @param _blockNumber                          Block number
     * @return _circulatingSupplyWei Return approximate circulating supply for last known block <= _blockNumber
    */
    function getCirculatingSupplyAt(uint256 _blockNumber) external view returns(uint256 _circulatingSupplyWei);

    /**
     * @notice Get total inflatable balance (initial genesis amount + total authorized inflation)
     * @return _inflatableBalanceWei Return inflatable balance
    */
    function getInflatableBalance() external view returns(uint256 _inflatableBalanceWei);
}


// File contracts/userInterfaces/IFtsoRewardManager.sol

//
pragma solidity 0.7.6;

interface IFtsoRewardManager {

    event RewardClaimed(
        address indexed dataProvider,
        address indexed whoClaimed,
        address indexed sentTo,
        uint256 rewardEpoch,
        uint256 amount
    );

    event RewardsDistributed(
        address indexed ftso,
        uint256 epochId,
        address[] addresses,
        uint256[] rewards
    );

    event FeePercentageChanged(
        address indexed dataProvider,
        uint256 value,
        uint256 validFromEpoch
    );

    event RewardClaimsExpired(
        uint256 rewardEpochId
    );

    /**
     * @notice Allows a percentage delegator to claim rewards.
     * @notice This function is intended to be used to claim rewards in case of delegation by percentage.
     * @param _recipient            address to transfer funds to
     * @param _rewardEpochs         array of reward epoch numbers to claim for
     * @return _rewardAmount        amount of total claimed rewards
     * @dev Reverts if `msg.sender` is delegating by amount
     */
    function claimReward(address payable _recipient, uint256[] memory _rewardEpochs)
        external returns (uint256 _rewardAmount);

    /**
     * @notice Allows the sender to claim the rewards from specified data providers.
     * @notice This function is intended to be used to claim rewards in case of delegation by amount.
     * @param _recipient            address to transfer funds to
     * @param _rewardEpochs         array of reward epoch numbers to claim for
     * @param _dataProviders        array of addresses representing data providers to claim the reward from
     * @return _rewardAmount        amount of total claimed rewards
     * @dev Function can be used by a percentage delegator but is more gas consuming than `claimReward`.
     */
    function claimRewardFromDataProviders(
        address payable _recipient,
        uint256[] memory _rewardEpochs,
        address[] memory _dataProviders
    )
        external
        returns (uint256 _rewardAmount);

    /**
     * @notice Allows data provider to set (or update last) fee percentage.
     * @param _feePercentageBIPS    number representing fee percentage in BIPS
     * @return _validFromEpoch      reward epoch number when the setting becomes effective.
     */
    function setDataProviderFeePercentage(uint256 _feePercentageBIPS)
        external returns (uint256 _validFromEpoch);

    /**
     * @notice Returns the current fee percentage of `_dataProvider`
     * @param _dataProvider         address representing data provider
     */
    function getDataProviderCurrentFeePercentage(address _dataProvider)
        external view returns (uint256 _feePercentageBIPS);

    /**
     * @notice Returns the scheduled fee percentage changes of `_dataProvider`
     * @param _dataProvider         address representing data provider
     * @return _feePercentageBIPS   positional array of fee percentages in BIPS
     * @return _validFromEpoch      positional array of block numbers the fee setings are effective from
     * @return _fixed               positional array of boolean values indicating if settings are subjected to change
     */
    function getDataProviderScheduledFeePercentageChanges(address _dataProvider) external view
        returns (
            uint256[] memory _feePercentageBIPS,
            uint256[] memory _validFromEpoch,
            bool[] memory _fixed
        );

    /**
     * @notice Returns information on epoch reward
     * @param _rewardEpoch          reward epoch number
     * @return _totalReward         number representing the total epoch reward
     * @return _claimedReward       number representing the amount of total epoch reward that has been claimed
     */
    function getEpochReward(uint256 _rewardEpoch) external view
        returns (uint256 _totalReward, uint256 _claimedReward);

    /**
     * @notice Returns the state of rewards for `_beneficiary` at `_rewardEpoch`
     * @param _beneficiary          address of reward beneficiary
     * @param _rewardEpoch          reward epoch number
     * @return _dataProviders       positional array of addresses representing data providers
     * @return _rewardAmounts       positional array of reward amounts
     * @return _claimed             positional array of boolean values indicating if reward is claimed
     * @return _claimable           boolean value indicating if rewards are claimable
     * @dev Reverts when queried with `_beneficary` delegating by amount
     */
    function getStateOfRewards(
        address _beneficiary,
        uint256 _rewardEpoch
    )
        external view
        returns (
            address[] memory _dataProviders,
            uint256[] memory _rewardAmounts,
            bool[] memory _claimed,
            bool _claimable
        );

    /**
     * @notice Returns the state of rewards for `_beneficiary` at `_rewardEpoch` from `_dataProviders`
     * @param _beneficiary          address of reward beneficiary
     * @param _rewardEpoch          reward epoch number
     * @param _dataProviders        positional array of addresses representing data providers
     * @return _rewardAmounts       positional array of reward amounts
     * @return _claimed             positional array of boolean values indicating if reward is claimed
     * @return _claimable           boolean value indicating if rewards are claimable
     */
    function getStateOfRewardsFromDataProviders(
        address _beneficiary,
        uint256 _rewardEpoch,
        address[] memory _dataProviders
    )
        external view
        returns (
            uint256[] memory _rewardAmounts,
            bool[] memory _claimed,
            bool _claimable
        );

    /**
     * @notice Returns the start and the end of the reward epoch range for which the reward is claimable
     * @param _startEpochId         the oldest epoch id that allows reward claiming
     * @param _endEpochId           the newest epoch id that allows reward claiming
     */
    function getEpochsWithClaimableRewards() external view
        returns (
            uint256 _startEpochId,
            uint256 _endEpochId
        );

    /**
     * @notice Returns the array of claimable epoch ids for which the reward has not yet been claimed
     * @param _beneficiary          address of reward beneficiary
     * @return _epochIds            array of epoch ids
     * @dev Reverts when queried with `_beneficary` delegating by amount
     */
    function getEpochsWithUnclaimedRewards(address _beneficiary) external view returns (
        uint256[] memory _epochIds
    );

    /**
     * @notice Returns the information on claimed reward of `_dataProvider` for `_rewardEpoch` by `_claimer`
     * @param _rewardEpoch          reward epoch number
     * @param _dataProvider         address representing the data provider
     * @param _claimer              address representing the claimer
     * @return _claimed             boolean indicating if reward has been claimed
     * @return _amount              number representing the claimed amount
     */
    function getClaimedReward(
        uint256 _rewardEpoch,
        address _dataProvider,
        address _claimer
    )
        external view
        returns (
            bool _claimed,
            uint256 _amount
        );

    /**
     * @notice Return reward epoch that will expire, when new reward epoch will start
     * @return Reward epoch id that will expire next
     */
    function getRewardEpochToExpireNext() external view returns (uint256);
}


// File contracts/tokenPools/interface/IIFtsoRewardManager.sol

//
pragma solidity 0.7.6;

interface IIFtsoRewardManager is IFtsoRewardManager {

    event DailyAuthorizedInflationSet(uint256 authorizedAmountWei);
    event InflationReceived(uint256 amountReceivedWei);

    function activate() external;
    function deactivate() external;
    function closeExpiredRewardEpoch(uint256 _rewardEpochId) external;

    function distributeRewards(
        address[] memory addresses,
        uint256[] memory weights,
        uint256 totalWeight,
        uint256 epochId,
        address ftso,
        uint256 priceEpochDurationSeconds,
        uint256 currentRewardEpoch,
        uint256 priceEpochEndTime,
        uint256 votePowerBlock
    ) external;

    /**
     * @notice Returns the information on unclaimed reward of `_dataProvider` for `_rewardEpoch`
     * @param _rewardEpoch          reward epoch number
     * @param _dataProvider         address representing the data provider
     * @return _amount              number representing the unclaimed amount
     * @return _weight              number representing the share that has not yet been claimed
     */
    function getUnclaimedReward(
        uint256 _rewardEpoch,
        address _dataProvider
    )
        external view
        returns (
            uint256 _amount,
            uint256 _weight
        );
}


// File contracts/token/implementation/CleanupBlockNumberManager.sol

//
pragma solidity 0.7.6;


/**
 * @title Token history cleanup manager
 * @notice Maintains the list of cleanable tokens for which history cleanup can be collectively cleaned u
 */
contract CleanupBlockNumberManager is Governed {

    string internal constant ERR_CONTRACT_NOT_FOUND = "contract not found";
    string internal constant ERR_TRIGGER_CONTRACT_OR_GOVERNANCE_ONLY = "trigger or governance only";

    IICleanable[] public registeredTokens;
    address public triggerContract;

    event RegistrationUpdated (IICleanable theContract, bool add);
    event CleanupBlockNumberSet (IICleanable theContract, uint256 blockNumber, bool success);

    modifier onlyTriggerOrGovernance {
        require(
            msg.sender == address(triggerContract) ||
            msg.sender == governance, ERR_TRIGGER_CONTRACT_OR_GOVERNANCE_ONLY
        );
        _;
    }

    constructor(address _governance) Governed(_governance) {
        /* empty block */
    }

    /**
     * @notice Sets trigger contract address.
     * @dev Usually this is FTSO Manager contract address.
     */
    function setTriggerContractAddress(address _triggerContract) external onlyGovernance {
        triggerContract = _triggerContract;
    }
    /**
     * @notice Register a contract of which history cleanup index is to be managed
     * @param _cleanableToken     The address of the contract to be managed.
     * @dev when using this function take care that call of setCleanupBlockNumber
     * is permitted by this object
     */
    function registerToken(IICleanable _cleanableToken) external onlyGovernance {
        uint256 len = registeredTokens.length;

        for (uint256 i = 0; i < len; i++) {
            if (_cleanableToken == registeredTokens[i]) {
                return; // already registered
            }
        }

        registeredTokens.push(_cleanableToken);
        emit RegistrationUpdated (_cleanableToken, true);
    }

    /**
     * @notice Unregiseter a contract from history cleanup index management
     * @param _cleanableToken     The address of the contract to unregister.
     */
    function unregisterToken(IICleanable _cleanableToken) external onlyGovernance {
        uint256 len = registeredTokens.length;

        for (uint256 i = 0; i < len; i++) {
            if (_cleanableToken == registeredTokens[i]) {
                registeredTokens[i] = registeredTokens[len -1];
                registeredTokens.pop();
                emit RegistrationUpdated (_cleanableToken, false);
                return;
            }
        }

        revert(ERR_CONTRACT_NOT_FOUND);
    }

    /**
     * @notice Sets clean up block number on managed cleanable tokens
     * @param _blockNumber cleanup block number
     */
    function setCleanUpBlockNumber(uint256 _blockNumber) external onlyTriggerOrGovernance {
        uint256 len = registeredTokens.length;
        for (uint256 i = 0; i < len; i++) {
            try registeredTokens[i].setCleanupBlockNumber(_blockNumber) {
                emit CleanupBlockNumberSet(registeredTokens[i], _blockNumber, true);
            } catch {
                emit CleanupBlockNumberSet(registeredTokens[i], _blockNumber, false);
            }
        }
    }
}


// File contracts/utils/implementation/GovernedAndFlareDaemonized.sol

//
pragma solidity 0.7.6;


contract GovernedAndFlareDaemonized is Governed {

    FlareDaemon public immutable flareDaemon;

    modifier onlyFlareDaemon () {
        require (msg.sender == address(flareDaemon), "only flare daemon");
        _;
    }

    constructor(address _governance, FlareDaemon _flareDaemon) Governed(_governance) {
        require(address(_flareDaemon) != address(0), "flare daemon zero");
        flareDaemon = _flareDaemon;
    }
}


// File contracts/utils/implementation/RevertErrorTracking.sol

//
pragma solidity 0.7.6;


/**
 * @title Revert Error Tracking
 * @notice A contract to track and store revert errors
 **/
contract RevertErrorTracking {

    struct RevertedError {
        uint192 lastErrorBlock;
        uint64 numErrors;
        address fromContract;
        uint64 errorTypeIndex;
        string errorMessage;
    }

    struct LastErrorData {
        uint192 totalRevertedErrors;
        uint64 lastErrorTypeIndex;
    }

    string internal constant INDEX_TOO_HIGH = "start index high";

    mapping(bytes32 => RevertedError) internal revertedErrors;
    bytes32 [] internal revertErrorHashes;
    LastErrorData public errorData;

    event ContractRevertError(address theContract, uint256 atBlock, string theMessage);

    /**
     * @notice Returns latest reverted error
     * @return _lastErrorBlock         Block number of last reverted error
     * @return _numErrors              Number of times same error with same contract address has been reverted
     * @return _errorString            Revert error message
     * @return _erroringContract       Array of addresses of the reverting contracts
     * @return _totalRevertedErrors    Total number of revert errors across all contracts
     */
    function showLastRevertedError () external view
        returns(
            uint256[] memory _lastErrorBlock,
            uint256[] memory _numErrors,
            string[] memory _errorString,
            address[] memory _erroringContract,
            uint256 _totalRevertedErrors
        )
    {
        return showRevertedErrors(errorData.lastErrorTypeIndex, 1);
    }

    /**
     * @notice Adds caught error to reverted errors mapping
     * @param revertedContract         Address of the reverting contract
     * @param message                  Reverte message
     */
    function addRevertError(address revertedContract, string memory message) public {
        bytes32 errorStringHash = keccak256(abi.encode(revertedContract, message));

        revertedErrors[errorStringHash].numErrors += 1;
        revertedErrors[errorStringHash].lastErrorBlock = uint192(block.number);
        emit ContractRevertError(revertedContract, block.number, message);
        errorData.totalRevertedErrors += 1;

        if (revertedErrors[errorStringHash].numErrors > 1) {
            // not first time this errors
            return;
        }

        // first time we recieve this error string.
        revertErrorHashes.push(errorStringHash);
        revertedErrors[errorStringHash].fromContract = revertedContract;
        revertedErrors[errorStringHash].errorMessage = message;
        revertedErrors[errorStringHash].errorTypeIndex = uint64(revertErrorHashes.length - 1);

        errorData.lastErrorTypeIndex = revertedErrors[errorStringHash].errorTypeIndex;
    }

    /**
     * @notice Returns latest reverted error
     * @param startIndex               Starting index in the error list array
     * @param numErrorTypesToShow      Number of error types to show
     * @return _lastErrorBlock         Array of last block number this error reverted
     * @return _numErrors              Number of times the same error with same contract address has been tracked
     * @return _errorString            Array of revert error messages
     * @return _erroringContract       Array of addresses of the reverting contracts
     * @return _totalRevertedErrors    Total number of errors reverted across all contracts
     */
    function showRevertedErrors (uint startIndex, uint numErrorTypesToShow) public view
        returns(
            uint256[] memory _lastErrorBlock,
            uint256[] memory _numErrors,
            string[] memory _errorString,
            address[] memory _erroringContract,
            uint256 _totalRevertedErrors
        )
    {
        require(startIndex < revertErrorHashes.length, INDEX_TOO_HIGH);
        uint256 numReportElements =
            revertErrorHashes.length >= startIndex + numErrorTypesToShow ?
            numErrorTypesToShow :
            revertErrorHashes.length - startIndex;

        _lastErrorBlock = new uint256[] (numReportElements);
        _numErrors = new uint256[] (numReportElements);
        _errorString = new string[] (numReportElements);
        _erroringContract = new address[] (numReportElements);

        // we have error data error type.
        // error type is hash(error_string, source contract)
        // per error type we report how many times it happened.
        // what was last block it happened.
        // what is the error string.
        // what is the erroring contract
        for (uint i = 0; i < numReportElements; i++) {
            bytes32 hash = revertErrorHashes[startIndex + i];

            _lastErrorBlock[i] = revertedErrors[hash].lastErrorBlock;
            _numErrors[i] = revertedErrors[hash].numErrors;
            _errorString[i] = revertedErrors[hash].errorMessage;
            _erroringContract[i] = revertedErrors[hash].fromContract;
        }
        _totalRevertedErrors = errorData.totalRevertedErrors;
    }
}


// File contracts/userInterfaces/IFtsoRegistry.sol

//
pragma solidity 0.7.6;


interface IFtsoRegistry is IFtsoRegistryGenesis {

    function getFtso(uint256 _ftsoIndex) external view returns(IIFtso _activeFtsoAddress);
    function getFtsoBySymbol(string memory _symbol) external view returns(IIFtso _activeFtsoAddress);
    function getSupportedIndices() external view returns(uint256[] memory _supportedIndices);
    function getSupportedSymbols() external view returns(string[] memory _supportedSymbols);
    function getSupportedFtsos() external view returns(IIFtso[] memory _ftsos);
    function getFtsoIndex(string memory _symbol) external view returns (uint256 _assetIndex);
    function getFtsoSymbol(uint256 _ftsoIndex) external view returns (string memory _symbol);
    function getCurrentPrice(uint256 _ftsoIndex) external view returns(uint256 _price, uint256 _timestamp);
    function getCurrentPrice(string memory _symbol) external view returns(uint256 _price, uint256 _timestamp);

    function getSupportedIndicesAndFtsos() external view
        returns(uint256[] memory _supportedIndices, IIFtso[] memory _ftsos);

    function getSupportedSymbolsAndFtsos() external view
        returns(string[] memory _supportedSymbols, IIFtso[] memory _ftsos);

    function getSupportedIndicesAndSymbols() external view
        returns(uint256[] memory _supportedIndices, string[] memory _supportedSymbols);

    function getSupportedIndicesSymbolsAndFtsos() external view
        returns(uint256[] memory _supportedIndices, string[] memory _supportedSymbols, IIFtso[] memory _ftsos);
}


// File contracts/utils/interface/IIFtsoRegistry.sol

//
pragma solidity 0.7.6;



interface IIFtsoRegistry is IFtsoRegistry {

    function setFtsoManagerAddress(IIFtsoManager _ftsoManager) external;

    // returns ftso index
    function addFtso(IIFtso _ftsoContract) external returns(uint256);

    function removeFtso(IIFtso _ftso) external;
}


// File contracts/userInterfaces/IVoterWhitelister.sol

//
pragma solidity 0.7.6;

interface IVoterWhitelister {
    /**
     * Raised when an account is removed from the voter whitelist.
     */
    event VoterWhitelisted(address voter, uint256 ftsoIndex);

    /**
     * Raised when an account is removed from the voter whitelist.
     */
    event VoterRemovedFromWhitelist(address voter, uint256 ftsoIndex);

    /**
     * Request to whitelist `_voter` account to ftso at `_ftsoIndex`. Will revert if vote power too low.
     * May be called by any address.
     */
    function requestWhitelistingVoter(address _voter, uint256 _ftsoIndex) external;

    /**
     * Request to whitelist `_voter` account to all active ftsos.
     * May be called by any address.
     * It returns an array of supported ftso indices and success flag per index.
     */
    function requestFullVoterWhitelisting(
        address _voter
    )
        external
        returns (
            uint256[] memory _supportedIndices,
            bool[] memory _success
        );

    /**
     * Maximum number of voters in the whitelist for a new FTSO.
     */
    function defaultMaxVotersForFtso() external view returns (uint256);

    /**
     * Maximum number of voters in the whitelist for FTSO at index `_ftsoIndex`.
     */
    function maxVotersForFtso(uint256 _ftsoIndex) external view returns (uint256);

    /**
     * Get whitelisted price providers for ftso with `_symbol`
     */
    function getFtsoWhitelistedPriceProvidersBySymbol(string memory _symbol) external view returns (address[] memory);

    /**
     * Get whitelisted price providers for ftso at `_ftsoIndex`
     */
    function getFtsoWhitelistedPriceProviders(uint256 _ftsoIndex) external view returns (address[] memory);
}


// File contracts/utils/interface/IIVoterWhitelister.sol

//
pragma solidity 0.7.6;

interface IIVoterWhitelister is IVoterWhitelister {
    /**
     * Set the maximum number of voters in the whitelist for FTSO at index `_ftsoIndex`.
     * Possibly removes several voters with the least votepower from the whitelist.
     * Only governance can call this method.
     */
    function setMaxVotersForFtso(uint256 _ftsoIndex, uint256 _newMaxVoters) external;

    /**
     * Set the maximum number of voters in the whitelist for a new FTSO.
     * Only governance can call this method.
     */
    function setDefaultMaxVotersForFtso(uint256 _defaultMaxVotersForFtso) external;

    /**
     * Create whitelist with default size for ftso.
     * Only ftso manager can call this method.
     */
    function addFtso(uint256 _ftsoIndex) external;

    /**
     * Clear whitelist for ftso at `_ftsoIndex`.
     * Only ftso manager can call this method.
     */
    function removeFtso(uint256 _ftsoIndex) external;

    /**
     * Remove `_trustedAddress` from whitelist for ftso at `_ftsoIndex`.
     */
    function removeTrustedAddressFromWhitelist(address _trustedAddress, uint256 _ftsoIndex) external;
}


// File contracts/ftso/implementation/FtsoManager.sol

//
pragma solidity 0.7.6;














/**
 * FtsoManager is in charge of:
 * - defining reward epochs (few days)
 * - per reward epoch choose a single block that represents vote power of this epoch.
 * - keep track of all FTSO contracts
 * - per price epoch (few minutes)
 *    - randomly choose one FTSO for rewarding.
 *    - trigger finalize price reveal epoch
 *    - determines addresses and reward weights and triggers rewardDistribution
 */
contract FtsoManager is IIFtsoManager, GovernedAndFlareDaemonized, IFlareDaemonize, RevertErrorTracking {
    using FtsoManagerSettings for FtsoManagerSettings.State;

    struct RewardEpochData {
        uint256 votepowerBlock;
        uint256 startBlock;
        uint256 startTimestamp;
    }

    uint256 public constant MAX_TRUSTED_ADDRESSES_LENGTH = 5;

    string internal constant ERR_FIRST_EPOCH_START_TS_IN_FUTURE = "First epoch start timestamp in future";
    string internal constant ERR_REWARD_EPOCH_DURATION_ZERO = "Reward epoch 0";
    string internal constant ERR_REWARD_EPOCH_START_TOO_SOON = "Reward epoch start too soon";
    string internal constant ERR_REWARD_EPOCH_NOT_INITIALIZED = "Reward epoch not initialized yet";
    string internal constant ERR_REWARD_EPOCH_START_CONDITION_INVALID = "Reward epoch start condition invalid";
    string internal constant ERR_REWARD_EPOCH_DURATION_CONDITION_INVALID = "Reward epoch duration condition invalid";
    string internal constant ERR_PRICE_EPOCH_DURATION_ZERO = "Price epoch 0";
    string internal constant ERR_VOTE_POWER_INTERVAL_FRACTION_ZERO = "Vote power interval fraction 0";
    string internal constant ERR_REVEAL_PRICE_EPOCH_DURATION_ZERO = "Reveal price epoch 0";
    string internal constant ERR_REVEAL_PRICE_EPOCH_TOO_LONG = "Reveal price epoch too long";
    string internal constant ERR_GOV_PARAMS_NOT_INIT_FOR_FTSOS = "Gov. params not initialized";
    string internal constant ERR_GOV_PARAMS_INVALID = "Gov. params invalid";
    string internal constant ERR_ASSET_FTSO_NOT_MANAGED = "Asset FTSO not managed by ftso manager";
    string internal constant ERR_NOT_FOUND = "Not found";
    string internal constant ERR_ALREADY_ADDED = "Already added";
    string internal constant ERR_FTSO_ASSET_FTSO_ZERO = "Asset ftsos list empty";
    string internal constant ERR_FTSO_EQUALS_ASSET_FTSO = "ftso equals asset ftso";
    string internal constant ERR_FTSO_SYMBOLS_MUST_MATCH = "FTSO symbols must match";
    string internal constant ERR_REWARD_EXPIRY_OFFSET_INVALID = "Reward expiry invalid";
    string internal constant ERR_MAX_TRUSTED_ADDRESSES_LENGTH_EXCEEDED = "Max trusted addresses length exceeded";
    string internal constant ERR_CLOSING_EXPIRED_REWARD_EPOCH_FAIL = "Unknown fail when closing expired";
    string internal constant ERR_SET_CLEANUP_BLOCK_FAIL = "unknown fail. setting cleanup block";
    string internal constant ERR_PRICE_EPOCH_FINALIZE_FAIL = "unknown fail. finalize price epoch";
    string internal constant ERR_DISTRIBUTE_REWARD_FAIL = "unknown fail. distribute rewards";
    string internal constant ERR_FALLBACK_FINALIZE_FAIL = "unknown fail. fallback finalize price epoch";
    string internal constant ERR_INIT_EPOCH_REVEAL_FAIL = "unknown fail. init epoch for reveal";
    string internal constant ERR_FALLBACK_INIT_EPOCH_REVEAL_FAIL = "unknown fail. fallback init epoch for reveal";

    bool public override active;
    RewardEpochData[] public rewardEpochs;
    address public lastRewardedFtsoAddress;

    FtsoManagerSettings.State public settings;

    // price epoch data
    uint256 immutable internal firstPriceEpochStartTs;
    uint256 immutable internal priceEpochDurationSeconds;
    uint256 immutable internal revealEpochDurationSeconds;
    uint256 internal lastUnprocessedPriceEpoch;
    uint256 internal lastUnprocessedPriceEpochRevealEnds;

    // reward Epoch data
    uint256 immutable public rewardEpochDurationSeconds;
    uint256 immutable public rewardEpochsStartTs;
    uint256 immutable internal votePowerIntervalFraction;
    uint256 internal currentRewardEpochEnds;
    uint256 internal nextRewardEpochToExpire;

    mapping(IIFtso => bool) internal managedFtsos;
    mapping(IIFtso => bool) internal notInitializedFtsos;

    IIPriceSubmitter public immutable priceSubmitter;
    IIFtsoRewardManager public rewardManager;
    IIFtsoRegistry public ftsoRegistry;
    IIVoterWhitelister public voterWhitelister;
    IISupply public supply;
    CleanupBlockNumberManager public cleanupBlockNumberManager;

    // indicates if lastUnprocessedPriceEpoch is initialized for reveal
    // it has to be finalized before new reward epoch can start
    bool private priceEpochInitialized;

    // fallback mode
    bool internal fallbackMode; // all ftsos in fallback mode
    mapping(IIFtso => bool) internal ftsoInFallbackMode;

    constructor(
        address _governance,
        FlareDaemon _flareDaemon,
        IIPriceSubmitter _priceSubmitter,
        uint256 _firstEpochStartTs,
        uint256 _priceEpochDurationSeconds,
        uint256 _revealEpochDurationSeconds,
        uint256 _rewardEpochsStartTs,
        uint256 _rewardEpochDurationSeconds,
        uint256 _votePowerIntervalFraction
    )
        GovernedAndFlareDaemonized(_governance, _flareDaemon)
    {
        require(block.timestamp >= _firstEpochStartTs, ERR_FIRST_EPOCH_START_TS_IN_FUTURE);
        require(_rewardEpochDurationSeconds > 0, ERR_REWARD_EPOCH_DURATION_ZERO);
        require(_priceEpochDurationSeconds > 0, ERR_PRICE_EPOCH_DURATION_ZERO);
        require(_revealEpochDurationSeconds > 0, ERR_REVEAL_PRICE_EPOCH_DURATION_ZERO);
        require(_votePowerIntervalFraction > 0, ERR_VOTE_POWER_INTERVAL_FRACTION_ZERO);

        require(_revealEpochDurationSeconds < _priceEpochDurationSeconds, ERR_REVEAL_PRICE_EPOCH_TOO_LONG);
        require(_firstEpochStartTs + _revealEpochDurationSeconds <= _rewardEpochsStartTs,
            ERR_REWARD_EPOCH_START_TOO_SOON);
        require((_rewardEpochsStartTs - _revealEpochDurationSeconds - _firstEpochStartTs) %
            _priceEpochDurationSeconds == 0, ERR_REWARD_EPOCH_START_CONDITION_INVALID);
        require(_rewardEpochDurationSeconds % _priceEpochDurationSeconds == 0,
            ERR_REWARD_EPOCH_DURATION_CONDITION_INVALID);

        // reward epoch
        rewardEpochDurationSeconds = _rewardEpochDurationSeconds;
        rewardEpochsStartTs = _rewardEpochsStartTs;
        votePowerIntervalFraction = _votePowerIntervalFraction;
        currentRewardEpochEnds = _rewardEpochsStartTs + _rewardEpochDurationSeconds;

        // price epoch
        firstPriceEpochStartTs = _firstEpochStartTs;
        priceEpochDurationSeconds = _priceEpochDurationSeconds;
        revealEpochDurationSeconds = _revealEpochDurationSeconds;
        lastUnprocessedPriceEpochRevealEnds = _rewardEpochsStartTs;
        lastUnprocessedPriceEpoch = (_rewardEpochsStartTs - _firstEpochStartTs) / _priceEpochDurationSeconds;

        priceSubmitter = _priceSubmitter;
    }

    function setContractAddresses(
        IIFtsoRewardManager _rewardManager,
        IIFtsoRegistry _ftsoRegistry,
        IIVoterWhitelister _voterWhitelister,
        IISupply _supply,
        CleanupBlockNumberManager _cleanupBlockNumberManager
    )
        external
        onlyGovernance
    {
        rewardManager = _rewardManager;
        ftsoRegistry = _ftsoRegistry;
        voterWhitelister = _voterWhitelister;
        supply = _supply;
        cleanupBlockNumberManager = _cleanupBlockNumberManager;
    }

    /**
     * @notice Activates FTSO manager (daemonize() runs jobs)
     */
    function activate() external override onlyGovernance {
        active = true;
    }

    /**
     * @notice Runs task triggered by Daemon.
     * The tasks include the following by priority
     * - finalizePriceEpoch
     * - Set governance parameters and initialize epochs
     * - finalizeRewardEpoch
     */
    function daemonize() external override onlyFlareDaemon returns (bool) {
        // flare daemon trigger. once every block
        if (!active) return false;

        if (rewardEpochs.length == 0) {
            _initializeFirstRewardEpoch();
        } else {
            // all three conditions can be executed in the same block,
            // but are split into three `if else if` groups to reduce gas usage per one block
            if (priceEpochInitialized && lastUnprocessedPriceEpochRevealEnds <= block.timestamp) {
                // finalizes initialized price epoch if reveal period is over
                // sets priceEpochInitialized = false
                _finalizePriceEpoch();
            } else if (!priceEpochInitialized && currentRewardEpochEnds <= block.timestamp) {
                // initialized price epoch must be finalized before new reward epoch can start
                // advance currentRewardEpochEnds
                _finalizeRewardEpoch();
                _closeExpiredRewardEpochs();
                _cleanupOnRewardEpochFinalization();
            } else if (lastUnprocessedPriceEpochRevealEnds <= block.timestamp) {
                // new price epoch can be initialized after previous was finalized
                // and after new reward epoch was started (if needed)
                // initializes price epoch and sets governance parameters on ftsos and price submitter
                // advance lastUnprocessedPriceEpochRevealEnds, sets priceEpochInitialized = true
                _initializeCurrentEpochFTSOStatesForReveal();
            }
        }
        return true;
    }

    function switchToFallbackMode() external override onlyFlareDaemon returns (bool) {
        if (!fallbackMode) {
            fallbackMode = true;
            emit FallbackMode(true);
            return true;
        }
        return false;
    }

     /**
     * @notice Adds FTSO to the list of rewarded FTSOs
     * All ftsos in multi asset ftso must be managed by this ftso manager
     */
    function addFtso(IIFtso _ftso) external override onlyGovernance {
        _addFtso(_ftso, true);
    }

    /**
     * @notice Removes FTSO from the list of the rewarded FTSOs - revert if ftso is used in multi asset ftso
     * @dev Deactivates _ftso
     */
    function removeFtso(IIFtso _ftso) external override onlyGovernance {
        uint256 ftsoIndex = ftsoRegistry.getFtsoIndex(_ftso.symbol());
        voterWhitelister.removeFtso(ftsoIndex);
        ftsoRegistry.removeFtso(_ftso);
        _cleanFtso(_ftso);
    }

    /**
     * @notice Replaces one ftso with another - symbols must match
     * All ftsos in multi asset ftso must be managed by this ftso manager
     * @dev Deactivates _ftsoToRemove
     */
    function replaceFtso(
        IIFtso _ftsoToRemove,
        IIFtso _ftsoToAdd,
        bool _copyCurrentPrice,
        bool _copyAssetOrAssetFtsos
    )
        external override
        onlyGovernance
    {
        // should compare strings but it is not supported - comparing hashes instead
        require(keccak256(abi.encode(_ftsoToRemove.symbol())) == keccak256(abi.encode(_ftsoToAdd.symbol())),
            ERR_FTSO_SYMBOLS_MUST_MATCH);

        // Check if it already exists
        IIFtso[] memory availableFtsos = _getFtsos();
        uint256 len = availableFtsos.length;
        uint256 k = 0;
        while (k < len) {
            if (availableFtsos[k] == _ftsoToRemove) {
                break;
            }
            ++k;
        }
        if (k == len) {
            revert(ERR_NOT_FOUND);
        }

        if (_copyCurrentPrice) {
            (uint256 currentPrice, uint256 timestamp) = _ftsoToRemove.getCurrentPrice();
            _ftsoToAdd.updateInitialPrice(currentPrice, timestamp);
        }

        if (_copyAssetOrAssetFtsos) {
            IIVPToken asset = _ftsoToRemove.getAsset();
            if (address(asset) != address(0)) { // copy asset if exists
                _ftsoToAdd.setAsset(asset);
            } else { // copy assetFtsos list if not empty
                IIFtso[] memory assetFtsos = _ftsoToRemove.getAssetFtsos();
                if (assetFtsos.length > 0) {
                    _ftsoToAdd.setAssetFtsos(assetFtsos);
                }
            }
        }
        // Add without duplicate check
        _addFtso(_ftsoToAdd, false);

        // replace old contract with the new one in multi asset ftsos
        IIFtso[] memory contracts = _getFtsos();

        uint256 ftsosLen = contracts.length;
        for (uint256 i = 0; i < ftsosLen; i++) {
            IIFtso ftso = contracts[i];
            if (ftso == _ftsoToRemove) {
                continue;
            }
            IIFtso[] memory assetFtsos = ftso.getAssetFtsos();
            uint256 assetFtsosLen = assetFtsos.length;
            if (assetFtsosLen > 0) {
                bool changed = false;
                for (uint256 j = 0; j < assetFtsosLen; j++) {
                    if (assetFtsos[j] == _ftsoToRemove) {
                        assetFtsos[j] = _ftsoToAdd;
                        changed = true;
                    }
                }
                if (changed) {
                    ftso.setAssetFtsos(assetFtsos);
                }
            }
        }

        // cleanup old contract
        _cleanFtso(_ftsoToRemove);
    }

    /**
     * @notice Set asset for FTSO
     */
    function setFtsoAsset(IIFtso _ftso, IIVPToken _asset) external override onlyGovernance {
        _ftso.setAsset(_asset);
    }

    /**
     * @notice Set asset FTSOs for FTSO - all ftsos should already be managed by this ftso manager
     */
    function setFtsoAssetFtsos(IIFtso _ftso, IIFtso[] memory _assetFtsos) external override onlyGovernance {
        uint256 len = _assetFtsos.length;
        require (len > 0, ERR_FTSO_ASSET_FTSO_ZERO);
        for (uint256 i = 0; i < len; i++) {
            if (_ftso == _assetFtsos[i]) {
                revert(ERR_FTSO_EQUALS_ASSET_FTSO);
            }
        }

        _checkAssetFtsosAreManaged(_assetFtsos);
        _ftso.setAssetFtsos(_assetFtsos);
    }

    /**
     * @notice Set fallback mode
     */
    function setFallbackMode(bool _fallbackMode) external override onlyGovernance {
        fallbackMode = _fallbackMode;
        emit FallbackMode(_fallbackMode);
    }

    /**
     * @notice Set fallback mode for ftso
     */
    function setFtsoFallbackMode(IIFtso _ftso, bool _fallbackMode) external override onlyGovernance {
        require(managedFtsos[_ftso], ERR_NOT_FOUND);
        ftsoInFallbackMode[_ftso] = _fallbackMode;
        emit FtsoFallbackMode(_ftso, _fallbackMode);
    }

    /**
     * @notice Sets governance parameters for FTSOs
     */
    function setGovernanceParameters(
        uint256 _maxVotePowerNatThresholdFraction,
        uint256 _maxVotePowerAssetThresholdFraction,
        uint256 _lowAssetUSDThreshold,
        uint256 _highAssetUSDThreshold,
        uint256 _highAssetTurnoutThresholdBIPS,
        uint256 _lowNatTurnoutThresholdBIPS,
        uint256 _rewardExpiryOffsetSeconds,
        address[] memory _trustedAddresses
    )
        external override onlyGovernance
    {
        require(_maxVotePowerNatThresholdFraction > 0, ERR_GOV_PARAMS_INVALID);
        require(_maxVotePowerAssetThresholdFraction > 0, ERR_GOV_PARAMS_INVALID);
        require(_highAssetUSDThreshold >= _lowAssetUSDThreshold, ERR_GOV_PARAMS_INVALID);
        require(_highAssetTurnoutThresholdBIPS <= 1e4, ERR_GOV_PARAMS_INVALID);
        require(_lowNatTurnoutThresholdBIPS <= 1e4, ERR_GOV_PARAMS_INVALID);
        require(_rewardExpiryOffsetSeconds > 0, ERR_REWARD_EXPIRY_OFFSET_INVALID);
        require(_trustedAddresses.length <= MAX_TRUSTED_ADDRESSES_LENGTH, ERR_MAX_TRUSTED_ADDRESSES_LENGTH_EXCEEDED);
        settings._setState(
            _maxVotePowerNatThresholdFraction,
            _maxVotePowerAssetThresholdFraction,
            _lowAssetUSDThreshold,
            _highAssetUSDThreshold,
            _highAssetTurnoutThresholdBIPS,
            _lowNatTurnoutThresholdBIPS,
            _rewardExpiryOffsetSeconds,
            _trustedAddresses
        );
    }

    function getVotePowerIntervalFraction() external view returns (uint256) {
        return votePowerIntervalFraction;
    }

    function getPriceSubmitter() external view override returns (IPriceSubmitter) {
        return priceSubmitter;
    }

    /**
     * @dev half-closed intervals - end time not included
     */
    function getCurrentPriceEpochData() external view override
        returns (
            uint256 priceEpochId,
            uint256 priceEpochStartTimestamp,
            uint256 priceEpochEndTimestamp,
            uint256 priceEpochRevealEndTimestamp,
            uint256 currentTimestamp
        )
    {
        uint256 epochId = _getCurrentPriceEpochId();
        return (
            epochId,
            firstPriceEpochStartTs + epochId * priceEpochDurationSeconds,
            firstPriceEpochStartTs + (epochId + 1) * priceEpochDurationSeconds,
            firstPriceEpochStartTs + (epochId + 1) * priceEpochDurationSeconds + revealEpochDurationSeconds,
            block.timestamp
        );
    }

    /**
     * @notice Gets vote power block of the specified reward epoch
     * @param _rewardEpoch          Reward epoch sequence number
     */
    function getRewardEpochVotePowerBlock(uint256 _rewardEpoch) external view override returns (uint256) {
        return rewardEpochs[_rewardEpoch].votepowerBlock;
    }

    /*
     * @notice Returns the list of FTSOs
     */
    function getFtsos() external view override returns (IIFtso[] memory _ftsos) {
        return _getFtsos();
    }

    function getPriceEpochConfiguration() external view override
        returns (
            uint256 _firstPriceEpochStartTs,
            uint256 _priceEpochDurationSeconds,
            uint256 _revealEpochDurationSeconds
        )
    {
        return (firstPriceEpochStartTs, priceEpochDurationSeconds, revealEpochDurationSeconds);
    }

    function getFallbackMode() external view override
        returns (
            bool _fallbackMode,
            IIFtso[] memory _ftsos,
            bool[] memory _ftsoInFallbackMode
        )
    {
        _fallbackMode = fallbackMode;
        _ftsos = _getFtsos();
        uint256 len = _ftsos.length;
        _ftsoInFallbackMode = new bool[](len);

        for (uint256 i = 0; i < len; i++) {
            _ftsoInFallbackMode[i] = ftsoInFallbackMode[_ftsos[i]];
        }
    }

    /**
     * @notice Returns current reward epoch index (one currently running)
     */
    function getCurrentRewardEpoch() public view override returns (uint256) {
        uint256 rewardEpochsLength = rewardEpochs.length;
        require(rewardEpochsLength != 0, ERR_REWARD_EPOCH_NOT_INITIALIZED);
        return rewardEpochsLength - 1;
    }

    function _addFtso(IIFtso _ftso, bool _addNewFtso) internal {
        require(settings.initialized, ERR_GOV_PARAMS_NOT_INIT_FOR_FTSOS);

        _checkAssetFtsosAreManaged(_ftso.getAssetFtsos());

        if (_addNewFtso) {
            // Check if symbol already exists in registry
            bytes32 symbol = keccak256(abi.encode(_ftso.symbol()));
            string[] memory supportedSymbols = ftsoRegistry.getSupportedSymbols();
            uint256 len = supportedSymbols.length;
            while (len > 0) {
                --len;
                if (keccak256(abi.encode(supportedSymbols[len])) == symbol) {
                    revert(ERR_ALREADY_ADDED);
                }
            }
        }

        _ftso.activateFtso(firstPriceEpochStartTs, priceEpochDurationSeconds, revealEpochDurationSeconds);

        // Set the vote power block
        if (rewardEpochs.length != 0) {
            _ftso.setVotePowerBlock(rewardEpochs[rewardEpochs.length - 1].votepowerBlock);
        }

        // Configure
        _ftso.configureEpochs(
            settings.maxVotePowerNatThresholdFraction,
            settings.maxVotePowerAssetThresholdFraction,
            settings.lowAssetUSDThreshold,
            settings.highAssetUSDThreshold,
            settings.highAssetTurnoutThresholdBIPS,
            settings.lowNatTurnoutThresholdBIPS,
            settings.trustedAddresses
        );

        // skip first round of price finalization if price epoch was already initialized for reveal
        notInitializedFtsos[_ftso] = priceEpochInitialized;
        managedFtsos[_ftso] = true;
        uint256 ftsoIndex = ftsoRegistry.addFtso(_ftso);

        // When a new ftso is added we also add it to the voter whitelister contract
        if (_addNewFtso) {
            voterWhitelister.addFtso(ftsoIndex);
        }

        emit FtsoAdded(_ftso, true);
    }

    function _cleanFtso(IIFtso _ftso) internal {
        _ftso.deactivateFtso();
        // Since this is as mapping, we can also just delete it, as false is default value for non-existing keys
        delete ftsoInFallbackMode[_ftso];
        delete notInitializedFtsos[_ftso];
        delete managedFtsos[_ftso];
        _checkMultiAssetFtsosAreManaged(_getFtsos());
        emit FtsoAdded(_ftso, false);
    }

    /**
     * @notice Initializes first reward epoch. Also sets vote power block to FTSOs
     */
    function _initializeFirstRewardEpoch() internal {

        if (block.timestamp >= currentRewardEpochEnds - rewardEpochDurationSeconds) {
            IIFtso[] memory ftsos = _getFtsos();
            uint256 numFtsos = ftsos.length;
            // Prime the reward epoch array with a new reward epoch
            RewardEpochData memory epochData = RewardEpochData({
                votepowerBlock: block.number - 1,
                startBlock: block.number,
                startTimestamp: block.timestamp
            });

            rewardEpochs.push(epochData);

            for (uint256 i = 0; i < numFtsos; ++i) {
                ftsos[i].setVotePowerBlock(epochData.votepowerBlock);
            }
        }
    }

    /**
     * @notice Finalizes reward epoch
     */
    function _finalizeRewardEpoch() internal {
        IIFtso[] memory ftsos = _getFtsos();
        uint256 numFtsos = ftsos.length;

        uint256 lastRandom = block.timestamp;
        // Are there any FTSOs to process?
        if (numFtsos > 0) {
            for (uint256 i = 0; i < numFtsos; ++i) {
                lastRandom += ftsos[i].getCurrentRandom();
            }
        }

        lastRandom = uint256(keccak256(abi.encode(lastRandom)));
        // @dev when considering block boundary for vote power block:
        // - if far from now, it doesn't reflect last vote power changes
        // - if too small, possible loan attacks.
        // IMPORTANT: currentRewardEpoch is actually the one just getting finalized!
        uint256 votepowerBlockBoundary =
            (block.number - rewardEpochs[getCurrentRewardEpoch()].startBlock) / votePowerIntervalFraction;
        // note: votePowerIntervalFraction > 0

        if (votepowerBlockBoundary == 0) {
            votepowerBlockBoundary = 1;
        }

        //slither-disable-next-line weak-prng           // lastRandom calculated from ftso inputs
        uint256 votepowerBlocksAgo = lastRandom % votepowerBlockBoundary;
        // prevent block.number becoming votePowerBlock
        // if  lastRandom % votepowerBlockBoundary == 0
        if (votepowerBlocksAgo == 0) {
            votepowerBlocksAgo = 1;
        }

        RewardEpochData memory epochData = RewardEpochData({
            votepowerBlock: block.number - votepowerBlocksAgo,
            startBlock: block.number,
            startTimestamp: block.timestamp
        });
        rewardEpochs.push(epochData);
        for (uint256 i = 0; i < numFtsos; i++) {
            ftsos[i].setVotePowerBlock(epochData.votepowerBlock);
        }

        emit RewardEpochFinalized(epochData.votepowerBlock, epochData.startBlock);

        // Advance reward epoch end-time
        currentRewardEpochEnds += rewardEpochDurationSeconds;
    }

    /**
     * @notice Closes expired reward epochs
     */
    function _closeExpiredRewardEpochs() internal {
        uint256 currentRewardEpoch = getCurrentRewardEpoch();
        uint256 expiryThreshold = block.timestamp - settings.rewardExpiryOffsetSeconds;
        // NOTE: start time of (i+1)th reward epoch is the end time of i-th
        // This loop is clearly bounded by the value currentRewardEpoch, which is
        // always kept to the value of rewardEpochs.length - 1 in code and this value
        // does not change in the loop.
        while (
            nextRewardEpochToExpire < currentRewardEpoch &&
            rewardEpochs[nextRewardEpochToExpire + 1].startTimestamp <= expiryThreshold)
        {   // Note: Since nextRewardEpochToExpire + 1 starts at that time
            // nextRewardEpochToExpire ends strictly before expiryThreshold,
            try rewardManager.closeExpiredRewardEpoch(nextRewardEpochToExpire) {
                nextRewardEpochToExpire++;
            } catch Error(string memory message) {
                // closing of expired failed, which is not critical
                // just emit event for diagnostics
                emit ClosingExpiredRewardEpochFailed(nextRewardEpochToExpire);
                addRevertError(address(rewardManager), message);
                // Do not proceed with the loop.
                break;
            } catch {
                emit ClosingExpiredRewardEpochFailed(nextRewardEpochToExpire);
                addRevertError(address(rewardManager), ERR_CLOSING_EXPIRED_REWARD_EPOCH_FAIL);
                // Do not proceed with the loop.
                break;
            }
        }
    }

    /**
     * @notice Performs any cleanup needed immediately after a reward epoch is finalized
     */
    function _cleanupOnRewardEpochFinalization() internal {
        if (address(cleanupBlockNumberManager) == address(0)) {
            emit CleanupBlockNumberManagerUnset();
            return;
        }
        uint256 cleanupBlock = rewardEpochs[nextRewardEpochToExpire].votepowerBlock;

        try cleanupBlockNumberManager.setCleanUpBlockNumber(cleanupBlock) {
        } catch Error(string memory message) {
            // cleanup block number manager call failed, which is not critical
            // just emit event for diagnostics
            emit CleanupBlockNumberManagerFailedForBlock(cleanupBlock);
            addRevertError(address(cleanupBlockNumberManager), message);
        } catch {
            emit CleanupBlockNumberManagerFailedForBlock(cleanupBlock);
            addRevertError(address(cleanupBlockNumberManager), ERR_SET_CLEANUP_BLOCK_FAIL);
        }
    }

    function _finalizePriceEpochFailed(IIFtso ftso, string memory message) internal {
        emit FinalizingPriceEpochFailed(
            ftso,
            lastUnprocessedPriceEpoch,
            IFtso.PriceFinalizationType.WEIGHTED_MEDIAN
        );

        addRevertError(address(ftso), message);

        _fallbackFinalizePriceEpoch(ftso);
    }

    /**
     * @notice Finalizes price epoch
     */
    function _finalizePriceEpoch() internal {
        IIFtso[] memory ftsos = _getFtsos();
        uint256 numFtsos = ftsos.length;

        // Are there any FTSOs to process?
        if (numFtsos > 0 && !fallbackMode) {
            // choose winning ftso
            uint256 chosenFtsoId;
            if (lastRewardedFtsoAddress == address(0)) {
                // pump not yet primed
                //slither-disable-next-line weak-prng           // only used for first epoch
                chosenFtsoId = uint256(keccak256(abi.encode(
                        block.difficulty, block.timestamp
                    ))) % numFtsos;
            } else {
                // at least one finalize with real FTSO
                uint256 currentRandomSum = 0;
                for (uint256 i = 0; i < numFtsos; i++) {
                    currentRandomSum += ftsos[i].getCurrentRandom(); // may overflow but it is still ok
                }
                //slither-disable-next-line weak-prng           // ftso random calculated safely from inputs
                chosenFtsoId = uint256(keccak256(abi.encode(
                        currentRandomSum, block.timestamp
                    ))) % numFtsos;
            }
            address[] memory addresses;
            uint256[] memory weights;
            uint256 totalWeight;

            // On the off chance that the winning FTSO does not have any
            // recipient within the truncated price distribution to
            // receive rewards, find the next FTSO that does have reward
            // recipients and declare it the winner. Start with the next ftso.
            bool wasDistributed = false;
            address rewardedFtsoAddress = address(0);
            for (uint256 i = 0; i < numFtsos; i++) {
                //slither-disable-next-line weak-prng           // not a random, just choosing next
                uint256 id = (chosenFtsoId + i) % numFtsos;
                IIFtso ftso = ftsos[id];

                // skip finalizing ftso, as it is not initialized for reveal and tx would revert
                if (notInitializedFtsos[ftso]) {
                    delete notInitializedFtsos[ftso];
                    continue;
                }

                try ftso.finalizePriceEpoch(lastUnprocessedPriceEpoch, !wasDistributed) returns (
                    address[] memory _addresses,
                    uint256[] memory _weights,
                    uint256 _totalWeight
                ) {
                    if (!wasDistributed && _addresses.length > 0) { // change also in FTSO if condition changes
                        (addresses, weights, totalWeight) = (_addresses, _weights, _totalWeight);
                        wasDistributed = true;
                        rewardedFtsoAddress = address(ftso);
                    }
                } catch Error(string memory message) {
                    _finalizePriceEpochFailed(ftso, message);
                } catch {
                    _finalizePriceEpochFailed(ftso, ERR_PRICE_EPOCH_FINALIZE_FAIL);
                }
            }

            uint256 currentRewardEpoch = getCurrentRewardEpoch();

            if (wasDistributed) {
                try rewardManager.distributeRewards(
                    addresses,
                    weights,
                    totalWeight,
                    lastUnprocessedPriceEpoch,
                    rewardedFtsoAddress,
                    priceEpochDurationSeconds,
                    currentRewardEpoch,
                    _getPriceEpochEndTime(lastUnprocessedPriceEpoch) - 1, // actual end time (included)
                    rewardEpochs[currentRewardEpoch].votepowerBlock) {
                } catch Error(string memory message) {
                    emit DistributingRewardsFailed(rewardedFtsoAddress, lastUnprocessedPriceEpoch);
                    addRevertError(address(rewardManager), message);
                } catch {
                    emit DistributingRewardsFailed(rewardedFtsoAddress, lastUnprocessedPriceEpoch);
                    addRevertError(address(rewardManager), ERR_DISTRIBUTE_REWARD_FAIL);
                }
            }

            lastRewardedFtsoAddress = rewardedFtsoAddress;
            emit PriceEpochFinalized(rewardedFtsoAddress, currentRewardEpoch);
        } else {
            // only for fallback mode
            for (uint256 i = 0; i < numFtsos; i++) {
                IIFtso ftso = ftsos[i];
                // skip finalizing ftso, as it is not initialized for reveal and tx would revert
                if (notInitializedFtsos[ftso]) {
                    delete notInitializedFtsos[ftso];
                    continue;
                }
                _fallbackFinalizePriceEpoch(ftso);
            }

            lastRewardedFtsoAddress = address(0);
            emit PriceEpochFinalized(address(0), getCurrentRewardEpoch());
        }

        priceEpochInitialized = false;
    }

    function _fallbackFinalizePriceEpochFailed(IIFtso _ftso, string memory message) internal {
        emit FinalizingPriceEpochFailed(
            _ftso,
            lastUnprocessedPriceEpoch,
            IFtso.PriceFinalizationType.TRUSTED_ADDRESSES
        );
        addRevertError(address(_ftso), message);

        // if reverts we want to propagate up to daemon
        _ftso.forceFinalizePriceEpoch(lastUnprocessedPriceEpoch);
    }

    function _fallbackFinalizePriceEpoch(IIFtso _ftso) internal {
        try _ftso.averageFinalizePriceEpoch(lastUnprocessedPriceEpoch) {
        } catch Error(string memory message) {
            _fallbackFinalizePriceEpochFailed(_ftso, message);
        } catch {
            _fallbackFinalizePriceEpochFailed(_ftso, ERR_FALLBACK_FINALIZE_FAIL);
        }
    }

    /**
     * @notice Initializes epoch states in FTSOs for reveal.
     * Prior to initialization it sets governance parameters, if
     * governance has changed them. It also sets price submitter trusted addresses.
     */
    function _initializeCurrentEpochFTSOStatesForReveal() internal {
        if (settings.changed) {
            priceSubmitter.setTrustedAddresses(settings.trustedAddresses);
        }

        IIFtso[] memory ftsos = _getFtsos();
        uint256 numFtsos = ftsos.length;

        // circulating supply is used only when ftso is not in fallback mode
        uint256 circulatingSupplyNat;
        if (numFtsos > 0 && !fallbackMode) {
            uint256 votePowerBlock = rewardEpochs[rewardEpochs.length - 1].votepowerBlock;
            circulatingSupplyNat = supply.getCirculatingSupplyAtCached(votePowerBlock);
        }

        for (uint256 i = 0; i < numFtsos; i++) {
            IIFtso ftso = ftsos[i];
            if (settings.changed) {
                ftso.configureEpochs(
                    settings.maxVotePowerNatThresholdFraction,
                    settings.maxVotePowerAssetThresholdFraction,
                    settings.lowAssetUSDThreshold,
                    settings.highAssetUSDThreshold,
                    settings.highAssetTurnoutThresholdBIPS,
                    settings.lowNatTurnoutThresholdBIPS,
                    settings.trustedAddresses
                );
            }

            try ftso.initializeCurrentEpochStateForReveal(
                circulatingSupplyNat,
                fallbackMode || ftsoInFallbackMode[ftso]) {
            } catch Error(string memory message) {
                _initializeCurrentEpochStateForRevealFailed(ftso, message);
            } catch {
                _initializeCurrentEpochStateForRevealFailed(ftso, ERR_INIT_EPOCH_REVEAL_FAIL);
            }

        }
        settings.changed = false;

        // Advance price epoch id and end-time
        uint256 currentPriceEpochId = _getCurrentPriceEpochId();
        lastUnprocessedPriceEpoch = currentPriceEpochId;
        lastUnprocessedPriceEpochRevealEnds = _getPriceEpochRevealEndTime(currentPriceEpochId);

        priceEpochInitialized = true;
    }

    function _initializeCurrentEpochStateForRevealFailed(IIFtso ftso, string memory message) internal {
        emit InitializingCurrentEpochStateForRevealFailed(ftso, _getCurrentPriceEpochId());
        addRevertError(address(ftso), message);

        // if it was already called with fallback = true, just mark as not initialized, else retry
        if (fallbackMode || ftsoInFallbackMode[ftso]) {
            notInitializedFtsos[ftso] = true;
        } else {
            try ftso.initializeCurrentEpochStateForReveal(0, true) {
            } catch Error(string memory message1) {
                notInitializedFtsos[ftso] = true;
                emit InitializingCurrentEpochStateForRevealFailed(ftso, _getCurrentPriceEpochId());
                addRevertError(address(ftso), message1);
            } catch {
                notInitializedFtsos[ftso] = true;
                emit InitializingCurrentEpochStateForRevealFailed(ftso, _getCurrentPriceEpochId());
                addRevertError(address(ftso), ERR_FALLBACK_INIT_EPOCH_REVEAL_FAIL);
            }
        }
    }

    /**
     * @notice Check if asset ftsos are managed by this ftso manager, revert otherwise
     */
    function _checkAssetFtsosAreManaged(IIFtso[] memory _assetFtsos) internal view {
        uint256 len = _assetFtsos.length;
        for (uint256 i = 0; i < len; i++) {
            if (!managedFtsos[_assetFtsos[i]]) {
                revert(ERR_ASSET_FTSO_NOT_MANAGED);
            }
        }
    }

    /**
     * @notice Check if all multi asset ftsos are managed by this ftso manager, revert otherwise
     */
    function _checkMultiAssetFtsosAreManaged(IIFtso[] memory _ftsos) internal view {
        uint256 len = _ftsos.length;
        for (uint256 i = 0; i < len; i++) {
            _checkAssetFtsosAreManaged(_ftsos[i].getAssetFtsos());
        }
    }

    /**
     * @notice Returns price epoch reveal end time.
     * @param _priceEpochId The price epoch id.
     * @dev half-closed interval - end time not included
     */
    function _getPriceEpochRevealEndTime(uint256 _priceEpochId) internal view returns (uint256) {
        return firstPriceEpochStartTs + (_priceEpochId + 1) * priceEpochDurationSeconds + revealEpochDurationSeconds;
    }

    /**
     * @notice Returns price epoch end time.
     * @param _forPriceEpochId The price epoch id of the end time to fetch.
     * @dev half-closed interval - end time not included
     */
    function _getPriceEpochEndTime(uint256 _forPriceEpochId) internal view returns (uint256) {
        return firstPriceEpochStartTs + ((_forPriceEpochId + 1) * priceEpochDurationSeconds);
    }

    /**
     * @notice Returns current price epoch id. The calculation in this function
     * should fully match to definition of current epoch id in FTSO contracts.
     */
    function _getCurrentPriceEpochId() internal view returns (uint256) {
        return (block.timestamp - firstPriceEpochStartTs) / priceEpochDurationSeconds;
    }

    function _getFtsos() private view returns (IIFtso[] memory) {
        return ftsoRegistry.getSupportedFtsos();
    }
}
        

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_governance","internalType":"address"},{"type":"address","name":"_flareDaemon","internalType":"contract FlareDaemon"},{"type":"address","name":"_priceSubmitter","internalType":"contract IIPriceSubmitter"},{"type":"uint256","name":"_firstEpochStartTs","internalType":"uint256"},{"type":"uint256","name":"_priceEpochDurationSeconds","internalType":"uint256"},{"type":"uint256","name":"_revealEpochDurationSeconds","internalType":"uint256"},{"type":"uint256","name":"_rewardEpochsStartTs","internalType":"uint256"},{"type":"uint256","name":"_rewardEpochDurationSeconds","internalType":"uint256"},{"type":"uint256","name":"_votePowerIntervalFraction","internalType":"uint256"}]},{"type":"event","name":"CleanupBlockNumberManagerFailedForBlock","inputs":[{"type":"uint256","name":"blockNumber","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"CleanupBlockNumberManagerUnset","inputs":[],"anonymous":false},{"type":"event","name":"ClosingExpiredRewardEpochFailed","inputs":[{"type":"uint256","name":"_rewardEpoch","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ContractRevertError","inputs":[{"type":"address","name":"theContract","internalType":"address","indexed":false},{"type":"uint256","name":"atBlock","internalType":"uint256","indexed":false},{"type":"string","name":"theMessage","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"DistributingRewardsFailed","inputs":[{"type":"address","name":"ftso","internalType":"address","indexed":false},{"type":"uint256","name":"epochId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"FallbackMode","inputs":[{"type":"bool","name":"fallbackMode","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"FinalizingPriceEpochFailed","inputs":[{"type":"address","name":"ftso","internalType":"contract IIFtso","indexed":false},{"type":"uint256","name":"epochId","internalType":"uint256","indexed":false},{"type":"uint8","name":"failingType","internalType":"enum IFtso.PriceFinalizationType","indexed":false}],"anonymous":false},{"type":"event","name":"FtsoAdded","inputs":[{"type":"address","name":"ftso","internalType":"contract IIFtso","indexed":false},{"type":"bool","name":"add","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"FtsoFallbackMode","inputs":[{"type":"address","name":"ftso","internalType":"contract IIFtso","indexed":false},{"type":"bool","name":"fallbackMode","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"GovernanceProposed","inputs":[{"type":"address","name":"proposedGovernance","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"GovernanceUpdated","inputs":[{"type":"address","name":"oldGovernance","internalType":"address","indexed":false},{"type":"address","name":"newGoveranance","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"InitializingCurrentEpochStateForRevealFailed","inputs":[{"type":"address","name":"ftso","internalType":"contract IIFtso","indexed":false},{"type":"uint256","name":"epochId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"PriceEpochFinalized","inputs":[{"type":"address","name":"chosenFtso","internalType":"address","indexed":false},{"type":"uint256","name":"rewardEpochId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardEpochFinalized","inputs":[{"type":"uint256","name":"votepowerBlock","internalType":"uint256","indexed":false},{"type":"uint256","name":"startBlock","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_TRUSTED_ADDRESSES_LENGTH","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"activate","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"active","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addFtso","inputs":[{"type":"address","name":"_ftso","internalType":"contract IIFtso"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addRevertError","inputs":[{"type":"address","name":"revertedContract","internalType":"address"},{"type":"string","name":"message","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimGovernance","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract CleanupBlockNumberManager"}],"name":"cleanupBlockNumberManager","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"daemonize","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint192","name":"totalRevertedErrors","internalType":"uint192"},{"type":"uint64","name":"lastErrorTypeIndex","internalType":"uint64"}],"name":"errorData","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract FlareDaemon"}],"name":"flareDaemon","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIFtsoRegistry"}],"name":"ftsoRegistry","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"priceEpochId","internalType":"uint256"},{"type":"uint256","name":"priceEpochStartTimestamp","internalType":"uint256"},{"type":"uint256","name":"priceEpochEndTimestamp","internalType":"uint256"},{"type":"uint256","name":"priceEpochRevealEndTimestamp","internalType":"uint256"},{"type":"uint256","name":"currentTimestamp","internalType":"uint256"}],"name":"getCurrentPriceEpochData","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getCurrentRewardEpoch","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"_fallbackMode","internalType":"bool"},{"type":"address[]","name":"_ftsos","internalType":"contract IIFtso[]"},{"type":"bool[]","name":"_ftsoInFallbackMode","internalType":"bool[]"}],"name":"getFallbackMode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"_ftsos","internalType":"contract IIFtso[]"}],"name":"getFtsos","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_firstPriceEpochStartTs","internalType":"uint256"},{"type":"uint256","name":"_priceEpochDurationSeconds","internalType":"uint256"},{"type":"uint256","name":"_revealEpochDurationSeconds","internalType":"uint256"}],"name":"getPriceEpochConfiguration","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IPriceSubmitter"}],"name":"getPriceSubmitter","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getRewardEpochVotePowerBlock","inputs":[{"type":"uint256","name":"_rewardEpoch","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getVotePowerIntervalFraction","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"governance","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialise","inputs":[{"type":"address","name":"_governance","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"lastRewardedFtsoAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIPriceSubmitter"}],"name":"priceSubmitter","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"proposeGovernance","inputs":[{"type":"address","name":"_governance","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"proposedGovernance","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeFtso","inputs":[{"type":"address","name":"_ftso","internalType":"contract IIFtso"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"replaceFtso","inputs":[{"type":"address","name":"_ftsoToRemove","internalType":"contract IIFtso"},{"type":"address","name":"_ftsoToAdd","internalType":"contract IIFtso"},{"type":"bool","name":"_copyCurrentPrice","internalType":"bool"},{"type":"bool","name":"_copyAssetOrAssetFtsos","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardEpochDurationSeconds","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"votepowerBlock","internalType":"uint256"},{"type":"uint256","name":"startBlock","internalType":"uint256"},{"type":"uint256","name":"startTimestamp","internalType":"uint256"}],"name":"rewardEpochs","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardEpochsStartTs","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIFtsoRewardManager"}],"name":"rewardManager","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setContractAddresses","inputs":[{"type":"address","name":"_rewardManager","internalType":"contract IIFtsoRewardManager"},{"type":"address","name":"_ftsoRegistry","internalType":"contract IIFtsoRegistry"},{"type":"address","name":"_voterWhitelister","internalType":"contract IIVoterWhitelister"},{"type":"address","name":"_supply","internalType":"contract IISupply"},{"type":"address","name":"_cleanupBlockNumberManager","internalType":"contract CleanupBlockNumberManager"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFallbackMode","inputs":[{"type":"bool","name":"_fallbackMode","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFtsoAsset","inputs":[{"type":"address","name":"_ftso","internalType":"contract IIFtso"},{"type":"address","name":"_asset","internalType":"contract IIVPToken"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFtsoAssetFtsos","inputs":[{"type":"address","name":"_ftso","internalType":"contract IIFtso"},{"type":"address[]","name":"_assetFtsos","internalType":"contract IIFtso[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFtsoFallbackMode","inputs":[{"type":"address","name":"_ftso","internalType":"contract IIFtso"},{"type":"bool","name":"_fallbackMode","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setGovernanceParameters","inputs":[{"type":"uint256","name":"_maxVotePowerNatThresholdFraction","internalType":"uint256"},{"type":"uint256","name":"_maxVotePowerAssetThresholdFraction","internalType":"uint256"},{"type":"uint256","name":"_lowAssetUSDThreshold","internalType":"uint256"},{"type":"uint256","name":"_highAssetUSDThreshold","internalType":"uint256"},{"type":"uint256","name":"_highAssetTurnoutThresholdBIPS","internalType":"uint256"},{"type":"uint256","name":"_lowNatTurnoutThresholdBIPS","internalType":"uint256"},{"type":"uint256","name":"_rewardExpiryOffsetSeconds","internalType":"uint256"},{"type":"address[]","name":"_trustedAddresses","internalType":"address[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"maxVotePowerNatThresholdFraction","internalType":"uint256"},{"type":"uint256","name":"maxVotePowerAssetThresholdFraction","internalType":"uint256"},{"type":"uint256","name":"lowAssetUSDThreshold","internalType":"uint256"},{"type":"uint256","name":"highAssetUSDThreshold","internalType":"uint256"},{"type":"uint256","name":"highAssetTurnoutThresholdBIPS","internalType":"uint256"},{"type":"uint256","name":"lowNatTurnoutThresholdBIPS","internalType":"uint256"},{"type":"uint256","name":"rewardExpiryOffsetSeconds","internalType":"uint256"},{"type":"bool","name":"changed","internalType":"bool"},{"type":"bool","name":"initialized","internalType":"bool"}],"name":"settings","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"_lastErrorBlock","internalType":"uint256[]"},{"type":"uint256[]","name":"_numErrors","internalType":"uint256[]"},{"type":"string[]","name":"_errorString","internalType":"string[]"},{"type":"address[]","name":"_erroringContract","internalType":"address[]"},{"type":"uint256","name":"_totalRevertedErrors","internalType":"uint256"}],"name":"showLastRevertedError","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"_lastErrorBlock","internalType":"uint256[]"},{"type":"uint256[]","name":"_numErrors","internalType":"uint256[]"},{"type":"string[]","name":"_errorString","internalType":"string[]"},{"type":"address[]","name":"_erroringContract","internalType":"address[]"},{"type":"uint256","name":"_totalRevertedErrors","internalType":"uint256"}],"name":"showRevertedErrors","inputs":[{"type":"uint256","name":"startIndex","internalType":"uint256"},{"type":"uint256","name":"numErrorTypesToShow","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IISupply"}],"name":"supply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"switchToFallbackMode","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferGovernance","inputs":[{"type":"address","name":"_governance","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIVoterWhitelister"}],"name":"voterWhitelister","inputs":[]}]
              

Contract Creation Code

0x6101806040523480156200001257600080fd5b5060405162005a4f38038062005a4f833981016040819052620000359162000519565b888881806001600160a01b038116156200005457620000548162000435565b506001600160a01b038116620000a4576040805162461bcd60e51b815260206004820152601060248201526f5f676f7665726e616e6365207a65726f60801b604482015290519081900360640190fd5b506001600160a01b038116620000f5576040805162461bcd60e51b8152602060048201526011602482015270666c617265206461656d6f6e207a65726f60781b604482015290519081900360640190fd5b6001600160601b0319606091821b166080526040805191820190526025808252428911159250620059df6020830139906200014e5760405162461bcd60e51b8152600401620001459190620005a7565b60405180910390fd5b5060408051808201909152600e81526d05265776172642065706f636820360941b602082015282620001955760405162461bcd60e51b8152600401620001459190620005a7565b5060408051808201909152600d81526c050726963652065706f6368203609c1b602082015285620001db5760405162461bcd60e51b8152600401620001459190620005a7565b5060408051808201909152601481527f52657665616c2070726963652065706f63682030000000000000000000000000602082015284620002315760405162461bcd60e51b8152600401620001459190620005a7565b5060408051808201909152601e81527f566f746520706f77657220696e74657276616c206672616374696f6e20300000602082015281620002875760405162461bcd60e51b8152600401620001459190620005a7565b5060408051808201909152601b81527f52657665616c2070726963652065706f636820746f6f206c6f6e6700000000006020820152858510620002df5760405162461bcd60e51b8152600401620001459190620005a7565b508284870111156040518060400160405280601b81526020017f5265776172642065706f636820737461727420746f6f20736f6f6e0000000000815250906200033d5760405162461bcd60e51b8152600401620001459190620005a7565b50848685850303816200034c57fe5b0660001460405180606001604052806024815260200162005a2b60249139906200038b5760405162461bcd60e51b8152600401620001459190620005a7565b508482816200039657fe5b0660001460405180606001604052806027815260200162005a046027913990620003d55760405162461bcd60e51b8152600401620001459190620005a7565b5061010082905261012083905261014081905282820160135560a086905260c085905260e0849052601283905584868403816200040e57fe5b04601155505050505060609190911b6001600160601b031916610160525062000616915050565b600154600160a01b900460ff161562000495576040805162461bcd60e51b815260206004820152601460248201527f696e697469616c6973656420213d2066616c7365000000000000000000000000604482015290519081900360640190fd5b6001805460ff60a01b1916600160a01b179055600054604080516001600160a01b039283168152918316602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a1600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b60008060008060008060008060006101208a8c03121562000538578485fd5b89516200054581620005fd565b60208b01519099506200055881620005fd565b60408b01519098506200056b81620005fd565b8097505060608a0151955060808a0151945060a08a0151935060c08a0151925060e08a015191506101008a015190509295985092959850929598565b6000602080835283518082850152825b81811015620005d557858101830151858201604001528201620005b7565b81811115620005e75783604083870101525b50601f01601f1916929092016040019392505050565b6001600160a01b03811681146200061357600080fd5b50565b60805160601c60a05160c05160e0516101005161012051610140516101605160601c6152fc620006e360003980610545528061241952806138ca5250806108b5528061337652508061123a525080610e155280612b3f528061356052508061061b528061110f52806127ea52806143185250806105fa52806110de52806127c85280612fc05280613dd65280613ffb52806142f55250806105d952806110bd52806127a65280613df75280613fd652806142d05250806109ab52806112165280611aec52506152fc6000f3fe608060405234801561001057600080fd5b50600436106102745760003560e01c806393a7902511610151578063ce69f833116100c3578063e7a0d01e11610087578063e7a0d01e146104cf578063e7c830d4146104e2578063e847ae1e146104ea578063f2edab5a146104fd578063f937d6ad14610510578063ff882fbb1461051857610274565b8063ce69f8331461046c578063d38bfff414610481578063e06174e414610494578063e22fdece146104b1578063e371aef0146104b957610274565b8063a795f40911610115578063a795f40914610405578063a93a6f4214610418578063af946af71461042b578063c0ffe9081461043e578063c2b0d47b14610451578063c373a08e1461045957610274565b806393a79025146103b65780639d6a890f146103cf578063a1077532146103e2578063a578f55b146103ea578063a670ff87146103f257610274565b80634eac870f116101ea57806369b11ac6116101ae57806369b11ac6146103655780636b65cc341461036d5780636d0e8c34146103805780636ea0aa311461038857806385f3c9c91461039b5780639131205b146103a357610274565b80634eac870f146103305780635aa6e675146103385780635d36b1901461034057806360f2c5b21461034857806360f7ac971461035d57610274565b8063144e15911161023c578063144e1591146102c65780632663f1b4146102dd5780632b3c41a4146102f05780632fd8eb7d1461030957806338b5f869146103115780634b48dd5e1461031957610274565b806302fb0c5e14610279578063047fc9aa146102975780630e063d7d146102ac5780630f15f4c0146102b45780630f4ef8a6146102be575b600080fd5b61028161052b565b60405161028e9190614e8e565b60405180910390f35b61029f610534565b60405161028e9190614cde565b61029f610543565b6102bc610568565b005b61029f6105c8565b6102ce6105d7565b60405161028e93929190614f8f565b6102bc6102eb3660046145d4565b61063f565b6102f861069e565b60405161028e959493929190614def565b61029f6106d9565b61029f6106e8565b6103216106f7565b60405161028e93929190614e99565b61029f6107d3565b61029f6107e2565b6102bc6107f1565b6103506108b3565b60405161028e9190614f78565b61029f6108d7565b6103506108e6565b6102bc61037b366004614a2b565b6108eb565b61028161099e565b6102f8610396366004614ae1565b610aaf565b610350610e13565b6102bc6103b1366004614b25565b610e37565b6103be6110a7565b60405161028e959493929190614fa5565b6102bc6103dd3660046145d4565b61113a565b61029f611214565b610350611238565b6102bc6104003660046145d4565b61125c565b6102ce610413366004614ab1565b611486565b6102bc6104263660046148f3565b6114b9565b6102bc6104393660046149a0565b611649565b6102bc61044c3660046145f7565b61175a565b61029f611933565b6102bc6104673660046145d4565b611942565b6104746119e7565b60405161028e9190614ddc565b6102bc61048f3660046145d4565b6119f6565b61049c611ab8565b60405161028e9998979695949392919061500c565b610281611adf565b6104c1611bbd565b60405161028e929190614f56565b6102bc6104dd3660046149d4565b611bde565b6103506122db565b6102bc6104f8366004614883565b61233e565b61035061050b366004614ab1565b6123ee565b61029f612417565b6102bc610526366004614869565b61243b565b60055460ff1681565b601a546001600160a01b031681565b7f00000000000000000000000000000000000000000000000000000000000000005b90565b6000546001600160a01b031633146105b9576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b6005805460ff19166001179055565b6017546001600160a01b031681565b7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000909192565b6000546001600160a01b03163314610690576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b61069b8160016124de565b50565b6004546060908190819081906000906106c890600160c01b90046001600160401b03166001610aaf565b945094509450945094509091929394565b6007546001600160a01b031681565b6018546001600160a01b031681565b601b54600160a81b900460ff1660608061070f612abc565b8051909250806001600160401b038111801561072a57600080fd5b50604051908082528060200260200182016040528015610754578160200160208202803683370190505b50915060005b818110156107cc57601c600085838151811061077257fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a900460ff168382815181106107b457fe5b9115156020928302919091019091015260010161075a565b5050909192565b601b546001600160a01b031681565b6000546001600160a01b031681565b6001546001600160a01b03163314610840576040805162461bcd60e51b815260206004820152600d60248201526c1b9bdd0818db185a5b585a5b9d609a1b604482015290519081900360640190fd5b600054600154604080516001600160a01b03938416815292909116602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b7f000000000000000000000000000000000000000000000000000000000000000090565b6001546001600160a01b031681565b600581565b6000546001600160a01b0316331461093c576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b60405163d0d552dd60e01b81526001600160a01b0383169063d0d552dd90610968908490600401614cde565b600060405180830381600087803b15801561098257600080fd5b505af1158015610996573d6000803e3d6000fd5b505050505050565b6000336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a11576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b60055460ff16610a2357506000610565565b600654610a3757610a32612b3d565b610aa9565b601b54600160a01b900460ff168015610a5257504260125411155b15610a5f57610a32612cb2565b601b54600160a01b900460ff16158015610a7b57504260135411155b15610a9857610a88613293565b610a90613588565b610a32613717565b4260125411610aa957610aa96138a8565b50600190565b606080606080600060038054905087106040518060400160405280601081526020016f0e6e8c2e4e840d2dcc8caf040d0d2ced60831b81525090610b0f5760405162461bcd60e51b8152600401610b069190614f43565b60405180910390fd5b506003546000908888011115610b2a57600354889003610b2c565b865b9050806001600160401b0381118015610b4457600080fd5b50604051908082528060200260200182016040528015610b6e578160200160208202803683370190505b509550806001600160401b0381118015610b8757600080fd5b50604051908082528060200260200182016040528015610bb1578160200160208202803683370190505b509450806001600160401b0381118015610bca57600080fd5b50604051908082528060200260200182016040528015610bfe57816020015b6060815260200190600190039081610be95790505b509350806001600160401b0381118015610c1757600080fd5b50604051908082528060200260200182016040528015610c41578160200160208202803683370190505b50925060005b81811015610df75760006003828b0181548110610c6057fe5b6000918252602080832090910154808352600290915260409091205489519192506001600160c01b031690899084908110610c9757fe5b6020026020010181815250506002600082815260200190815260200160002060000160189054906101000a90046001600160401b03166001600160401b0316878381518110610ce257fe5b602090810291909101810191909152600082815260028083526040918290208101805483516001821615610100026000190190911692909204601f81018590048502830185019093528282529092909190830182828015610d845780601f10610d5957610100808354040283529160200191610d84565b820191906000526020600020905b815481529060010190602001808311610d6757829003601f168201915b5050505050868381518110610d9557fe5b60200260200101819052506002600082815260200190815260200160002060010160009054906101000a90046001600160a01b0316858381518110610dd657fe5b6001600160a01b039092166020928302919091019091015250600101610c47565b50506004549497939650919450926001600160c01b0316919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b03163314610e88576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b60408051808201909152601381527211dbdd8b881c185c985b5cc81a5b9d985b1a59606a1b602082015288610ed05760405162461bcd60e51b8152600401610b069190614f43565b5060408051808201909152601381527211dbdd8b881c185c985b5cc81a5b9d985b1a59606a1b602082015287610f195760405162461bcd60e51b8152600401610b069190614f43565b5060408051808201909152601381527211dbdd8b881c185c985b5cc81a5b9d985b1a59606a1b602082015286861015610f655760405162461bcd60e51b8152600401610b069190614f43565b5060408051808201909152601381527211dbdd8b881c185c985b5cc81a5b9d985b1a59606a1b6020820152612710851115610fb35760405162461bcd60e51b8152600401610b069190614f43565b5060408051808201909152601381527211dbdd8b881c185c985b5cc81a5b9d985b1a59606a1b60208201526127108411156110015760405162461bcd60e51b8152600401610b069190614f43565b5060408051808201909152601581527414995dd85c9908195e1c1a5c9e481a5b9d985b1a59605a1b60208201528261104c5760405162461bcd60e51b8152600401610b069190614f43565b5060058151111560405180606001604052806025815260200161519c602591399061108a5760405162461bcd60e51b8152600401610b069190614f43565b5061109d60088989898989898989613bd9565b5050505050505050565b6000806000806000806110b8613dd2565b9550507f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000808702820195506001870102019250507f000000000000000000000000000000000000000000000000000000000000000082019050429091929394565b600154600160a01b900460ff1615611190576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b6001805460ff60a01b1916600160a01b179055600054604080516001600160a01b039283168152918316602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a1600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b031633146112ad576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b6000601860009054906101000a90046001600160a01b03166001600160a01b031663e848da30836001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561130c57600080fd5b505afa158015611320573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113489190810190614a7f565b6040518263ffffffff1660e01b81526004016113649190614f43565b60206040518083038186803b15801561137c57600080fd5b505afa158015611390573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b49190614ac9565b60195460405163d873617160e01b81529192506001600160a01b03169063d8736171906113e5908490600401614f78565b600060405180830381600087803b1580156113ff57600080fd5b505af1158015611413573d6000803e3d6000fd5b505060185460405163a670ff8760e01b81526001600160a01b03909116925063a670ff879150611447908590600401614cde565b600060405180830381600087803b15801561146157600080fd5b505af1158015611475573d6000803e3d6000fd5b5050505061148282613e25565b5050565b6006818154811061149657600080fd5b600091825260209091206003909102018054600182015460029092015490925083565b6000546001600160a01b0316331461150a576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b80516040805180820190915260168152754173736574206674736f73206c69737420656d70747960501b6020820152816115575760405162461bcd60e51b8152600401610b069190614f43565b5060005b818110156115dc5782818151811061156f57fe5b60200260200101516001600160a01b0316846001600160a01b031614156115d45760408051808201825260168152756674736f20657175616c73206173736574206674736f60501b6020820152905162461bcd60e51b8152610b069190600401614f43565b60010161155b565b506115e682613efc565b60405163098fef7160e11b81526001600160a01b0384169063131fdee290611612908590600401614ddc565b600060405180830381600087803b15801561162c57600080fd5b505af1158015611640573d6000803e3d6000fd5b50505050505050565b6000546001600160a01b0316331461169a576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b6001600160a01b0382166000908152601560209081526040918290205482518084019093526009835268139bdd08199bdd5b9960ba1b9183019190915260ff166116f75760405162461bcd60e51b8152600401610b069190614f43565b506001600160a01b0382166000908152601c602052604090819020805460ff1916831515179055517f24462ede4d3e8e5a69fecec6290d42a311016ca752216d9a3d681e284791b7ac9061174e9084908490614ee9565b60405180910390a15050565b6000828260405160200161176f929190614d0b565b60408051601f198184030181528282528051602091820120600081815260029092529190208054436001600160c01b038181166001600160401b03600160c01b80860482166001019091160291909316176001600160c01b031916919091179091559092507f1a601cf5e0efbd558b2778b7389af04741d1c49bcab104c40daa2da194593617916118039186918690614d2f565b60405180910390a1600480546001600160c01b0319811660016001600160c01b03928316810190921617909155600082815260026020526040902054600160c01b90046001600160401b0316111561185b5750611482565b6003805460018082019092557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01829055600082815260026020818152604090922092830180546001600160a01b0319166001600160a01b03881617905584516118cb9390910191850190614417565b50600354600091825260026020526040909120600101805467ffffffffffffffff60a01b1916600160a01b6000199093016001600160401b0390811684029190911791829055600480546001600160c01b03169390920416600160c01b029190911790555050565b6019546001600160a01b031681565b6000546001600160a01b03163314611993576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600180546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f1f95fb40be3a947982072902a887b521248d1d8931a39eb38f84f4d6fd758b699181900360200190a150565b60606119f1612abc565b905090565b6000546001600160a01b03163314611a47576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600054604080516001600160a01b039283168152918316602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a1600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b600854600954600a54600b54600c54600d54600e5460105460ff8082169161010090041689565b6000336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611b52576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b601b54600160a81b900460ff16611bb757601b805460ff60a81b1916600160a81b1790556040517f217a37a37fc40a97159886f80c3d45986e6fc4330ce6ad7283478b5e5ab705bc90611ba790600190614e8e565b60405180910390a1506001610565565b50600090565b6004546001600160c01b03811690600160c01b90046001600160401b031682565b6000546001600160a01b03163314611c2f576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b826001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015611c6857600080fd5b505afa158015611c7c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ca49190810190614a7f565b604051602001611cb49190614f43565b60405160208183030381529060405280519060200120846001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015611d0357600080fd5b505afa158015611d17573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611d3f9190810190614a7f565b604051602001611d4f9190614f43565b60405160208183030381529060405280519060200120146040518060400160405280601781526020017f4654534f2073796d626f6c73206d757374206d6174636800000000000000000081525090611dba5760405162461bcd60e51b8152600401610b069190614f43565b506000611dc5612abc565b805190915060005b81811015611e0f57866001600160a01b0316838281518110611deb57fe5b60200260200101516001600160a01b03161415611e0757611e0f565b600101611dcd565b81811415611e4e576040805180820182526009815268139bdd08199bdd5b9960ba1b6020820152905162461bcd60e51b8152610b069190600401614f43565b8415611f2f57600080886001600160a01b031663eb91d37e6040518163ffffffff1660e01b8152600401604080518083038186803b158015611e8f57600080fd5b505afa158015611ea3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ec79190614b02565b60405163306ba25360e01b815291935091506001600160a01b0389169063306ba25390611efa9085908590600401614f81565b600060405180830381600087803b158015611f1457600080fd5b505af1158015611f28573d6000803e3d6000fd5b5050505050505b8315612100576000876001600160a01b0316635c222bad6040518163ffffffff1660e01b815260040160206040518083038186803b158015611f7057600080fd5b505afa158015611f84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa89190614a63565b90506001600160a01b0381161561201c5760405163d0d552dd60e01b81526001600160a01b0388169063d0d552dd90611fe5908490600401614cde565b600060405180830381600087803b158015611fff57600080fd5b505af1158015612013573d6000803e3d6000fd5b505050506120fe565b6000886001600160a01b03166318931c356040518163ffffffff1660e01b815260040160006040518083038186803b15801561205757600080fd5b505afa15801561206b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120939190810190614749565b8051909150156120fc5760405163098fef7160e11b81526001600160a01b0389169063131fdee2906120c9908490600401614ddc565b600060405180830381600087803b1580156120e357600080fd5b505af11580156120f7573d6000803e3d6000fd5b505050505b505b505b61210b8660006124de565b6000612115612abc565b805190915060005b818110156122c657600083828151811061213357fe5b602002602001015190508a6001600160a01b0316816001600160a01b0316141561215d57506122be565b6000816001600160a01b03166318931c356040518163ffffffff1660e01b815260040160006040518083038186803b15801561219857600080fd5b505afa1580156121ac573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526121d49190810190614749565b805190915080156122ba576000805b82811015612252578e6001600160a01b031684828151811061220157fe5b60200260200101516001600160a01b0316141561224a578d84828151811061222557fe5b60200260200101906001600160a01b031690816001600160a01b031681525050600191505b6001016121e3565b5080156122b85760405163098fef7160e11b81526001600160a01b0385169063131fdee290612285908690600401614ddc565b600060405180830381600087803b15801561229f57600080fd5b505af11580156122b3573d6000803e3d6000fd5b505050505b505b5050505b60010161211d565b506122d089613e25565b505050505050505050565b6006546040805180820190915260208082527f5265776172642065706f6368206e6f7420696e697469616c697a6564207965749082015260009190816123345760405162461bcd60e51b8152600401610b069190614f43565b5060001901905090565b6000546001600160a01b0316331461238f576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b601780546001600160a01b03199081166001600160a01b03978816179091556018805482169587169590951790945560198054851693861693909317909255601a80548416918516919091179055601b80549092169216919091179055565b6000600682815481106123fd57fe5b90600052602060002090600302016000015490505b919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b0316331461248c576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b601b805460ff60a81b1916600160a81b831515021790556040517f217a37a37fc40a97159886f80c3d45986e6fc4330ce6ad7283478b5e5ab705bc906124d3908390614e8e565b60405180910390a150565b60105460408051808201909152601b81527f476f762e20706172616d73206e6f7420696e697469616c697a65640000000000602082015290610100900460ff1661253b5760405162461bcd60e51b8152600401610b069190614f43565b506125b9826001600160a01b03166318931c356040518163ffffffff1660e01b815260040160006040518083038186803b15801561257857600080fd5b505afa15801561258c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125b49190810190614749565b613efc565b8015612782576000826001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b1580156125fa57600080fd5b505afa15801561260e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126369190810190614a7f565b6040516020016126469190614f43565b6040516020818303038152906040528051906020012090506000601860009054906101000a90046001600160a01b03166001600160a01b031663ce1c0e4d6040518163ffffffff1660e01b815260040160006040518083038186803b1580156126ae57600080fd5b505afa1580156126c2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126ea91908101906147e1565b80519091505b801561277e57806001900390508282828151811061270a57fe5b60200260200101516040516020016127229190614f43565b60405160208183030381529060405280519060200120141561277957604080518082018252600d81526c105b1c9958591e481859191959609a1b6020820152905162461bcd60e51b8152610b069190600401614f43565b6126f0565b5050505b604051630bc29bcf60e21b81526001600160a01b03831690632f0a6f3c90612812907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000000090600401614f8f565b600060405180830381600087803b15801561282c57600080fd5b505af1158015612840573d6000803e3d6000fd5b50506006541591506128d2905057600680546001600160a01b0384169163e536f39691600019810190811061287157fe5b9060005260206000209060030201600001546040518263ffffffff1660e01b815260040161289f9190614f78565b600060405180830381600087803b1580156128b957600080fd5b505af11580156128cd573d6000803e3d6000fd5b505050505b600854600954600a54600b54600c54600d5460405163f7dba1f560e01b81526001600160a01b0389169663f7dba1f596612919969195909491939092600f90600401614fc8565b600060405180830381600087803b15801561293357600080fd5b505af1158015612947573d6000803e3d6000fd5b5050601b546001600160a01b038086166000908152601660209081526040808320805460ff600160a01b90970496909616151560ff19968716179055601590915280822080549094166001179093556018549251630998fc6d60e21b815290945091169150632663f1b4906129c0908690600401614cde565b602060405180830381600087803b1580156129da57600080fd5b505af11580156129ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a129190614ac9565b90508115612a7d57601954604051630d15c16960e21b81526001600160a01b039091169063345705a490612a4a908490600401614f78565b600060405180830381600087803b158015612a6457600080fd5b505af1158015612a78573d6000803e3d6000fd5b505050505b7fa0985424f2efdcae4b57a7c84bbf0a0b19f93054f21e9eb1cfcd5a59813fe1da836001604051612aaf929190614ee9565b60405180910390a1505050565b60185460408051635200305d60e11b815290516060926001600160a01b03169163a40060ba916004808301926000929190829003018186803b158015612b0157600080fd5b505afa158015612b15573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119f19190810190614749565b7f0000000000000000000000000000000000000000000000000000000000000000601354034210612cb0576000612b72612abc565b8051604080516060810182524360001981018252602082019081524292820192835260068054600181018255600091825283517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f60039092029182015591517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4083015592517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d41909101559293509091905b82811015612cab57838181518110612c3757fe5b60200260200101516001600160a01b031663e536f39683600001516040518263ffffffff1660e01b8152600401612c6e9190614f78565b600060405180830381600087803b158015612c8857600080fd5b505af1158015612c9c573d6000803e3d6000fd5b50505050806001019050612c23565b505050505b565b6000612cbc612abc565b80519091508015801590612cda5750601b54600160a81b900460ff16155b156131ae576007546000906001600160a01b0316612d2e57814442604051602001612d06929190614f81565b6040516020818303038152906040528051906020012060001c81612d2657fe5b069050612e04565b6000805b83811015612dca57848181518110612d4657fe5b60200260200101516001600160a01b031663d89601fd6040518163ffffffff1660e01b815260040160206040518083038186803b158015612d8657600080fd5b505afa158015612d9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dbe9190614ac9565b90910190600101612d32565b50828142604051602001612ddf929190614f81565b6040516020818303038152906040528051906020012060001c81612dff57fe5b069150505b60608060008080805b87811015612f8c5760008882890181612e2257fe5b06905060008a8281518110612e3357fe5b6020908102919091018101516001600160a01b0381166000908152601690925260409091205490915060ff1615612e89576001600160a01b03166000908152601660205260409020805460ff1916905550612f84565b6011546040516340462a2d60e01b81526001600160a01b038316916340462a2d91612eba9190891590600401614f33565b600060405180830381600087803b158015612ed457600080fd5b505af1925050508015612f0957506040513d6000823e601f3d908101601f19168201604052612f06919081019061467e565b60015b612f5757612f156150e2565b80612f205750612f30565b612f2a8282613f83565b50612f52565b612f528160405180606001604052806022815260200161520f60229139613f83565b612f81565b87158015612f66575060008351115b15612f7d5791995097509550600194509250828787875b5050505b50505b600101612e0d565b506000612f976122db565b9050821561314d576017546011546001600160a01b039091169063a9b79e1790889088908890877f0000000000000000000000000000000000000000000000000000000000000000886001612feb85613fd4565b0360068b81548110612ff957fe5b9060005260206000209060030201600001546040518a63ffffffff1660e01b815260040161302f99989796959493929190614d5f565b600060405180830381600087803b15801561304957600080fd5b505af192505050801561305a575060015b61314d576130666150e2565b8061307157506130c8565b7f175a1d13d190d6a1e14461c214b3ecf6118b828797750b7bffd7c4f2c1eba54c836011546040516130a4929190614cf2565b60405180910390a16017546130c2906001600160a01b03168261175a565b5061314d565b7f175a1d13d190d6a1e14461c214b3ecf6118b828797750b7bffd7c4f2c1eba54c826011546040516130fb929190614cf2565b60405180910390a16017546040805180820190915260208082527f756e6b6e6f776e206661696c2e206469737472696275746520726577617264739082015261314d916001600160a01b03169061175a565b600780546001600160a01b0319166001600160a01b0384161790556040517f98b050a4042fbd1b89934ef40b9342e593f15081a348af940573a0179031f4ad9061319a9084908490614cf2565b60405180910390a150505050505050613282565b60005b8181101561322f5760008382815181106131c757fe5b6020908102919091018101516001600160a01b0381166000908152601690925260409091205490915060ff161561321c576001600160a01b03166000908152601660205260409020805460ff19169055613227565b61322581614021565b505b6001016131b1565b50600780546001600160a01b03191690557f98b050a4042fbd1b89934ef40b9342e593f15081a348af940573a0179031f4ad600061326b6122db565b604051613279929190614cf2565b60405180910390a15b5050601b805460ff60a01b19169055565b600061329d612abc565b80519091504281156133465760005b82811015613344578381815181106132c057fe5b60200260200101516001600160a01b031663d89601fd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561330057600080fd5b505afa158015613314573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133389190614ac9565b909101906001016132ac565b505b806040516020016133579190614f78565b6040516020818303038152906040528051906020012060001c905060007f0000000000000000000000000000000000000000000000000000000000000000600661339f6122db565b815481106133a957fe5b9060005260206000209060030201600101544303816133c457fe5b049050806133d0575060015b60008183816133db57fe5b069050806133e7575060015b60408051606081018252438381038252602082019081524292820192835260068054600181018255600091825283517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f60039092029182015591517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4083015592517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4190910155905b85811015613518578681815181106134a357fe5b60200260200101516001600160a01b031663e536f39683600001516040518263ffffffff1660e01b81526004016134da9190614f78565b600060405180830381600087803b1580156134f457600080fd5b505af1158015613508573d6000803e3d6000fd5b50506001909201915061348f9050565b50805160208201516040517f1813f880dc24666c8b69c9d771a487ea620a27fde1514be3112847056c0c532292613550929091614f81565b60405180910390a15050601380547f000000000000000000000000000000000000000000000000000000000000000001905550505050565b60006135926122db565b600e5490915042035b816014541080156135cf5750806006601454600101815481106135ba57fe5b90600052602060002090600302016002015411155b1561148257601754601454604051636b60edf760e11b81526001600160a01b039092169163d6c1dbee9161360591600401614f78565b600060405180830381600087803b15801561361f57600080fd5b505af1925050508015613630575060015b6137095761363c6150e2565b80613647575061369c565b7fa819a21065ad87bdde9e6d398d3213e0d3634afd87aceb7092236483f5d7ca8d6014546040516136789190614f78565b60405180910390a1601754613696906001600160a01b03168261175a565b50611482565b7fa819a21065ad87bdde9e6d398d3213e0d3634afd87aceb7092236483f5d7ca8d6014546040516136cd9190614f78565b60405180910390a160175460408051606081019091526021808252613704926001600160a01b03169190615231602083013961175a565b611482565b60148054600101905561359b565b601b546001600160a01b0316613755576040517f9a880a9e2a01928f1a99d7b0e2ea1147f52e2eb381f8d9345c110932d57bce8d90600090a1612cb0565b600060066014548154811061376657fe5b6000918252602090912060039091020154601b5460405163cbc31cf760e01b81529192506001600160a01b03169063cbc31cf7906137a8908490600401614f78565b600060405180830381600087803b1580156137c257600080fd5b505af19250505080156137d3575060015b61069b576137df6150e2565b806137ea575061383d565b7f9f874ea08c7014cce74622bfe71434f81aba7598ad65126a6aea86945bdfa18d826040516138199190614f78565b60405180910390a1601b54613837906001600160a01b03168261175a565b506138a3565b7f9f874ea08c7014cce74622bfe71434f81aba7598ad65126a6aea86945bdfa18d8160405161386c9190614f78565b60405180910390a1601b54604080516060810190915260238082526138a3926001600160a01b031691906151c1602083013961175a565b61069b565b60105460ff161561393357604051639ec2b58160e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690639ec2b5819061390090600f90600401614dc9565b600060405180830381600087803b15801561391a57600080fd5b505af115801561392e573d6000803e3d6000fd5b505050505b600061393d612abc565b80519091506000811580159061395d5750601b54600160a81b900460ff16155b15613a0f576006805460009190600019810190811061397857fe5b6000918252602090912060039091020154601a546040516237b08960e41b81529192506001600160a01b03169063037b0890906139b9908490600401614f78565b602060405180830381600087803b1580156139d357600080fd5b505af11580156139e7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a0b9190614ac9565b9150505b60005b82811015613b98576000848281518110613a2857fe5b602090810291909101015160105490915060ff1615613abb57600854600954600a54600b54600c54600d5460405163f7dba1f560e01b81526001600160a01b0388169663f7dba1f596613a88969195909491939092600f90600401614fc8565b600060405180830381600087803b158015613aa257600080fd5b505af1158015613ab6573d6000803e3d6000fd5b505050505b806001600160a01b031663f670ebe384601b60159054906101000a900460ff1680613afe57506001600160a01b0384166000908152601c602052604090205460ff165b6040518363ffffffff1660e01b8152600401613b1b929190614f33565b600060405180830381600087803b158015613b3557600080fd5b505af1925050508015613b46575060015b613b8f57613b526150e2565b80613b5d5750613b6d565b613b6782826140bd565b50613b8f565b613b8f8160405180606001604052806023815260200161527e602391396140bd565b50600101613a12565b506010805460ff191690556000613bad613dd2565b60118190559050613bbd816142ce565b6012555050601b805460ff60a01b1916600160a01b1790555050565b88548814613bf45760088901805460ff191660011790558789555b86896001015414613c175760088901805460ff1916600190811790915589018790555b85896002015414613c395760088901805460ff19166001179055600289018690555b84896003015414613c5b5760088901805460ff19166001179055600389018590555b83896004015414613c7d5760088901805460ff19166001179055600489018490555b82896005015414613c9f5760088901805460ff19166001179055600589018390555b81896006015414613cc15760088901805460ff19166001179055600689018290555b805160078a015414613cf7578051613ce29060078b019060208401906144a3565b5060088901805460ff19166001179055613db6565b60005b8151811015613db457818181518110613d0f57fe5b60200260200101516001600160a01b03168a6007018281548110613d2f57fe5b6000918252602090912001546001600160a01b031614613dac5760088a01805460ff191660011790558151829082908110613d6657fe5b60200260200101518a6007018281548110613d7d57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b600101613cfa565b505b5050506008909501805461ff0019166101001790555050505050565b60007f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000420381613e1f57fe5b04905090565b806001600160a01b031663555989da6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613e6057600080fd5b505af1158015613e74573d6000803e3d6000fd5b5050506001600160a01b0382166000908152601c60209081526040808320805460ff199081169091556016835281842080548216905560159092529091208054909116905550613eca613ec5612abc565b61433d565b7fa0985424f2efdcae4b57a7c84bbf0a0b19f93054f21e9eb1cfcd5a59813fe1da8160006040516124d3929190614ee9565b805160005b81811015613f7e5760156000848381518110613f1957fe5b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff16613f76576040518060600160405280602681526020016152a16026913960405162461bcd60e51b8152600401610b069190614f43565b600101613f01565b505050565b7f79f4c7cc43bfb79f5a3aad0d92f75b6fed7db061bb5cc2580a01c8132711b881826011546001604051613fb993929190614f04565b60405180910390a1613fcb828261175a565b61148282614021565b7f0000000000000000000000000000000000000000000000000000000000000000600182017f00000000000000000000000000000000000000000000000000000000000000000201919050565b601154604051639de6f92760e01b81526001600160a01b03831691639de6f9279161404f9190600401614f78565b600060405180830381600087803b15801561406957600080fd5b505af192505050801561407a575060015b61069b576140866150e2565b80614091575061409b565b61383782826143a1565b6138a3816040518060600160405280602b81526020016151e4602b91396143a1565b7f61156899176547b8075bfa81fa2996c6057ce9c71320884b11c0179d9dc2e462826140e7613dd2565b6040516140f5929190614cf2565b60405180910390a1614107828261175a565b601b54600160a81b900460ff168061413757506001600160a01b0382166000908152601c602052604090205460ff165b15614164576001600160a01b0382166000908152601660205260409020805460ff19166001179055611482565b60405163f670ebe360e01b81526001600160a01b0383169063f670ebe39061419490600090600190600401614f33565b600060405180830381600087803b1580156141ae57600080fd5b505af19250505080156141bf575060015b611482576141cb6150e2565b806141d65750614249565b6001600160a01b0383166000908152601660205260409020805460ff191660011790557f61156899176547b8075bfa81fa2996c6057ce9c71320884b11c0179d9dc2e46283614223613dd2565b604051614231929190614cf2565b60405180910390a1614243838261175a565b50613704565b6001600160a01b0382166000908152601660205260409020805460ff191660011790557f61156899176547b8075bfa81fa2996c6057ce9c71320884b11c0179d9dc2e46282614296613dd2565b6040516142a4929190614cf2565b60405180910390a1613704826040518060600160405280602c8152602001615252602c913961175a565b7f0000000000000000000000000000000000000000000000000000000000000000600182017f000000000000000000000000000000000000000000000000000000000000000002017f000000000000000000000000000000000000000000000000000000000000000001919050565b805160005b81811015613f7e5761439983828151811061435957fe5b60200260200101516001600160a01b03166318931c356040518163ffffffff1660e01b815260040160006040518083038186803b15801561257857600080fd5b600101614342565b7f79f4c7cc43bfb79f5a3aad0d92f75b6fed7db061bb5cc2580a01c8132711b8818260115460026040516143d793929190614f04565b60405180910390a16143e9828261175a565b60115460405163974d7a6b60e01b81526001600160a01b0384169163974d7a6b916109689190600401614f78565b828054600181600116156101000203166002900490600052602060002090601f01602090048101928261444d5760008555614493565b82601f1061446657805160ff1916838001178555614493565b82800160010185558215614493579182015b82811115614493578251825591602001919060010190614478565b5061449f9291506144f8565b5090565b828054828255906000526020600020908101928215614493579160200282015b8281111561449357825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906144c3565b5b8082111561449f57600081556001016144f9565b600082601f83011261451d578081fd5b8151602061453261452d83615072565b61504f565b828152818101908583018385028701840188101561454e578586fd5b855b8581101561456c57815184529284019290840190600101614550565b5090979650505050505050565b8035801515811461241257600080fd5b600082601f830112614599578081fd5b81516145a761452d8261508f565b8181528460208386010111156145bb578283fd5b6145cc8260208301602087016150b0565b949350505050565b6000602082840312156145e5578081fd5b81356145f081615186565b9392505050565b60008060408385031215614609578081fd5b823561461481615186565b915060208301356001600160401b0381111561462e578182fd5b8301601f8101851361463e578182fd5b803561464c61452d8261508f565b818152866020838501011115614660578384fd5b81602084016020830137908101602001929092525090939092509050565b600080600060608486031215614692578081fd5b83516001600160401b03808211156146a8578283fd5b818601915086601f8301126146bb578283fd5b815160206146cb61452d83615072565b82815281810190858301838502870184018c10156146e7578788fd5b8796505b848710156147125780516146fe81615186565b8352600196909601959183019183016146eb565b509189015191975090935050508082111561472b578283fd5b506147388682870161450d565b925050604084015190509250925092565b6000602080838503121561475b578182fd5b82516001600160401b03811115614770578283fd5b8301601f81018513614780578283fd5b805161478e61452d82615072565b81815283810190838501858402850186018910156147aa578687fd5b8694505b838510156147d55780516147c181615186565b8352600194909401939185019185016147ae565b50979650505050505050565b600060208083850312156147f3578182fd5b82516001600160401b03811115614808578283fd5b8301601f81018513614818578283fd5b805161482661452d82615072565b81815283810190838501865b8481101561485b576148498a888451890101614589565b84529286019290860190600101614832565b509098975050505050505050565b60006020828403121561487a578081fd5b6145f082614579565b600080600080600060a0868803121561489a578283fd5b85356148a581615186565b945060208601356148b581615186565b935060408601356148c581615186565b925060608601356148d581615186565b915060808601356148e581615186565b809150509295509295909350565b60008060408385031215614905578182fd5b823561491081615186565b91506020838101356001600160401b0381111561492b578283fd5b8401601f8101861361493b578283fd5b803561494961452d82615072565b81815283810190838501858402850186018a1015614965578687fd5b8694505b8385101561499057803561497c81615186565b835260019490940193918501918501614969565b5080955050505050509250929050565b600080604083850312156149b2578182fd5b82356149bd81615186565b91506149cb60208401614579565b90509250929050565b600080600080608085870312156149e9578182fd5b84356149f481615186565b93506020850135614a0481615186565b9250614a1260408601614579565b9150614a2060608601614579565b905092959194509250565b60008060408385031215614a3d578182fd5b8235614a4881615186565b91506020830135614a5881615186565b809150509250929050565b600060208284031215614a74578081fd5b81516145f081615186565b600060208284031215614a90578081fd5b81516001600160401b03811115614aa5578182fd5b6145cc84828501614589565b600060208284031215614ac2578081fd5b5035919050565b600060208284031215614ada578081fd5b5051919050565b60008060408385031215614af3578182fd5b50508035926020909101359150565b60008060408385031215614b14578182fd5b505080516020909101519092909150565b600080600080600080600080610100898b031215614b41578586fd5b883597506020808a0135975060408a0135965060608a0135955060808a0135945060a08a0135935060c08a0135925060e08a01356001600160401b03811115614b88578283fd5b8a01601f81018c13614b98578283fd5b8035614ba661452d82615072565b8082825284820191508484018f868786028701011115614bc4578687fd5b8694505b83851015614bef578035614bdb81615186565b835260019490940193918501918501614bc8565b5080955050505050509295985092959890939650565b6000815180845260208085019450808401835b83811015614c3d5781516001600160a01b031687529582019590820190600101614c18565b509495945050505050565b6000815480845260208085019450838352808320835b83811015614c3d5781546001600160a01b031687529582019560019182019101614c5e565b6000815180845260208085019450808401835b83811015614c3d57815187529582019590820190600101614c96565b60008151808452614cca8160208601602086016150b0565b601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03831681526040602082018190526000906145cc90830184614cb2565b600060018060a01b038516825283602083015260606040830152614d566060830184614cb2565b95945050505050565b6000610120808352614d738184018d614c05565b90508281036020840152614d87818c614c83565b604084019a909a52505060608101969096526001600160a01b0394909416608086015260a085019290925260c084015260e08301526101009091015292915050565b6000602082526145f06020830184614c48565b6000602082526145f06020830184614c05565b600060a08252614e0260a0830188614c83565b602083820381850152614e158289614c83565b848103604086015287518082529092508183019082810284018301838a01865b83811015614e6357601f19878403018552614e51838351614cb2565b94860194925090850190600101614e35565b50508681036060880152614e77818a614c05565b955050505050508260808301529695505050505050565b901515815260200190565b600084151582526020606081840152614eb56060840186614c05565b8381036040850152845180825282860191830190845b8181101561485b578351151583529284019291840191600101614ecb565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b0384168152602081018390526060810160068310614f2557fe5b826040830152949350505050565b9182521515602082015260400190565b6000602082526145f06020830184614cb2565b6001600160c01b039290921682526001600160401b0316602082015260400190565b90815260200190565b918252602082015260400190565b9283526020830191909152604082015260600190565b948552602085019390935260408401919091526060830152608082015260a00190565b60008882528760208301528660408301528560608301528460808301528360a083015260e060c0830152614fff60e0830184614c48565b9998505050505050505050565b988952602089019790975260408801959095526060870193909352608086019190915260a085015260c0840152151560e083015215156101008201526101200190565b6040518181016001600160401b038111828210171561506a57fe5b604052919050565b60006001600160401b0382111561508557fe5b5060209081020190565b60006001600160401b038211156150a257fe5b50601f01601f191660200190565b60005b838110156150cb5781810151838201526020016150b3565b83811115612cab5750506000910152565b60e01c90565b600060443d10156150f257610565565b600481823e6308c379a061510682516150dc565b1461511057610565565b6040513d600319016004823e80513d6001600160401b03816024840111818411171561513f5750505050610565565b828401925082519150808211156151595750505050610565565b503d8301602082840101111561517157505050610565565b601f01601f1916810160200160405291505090565b6001600160a01b038116811461069b57600080fdfe4d6178207472757374656420616464726573736573206c656e677468206578636565646564756e6b6e6f776e206661696c2e2073657474696e6720636c65616e757020626c6f636b756e6b6e6f776e206661696c2e2066616c6c6261636b2066696e616c697a652070726963652065706f6368756e6b6e6f776e206661696c2e2066696e616c697a652070726963652065706f6368556e6b6e6f776e206661696c207768656e20636c6f73696e672065787069726564756e6b6e6f776e206661696c2e2066616c6c6261636b20696e69742065706f636820666f722072657665616c756e6b6e6f776e206661696c2e20696e69742065706f636820666f722072657665616c4173736574204654534f206e6f74206d616e61676564206279206674736f206d616e61676572a264697066735822122031a4df8ff2e3927ffe942baa09d7ccfecacbd707bb5bbb9857ab0f5bfd8dccfd64736f6c6343000706003346697273742065706f63682073746172742074696d657374616d7020696e206675747572655265776172642065706f6368206475726174696f6e20636f6e646974696f6e20696e76616c69645265776172642065706f636820737461727420636f6e646974696f6e20696e76616c6964000000000000000000000000493044fbbaa7f9f78379864fa88accaff6a7586e00000000000000000000000010000000000000000000000000000000000000020000000000000000000000001000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000006143aba100000000000000000000000000000000000000000000000000000000000000b4000000000000000000000000000000000000000000000000000000000000005a000000000000000000000000000000000000000000000000000000006145a63b0000000000000000000000000000000000000000000000000000000000093a800000000000000000000000000000000000000000000000000000000000000004

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106102745760003560e01c806393a7902511610151578063ce69f833116100c3578063e7a0d01e11610087578063e7a0d01e146104cf578063e7c830d4146104e2578063e847ae1e146104ea578063f2edab5a146104fd578063f937d6ad14610510578063ff882fbb1461051857610274565b8063ce69f8331461046c578063d38bfff414610481578063e06174e414610494578063e22fdece146104b1578063e371aef0146104b957610274565b8063a795f40911610115578063a795f40914610405578063a93a6f4214610418578063af946af71461042b578063c0ffe9081461043e578063c2b0d47b14610451578063c373a08e1461045957610274565b806393a79025146103b65780639d6a890f146103cf578063a1077532146103e2578063a578f55b146103ea578063a670ff87146103f257610274565b80634eac870f116101ea57806369b11ac6116101ae57806369b11ac6146103655780636b65cc341461036d5780636d0e8c34146103805780636ea0aa311461038857806385f3c9c91461039b5780639131205b146103a357610274565b80634eac870f146103305780635aa6e675146103385780635d36b1901461034057806360f2c5b21461034857806360f7ac971461035d57610274565b8063144e15911161023c578063144e1591146102c65780632663f1b4146102dd5780632b3c41a4146102f05780632fd8eb7d1461030957806338b5f869146103115780634b48dd5e1461031957610274565b806302fb0c5e14610279578063047fc9aa146102975780630e063d7d146102ac5780630f15f4c0146102b45780630f4ef8a6146102be575b600080fd5b61028161052b565b60405161028e9190614e8e565b60405180910390f35b61029f610534565b60405161028e9190614cde565b61029f610543565b6102bc610568565b005b61029f6105c8565b6102ce6105d7565b60405161028e93929190614f8f565b6102bc6102eb3660046145d4565b61063f565b6102f861069e565b60405161028e959493929190614def565b61029f6106d9565b61029f6106e8565b6103216106f7565b60405161028e93929190614e99565b61029f6107d3565b61029f6107e2565b6102bc6107f1565b6103506108b3565b60405161028e9190614f78565b61029f6108d7565b6103506108e6565b6102bc61037b366004614a2b565b6108eb565b61028161099e565b6102f8610396366004614ae1565b610aaf565b610350610e13565b6102bc6103b1366004614b25565b610e37565b6103be6110a7565b60405161028e959493929190614fa5565b6102bc6103dd3660046145d4565b61113a565b61029f611214565b610350611238565b6102bc6104003660046145d4565b61125c565b6102ce610413366004614ab1565b611486565b6102bc6104263660046148f3565b6114b9565b6102bc6104393660046149a0565b611649565b6102bc61044c3660046145f7565b61175a565b61029f611933565b6102bc6104673660046145d4565b611942565b6104746119e7565b60405161028e9190614ddc565b6102bc61048f3660046145d4565b6119f6565b61049c611ab8565b60405161028e9998979695949392919061500c565b610281611adf565b6104c1611bbd565b60405161028e929190614f56565b6102bc6104dd3660046149d4565b611bde565b6103506122db565b6102bc6104f8366004614883565b61233e565b61035061050b366004614ab1565b6123ee565b61029f612417565b6102bc610526366004614869565b61243b565b60055460ff1681565b601a546001600160a01b031681565b7f00000000000000000000000010000000000000000000000000000000000000035b90565b6000546001600160a01b031633146105b9576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b6005805460ff19166001179055565b6017546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000006143aba17f00000000000000000000000000000000000000000000000000000000000000b47f000000000000000000000000000000000000000000000000000000000000005a909192565b6000546001600160a01b03163314610690576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b61069b8160016124de565b50565b6004546060908190819081906000906106c890600160c01b90046001600160401b03166001610aaf565b945094509450945094509091929394565b6007546001600160a01b031681565b6018546001600160a01b031681565b601b54600160a81b900460ff1660608061070f612abc565b8051909250806001600160401b038111801561072a57600080fd5b50604051908082528060200260200182016040528015610754578160200160208202803683370190505b50915060005b818110156107cc57601c600085838151811061077257fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a900460ff168382815181106107b457fe5b9115156020928302919091019091015260010161075a565b5050909192565b601b546001600160a01b031681565b6000546001600160a01b031681565b6001546001600160a01b03163314610840576040805162461bcd60e51b815260206004820152600d60248201526c1b9bdd0818db185a5b585a5b9d609a1b604482015290519081900360640190fd5b600054600154604080516001600160a01b03938416815292909116602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b7f000000000000000000000000000000000000000000000000000000000000000490565b6001546001600160a01b031681565b600581565b6000546001600160a01b0316331461093c576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b60405163d0d552dd60e01b81526001600160a01b0383169063d0d552dd90610968908490600401614cde565b600060405180830381600087803b15801561098257600080fd5b505af1158015610996573d6000803e3d6000fd5b505050505050565b6000336001600160a01b037f00000000000000000000000010000000000000000000000000000000000000021614610a11576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b60055460ff16610a2357506000610565565b600654610a3757610a32612b3d565b610aa9565b601b54600160a01b900460ff168015610a5257504260125411155b15610a5f57610a32612cb2565b601b54600160a01b900460ff16158015610a7b57504260135411155b15610a9857610a88613293565b610a90613588565b610a32613717565b4260125411610aa957610aa96138a8565b50600190565b606080606080600060038054905087106040518060400160405280601081526020016f0e6e8c2e4e840d2dcc8caf040d0d2ced60831b81525090610b0f5760405162461bcd60e51b8152600401610b069190614f43565b60405180910390fd5b506003546000908888011115610b2a57600354889003610b2c565b865b9050806001600160401b0381118015610b4457600080fd5b50604051908082528060200260200182016040528015610b6e578160200160208202803683370190505b509550806001600160401b0381118015610b8757600080fd5b50604051908082528060200260200182016040528015610bb1578160200160208202803683370190505b509450806001600160401b0381118015610bca57600080fd5b50604051908082528060200260200182016040528015610bfe57816020015b6060815260200190600190039081610be95790505b509350806001600160401b0381118015610c1757600080fd5b50604051908082528060200260200182016040528015610c41578160200160208202803683370190505b50925060005b81811015610df75760006003828b0181548110610c6057fe5b6000918252602080832090910154808352600290915260409091205489519192506001600160c01b031690899084908110610c9757fe5b6020026020010181815250506002600082815260200190815260200160002060000160189054906101000a90046001600160401b03166001600160401b0316878381518110610ce257fe5b602090810291909101810191909152600082815260028083526040918290208101805483516001821615610100026000190190911692909204601f81018590048502830185019093528282529092909190830182828015610d845780601f10610d5957610100808354040283529160200191610d84565b820191906000526020600020905b815481529060010190602001808311610d6757829003601f168201915b5050505050868381518110610d9557fe5b60200260200101819052506002600082815260200190815260200160002060010160009054906101000a90046001600160a01b0316858381518110610dd657fe5b6001600160a01b039092166020928302919091019091015250600101610c47565b50506004549497939650919450926001600160c01b0316919050565b7f0000000000000000000000000000000000000000000000000000000000093a8081565b6000546001600160a01b03163314610e88576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b60408051808201909152601381527211dbdd8b881c185c985b5cc81a5b9d985b1a59606a1b602082015288610ed05760405162461bcd60e51b8152600401610b069190614f43565b5060408051808201909152601381527211dbdd8b881c185c985b5cc81a5b9d985b1a59606a1b602082015287610f195760405162461bcd60e51b8152600401610b069190614f43565b5060408051808201909152601381527211dbdd8b881c185c985b5cc81a5b9d985b1a59606a1b602082015286861015610f655760405162461bcd60e51b8152600401610b069190614f43565b5060408051808201909152601381527211dbdd8b881c185c985b5cc81a5b9d985b1a59606a1b6020820152612710851115610fb35760405162461bcd60e51b8152600401610b069190614f43565b5060408051808201909152601381527211dbdd8b881c185c985b5cc81a5b9d985b1a59606a1b60208201526127108411156110015760405162461bcd60e51b8152600401610b069190614f43565b5060408051808201909152601581527414995dd85c9908195e1c1a5c9e481a5b9d985b1a59605a1b60208201528261104c5760405162461bcd60e51b8152600401610b069190614f43565b5060058151111560405180606001604052806025815260200161519c602591399061108a5760405162461bcd60e51b8152600401610b069190614f43565b5061109d60088989898989898989613bd9565b5050505050505050565b6000806000806000806110b8613dd2565b9550507f000000000000000000000000000000000000000000000000000000006143aba17f00000000000000000000000000000000000000000000000000000000000000b4808702820195506001870102019250507f000000000000000000000000000000000000000000000000000000000000005a82019050429091929394565b600154600160a01b900460ff1615611190576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b6001805460ff60a01b1916600160a01b179055600054604080516001600160a01b039283168152918316602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a1600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b7f000000000000000000000000100000000000000000000000000000000000000281565b7f000000000000000000000000000000000000000000000000000000006145a63b81565b6000546001600160a01b031633146112ad576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b6000601860009054906101000a90046001600160a01b03166001600160a01b031663e848da30836001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561130c57600080fd5b505afa158015611320573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113489190810190614a7f565b6040518263ffffffff1660e01b81526004016113649190614f43565b60206040518083038186803b15801561137c57600080fd5b505afa158015611390573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b49190614ac9565b60195460405163d873617160e01b81529192506001600160a01b03169063d8736171906113e5908490600401614f78565b600060405180830381600087803b1580156113ff57600080fd5b505af1158015611413573d6000803e3d6000fd5b505060185460405163a670ff8760e01b81526001600160a01b03909116925063a670ff879150611447908590600401614cde565b600060405180830381600087803b15801561146157600080fd5b505af1158015611475573d6000803e3d6000fd5b5050505061148282613e25565b5050565b6006818154811061149657600080fd5b600091825260209091206003909102018054600182015460029092015490925083565b6000546001600160a01b0316331461150a576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b80516040805180820190915260168152754173736574206674736f73206c69737420656d70747960501b6020820152816115575760405162461bcd60e51b8152600401610b069190614f43565b5060005b818110156115dc5782818151811061156f57fe5b60200260200101516001600160a01b0316846001600160a01b031614156115d45760408051808201825260168152756674736f20657175616c73206173736574206674736f60501b6020820152905162461bcd60e51b8152610b069190600401614f43565b60010161155b565b506115e682613efc565b60405163098fef7160e11b81526001600160a01b0384169063131fdee290611612908590600401614ddc565b600060405180830381600087803b15801561162c57600080fd5b505af1158015611640573d6000803e3d6000fd5b50505050505050565b6000546001600160a01b0316331461169a576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b6001600160a01b0382166000908152601560209081526040918290205482518084019093526009835268139bdd08199bdd5b9960ba1b9183019190915260ff166116f75760405162461bcd60e51b8152600401610b069190614f43565b506001600160a01b0382166000908152601c602052604090819020805460ff1916831515179055517f24462ede4d3e8e5a69fecec6290d42a311016ca752216d9a3d681e284791b7ac9061174e9084908490614ee9565b60405180910390a15050565b6000828260405160200161176f929190614d0b565b60408051601f198184030181528282528051602091820120600081815260029092529190208054436001600160c01b038181166001600160401b03600160c01b80860482166001019091160291909316176001600160c01b031916919091179091559092507f1a601cf5e0efbd558b2778b7389af04741d1c49bcab104c40daa2da194593617916118039186918690614d2f565b60405180910390a1600480546001600160c01b0319811660016001600160c01b03928316810190921617909155600082815260026020526040902054600160c01b90046001600160401b0316111561185b5750611482565b6003805460018082019092557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01829055600082815260026020818152604090922092830180546001600160a01b0319166001600160a01b03881617905584516118cb9390910191850190614417565b50600354600091825260026020526040909120600101805467ffffffffffffffff60a01b1916600160a01b6000199093016001600160401b0390811684029190911791829055600480546001600160c01b03169390920416600160c01b029190911790555050565b6019546001600160a01b031681565b6000546001600160a01b03163314611993576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600180546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f1f95fb40be3a947982072902a887b521248d1d8931a39eb38f84f4d6fd758b699181900360200190a150565b60606119f1612abc565b905090565b6000546001600160a01b03163314611a47576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600054604080516001600160a01b039283168152918316602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a1600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b600854600954600a54600b54600c54600d54600e5460105460ff8082169161010090041689565b6000336001600160a01b037f00000000000000000000000010000000000000000000000000000000000000021614611b52576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b601b54600160a81b900460ff16611bb757601b805460ff60a81b1916600160a81b1790556040517f217a37a37fc40a97159886f80c3d45986e6fc4330ce6ad7283478b5e5ab705bc90611ba790600190614e8e565b60405180910390a1506001610565565b50600090565b6004546001600160c01b03811690600160c01b90046001600160401b031682565b6000546001600160a01b03163314611c2f576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b826001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015611c6857600080fd5b505afa158015611c7c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ca49190810190614a7f565b604051602001611cb49190614f43565b60405160208183030381529060405280519060200120846001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015611d0357600080fd5b505afa158015611d17573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611d3f9190810190614a7f565b604051602001611d4f9190614f43565b60405160208183030381529060405280519060200120146040518060400160405280601781526020017f4654534f2073796d626f6c73206d757374206d6174636800000000000000000081525090611dba5760405162461bcd60e51b8152600401610b069190614f43565b506000611dc5612abc565b805190915060005b81811015611e0f57866001600160a01b0316838281518110611deb57fe5b60200260200101516001600160a01b03161415611e0757611e0f565b600101611dcd565b81811415611e4e576040805180820182526009815268139bdd08199bdd5b9960ba1b6020820152905162461bcd60e51b8152610b069190600401614f43565b8415611f2f57600080886001600160a01b031663eb91d37e6040518163ffffffff1660e01b8152600401604080518083038186803b158015611e8f57600080fd5b505afa158015611ea3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ec79190614b02565b60405163306ba25360e01b815291935091506001600160a01b0389169063306ba25390611efa9085908590600401614f81565b600060405180830381600087803b158015611f1457600080fd5b505af1158015611f28573d6000803e3d6000fd5b5050505050505b8315612100576000876001600160a01b0316635c222bad6040518163ffffffff1660e01b815260040160206040518083038186803b158015611f7057600080fd5b505afa158015611f84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa89190614a63565b90506001600160a01b0381161561201c5760405163d0d552dd60e01b81526001600160a01b0388169063d0d552dd90611fe5908490600401614cde565b600060405180830381600087803b158015611fff57600080fd5b505af1158015612013573d6000803e3d6000fd5b505050506120fe565b6000886001600160a01b03166318931c356040518163ffffffff1660e01b815260040160006040518083038186803b15801561205757600080fd5b505afa15801561206b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120939190810190614749565b8051909150156120fc5760405163098fef7160e11b81526001600160a01b0389169063131fdee2906120c9908490600401614ddc565b600060405180830381600087803b1580156120e357600080fd5b505af11580156120f7573d6000803e3d6000fd5b505050505b505b505b61210b8660006124de565b6000612115612abc565b805190915060005b818110156122c657600083828151811061213357fe5b602002602001015190508a6001600160a01b0316816001600160a01b0316141561215d57506122be565b6000816001600160a01b03166318931c356040518163ffffffff1660e01b815260040160006040518083038186803b15801561219857600080fd5b505afa1580156121ac573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526121d49190810190614749565b805190915080156122ba576000805b82811015612252578e6001600160a01b031684828151811061220157fe5b60200260200101516001600160a01b0316141561224a578d84828151811061222557fe5b60200260200101906001600160a01b031690816001600160a01b031681525050600191505b6001016121e3565b5080156122b85760405163098fef7160e11b81526001600160a01b0385169063131fdee290612285908690600401614ddc565b600060405180830381600087803b15801561229f57600080fd5b505af11580156122b3573d6000803e3d6000fd5b505050505b505b5050505b60010161211d565b506122d089613e25565b505050505050505050565b6006546040805180820190915260208082527f5265776172642065706f6368206e6f7420696e697469616c697a6564207965749082015260009190816123345760405162461bcd60e51b8152600401610b069190614f43565b5060001901905090565b6000546001600160a01b0316331461238f576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b601780546001600160a01b03199081166001600160a01b03978816179091556018805482169587169590951790945560198054851693861693909317909255601a80548416918516919091179055601b80549092169216919091179055565b6000600682815481106123fd57fe5b90600052602060002090600302016000015490505b919050565b7f000000000000000000000000100000000000000000000000000000000000000381565b6000546001600160a01b0316331461248c576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b601b805460ff60a81b1916600160a81b831515021790556040517f217a37a37fc40a97159886f80c3d45986e6fc4330ce6ad7283478b5e5ab705bc906124d3908390614e8e565b60405180910390a150565b60105460408051808201909152601b81527f476f762e20706172616d73206e6f7420696e697469616c697a65640000000000602082015290610100900460ff1661253b5760405162461bcd60e51b8152600401610b069190614f43565b506125b9826001600160a01b03166318931c356040518163ffffffff1660e01b815260040160006040518083038186803b15801561257857600080fd5b505afa15801561258c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125b49190810190614749565b613efc565b8015612782576000826001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b1580156125fa57600080fd5b505afa15801561260e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126369190810190614a7f565b6040516020016126469190614f43565b6040516020818303038152906040528051906020012090506000601860009054906101000a90046001600160a01b03166001600160a01b031663ce1c0e4d6040518163ffffffff1660e01b815260040160006040518083038186803b1580156126ae57600080fd5b505afa1580156126c2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126ea91908101906147e1565b80519091505b801561277e57806001900390508282828151811061270a57fe5b60200260200101516040516020016127229190614f43565b60405160208183030381529060405280519060200120141561277957604080518082018252600d81526c105b1c9958591e481859191959609a1b6020820152905162461bcd60e51b8152610b069190600401614f43565b6126f0565b5050505b604051630bc29bcf60e21b81526001600160a01b03831690632f0a6f3c90612812907f000000000000000000000000000000000000000000000000000000006143aba1907f00000000000000000000000000000000000000000000000000000000000000b4907f000000000000000000000000000000000000000000000000000000000000005a90600401614f8f565b600060405180830381600087803b15801561282c57600080fd5b505af1158015612840573d6000803e3d6000fd5b50506006541591506128d2905057600680546001600160a01b0384169163e536f39691600019810190811061287157fe5b9060005260206000209060030201600001546040518263ffffffff1660e01b815260040161289f9190614f78565b600060405180830381600087803b1580156128b957600080fd5b505af11580156128cd573d6000803e3d6000fd5b505050505b600854600954600a54600b54600c54600d5460405163f7dba1f560e01b81526001600160a01b0389169663f7dba1f596612919969195909491939092600f90600401614fc8565b600060405180830381600087803b15801561293357600080fd5b505af1158015612947573d6000803e3d6000fd5b5050601b546001600160a01b038086166000908152601660209081526040808320805460ff600160a01b90970496909616151560ff19968716179055601590915280822080549094166001179093556018549251630998fc6d60e21b815290945091169150632663f1b4906129c0908690600401614cde565b602060405180830381600087803b1580156129da57600080fd5b505af11580156129ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a129190614ac9565b90508115612a7d57601954604051630d15c16960e21b81526001600160a01b039091169063345705a490612a4a908490600401614f78565b600060405180830381600087803b158015612a6457600080fd5b505af1158015612a78573d6000803e3d6000fd5b505050505b7fa0985424f2efdcae4b57a7c84bbf0a0b19f93054f21e9eb1cfcd5a59813fe1da836001604051612aaf929190614ee9565b60405180910390a1505050565b60185460408051635200305d60e11b815290516060926001600160a01b03169163a40060ba916004808301926000929190829003018186803b158015612b0157600080fd5b505afa158015612b15573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119f19190810190614749565b7f0000000000000000000000000000000000000000000000000000000000093a80601354034210612cb0576000612b72612abc565b8051604080516060810182524360001981018252602082019081524292820192835260068054600181018255600091825283517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f60039092029182015591517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4083015592517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d41909101559293509091905b82811015612cab57838181518110612c3757fe5b60200260200101516001600160a01b031663e536f39683600001516040518263ffffffff1660e01b8152600401612c6e9190614f78565b600060405180830381600087803b158015612c8857600080fd5b505af1158015612c9c573d6000803e3d6000fd5b50505050806001019050612c23565b505050505b565b6000612cbc612abc565b80519091508015801590612cda5750601b54600160a81b900460ff16155b156131ae576007546000906001600160a01b0316612d2e57814442604051602001612d06929190614f81565b6040516020818303038152906040528051906020012060001c81612d2657fe5b069050612e04565b6000805b83811015612dca57848181518110612d4657fe5b60200260200101516001600160a01b031663d89601fd6040518163ffffffff1660e01b815260040160206040518083038186803b158015612d8657600080fd5b505afa158015612d9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dbe9190614ac9565b90910190600101612d32565b50828142604051602001612ddf929190614f81565b6040516020818303038152906040528051906020012060001c81612dff57fe5b069150505b60608060008080805b87811015612f8c5760008882890181612e2257fe5b06905060008a8281518110612e3357fe5b6020908102919091018101516001600160a01b0381166000908152601690925260409091205490915060ff1615612e89576001600160a01b03166000908152601660205260409020805460ff1916905550612f84565b6011546040516340462a2d60e01b81526001600160a01b038316916340462a2d91612eba9190891590600401614f33565b600060405180830381600087803b158015612ed457600080fd5b505af1925050508015612f0957506040513d6000823e601f3d908101601f19168201604052612f06919081019061467e565b60015b612f5757612f156150e2565b80612f205750612f30565b612f2a8282613f83565b50612f52565b612f528160405180606001604052806022815260200161520f60229139613f83565b612f81565b87158015612f66575060008351115b15612f7d5791995097509550600194509250828787875b5050505b50505b600101612e0d565b506000612f976122db565b9050821561314d576017546011546001600160a01b039091169063a9b79e1790889088908890877f00000000000000000000000000000000000000000000000000000000000000b4886001612feb85613fd4565b0360068b81548110612ff957fe5b9060005260206000209060030201600001546040518a63ffffffff1660e01b815260040161302f99989796959493929190614d5f565b600060405180830381600087803b15801561304957600080fd5b505af192505050801561305a575060015b61314d576130666150e2565b8061307157506130c8565b7f175a1d13d190d6a1e14461c214b3ecf6118b828797750b7bffd7c4f2c1eba54c836011546040516130a4929190614cf2565b60405180910390a16017546130c2906001600160a01b03168261175a565b5061314d565b7f175a1d13d190d6a1e14461c214b3ecf6118b828797750b7bffd7c4f2c1eba54c826011546040516130fb929190614cf2565b60405180910390a16017546040805180820190915260208082527f756e6b6e6f776e206661696c2e206469737472696275746520726577617264739082015261314d916001600160a01b03169061175a565b600780546001600160a01b0319166001600160a01b0384161790556040517f98b050a4042fbd1b89934ef40b9342e593f15081a348af940573a0179031f4ad9061319a9084908490614cf2565b60405180910390a150505050505050613282565b60005b8181101561322f5760008382815181106131c757fe5b6020908102919091018101516001600160a01b0381166000908152601690925260409091205490915060ff161561321c576001600160a01b03166000908152601660205260409020805460ff19169055613227565b61322581614021565b505b6001016131b1565b50600780546001600160a01b03191690557f98b050a4042fbd1b89934ef40b9342e593f15081a348af940573a0179031f4ad600061326b6122db565b604051613279929190614cf2565b60405180910390a15b5050601b805460ff60a01b19169055565b600061329d612abc565b80519091504281156133465760005b82811015613344578381815181106132c057fe5b60200260200101516001600160a01b031663d89601fd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561330057600080fd5b505afa158015613314573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133389190614ac9565b909101906001016132ac565b505b806040516020016133579190614f78565b6040516020818303038152906040528051906020012060001c905060007f0000000000000000000000000000000000000000000000000000000000000004600661339f6122db565b815481106133a957fe5b9060005260206000209060030201600101544303816133c457fe5b049050806133d0575060015b60008183816133db57fe5b069050806133e7575060015b60408051606081018252438381038252602082019081524292820192835260068054600181018255600091825283517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f60039092029182015591517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4083015592517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4190910155905b85811015613518578681815181106134a357fe5b60200260200101516001600160a01b031663e536f39683600001516040518263ffffffff1660e01b81526004016134da9190614f78565b600060405180830381600087803b1580156134f457600080fd5b505af1158015613508573d6000803e3d6000fd5b50506001909201915061348f9050565b50805160208201516040517f1813f880dc24666c8b69c9d771a487ea620a27fde1514be3112847056c0c532292613550929091614f81565b60405180910390a15050601380547f0000000000000000000000000000000000000000000000000000000000093a8001905550505050565b60006135926122db565b600e5490915042035b816014541080156135cf5750806006601454600101815481106135ba57fe5b90600052602060002090600302016002015411155b1561148257601754601454604051636b60edf760e11b81526001600160a01b039092169163d6c1dbee9161360591600401614f78565b600060405180830381600087803b15801561361f57600080fd5b505af1925050508015613630575060015b6137095761363c6150e2565b80613647575061369c565b7fa819a21065ad87bdde9e6d398d3213e0d3634afd87aceb7092236483f5d7ca8d6014546040516136789190614f78565b60405180910390a1601754613696906001600160a01b03168261175a565b50611482565b7fa819a21065ad87bdde9e6d398d3213e0d3634afd87aceb7092236483f5d7ca8d6014546040516136cd9190614f78565b60405180910390a160175460408051606081019091526021808252613704926001600160a01b03169190615231602083013961175a565b611482565b60148054600101905561359b565b601b546001600160a01b0316613755576040517f9a880a9e2a01928f1a99d7b0e2ea1147f52e2eb381f8d9345c110932d57bce8d90600090a1612cb0565b600060066014548154811061376657fe5b6000918252602090912060039091020154601b5460405163cbc31cf760e01b81529192506001600160a01b03169063cbc31cf7906137a8908490600401614f78565b600060405180830381600087803b1580156137c257600080fd5b505af19250505080156137d3575060015b61069b576137df6150e2565b806137ea575061383d565b7f9f874ea08c7014cce74622bfe71434f81aba7598ad65126a6aea86945bdfa18d826040516138199190614f78565b60405180910390a1601b54613837906001600160a01b03168261175a565b506138a3565b7f9f874ea08c7014cce74622bfe71434f81aba7598ad65126a6aea86945bdfa18d8160405161386c9190614f78565b60405180910390a1601b54604080516060810190915260238082526138a3926001600160a01b031691906151c1602083013961175a565b61069b565b60105460ff161561393357604051639ec2b58160e01b81526001600160a01b037f00000000000000000000000010000000000000000000000000000000000000031690639ec2b5819061390090600f90600401614dc9565b600060405180830381600087803b15801561391a57600080fd5b505af115801561392e573d6000803e3d6000fd5b505050505b600061393d612abc565b80519091506000811580159061395d5750601b54600160a81b900460ff16155b15613a0f576006805460009190600019810190811061397857fe5b6000918252602090912060039091020154601a546040516237b08960e41b81529192506001600160a01b03169063037b0890906139b9908490600401614f78565b602060405180830381600087803b1580156139d357600080fd5b505af11580156139e7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a0b9190614ac9565b9150505b60005b82811015613b98576000848281518110613a2857fe5b602090810291909101015160105490915060ff1615613abb57600854600954600a54600b54600c54600d5460405163f7dba1f560e01b81526001600160a01b0388169663f7dba1f596613a88969195909491939092600f90600401614fc8565b600060405180830381600087803b158015613aa257600080fd5b505af1158015613ab6573d6000803e3d6000fd5b505050505b806001600160a01b031663f670ebe384601b60159054906101000a900460ff1680613afe57506001600160a01b0384166000908152601c602052604090205460ff165b6040518363ffffffff1660e01b8152600401613b1b929190614f33565b600060405180830381600087803b158015613b3557600080fd5b505af1925050508015613b46575060015b613b8f57613b526150e2565b80613b5d5750613b6d565b613b6782826140bd565b50613b8f565b613b8f8160405180606001604052806023815260200161527e602391396140bd565b50600101613a12565b506010805460ff191690556000613bad613dd2565b60118190559050613bbd816142ce565b6012555050601b805460ff60a01b1916600160a01b1790555050565b88548814613bf45760088901805460ff191660011790558789555b86896001015414613c175760088901805460ff1916600190811790915589018790555b85896002015414613c395760088901805460ff19166001179055600289018690555b84896003015414613c5b5760088901805460ff19166001179055600389018590555b83896004015414613c7d5760088901805460ff19166001179055600489018490555b82896005015414613c9f5760088901805460ff19166001179055600589018390555b81896006015414613cc15760088901805460ff19166001179055600689018290555b805160078a015414613cf7578051613ce29060078b019060208401906144a3565b5060088901805460ff19166001179055613db6565b60005b8151811015613db457818181518110613d0f57fe5b60200260200101516001600160a01b03168a6007018281548110613d2f57fe5b6000918252602090912001546001600160a01b031614613dac5760088a01805460ff191660011790558151829082908110613d6657fe5b60200260200101518a6007018281548110613d7d57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b600101613cfa565b505b5050506008909501805461ff0019166101001790555050505050565b60007f00000000000000000000000000000000000000000000000000000000000000b47f000000000000000000000000000000000000000000000000000000006143aba1420381613e1f57fe5b04905090565b806001600160a01b031663555989da6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613e6057600080fd5b505af1158015613e74573d6000803e3d6000fd5b5050506001600160a01b0382166000908152601c60209081526040808320805460ff199081169091556016835281842080548216905560159092529091208054909116905550613eca613ec5612abc565b61433d565b7fa0985424f2efdcae4b57a7c84bbf0a0b19f93054f21e9eb1cfcd5a59813fe1da8160006040516124d3929190614ee9565b805160005b81811015613f7e5760156000848381518110613f1957fe5b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff16613f76576040518060600160405280602681526020016152a16026913960405162461bcd60e51b8152600401610b069190614f43565b600101613f01565b505050565b7f79f4c7cc43bfb79f5a3aad0d92f75b6fed7db061bb5cc2580a01c8132711b881826011546001604051613fb993929190614f04565b60405180910390a1613fcb828261175a565b61148282614021565b7f000000000000000000000000000000000000000000000000000000006143aba1600182017f00000000000000000000000000000000000000000000000000000000000000b40201919050565b601154604051639de6f92760e01b81526001600160a01b03831691639de6f9279161404f9190600401614f78565b600060405180830381600087803b15801561406957600080fd5b505af192505050801561407a575060015b61069b576140866150e2565b80614091575061409b565b61383782826143a1565b6138a3816040518060600160405280602b81526020016151e4602b91396143a1565b7f61156899176547b8075bfa81fa2996c6057ce9c71320884b11c0179d9dc2e462826140e7613dd2565b6040516140f5929190614cf2565b60405180910390a1614107828261175a565b601b54600160a81b900460ff168061413757506001600160a01b0382166000908152601c602052604090205460ff165b15614164576001600160a01b0382166000908152601660205260409020805460ff19166001179055611482565b60405163f670ebe360e01b81526001600160a01b0383169063f670ebe39061419490600090600190600401614f33565b600060405180830381600087803b1580156141ae57600080fd5b505af19250505080156141bf575060015b611482576141cb6150e2565b806141d65750614249565b6001600160a01b0383166000908152601660205260409020805460ff191660011790557f61156899176547b8075bfa81fa2996c6057ce9c71320884b11c0179d9dc2e46283614223613dd2565b604051614231929190614cf2565b60405180910390a1614243838261175a565b50613704565b6001600160a01b0382166000908152601660205260409020805460ff191660011790557f61156899176547b8075bfa81fa2996c6057ce9c71320884b11c0179d9dc2e46282614296613dd2565b6040516142a4929190614cf2565b60405180910390a1613704826040518060600160405280602c8152602001615252602c913961175a565b7f000000000000000000000000000000000000000000000000000000006143aba1600182017f00000000000000000000000000000000000000000000000000000000000000b402017f000000000000000000000000000000000000000000000000000000000000005a01919050565b805160005b81811015613f7e5761439983828151811061435957fe5b60200260200101516001600160a01b03166318931c356040518163ffffffff1660e01b815260040160006040518083038186803b15801561257857600080fd5b600101614342565b7f79f4c7cc43bfb79f5a3aad0d92f75b6fed7db061bb5cc2580a01c8132711b8818260115460026040516143d793929190614f04565b60405180910390a16143e9828261175a565b60115460405163974d7a6b60e01b81526001600160a01b0384169163974d7a6b916109689190600401614f78565b828054600181600116156101000203166002900490600052602060002090601f01602090048101928261444d5760008555614493565b82601f1061446657805160ff1916838001178555614493565b82800160010185558215614493579182015b82811115614493578251825591602001919060010190614478565b5061449f9291506144f8565b5090565b828054828255906000526020600020908101928215614493579160200282015b8281111561449357825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906144c3565b5b8082111561449f57600081556001016144f9565b600082601f83011261451d578081fd5b8151602061453261452d83615072565b61504f565b828152818101908583018385028701840188101561454e578586fd5b855b8581101561456c57815184529284019290840190600101614550565b5090979650505050505050565b8035801515811461241257600080fd5b600082601f830112614599578081fd5b81516145a761452d8261508f565b8181528460208386010111156145bb578283fd5b6145cc8260208301602087016150b0565b949350505050565b6000602082840312156145e5578081fd5b81356145f081615186565b9392505050565b60008060408385031215614609578081fd5b823561461481615186565b915060208301356001600160401b0381111561462e578182fd5b8301601f8101851361463e578182fd5b803561464c61452d8261508f565b818152866020838501011115614660578384fd5b81602084016020830137908101602001929092525090939092509050565b600080600060608486031215614692578081fd5b83516001600160401b03808211156146a8578283fd5b818601915086601f8301126146bb578283fd5b815160206146cb61452d83615072565b82815281810190858301838502870184018c10156146e7578788fd5b8796505b848710156147125780516146fe81615186565b8352600196909601959183019183016146eb565b509189015191975090935050508082111561472b578283fd5b506147388682870161450d565b925050604084015190509250925092565b6000602080838503121561475b578182fd5b82516001600160401b03811115614770578283fd5b8301601f81018513614780578283fd5b805161478e61452d82615072565b81815283810190838501858402850186018910156147aa578687fd5b8694505b838510156147d55780516147c181615186565b8352600194909401939185019185016147ae565b50979650505050505050565b600060208083850312156147f3578182fd5b82516001600160401b03811115614808578283fd5b8301601f81018513614818578283fd5b805161482661452d82615072565b81815283810190838501865b8481101561485b576148498a888451890101614589565b84529286019290860190600101614832565b509098975050505050505050565b60006020828403121561487a578081fd5b6145f082614579565b600080600080600060a0868803121561489a578283fd5b85356148a581615186565b945060208601356148b581615186565b935060408601356148c581615186565b925060608601356148d581615186565b915060808601356148e581615186565b809150509295509295909350565b60008060408385031215614905578182fd5b823561491081615186565b91506020838101356001600160401b0381111561492b578283fd5b8401601f8101861361493b578283fd5b803561494961452d82615072565b81815283810190838501858402850186018a1015614965578687fd5b8694505b8385101561499057803561497c81615186565b835260019490940193918501918501614969565b5080955050505050509250929050565b600080604083850312156149b2578182fd5b82356149bd81615186565b91506149cb60208401614579565b90509250929050565b600080600080608085870312156149e9578182fd5b84356149f481615186565b93506020850135614a0481615186565b9250614a1260408601614579565b9150614a2060608601614579565b905092959194509250565b60008060408385031215614a3d578182fd5b8235614a4881615186565b91506020830135614a5881615186565b809150509250929050565b600060208284031215614a74578081fd5b81516145f081615186565b600060208284031215614a90578081fd5b81516001600160401b03811115614aa5578182fd5b6145cc84828501614589565b600060208284031215614ac2578081fd5b5035919050565b600060208284031215614ada578081fd5b5051919050565b60008060408385031215614af3578182fd5b50508035926020909101359150565b60008060408385031215614b14578182fd5b505080516020909101519092909150565b600080600080600080600080610100898b031215614b41578586fd5b883597506020808a0135975060408a0135965060608a0135955060808a0135945060a08a0135935060c08a0135925060e08a01356001600160401b03811115614b88578283fd5b8a01601f81018c13614b98578283fd5b8035614ba661452d82615072565b8082825284820191508484018f868786028701011115614bc4578687fd5b8694505b83851015614bef578035614bdb81615186565b835260019490940193918501918501614bc8565b5080955050505050509295985092959890939650565b6000815180845260208085019450808401835b83811015614c3d5781516001600160a01b031687529582019590820190600101614c18565b509495945050505050565b6000815480845260208085019450838352808320835b83811015614c3d5781546001600160a01b031687529582019560019182019101614c5e565b6000815180845260208085019450808401835b83811015614c3d57815187529582019590820190600101614c96565b60008151808452614cca8160208601602086016150b0565b601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03831681526040602082018190526000906145cc90830184614cb2565b600060018060a01b038516825283602083015260606040830152614d566060830184614cb2565b95945050505050565b6000610120808352614d738184018d614c05565b90508281036020840152614d87818c614c83565b604084019a909a52505060608101969096526001600160a01b0394909416608086015260a085019290925260c084015260e08301526101009091015292915050565b6000602082526145f06020830184614c48565b6000602082526145f06020830184614c05565b600060a08252614e0260a0830188614c83565b602083820381850152614e158289614c83565b848103604086015287518082529092508183019082810284018301838a01865b83811015614e6357601f19878403018552614e51838351614cb2565b94860194925090850190600101614e35565b50508681036060880152614e77818a614c05565b955050505050508260808301529695505050505050565b901515815260200190565b600084151582526020606081840152614eb56060840186614c05565b8381036040850152845180825282860191830190845b8181101561485b578351151583529284019291840191600101614ecb565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b0384168152602081018390526060810160068310614f2557fe5b826040830152949350505050565b9182521515602082015260400190565b6000602082526145f06020830184614cb2565b6001600160c01b039290921682526001600160401b0316602082015260400190565b90815260200190565b918252602082015260400190565b9283526020830191909152604082015260600190565b948552602085019390935260408401919091526060830152608082015260a00190565b60008882528760208301528660408301528560608301528460808301528360a083015260e060c0830152614fff60e0830184614c48565b9998505050505050505050565b988952602089019790975260408801959095526060870193909352608086019190915260a085015260c0840152151560e083015215156101008201526101200190565b6040518181016001600160401b038111828210171561506a57fe5b604052919050565b60006001600160401b0382111561508557fe5b5060209081020190565b60006001600160401b038211156150a257fe5b50601f01601f191660200190565b60005b838110156150cb5781810151838201526020016150b3565b83811115612cab5750506000910152565b60e01c90565b600060443d10156150f257610565565b600481823e6308c379a061510682516150dc565b1461511057610565565b6040513d600319016004823e80513d6001600160401b03816024840111818411171561513f5750505050610565565b828401925082519150808211156151595750505050610565565b503d8301602082840101111561517157505050610565565b601f01601f1916810160200160405291505090565b6001600160a01b038116811461069b57600080fdfe4d6178207472757374656420616464726573736573206c656e677468206578636565646564756e6b6e6f776e206661696c2e2073657474696e6720636c65616e757020626c6f636b756e6b6e6f776e206661696c2e2066616c6c6261636b2066696e616c697a652070726963652065706f6368756e6b6e6f776e206661696c2e2066696e616c697a652070726963652065706f6368556e6b6e6f776e206661696c207768656e20636c6f73696e672065787069726564756e6b6e6f776e206661696c2e2066616c6c6261636b20696e69742065706f636820666f722072657665616c756e6b6e6f776e206661696c2e20696e69742065706f636820666f722072657665616c4173736574204654534f206e6f74206d616e61676564206279206674736f206d616e61676572a264697066735822122031a4df8ff2e3927ffe942baa09d7ccfecacbd707bb5bbb9857ab0f5bfd8dccfd64736f6c63430007060033