false
false
0

Contract Address Details

0xbcE1972De5d1598a948A36186eCeBFD4690F3a5C

Contract Name
IncentivePool
Creator
0x4598a6–d10d29 at 0x9d662b–183d8b
Balance
0 FLR ( )
Tokens
Fetching tokens...
Transactions
3 Transactions
Transfers
0 Transfers
Gas Used
73,498
Last Balance Update
21728201
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
IncentivePool




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




Optimization runs
200
Verified at
2022-07-13T21:16:23.474570Z

Constructor Arguments

0000000000000000000000004598a6c05910ab914f0cbaaca1911cd337d10d290000000000000000000000001000000000000000000000000000000000000002000000000000000000000000baf89d873d198ff78e72d2745b01cba3c6e5be6b00000000000000000000000010000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000063718500

Arg [0] (address) : 0x4598a6c05910ab914f0cbaaca1911cd337d10d29
Arg [1] (address) : 0x1000000000000000000000000000000000000002
Arg [2] (address) : 0xbaf89d873d198ff78e72d2745b01cba3c6e5be6b
Arg [3] (address) : 0x1000000000000000000000000000000000000005
Arg [4] (uint256) : 1668384000

              

./contracts/tokenPools/implementation/IncentivePool.sol

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

import  "../../genesis/implementation/FlareDaemon.sol";
import "../../genesis/interface/IFlareDaemonize.sol";
import "../../utils/implementation/GovernedAndFlareDaemonized.sol";
import "../../addressUpdater/implementation/AddressUpdatable.sol";
import "../lib/IncentivePoolAnnum.sol";
import "../lib/IncentivePoolAnnums.sol";
import "../interface/IIIncentivePoolAllocation.sol";
import "../lib/IncentivePoolRewardService.sol"; 
import "../../inflation/interface/IISupply.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "../../utils/implementation/SafePct.sol";
import "../interface/IITokenPool.sol";
import "../../genesis/implementation/IncentivePoolTreasury.sol";

/**
 * @title IncentivePool
 * @notice A contract to manage the process of recognizing, authorizing and funding
 *   native tokens for Flare services that are rewardable by incentivePool.
 **/
contract IncentivePool is GovernedAndFlareDaemonized, IFlareDaemonize, IITokenPool, AddressUpdatable {
    using IncentivePoolAnnums for IncentivePoolAnnums.IncentivePoolAnnumsState;
    using SafeMath for uint256;
    using SafePct for uint256;

    // Composable contracts
    IncentivePoolTreasury public immutable treasury;
    IIIncentivePoolAllocation public incentivePoolAllocation;
    IISupply public supply;

    // The annums
    IncentivePoolAnnums.IncentivePoolAnnumsState private incentivePoolAnnums;       // IncentivePool annum data

    // Instance vars
    uint256 public lastAuthorizationTs;                             // The last time incentive was authorized
    mapping(IIIncentivePoolReceiver => TopupConfiguration)
        internal topupConfigurations;                               // A topup configuration for a contract
                                                                    //   receiving incentive.
    uint256 public immutable rewardEpochStartTs;                    // Do not start incentivePool annums before this
    uint256 public rewardEpochStartedTs;                            // When the first reward epoch was started

    // Constants
    string internal constant ERR_IS_ZERO = "address is 0";
    string internal constant ERR_OUT_OF_BALANCE = "out of balance";
    string internal constant ERR_TOPUP_LOW = "topup low";
    string internal constant ERR_TOPUP_HIGH = "topup high";
    string internal constant ERR_GET_ANNUAL_PERCENT = "unknown error. getAnnualPercentageBips";
    string internal constant ERR_TREASURY_ONLY = "treasury only";

    uint256 internal constant BIPS100 = 1e4;                            // 100% in basis points
    uint256 internal constant DEFAULT_TOPUP_FACTOR_X100 = 120;
    uint256 internal constant MAX_DAILY_TOPUP_FACTOR_X100 = 400;
    uint256 internal constant AUTHORIZE_TIME_FRAME_SEC = 1 days;

    event IncentiveAuthorized(uint256 amountWei);
    event TopupRequested(uint256 amountWei);
    event IncentivePoolAllocationSet(IIIncentivePoolAllocation incentivePoolAllocation);
    event IncentivePoolRewardServiceTopupComputed(IIIncentivePoolReceiver incentivePoolReceiver, uint256 amountWei);
    event IncentivePoolRewardServiceDailyAuthorizedIncentiveComputed(
        IIIncentivePoolReceiver incentivePoolReceiver,
        uint256 amountWei);
    event IncentivePoolRewardServiceTopupRequestReceived(
        IIIncentivePoolReceiver incentivePoolReceiver,
        uint256 amountWei);
    event SupplySet(IISupply oldSupply, IISupply newSupply);
    event TopupConfigurationSet(TopupConfiguration topupConfiguration);
    event NewAnnumInitialized(
        uint256 startTimeStamp,
        uint256 endTimeStamp,
        uint256 inflatableSupplyWei,
        uint256 recognizedIncentiveWei,
        uint256 totalAuthorizedIncentiveWei,
        uint256 totalIncentiveTopupRequestedWei,
        uint256 totalIncentiveTopupReceivedWei,
        uint256 totalIncentiveTopupWithdrawnWei
    );

    modifier notZero(address _address) {
        require(_address != address(0), ERR_IS_ZERO);
        _;
    }

    constructor (
        address _governance, 
        FlareDaemon _flareDaemon,
        address _addressUpdater,
        IncentivePoolTreasury _treasury,
        uint256 _rewardEpochStartTs
    )
        notZero(address(_treasury))
        GovernedAndFlareDaemonized(_governance, _flareDaemon)
        AddressUpdatable(_addressUpdater)
    {
        treasury = _treasury;
        rewardEpochStartTs = _rewardEpochStartTs;
    }

    /**
     * @notice Needed in order to receive funds from Treasury
     */
    receive() external payable {
        require(msg.sender == address(treasury), ERR_TREASURY_ONLY);
    }

    /**
     * @notice Return token pool supply data
     * @return _lockedFundsWei                  Funds that are intentionally locked in the token pool 
     * and not part of circulating supply
     * @return _totalInflationAuthorizedWei     Total inflation authorized amount (wei)
     * @return _totalClaimedWei                 Total claimed amount (wei)
     */
    function getTokenPoolSupplyData() external view override returns (
        uint256 _lockedFundsWei,
        uint256 _totalInflationAuthorizedWei,
        uint256 _totalClaimedWei
    ){
        _lockedFundsWei = address(treasury).balance.add(incentivePoolAnnums.totalIncentiveTopupWithdrawnWei);
        _totalInflationAuthorizedWei = 0;
        _totalClaimedWei = incentivePoolAnnums.totalIncentiveTopupWithdrawnWei;
    }

    /**
     * @notice Get a tuple of totals across incentivePool annums.
     * @return _totalAuthorizedIncentiveWei     Total authorized incentive
     * @return _totalIncentiveTopupRequestedWei Total incentive requested to be topped up for rewarding
     * @return _totalIncentiveTopupReceivedWei  Total incentive received for funding reward services
     * @return _totalIncentiveTopupWithdrawnWei Total incentive used for funding reward services
     * @return _totalRecognizedIncentiveWei     Total incentive recognized for rewarding
     */
    function getTotals()
        external view 
        returns (
            uint256 _totalAuthorizedIncentiveWei,
            uint256 _totalIncentiveTopupRequestedWei,
            uint256 _totalIncentiveTopupReceivedWei,
            uint256 _totalIncentiveTopupWithdrawnWei,
            uint256 _totalRecognizedIncentiveWei
        )
    {
        _totalAuthorizedIncentiveWei = incentivePoolAnnums.totalAuthorizedIncentiveWei;
        _totalIncentiveTopupRequestedWei = incentivePoolAnnums.totalIncentiveTopupRequestedWei;
        _totalIncentiveTopupReceivedWei = incentivePoolAnnums.totalIncentiveTopupReceivedWei;
        _totalIncentiveTopupWithdrawnWei = incentivePoolAnnums.totalIncentiveTopupWithdrawnWei;
        _totalRecognizedIncentiveWei = incentivePoolAnnums.totalRecognizedIncentiveWei;
    }

    /**
     * @notice Given an index, return the annum at that index.
     * @param _index    The index of the annum to fetch.
     * @return          The incentivePool annum state.
     * @dev Expect library to revert if index not found.
     */
    function getAnnum(uint256 _index) external view returns(IncentivePoolAnnum.IncentivePoolAnnumState memory) {
        return incentivePoolAnnums.getAnnum(_index);
    }

    /**
     * @notice Return the current annum.
     * @return The incentivePool annum state of the current annum.
     * @dev Expect library to revert if there is no current annum.
     */
    function getCurrentAnnum() external view returns(IncentivePoolAnnum.IncentivePoolAnnumState memory) {
        return incentivePoolAnnums.getCurrentAnnum();
    }

    /**
     * @notice Set the topup configuration for a reward service.
     * @param _incentivePoolReceiver    The reward service to receive the incentivePool funds for distribution.
     * @param _topupType            The type to signal how the topup amounts are to be calculated.
     *                              FACTOROFDAILYAUTHORIZED = Use a factor of last daily authorized to set a
     *                              target balance for a reward service to maintain as a reserve for claiming.
     *                              ALLAUTHORIZED = Mint enough native tokens to topup reward service contract to hold
     *                              all authorized but unrequested rewards.
     * @param _topupFactorX100      If _topupType == FACTOROFDAILYAUTHORIZED, then this factor (times 100)
     *                              is multipled by last daily authorized incentive to obtain the
     *                              maximum balance that a reward service can hold at any given time. If it holds less,
     *                              then this max amount is used to compute the mint request topup required to 
     *                              bring the reward service contract native token balance up to that amount.
     * @dev Topup factor, if _topupType == FACTOROFDAILYAUTHORIZED, must be > 100 and <= 400.
     */
    function setTopupConfiguration(
        IIIncentivePoolReceiver _incentivePoolReceiver, 
        TopupType _topupType, 
        uint256 _topupFactorX100
    )
        external
        notZero(address(_incentivePoolReceiver))
        onlyGovernance
    {
        if (_topupType == TopupType.FACTOROFDAILYAUTHORIZED) {
            require(_topupFactorX100 > 100, ERR_TOPUP_LOW);
            require(_topupFactorX100 <= MAX_DAILY_TOPUP_FACTOR_X100, ERR_TOPUP_HIGH);
        }
        TopupConfiguration storage topupConfiguration = topupConfigurations[_incentivePoolReceiver];
        topupConfiguration.topupType = _topupType;
        topupConfiguration.topupFactorX100 = _topupFactorX100;
        topupConfiguration.configured = true;

        emit TopupConfigurationSet(topupConfiguration);
    }

    /**
     * @notice Given an incentivePool receiver, get the topup configuration.
     * @param _incentivePoolReceiver    The reward service.
     * @return _topupConfiguration  The configurartion of how the topup requests are calculated for a given
     *                              reward service.
     */
    function getTopupConfiguration(
        IIIncentivePoolReceiver _incentivePoolReceiver
    )
        external
        notZero(address(_incentivePoolReceiver))
        returns(TopupConfiguration memory _topupConfiguration)
    {
        TopupConfiguration storage topupConfiguration = topupConfigurations[_incentivePoolReceiver];
        if (!topupConfiguration.configured) {
            topupConfiguration.topupType = TopupType.FACTOROFDAILYAUTHORIZED;
            topupConfiguration.topupFactorX100 = DEFAULT_TOPUP_FACTOR_X100;
            topupConfiguration.configured = true;
        }
        _topupConfiguration.topupType = topupConfiguration.topupType;
        _topupConfiguration.topupFactorX100 = topupConfiguration.topupFactorX100;
        _topupConfiguration.configured = topupConfiguration.configured;
    }

    /**
     * @notice Pulsed by the FlareDaemon to trigger timing-based events for the incentive process.
     * @dev There are two events:
     *   1) an annual event to recognize incentive for a new annum
     *   2) a daily event to:
     *     a) authorize incentive for rewarding
     *     b) distribute enough native tokens to topup reward services for claiming reserves
     */
    function daemonize() external virtual override notZero(address(supply)) onlyFlareDaemon returns(bool) {
        // If incentive rewarding not started yet, blow off processing until it does.
        if (rewardEpochStartTs == 0 || block.timestamp < rewardEpochStartTs) {
            return true;
        }

        // If incetive rewarding started and we have not updated when it started, do so now.
        if (rewardEpochStartedTs == 0) {
            rewardEpochStartedTs = block.timestamp;
        }

        // Is it time to recognize an initial incentivePool annum?
        if (incentivePoolAnnums.getCount() == 0) {
            _initNewAnnum(block.timestamp);
        } else {
            uint256 currentAnnumEndTimeStamp = incentivePoolAnnums.getCurrentAnnum().endTimeStamp;

            // Is it time to recognize a new incentivePool annum?
            if (block.timestamp > currentAnnumEndTimeStamp) {
                _initNewAnnum(currentAnnumEndTimeStamp.add(1));
            }
        }

        // Is it time to authorize new incentive? Do it daily.
        if (lastAuthorizationTs.add(AUTHORIZE_TIME_FRAME_SEC) <= block.timestamp) {
            // Update time we last authorized.
            lastAuthorizationTs = block.timestamp;

            // Authorize incentive for current sharing percentages.
            uint256 amountAuthorizedWei = incentivePoolAnnums.authorizeDailyIncentive(
                block.timestamp,
                treasury.MAX_DAILY_PULL_AMOUNT_WEI().mulDiv(100, MAX_DAILY_TOPUP_FACTOR_X100),
                incentivePoolAllocation.getSharingPercentages()
            );

            emit IncentiveAuthorized(amountAuthorizedWei);

            // Time to compute topup amount for incentivePool receivers.
            uint256 topupRequestWei = incentivePoolAnnums.computeTopupRequest(this);
            emit TopupRequested(topupRequestWei);
            // Pull funds from treasury contract
            treasury.pullFunds(topupRequestWei);
            // Distribute received funds
            uint256 amountPostedWei = incentivePoolAnnums.distributeTopupRequest();
            // calculated and distributed amount should be the same
            assert(topupRequestWei == amountPostedWei);
        }
        return true;
    }

    function switchToFallbackMode() external view override onlyFlareDaemon returns (bool) {
        // do nothing - there is no fallback mode in IncentivePool
        return false;
    }

    /**
     * @notice Implement this function for updating daemonized contracts through AddressUpdater.
     */
    function getContractName() external pure override returns (string memory) {
        return "IncentivePool";
    }

    /**
     * @notice Returns next expected incentive topup timestamp which is also incentive authorization time. 
     *     The returned time from this API is actually the time of the block in which the topup is requested. 
     *     The Actual topup will take place in the same block.
     */
    function getNextExpectedTopupTs() external view returns (uint256 _nextTopupTs) {
        _nextTopupTs = lastAuthorizationTs.add(AUTHORIZE_TIME_FRAME_SEC);
    }

    /**
     * @notice Implementation of the AddressUpdatable abstract method - updates supply and incentivePool allocation.
     * @notice Set a reference to a provider of sharing percentages by incentivePool receiver.
     * @dev Assume that sharing percentages sum to 100% if at least one exists, but
     *      if no sharing percentages are defined, then no incentive will be authorized.
     * @notice Set a reference to a provider of the annual incentivePool percentage.
     * @dev Assume that referencing contract has reasonablness limitations on percentages.
     */
    function _updateContractAddresses(
        bytes32[] memory _contractNameHashes,
        address[] memory _contractAddresses
    )
        internal override
    {
        IISupply _supply = IISupply(_getContractAddress(_contractNameHashes, _contractAddresses, "Supply"));
        emit SupplySet(supply, _supply);
        supply = _supply;

        incentivePoolAllocation = IIIncentivePoolAllocation(
            _getContractAddress(_contractNameHashes, _contractAddresses, "IncentivePoolAllocation"));
        emit IncentivePoolAllocationSet(incentivePoolAllocation);
    }

    function _initNewAnnum(uint256 startTs) internal {
        uint256 inflatableSupply = supply.getInflatableBalance();
        uint256 freeTreasuryBalance = address(treasury).balance
            .add(incentivePoolAnnums.totalIncentiveTopupWithdrawnWei)
            .sub(incentivePoolAnnums.totalAuthorizedIncentiveWei);

        try incentivePoolAllocation.getAnnualPercentageBips() returns(uint256 annualPercentBips) {
            incentivePoolAnnums.initializeNewAnnum(startTs, freeTreasuryBalance, inflatableSupply, annualPercentBips);
        } catch Error(string memory message) {
            revert(message);
        } catch {
            revert(ERR_GET_ANNUAL_PERCENT);
        }

        IncentivePoolAnnum.IncentivePoolAnnumState memory incentivePoolAnnum = incentivePoolAnnums.getCurrentAnnum();

        emit NewAnnumInitialized(
            incentivePoolAnnum.startTimeStamp,
            incentivePoolAnnum.endTimeStamp,
            inflatableSupply,
            incentivePoolAnnum.recognizedIncentiveWei,
            incentivePoolAnnum.incentivePoolRewardServices.totalAuthorizedIncentiveWei,
            incentivePoolAnnum.incentivePoolRewardServices.totalIncentiveTopupRequestedWei,
            incentivePoolAnnum.incentivePoolRewardServices.totalIncentiveTopupReceivedWei,
            incentivePoolAnnum.incentivePoolRewardServices.totalIncentiveTopupWithdrawnWei
        );
    }
}
        

./contracts/governance/implementation/Governed.sol

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

import { GovernedBase } from "./GovernedBase.sol";


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

./contracts/genesis/implementation/IncentivePoolTreasury.sol

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

import "../../governance/implementation/GovernedAtGenesis.sol";


/**
 * @title Incentive pool treasury
 * @notice A genesis contract which holds the entire treasury for the incentive pool.
 *         It enables limited flow of funds to the incentive pool.
 */
contract IncentivePoolTreasury is GovernedAtGenesis {

    // How often can incentive pool pull funds - 23 hours constant
    uint256 internal constant MAX_PULL_FREQUENCY_SEC = 23 hours;
    uint256 public constant MAX_DAILY_PULL_AMOUNT_WEI = 25000000 ether;

    // Errors
    string internal constant ERR_INCENTIVE_POOL_ONLY = "incentive pool only";
    string internal constant ERR_TOO_OFTEN = "too often";
    string internal constant ERR_TOO_MUCH = "too much";
    string internal constant ERR_PULL_FAILED = "pull failed";
    string internal constant ERR_ALREADY_SET = "already set";

    // Storage
    address public incentivePool;
    uint256 public lastPullTs;


    modifier onlyIncentivePool {
        require (msg.sender == incentivePool, ERR_INCENTIVE_POOL_ONLY);
        _;
    }

    /**
     * @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 */
    }

    /**
     * @notice Sets incentive pool contract address.
     * @param _incentivePool            Incentive pool contract address.
     */
    function setIncentivePoolContract(address _incentivePool) external onlyGovernance {
        require(incentivePool == address(0), ERR_ALREADY_SET);
        incentivePool = _incentivePool;
    }

    /**
     * @notice Moves funds to the incentive pool contract (once per day)
     * @param _amountWei   The amount of wei to pull to incentive pool contract
     */
    function pullFunds(uint256 _amountWei) external onlyIncentivePool {
        // this also serves as reentrancy guard, since any re-entry will happen in the same block
        require(lastPullTs + MAX_PULL_FREQUENCY_SEC <= block.timestamp, ERR_TOO_OFTEN);
        require(_amountWei <= MAX_DAILY_PULL_AMOUNT_WEI, ERR_TOO_MUCH);
        lastPullTs = block.timestamp;
        /* solhint-disable avoid-low-level-calls */
        //slither-disable-next-line arbitrary-send
        (bool success, ) = msg.sender.call{value: _amountWei}("");
        /* solhint-enable avoid-low-level-calls */
        require(success, ERR_PULL_FAILED);
    }
}
          

./contracts/genesis/interface/IFlareDaemonize.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6 <0.9;


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

    
    /// Implement this function for updating daemonized contracts through AddressUpdater.
    function getContractName() external view returns (string memory);
}
          

./contracts/addressUpdater/implementation/AddressUpdatable.sol

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

import "../interface/IIAddressUpdatable.sol";


abstract contract AddressUpdatable is IIAddressUpdatable {

    // https://docs.soliditylang.org/en/v0.8.7/contracts.html#constant-and-immutable-state-variables
    // No storage slot is allocated
    bytes32 internal constant ADDRESS_STORAGE_POSITION = 
        keccak256("flare.diamond.AddressUpdatable.ADDRESS_STORAGE_POSITION");

    modifier onlyAddressUpdater() {
        require (msg.sender == getAddressUpdater(), "only address updater");
        _;
    }

    constructor(address _addressUpdater) {
        setAddressUpdaterValue(_addressUpdater);
    }

    function getAddressUpdater() public view returns (address _addressUpdater) {
        // Only direct constants are allowed in inline assembly, so we assign it here
        bytes32 position = ADDRESS_STORAGE_POSITION;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            _addressUpdater := sload(position)
        }
    }

    /**
     * @notice external method called from AddressUpdater only
     */
    function updateContractAddresses(
        bytes32[] memory _contractNameHashes,
        address[] memory _contractAddresses
    )
        external override
        onlyAddressUpdater
    {
        // update addressUpdater address
        setAddressUpdaterValue(_getContractAddress(_contractNameHashes, _contractAddresses, "AddressUpdater"));
        // update all other addresses
        _updateContractAddresses(_contractNameHashes, _contractAddresses);
    }

    /**
     * @notice virtual method that a contract extending AddressUpdatable must implement
     */
    function _updateContractAddresses(
        bytes32[] memory _contractNameHashes,
        address[] memory _contractAddresses
    ) internal virtual;

    /**
     * @notice helper method to get contract address
     * @dev it reverts if contract name does not exist
     */
    function _getContractAddress(
        bytes32[] memory _nameHashes,
        address[] memory _addresses,
        string memory _nameToFind
    )
        internal pure
        returns(address)
    {
        bytes32 nameHash = keccak256(abi.encode(_nameToFind));
        address a = address(0);
        for (uint256 i = 0; i < _nameHashes.length; i++) {
            if (nameHash == _nameHashes[i]) {
                a = _addresses[i];
                break;
            }
        }
        require(a != address(0), "address zero");
        return a;
    }

    function setAddressUpdaterValue(address _addressUpdater) internal {
        // Only direct constants are allowed in inline assembly, so we assign it here
        bytes32 position = ADDRESS_STORAGE_POSITION;
        // solhint-disable-next-line no-inline-assembly  
        assembly {
            sstore(position, _addressUpdater)
        }
    }
}
          

./contracts/addressUpdater/interface/IIAddressUpdatable.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6 <0.9;


interface IIAddressUpdatable {
    /**
     * @notice Updates contract addresses - should be called only from AddressUpdater contract
     * @param _contractNameHashes       list of keccak256(abi.encode(...)) contract names
     * @param _contractAddresses        list of contract addresses corresponding to the contract names
     */
    function updateContractAddresses(
        bytes32[] memory _contractNameHashes,
        address[] memory _contractAddresses
        ) external;
}
          

./contracts/genesis/implementation/FlareDaemon.sol

// SPDX-License-Identifier: MIT
// 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;
pragma abicoder v2;

import "../../governance/implementation/GovernedAtGenesis.sol";
import "../../addressUpdater/implementation/AddressUpdatable.sol";
import "../interface/IInflationGenesis.sol";
import "../interface/IFlareDaemonize.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "../../utils/implementation/SafePct.sol";


/**
 * @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, AddressUpdatable {
    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_ALREADY_SET = "already set";
    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 - 60 million native token
    uint256 internal constant MAX_MINTING_REQUEST_DEFAULT = 60000000 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 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)) AddressUpdatable(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[] memory _registrations) external onlyGovernance {
        _registerToDaemonize(_registrations);
    }

    /**
     * @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 address udpater contract.
     * @param _addressUpdater   The address updater contract.
     */
    function setAddressUpdater(address _addressUpdater) external onlyGovernance {
        require(getAddressUpdater() == address(0), ERR_ALREADY_SET);
        setAddressUpdaterValue(_addressUpdater);
    }

    /**
     * @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 onlySystemTrigger returns (uint256 _toMintWei) {
        return triggerInternal();
    }

    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 AddressUpdatable abstract method - updates Inflation and daemonized contracts.
     * @dev It also sets `maxMintingRequestWei` if it was not set before.
     */
    function _updateContractAddresses(
        bytes32[] memory _contractNameHashes,
        address[] memory _contractAddresses
    )
        internal override
    {
        IInflationGenesis _inflation = IInflationGenesis(
            _getContractAddress(_contractNameHashes, _contractAddresses, "Inflation"));
        emit InflationSet(_inflation, inflation);
        inflation = _inflation;
        if (maxMintingRequestWei == 0) {
            maxMintingRequestWei = MAX_MINTING_REQUEST_DEFAULT;
        }

        uint256 len = daemonizeContracts.length;
        if (len == 0) {
            return;
        }

        Registration[] memory registrations = new Registration[](len);
        for (uint256 i = 0; i < len; i++) {
            IFlareDaemonize daemonizeContract = daemonizeContracts[i];
            registrations[i].daemonizedContract = IFlareDaemonize(
                _getContractAddress(_contractNameHashes, _contractAddresses, daemonizeContract.getContractName()));
            registrations[i].gasLimit = gasLimits[daemonizeContract];
        }

        _registerToDaemonize(registrations);
    }

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

        // Update balance
        lastBalance = address(this).balance;
        
        // 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);
        }
    }

    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 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[] memory _registrations) internal {
        // 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 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);
    }
}
          

./contracts/genesis/interface/IInflationGenesis.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6 <0.9;


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

./contracts/governance/implementation/GovernedAtGenesis.sol

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

import "./GovernedBase.sol";


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

./contracts/governance/implementation/GovernedBase.sol

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

import "../../userInterfaces/IGovernanceSettings.sol";


/**
 * @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 {
    struct TimelockedCall {
        uint256 allowedAfterTimestamp;
        bytes encodedCall;
    }
    
    // solhint-disable-next-line const-name-snakecase
    IGovernanceSettings public constant governanceSettings = 
        IGovernanceSettings(0x1000000000000000000000000000000000000007);

    address private initialGovernance;

    bool private initialised;
    
    bool public productionMode;
    
    bool private executing;
    
    mapping(bytes4 => TimelockedCall) public timelockedCalls;
    
    event GovernanceCallTimelocked(bytes4 selector, uint256 allowedAfterTimestamp, bytes encodedCall);
    event TimelockedGovernanceCallExecuted(bytes4 selector, uint256 timestamp);
    event TimelockedGovernanceCallCanceled(bytes4 selector, uint256 timestamp);
    
    event GovernanceInitialised(address initialGovernance);
    event GovernedProductionModeEntered(address governanceSettings);
    
    modifier onlyGovernance {
        if (executing || !productionMode) {
            _beforeExecute();
            _;
        } else {
            _recordTimelockedCall(msg.data);
        }
    }
    
    modifier onlyImmediateGovernance () {
        _checkOnlyGovernance();
        _;
    }

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

    /**
     * @notice Execute the timelocked governance calls once the timelock period expires.
     * @dev Only executor can call this method.
     * @param _selector The method selector (only one timelocked call per method is stored).
     */
    function executeGovernanceCall(bytes4 _selector) external {
        require(governanceSettings.isExecutor(msg.sender), "only executor");
        TimelockedCall storage call = timelockedCalls[_selector];
        require(call.allowedAfterTimestamp != 0, "timelock: invalid selector");
        require(block.timestamp >= call.allowedAfterTimestamp, "timelock: not allowed yet");
        bytes memory encodedCall = call.encodedCall;
        delete timelockedCalls[_selector];
        executing = true;
        //solhint-disable-next-line avoid-low-level-calls
        (bool success,) = address(this).call(encodedCall);
        executing = false;
        emit TimelockedGovernanceCallExecuted(_selector, block.timestamp);
        _passReturnOrRevert(success);
    }
    
    /**
     * Cancel a timelocked governance call before it has been executed.
     * @dev Only governance can call this method.
     * @param _selector The method selector.
     */
    function cancelGovernanceCall(bytes4 _selector) external onlyImmediateGovernance {
        require(timelockedCalls[_selector].allowedAfterTimestamp != 0, "timelock: invalid selector");
        emit TimelockedGovernanceCallCanceled(_selector, block.timestamp);
        delete timelockedCalls[_selector];
    }
    
    /**
     * Enter the production mode after all the initial governance settings have been set.
     * This enables timelocks and the governance is afterwards obtained by calling 
     * governanceSettings.getGovernanceAddress(). 
     */
    function switchToProductionMode() external {
        _checkOnlyGovernance();
        require(!productionMode, "already in production mode");
        initialGovernance = address(0);
        productionMode = true;
        emit GovernedProductionModeEntered(address(governanceSettings));
    }

    /**
     * @notice Initialize the governance address if not first initialized.
     */
    function initialise(address _initialGovernance) public virtual {
        require(initialised == false, "initialised != false");
        initialised = true;
        initialGovernance = _initialGovernance;
        emit GovernanceInitialised(_initialGovernance);
    }
    
    /**
     * Returns the current effective governance address.
     */
    function governance() public view returns (address) {
        return productionMode ? governanceSettings.getGovernanceAddress() : initialGovernance;
    }

    function _beforeExecute() private {
        if (executing) {
            // can only be run from executeGovernanceCall(), where we check that only executor can call
            // make sure nothing else gets executed, even in case of reentrancy
            assert(msg.sender == address(this));
            executing = false;
        } else {
            // must be called with: productionMode=false
            // must check governance in this case
            _checkOnlyGovernance();
        }
    }

    function _recordTimelockedCall(bytes calldata _data) private {
        _checkOnlyGovernance();
        bytes4 selector;
        //solhint-disable-next-line no-inline-assembly
        assembly {
            selector := calldataload(_data.offset)
        }
        uint256 timelock = governanceSettings.getTimelock();
        uint256 allowedAt = block.timestamp + timelock;
        timelockedCalls[selector] = TimelockedCall({
            allowedAfterTimestamp: allowedAt,
            encodedCall: _data
        });
        emit GovernanceCallTimelocked(selector, allowedAt, _data);
    }
    
    function _checkOnlyGovernance() private view {
        require(msg.sender == governance(), "only governance");
    }
    
    function _passReturnOrRevert(bool _success) private pure {
        // pass exact return or revert data - needs to be done in assembly
        //solhint-disable-next-line no-inline-assembly
        assembly {
            let size := returndatasize()
            let ptr := mload(0x40)
            mstore(0x40, add(ptr, size))
            returndatacopy(ptr, 0, size)
            if _success {
                return(ptr, size)
            }
            revert(ptr, size)
        }
    }
}
          

./contracts/inflation/interface/IISupply.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6 <0.9;


interface IISupply {

    /**
     * @notice Updates circulating supply
     * @dev Also updates the burn address amount
    */
    function updateCirculatingSupply() 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);
}
          

./contracts/tokenPools/interface/IIIncentivePoolAllocation.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6 <0.9;
pragma abicoder v2;

import "./IIIncentivePoolPercentageProvider.sol";
import "./IIIncentivePoolSharingPercentageProvider.sol";

interface IIIncentivePoolAllocation is IIIncentivePoolPercentageProvider, IIIncentivePoolSharingPercentageProvider {
    
}
          

./contracts/tokenPools/interface/IIIncentivePoolPercentageProvider.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6 <0.9;

interface IIIncentivePoolPercentageProvider {
    /**
     * Return the annual incentivePool rate in bips.
     */
    function getAnnualPercentageBips() external returns(uint256);
}
          

./contracts/tokenPools/interface/IIIncentivePoolReceiver.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6 <0.9;

interface IIIncentivePoolReceiver {
    /**
     * Notify the receiver that it is entitled to receive `_toAuthorizeWei` incentive amount.
     * @param _toAuthorizeWei the amount of incentive that can be awarded in the coming day
     */
    function setDailyAuthorizedIncentive(uint256 _toAuthorizeWei) external;
    
    /**
     * Receive native tokens from incentivePool.
     */
    function receiveIncentive() external payable;

    /**
     * IncentivePool receivers have a reference to the IncentivePool contract.
     */
    function getIncentivePoolAddress() external returns(address);
    
    /**
     * Implement this function for updating incentivePool receiver contracts through AddressUpdater.
     */
    function getContractName() external view returns (string memory);
}
          

./contracts/tokenPools/interface/IIIncentivePoolSharingPercentageProvider.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6 <0.9;
pragma abicoder v2;

import "./IIIncentivePoolReceiver.sol";

struct SharingPercentage {
    IIIncentivePoolReceiver incentivePoolReceiver;
    uint256 percentBips;
}

interface IIIncentivePoolSharingPercentageProvider {
    /**
     * Return the shared percentage per incentivPool receiver.
     * @dev Assumption is that implementer edited that percents sum to 100 pct and
     *   that receiver addresses are valid.
     */
    function getSharingPercentages() external returns(SharingPercentage[] memory);
}
          

./contracts/tokenPools/interface/IITokenPool.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.6 <0.9;

interface IITokenPool {

    /**
     * @notice Return token pool supply data
     * @return _lockedFundsWei                  Funds that are intentionally locked in the token pool 
     * and not part of circulating supply
     * @return _totalInflationAuthorizedWei     Total inflation authorized amount (wei)
     * @return _totalClaimedWei                 Total claimed amount (wei)
     */
    function getTokenPoolSupplyData() external returns (
        uint256 _lockedFundsWei,
        uint256 _totalInflationAuthorizedWei,
        uint256 _totalClaimedWei
    );
}
          

./contracts/tokenPools/lib/IncentivePoolAnnum.sol

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

import "../../utils/implementation/DateTimeLibrary.sol";
import "./IncentivePoolRewardServices.sol";
import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts/utils/SafeCast.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "../../utils/implementation/SafePct.sol";


/**
 * @title IncentivePool Annum library
 * @notice A library to manage an incentivePool annum. 
 **/
library IncentivePoolAnnum {    
    using BokkyPooBahsDateTimeLibrary for uint256;
    using IncentivePoolAnnum for IncentivePoolAnnum.IncentivePoolAnnumState;
    using SafeCast for uint256;
    using SafeMath for uint256;
    using SafePct for uint256;

    /**
     * @dev `IncentivePoolAnnumState` is state structure used by this library to manage
     *   an incentivePool annum.
     */
    struct IncentivePoolAnnumState {
        uint256 recognizedIncentiveWei;
        uint256 startTimeStamp;
        uint256 endTimeStamp;
        IncentivePoolRewardServices.IncentivePoolRewardServicesState incentivePoolRewardServices;
    }

    uint256 internal constant BIPS100 = 1e4;                                // 100% in basis points
    uint256 internal constant MAX_ANNUAL_FACTOR_BIPS = 1e3;                 // 10% in basis points

    /**
     * @notice Helper function to compute recognized incentive.
     * @param _treasuryBalance                      The treasury balance used to recognize incentive.
     * @param _inflatableBalance                    The inflatable balance used to recognize incentive.
     * @param _annualIncentivePoolPercentageBips    The annual percentage used to recognize incentive.
     * @return The computed recognized incentive.
     */
    function _computeRecognizedIncentiveWei(
        uint256 _treasuryBalance,
        uint256 _inflatableBalance, 
        uint256 _annualIncentivePoolPercentageBips
    ) 
        internal pure
        returns(uint256)
    {
        return Math.min(
            _inflatableBalance.mulDiv(_annualIncentivePoolPercentageBips, 12 * BIPS100),
            _treasuryBalance.mulDiv(MAX_ANNUAL_FACTOR_BIPS, 12 * BIPS100)
        ); // monthly incentive
    }

    /**
     * @notice Helper function to compute the number of days remaining in an annum.
     * @param _atTimeStamp  Compute the number of days for the annum at this time stamp.
     * @return The number of days computed.
     * @dev If _atTimeStamp is after the end of the annum, 0 days will be returned.
     */
    function _computeDaysRemainingInAnnum(
        IncentivePoolAnnumState storage _self, 
        uint256 _atTimeStamp
    )
        internal view
        returns(uint256)
    {
        uint256 endTimeStamp = _self.endTimeStamp;
        if (_atTimeStamp > endTimeStamp) {
            return 0;
        } else {
            return _atTimeStamp.diffDays(endTimeStamp);
        }
    }

    /**
     * @notice Given a start time stamp, compute the end time stamp for an annum.
     * @param _startTimeStamp The start time stamp for an annum.
     * @return The end time stamp for the annum.
     */
    function _getAnnumEndsTs(uint256 _startTimeStamp) internal pure returns (uint256) {
        // This should cover passing through Feb 29
        return _startTimeStamp.addDays(30).subSeconds(1);
    }

    /**
     * @notice Compute the number of periods remaining within an annum.
     * @param _atTimeStamp  Compute periods remaining at this time stamp.
     * @return The number of periods remaining.
     * @dev The number of periods must include the current day.
     */
    function getPeriodsRemaining(
        IncentivePoolAnnumState storage _self, 
        uint256 _atTimeStamp
    )
        internal view 
        returns(uint256)
    {
        assert(_atTimeStamp <= _self.endTimeStamp);
        // Add 1 to the periods remaining because the difference between days does not count the current day.
        return _computeDaysRemainingInAnnum(_self, _atTimeStamp).add(1);
    }

    /**
     * @notice Initialize a new annum data structure.
     * @param _startTimeStamp                       The start time stamp of the new annum.
     * @param _treasuryBalance                      The treasury balance used to calculate recognized 
     *                                              incentive for the new annum.
     * @param _inflatableBalanceWei                 The inflatable balance used to calculate recognized 
     *                                              incentive for the new annum.
     * @param _annualIncentivePoolPercentageBips    The annual incentivePool percentage in bips to calc recognized 
     *                                              incentivePool.
     * @dev A newly created IncentivePoolAnnumState is expected to exist.
     */
    function initialize(
        IncentivePoolAnnumState storage _self,
        uint256 _startTimeStamp, 
        uint256 _treasuryBalance, 
        uint256 _inflatableBalanceWei, 
        uint256 _annualIncentivePoolPercentageBips
    ) 
        internal
    {
        _self.startTimeStamp = _startTimeStamp;
        _self.recognizedIncentiveWei = _computeRecognizedIncentiveWei(
            _treasuryBalance,
            _inflatableBalanceWei, 
            _annualIncentivePoolPercentageBips);
        _self.endTimeStamp = _getAnnumEndsTs(_startTimeStamp);
    }
}
          

./contracts/tokenPools/lib/IncentivePoolAnnums.sol

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

import "../implementation/IncentivePool.sol";
import "./IncentivePoolAnnum.sol";
import "./IncentivePoolRewardServices.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "../../utils/implementation/SafePct.sol";
import "../interface/IIIncentivePoolSharingPercentageProvider.sol";


/**
 * @title IncentivePool Annums library
 * @notice A library to manage a collection of incentivePool annum and associated totals.
 * @dev Operations such as authorizing daily incentive are dispatched from this collection
 *  library because the result of the authorization is added to the total authorized across
 *  all annums, which is a concern of this library and not the concern of a given annum, nor the caller.
 **/
library IncentivePoolAnnums {    
    using IncentivePoolAnnum for IncentivePoolAnnum.IncentivePoolAnnumState;
    using IncentivePoolRewardServices for IncentivePoolRewardServices.IncentivePoolRewardServicesState;
    using SafeMath for uint256;
    using SafePct for uint256;

    /**
     * @dev `IncentivePoolAnnumsState` is state structure used by this library to manage
     *   a collection of incentivePool annums and associated totals.
     */
    struct IncentivePoolAnnumsState {
        // Collection of annums
        IncentivePoolAnnum.IncentivePoolAnnumState[] incentivePoolAnnums;
        uint256 currentAnnum;
        // Balances
        uint256 totalRecognizedIncentiveWei;
        uint256 totalAuthorizedIncentiveWei;
        uint256 totalIncentiveTopupRequestedWei;
        uint256 totalIncentiveTopupReceivedWei;
        uint256 totalIncentiveTopupWithdrawnWei;
    }

    string internal constant ERR_NO_ANNUM = "no annum";
    string internal constant ERR_TOO_EARLY = "too early";

    /**
     * @notice Dispatch incentivePool authorization to be performed across all reward services according to their
     *   sharing percentage for the current annum, and then maintain sum total of incentive
     *   authorized across all annums.
     * @param _atTimeStamp  The timestamp at which the number of daily periods remaining in the current
     *   annum will be calculated.
     * @param _maxAuthorizeAmountWei The maximum amount that can be authorized according to treasury pull limits.
     * @param _sharingPercentages   An array of the sharing percentages by incentivePool receiver used to
     *   allocate authorized incentive.
     * @return _amountAuthorizedWei The amount of incentive authorized for this authorization cycle.
     * @dev Invariant: total incentive authorized cannot be greater than total incentive recognized. 
     */
    function authorizeDailyIncentive(
        IncentivePoolAnnumsState storage _self,
        uint256 _atTimeStamp, 
        uint256 _maxAuthorizeAmountWei,
        SharingPercentage[] memory _sharingPercentages
    ) 
        internal
        returns(uint256 _amountAuthorizedWei)
    {
        // Get the current annum
        IncentivePoolAnnum.IncentivePoolAnnumState storage currentAnnum = getCurrentAnnum(_self);

        // Authorize daily incentive for the current annum, across reward services, given
        // sharing percentages.
        _amountAuthorizedWei = currentAnnum.incentivePoolRewardServices.authorizeDailyIncentive(
            _self.totalRecognizedIncentiveWei,
            _self.totalAuthorizedIncentiveWei, 
            currentAnnum.getPeriodsRemaining(_atTimeStamp), 
            _maxAuthorizeAmountWei,
            _sharingPercentages);
        // Accumulate total authorized incentive across all annums
        _self.totalAuthorizedIncentiveWei = _self.totalAuthorizedIncentiveWei.add(_amountAuthorizedWei);
        // Make sure that total authorized never exceeds total recognized
        assert(_self.totalAuthorizedIncentiveWei <= _self.totalRecognizedIncentiveWei);
    }

    /**
     * @notice Dispatch topup request calculations across reward services and sum up total mint request made
     *   to fund topup of reward services.
     * @param _incentivePool    The IncentivePool contract containing the topup confguration of each reward service.
     * @return _topupRequestWei The amount of native token requested across reward services for this cycle.
     * @dev Invariant: total incentive topup requested cannot exceed total incentive authorized
     */
    function computeTopupRequest(
        IncentivePoolAnnumsState storage _self,
        IncentivePool _incentivePool
    )
        internal
        returns(uint256 _topupRequestWei)
    {
        // Get the current annum
        IncentivePoolAnnum.IncentivePoolAnnumState storage currentAnnum = getCurrentAnnum(_self);
        // Compute the topup
        _topupRequestWei = currentAnnum.incentivePoolRewardServices.computeTopupRequest(_incentivePool);
        // Sum the topup request total across annums
        _self.totalIncentiveTopupRequestedWei = _self.totalIncentiveTopupRequestedWei.add(_topupRequestWei);
        // Make sure that total topup requested can never exceed incentive authorized
        assert(_self.totalIncentiveTopupRequestedWei <= _self.totalAuthorizedIncentiveWei);
    }

    /**
     * @notice Distribute native tokens to satisfy reward services topup requests.
     * @return _amountPostedWei The native tokens posted (funded) to reward service contracts.
     * @dev Invariants:
     *   1) Native tokens topup received cannot exceed native tokens topup requested
     *   2) Native tokens topup withdrawn for funding cannot exceed native tokens topup received
     */
    function distributeTopupRequest(
        IncentivePoolAnnumsState storage _self
    )
        internal
        returns(uint256 _amountPostedWei)
    {
        // Get the current annum
        IncentivePoolAnnum.IncentivePoolAnnumState storage currentAnnum = getCurrentAnnum(_self);

        // Distribute topup request. Post to received and withdrawn buckets for each reward service.
        _amountPostedWei = currentAnnum.incentivePoolRewardServices.distributeTopupRequest();
        // Post the amount of native tokens received into the IncentivePool contract
        _self.totalIncentiveTopupReceivedWei = _self.totalIncentiveTopupReceivedWei.add(_amountPostedWei);
        // Received should never be more than requested
        assert(_self.totalIncentiveTopupReceivedWei <= _self.totalIncentiveTopupRequestedWei);
        // Post amount withdrawn and transferred to reward service contracts
        _self.totalIncentiveTopupWithdrawnWei = _self.totalIncentiveTopupWithdrawnWei.add(_amountPostedWei);
        // Withdrawn should never be more than received
        assert(_self.totalIncentiveTopupWithdrawnWei <= _self.totalIncentiveTopupReceivedWei);
    }

    /**
     * @notice Get the number of incentivePool annums.
     * @return The count.
     */
    function getCount(IncentivePoolAnnumsState storage _self) internal view returns(uint256) {
        return _self.incentivePoolAnnums.length;
    }

    /**
     * @notice Given an index, return a given incentivePool annum data.
     * @param _index    The index of the annum to fetch.
     * @return _incentivePoolAnnum  Returns IncentivePoolAnnum.IncentivePoolAnnumState found at _index.
     * @dev Will revert if index not found.
     */
    function getAnnum(
        IncentivePoolAnnumsState storage _self,
        uint256 _index
    )
        internal view
        returns (IncentivePoolAnnum.IncentivePoolAnnumState storage _incentivePoolAnnum)
    {
        require(_index < getCount(_self), ERR_NO_ANNUM);
        _incentivePoolAnnum = _self.incentivePoolAnnums[_index];
    }

    /**
     * @notice Return incentivePool annum data for the current annum.
     * @return _incentivePoolAnnum  Returns IncentivePoolAnnum.IncentivePoolAnnumState for the current annum.
     * @dev Will revert if no current annum.
     */
    function getCurrentAnnum(
        IncentivePoolAnnumsState storage _self
    )
        internal view 
        returns (IncentivePoolAnnum.IncentivePoolAnnumState storage _incentivePoolAnnum)
    {
        require(getCount(_self) > 0, ERR_NO_ANNUM);
        _incentivePoolAnnum = _self.incentivePoolAnnums[_self.currentAnnum];
    }

    /**
     * @notice Initialize a new annum, add it to the annum collection, maintian running total
     *   of recognized incentive resulting from new annum, and set current annum pointer.
     * @param _startTimeStamp                       The timestamp to start the annum.
     * @param _treasuryBalance                      The treasury balance used to recognize incentive.
     * @param _inflatableBalance                    The inflatable balance used to recognize incentive.
     * @param _annualIncentivePoolPercentageBips    The incentivePool percentage in bips to use when recognizing 
     *                                              incentive.
     */
    function initializeNewAnnum(
        IncentivePoolAnnumsState storage _self,
        uint256 _startTimeStamp, 
        uint256 _treasuryBalance, 
        uint256 _inflatableBalance, 
        uint256 _annualIncentivePoolPercentageBips
    ) 
        internal
    {
        // Start time cannot be before last annum ends
        if (getCount(_self) > 0) {
            require(_startTimeStamp > getCurrentAnnum(_self).endTimeStamp, ERR_TOO_EARLY);
        }
        // Create an empty annum
        IncentivePoolAnnum.IncentivePoolAnnumState storage incentivePoolAnnum = _self.incentivePoolAnnums.push();
        // Initialize it with newly passed in annum info
        incentivePoolAnnum.initialize(
            _startTimeStamp, 
            _treasuryBalance, 
            _inflatableBalance, 
            _annualIncentivePoolPercentageBips
        );
        // Accumulate total recognized incentive across annums 
        _self.totalRecognizedIncentiveWei = 
            _self.totalRecognizedIncentiveWei.add(incentivePoolAnnum.recognizedIncentiveWei);
        // Reposition index pointing to current annum
        if (_self.incentivePoolAnnums.length > 1) {
            _self.currentAnnum = _self.currentAnnum.add(1);
        }
    }
}
          

./contracts/tokenPools/lib/IncentivePoolRewardService.sol

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

import "../interface/IIIncentivePoolReceiver.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "../../utils/implementation/SafePct.sol";


enum TopupType{ FACTOROFDAILYAUTHORIZED, ALLAUTHORIZED }

/**
* @notice A struct that defines how mint request topups will be computed for a reward service.
* @param topupType             The type to signal how the topup amounts are to be calculated.
*                              FACTOROFDAILYAUTHORIZED = Use a factor of last daily authorized to set a
*                              target balance for a reward service to maintain as a reserve for claiming.
*                              ALLAUTHORIZED = Mint enough native tokens to topup reward service contract to hold
*                              all authorized but unrequested rewards.
* @param topupFactorX100       If _topupType == FACTOROFDAILYAUTHORIZED, then this factor (times 100)
*                              is multipled by last daily authorized incentive to obtain the
*                              maximum balance that a reward service can hold at any given time. If it holds less,
*                              then this max amount is used to compute the mint request topup required to 
*                              bring the reward service contract native token balance up to that amount.
*/
struct TopupConfiguration {
    TopupType topupType;                            // Topup algo type
    uint256 topupFactorX100;                        // Topup factor, times 100, if applicable for type
    bool configured;                                // Flag to indicate whether initially configured
}

/**
 * @title Reward Service library
 * @notice A library representing a reward service. A reward service consists of a reward contract and
 *   associated incentivePool-related totals. When a topup configuration is applied, a reward service can
 *   also make requests to topup native tokens within a reward contract.
 * @dev A reward service exists within the context of a given incentivePool annum.
 **/
library IncentivePoolRewardService {    
    using SafeMath for uint256;
    using SafePct for uint256;

    /**
     * @dev `IncentivePoolRewardServiceState` is state structure used by this library to manage
     *   an a reward service tracking authorize incentivePool.
     */
    struct IncentivePoolRewardServiceState {
        IIIncentivePoolReceiver incentivePoolReceiver;  // The target rewarding contract
        uint256 authorizedIncentiveWei;                 // Total authorized incentive for this reward service
        uint256 lastDailyAuthorizedIncentiveWei;        // Last daily authorized incentive amount
        uint256 incentivePoolTopupRequestedWei;         // Total incentive topup requested
        uint256 incentivePoolTopupReceivedWei;          // Total incentive topup received
        uint256 incentivePoolTopupWithdrawnWei;         // Total incentive sent to rewarding service contract
    }

    event IncentivePoolRewardServiceTopupComputed(IIIncentivePoolReceiver incentivePoolReceiver, uint256 amountWei);

    /**
     * @notice Maintain authorized incentive total for service.
     * @param _amountWei Amount to add.
     */
    function addAuthorizedIncentive(IncentivePoolRewardServiceState storage _self, uint256 _amountWei) internal {
        _self.authorizedIncentiveWei = _self.authorizedIncentiveWei.add(_amountWei);
        _self.lastDailyAuthorizedIncentiveWei = _amountWei;
    }

    /**
     * @notice Maintain topup native tokens received total for service. 
     * @param _amountWei Amount to add.
     */
    function addTopupReceived(IncentivePoolRewardServiceState storage _self, uint256 _amountWei) internal {
        _self.incentivePoolTopupReceivedWei = _self.incentivePoolTopupReceivedWei.add(_amountWei);
    }

    /**
     * @notice Maintain topup native tokens withdrawn (funded) total for service. 
     * @param _amountWei Amount to add.
     */
    function addTopupWithdrawn(IncentivePoolRewardServiceState storage _self, uint256 _amountWei) internal {
        _self.incentivePoolTopupWithdrawnWei = _self.incentivePoolTopupWithdrawnWei.add(_amountWei);
    }

    /**
     * @notice Given a topup configuration, compute the topup request for the reward contract associated
     *   to the service.
     * @param _topupConfiguration   The topup configuration defining the algo used to compute the topup amount.
     * @return _topupRequestWei     The topup request amount computed.
     */
    function computeTopupRequest(
        IncentivePoolRewardServiceState storage _self,
        TopupConfiguration memory _topupConfiguration
    )
        internal 
        returns (uint256 _topupRequestWei)
    {
        // Get the balance of the incentivePool receiver
        uint256 incentivePoolReceiverBalanceWei = address(_self.incentivePoolReceiver).balance;
        if (_topupConfiguration.topupType == TopupType.FACTOROFDAILYAUTHORIZED) {
            // Compute a topup request based purely on the given factor, the last daily authorization, and
            // the balance that is sitting in the reward service contract.
            uint256 requestedBalanceWei = _self.lastDailyAuthorizedIncentiveWei
                .mulDiv(_topupConfiguration.topupFactorX100, 100);
            uint256 rawTopupRequestWei = 0;
            // If current balance is less then requested, request some more.
            if (requestedBalanceWei > incentivePoolReceiverBalanceWei) {
                rawTopupRequestWei = requestedBalanceWei.sub(incentivePoolReceiverBalanceWei);
            }
            // Compute what is already pending to be topped up
            uint256 topupPendingWei = getPendingTopup(_self);
            // If what is pending to topup is greater than the raw request, request no more.
            if (topupPendingWei > rawTopupRequestWei) {
                _topupRequestWei = 0;
            } else {
                // Back out any request that is already pending
                _topupRequestWei = rawTopupRequestWei.sub(topupPendingWei);
            }
            // And finally, in any case, topup requested cannot be more than the net of 
            // authorized, pending, and received
            uint256 maxTopupRequestWei = _self.authorizedIncentiveWei
                .sub(topupPendingWei)
                .sub(_self.incentivePoolTopupReceivedWei);
            if (_topupRequestWei > maxTopupRequestWei) {
                _topupRequestWei = maxTopupRequestWei;
            }
        } else if (_topupConfiguration.topupType == TopupType.ALLAUTHORIZED) {
            _topupRequestWei = _self.authorizedIncentiveWei
                .sub(_self.incentivePoolTopupRequestedWei);
        } else { // This code is unreachable since TopupType currently has only 2 constructors
            _topupRequestWei = 0;
            assert(false);
        }
        _self.incentivePoolTopupRequestedWei = _self.incentivePoolTopupRequestedWei.add(_topupRequestWei);
        
        emit IncentivePoolRewardServiceTopupComputed(_self.incentivePoolReceiver, _topupRequestWei);
    }

    /**
     * @notice Compute a pending topup request.
     * @return _pendingTopupWei The amount pending to be sent.
     */
    function getPendingTopup(
        IncentivePoolRewardServiceState storage _self
    )
        internal view
        returns(uint256 _pendingTopupWei)
    {
        return _self.incentivePoolTopupRequestedWei.sub(_self.incentivePoolTopupReceivedWei);        
    }

    /**
     * @notice Initial a new reward service.
     * @dev Assume service is already instantiated.
     */
    function initialize(
        IncentivePoolRewardServiceState storage _self,
        IIIncentivePoolReceiver _incentivePoolReceiver
    ) 
        internal
    {
        _self.incentivePoolReceiver = _incentivePoolReceiver;
        _self.authorizedIncentiveWei = 0;
        _self.lastDailyAuthorizedIncentiveWei = 0;
        _self.incentivePoolTopupRequestedWei = 0;
        _self.incentivePoolTopupReceivedWei = 0;
        _self.incentivePoolTopupWithdrawnWei = 0;
    }
}
          

./contracts/tokenPools/lib/IncentivePoolRewardServices.sol

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

import "../../utils/implementation/DateTimeLibrary.sol";
import "../implementation/IncentivePool.sol";
import "../interface/IIIncentivePoolReceiver.sol";
import "./IncentivePoolRewardService.sol";
import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "../../utils/implementation/SafePct.sol";
import "../interface/IIIncentivePoolSharingPercentageProvider.sol";
import "./IncentivePoolRewardService.sol";


/**
 * @title Incentive Pool Reward Services library
 * @notice A library to manage a collection of reward services, their associated totals, and to perform operations
 *  that impact or involve the collection, such as calculating topup amounts across services.
 * @dev There are two concepts that are helpful to understand. A sharing percentage associates an incentivePool
 *  receiver with a sharing percentage used to calculate percentage of authorized incentive a given reward contract
 *  is entitled to receive for distributing rewards. A reward service is associtated to a topup configuration, which
 *  dictates how much native token will be sent for claiming reserves, and it stores totals for a given 
 *  incentivePool receiver, for a given annum.
 **/
library IncentivePoolRewardServices {    
    using BokkyPooBahsDateTimeLibrary for uint256;
    using IncentivePoolRewardService for IncentivePoolRewardService.IncentivePoolRewardServiceState;
    using SafeMath for uint256;
    using SafePct for uint256;

    /**
     * @dev `IncentivePoolRewardServicesState` is state structure used by this library to manage
     *   a collection of reward services and associated totals.
     */
    struct IncentivePoolRewardServicesState {
        // Collection of annums
        IncentivePoolRewardService.IncentivePoolRewardServiceState[] incentivePoolRewardServices;
        // Balances
        uint256 totalAuthorizedIncentiveWei;
        uint256 totalIncentiveTopupRequestedWei;
        uint256 totalIncentiveTopupReceivedWei;
        uint256 totalIncentiveTopupWithdrawnWei;
    }

    uint256 internal constant BIPS100 = 1e4;                            // 100% in basis points

    event IncentivePoolRewardServiceDailyAuthorizedIncentiveComputed(
        IIIncentivePoolReceiver incentivePoolReceiver,
        uint256 amountWei);
    event IncentivePoolRewardServiceTopupRequestReceived(
        IIIncentivePoolReceiver incentivePoolReceiver,
        uint256 amountWei);

    /**
     * @notice For all sharing percentages, compute authorized daily incentive for current cycle
     *  and then allocate it across associated incentivePool receivers according to their sharing percentages, 
     *  updating reward service totals along the way. Finally,
     *  set the daily authorized incentive for the given incentivePool receiver.
     * @param _totalRecognizedIncentiveWei The total recognized incentive across all annums.
     * @param _totalAuthorizedIncentiveWei The total authorized incentive across all annums.
     * @param _periodsRemaining The number of periods remaining in the current annum.
     * @param _maxAuthorizeAmountWei The maximum amount that can be authorized according to treasury pull limits.
     * @param _sharingPercentages An array of incentive sharing percentages.
     * @return _amountAuthorizedWei The incentive authorized for this cycle.
     * @dev This method requires totals across all annums so as to continually calculate
     *   the amount remaining to be authorized regardless of timing slippage between annums should it
     *   occur.
     */
    function authorizeDailyIncentive(
        IncentivePoolRewardServicesState storage _self,
        uint256 _totalRecognizedIncentiveWei,
        uint256 _totalAuthorizedIncentiveWei,
        uint256 _periodsRemaining,
        uint256 _maxAuthorizeAmountWei,
        SharingPercentage[] memory _sharingPercentages
    )
        internal
        returns(uint256 _amountAuthorizedWei)
    {
        // If there are no sharing percentages, then there is nothing to authorize.
        if (_sharingPercentages.length == 0) {
            _amountAuthorizedWei = 0;
            return _amountAuthorizedWei;
        }
        
        // Compute amount to allocate
        uint256 amountToAuthorizeRemaingWei = Math.min(
            _totalRecognizedIncentiveWei.sub(_totalAuthorizedIncentiveWei).div(_periodsRemaining),
            _maxAuthorizeAmountWei);
        // Set up return value with amount authorized
        _amountAuthorizedWei = amountToAuthorizeRemaingWei;
        // Accumulate authorized total...note that this total is for a given annum, for a given service
        _self.totalAuthorizedIncentiveWei = _self.totalAuthorizedIncentiveWei.add(amountToAuthorizeRemaingWei);
        // Start with total bips in denominator
        uint256 divisorRemaining = BIPS100;
        // Loop over sharing percentages
        for (uint256 i; i < _sharingPercentages.length; i++) {
            // Compute the amount to authorize for a given service
            uint256 toAuthorizeWei = amountToAuthorizeRemaingWei.mulDiv(
                _sharingPercentages[i].percentBips, 
                divisorRemaining
            );
            // Reduce the numerator by amount just computed
            amountToAuthorizeRemaingWei = amountToAuthorizeRemaingWei.sub(toAuthorizeWei);
            // Reduce the divisor by the bips just allocated
            divisorRemaining = divisorRemaining.sub(_sharingPercentages[i].percentBips);
            // Try to find a matching reward service for the given sharing percentage.
            // New sharing percentages can be added at any time. And if one gets removed,  
            // we don't remove that reward service for a given annum, since its total still
            // remains applicable.
            ( bool found, uint256 incentivePoolRewardServiceIndex ) = 
                findIncentivePoolRewardService(_self, _sharingPercentages[i].incentivePoolReceiver);
            if (found) {
                // Get the existing reward service
                IncentivePoolRewardService.IncentivePoolRewardServiceState storage incentivePoolRewardService = 
                    _self.incentivePoolRewardServices[incentivePoolRewardServiceIndex];
                // Accumulate the amount authorized for the service
                incentivePoolRewardService.addAuthorizedIncentive(toAuthorizeWei);
            } else {
                // Initialize a new reward service
                IncentivePoolRewardService.IncentivePoolRewardServiceState storage incentivePoolRewardService = 
                    _self.incentivePoolRewardServices.push();
                incentivePoolRewardService.initialize(_sharingPercentages[i].incentivePoolReceiver);
                // Accumulate the amount authorized for the service
                incentivePoolRewardService.addAuthorizedIncentive(toAuthorizeWei);                
            }                
            // Signal the incentivePool receiver of the reward service (the actual rewarding contract)
            // with amount just authorized.
            _sharingPercentages[i].incentivePoolReceiver.setDailyAuthorizedIncentive(toAuthorizeWei);
            
            emit IncentivePoolRewardServiceDailyAuthorizedIncentiveComputed(
                _sharingPercentages[i].incentivePoolReceiver, 
                toAuthorizeWei);
        }
    }

    /**
     * @notice Given topup configurations as maintained by an instantiated IncentivePool contract, compute
     *   the topup requests needed to topup reward contracts with native token reserves to satisfy claim requests.
     * @param _incentivePool    The IncentivePool contract holding the topup configurations.
     * @return _topupRequestWei The topup request to mint native tokens across reward services for this cycle.
     */
    function computeTopupRequest(
        IncentivePoolRewardServicesState storage _self,
        IncentivePool _incentivePool
    )
        internal
        returns (uint256 _topupRequestWei)
    {
        for (uint256 i; i < _self.incentivePoolRewardServices.length; i++) {
            TopupConfiguration memory topupConfiguration = 
                _incentivePool.getTopupConfiguration(_self.incentivePoolRewardServices[i].incentivePoolReceiver);
            _topupRequestWei = 
                _topupRequestWei.add(_self.incentivePoolRewardServices[i].computeTopupRequest(topupConfiguration));
        }
        _self.totalIncentiveTopupRequestedWei = _self.totalIncentiveTopupRequestedWei.add(_topupRequestWei);
        // Make sure topup requested never exceeds the amount authorized
        assert(_self.totalIncentiveTopupRequestedWei <= _self.totalAuthorizedIncentiveWei);
    }

    /**
     * @notice Given an incentivePool receiver, return the index of the associated reward service.
     * @param _incentivePoolReceiver The incentivePool receiver.
     * @return _found   True if the reward service was found.
     * @return _index   The index on the incentivePoolRewardServices array of the found service. Index is undefined
     *   if the reward service was not found.
     */
    function findIncentivePoolRewardService(
        IncentivePoolRewardServicesState storage _self,
        IIIncentivePoolReceiver _incentivePoolReceiver
    ) 
        internal view
        returns(bool _found, uint256 _index)
    {
        // The number of these is expected to be low.
        _found = false;
        for (uint256 i; i < _self.incentivePoolRewardServices.length; i++) {
            if (_self.incentivePoolRewardServices[i].incentivePoolReceiver == _incentivePoolReceiver) {
                _index = i;
                _found = true;
                break;
            }
        }
    }

    /**
     * @notice Receive a topup request of native tokens and disburse amongst requestors.
     * @return _amountPostedWei The total amount of native tokens funded.
     * @dev Assume value is siting in IncentivePool contract waiting to be posted and transmitted.
     *   This function is atomic, so if for some reason not enough native tokens are available, this
     *   function will fail until all topup requests can be satisfied.
     */
    function distributeTopupRequest(
        IncentivePoolRewardServicesState storage _self
    ) 
        internal 
        returns(uint256 _amountPostedWei)
    {
        // Spin through all reward services
        for (uint256 i; i < _self.incentivePoolRewardServices.length; i++) {
            // Get the pending topup for the service
            uint256 pendingTopupWei = _self.incentivePoolRewardServices[i].getPendingTopup();
            // Accumulate topup received
            _self.incentivePoolRewardServices[i].addTopupReceived(pendingTopupWei);
            _self.totalIncentiveTopupReceivedWei = _self.totalIncentiveTopupReceivedWei.add(pendingTopupWei);
            // Transfer topup to rewarding service contract
            _self.incentivePoolRewardServices[i].incentivePoolReceiver.receiveIncentive{value: pendingTopupWei}();
            // Accumulate topup withdrawn
            _self.incentivePoolRewardServices[i].addTopupWithdrawn(pendingTopupWei);
            _self.totalIncentiveTopupWithdrawnWei = _self.totalIncentiveTopupWithdrawnWei.add(pendingTopupWei);
            // Accumulate amount posted
            _amountPostedWei = _amountPostedWei.add(pendingTopupWei);
            
            emit IncentivePoolRewardServiceTopupRequestReceived(
                _self.incentivePoolRewardServices[i].incentivePoolReceiver,
                pendingTopupWei);
        }
    }
}
          

./contracts/userInterfaces/IGovernanceSettings.sol

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


/**
 * A special contract that holds Flare governance address.
 * This contract enables updating governance address and timelock only by hard forking the network,
 * meaning only by updating validator code.
 */
interface IGovernanceSettings {
    /**
     * Get the governance account address.
     * The governance address can only be changed by a hardfork.
     */
    function getGovernanceAddress() external view returns (address);
    
    /**
     * Get the time in seconds that must pass between a governance call and execution.
     * The timelock value can only be changed by a hardfork.
     */
    function getTimelock() external view returns (uint256);
    
    /**
     * Get the addresses of the accounts that are allowed to execute the timelocked governance calls
     * once the timelock period expires.
     * Executors can be changed without a hardfork, via a normal governance call.
     */
    function getExecutors() external view returns (address[] memory);
    
    /**
     * Check whether an address is one of the executors.
     */
    function isExecutor(address _address) external view returns (bool);
}
          

./contracts/utils/implementation/DateTimeLibrary.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
// ----------------------------------------------------------------------------
// BokkyPooBah's DateTime Library v1.01
//
// A gas-efficient Solidity date and time library
//
// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary
//
// Tested date range 1970/01/01 to 2345/12/31
//
// Conventions:
// Unit      | Range         | Notes
// :-------- |:-------------:|:-----
// timestamp | >= 0          | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC
// year      | 1970 ... 2345 |
// month     | 1 ... 12      |
// day       | 1 ... 31      |
// hour      | 0 ... 23      |
// minute    | 0 ... 59      |
// second    | 0 ... 59      |
// dayOfWeek | 1 ... 7       | 1 = Monday, ..., 7 = Sunday
//
//
// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence.
// ----------------------------------------------------------------------------

library BokkyPooBahsDateTimeLibrary {

    uint public constant SECONDS_PER_DAY = 24 * 60 * 60;
    uint public constant SECONDS_PER_HOUR = 60 * 60;
    uint public constant SECONDS_PER_MINUTE = 60;
    int public constant OFFSET19700101 = 2440588;

    uint public constant DOW_MON = 1;
    uint public constant DOW_TUE = 2;
    uint public constant DOW_WED = 3;
    uint public constant DOW_THU = 4;
    uint public constant DOW_FRI = 5;
    uint public constant DOW_SAT = 6;
    uint public constant DOW_SUN = 7;

    // ------------------------------------------------------------------------
    // Calculate the number of days from 1970/01/01 to year/month/day using
    // the date conversion algorithm from
    //   http://aa.usno.navy.mil/faq/docs/JD_Formula.php
    // and subtracting the offset 2440588 so that 1970/01/01 is day 0
    //
    // days = day
    //      - 32075
    //      + 1461 * (year + 4800 + (month - 14) / 12) / 4
    //      + 367 * (month - 2 - (month - 14) / 12 * 12) / 12
    //      - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4
    //      - offset
    // ------------------------------------------------------------------------
    function _daysFromDate(uint year, uint month, uint day) internal pure returns (uint _days) {
        require(year >= 1970);
        int _year = int(year);
        int _month = int(month);
        int _day = int(day);

        int __days = _day
          - 32075
          + 1461 * (_year + 4800 + (_month - 14) / 12) / 4
          + 367 * (_month - 2 - (_month - 14) / 12 * 12) / 12
          - 3 * ((_year + 4900 + (_month - 14) / 12) / 100) / 4
          - OFFSET19700101;

        _days = uint(__days);
    }

    // ------------------------------------------------------------------------
    // Calculate year/month/day from the number of days since 1970/01/01 using
    // the date conversion algorithm from
    //   http://aa.usno.navy.mil/faq/docs/JD_Formula.php
    // and adding the offset 2440588 so that 1970/01/01 is day 0
    //
    // int tempL = days + 68569 + offset
    // int tempN = 4 * tempL / 146097
    // tempL = tempL - (146097 * tempN + 3) / 4
    // year = 4000 * (tempL + 1) / 1461001
    // tempL = tempL - 1461 * year / 4 + 31
    // month = 80 * tempL / 2447
    // dd = tempL - 2447 * month / 80
    // tempL = month / 11
    // month = month + 2 - 12 * tempL
    // year = 100 * (tempN - 49) + year + tempL
    // ------------------------------------------------------------------------
    //solhint-disable max-line-length
    function _daysToDate(uint _days) internal pure returns (uint year, uint month, uint day) {
        int __days = int(_days);

        /* solhint-disable var-name-mixedcase */
        int L = __days + 68569 + OFFSET19700101;
        int N = 4 * L / 146097;
        /* solhint-enable var-name-mixedcase */
        L = L - (146097 * N + 3) / 4;
        int _year = 4000 * (L + 1) / 1461001;
        L = L - 1461 * _year / 4 + 31;
        int _month = 80 * L / 2447;
        int _day = L - 2447 * _month / 80;
        L = _month / 11;
        _month = _month + 2 - 12 * L;
        _year = 100 * (N - 49) + _year + L;

        year = uint(_year);
        month = uint(_month);
        day = uint(_day);
    }

    function timestampFromDate(uint year, uint month, uint day) internal pure returns (uint timestamp) {
        timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY;
    }

    function timestampFromDateTime(
        uint year, 
        uint month, 
        uint day, 
        uint hour, 
        uint minute, 
        uint second) internal pure returns (uint timestamp) {
        timestamp = 
            _daysFromDate(year, month, day) * 
            SECONDS_PER_DAY + 
            hour * 
            SECONDS_PER_HOUR + 
            minute * 
            SECONDS_PER_MINUTE + 
            second;
    }

    function timestampToDate(uint timestamp) internal pure returns (uint year, uint month, uint day) {
        (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);
    }

    function timestampToDateTime(uint timestamp) internal pure returns (
        uint year, 
        uint month, 
        uint day, 
        uint hour, 
        uint minute, 
        uint second) {
        (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);
        uint secs = timestamp % SECONDS_PER_DAY;
        hour = secs / SECONDS_PER_HOUR;
        secs = secs % SECONDS_PER_HOUR;
        minute = secs / SECONDS_PER_MINUTE;
        second = secs % SECONDS_PER_MINUTE;
    }

    function isValidDate(uint year, uint month, uint day) internal pure returns (bool valid) {
        if (year >= 1970 && month > 0 && month <= 12) {
            uint daysInMonth = _getDaysInMonth(year, month);
            if (day > 0 && day <= daysInMonth) {
                valid = true;
            }
        }
    }

    function isValidDateTime(
        uint year, 
        uint month, 
        uint day, 
        uint hour, 
        uint minute, 
        uint second) internal pure returns (bool valid) {
        if (isValidDate(year, month, day)) {
            if (hour < 24 && minute < 60 && second < 60) {
                valid = true;
            }
        }
    }

    function isLeapYear(uint timestamp) internal pure returns (bool leapYear) {
        (uint year,,) = _daysToDate(timestamp / SECONDS_PER_DAY);
        leapYear = _isLeapYear(year);
    }

    function _isLeapYear(uint year) internal pure returns (bool leapYear) {
        leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
    }

    function isWeekDay(uint timestamp) internal pure returns (bool weekDay) {
        weekDay = getDayOfWeek(timestamp) <= DOW_FRI;
    }

    function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) {
        weekEnd = getDayOfWeek(timestamp) >= DOW_SAT;
    }

    function getDaysInMonth(uint timestamp) internal pure returns (uint daysInMonth) {
        (uint year, uint month,) = _daysToDate(timestamp / SECONDS_PER_DAY);
        daysInMonth = _getDaysInMonth(year, month);
    }

    function _getDaysInMonth(uint year, uint month) internal pure returns (uint daysInMonth) {
        if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
            daysInMonth = 31;
        } else if (month != 2) {
            daysInMonth = 30;
        } else {
            daysInMonth = _isLeapYear(year) ? 29 : 28;
        }
    }

    // 1 = Monday, 7 = Sunday
    function getDayOfWeek(uint timestamp) internal pure returns (uint dayOfWeek) {
        uint _days = timestamp / SECONDS_PER_DAY;
        dayOfWeek = (_days + 3) % 7 + 1;
    }

    function getYear(uint timestamp) internal pure returns (uint year) {
        (year,,) = _daysToDate(timestamp / SECONDS_PER_DAY);
    }

    function getMonth(uint timestamp) internal pure returns (uint month) {
        (,month,) = _daysToDate(timestamp / SECONDS_PER_DAY);
    }

    function getDay(uint timestamp) internal pure returns (uint day) {
        (,,day) = _daysToDate(timestamp / SECONDS_PER_DAY);
    }

    function getHour(uint timestamp) internal pure returns (uint hour) {
        uint secs = timestamp % SECONDS_PER_DAY;
        hour = secs / SECONDS_PER_HOUR;
    }

    function getMinute(uint timestamp) internal pure returns (uint minute) {
        uint secs = timestamp % SECONDS_PER_HOUR;
        minute = secs / SECONDS_PER_MINUTE;
    }

    function getSecond(uint timestamp) internal pure returns (uint second) {
        second = timestamp % SECONDS_PER_MINUTE;
    }

    function addYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) {
        (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY);
        year += _years;
        uint daysInMonth = _getDaysInMonth(year, month);
        // When adding a year to feb 29th
        if (day > daysInMonth) {
            day = daysInMonth;
        }
        newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY;
        require(newTimestamp >= timestamp);
    }

    function addMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) {
        (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY);
        month += _months;
        year += (month - 1) / 12;
        month = (month - 1) % 12 + 1;
        uint daysInMonth = _getDaysInMonth(year, month);
        if (day > daysInMonth) {
            day = daysInMonth;
        }
        newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY;
        require(newTimestamp >= timestamp);
    }

    function addDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) {
        newTimestamp = timestamp + _days * SECONDS_PER_DAY;
        require(newTimestamp >= timestamp);
    }

    function addHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) {
        newTimestamp = timestamp + _hours * SECONDS_PER_HOUR;
        require(newTimestamp >= timestamp);
    }

    function addMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) {
        newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE;
        require(newTimestamp >= timestamp);
    }

    function addSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) {
        newTimestamp = timestamp + _seconds;
        require(newTimestamp >= timestamp);
    }

    /**
     * @dev removed since it can be a cause of errors 
     * adding and removing a year may not end up on the same point in time    
     */
    // function subYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) {
    //     (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY);
    //     year -= _years;
    //     uint daysInMonth = _getDaysInMonth(year, month);
    //     if (day > daysInMonth) {
    //         day = daysInMonth;
    //     }
    //     newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY;
    //     require(newTimestamp <= timestamp);
    // }

    /**
     * @dev removed since it can be a cause of errors 
     * adding and removing a month may not end up on the same point in time 
     * Intendet functionality:
     * 31.5 + 1 month => 30.6
     * 30.6 - 1 month => 30.5 
     * this may cause problems
     */
    // function subMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) {
    //     (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY);
    //     uint yearMonth = year * 12 + (month - 1) - _months;
    //     year = yearMonth / 12;
    //     month = yearMonth % 12 + 1;
    //     uint daysInMonth = _getDaysInMonth(year, month);
    //     if (day > daysInMonth) {
    //         day = daysInMonth;
    //     }
    //     newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY;
    //     require(newTimestamp <= timestamp);
    // }

    function subDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) {
        newTimestamp = timestamp - _days * SECONDS_PER_DAY;
        require(newTimestamp <= timestamp);
    }

    function subHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) {
        newTimestamp = timestamp - _hours * SECONDS_PER_HOUR;
        require(newTimestamp <= timestamp);
    }

    function subMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) {
        newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE;
        require(newTimestamp <= timestamp);
    }

    function subSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) {
        newTimestamp = timestamp - _seconds;
        require(newTimestamp <= timestamp);
    }

    function diffYears(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _years) {
        require(fromTimestamp <= toTimestamp);
        (uint fromYear,,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY);
        (uint toYear,,) = _daysToDate(toTimestamp / SECONDS_PER_DAY);
        _years = toYear - fromYear;
    }

    function diffMonths(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _months) {
        require(fromTimestamp <= toTimestamp);
        (uint fromYear, uint fromMonth,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY);
        (uint toYear, uint toMonth,) = _daysToDate(toTimestamp / SECONDS_PER_DAY);
        _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth;
    }

    function diffDays(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _days) {
        require(fromTimestamp <= toTimestamp);
        _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY;
    }

    function diffHours(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _hours) {
        require(fromTimestamp <= toTimestamp);
        _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR;
    }

    function diffMinutes(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _minutes) {
        require(fromTimestamp <= toTimestamp);
        _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE;
    }

    function diffSeconds(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _seconds) {
        require(fromTimestamp <= toTimestamp);
        _seconds = toTimestamp - fromTimestamp;
    }
    
    function getDaysInYear(uint timestamp) internal pure returns (uint daysInYear) {
        return isLeapYear(timestamp) ? 366 : 365;
    }
}
          

./contracts/utils/implementation/GovernedAndFlareDaemonized.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
import { FlareDaemon } from "../../genesis/implementation/FlareDaemon.sol";
import { Governed } from "../../governance/implementation/Governed.sol";


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

./contracts/utils/implementation/SafePct.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;
import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";

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

@openzeppelin/contracts/math/Math.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow, so we distribute
        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
    }
}
          

@openzeppelin/contracts/math/SafeMath.sol

// SPDX-License-Identifier: MIT

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

@openzeppelin/contracts/utils/SafeCast.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;


/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` 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 SafeCast {

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits");
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v3.1._
     */
    function toInt128(int256 value) internal pure returns (int128) {
        require(value >= -2**127 && value < 2**127, "SafeCast: value doesn\'t fit in 128 bits");
        return int128(value);
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v3.1._
     */
    function toInt64(int256 value) internal pure returns (int64) {
        require(value >= -2**63 && value < 2**63, "SafeCast: value doesn\'t fit in 64 bits");
        return int64(value);
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v3.1._
     */
    function toInt32(int256 value) internal pure returns (int32) {
        require(value >= -2**31 && value < 2**31, "SafeCast: value doesn\'t fit in 32 bits");
        return int32(value);
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v3.1._
     */
    function toInt16(int256 value) internal pure returns (int16) {
        require(value >= -2**15 && value < 2**15, "SafeCast: value doesn\'t fit in 16 bits");
        return int16(value);
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     *
     * _Available since v3.1._
     */
    function toInt8(int256 value) internal pure returns (int8) {
        require(value >= -2**7 && value < 2**7, "SafeCast: value doesn\'t fit in 8 bits");
        return int8(value);
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        require(value < 2**255, "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}
          

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_governance","internalType":"address"},{"type":"address","name":"_flareDaemon","internalType":"contract FlareDaemon"},{"type":"address","name":"_addressUpdater","internalType":"address"},{"type":"address","name":"_treasury","internalType":"contract IncentivePoolTreasury"},{"type":"uint256","name":"_rewardEpochStartTs","internalType":"uint256"}]},{"type":"event","name":"GovernanceCallTimelocked","inputs":[{"type":"bytes4","name":"selector","internalType":"bytes4","indexed":false},{"type":"uint256","name":"allowedAfterTimestamp","internalType":"uint256","indexed":false},{"type":"bytes","name":"encodedCall","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"GovernanceInitialised","inputs":[{"type":"address","name":"initialGovernance","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"GovernedProductionModeEntered","inputs":[{"type":"address","name":"governanceSettings","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"IncentiveAuthorized","inputs":[{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"IncentivePoolAllocationSet","inputs":[{"type":"address","name":"incentivePoolAllocation","internalType":"contract IIIncentivePoolAllocation","indexed":false}],"anonymous":false},{"type":"event","name":"IncentivePoolRewardServiceDailyAuthorizedIncentiveComputed","inputs":[{"type":"address","name":"incentivePoolReceiver","internalType":"contract IIIncentivePoolReceiver","indexed":false},{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"IncentivePoolRewardServiceTopupComputed","inputs":[{"type":"address","name":"incentivePoolReceiver","internalType":"contract IIIncentivePoolReceiver","indexed":false},{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"IncentivePoolRewardServiceTopupRequestReceived","inputs":[{"type":"address","name":"incentivePoolReceiver","internalType":"contract IIIncentivePoolReceiver","indexed":false},{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"NewAnnumInitialized","inputs":[{"type":"uint256","name":"startTimeStamp","internalType":"uint256","indexed":false},{"type":"uint256","name":"endTimeStamp","internalType":"uint256","indexed":false},{"type":"uint256","name":"inflatableSupplyWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"recognizedIncentiveWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalAuthorizedIncentiveWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalIncentiveTopupRequestedWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalIncentiveTopupReceivedWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalIncentiveTopupWithdrawnWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SupplySet","inputs":[{"type":"address","name":"oldSupply","internalType":"contract IISupply","indexed":false},{"type":"address","name":"newSupply","internalType":"contract IISupply","indexed":false}],"anonymous":false},{"type":"event","name":"TimelockedGovernanceCallCanceled","inputs":[{"type":"bytes4","name":"selector","internalType":"bytes4","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"TimelockedGovernanceCallExecuted","inputs":[{"type":"bytes4","name":"selector","internalType":"bytes4","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"TopupConfigurationSet","inputs":[{"type":"tuple","name":"topupConfiguration","internalType":"struct TopupConfiguration","indexed":false,"components":[{"type":"uint8","name":"topupType","internalType":"enum TopupType"},{"type":"uint256","name":"topupFactorX100","internalType":"uint256"},{"type":"bool","name":"configured","internalType":"bool"}]}],"anonymous":false},{"type":"event","name":"TopupRequested","inputs":[{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelGovernanceCall","inputs":[{"type":"bytes4","name":"_selector","internalType":"bytes4"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"daemonize","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeGovernanceCall","inputs":[{"type":"bytes4","name":"_selector","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract FlareDaemon"}],"name":"flareDaemon","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"_addressUpdater","internalType":"address"}],"name":"getAddressUpdater","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct IncentivePoolAnnum.IncentivePoolAnnumState","components":[{"type":"uint256","name":"recognizedIncentiveWei","internalType":"uint256"},{"type":"uint256","name":"startTimeStamp","internalType":"uint256"},{"type":"uint256","name":"endTimeStamp","internalType":"uint256"},{"type":"tuple","name":"incentivePoolRewardServices","internalType":"struct IncentivePoolRewardServices.IncentivePoolRewardServicesState","components":[{"type":"tuple[]","name":"incentivePoolRewardServices","internalType":"struct IncentivePoolRewardService.IncentivePoolRewardServiceState[]","components":[{"type":"address","name":"incentivePoolReceiver","internalType":"contract IIIncentivePoolReceiver"},{"type":"uint256","name":"authorizedIncentiveWei","internalType":"uint256"},{"type":"uint256","name":"lastDailyAuthorizedIncentiveWei","internalType":"uint256"},{"type":"uint256","name":"incentivePoolTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"incentivePoolTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"incentivePoolTopupWithdrawnWei","internalType":"uint256"}]},{"type":"uint256","name":"totalAuthorizedIncentiveWei","internalType":"uint256"},{"type":"uint256","name":"totalIncentiveTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"totalIncentiveTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"totalIncentiveTopupWithdrawnWei","internalType":"uint256"}]}]}],"name":"getAnnum","inputs":[{"type":"uint256","name":"_index","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"getContractName","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct IncentivePoolAnnum.IncentivePoolAnnumState","components":[{"type":"uint256","name":"recognizedIncentiveWei","internalType":"uint256"},{"type":"uint256","name":"startTimeStamp","internalType":"uint256"},{"type":"uint256","name":"endTimeStamp","internalType":"uint256"},{"type":"tuple","name":"incentivePoolRewardServices","internalType":"struct IncentivePoolRewardServices.IncentivePoolRewardServicesState","components":[{"type":"tuple[]","name":"incentivePoolRewardServices","internalType":"struct IncentivePoolRewardService.IncentivePoolRewardServiceState[]","components":[{"type":"address","name":"incentivePoolReceiver","internalType":"contract IIIncentivePoolReceiver"},{"type":"uint256","name":"authorizedIncentiveWei","internalType":"uint256"},{"type":"uint256","name":"lastDailyAuthorizedIncentiveWei","internalType":"uint256"},{"type":"uint256","name":"incentivePoolTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"incentivePoolTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"incentivePoolTopupWithdrawnWei","internalType":"uint256"}]},{"type":"uint256","name":"totalAuthorizedIncentiveWei","internalType":"uint256"},{"type":"uint256","name":"totalIncentiveTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"totalIncentiveTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"totalIncentiveTopupWithdrawnWei","internalType":"uint256"}]}]}],"name":"getCurrentAnnum","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_nextTopupTs","internalType":"uint256"}],"name":"getNextExpectedTopupTs","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_lockedFundsWei","internalType":"uint256"},{"type":"uint256","name":"_totalInflationAuthorizedWei","internalType":"uint256"},{"type":"uint256","name":"_totalClaimedWei","internalType":"uint256"}],"name":"getTokenPoolSupplyData","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"tuple","name":"_topupConfiguration","internalType":"struct TopupConfiguration","components":[{"type":"uint8","name":"topupType","internalType":"enum TopupType"},{"type":"uint256","name":"topupFactorX100","internalType":"uint256"},{"type":"bool","name":"configured","internalType":"bool"}]}],"name":"getTopupConfiguration","inputs":[{"type":"address","name":"_incentivePoolReceiver","internalType":"contract IIIncentivePoolReceiver"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_totalAuthorizedIncentiveWei","internalType":"uint256"},{"type":"uint256","name":"_totalIncentiveTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"_totalIncentiveTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"_totalIncentiveTopupWithdrawnWei","internalType":"uint256"},{"type":"uint256","name":"_totalRecognizedIncentiveWei","internalType":"uint256"}],"name":"getTotals","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"governance","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IGovernanceSettings"}],"name":"governanceSettings","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIIncentivePoolAllocation"}],"name":"incentivePoolAllocation","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialise","inputs":[{"type":"address","name":"_initialGovernance","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastAuthorizationTs","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"productionMode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardEpochStartTs","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardEpochStartedTs","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setTopupConfiguration","inputs":[{"type":"address","name":"_incentivePoolReceiver","internalType":"contract IIIncentivePoolReceiver"},{"type":"uint8","name":"_topupType","internalType":"enum TopupType"},{"type":"uint256","name":"_topupFactorX100","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IISupply"}],"name":"supply","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"switchToFallbackMode","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"switchToProductionMode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"allowedAfterTimestamp","internalType":"uint256"},{"type":"bytes","name":"encodedCall","internalType":"bytes"}],"name":"timelockedCalls","inputs":[{"type":"bytes4","name":"","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IncentivePoolTreasury"}],"name":"treasury","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateContractAddresses","inputs":[{"type":"bytes32[]","name":"_contractNameHashes","internalType":"bytes32[]"},{"type":"address[]","name":"_contractAddresses","internalType":"address[]"}]},{"type":"receive","stateMutability":"payable"}]
              

Contract Creation Code

0x60e06040523480156200001157600080fd5b506040516200399838038062003998833981016040819052620000349162000273565b82858581806001600160a01b03811615620000545762000054816200018c565b506001600160a01b038116620000a4576040805162461bcd60e51b815260206004820152601060248201526f5f676f7665726e616e6365207a65726f60801b604482015290519081900360640190fd5b506001600160a01b038116620000f5576040805162461bcd60e51b8152602060048201526011602482015270666c617265206461656d6f6e207a65726f60781b604482015290519081900360640190fd5b60601b6001600160601b0319166080525062000111816200024f565b5060408051808201909152600c81526b06164647265737320697320360a41b602082015282906001600160a01b0382166200016a5760405162461bcd60e51b8152600401620001619190620002e6565b60405180910390fd5b505060609190911b6001600160601b03191660a05260c0525062000355915050565b600054600160a01b900460ff1615620001ec576040805162461bcd60e51b815260206004820152601460248201527f696e697469616c6973656420213d2066616c7365000000000000000000000000604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b600080600080600060a086880312156200028b578081fd5b855162000298816200033c565b6020870151909550620002ab816200033c565b6040870151909450620002be816200033c565b6060870151909350620002d1816200033c565b80925050608086015190509295509295909350565b6000602080835283518082850152825b818110156200031457858101830151858201604001528201620002f6565b81811115620003265783604083870101525b50601f01601f1916929092016040019392505050565b6001600160a01b03811681146200035257600080fd5b50565b60805160601c60a05160601c60c0516135e3620003b560003980610c6c5280610c94528061139b5250806101d452806105585280610a925280610d495280610f0b52806118f7525080610c0452806112cc52806114fa52506135e36000f3fe6080604052600436106101a05760003560e01c806384e10a90116100ec578063c9d3dc871161008a578063f5a9838311610064578063f5a98383146104cd578063f5f5ba72146104e2578063f639c12c14610504578063f64cee61146105195761021e565b8063c9d3dc871461048e578063e17f212e146104a3578063e22fdece146104b85761021e565b8063a1077532116100c6578063a107753214610422578063b00c0b7614610437578063b8cca0cf14610457578063c39049e41461046c5761021e565b806384e10a90146103c7578063983963d8146103ed5780639d6a890f146104025761021e565b80635ff270791161015957806367fc40291161013357806367fc4029146103375780636d0e8c34146103575780636e61ab961461037957806374e6310e146103995761021e565b80635ff27079146102eb57806361d027b31461030d57806362354e03146103225761021e565b8063047fc9aa146102235780632dafdbbf1461024e57806333ed77cc146102725780634b13e872146102945780635267a15d146102c15780635aa6e675146102d65761021e565b3661021e5760408051808201909152600d81526c7472656173757279206f6e6c7960981b6020820152336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461021b5760405162461bcd60e51b81526004016102129190613275565b60405180910390fd5b50005b600080fd5b34801561022f57600080fd5b50610238610539565b6040516102459190613223565b60405180910390f35b34801561025a57600080fd5b50610263610548565b604051610245939291906133e8565b34801561027e57600080fd5b5061028761059f565b60405161024591906133c6565b3480156102a057600080fd5b506102b46102af366004612f28565b6105a5565b6040516102459190613363565b3480156102cd57600080fd5b50610238610680565b3480156102e257600080fd5b506102386106a5565b3480156102f757600080fd5b5061030b6103063660046130cc565b61073b565b005b34801561031957600080fd5b50610238610a90565b34801561032e57600080fd5b50610238610ab4565b34801561034357600080fd5b5061030b6103523660046130cc565b610abf565b34801561036357600080fd5b5061036c610ba7565b6040516102459190613237565b34801561038557600080fd5b5061030b6103943660046130f4565b610f96565b3480156103a557600080fd5b506103b96103b43660046130cc565b611142565b6040516102459291906133cf565b3480156103d357600080fd5b506103dc6111e8565b6040516102459594939291906133fe565b3480156103f957600080fd5b50610238611202565b34801561040e57600080fd5b5061030b61041d366004612f28565b611211565b34801561042e57600080fd5b506102386112ca565b34801561044357600080fd5b5061030b610452366004612f44565b6112ee565b34801561046357600080fd5b50610287611399565b34801561047857600080fd5b506104816113bd565b6040516102459190613288565b34801561049a57600080fd5b506102876114d7565b3480156104af57600080fd5b5061036c6114dd565b3480156104c457600080fd5b5061036c6114ed565b3480156104d957600080fd5b5061030b611566565b3480156104ee57600080fd5b506104f7611620565b6040516102459190613275565b34801561051057600080fd5b50610287611647565b34801561052557600080fd5b5061048161053436600461319a565b61165a565b6003546001600160a01b031681565b600080600061058f6004600601547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163161177690919063ffffffff16565b600a549094600094509092509050565b600d5481565b6105ad612d55565b60408051808201909152600c81526b06164647265737320697320360a41b602082015282906001600160a01b0382166105f95760405162461bcd60e51b81526004016102129190613275565b506001600160a01b0383166000908152600c60205260409020600281015460ff1661064057805460ff19908116825560786001808401919091556002830180549092161790555b8054839060ff16600181111561065257fe5b9081600181111561065f57fe5b905250600181015460208401526002015460ff161515604083015250919050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e77195490565b60008054600160a81b900460ff166106c8576000546001600160a01b0316610735565b60076001609c1b016001600160a01b031663732524946040518163ffffffff1660e01b815260040160206040518083038186803b15801561070857600080fd5b505afa15801561071c573d6000803e3d6000fd5b505050506040513d602081101561073257600080fd5b50515b90505b90565b60408051630debfda360e41b8152336004820152905160076001609c1b019163debfda30916024808301926020929190829003018186803b15801561077f57600080fd5b505afa158015610793573d6000803e3d6000fd5b505050506040513d60208110156107a957600080fd5b50516107ec576040805162461bcd60e51b815260206004820152600d60248201526c37b7363c9032bc32b1baba37b960991b604482015290519081900360640190fd5b6001600160e01b0319811660009081526001602052604090208054610858576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b80544210156108ae576040805162461bcd60e51b815260206004820152601960248201527f74696d656c6f636b3a206e6f7420616c6c6f7765642079657400000000000000604482015290519081900360640190fd5b6000816001018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156109485780601f1061091d57610100808354040283529160200191610948565b820191906000526020600020905b81548152906001019060200180831161092b57829003601f168201915b5050506001600160e01b031986166000908152600160208190526040822082815594955090925061097c9150830182612d77565b50506000805460ff60b01b1916600160b01b178155604051825130918491819060208401908083835b602083106109c45780518252601f1990920191602091820191016109a5565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114610a26576040519150601f19603f3d011682016040523d82523d6000602084013e610a2b565b606091505b50506000805460ff60b01b19169055604080516001600160e01b03198716815242602082015281519293507fa7326b57fc9cfe267aaea5e7f0b01757154d265620a0585819416ee9ddd2c438929081900390910190a1610a8a816117d9565b50505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60076001609c1b0181565b610ac76117f6565b6001600160e01b03198116600090815260016020526040902054610b32576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b604080516001600160e01b03198316815242602082015281517f7735b2391c38a81419c513e30ca578db7158eadd7101511b23e221c654d19cf8929181900390910190a16001600160e01b03198116600090815260016020819052604082208281559190610ba290830182612d77565b505050565b60035460408051808201909152600c81526b06164647265737320697320360a41b60208201526000916001600160a01b03169081610bf85760405162461bcd60e51b81526004016102129190613275565b50336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610c6a576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000001580610cb657507f000000000000000000000000000000000000000000000000000000000000000042105b15610cc45760019150610f92565b600d54610cd05742600d555b610cda6004611857565b610cec57610ce74261185b565b610d1b565b6000610cf86004611ba0565b60020154905080421115610d1957610d19610d14826001611776565b61185b565b505b600b544290610d2d9062015180611776565b11610f8d5742600b819055506000610e7542610ddf60646101907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166397249db76040518163ffffffff1660e01b815260040160206040518083038186803b158015610da057600080fd5b505afa158015610db4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd891906131b2565b9190611c15565b600260009054906101000a90046001600160a01b03166001600160a01b031663c853b8d46040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610e2f57600080fd5b505af1158015610e43573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e6b9190810190612ffb565b6004929190611d23565b90507f83271265e292ba2d92e1eb89cdbda68f1803ae726a27a5afe6a77d6430cddbd581604051610ea691906133c6565b60405180910390a16000610ebb600430611d87565b90507f1f0936062e6ce780790714a1ec5787d290675660a8566059ac9d6cfb2a336eec81604051610eec91906133c6565b60405180910390a160405163ec8d877760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ec8d877790610f409084906004016133c6565b600060405180830381600087803b158015610f5a57600080fd5b505af1158015610f6e573d6000803e3d6000fd5b505050506000610f7e6004611dcf565b9050808214610f8957fe5b5050505b600191505b5090565b60408051808201909152600c81526b06164647265737320697320360a41b602082015283906001600160a01b038216610fe25760405162461bcd60e51b81526004016102129190613275565b50600054600160b01b900460ff16806110055750600054600160a81b900460ff16155b1561113757611012611e38565b600083600181111561102057fe5b14156110ae57604080518082019091526009815268746f707570206c6f7760b81b6020820152606483116110675760405162461bcd60e51b81526004016102129190613275565b5060408051808201909152600a8152690e8dee0eae040d0d2ced60b31b60208201526101908311156110ac5760405162461bcd60e51b81526004016102129190613275565b505b6001600160a01b0384166000908152600c6020526040902080548490829060ff1916600183818111156110dd57fe5b0217905550600180820184905560028201805460ff191690911790556040517fcf085312d79a75faa5f1b9f6bec58a64813338f5e5e5759573cab22c6da2d25b90611129908390613392565b60405180910390a150610a8a565b610a8a600036611e6d565b600160208181526000928352604092839020805481840180548651600296821615610100026000190190911695909504601f810185900485028601850190965285855290949193929091908301828280156111de5780601f106111b3576101008083540402835291602001916111de565b820191906000526020600020905b8154815290600101906020018083116111c157829003601f168201915b5050505050905082565b600754600854600954600a54600654939492939192909190565b6002546001600160a01b031681565b600054600160a01b900460ff1615611267576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b7f000000000000000000000000000000000000000000000000000000000000000081565b6112f6610680565b6001600160a01b0316336001600160a01b031614611352576040805162461bcd60e51b815260206004820152601460248201527337b7363c9030b2323932b9b9903ab83230ba32b960611b604482015290519081900360640190fd5b61138b61138683836040518060400160405280600e81526020016d20b2323932b9b9aab83230ba32b960911b815250611ff0565b61211d565b6113958282612141565b5050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6113c5612dbe565b6113cf6004611ba0565b604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382016040518060a001604052908160008201805480602002602001604051908101604052809291908181526020016000905b8282101561149e5760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a0830152908352909201910161142d565b50505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505081525050905090565b600b5481565b600054600160a81b900460ff1681565b6000336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611560576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b50600090565b61156e6117f6565b600054600160a81b900460ff16156115cd576040805162461bcd60e51b815260206004820152601a60248201527f616c726561647920696e2070726f64756374696f6e206d6f6465000000000000604482015290519081900360640190fd5b60008054600161ff0160a01b031916600160a81b1790556040805160076001609c1b01815290517f83af113638b5422f9e977cebc0aaf0eaf2188eb9a8baae7f9d46c42b33a1560c9181900360200190a1565b60408051808201909152600d81526c125b98d95b9d1a5d99541bdbdb609a1b602082015290565b600b546000906107359062015180611776565b611662612dbe565b61166d60048361226b565b604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382016040518060a001604052908160008201805480602002602001604051908101604052809291908181526020016000905b8282101561173c5760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a083015290835290920191016116cb565b5050509082525060018201546020820152600282015460408201526003820154606082015260049091015460809091015290525092915050565b6000828201838110156117d0576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b3d604051818101604052816000823e82156117f2578181f35b8181fd5b6117fe6106a5565b6001600160a01b0316336001600160a01b031614611855576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b565b5490565b60035460408051631b73b4cb60e01b815290516000926001600160a01b031691631b73b4cb916004808301926020929190829003018186803b1580156118a057600080fd5b505afa1580156118b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d891906131b2565b600754600a54919250600091611924919061191e906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163190611776565b906122dd565b9050600260009054906101000a90046001600160a01b03166001600160a01b031663981940296040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561197657600080fd5b505af19250505080156119a6575060408051601f3d908101601f191682019092526119a3918101906131b2565b60015b611a09576119b261349f565b806119bd57506119d7565b8060405162461bcd60e51b81526004016102129190613275565b6040518060600160405280602681526020016135676026913960405162461bcd60e51b81526004016102129190613275565b611a1760048584868561233a565b506000611a246004611ba0565b604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382016040518060a001604052908160008201805480602002602001604051908101604052809291908181526020016000905b82821015611af35760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a08301529083529092019101611a82565b5050505081526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152505090507f677db469fe5eaf40f0415f5433ebc8ebe9ac089662feca0280495fb4c96da29181602001518260400151858460000151856060015160200151866060015160400151876060015160600151886060015160800151604051611b92989796959493929190613421565b60405180910390a150505050565b600080611bac83611857565b11604051806040016040528060088152602001676e6f20616e6e756d60c01b81525090611bec5760405162461bcd60e51b81526004016102129190613275565b5081600001826001015481548110611c0057fe5b90600052602060002090600802019050919050565b6000808211611c5e576040805162461bcd60e51b815260206004820152601060248201526f4469766973696f6e206279207a65726f60801b604482015290519081900360640190fd5b83611c6b57506000611d1c565b83830283858281611c7857fe5b041415611c9157828181611c8857fe5b04915050611d1c565b6000838681611c9c57fe5b0490506000848781611caa57fe5b0690506000858781611cb857fe5b0490506000868881611cc657fe5b069050611d14611ce088611cda86856123fc565b90612455565b611d0e611ced86866123fc565b611d0e611cfa89876123fc565b611d0e8d611d088c8b6123fc565b906123fc565b90611776565b955050505050505b9392505050565b600080611d2f86611ba0565b60028701546003880154919250611d5891611d4a84896124bc565b6003850192919088886124db565b6003870154909250611d6a9083611776565b6003870181905560028701541015611d7e57fe5b50949350505050565b600080611d9384611ba0565b9050611da26003820184612730565b6004850154909250611db49083611776565b6004850181905560038501541015611dc857fe5b5092915050565b600080611ddb83611ba0565b9050611de981600301612854565b6005840154909250611dfb9083611776565b6005840181905560048401541015611e0f57fe5b6006830154611e1e9083611776565b6006840181905560058401541015611e3257fe5b50919050565b600054600160b01b900460ff1615611e6557333014611e5357fe5b6000805460ff60b01b19169055611855565b6118556117f6565b611e756117f6565b600082359050600060076001609c1b016001600160a01b0316636221a54b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ebd57600080fd5b505afa158015611ed1573d6000803e3d6000fd5b505050506040513d6020811015611ee757600080fd5b505160408051808201825242830180825282516020601f89018190048102820181019094528781529394509290918281019190889088908190840183828082843760009201829052509390945250506001600160e01b03198616815260016020818152604090922084518155848301518051919450611f6b93928501920190612deb565b509050507fed948300a3694aa01d4a6b258bfd664350193d770c0b51f8387277f6d83ea3b68382878760405180856001600160e01b0319168152602001848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f191690920182900397509095505050505050a15050505050565b600080826040516020018080602001828103825283818151815260200191508051906020019080838360005b8381101561203457818101518382015260200161201c565b50505050905090810190601f1680156120615780820380516001836020036101000a031916815260200191505b50925050506040516020818303038152906040528051906020012090506000805b86518110156120c95786818151811061209757fe5b60200260200101518314156120c1578581815181106120b257fe5b602002602001015191506120c9565b600101612082565b506001600160a01b038116612114576040805162461bcd60e51b815260206004820152600c60248201526b61646472657373207a65726f60a01b604482015290519081900360640190fd5b95945050505050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b600061216c838360405180604001604052806006815260200165537570706c7960d01b815250611ff0565b6003546040519192507f9a9b245c8db671c90d6db95f7ff0c18c15378a1d55ee4aea21759be8ad27d30e916121ac916001600160a01b031690849061325b565b60405180910390a1600380546001600160a01b0319166001600160a01b03831617905560408051808201909152601781527f496e63656e74697665506f6f6c416c6c6f636174696f6e00000000000000000060208201526122109084908490611ff0565b600280546001600160a01b0319166001600160a01b0392831617908190556040517f8c42cf8a1561f290fbb07d1ff00cab15929cf29ebc85adb0b8aaee1cd57be7ec9261225e921690613223565b60405180910390a1505050565b600061227683611857565b8210604051806040016040528060088152602001676e6f20616e6e756d60c01b815250906122b75760405162461bcd60e51b81526004016102129190613275565b508260000182815481106122c757fe5b9060005260206000209060080201905092915050565b600082821115612334576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b600061234586611857565b111561239c5761235485611ba0565b60020154841160405180604001604052806009815260200168746f6f206561726c7960b81b8152509061239a5760405162461bcd60e51b81526004016102129190613275565b505b84546001810186556000868152602090206008909102016123c081868686866129fe565b805460028701546123d091611776565b60028701558554600110156123f4576001868101546123ee91611776565b60018701555b505050505050565b60008261240b575060006117d3565b8282028284828161241857fe5b04146117d05760405162461bcd60e51b815260040180806020018281038252602181526020018061358d6021913960400191505060405180910390fd5b60008082116124ab576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816124b457fe5b049392505050565b600082600201548211156124cc57fe5b6117d06001611d0e8585612a2a565b60008151600014156124ef57506000612726565b600061250861250286611cda8a8a6122dd565b85612a56565b600189015490925082915061251d9082611776565b600189015561271060005b845181101561272257600061255f86838151811061254257fe5b6020026020010151602001518486611c159092919063ffffffff16565b905061256b84826122dd565b935061259786838151811061257c57fe5b602002602001015160200151846122dd90919063ffffffff16565b92506000806125bd8d8986815181106125ac57fe5b602002602001015160000151612a6c565b9150915081156126015760008d60000182815481106125d857fe5b906000526020600020906006020190506125fb8482612acf90919063ffffffff16565b50612652565b8c54600181018e5560008e815260209020895160069092020190612646908a908790811061262b57fe5b60200260200101516000015182612aeb90919063ffffffff16565b6126508185612acf565b505b87848151811061265e57fe5b6020026020010151600001516001600160a01b031663de6feb78846040518263ffffffff1660e01b815260040161269591906133c6565b600060405180830381600087803b1580156126af57600080fd5b505af11580156126c3573d6000803e3d6000fd5b505050507f7783f810e61c0050d5bcac23752779876844351f2984c24b51c19f7f949c8e498885815181106126f457fe5b6020026020010151600001518460405161270f929190613242565b60405180910390a1505050600101612528565b5050505b9695505050505050565b6000805b8354811015612830576000836001600160a01b0316634b13e87286600001848154811061275d57fe5b60009182526020909120600690910201546040516001600160e01b031960e084901b168152612798916001600160a01b031690600401613223565b606060405180830381600087803b1580156127b257600080fd5b505af11580156127c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127ea9190613134565b905061282561281e8287600001858154811061280257fe5b9060005260206000209060060201612b2c90919063ffffffff16565b8490611776565b925050600101612734565b5060028301546128409082611776565b60028401819055600184015410156117d357fe5b6000805b8254811015611e3257600061288884600001838154811061287557fe5b9060005260206000209060060201612c7a565b90506128b98185600001848154811061289d57fe5b9060005260206000209060060201612c9790919063ffffffff16565b60038401546128c89082611776565b600385015583548490839081106128db57fe5b6000918252602082206006909102015460408051630a763c4b60e31b815290516001600160a01b03909216926353b1e258928592600480820193929182900301818588803b15801561292c57600080fd5b505af1158015612940573d6000803e3d6000fd5b50505050506129748185600001848154811061295857fe5b9060005260206000209060060201612cb290919063ffffffff16565b60048401546129839082611776565b60048501556129928382611776565b92507f14539bbe7bf8bc27c7dd3cd8f969ee5ed76f196818aebbeb71de02ac27183a678460000183815481106129c457fe5b60009182526020909120600690910201546040516129ed916001600160a01b0316908490613242565b60405180910390a150600101612858565b60018501849055612a10838383612ccd565b8555612a1b84612cfd565b85600201819055505050505050565b600282015460009080831115612a445760009150506117d3565b612a4e8382612d15565b9150506117d3565b6000818310612a6557816117d0565b5090919050565b600080805b8454811015612ac757836001600160a01b0316856000018281548110612a9357fe5b60009182526020909120600690910201546001600160a01b03161415612abf5780915060019250612ac7565b600101612a71565b509250929050565b6001820154612ade9082611776565b6001830155600290910155565b81546001600160a01b0319166001600160a01b0391909116178155600060018201819055600282018190556003820181905560048201819055600590910155565b81546000906001600160a01b0316318183516001811115612b4957fe5b1415612be45760208301516002850154600091612b6891906064611c15565b9050600082821115612b8157612b7e82846122dd565b90505b6000612b8c87612c7a565b905081811115612b9f5760009450612bac565b612ba982826122dd565b94505b6000612bcd886004015461191e848b600101546122dd90919063ffffffff16565b905080861115612bdb578095505b50505050612c19565b600183516001811115612bf357fe5b1415612c135760038401546001850154612c0c916122dd565b9150612c19565b60009150fe5b6003840154612c289083611776565b600385015583546040517fd6c57656fb4211e1e1ca98fb5da438e294ee525b0eb501a7c143163416013da491612c6b916001600160a01b03909116908590613242565b60405180910390a15092915050565b60006117d3826004015483600301546122dd90919063ffffffff16565b6004820154612ca69082611776565b82600401819055505050565b6005820154612cc19082611776565b82600501819055505050565b6000612cf5612ce084846201d4c0611c15565b612cf0866103e86201d4c0611c15565b612a56565b949350505050565b60006117d36001612d0f84601e612d30565b90612d45565b600081831115612d2457600080fd5b620151808383036124b4565b6201518081028201828110156117d357600080fd5b808203828111156117d357600080fd5b6040805160608101909152806000815260006020820181905260409091015290565b50805460018160011615610100020316600290046000825580601f10612d9d5750612dbb565b601f016020900490600052602060002090810190612dbb9190612e6f565b50565b6040518060800160405280600081526020016000815260200160008152602001612de6612e84565b905290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282612e215760008555612e67565b82601f10612e3a57805160ff1916838001178555612e67565b82800160010185558215612e67579182015b82811115612e67578251825591602001919060010190612e4c565b50610f929291505b5b80821115610f925760008155600101612e70565b6040518060a0016040528060608152602001600081526020016000815260200160008152602001600081525090565b600082601f830112612ec3578081fd5b81356020612ed8612ed38361347b565b613457565b8281528181019085830183850287018401881015612ef4578586fd5b855b85811015612f1b578135612f0981613544565b84529284019290840190600101612ef6565b5090979650505050505050565b600060208284031215612f39578081fd5b81356117d081613544565b60008060408385031215612f56578081fd5b823567ffffffffffffffff80821115612f6d578283fd5b818501915085601f830112612f80578283fd5b81356020612f90612ed38361347b565b82815281810190858301838502870184018b1015612fac578788fd5b8796505b84871015612fce578035835260019690960195918301918301612fb0565b5096505086013592505080821115612fe4578283fd5b50612ff185828601612eb3565b9150509250929050565b6000602080838503121561300d578182fd5b825167ffffffffffffffff80821115613024578384fd5b818501915085601f830112613037578384fd5b8151613045612ed38261347b565b818152848101908486016040808502870188018b1015613063578889fd5b8896505b848710156130bd5780828c03121561307d578889fd5b8051818101818110888211171561309057fe5b8252825161309d81613544565b815282890151898201528452600196909601959287019290810190613067565b50909998505050505050505050565b6000602082840312156130dd578081fd5b81356001600160e01b0319811681146117d0578182fd5b600080600060608486031215613108578081fd5b833561311381613544565b9250602084013561312381613559565b929592945050506040919091013590565b600060608284031215613145578081fd5b6040516060810181811067ffffffffffffffff8211171561316257fe5b604052825161317081613559565b8152602083810151908201526040830151801515811461318e578283fd5b60408201529392505050565b6000602082840312156131ab578081fd5b5035919050565b6000602082840312156131c3578081fd5b5051919050565b60008151808452815b818110156131ef576020818501810151868301820152016131d3565b818111156132005782602083870101525b50601f01601f19169290920160200192915050565b6002811061321f57fe5b9052565b6001600160a01b0391909116815260200190565b901515815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6000602082526117d060208301846131ca565b6000602080835260a0845182850152818501516040818187015280870151915060608281880152808801519250608080818901526101408801845186878b01528181518084526101608c01915089830193508a92505b8083101561333257835180516001600160a01b031683528a8101518b84015287810151888401528681015187840152858101518684015289015189830152928901926001929092019160c0909101906132de565b509786015160c08b015250509183015160e08801528201516101008701520151610120909401939093529392505050565b6000606082019050613376828451613215565b6020830151602083015260408301511515604083015292915050565b60006060820190506133a88260ff855416613215565b6001830154602083015260029092015460ff16151560409091015290565b90815260200190565b600083825260406020830152612cf560408301846131ca565b9283526020830191909152604082015260600190565b948552602085019390935260408401919091526060830152608082015260a00190565b978852602088019690965260408701949094526060860192909252608085015260a084015260c083015260e08201526101000190565b60405181810167ffffffffffffffff8111828210171561347357fe5b604052919050565b600067ffffffffffffffff82111561348f57fe5b5060209081020190565b60e01c90565b600060443d10156134af57610738565b600481823e6308c379a06134c38251613499565b146134cd57610738565b6040513d600319016004823e80513d67ffffffffffffffff81602484011181841117156134fd5750505050610738565b828401925082519150808211156135175750505050610738565b503d8301602082840101111561352f57505050610738565b601f01601f1916810160200160405291505090565b6001600160a01b0381168114612dbb57600080fd5b60028110612dbb57600080fdfe756e6b6e6f776e206572726f722e20676574416e6e75616c50657263656e7461676542697073536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a2646970667358221220503e0222a79264355967f4c67519a30dc1b722f4bec55571c70b3e49263e6d2464736f6c634300070600330000000000000000000000004598a6c05910ab914f0cbaaca1911cd337d10d290000000000000000000000001000000000000000000000000000000000000002000000000000000000000000baf89d873d198ff78e72d2745b01cba3c6e5be6b00000000000000000000000010000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000063718500

Deployed ByteCode

0x6080604052600436106101a05760003560e01c806384e10a90116100ec578063c9d3dc871161008a578063f5a9838311610064578063f5a98383146104cd578063f5f5ba72146104e2578063f639c12c14610504578063f64cee61146105195761021e565b8063c9d3dc871461048e578063e17f212e146104a3578063e22fdece146104b85761021e565b8063a1077532116100c6578063a107753214610422578063b00c0b7614610437578063b8cca0cf14610457578063c39049e41461046c5761021e565b806384e10a90146103c7578063983963d8146103ed5780639d6a890f146104025761021e565b80635ff270791161015957806367fc40291161013357806367fc4029146103375780636d0e8c34146103575780636e61ab961461037957806374e6310e146103995761021e565b80635ff27079146102eb57806361d027b31461030d57806362354e03146103225761021e565b8063047fc9aa146102235780632dafdbbf1461024e57806333ed77cc146102725780634b13e872146102945780635267a15d146102c15780635aa6e675146102d65761021e565b3661021e5760408051808201909152600d81526c7472656173757279206f6e6c7960981b6020820152336001600160a01b037f0000000000000000000000001000000000000000000000000000000000000005161461021b5760405162461bcd60e51b81526004016102129190613275565b60405180910390fd5b50005b600080fd5b34801561022f57600080fd5b50610238610539565b6040516102459190613223565b60405180910390f35b34801561025a57600080fd5b50610263610548565b604051610245939291906133e8565b34801561027e57600080fd5b5061028761059f565b60405161024591906133c6565b3480156102a057600080fd5b506102b46102af366004612f28565b6105a5565b6040516102459190613363565b3480156102cd57600080fd5b50610238610680565b3480156102e257600080fd5b506102386106a5565b3480156102f757600080fd5b5061030b6103063660046130cc565b61073b565b005b34801561031957600080fd5b50610238610a90565b34801561032e57600080fd5b50610238610ab4565b34801561034357600080fd5b5061030b6103523660046130cc565b610abf565b34801561036357600080fd5b5061036c610ba7565b6040516102459190613237565b34801561038557600080fd5b5061030b6103943660046130f4565b610f96565b3480156103a557600080fd5b506103b96103b43660046130cc565b611142565b6040516102459291906133cf565b3480156103d357600080fd5b506103dc6111e8565b6040516102459594939291906133fe565b3480156103f957600080fd5b50610238611202565b34801561040e57600080fd5b5061030b61041d366004612f28565b611211565b34801561042e57600080fd5b506102386112ca565b34801561044357600080fd5b5061030b610452366004612f44565b6112ee565b34801561046357600080fd5b50610287611399565b34801561047857600080fd5b506104816113bd565b6040516102459190613288565b34801561049a57600080fd5b506102876114d7565b3480156104af57600080fd5b5061036c6114dd565b3480156104c457600080fd5b5061036c6114ed565b3480156104d957600080fd5b5061030b611566565b3480156104ee57600080fd5b506104f7611620565b6040516102459190613275565b34801561051057600080fd5b50610287611647565b34801561052557600080fd5b5061048161053436600461319a565b61165a565b6003546001600160a01b031681565b600080600061058f6004600601547f00000000000000000000000010000000000000000000000000000000000000056001600160a01b03163161177690919063ffffffff16565b600a549094600094509092509050565b600d5481565b6105ad612d55565b60408051808201909152600c81526b06164647265737320697320360a41b602082015282906001600160a01b0382166105f95760405162461bcd60e51b81526004016102129190613275565b506001600160a01b0383166000908152600c60205260409020600281015460ff1661064057805460ff19908116825560786001808401919091556002830180549092161790555b8054839060ff16600181111561065257fe5b9081600181111561065f57fe5b905250600181015460208401526002015460ff161515604083015250919050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e77195490565b60008054600160a81b900460ff166106c8576000546001600160a01b0316610735565b60076001609c1b016001600160a01b031663732524946040518163ffffffff1660e01b815260040160206040518083038186803b15801561070857600080fd5b505afa15801561071c573d6000803e3d6000fd5b505050506040513d602081101561073257600080fd5b50515b90505b90565b60408051630debfda360e41b8152336004820152905160076001609c1b019163debfda30916024808301926020929190829003018186803b15801561077f57600080fd5b505afa158015610793573d6000803e3d6000fd5b505050506040513d60208110156107a957600080fd5b50516107ec576040805162461bcd60e51b815260206004820152600d60248201526c37b7363c9032bc32b1baba37b960991b604482015290519081900360640190fd5b6001600160e01b0319811660009081526001602052604090208054610858576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b80544210156108ae576040805162461bcd60e51b815260206004820152601960248201527f74696d656c6f636b3a206e6f7420616c6c6f7765642079657400000000000000604482015290519081900360640190fd5b6000816001018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156109485780601f1061091d57610100808354040283529160200191610948565b820191906000526020600020905b81548152906001019060200180831161092b57829003601f168201915b5050506001600160e01b031986166000908152600160208190526040822082815594955090925061097c9150830182612d77565b50506000805460ff60b01b1916600160b01b178155604051825130918491819060208401908083835b602083106109c45780518252601f1990920191602091820191016109a5565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114610a26576040519150601f19603f3d011682016040523d82523d6000602084013e610a2b565b606091505b50506000805460ff60b01b19169055604080516001600160e01b03198716815242602082015281519293507fa7326b57fc9cfe267aaea5e7f0b01757154d265620a0585819416ee9ddd2c438929081900390910190a1610a8a816117d9565b50505050565b7f000000000000000000000000100000000000000000000000000000000000000581565b60076001609c1b0181565b610ac76117f6565b6001600160e01b03198116600090815260016020526040902054610b32576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b604080516001600160e01b03198316815242602082015281517f7735b2391c38a81419c513e30ca578db7158eadd7101511b23e221c654d19cf8929181900390910190a16001600160e01b03198116600090815260016020819052604082208281559190610ba290830182612d77565b505050565b60035460408051808201909152600c81526b06164647265737320697320360a41b60208201526000916001600160a01b03169081610bf85760405162461bcd60e51b81526004016102129190613275565b50336001600160a01b037f00000000000000000000000010000000000000000000000000000000000000021614610c6a576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000637185001580610cb657507f000000000000000000000000000000000000000000000000000000006371850042105b15610cc45760019150610f92565b600d54610cd05742600d555b610cda6004611857565b610cec57610ce74261185b565b610d1b565b6000610cf86004611ba0565b60020154905080421115610d1957610d19610d14826001611776565b61185b565b505b600b544290610d2d9062015180611776565b11610f8d5742600b819055506000610e7542610ddf60646101907f00000000000000000000000010000000000000000000000000000000000000056001600160a01b03166397249db76040518163ffffffff1660e01b815260040160206040518083038186803b158015610da057600080fd5b505afa158015610db4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd891906131b2565b9190611c15565b600260009054906101000a90046001600160a01b03166001600160a01b031663c853b8d46040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610e2f57600080fd5b505af1158015610e43573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e6b9190810190612ffb565b6004929190611d23565b90507f83271265e292ba2d92e1eb89cdbda68f1803ae726a27a5afe6a77d6430cddbd581604051610ea691906133c6565b60405180910390a16000610ebb600430611d87565b90507f1f0936062e6ce780790714a1ec5787d290675660a8566059ac9d6cfb2a336eec81604051610eec91906133c6565b60405180910390a160405163ec8d877760e01b81526001600160a01b037f0000000000000000000000001000000000000000000000000000000000000005169063ec8d877790610f409084906004016133c6565b600060405180830381600087803b158015610f5a57600080fd5b505af1158015610f6e573d6000803e3d6000fd5b505050506000610f7e6004611dcf565b9050808214610f8957fe5b5050505b600191505b5090565b60408051808201909152600c81526b06164647265737320697320360a41b602082015283906001600160a01b038216610fe25760405162461bcd60e51b81526004016102129190613275565b50600054600160b01b900460ff16806110055750600054600160a81b900460ff16155b1561113757611012611e38565b600083600181111561102057fe5b14156110ae57604080518082019091526009815268746f707570206c6f7760b81b6020820152606483116110675760405162461bcd60e51b81526004016102129190613275565b5060408051808201909152600a8152690e8dee0eae040d0d2ced60b31b60208201526101908311156110ac5760405162461bcd60e51b81526004016102129190613275565b505b6001600160a01b0384166000908152600c6020526040902080548490829060ff1916600183818111156110dd57fe5b0217905550600180820184905560028201805460ff191690911790556040517fcf085312d79a75faa5f1b9f6bec58a64813338f5e5e5759573cab22c6da2d25b90611129908390613392565b60405180910390a150610a8a565b610a8a600036611e6d565b600160208181526000928352604092839020805481840180548651600296821615610100026000190190911695909504601f810185900485028601850190965285855290949193929091908301828280156111de5780601f106111b3576101008083540402835291602001916111de565b820191906000526020600020905b8154815290600101906020018083116111c157829003601f168201915b5050505050905082565b600754600854600954600a54600654939492939192909190565b6002546001600160a01b031681565b600054600160a01b900460ff1615611267576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b7f000000000000000000000000100000000000000000000000000000000000000281565b6112f6610680565b6001600160a01b0316336001600160a01b031614611352576040805162461bcd60e51b815260206004820152601460248201527337b7363c9030b2323932b9b9903ab83230ba32b960611b604482015290519081900360640190fd5b61138b61138683836040518060400160405280600e81526020016d20b2323932b9b9aab83230ba32b960911b815250611ff0565b61211d565b6113958282612141565b5050565b7f000000000000000000000000000000000000000000000000000000006371850081565b6113c5612dbe565b6113cf6004611ba0565b604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382016040518060a001604052908160008201805480602002602001604051908101604052809291908181526020016000905b8282101561149e5760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a0830152908352909201910161142d565b50505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505081525050905090565b600b5481565b600054600160a81b900460ff1681565b6000336001600160a01b037f00000000000000000000000010000000000000000000000000000000000000021614611560576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b50600090565b61156e6117f6565b600054600160a81b900460ff16156115cd576040805162461bcd60e51b815260206004820152601a60248201527f616c726561647920696e2070726f64756374696f6e206d6f6465000000000000604482015290519081900360640190fd5b60008054600161ff0160a01b031916600160a81b1790556040805160076001609c1b01815290517f83af113638b5422f9e977cebc0aaf0eaf2188eb9a8baae7f9d46c42b33a1560c9181900360200190a1565b60408051808201909152600d81526c125b98d95b9d1a5d99541bdbdb609a1b602082015290565b600b546000906107359062015180611776565b611662612dbe565b61166d60048361226b565b604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382016040518060a001604052908160008201805480602002602001604051908101604052809291908181526020016000905b8282101561173c5760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a083015290835290920191016116cb565b5050509082525060018201546020820152600282015460408201526003820154606082015260049091015460809091015290525092915050565b6000828201838110156117d0576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b3d604051818101604052816000823e82156117f2578181f35b8181fd5b6117fe6106a5565b6001600160a01b0316336001600160a01b031614611855576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b565b5490565b60035460408051631b73b4cb60e01b815290516000926001600160a01b031691631b73b4cb916004808301926020929190829003018186803b1580156118a057600080fd5b505afa1580156118b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d891906131b2565b600754600a54919250600091611924919061191e906001600160a01b037f0000000000000000000000001000000000000000000000000000000000000005163190611776565b906122dd565b9050600260009054906101000a90046001600160a01b03166001600160a01b031663981940296040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561197657600080fd5b505af19250505080156119a6575060408051601f3d908101601f191682019092526119a3918101906131b2565b60015b611a09576119b261349f565b806119bd57506119d7565b8060405162461bcd60e51b81526004016102129190613275565b6040518060600160405280602681526020016135676026913960405162461bcd60e51b81526004016102129190613275565b611a1760048584868561233a565b506000611a246004611ba0565b604051806080016040529081600082015481526020016001820154815260200160028201548152602001600382016040518060a001604052908160008201805480602002602001604051908101604052809291908181526020016000905b82821015611af35760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a08301529083529092019101611a82565b5050505081526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152505090507f677db469fe5eaf40f0415f5433ebc8ebe9ac089662feca0280495fb4c96da29181602001518260400151858460000151856060015160200151866060015160400151876060015160600151886060015160800151604051611b92989796959493929190613421565b60405180910390a150505050565b600080611bac83611857565b11604051806040016040528060088152602001676e6f20616e6e756d60c01b81525090611bec5760405162461bcd60e51b81526004016102129190613275565b5081600001826001015481548110611c0057fe5b90600052602060002090600802019050919050565b6000808211611c5e576040805162461bcd60e51b815260206004820152601060248201526f4469766973696f6e206279207a65726f60801b604482015290519081900360640190fd5b83611c6b57506000611d1c565b83830283858281611c7857fe5b041415611c9157828181611c8857fe5b04915050611d1c565b6000838681611c9c57fe5b0490506000848781611caa57fe5b0690506000858781611cb857fe5b0490506000868881611cc657fe5b069050611d14611ce088611cda86856123fc565b90612455565b611d0e611ced86866123fc565b611d0e611cfa89876123fc565b611d0e8d611d088c8b6123fc565b906123fc565b90611776565b955050505050505b9392505050565b600080611d2f86611ba0565b60028701546003880154919250611d5891611d4a84896124bc565b6003850192919088886124db565b6003870154909250611d6a9083611776565b6003870181905560028701541015611d7e57fe5b50949350505050565b600080611d9384611ba0565b9050611da26003820184612730565b6004850154909250611db49083611776565b6004850181905560038501541015611dc857fe5b5092915050565b600080611ddb83611ba0565b9050611de981600301612854565b6005840154909250611dfb9083611776565b6005840181905560048401541015611e0f57fe5b6006830154611e1e9083611776565b6006840181905560058401541015611e3257fe5b50919050565b600054600160b01b900460ff1615611e6557333014611e5357fe5b6000805460ff60b01b19169055611855565b6118556117f6565b611e756117f6565b600082359050600060076001609c1b016001600160a01b0316636221a54b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ebd57600080fd5b505afa158015611ed1573d6000803e3d6000fd5b505050506040513d6020811015611ee757600080fd5b505160408051808201825242830180825282516020601f89018190048102820181019094528781529394509290918281019190889088908190840183828082843760009201829052509390945250506001600160e01b03198616815260016020818152604090922084518155848301518051919450611f6b93928501920190612deb565b509050507fed948300a3694aa01d4a6b258bfd664350193d770c0b51f8387277f6d83ea3b68382878760405180856001600160e01b0319168152602001848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f191690920182900397509095505050505050a15050505050565b600080826040516020018080602001828103825283818151815260200191508051906020019080838360005b8381101561203457818101518382015260200161201c565b50505050905090810190601f1680156120615780820380516001836020036101000a031916815260200191505b50925050506040516020818303038152906040528051906020012090506000805b86518110156120c95786818151811061209757fe5b60200260200101518314156120c1578581815181106120b257fe5b602002602001015191506120c9565b600101612082565b506001600160a01b038116612114576040805162461bcd60e51b815260206004820152600c60248201526b61646472657373207a65726f60a01b604482015290519081900360640190fd5b95945050505050565b7f714f205b2abd25bef1d06a1af944e38c113fe6160375c4e1d6d5cf28848e771955565b600061216c838360405180604001604052806006815260200165537570706c7960d01b815250611ff0565b6003546040519192507f9a9b245c8db671c90d6db95f7ff0c18c15378a1d55ee4aea21759be8ad27d30e916121ac916001600160a01b031690849061325b565b60405180910390a1600380546001600160a01b0319166001600160a01b03831617905560408051808201909152601781527f496e63656e74697665506f6f6c416c6c6f636174696f6e00000000000000000060208201526122109084908490611ff0565b600280546001600160a01b0319166001600160a01b0392831617908190556040517f8c42cf8a1561f290fbb07d1ff00cab15929cf29ebc85adb0b8aaee1cd57be7ec9261225e921690613223565b60405180910390a1505050565b600061227683611857565b8210604051806040016040528060088152602001676e6f20616e6e756d60c01b815250906122b75760405162461bcd60e51b81526004016102129190613275565b508260000182815481106122c757fe5b9060005260206000209060080201905092915050565b600082821115612334576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b600061234586611857565b111561239c5761235485611ba0565b60020154841160405180604001604052806009815260200168746f6f206561726c7960b81b8152509061239a5760405162461bcd60e51b81526004016102129190613275565b505b84546001810186556000868152602090206008909102016123c081868686866129fe565b805460028701546123d091611776565b60028701558554600110156123f4576001868101546123ee91611776565b60018701555b505050505050565b60008261240b575060006117d3565b8282028284828161241857fe5b04146117d05760405162461bcd60e51b815260040180806020018281038252602181526020018061358d6021913960400191505060405180910390fd5b60008082116124ab576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816124b457fe5b049392505050565b600082600201548211156124cc57fe5b6117d06001611d0e8585612a2a565b60008151600014156124ef57506000612726565b600061250861250286611cda8a8a6122dd565b85612a56565b600189015490925082915061251d9082611776565b600189015561271060005b845181101561272257600061255f86838151811061254257fe5b6020026020010151602001518486611c159092919063ffffffff16565b905061256b84826122dd565b935061259786838151811061257c57fe5b602002602001015160200151846122dd90919063ffffffff16565b92506000806125bd8d8986815181106125ac57fe5b602002602001015160000151612a6c565b9150915081156126015760008d60000182815481106125d857fe5b906000526020600020906006020190506125fb8482612acf90919063ffffffff16565b50612652565b8c54600181018e5560008e815260209020895160069092020190612646908a908790811061262b57fe5b60200260200101516000015182612aeb90919063ffffffff16565b6126508185612acf565b505b87848151811061265e57fe5b6020026020010151600001516001600160a01b031663de6feb78846040518263ffffffff1660e01b815260040161269591906133c6565b600060405180830381600087803b1580156126af57600080fd5b505af11580156126c3573d6000803e3d6000fd5b505050507f7783f810e61c0050d5bcac23752779876844351f2984c24b51c19f7f949c8e498885815181106126f457fe5b6020026020010151600001518460405161270f929190613242565b60405180910390a1505050600101612528565b5050505b9695505050505050565b6000805b8354811015612830576000836001600160a01b0316634b13e87286600001848154811061275d57fe5b60009182526020909120600690910201546040516001600160e01b031960e084901b168152612798916001600160a01b031690600401613223565b606060405180830381600087803b1580156127b257600080fd5b505af11580156127c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127ea9190613134565b905061282561281e8287600001858154811061280257fe5b9060005260206000209060060201612b2c90919063ffffffff16565b8490611776565b925050600101612734565b5060028301546128409082611776565b60028401819055600184015410156117d357fe5b6000805b8254811015611e3257600061288884600001838154811061287557fe5b9060005260206000209060060201612c7a565b90506128b98185600001848154811061289d57fe5b9060005260206000209060060201612c9790919063ffffffff16565b60038401546128c89082611776565b600385015583548490839081106128db57fe5b6000918252602082206006909102015460408051630a763c4b60e31b815290516001600160a01b03909216926353b1e258928592600480820193929182900301818588803b15801561292c57600080fd5b505af1158015612940573d6000803e3d6000fd5b50505050506129748185600001848154811061295857fe5b9060005260206000209060060201612cb290919063ffffffff16565b60048401546129839082611776565b60048501556129928382611776565b92507f14539bbe7bf8bc27c7dd3cd8f969ee5ed76f196818aebbeb71de02ac27183a678460000183815481106129c457fe5b60009182526020909120600690910201546040516129ed916001600160a01b0316908490613242565b60405180910390a150600101612858565b60018501849055612a10838383612ccd565b8555612a1b84612cfd565b85600201819055505050505050565b600282015460009080831115612a445760009150506117d3565b612a4e8382612d15565b9150506117d3565b6000818310612a6557816117d0565b5090919050565b600080805b8454811015612ac757836001600160a01b0316856000018281548110612a9357fe5b60009182526020909120600690910201546001600160a01b03161415612abf5780915060019250612ac7565b600101612a71565b509250929050565b6001820154612ade9082611776565b6001830155600290910155565b81546001600160a01b0319166001600160a01b0391909116178155600060018201819055600282018190556003820181905560048201819055600590910155565b81546000906001600160a01b0316318183516001811115612b4957fe5b1415612be45760208301516002850154600091612b6891906064611c15565b9050600082821115612b8157612b7e82846122dd565b90505b6000612b8c87612c7a565b905081811115612b9f5760009450612bac565b612ba982826122dd565b94505b6000612bcd886004015461191e848b600101546122dd90919063ffffffff16565b905080861115612bdb578095505b50505050612c19565b600183516001811115612bf357fe5b1415612c135760038401546001850154612c0c916122dd565b9150612c19565b60009150fe5b6003840154612c289083611776565b600385015583546040517fd6c57656fb4211e1e1ca98fb5da438e294ee525b0eb501a7c143163416013da491612c6b916001600160a01b03909116908590613242565b60405180910390a15092915050565b60006117d3826004015483600301546122dd90919063ffffffff16565b6004820154612ca69082611776565b82600401819055505050565b6005820154612cc19082611776565b82600501819055505050565b6000612cf5612ce084846201d4c0611c15565b612cf0866103e86201d4c0611c15565b612a56565b949350505050565b60006117d36001612d0f84601e612d30565b90612d45565b600081831115612d2457600080fd5b620151808383036124b4565b6201518081028201828110156117d357600080fd5b808203828111156117d357600080fd5b6040805160608101909152806000815260006020820181905260409091015290565b50805460018160011615610100020316600290046000825580601f10612d9d5750612dbb565b601f016020900490600052602060002090810190612dbb9190612e6f565b50565b6040518060800160405280600081526020016000815260200160008152602001612de6612e84565b905290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282612e215760008555612e67565b82601f10612e3a57805160ff1916838001178555612e67565b82800160010185558215612e67579182015b82811115612e67578251825591602001919060010190612e4c565b50610f929291505b5b80821115610f925760008155600101612e70565b6040518060a0016040528060608152602001600081526020016000815260200160008152602001600081525090565b600082601f830112612ec3578081fd5b81356020612ed8612ed38361347b565b613457565b8281528181019085830183850287018401881015612ef4578586fd5b855b85811015612f1b578135612f0981613544565b84529284019290840190600101612ef6565b5090979650505050505050565b600060208284031215612f39578081fd5b81356117d081613544565b60008060408385031215612f56578081fd5b823567ffffffffffffffff80821115612f6d578283fd5b818501915085601f830112612f80578283fd5b81356020612f90612ed38361347b565b82815281810190858301838502870184018b1015612fac578788fd5b8796505b84871015612fce578035835260019690960195918301918301612fb0565b5096505086013592505080821115612fe4578283fd5b50612ff185828601612eb3565b9150509250929050565b6000602080838503121561300d578182fd5b825167ffffffffffffffff80821115613024578384fd5b818501915085601f830112613037578384fd5b8151613045612ed38261347b565b818152848101908486016040808502870188018b1015613063578889fd5b8896505b848710156130bd5780828c03121561307d578889fd5b8051818101818110888211171561309057fe5b8252825161309d81613544565b815282890151898201528452600196909601959287019290810190613067565b50909998505050505050505050565b6000602082840312156130dd578081fd5b81356001600160e01b0319811681146117d0578182fd5b600080600060608486031215613108578081fd5b833561311381613544565b9250602084013561312381613559565b929592945050506040919091013590565b600060608284031215613145578081fd5b6040516060810181811067ffffffffffffffff8211171561316257fe5b604052825161317081613559565b8152602083810151908201526040830151801515811461318e578283fd5b60408201529392505050565b6000602082840312156131ab578081fd5b5035919050565b6000602082840312156131c3578081fd5b5051919050565b60008151808452815b818110156131ef576020818501810151868301820152016131d3565b818111156132005782602083870101525b50601f01601f19169290920160200192915050565b6002811061321f57fe5b9052565b6001600160a01b0391909116815260200190565b901515815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6000602082526117d060208301846131ca565b6000602080835260a0845182850152818501516040818187015280870151915060608281880152808801519250608080818901526101408801845186878b01528181518084526101608c01915089830193508a92505b8083101561333257835180516001600160a01b031683528a8101518b84015287810151888401528681015187840152858101518684015289015189830152928901926001929092019160c0909101906132de565b509786015160c08b015250509183015160e08801528201516101008701520151610120909401939093529392505050565b6000606082019050613376828451613215565b6020830151602083015260408301511515604083015292915050565b60006060820190506133a88260ff855416613215565b6001830154602083015260029092015460ff16151560409091015290565b90815260200190565b600083825260406020830152612cf560408301846131ca565b9283526020830191909152604082015260600190565b948552602085019390935260408401919091526060830152608082015260a00190565b978852602088019690965260408701949094526060860192909252608085015260a084015260c083015260e08201526101000190565b60405181810167ffffffffffffffff8111828210171561347357fe5b604052919050565b600067ffffffffffffffff82111561348f57fe5b5060209081020190565b60e01c90565b600060443d10156134af57610738565b600481823e6308c379a06134c38251613499565b146134cd57610738565b6040513d600319016004823e80513d67ffffffffffffffff81602484011181841117156134fd5750505050610738565b828401925082519150808211156135175750505050610738565b503d8301602082840101111561352f57505050610738565b601f01601f1916810160200160405291505090565b6001600160a01b0381168114612dbb57600080fd5b60028110612dbb57600080fdfe756e6b6e6f776e206572726f722e20676574416e6e75616c50657263656e7461676542697073536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a2646970667358221220503e0222a79264355967f4c67519a30dc1b722f4bec55571c70b3e49263e6d2464736f6c63430007060033