Contract Address Details

0x87E80E90EACA1d458dfdf60a9d697e7E83aB02b2

Contract Name
Inflation
Creator
0x493044–a7586e at 0x369ddd–3e5a86
Balance
0 SGB
Tokens
Fetching tokens...
Transactions
5 Transactions
Transfers
1 Transfers
Gas Used
198,804
Last Balance Update
27206897
Contract name:
Inflation




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




Optimization runs
200
EVM Version
default




Verified at
2021-09-22T15:17:37.689115Z

Constructor Arguments

000000000000000000000000493044fbbaa7f9f78379864fa88accaff6a7586e0000000000000000000000001000000000000000000000000000000000000002000000000000000000000000039314fc0ee5552d868837517580444948388387000000000000000000000000039314fc0ee5552d868837517580444948388387000000000000000000000000000000000000000000000000000000006143aba1

Arg [0] (address) : 0x493044fbbaa7f9f78379864fa88accaff6a7586e
Arg [1] (address) : 0x1000000000000000000000000000000000000002
Arg [2] (address) : 0x039314fc0ee5552d868837517580444948388387
Arg [3] (address) : 0x039314fc0ee5552d868837517580444948388387
Arg [4] (uint256) : 1631824801

              

Contract source code

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

// Inlining: GovernedBase.sol

// Data
pragma solidity 0.7.6;


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

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

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

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

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

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

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

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

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

        initialised = true;
        emit GovernanceUpdated(governance, _governance);
        governance = _governance;
        proposedGovernance = address(0);
    }
}
// End of data
// End of inlining: GovernedBase.sol

// Inlining: Inflation.sol


// Inlining: IIInflationSharingPercentageProvider.sol

// Data
pragma solidity 0.7.6;


struct SharingPercentage {
    IIInflationReceiver inflationReceiver;
    uint256 percentBips;
}

interface IIInflationSharingPercentageProvider {
    /**
     * Return the shared percentage per inflation 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);
}
// End of data
// End of inlining: IIInflationSharingPercentageProvider.sol

// Inlining: InflationAnnum.sol


// Inlining: SafeCast.sol

// Data
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);
    }
}
// End of data
// End of inlining: SafeCast.sol

// Inlining: RewardServices.sol

// Data
pragma solidity 0.7.6;



/**
 * @title 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 inflation receiver
 *   with a sharing percentage used to calculate percentage of authorized inflation 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 minted and sent for claiming reserves, and it stores totals for a given
 *   inflation
 *   receiver, for a given annum.
 **/
library RewardServices {
    using BokkyPooBahsDateTimeLibrary for uint256;
    using RewardService for RewardService.RewardServiceState;
    using SafeMath for uint256;
    using SafePct for uint256;

    /**
     * @dev `RewardServicesState` is state structure used by this library to manage
     *   a collection of reward services and associated totals.
     */
    struct RewardServicesState {
        // Collection of annums
        RewardService.RewardServiceState[] rewardServices;
        // Balances
        uint256 totalAuthorizedInflationWei;
        uint256 totalInflationTopupRequestedWei;
        uint256 totalInflationTopupReceivedWei;
        uint256 totalInflationTopupWithdrawnWei;
    }

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

    event RewardServiceDailyAuthorizedInflationComputed(IIInflationReceiver inflationReceiver, uint256 amountWei);
    event RewardServiceTopupRequestReceived(IIInflationReceiver inflationReceiver, uint256 amountWei);

    /**
     * @notice For all sharing percentages, compute authorized daily inflation for current cycle
     *  and then allocate it across associated inflation receivers according to their sharing percentages,
     *  updating reward service totals along the way. Finally,
     *  set the daily authorized inflation for the given inflation receiver.
     * @param _totalRecognizedInflationWei The total recognized inflation across all annums.
     * @param _totalAuthorizedInflationWei The total authorized inflation across all annums.
     * @param _periodsRemaining The number of periods remaining in the current annum.
     * @param _sharingPercentages An array of inflation sharing percentages.
     * @return _amountAuthorizedWei The inflation 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 authorizeDailyInflation(
        RewardServicesState storage _self,
        uint256 _totalRecognizedInflationWei,
        uint256 _totalAuthorizedInflationWei,
        uint256 _periodsRemaining,
        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 = _totalRecognizedInflationWei
            .sub(_totalAuthorizedInflationWei)
            .div(_periodsRemaining);
        // 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.totalAuthorizedInflationWei = _self.totalAuthorizedInflationWei.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 rewardServiceIndex ) =
                findRewardService(_self, _sharingPercentages[i].inflationReceiver);
            if (found) {
                // Get the existing reward service
                RewardService.RewardServiceState storage rewardService = _self.rewardServices[rewardServiceIndex];
                // Accumulate the amount authorized for the service
                rewardService.addAuthorizedInflation(toAuthorizeWei);
            } else {
                // Initialize a new reward service
                RewardService.RewardServiceState storage rewardService = _self.rewardServices.push();
                rewardService.initialize(_sharingPercentages[i].inflationReceiver);
                // Accumulate the amount authorized for the service
                rewardService.addAuthorizedInflation(toAuthorizeWei);
            }
            // Signal the inflation receiver of the reward service (the actual rewarding contract)
            // with amount just authorized.
            _sharingPercentages[i].inflationReceiver.setDailyAuthorizedInflation(toAuthorizeWei);

            emit RewardServiceDailyAuthorizedInflationComputed(
                _sharingPercentages[i].inflationReceiver,
                toAuthorizeWei);
        }
    }

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

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

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

            emit RewardServiceTopupRequestReceived(_self.rewardServices[i].inflationReceiver, pendingTopupWei);
        }
    }
}
// End of data
// End of inlining: RewardServices.sol

// Inlining: DateTimeLibrary.sol

// Data
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;
    }
}
// End of data
// End of inlining: DateTimeLibrary.sol
// Data
pragma solidity 0.7.6;



/**
 * @title Inflation Annum library
 * @notice A library to manage an inflation annum.
 **/
library InflationAnnum {
    using BokkyPooBahsDateTimeLibrary for uint256;
    using InflationAnnum for InflationAnnum.InflationAnnumState;
    using SafeCast for uint256;
    using SafeMath for uint256;
    using SafePct for uint256;

    /**
     * @dev `InflationAnnumState` is state structure used by this library to manage
     *   an inflation annum.
     */
    struct InflationAnnumState {
        uint256 recognizedInflationWei;
        uint16 daysInAnnum;
        uint256 startTimeStamp;
        uint256 endTimeStamp;
        RewardServices.RewardServicesState rewardServices;
    }

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

    /**
     * @notice Helper function to compute recognized inflation.
     * @param _inflatableBalance                The balance used to recognize inflation.
     * @param _annualInflationPercentageBips    The annual percentage used to recognize inflation.
     * @return The computed recognized inflation.
     */
    function _computeRecognizedInflationWei(
        uint256 _inflatableBalance,
        uint256 _annualInflationPercentageBips
    )
        internal pure
        returns(uint256)
    {
        return _inflatableBalance.mulDiv(
            _annualInflationPercentageBips,
            BIPS100);
    }

    /**
     * @notice Helper function to compute the number of days in an annum.
     * @param _startTimeStamp   The start time of the annum in question.
     * @return  The number of days in the annum.
     */
    function _computeDaysInAnnum(uint256 _startTimeStamp, uint256 _endTimeStamp) internal pure returns(uint16) {
        uint256 daysInAnnum = _startTimeStamp.diffDays(_endTimeStamp.add(1));
        return daysInAnnum.toUint16();
    }

    /**
     * @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(
        InflationAnnumState 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.addYears(1).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(
        InflationAnnumState 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 _inflatableBalanceWei The inflatable balance used to calculate recognized inflation for the new annum.
     * @param _annualInflationPercentageBips The annual inflation percentage in bips to calc recognized inflation.
     * @dev A newly created InflationAnnumState is expected to exist.
     */
    function initialize(
        InflationAnnumState storage _self,
        uint256 _startTimeStamp,
        uint256 _inflatableBalanceWei,
        uint256 _annualInflationPercentageBips
    )
        internal
    {
        _self.startTimeStamp = _startTimeStamp;
        _self.recognizedInflationWei = _computeRecognizedInflationWei(
            _inflatableBalanceWei,
            _annualInflationPercentageBips);
        _self.endTimeStamp = _getAnnumEndsTs(_startTimeStamp);
        _self.daysInAnnum = _computeDaysInAnnum(_startTimeStamp, _self.endTimeStamp);
    }
}
// End of data
// End of inlining: InflationAnnum.sol

// Inlining: GovernedAndFlareDaemonized.sol


// Inlining: Governed.sol

// Data
pragma solidity 0.7.6;



/**
 * @title Governed
 * @dev For deployed, governed contracts, enforce a non-zero address at create time.
 **/
contract Governed is GovernedBase {
    constructor(address _governance) GovernedBase(_governance) {
        require(_governance != address(0), "_governance zero");
    }
}
// End of data
// End of inlining: Governed.sol
// Data
pragma solidity 0.7.6;


contract GovernedAndFlareDaemonized is Governed {

    FlareDaemon public immutable flareDaemon;

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

    constructor(address _governance, FlareDaemon _flareDaemon) Governed(_governance) {
        require(address(_flareDaemon) != address(0), "flare daemon zero");
        flareDaemon = _flareDaemon;
    }
}
// End of data
// End of inlining: GovernedAndFlareDaemonized.sol

// Inlining: IInflationGenesis.sol

// Data
pragma solidity 0.7.6;



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

// Inlining: IIInflationReceiver.sol

// Data
pragma solidity 0.7.6;

interface IIInflationReceiver {
    /**
     * Notify the receiver that it is entitled to receive `_toAuthorizeWei` inflation amount.
     * @param _toAuthorizeWei the amount of inflation that can be awarded in the coming day
     */
    function setDailyAuthorizedInflation(uint256 _toAuthorizeWei) external;

    /**
     * Receive native tokens from inflation.
     */
    function receiveInflation() external payable;

    /**
     * Inflation receivers have a reference to the Inflation contract.
     */
    function getInflationAddress() external returns(address);
}
// End of data
// End of inlining: IIInflationReceiver.sol

// Inlining: IIInflationPercentageProvider.sol

// Data
pragma solidity 0.7.6;

interface IIInflationPercentageProvider {
    /**
     * Return the annual inflation rate in bips.
     */
    function getAnnualPercentageBips() external returns(uint256);
}
// End of data
// End of inlining: IIInflationPercentageProvider.sol

// Inlining: RewardService.sol

// Data
pragma solidity 0.7.6;



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 inflation 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 inflation-related totals. When a topup configuration is applied, a reward service can
 *   also make minting requests to topup native tokens within a reward contract.
 * @dev A reward service exists within the context of a given inflation annum.
 **/
library RewardService {
    using SafeMath for uint256;
    using SafePct for uint256;

    /**
     * @dev `RewardServiceState` is state structure used by this library to manage
     *   an a reward service tracking authorize inflation.
     */
    struct RewardServiceState {
        IIInflationReceiver inflationReceiver;          // The target rewarding contract
        uint256 authorizedInflationWei;                 // Total authorized inflation for this reward service
        uint256 lastDailyAuthorizedInflationWei;        // Last daily authorized inflation amount
        uint256 inflationTopupRequestedWei;             // Total inflation topup requested to be minted
        uint256 inflationTopupReceivedWei;              // Total inflation minting received
        uint256 inflationTopupWithdrawnWei;             // Total inflation minting sent to rewarding service contract
    }

    event RewardServiceTopupComputed(IIInflationReceiver inflationReceiver, uint256 amountWei);

    /**
     * @notice Maintain authorized inflation total for service.
     * @param _amountWei Amount to add.
     */
    function addAuthorizedInflation(RewardServiceState storage _self, uint256 _amountWei) internal {
        _self.authorizedInflationWei = _self.authorizedInflationWei.add(_amountWei);
        _self.lastDailyAuthorizedInflationWei = _amountWei;
    }

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

    /**
     * @notice Maintain topup native tokens withdrawn (funded) total for service.
     * @param _amountWei Amount to add.
     */
    function addTopupWithdrawn(RewardServiceState storage _self, uint256 _amountWei) internal {
        _self.inflationTopupWithdrawnWei = _self.inflationTopupWithdrawnWei.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(
        RewardServiceState storage _self,
        TopupConfiguration memory _topupConfiguration
    )
        internal
        returns (uint256 _topupRequestWei)
    {
        // Get the balance of the inflation receiver
        uint256 inflationReceiverBalanceWei = address(_self.inflationReceiver).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.lastDailyAuthorizedInflationWei
                .mulDiv(_topupConfiguration.topupFactorX100, 100);
            uint256 rawTopupRequestWei = 0;
            // If current balance is less then requested, request some more.
            if (requestedBalanceWei > inflationReceiverBalanceWei) {
                rawTopupRequestWei = requestedBalanceWei.sub(inflationReceiverBalanceWei);
            }
            // 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.authorizedInflationWei
                .sub(topupPendingWei)
                .sub(_self.inflationTopupReceivedWei);
            if (_topupRequestWei > maxTopupRequestWei) {
                _topupRequestWei = maxTopupRequestWei;
            }
        } else if (_topupConfiguration.topupType == TopupType.ALLAUTHORIZED) {
            _topupRequestWei = _self.authorizedInflationWei
                .sub(_self.inflationTopupRequestedWei);
        } else { // This code is unreachable since TopupType currently has only 2 constructors
            _topupRequestWei = 0;
            assert(false);
        }
        _self.inflationTopupRequestedWei = _self.inflationTopupRequestedWei.add(_topupRequestWei);

        emit RewardServiceTopupComputed(_self.inflationReceiver, _topupRequestWei);
    }

    /**
     * @notice Compute a pending topup request.
     * @return _pendingTopupWei The amount pending to be minted.
     */
    function getPendingTopup(
        RewardServiceState storage _self
    )
        internal view
        returns(uint256 _pendingTopupWei)
    {
        return _self.inflationTopupRequestedWei.sub(_self.inflationTopupReceivedWei);
    }

    /**
     * @notice Initial a new reward service.
     * @dev Assume service is already instantiated.
     */
    function initialize(
        RewardServiceState storage _self,
        IIInflationReceiver _inflationReceiver
    )
        internal
    {
        _self.inflationReceiver = _inflationReceiver;
        _self.authorizedInflationWei = 0;
        _self.lastDailyAuthorizedInflationWei = 0;
        _self.inflationTopupRequestedWei = 0;
        _self.inflationTopupReceivedWei = 0;
        _self.inflationTopupWithdrawnWei = 0;
    }
}
// End of data
// End of inlining: RewardService.sol

// Inlining: IFlareDaemonize.sol

// Data
pragma solidity 0.7.6;


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

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

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

// Inlining: IISupply.sol

// Data
pragma solidity 0.7.6;


interface IISupply {

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

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

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

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

    /**
     * @notice Get total inflatable balance (initial genesis amount + total authorized inflation)
     * @return _inflatableBalanceWei Return inflatable balance
    */
    function getInflatableBalance() external view returns(uint256 _inflatableBalanceWei);
}
// End of data
// End of inlining: IISupply.sol

// Inlining: SafeMath.sol

// Data
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;
    }
}
// End of data
// End of inlining: SafeMath.sol

// Inlining: SafePct.sol

// Data
pragma solidity 0.7.6;


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

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

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

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

        return (a.mul(c).mul(z)).add(a.mul(d)).add(b.mul(c)).add(b.mul(d).div(z));
    }
}
// End of data
// End of inlining: SafePct.sol

// Inlining: FlareDaemon.sol


// Inlining: GovernedAtGenesis.sol



// Data
pragma solidity 0.7.6;



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

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

    /**
     * @notice Disallow initialise to be called
     * @param _governance The governance address for initial claiming
     **/
    // solhint-disable-next-line no-unused-vars
    function initialise(address _governance) public override pure {
        assert(false);
    }
}
// End of data
// End of inlining: GovernedAtGenesis.sol
// Data
pragma solidity 0.7.6;
// 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.



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

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

    struct LastErrorData {
        uint192 totalDaemonizedErrors;
        uint64 lastErrorTypeIndex;
    }

    struct Registration {
        IFlareDaemonize daemonizedContract;
        uint256 gasLimit;
    }

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

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

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

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

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

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

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

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

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

    /**
     * @dev Access control to protect methods to allow only minters to call select methods
     *   (like transferring balance out).
     */
    modifier onlyInflation (address _inflation) {
        require (address(inflation) == _inflation, ERR_NOT_INFLATION);
        _;
    }
    
    /**
     * @dev Access control to protect trigger() method. 
     * Please note that the sender address is the same as deployed FlareDaemon address in this case.
     */
    modifier onlySystemTrigger {
        require (msg.sender == 0x1000000000000000000000000000000000000002);
        _;
    }

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

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

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

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

        // Unregister everything first
        _unregisterAll();

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

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

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

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

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

        maxMintingRequestWei = _maxMintingRequestWei;
        lastUpdateMaxMintRequestTs = block.timestamp;
    }

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

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

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

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

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

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

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

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

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

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

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

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

        uint256 currentBalance = address(this).balance;

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

        uint256 len = daemonizeContracts.length;

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

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

        lastBalance = address(this).balance;
    }

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

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

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

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

        uint256 len = daemonizeContracts.length;

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

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

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


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

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

// Inlining: InflationAnnums.sol

// Data
pragma solidity 0.7.6;



/**
 * @title Inflation Annums library
 * @notice A library to manage a collection of inflation annum and associated totals.
 * @dev Operations such as authorizing daily inflation 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 InflationAnnums {    
    using InflationAnnum for InflationAnnum.InflationAnnumState;
    using RewardServices for RewardServices.RewardServicesState;
    using SafeMath for uint256;
    using SafePct for uint256;

    /**
     * @dev `InflationAnnumsState` is state structure used by this library to manage
     *   a collection of inflation annums and associated totals.
     */
    struct InflationAnnumsState {
        // Collection of annums
        InflationAnnum.InflationAnnumState[] inflationAnnums;
        uint256 currentAnnum;
        // Balances
        uint256 totalRecognizedInflationWei;
        uint256 totalAuthorizedInflationWei;
        uint256 totalInflationTopupRequestedWei;
        uint256 totalInflationTopupReceivedWei;
        uint256 totalInflationTopupWithdrawnWei;
    }

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

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

        // Authorize daily inflation for the current annum, across reward services, given
        // sharing percentages.
        _amountAuthorizedWei = currentAnnum.rewardServices.authorizeDailyInflation(
            _self.totalRecognizedInflationWei,
            _self.totalAuthorizedInflationWei, 
            currentAnnum.getPeriodsRemaining(_atTimeStamp), 
            _sharingPercentages);
        // Accumulate total authorized inflation across all annums
        _self.totalAuthorizedInflationWei = _self.totalAuthorizedInflationWei.add(_amountAuthorizedWei);
        // Make sure that total authorized never exceeds total recognized
        assert(_self.totalAuthorizedInflationWei <= _self.totalRecognizedInflationWei);
    }

    /**
     * @notice Dispatch topup request calculations across reward services and sum up total mint request made
     *   to fund topup of reward services.
     * @param _inflation    The Inflation contract containing the topup confguration of each reward service.
     * @return _topupRequestWei The amount of native token requested to be minted across reward services for 
     *   this cycle.
     * @dev Invariant: total inflation topup requested cannot exceed total inflation authorized
     */
    function computeTopupRequest(
        InflationAnnumsState storage _self,
        Inflation _inflation
    )
        internal
        returns(uint256 _topupRequestWei)
    {
        // Get the current annum
        InflationAnnum.InflationAnnumState storage currentAnnum = getCurrentAnnum(_self);
        // Compute the topup
        _topupRequestWei = currentAnnum.rewardServices.computeTopupRequest(_inflation);
        // Sum the topup request total across annums
        _self.totalInflationTopupRequestedWei = _self.totalInflationTopupRequestedWei.add(_topupRequestWei);
        // Make sure that total topup requested can never exceed inflation authorized
        assert(_self.totalInflationTopupRequestedWei <= _self.totalAuthorizedInflationWei);
    }

    /**
     * @notice Receive minted native tokens (and fund) 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 receiveTopupRequest(
        InflationAnnumsState storage _self
    )
        internal
        returns(uint256 _amountPostedWei)
    {
        // Get the current annum
        InflationAnnum.InflationAnnumState storage currentAnnum = getCurrentAnnum(_self);

        // Receive minting of topup request. Post to received and withdrawn buckets for each reward service.
        _amountPostedWei = currentAnnum.rewardServices.receiveTopupRequest();
        // Post the amount of native tokens received into the Inflation contract
        _self.totalInflationTopupReceivedWei = _self.totalInflationTopupReceivedWei.add(_amountPostedWei);
        // Received should never be more than requested
        assert(_self.totalInflationTopupReceivedWei <= _self.totalInflationTopupRequestedWei);
        // Post amount withdrawn and transferred to reward service contracts
        _self.totalInflationTopupWithdrawnWei = _self.totalInflationTopupWithdrawnWei.add(_amountPostedWei);
        // Withdrawn should never be more than received
        assert(_self.totalInflationTopupWithdrawnWei <= _self.totalInflationTopupReceivedWei);
    }

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

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

    /**
     * @notice Return inflation annum data for the current annum.
     * @return _inflationAnnum  Returns InflationAnnum.InflationAnnumState for the current annum.
     * @dev Will revert if no current annum.
     */
    function getCurrentAnnum(
        InflationAnnumsState storage _self
    )
        internal view 
        returns (InflationAnnum.InflationAnnumState storage _inflationAnnum)
    {
        require(getCount(_self) > 0, ERR_NO_ANNUM);
        _inflationAnnum = _self.inflationAnnums[_self.currentAnnum];
    }

    /**
     * @notice Initialize a new annum, add it to the annum collection, maintian running total
     *   of recognized inflation resulting from new annum, and set current annum pointer.
     * @param _startTimeStamp                   The timestamp to start the annum.
     * @param _inflatableBalance                The balance to use when recognizing inflation for the annum.
     * @param _annualInflationPercentageBips    The inflation percentage in bips to use when recognizing inflation.
     */
    function initializeNewAnnum(
        InflationAnnumsState storage _self,
        uint256 _startTimeStamp, 
        uint256 _inflatableBalance, 
        uint256 _annualInflationPercentageBips
    ) 
        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
        InflationAnnum.InflationAnnumState storage inflationAnnum = _self.inflationAnnums.push();
        // Initialize it with newly passed in annum info
        inflationAnnum.initialize(_startTimeStamp, _inflatableBalance, _annualInflationPercentageBips);
        // Accumulate total recognized inflation across annums 
        _self.totalRecognizedInflationWei = 
            _self.totalRecognizedInflationWei.add(inflationAnnum.recognizedInflationWei);
        // Reposition index pointing to current annum
        if (_self.inflationAnnums.length > 1) {
            _self.currentAnnum = _self.currentAnnum.add(1);
        }
    }
}
// End of data
// End of inlining: InflationAnnums.sol
// Data
pragma solidity 0.7.6;


/**
 * @title Inflation
 * @notice A contract to manage the process of recognizing, authorizing, minting, and funding
 *   native tokens for Flare services that are rewardable by inflation.
 * @dev Please see docs/specs/Inflation.md to better understand this terminology.
 **/
contract Inflation is IInflationGenesis, GovernedAndFlareDaemonized, IFlareDaemonize {
    using InflationAnnums for InflationAnnums.InflationAnnumsState;
    using SafeMath for uint256;
    using SafePct for uint256;

    // Composable contracts
    IIInflationPercentageProvider public inflationPercentageProvider;
    IIInflationSharingPercentageProvider public inflationSharingPercentageProvider;
    IISupply public supply;

    // The annums
    InflationAnnums.InflationAnnumsState private inflationAnnums;       // Inflation annum data

    // Instance vars
    uint256 public lastAuthorizationTs;                                 // The last time inflation was authorized
    mapping(IIInflationReceiver => TopupConfiguration)
        internal topupConfigurations;                                   // A topup configuration for a contract
                                                                        //   receiving inflation.
    uint256 public totalSelfDestructReceivedWei;
    //slither-disable-next-line uninitialized-state                     // no problem, will be zero initialized anyway
    uint256 public totalSelfDestructWithdrawnWei;
    uint256 immutable public rewardEpochStartTs;                        // Do not start inflation 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_GET_ANNUAL_PERCENT = "unknown error. getAnnualPercentageBips";
    string internal constant ERR_SUPPLY_UPDATE = "unknown error. updateAuthorizedInflationAndCirculatingSupply";
    string internal constant ERR_REQUEST_MINT = "unknown error. requestMinting";

    uint256 internal constant BIPS100 = 1e4;                            // 100% in basis points
    uint256 internal constant DEFAULT_TOPUP_FACTOR_X100 = 120;
    // DO NOT UPDATE - this affects supply contract, which is expected to be updated once a day
    uint256 internal constant AUTHORIZE_TIME_FRAME_SEC = 1 days;

    event InflationAuthorized(uint256 amountWei);
    event MintingReceived(uint256 amountWei, uint256 selfDestructAmountWei);
    event TopupRequested(uint256 amountWei);
    event InflationPercentageProviderSet(IIInflationPercentageProvider inflationPercentageProvider);
    event InflationSharingPercentageProviderSet(
        IIInflationSharingPercentageProvider inflationSharingPercentageProvider);
    event RewardServiceTopupComputed(IIInflationReceiver inflationReceiver, uint256 amountWei);
    event RewardServiceDailyAuthorizedInflationComputed(IIInflationReceiver inflationReceiver, uint256 amountWei);
    event RewardServiceTopupRequestReceived(IIInflationReceiver inflationReceiver, uint256 amountWei);
    event SupplySet(IISupply oldSupply, IISupply newSupply);
    event TopupConfigurationSet(TopupConfiguration topupConfiguration);
    event NewAnnumInitialized(
        uint16 daysInAnnum,
        uint256 startTimeStamp,
        uint256 endTimeStamp,
        uint256 inflatableSupplyWei,
        uint256 recognizedInflationWei,
        uint256 totalAuthorizedInflationWei,
        uint256 totalInflationTopupRequestedWei,
        uint256 totalInflationTopupReceivedWei,
        uint256 totalInflationTopupWithdrawnWei
    );

    /**
     * @dev This modifier ensures that this contract's balance matches the expected balance.
     */
    modifier mustBalance {
        _;
        require (getExpectedBalance() == address(this).balance, ERR_OUT_OF_BALANCE);
    }

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

    constructor (
        address _governance, 
        FlareDaemon _flareDaemon,
        IIInflationPercentageProvider _inflationPercentageProvider,
        IIInflationSharingPercentageProvider _inflationSharingPercentageProvider,
        uint256 _rewardEpochStartTs
    )
        GovernedAndFlareDaemonized(_governance, _flareDaemon)
        notZero(address(_inflationPercentageProvider))
        notZero(address(_inflationSharingPercentageProvider))
    {
        inflationPercentageProvider = _inflationPercentageProvider;
        inflationSharingPercentageProvider = _inflationSharingPercentageProvider;
        rewardEpochStartTs = _rewardEpochStartTs;
    }

    /**
     * @notice Get a tuple of totals across inflation annums.
     * @return _totalAuthorizedInflationWei     Total inflation authorized to be mintable
     * @return _totalInflationTopupRequestedWei Total inflation requested to be topped up for rewarding
     * @return _totalInflationTopupReceivedWei  Total inflation received for funding reward services
     * @return _totalInflationTopupWithdrawnWei Total inflation used for funding reward services
     * @return _totalRecognizedInflationWei     Total inflation recognized for rewarding
     * @return _totalSelfDestructReceivedWei    Total balance received as a self-destruct recipient
     * @return _totalSelfDestructWithdrawnWei   Total self-destruct balance withdrawn
     */
    function getTotals()
        external view 
        returns (
            uint256 _totalAuthorizedInflationWei,
            uint256 _totalInflationTopupRequestedWei,
            uint256 _totalInflationTopupReceivedWei,
            uint256 _totalInflationTopupWithdrawnWei,
            uint256 _totalRecognizedInflationWei,
            uint256 _totalSelfDestructReceivedWei,
            uint256 _totalSelfDestructWithdrawnWei
        )
    {
        _totalAuthorizedInflationWei = inflationAnnums.totalAuthorizedInflationWei;
        _totalInflationTopupRequestedWei = inflationAnnums.totalInflationTopupRequestedWei;
        _totalInflationTopupReceivedWei = inflationAnnums.totalInflationTopupReceivedWei;
        _totalInflationTopupWithdrawnWei = inflationAnnums.totalInflationTopupWithdrawnWei;
        _totalRecognizedInflationWei = inflationAnnums.totalRecognizedInflationWei;
        _totalSelfDestructReceivedWei = totalSelfDestructReceivedWei;
        _totalSelfDestructWithdrawnWei = totalSelfDestructWithdrawnWei;
    }

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

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

    /**
     * @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 override payable onlyFlareDaemon mustBalance {
        uint256 amountPostedWei = inflationAnnums.receiveTopupRequest();
        // Assume that if we received (or already have) more than we posted, 
        // it must be amounts sent from a contract self-destruct
        // recipient in this block.
        uint256 prevBalance = getExpectedBalance();
        uint256 selfDestructProceeds = address(this).balance.sub(prevBalance);
        if (selfDestructProceeds > 0) {
            totalSelfDestructReceivedWei = totalSelfDestructReceivedWei.add(selfDestructProceeds);
        }
        emit MintingReceived(amountPostedWei, selfDestructProceeds);
    }

    /**
     * @notice Set a reference to a provider of the annual inflation percentage.
     * @param _inflationPercentageProvider  A contract providing the annual inflation percentage.
     * @dev Assume that referencing contract has reasonablness limitations on percentages.
     */
    function setInflationPercentageProvider(
        IIInflationPercentageProvider _inflationPercentageProvider
    )
        external
        notZero(address(_inflationPercentageProvider))
        onlyGovernance
    {
        inflationPercentageProvider = _inflationPercentageProvider;

        emit InflationPercentageProviderSet(_inflationPercentageProvider);
    }

    /**
     * @notice Set a reference to a provider of sharing percentages by inflation receiver.
     * @param _inflationSharingPercentageProvider   A contract providing sharing percentages.
     * @dev Assume that sharing percentages sum to 100% if at least one exists, but
     *   if no sharing percentages are defined, then no inflation will be authorized.
     */
    function setInflationSharingPercentageProvider(
        IIInflationSharingPercentageProvider _inflationSharingPercentageProvider
    )
        external
        notZero(address(_inflationSharingPercentageProvider))
        onlyGovernance
    {
        inflationSharingPercentageProvider = _inflationSharingPercentageProvider;

        emit InflationSharingPercentageProviderSet(_inflationSharingPercentageProvider);
    }

    /**
     * @notice Set a reference to the Supply contract.
     * @param _supply   The Supply contract.
     * @dev The supply contract is used to get and update the inflatable balance.
     */
    function setSupply(IISupply _supply) external notZero(address(_supply)) onlyGovernance {
        emit SupplySet(supply, _supply);
        supply = _supply;
    }

    /**
     * @notice Set the topup configuration for a reward service.
     * @param _inflationReceiver    The reward service to receive the inflation 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 inflation 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 greater than 100.
     */
    function setTopupConfiguration(
        IIInflationReceiver _inflationReceiver, 
        TopupType _topupType, 
        uint256 _topupFactorX100
    )
        external
        notZero(address(_inflationReceiver))
        onlyGovernance
    {
        if (_topupType == TopupType.FACTOROFDAILYAUTHORIZED) {
            require(_topupFactorX100 > 100, ERR_TOPUP_LOW);
        }
        TopupConfiguration storage topupConfiguration = topupConfigurations[_inflationReceiver];
        topupConfiguration.topupType = _topupType;
        topupConfiguration.topupFactorX100 = _topupFactorX100;
        topupConfiguration.configured = true;

        emit TopupConfigurationSet(topupConfiguration);
    }

    /**
     * @notice Given an inflation receiver, get the topup configuration.
     * @param _inflationReceiver    The reward service.
     * @return _topupConfiguration  The configurartion of how the topup requests are calculated for a given
     *                              reward service.
     */
    function getTopupConfiguration(
        IIInflationReceiver _inflationReceiver
    )
        external
        notZero(address(_inflationReceiver))
        returns(TopupConfiguration memory _topupConfiguration)
    {
        TopupConfiguration storage topupConfiguration = topupConfigurations[_inflationReceiver];
        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 inflation process.
     * @dev There are two events:
     *   1) an annual event to recognize inflation for a new annum
     *   2) a daily event to:
     *     a) authorize mintable inflation for rewarding
     *     b) request minting of enough native tokens to topup reward services for claiming reserves
     */
    function daemonize() external virtual override notZero(address(supply)) returns(bool) {
        // If inflation rewarding not started yet, blow off processing until it does.
        if (block.timestamp < rewardEpochStartTs) {
            return true;
        }

        // If inflation 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 inflation annum?
        if (inflationAnnums.getCount() == 0) {
            _initNewAnnum(block.timestamp);
        } else {
            uint256 currentAnnumEndTimeStamp = inflationAnnums.getCurrentAnnum().endTimeStamp;

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

        // Is it time to authorize new inflation? Do it daily.
        if (lastAuthorizationTs.add(AUTHORIZE_TIME_FRAME_SEC) < block.timestamp) {

            // Update time we last authorized.
            lastAuthorizationTs = block.timestamp;

            // Authorize inflation for current sharing percentges.
            uint256 amountAuthorizedWei = inflationAnnums.authorizeDailyInflation(
                block.timestamp,
                inflationSharingPercentageProvider.getSharingPercentages()
            );

            emit InflationAuthorized(amountAuthorizedWei);

            // Call supply contract to keep inflatable balance and circulating supply updated.
            try supply.updateAuthorizedInflationAndCirculatingSupply(amountAuthorizedWei) {
            } catch Error(string memory message) {
                revert(message);
            } catch {
                revert(ERR_SUPPLY_UPDATE);
            }

            // Time to compute topup amount for inflation receivers.
            uint256 topupRequestWei = inflationAnnums.computeTopupRequest(this);

            emit TopupRequested(topupRequestWei);

            // Send mint request to the daemon.
            try flareDaemon.requestMinting(topupRequestWei) {
            } catch Error(string memory message) {
                revert(message);
            } catch {
                revert(ERR_REQUEST_MINT);
            }
        }
        return true;
    }

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

    function _initNewAnnum(uint256 startTs) internal {
        uint256 inflatableSupply = supply.getInflatableBalance();

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

        InflationAnnum.InflationAnnumState memory inflationAnnum = inflationAnnums.getCurrentAnnum();

        emit NewAnnumInitialized(
            inflationAnnum.daysInAnnum, 
            inflationAnnum.startTimeStamp,
            inflationAnnum.endTimeStamp,
            inflatableSupply,
            inflationAnnum.recognizedInflationWei,
            inflationAnnum.rewardServices.totalAuthorizedInflationWei,
            inflationAnnum.rewardServices.totalInflationTopupRequestedWei,
            inflationAnnum.rewardServices.totalInflationTopupReceivedWei,
            inflationAnnum.rewardServices.totalInflationTopupWithdrawnWei
        );
    }

    /**
     * @notice Compute the expected balance of this contract.
     * @param _balanceExpectedWei   The computed balance expected.
     */
    function getExpectedBalance() private view returns(uint256 _balanceExpectedWei) {
        return inflationAnnums.totalInflationTopupReceivedWei        
            .sub(inflationAnnums.totalInflationTopupWithdrawnWei)
            .add(totalSelfDestructReceivedWei)
            .sub(totalSelfDestructWithdrawnWei);
    }
}
// End of data
// End of inlining: Inflation.sol
        

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_governance","internalType":"address"},{"type":"address","name":"_flareDaemon","internalType":"contract FlareDaemon"},{"type":"address","name":"_inflationPercentageProvider","internalType":"contract IIInflationPercentageProvider"},{"type":"address","name":"_inflationSharingPercentageProvider","internalType":"contract IIInflationSharingPercentageProvider"},{"type":"uint256","name":"_rewardEpochStartTs","internalType":"uint256"}]},{"type":"event","name":"GovernanceProposed","inputs":[{"type":"address","name":"proposedGovernance","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"GovernanceUpdated","inputs":[{"type":"address","name":"oldGovernance","internalType":"address","indexed":false},{"type":"address","name":"newGoveranance","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"InflationAuthorized","inputs":[{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"InflationPercentageProviderSet","inputs":[{"type":"address","name":"inflationPercentageProvider","internalType":"contract IIInflationPercentageProvider","indexed":false}],"anonymous":false},{"type":"event","name":"InflationSharingPercentageProviderSet","inputs":[{"type":"address","name":"inflationSharingPercentageProvider","internalType":"contract IIInflationSharingPercentageProvider","indexed":false}],"anonymous":false},{"type":"event","name":"MintingReceived","inputs":[{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"selfDestructAmountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"NewAnnumInitialized","inputs":[{"type":"uint16","name":"daysInAnnum","internalType":"uint16","indexed":false},{"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":"recognizedInflationWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalAuthorizedInflationWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalInflationTopupRequestedWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalInflationTopupReceivedWei","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalInflationTopupWithdrawnWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardServiceDailyAuthorizedInflationComputed","inputs":[{"type":"address","name":"inflationReceiver","internalType":"contract IIInflationReceiver","indexed":false},{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardServiceTopupComputed","inputs":[{"type":"address","name":"inflationReceiver","internalType":"contract IIInflationReceiver","indexed":false},{"type":"uint256","name":"amountWei","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardServiceTopupRequestReceived","inputs":[{"type":"address","name":"inflationReceiver","internalType":"contract IIInflationReceiver","indexed":false},{"type":"uint256","name":"amountWei","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":"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":"claimGovernance","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"daemonize","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract FlareDaemon"}],"name":"flareDaemon","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct InflationAnnum.InflationAnnumState","components":[{"type":"uint256","name":"recognizedInflationWei","internalType":"uint256"},{"type":"uint16","name":"daysInAnnum","internalType":"uint16"},{"type":"uint256","name":"startTimeStamp","internalType":"uint256"},{"type":"uint256","name":"endTimeStamp","internalType":"uint256"},{"type":"tuple","name":"rewardServices","internalType":"struct RewardServices.RewardServicesState","components":[{"type":"tuple[]","name":"rewardServices","internalType":"struct RewardService.RewardServiceState[]","components":[{"type":"address","name":"inflationReceiver","internalType":"contract IIInflationReceiver"},{"type":"uint256","name":"authorizedInflationWei","internalType":"uint256"},{"type":"uint256","name":"lastDailyAuthorizedInflationWei","internalType":"uint256"},{"type":"uint256","name":"inflationTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"inflationTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"inflationTopupWithdrawnWei","internalType":"uint256"}]},{"type":"uint256","name":"totalAuthorizedInflationWei","internalType":"uint256"},{"type":"uint256","name":"totalInflationTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"totalInflationTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"totalInflationTopupWithdrawnWei","internalType":"uint256"}]}]}],"name":"getAnnum","inputs":[{"type":"uint256","name":"_index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct InflationAnnum.InflationAnnumState","components":[{"type":"uint256","name":"recognizedInflationWei","internalType":"uint256"},{"type":"uint16","name":"daysInAnnum","internalType":"uint16"},{"type":"uint256","name":"startTimeStamp","internalType":"uint256"},{"type":"uint256","name":"endTimeStamp","internalType":"uint256"},{"type":"tuple","name":"rewardServices","internalType":"struct RewardServices.RewardServicesState","components":[{"type":"tuple[]","name":"rewardServices","internalType":"struct RewardService.RewardServiceState[]","components":[{"type":"address","name":"inflationReceiver","internalType":"contract IIInflationReceiver"},{"type":"uint256","name":"authorizedInflationWei","internalType":"uint256"},{"type":"uint256","name":"lastDailyAuthorizedInflationWei","internalType":"uint256"},{"type":"uint256","name":"inflationTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"inflationTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"inflationTopupWithdrawnWei","internalType":"uint256"}]},{"type":"uint256","name":"totalAuthorizedInflationWei","internalType":"uint256"},{"type":"uint256","name":"totalInflationTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"totalInflationTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"totalInflationTopupWithdrawnWei","internalType":"uint256"}]}]}],"name":"getCurrentAnnum","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":"_inflationReceiver","internalType":"contract IIInflationReceiver"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_totalAuthorizedInflationWei","internalType":"uint256"},{"type":"uint256","name":"_totalInflationTopupRequestedWei","internalType":"uint256"},{"type":"uint256","name":"_totalInflationTopupReceivedWei","internalType":"uint256"},{"type":"uint256","name":"_totalInflationTopupWithdrawnWei","internalType":"uint256"},{"type":"uint256","name":"_totalRecognizedInflationWei","internalType":"uint256"},{"type":"uint256","name":"_totalSelfDestructReceivedWei","internalType":"uint256"},{"type":"uint256","name":"_totalSelfDestructWithdrawnWei","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 IIInflationPercentageProvider"}],"name":"inflationPercentageProvider","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IIInflationSharingPercentageProvider"}],"name":"inflationSharingPercentageProvider","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialise","inputs":[{"type":"address","name":"_governance","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastAuthorizationTs","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"proposeGovernance","inputs":[{"type":"address","name":"_governance","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"proposedGovernance","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"receiveMinting","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":"setInflationPercentageProvider","inputs":[{"type":"address","name":"_inflationPercentageProvider","internalType":"contract IIInflationPercentageProvider"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setInflationSharingPercentageProvider","inputs":[{"type":"address","name":"_inflationSharingPercentageProvider","internalType":"contract IIInflationSharingPercentageProvider"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setSupply","inputs":[{"type":"address","name":"_supply","internalType":"contract IISupply"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setTopupConfiguration","inputs":[{"type":"address","name":"_inflationReceiver","internalType":"contract IIInflationReceiver"},{"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":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSelfDestructReceivedWei","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSelfDestructWithdrawnWei","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferGovernance","inputs":[{"type":"address","name":"_governance","internalType":"address"}]}]
            

Deployed ByteCode

0x6080604052600436106101815760003560e01c80639d6a890f116100d1578063c9d3dc871161008a578063e22fdece11610064578063e22fdece146103e8578063f4091864146103fd578063f64cee611461041d578063fb12efec1461043d57610181565b8063c9d3dc871461039e578063cf02a55b146103b3578063d38bfff4146103c857610181565b80639d6a890f1461030a578063a10775321461032a578063b8cca0cf1461033f578063c373a08e14610354578063c39049e414610374578063c611c2c51461039657610181565b80635d36b1901161013e5780636e61ab96116101185780636e61ab961461029857806372993615146102b857806375ff07b9146102cd57806384e10a90146102e257610181565b80635d36b1901461024c57806360f7ac97146102615780636d0e8c341461027657610181565b8063047fc9aa146101865780630edab99e146101b157806319fad18b146101c657806333ed77cc146101e85780634b13e8721461020a5780635aa6e67514610237575b600080fd5b34801561019257600080fd5b5061019b61045d565b6040516101a89190612b54565b60405180910390f35b3480156101bd57600080fd5b5061019b61046c565b3480156101d257600080fd5b506101e66101e1366004612978565b61047b565b005b3480156101f457600080fd5b506101fd61058c565b6040516101a89190612d8d565b34801561021657600080fd5b5061022a610225366004612978565b610592565b6040516101a89190612ce5565b34801561024357600080fd5b5061019b61066d565b34801561025857600080fd5b506101e661067c565b34801561026d57600080fd5b5061019b61073e565b34801561028257600080fd5b5061028b61074d565b6040516101a89190612b68565b3480156102a457600080fd5b506101e66102b3366004612a70565b610b6e565b3480156102c457600080fd5b506101fd610ced565b3480156102d957600080fd5b5061019b610cf3565b3480156102ee57600080fd5b506102f7610d02565b6040516101a89796959493929190612da4565b34801561031657600080fd5b506101e6610325366004612978565b610d26565b34801561033657600080fd5b5061019b610e00565b34801561034b57600080fd5b506101fd610e24565b34801561036057600080fd5b506101e661036f366004612978565b610e48565b34801561038057600080fd5b50610389610eed565b6040516101a89190612bf9565b6101e661100e565b3480156103aa57600080fd5b506101fd61114c565b3480156103bf57600080fd5b506101fd611152565b3480156103d457600080fd5b506101e66103e3366004612978565b611158565b3480156103f457600080fd5b5061028b61121a565b34801561040957600080fd5b506101e6610418366004612978565b611293565b34801561042957600080fd5b50610389610438366004612b16565b611388565b34801561044957600080fd5b506101e6610458366004612978565b6114aa565b6004546001600160a01b031681565b6002546001600160a01b031681565b60408051808201909152600c81526b06164647265737320697320360a41b602082015281906001600160a01b0382166104d05760405162461bcd60e51b81526004016104c79190612ba6565b60405180910390fd5b506000546001600160a01b03163314610522576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b6004546040517f9a9b245c8db671c90d6db95f7ff0c18c15378a1d55ee4aea21759be8ad27d30e91610561916001600160a01b03909116908590612b8c565b60405180910390a150600480546001600160a01b0319166001600160a01b0392909216919091179055565b60105481565b61059a6128ef565b60408051808201909152600c81526b06164647265737320697320360a41b602082015282906001600160a01b0382166105e65760405162461bcd60e51b81526004016104c79190612ba6565b506001600160a01b0383166000908152600d60205260409020600281015460ff1661062d57805460ff19908116825560786001808401919091556002830180549092161790555b8054839060ff16600181111561063f57fe5b9081600181111561064c57fe5b905250600181015460208401526002015460ff161515604083015250919050565b6000546001600160a01b031681565b6001546001600160a01b031633146106cb576040805162461bcd60e51b815260206004820152600d60248201526c1b9bdd0818db185a5b585a5b9d609a1b604482015290519081900360640190fd5b600054600154604080516001600160a01b03938416815292909116602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6001546001600160a01b031681565b60045460408051808201909152600c81526b06164647265737320697320360a41b60208201526000916001600160a01b0316908161079e5760405162461bcd60e51b81526004016104c79190612ba6565b50336001600160a01b037f00000000000000000000000010000000000000000000000000000000000000021614610810576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000006143aba14210156108415760019150610b6a565b60105461084d57426010555b6108576005611593565b6108695761086442611597565b610898565b60006108756005611886565b60030154905080421115610896576108966108918260016118fb565b611597565b505b600c5442906108aa90620151806118fb565b1015610b655742600c81905550600061095242600360009054906101000a90046001600160a01b03166001600160a01b031663c853b8d46040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561090d57600080fd5b505af1158015610921573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109499190810190612994565b6005919061195e565b90507fe69ea09c0c2d88b5a023a23e65e8ffeb65667d6b7b4076cbee9ba25f54502355816040516109839190612d8d565b60405180910390a160048054604051630512107160e51b81526001600160a01b039091169163a2420e20916109ba91859101612d8d565b600060405180830381600087803b1580156109d457600080fd5b505af19250505080156109e5575060015b610a48576109f1612dfe565b806109fc5750610a16565b8060405162461bcd60e51b81526004016104c79190612ba6565b6040518060600160405280603c8152602001612f33603c913960405162461bcd60e51b81526004016104c79190612ba6565b6000610a556005306119c0565b90507f1f0936062e6ce780790714a1ec5787d290675660a8566059ac9d6cfb2a336eec81604051610a869190612d8d565b60405180910390a160405163074ef3eb60e51b81526001600160a01b037f0000000000000000000000001000000000000000000000000000000000000002169063e9de7d6090610ada908490600401612d8d565b600060405180830381600087803b158015610af457600080fd5b505af1925050508015610b05575060015b610b6257610b11612dfe565b806109fc5750604080518082018252601d81527f756e6b6e6f776e206572726f722e20726571756573744d696e74696e670000006020820152905162461bcd60e51b81526104c79190600401612ba6565b50505b600191505b5090565b60408051808201909152600c81526b06164647265737320697320360a41b602082015283906001600160a01b038216610bba5760405162461bcd60e51b81526004016104c79190612ba6565b506000546001600160a01b03163314610c0c576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b6000836001811115610c1a57fe5b1415610c6357604080518082019091526009815268746f707570206c6f7760b81b602082015260648311610c615760405162461bcd60e51b81526004016104c79190612ba6565b505b6001600160a01b0384166000908152600d6020526040902080548490829060ff191660018381811115610c9257fe5b0217905550600180820184905560028201805460ff191690911790556040517fcf085312d79a75faa5f1b9f6bec58a64813338f5e5e5759573cab22c6da2d25b90610cde908390612d14565b60405180910390a15050505050565b600e5481565b6003546001600160a01b031681565b600854600954600a54600b54600754600e54600f5495969495939492939192909190565b600154600160a01b900460ff1615610d7c576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b6001805460ff60a01b1916600160a01b179055600054604080516001600160a01b039283168152918316602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a1600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b7f000000000000000000000000100000000000000000000000000000000000000281565b7f000000000000000000000000000000000000000000000000000000006143aba181565b6000546001600160a01b03163314610e99576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600180546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f1f95fb40be3a947982072902a887b521248d1d8931a39eb38f84f4d6fd758b699181900360200190a150565b610ef5612911565b610eff6005611886565b6040805160a0808201835283548252600184015461ffff1660208084019190915260028501548385015260038501546060840152835160048601805460c0938102830184019096529281018581529395946080870194919392849291849160009085015b82821015610fd45760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a08301529083529092019101610f63565b5050505081526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152505090505b90565b336001600160a01b037f0000000000000000000000001000000000000000000000000000000000000002161461107f576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b600061108b6005611a08565b90506000611097611a71565b905060006110a54783611aa4565b905080156110be57600e546110ba90826118fb565b600e555b7f992ba5c7b7d6602101783b4d28d0b93011fb883039e68c729b933bf71167862783826040516110ef929190612d96565b60405180910390a150505047611103611a71565b146040518060400160405280600e81526020016d6f7574206f662062616c616e636560901b815250906111495760405162461bcd60e51b81526004016104c79190612ba6565b50565b600c5481565b600f5481565b6000546001600160a01b031633146111a9576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600054604080516001600160a01b039283168152918316602083015280517f434a2db650703b36c824e745330d6397cdaa9ee2cc891a4938ae853e1c50b68d9281900390910190a1600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b6000336001600160a01b037f0000000000000000000000001000000000000000000000000000000000000002161461128d576040805162461bcd60e51b815260206004820152601160248201527037b7363c90333630b932903230b2b6b7b760791b604482015290519081900360640190fd5b50600090565b60408051808201909152600c81526b06164647265737320697320360a41b602082015281906001600160a01b0382166112df5760405162461bcd60e51b81526004016104c79190612ba6565b506000546001600160a01b03163314611331576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600280546001600160a01b0319166001600160a01b0384161790556040517f0af082a7803e8aab87aaf1c3d3579edf164f730507c244637104bcbf68795a059061137c908490612b54565b60405180910390a15050565b611390612911565b61139b600583611b01565b6040805160a0808201835283548252600184015461ffff1660208084019190915260028501548385015260038501546060840152835160048601805460c0938102830184019096529281018581529395946080870194919392849291849160009085015b828210156114705760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a083015290835290920191016113ff565b5050509082525060018201546020820152600282015460408201526003820154606082015260049091015460809091015290525092915050565b60408051808201909152600c81526b06164647265737320697320360a41b602082015281906001600160a01b0382166114f65760405162461bcd60e51b81526004016104c79190612ba6565b506000546001600160a01b03163314611548576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b600380546001600160a01b0319166001600160a01b0384161790556040517f678eecd70ad0d081346cfe3b80c1ea3a8face065f7d1b3f7342f50d202b7893e9061137c908490612b54565b5490565b6000600460009054906101000a90046001600160a01b03166001600160a01b0316631b73b4cb6040518163ffffffff1660e01b815260040160206040518083038186803b1580156115e757600080fd5b505afa1580156115fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161f9190612b2e565b9050600260009054906101000a90046001600160a01b03166001600160a01b031663981940296040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561167157600080fd5b505af19250505080156116a1575060408051601f3d908101601f1916820190925261169e91810190612b2e565b60015b6116e5576116ad612dfe565b806109fc5750604051806060016040528060268152602001612eec6026913960405162461bcd60e51b81526004016104c79190612ba6565b6116f26005848484611b73565b5060006116ff6005611886565b6040805160a0808201835283548252600184015461ffff1660208084019190915260028501548385015260038501546060840152835160048601805460c0938102830184019096529281018581529395946080870194919392849291849160009085015b828210156117d45760008481526020908190206040805160c0810182526006860290920180546001600160a01b031683526001808201548486015260028201549284019290925260038101546060840152600481015460808401526005015460a08301529083529092019101611763565b5050505081526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152505090507ffa3b6f810dd40012f117b5a482760aa3252aa7bc7f7d78004bace4223dec497981602001518260400151836060015185856000015186608001516020015187608001516040015188608001516060015189608001516080015160405161187999989796959493929190612d48565b60405180910390a1505050565b60008061189283611593565b11604051806040016040528060088152602001676e6f20616e6e756d60c01b815250906118d25760405162461bcd60e51b81526004016104c79190612ba6565b50816000018260010154815481106118e657fe5b90600052602060002090600902019050919050565b600082820183811015611955576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b60008061196a85611886565b60028601546003870154919250611992916119858488611c33565b6004850192919087611c52565b60038601549092506119a490836118fb565b60038601819055600286015410156119b857fe5b509392505050565b6000806119cc84611886565b90506119db6004820184611ea3565b60048501549092506119ed90836118fb565b6004850181905560038501541015611a0157fe5b5092915050565b600080611a1483611886565b9050611a2281600401611fc7565b6005840154909250611a3490836118fb565b6005840181905560048401541015611a4857fe5b6006830154611a5790836118fb565b6006840181905560058401541015611a6b57fe5b50919050565b600f54600e54600b54600a54600093611a9f939092611a9992611a9391611aa4565b906118fb565b90611aa4565b905090565b600082821115611afb576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000611b0c83611593565b8210604051806040016040528060088152602001676e6f20616e6e756d60c01b81525090611b4d5760405162461bcd60e51b81526004016104c79190612ba6565b50826000018281548110611b5d57fe5b9060005260206000209060090201905092915050565b6000611b7e85611593565b1115611bd557611b8d84611886565b60030154831160405180604001604052806009815260200168746f6f206561726c7960b81b81525090611bd35760405162461bcd60e51b81526004016104c79190612ba6565b505b8354600181018555600085815260209020600990910201611bf881858585612171565b80546002860154611c08916118fb565b6002860155845460011015611c2c57600185810154611c26916118fb565b60018601555b5050505050565b60008260030154821115611c4357fe5b6119556001611a9385856121be565b6000815160001415611c6657506000611e9a565b6000611c7c84611c768888611aa4565b906121ea565b6001880154909250829150611c9190826118fb565b600188015561271060005b8451811015611e96576000611cd3868381518110611cb657fe5b60200260200101516020015184866122519092919063ffffffff16565b9050611cdf8482611aa4565b9350611d0b868381518110611cf057fe5b60200260200101516020015184611aa490919063ffffffff16565b9250600080611d318c898681518110611d2057fe5b602002602001015160000151612353565b915091508115611d755760008c6000018281548110611d4c57fe5b90600052602060002090600602019050611d6f84826123b690919063ffffffff16565b50611dc6565b8b54600181018d5560008d815260209020895160069092020190611dba908a9087908110611d9f57fe5b602002602001015160000151826123d290919063ffffffff16565b611dc481856123b6565b505b878481518110611dd257fe5b6020026020010151600001516001600160a01b031663e2739563846040518263ffffffff1660e01b8152600401611e099190612d8d565b600060405180830381600087803b158015611e2357600080fd5b505af1158015611e37573d6000803e3d6000fd5b505050507fea9b87b57d7b678dd3c9da933ff547ad63395e04ee46cd57894c7b53618dc39a888581518110611e6857fe5b60200260200101516000015184604051611e83929190612b73565b60405180910390a1505050600101611c9c565b5050505b95945050505050565b6000805b8354811015611fa3576000836001600160a01b0316634b13e872866000018481548110611ed057fe5b60009182526020909120600690910201546040516001600160e01b031960e084901b168152611f0b916001600160a01b031690600401612b54565b606060405180830381600087803b158015611f2557600080fd5b505af1158015611f39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5d9190612ab0565b9050611f98611f9182876000018581548110611f7557fe5b906000526020600020906006020161241390919063ffffffff16565b84906118fb565b925050600101611ea7565b506002830154611fb390826118fb565b600284018190556001840154101561195857fe5b6000805b8254811015611a6b576000611ffb846000018381548110611fe857fe5b9060005260206000209060060201612561565b905061202c8185600001848154811061201057fe5b906000526020600020906006020161257e90919063ffffffff16565b600384015461203b90826118fb565b6003850155835484908390811061204e57fe5b60009182526020822060069091020154604080516306201f1d60e01b815290516001600160a01b03909216926306201f1d928592600480820193929182900301818588803b15801561209f57600080fd5b505af11580156120b3573d6000803e3d6000fd5b50505050506120e7818560000184815481106120cb57fe5b906000526020600020906006020161259990919063ffffffff16565b60048401546120f690826118fb565b600485015561210583826118fb565b92507f4839bc860ac633cfbce1fe18dc3c135733eca7b2dc8ed40e6e6b713a431bcf4484600001838154811061213757fe5b6000918252602090912060069091020154604051612160916001600160a01b0316908490612b73565b60405180910390a150600101611fcb565b6002840183905561218282826125b4565b845561218d836125c3565b6003850181905561219f9084906125da565b600194909401805461ffff191661ffff90951694909417909355505050565b6003820154600090808311156121d8576000915050611958565b6121e28382612605565b915050611958565b6000808211612240576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161224957fe5b049392505050565b600080821161229a576040805162461bcd60e51b815260206004820152601060248201526f4469766973696f6e206279207a65726f60801b604482015290519081900360640190fd5b836122a75750600061234c565b838302838582816122b457fe5b0414156122cd578281816122c457fe5b0491505061234c565b60008386816122d857fe5b04905060008487816122e657fe5b06905060008587816122f457fe5b049050600086888161230257fe5b06905061234461231688611c768685612620565b611a936123238686612620565b611a936123308987612620565b611a938d61233e8c8b612620565b90612620565b955050505050505b9392505050565b600080805b84548110156123ae57836001600160a01b031685600001828154811061237a57fe5b60009182526020909120600690910201546001600160a01b031614156123a657809150600192506123ae565b600101612358565b509250929050565b60018201546123c590826118fb565b6001830155600290910155565b81546001600160a01b0319166001600160a01b0391909116178155600060018201819055600282018190556003820181905560048201819055600590910155565b81546000906001600160a01b031631818351600181111561243057fe5b14156124cb576020830151600285015460009161244f91906064612251565b9050600082821115612468576124658284611aa4565b90505b600061247387612561565b9050818111156124865760009450612493565b6124908282611aa4565b94505b60006124b48860040154611a99848b60010154611aa490919063ffffffff16565b9050808611156124c2578095505b50505050612500565b6001835160018111156124da57fe5b14156124fa57600384015460018501546124f391611aa4565b9150612500565b60009150fe5b600384015461250f90836118fb565b600385015583546040517f9145b1e2df1630c4e7b11419b36afb9de07a4dc780726dfa970f265b1d627ad791612552916001600160a01b03909116908590612b73565b60405180910390a15092915050565b600061195882600401548360030154611aa490919063ffffffff16565b600482015461258d90826118fb565b82600401819055505050565b60058201546125a890826118fb565b82600501819055505050565b60006119558383612710612251565b600061195860016125d48482612679565b906126df565b6000806125f26125eb8460016118fb565b8590612605565b90506125fd816126ef565b949350505050565b60008183111561261457600080fd5b62015180838303612249565b60008261262f57506000611958565b8282028284828161263c57fe5b04146119555760405162461bcd60e51b8152600401808060200182810382526021815260200180612f126021913960400191505060405180910390fd5b600080808061268c620151808704612732565b91870194509250905060006126a184846127c8565b9050808211156126af578091505b620151808706620151806126c486868661284e565b02019450868510156126d557600080fd5b5050505092915050565b8082038281111561195857600080fd5b6000620100008210610b6a5760405162461bcd60e51b8152600401808060200182810382526026815260200180612ec66026913960400191505060405180910390fd5b60008080836226496581018262023ab1600483020590506004600362023ab18302010590910390600062164b09610fa0600185010205905060046105b58202058303601f019250600061098f846050028161278957fe5b0590506000605061098f83020585039050600b820560301994909401606402929092018301996002600c90940290910392909201975095509350505050565b600081600114806127d95750816003145b806127e45750816005145b806127ef5750816007145b806127fa5750816008145b80612805575081600a145b80612810575081600c145b1561281d5750601f611958565b8160021461282d5750601e611958565b612836836128ca565b61284157601c612844565b601d5b60ff169392505050565b60006107b284101561285f57600080fd5b838383600062253d8c600460036064611324600c600d19890105890101050205600c80600d19870105600c02600287030361016f028161289b57fe5b0560046105b5600c600d1989010589016112c0010205617d4b8603010103039050809450505050509392505050565b6000600482061580156128df57506064820615155b8061195857505061019090061590565b6040805160608101909152806000815260006020820181905260409091015290565b6040518060a0016040528060008152602001600061ffff1681526020016000815260200160008152602001612944612949565b905290565b6040518060a0016040528060608152602001600081526020016000815260200160008152602001600081525090565b600060208284031215612989578081fd5b813561195581612ea3565b600060208083850312156129a6578182fd5b825167ffffffffffffffff808211156129bd578384fd5b818501915085601f8301126129d0578384fd5b8151818111156129dc57fe5b6129e98485830201612dd4565b818152848101908486016040808502870188018b1015612a07578889fd5b8896505b84871015612a615780828c031215612a21578889fd5b80518181018181108882111715612a3457fe5b82528251612a4181612ea3565b815282890151898201528452600196909601959287019290810190612a0b565b50909998505050505050505050565b600080600060608486031215612a84578182fd5b8335612a8f81612ea3565b92506020840135612a9f81612eb8565b929592945050506040919091013590565b600060608284031215612ac1578081fd5b6040516060810181811067ffffffffffffffff82111715612ade57fe5b6040528251612aec81612eb8565b81526020838101519082015260408301518015158114612b0a578283fd5b60408201529392505050565b600060208284031215612b27578081fd5b5035919050565b600060208284031215612b3f578081fd5b5051919050565b60028110612b5057fe5b9052565b6001600160a01b0391909116815260200190565b901515815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6000602080835283518082850152825b81811015612bd257858101830151858201604001528201612bb6565b81811115612be35783604083870101525b50601f01601f1916929092016040019392505050565b6000602080835260c084518285015281850151604061ffff821681870152808701519150606082818801528088015192506080838189015280890151935060a080818a01526101608901855182888c01528181518084526101808d0191508a830193508b92505b80831015612cb257835180516001600160a01b031683528b8101518c84015288810151898401528781015188840152868101518784015285015185830152928a01926001929092019190890190612c60565b509887015160e08c0152505050918301516101008801528201516101208701520151610140909401939093529392505050565b6000606082019050612cf8828451612b46565b6020830151602083015260408301511515604083015292915050565b6000606082019050612d2a8260ff855416612b46565b6001830154602083015260029092015460ff16151560409091015290565b61ffff999099168952602089019790975260408801959095526060870193909352608086019190915260a085015260c084015260e08301526101008201526101200190565b90815260200190565b918252602082015260400190565b968752602087019590955260408601939093526060850191909152608084015260a083015260c082015260e00190565b60405181810167ffffffffffffffff81118282101715612df057fe5b604052919050565b60e01c90565b600060443d1015612e0e5761100b565b600481823e6308c379a0612e228251612df8565b14612e2c5761100b565b6040513d600319016004823e80513d67ffffffffffffffff8160248401118184111715612e5c575050505061100b565b82840192508251915080821115612e76575050505061100b565b503d83016020828401011115612e8e5750505061100b565b601f01601f1916810160200160405291505090565b6001600160a01b038116811461114957600080fd5b6002811061114957600080fdfe53616665436173743a2076616c756520646f65736e27742066697420696e2031362062697473756e6b6e6f776e206572726f722e20676574416e6e75616c50657263656e7461676542697073536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77756e6b6e6f776e206572726f722e20757064617465417574686f72697a6564496e666c6174696f6e416e6443697263756c6174696e67537570706c79a26469706673582212205ef2d4eb27b194681a5c9017928096c24afe2d3fcc7731d5f43f3a46f9e46b2164736f6c63430007060033