Contract Address Details

0xd7b8D88603De93dD9b430ea5f81dC32C117Df250

Contract Name
Distribution
Creator
0x4598a6–d10d29 at 0x70029a–bcbe85
Balance
0 FLR
Tokens
Fetching tokens...
Transactions
4,073 Transactions
Transfers
0 Transfers
Gas Used
7,342,608,495
Last Balance Update
3079121
Contract name:
Distribution




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




Optimization runs
200
Verified at
2022-07-13T21:21:08.882375Z

Constructor Arguments

0000000000000000000000004598a6c05910ab914f0cbaaca1911cd337d10d2900000000000000000000000010000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000064602480

Arg [0] (address) : 0x4598a6c05910ab914f0cbaaca1911cd337d10d29
Arg [1] (address) : 0x1000000000000000000000000000000000000004
Arg [2] (uint256) : 1684022400

              

./contracts/tokenPools/implementation/Distribution.sol

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

import "../../governance/implementation/Governed.sol";
import "@openzeppelin/contracts/utils/SafeCast.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "../../utils/implementation/SafePct.sol";
import "../../userInterfaces/IDistribution.sol";
import "../interface/IITokenPool.sol";

/**
 * @title Distribution
 * @notice A contract to manage the ongoing airdrop distribution after the initial airdrop allocation. 
 * The remaining amount is distributed by this contract, with a set rate every 30 days
 * @notice The balance that will be added to this contract must initially be a part of circulating supply 
 **/
contract Distribution is Governed, ReentrancyGuard, IDistribution, IITokenPool {
    using SafeCast for uint256;
    using SafeMath for uint256;
    using SafePct for uint256;

    // Airdrop Account stuct (for memory)
    struct AirdropAccount {
        uint256 entitlementBalanceWei;            // 100% of entitled airdrop in Wei
        uint256 totalClaimedWei;                  // already claimed Wei
        uint256 optOutBalanceWei;                 // The balance that accounts is opting out (per account)
        uint256 airdroppedAtGenesisWei;           // Amount airdropped (initial airdrop amount)
        // HealthChecks:
        // * entitlementBalanceWei >= totalClaimedWei 
        // * entitlementBalanceWei == totalClaimedWei + optOutBalanceWei if optOutBalanceWei > 0
        // * entitlementBalanceWei == totalClaimedWei at some point in the future
    }

    // constants
    uint256 internal constant MONTH = 30 days;
    uint256 internal constant MAX_ADDRESS_BATCH_SIZE = 1000;
    uint256 internal constant TOTAL_BIPS = 10000;
    uint256 internal constant CLAIMED_AT_GENESIS_BIPS = 1500;
    uint256 internal constant TOTAL_CLAIMABLE_BIPS = 8500;
    uint256 internal constant MONTHLY_CLAIMABLE_BIPS = 237;  // 2.37% every 30 days

    // storage
    uint256 public immutable latestEntitlementStartTs;  // Latest day 0 when contract starts
    mapping(address => AirdropAccount) public airdropAccounts;
    uint256 public totalEntitlementWei;   // Total wei to be distributed by this contract (all but initial airdrop)
    uint256 public totalClaimedWei;       // All wei already claimed
    uint256 public totalOptOutWei;        // The total opt-out Wei of all accounts that opt-out
    uint256 public withdrawnOptOutWei;    // Amount of opt-out Wei that was withdrawn by governance
    uint256 public entitlementStartTs;    // Day 0 when contract starts

    // contracts
    address public immutable treasury;

    // Errors
    string internal constant ERR_ADDRESS_ZERO = "address zero";
    string internal constant ERR_OUT_OF_BALANCE = "balance too low";
    string internal constant ERR_TOO_MANY = "too many";
    string internal constant ERR_NOT_REGISTERED = "not registered";
    string internal constant ERR_NOT_STARTED = "not started";
    string internal constant ERR_FULLY_CLAIMED = "already fully claimed";
    string internal constant ERR_OPT_OUT = "already opted out";
    string internal constant ERR_NO_BALANCE_CLAIMABLE = "no balance currently available";
    string internal constant ERR_ARRAY_MISMATCH = "arrays lengths mismatch";
    string internal constant ERR_ALREADY_STARTED = "already started";
    string internal constant ERR_TREASURY_ONLY = "treasury only";
    string internal constant ERR_IN_THE_PAST = "in the past";
    string internal constant ERR_WRONG_START_TIMESTAMP = "wrong start timestamp";

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

    /**
     * @dev This modifier ensures that the entitelment was already started
     */
    modifier entitlementStarted {
        require (entitlementStartTs != 0 && entitlementStartTs < block.timestamp, ERR_NOT_STARTED);
        _;
    }

    /**
     * @dev Access control to protect methods to allow only minters to call select methods
     *   (like transferring balance out).
     */
    modifier accountCanClaim (address _owner) {
        require(airdropAccounts[_owner].airdroppedAtGenesisWei != 0, ERR_NOT_REGISTERED);
        require(airdropAccounts[_owner].optOutBalanceWei == 0, ERR_OPT_OUT);
        _;
    }

    constructor(
        address _governance,
        address _treasury,
        uint256 _latestEntitlementStartTs
    )
        Governed(_governance)
    {
        require(_treasury != address(0), ERR_ADDRESS_ZERO);
        require(_latestEntitlementStartTs >= block.timestamp, ERR_IN_THE_PAST);
        treasury = _treasury;
        latestEntitlementStartTs = _latestEntitlementStartTs;
    }

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

    /**
     * @notice Method to set addresses and their respective balances in batches to this contract (airdrop)
     * @param toAddress array of adresses we are adding in batch
     * @param balance array of balances to be airdropped to respective accounts (total amount - 100%)
     * @dev Note that toAddress and balance arrays must be equal length
     * @dev Note that script must use the same batches to fill data (if restarted), otherwise duplicates may occure
     */
    function setAirdropBalances(address[] calldata toAddress, uint256[] calldata balance) external onlyGovernance {
        require(toAddress.length <= MAX_ADDRESS_BATCH_SIZE, ERR_TOO_MANY);
        require(toAddress.length == balance.length, ERR_ARRAY_MISMATCH);
        require (entitlementStartTs == 0, ERR_ALREADY_STARTED);

        if (airdropAccounts[toAddress[0]].entitlementBalanceWei > 0) return; // batch already added
        for (uint16 i = 0; i < toAddress.length; i++) {
            // Assume that when the initial 15% was allocated, that any remainder was truncated.
            // Therefore, compute the difference to obtain the remaining entitlement balance.
            uint256 claimedAtGenesis = balance[i].mulDiv(CLAIMED_AT_GENESIS_BIPS, TOTAL_BIPS);
            uint256 entiteledWei = balance[i].sub(claimedAtGenesis);
            airdropAccounts[toAddress[i]] =
                AirdropAccount({
                    entitlementBalanceWei: entiteledWei,
                    totalClaimedWei: 0,
                    optOutBalanceWei: 0,
                    airdroppedAtGenesisWei: claimedAtGenesis
                });
            totalEntitlementWei = totalEntitlementWei.add(entiteledWei);
        }
        // We added the accounts to airdrop, emit event
        emit AccountsAdded(toAddress);
    }

    /** 
     * @notice Start the distribution contract at _entitlementStartTs timestamp
     * @param _entitlementStartTs point in time when we start
     * @dev should be called immediately after all airdrop accounts and balances are set
     */
    function setEntitlementStart(uint256 _entitlementStartTs) external virtual onlyGovernance {
        require(entitlementStartTs == 0 || entitlementStartTs > block.timestamp, ERR_ALREADY_STARTED);
        require(_entitlementStartTs >= block.timestamp && _entitlementStartTs <= latestEntitlementStartTs,
            ERR_WRONG_START_TIMESTAMP);
        require(treasury.balance >= totalEntitlementWei || address(this).balance >= totalEntitlementWei,
            ERR_OUT_OF_BALANCE);
        entitlementStartTs = _entitlementStartTs;
        emit EntitlementStart(_entitlementStartTs);
    }

    /**
     * @notice Method to opt-out of receiving airdrop rewards
     * @dev 
     */
    function optOutOfAirdrop() external override accountCanClaim(msg.sender) entitlementStarted {
        // you can only opt-out for your address
        AirdropAccount storage airdropAccount = airdropAccounts[msg.sender];
        require(airdropAccount.entitlementBalanceWei > airdropAccount.totalClaimedWei, ERR_FULLY_CLAIMED);
        // emit opt-out event
        emit AccountOptOut(msg.sender);
        // set all unclaimed wei to opt-out balance
        airdropAccount.optOutBalanceWei = airdropAccount.entitlementBalanceWei - airdropAccount.totalClaimedWei;
        // Add this accounts opt-out balance to full opt-out balance
        totalOptOutWei = totalOptOutWei.add(airdropAccount.optOutBalanceWei);
    }

    /**
     * @notice Method for claiming unlocked airdrop amounts
     * @return _amountWei claimed wei
     */
    function claim(address payable _recipient) external override 
        entitlementStarted mustBalance nonReentrant accountCanClaim(msg.sender) 
        returns(uint256 _amountWei) 
    {
        // Get the account
        AirdropAccount storage airdropAccount = airdropAccounts[msg.sender];
        // Get the current claimable amount for the account
        _amountWei = _getCurrentClaimableWei(msg.sender);
        // Make sure we are not withdrawing 0 funds
        require(_amountWei > 0, ERR_NO_BALANCE_CLAIMABLE);
        // Update claimed balance
        airdropAccount.totalClaimedWei += _amountWei;
        // Update grand total claimed
        totalClaimedWei = totalClaimedWei.add(_amountWei);
        // Emit the claim event
        emit AccountClaimed(msg.sender);
        // Send
        /* solhint-disable avoid-low-level-calls */
        //slither-disable-next-line arbitrary-send   
        (bool success, ) = _recipient.call{value: _amountWei}("");
        /* solhint-enable avoid-low-level-calls */
        require(success, "error");
    }

    /**
     * @notice Method for withdrawing funds that were opt-out by users. Only accessible form governance address
     * @return _amountWei withdrawn opt-out wei
     * @param _targetAddress an address to withdraw funds to
     */
    function withdrawOptOutWei(address payable _targetAddress) external onlyGovernance entitlementStarted mustBalance 
        returns(uint256 _amountWei) 
    {
        require(totalOptOutWei > 0, ERR_NO_BALANCE_CLAIMABLE);
        require(totalOptOutWei != withdrawnOptOutWei, ERR_NO_BALANCE_CLAIMABLE);
        // Update opt-out balance
        _amountWei = totalOptOutWei.sub(withdrawnOptOutWei);
        withdrawnOptOutWei = totalOptOutWei;
        // emit the event
        emit OptOutWeiWithdrawn();
        // Send Wei to address
        _targetAddress.transfer(_amountWei);
    }

    function getTokenPoolSupplyData() external override view 
        returns (uint256 _lockedFundsWei, uint256 _totalInflationAuthorizedWei, uint256 _totalClaimedWei)
    {
        // This is the total amount of tokens that are actually already in circulating supply
        _lockedFundsWei = totalEntitlementWei;
        // We will never increase this balance since distribution funds are taken from genesis 
        /// amounts and not from inflation.
        _totalInflationAuthorizedWei = 0;
        // What was actually already added to circulating supply
        _totalClaimedWei = totalClaimedWei + withdrawnOptOutWei;
    }

    /**
     * @notice current claimable amount of wei for requesting account
     * @return _amountWei amount of wei available for this account at current time
     */
    function getClaimableAmount() external view override entitlementStarted 
        returns(uint256 _amountWei) 
    {
        _amountWei = _getCurrentClaimableWei(msg.sender);
    }

    /**
     * @notice current claimable amount of wei for account
     * @param account the address of an account we want to get the available wei
     * @return _amountWei amount of wei available for provided account at current time
     */
    function getClaimableAmountOf(address account) external view override entitlementStarted 
        returns(uint256 _amountWei) 
    {
        _amountWei = _getCurrentClaimableWei(account);
    }

    /**
     * @notice Time till next Wei will be claimable (in secods)
     * @return timeTill (sec) Time till next claimable Wei in seconds
     */
    function secondsTillNextClaim() external view override entitlementStarted 
        returns(uint256 timeTill) 
    {
        timeTill = _timeTillNextClaim(msg.sender);
    }

    /**
     * @notice Get the claimable percent for the current timestamp
     * @dev Every 30 days from initial day 2.37% of the total amount is unlocked and becomes available for claiming
     * @return percentBips maximal claimable bips at given time
     */
    function _getCurrentClaimablePercent() internal view entitlementStarted 
        returns(uint256 percentBips)
    {
        uint256 diffDays = block.timestamp.sub(entitlementStartTs).div(1 days);
        percentBips = Math.min(diffDays.div(30).mul(MONTHLY_CLAIMABLE_BIPS),TOTAL_CLAIMABLE_BIPS);
    }

    /**
     * @notice Get current claimable amount for users account
     * @dev Every 30 days from initial day 2.37% of the reward is released
     */
    function _getCurrentClaimableWei(address _owner) internal view entitlementStarted accountCanClaim(_owner) 
        returns(uint256 claimableWei)
    {
        // Attempt to get the account in question
        AirdropAccount memory airdropAccount = airdropAccounts[_owner];
        uint256 currentMaxClaimableBips = _getCurrentClaimablePercent();
        uint256 tempCla=airdropAccount.entitlementBalanceWei.mulDiv(currentMaxClaimableBips,TOTAL_CLAIMABLE_BIPS);
        // Can never claime more that we are initially entiteled to
        tempCla = Math.min(tempCla, airdropAccount.entitlementBalanceWei).toUint128();
        // Substract already claimed
        claimableWei = tempCla - airdropAccount.totalClaimedWei; 
    }

    /**
     * @notice Calculate the time till nex entitelment Wei is released  
     */
    function _timeTillNextClaim(address _account) internal view entitlementStarted accountCanClaim(_account) 
        returns(uint256 timeTill) 
    {
        // Get the account we want to check
        require(block.timestamp.sub(entitlementStartTs).div(MONTH) < 36, ERR_FULLY_CLAIMED);
        timeTill = MONTH.sub(block.timestamp.sub(entitlementStartTs).mod(MONTH));
    }

    /**
     * @notice Compute the expected balance of this contract.
     * @param _balanceExpectedWei   The computed balance expected.
     */
    function _getExpectedBalance() private view returns(uint256 _balanceExpectedWei) {
        return totalEntitlementWei.sub(totalClaimedWei).sub(withdrawnOptOutWei);
    }
}
        

./contracts/governance/implementation/Governed.sol

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

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


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

./contracts/governance/implementation/GovernedBase.sol

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

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


/**
 * @title Governed Base
 * @notice This abstract base class defines behaviors for a governed contract.
 * @dev This class is abstract so that specific behaviors can be defined for the constructor.
 *   Contracts should not be left ungoverned, but not all contract will have a constructor
 *   (for example those pre-defined in genesis).
 **/
abstract contract GovernedBase {
    struct TimelockedCall {
        uint256 allowedAfterTimestamp;
        bytes encodedCall;
    }
    
    // solhint-disable-next-line const-name-snakecase
    IGovernanceSettings public constant governanceSettings = 
        IGovernanceSettings(0x1000000000000000000000000000000000000007);

    address private initialGovernance;

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

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

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

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

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

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

./contracts/tokenPools/interface/IITokenPool.sol

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

interface IITokenPool {

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

./contracts/userInterfaces/IDistribution.sol

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

interface IDistribution {
    // Events
    event EntitlementStart(uint256 entitlementStartTs);
    event AccountClaimed(address indexed theAccount);
    event AccountOptOut(address indexed theAccount);
    event OptOutWeiWithdrawn();
    event AccountsAdded(address[] accountsArray);

    // Methods
    function claim(address payable _recipient) external returns(uint256 _amountWei);
    function optOutOfAirdrop() external;
    function getClaimableAmount() external view returns(uint256 _amountWei);
    function getClaimableAmountOf(address account) external view returns(uint256 _amountWei);
    function secondsTillNextClaim() external view returns(uint256 timetill);
}
          

./contracts/userInterfaces/IGovernanceSettings.sol

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


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

./contracts/utils/implementation/SafePct.sol

// SPDX-License-Identifier: MIT

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

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

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

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

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

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

@openzeppelin/contracts/math/Math.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

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

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

@openzeppelin/contracts/math/SafeMath.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

@openzeppelin/contracts/utils/ReentrancyGuard.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor () internal {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}
          

@openzeppelin/contracts/utils/SafeCast.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;


/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafeCast {

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

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

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

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

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

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

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

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

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

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

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

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

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_governance","internalType":"address"},{"type":"address","name":"_treasury","internalType":"address"},{"type":"uint256","name":"_latestEntitlementStartTs","internalType":"uint256"}]},{"type":"event","name":"AccountClaimed","inputs":[{"type":"address","name":"theAccount","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"AccountOptOut","inputs":[{"type":"address","name":"theAccount","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"AccountsAdded","inputs":[{"type":"address[]","name":"accountsArray","internalType":"address[]","indexed":false}],"anonymous":false},{"type":"event","name":"EntitlementStart","inputs":[{"type":"uint256","name":"entitlementStartTs","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"GovernanceCallTimelocked","inputs":[{"type":"bytes4","name":"selector","internalType":"bytes4","indexed":false},{"type":"uint256","name":"allowedAfterTimestamp","internalType":"uint256","indexed":false},{"type":"bytes","name":"encodedCall","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"event","name":"GovernanceInitialised","inputs":[{"type":"address","name":"initialGovernance","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"GovernedProductionModeEntered","inputs":[{"type":"address","name":"governanceSettings","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"OptOutWeiWithdrawn","inputs":[],"anonymous":false},{"type":"event","name":"TimelockedGovernanceCallCanceled","inputs":[{"type":"bytes4","name":"selector","internalType":"bytes4","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"TimelockedGovernanceCallExecuted","inputs":[{"type":"bytes4","name":"selector","internalType":"bytes4","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"entitlementBalanceWei","internalType":"uint256"},{"type":"uint256","name":"totalClaimedWei","internalType":"uint256"},{"type":"uint256","name":"optOutBalanceWei","internalType":"uint256"},{"type":"uint256","name":"airdroppedAtGenesisWei","internalType":"uint256"}],"name":"airdropAccounts","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelGovernanceCall","inputs":[{"type":"bytes4","name":"_selector","internalType":"bytes4"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"_amountWei","internalType":"uint256"}],"name":"claim","inputs":[{"type":"address","name":"_recipient","internalType":"address payable"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"entitlementStartTs","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeGovernanceCall","inputs":[{"type":"bytes4","name":"_selector","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_amountWei","internalType":"uint256"}],"name":"getClaimableAmount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_amountWei","internalType":"uint256"}],"name":"getClaimableAmountOf","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_lockedFundsWei","internalType":"uint256"},{"type":"uint256","name":"_totalInflationAuthorizedWei","internalType":"uint256"},{"type":"uint256","name":"_totalClaimedWei","internalType":"uint256"}],"name":"getTokenPoolSupplyData","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"governance","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IGovernanceSettings"}],"name":"governanceSettings","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialise","inputs":[{"type":"address","name":"_initialGovernance","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"latestEntitlementStartTs","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"optOutOfAirdrop","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"productionMode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"timeTill","internalType":"uint256"}],"name":"secondsTillNextClaim","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setAirdropBalances","inputs":[{"type":"address[]","name":"toAddress","internalType":"address[]"},{"type":"uint256[]","name":"balance","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setEntitlementStart","inputs":[{"type":"uint256","name":"_entitlementStartTs","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"switchToProductionMode","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"allowedAfterTimestamp","internalType":"uint256"},{"type":"bytes","name":"encodedCall","internalType":"bytes"}],"name":"timelockedCalls","inputs":[{"type":"bytes4","name":"","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalClaimedWei","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalEntitlementWei","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalOptOutWei","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"treasury","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"_amountWei","internalType":"uint256"}],"name":"withdrawOptOutWei","inputs":[{"type":"address","name":"_targetAddress","internalType":"address payable"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"withdrawnOptOutWei","inputs":[]},{"type":"receive","stateMutability":"payable"}]
            

Deployed ByteCode

0x6080604052600436106101695760003560e01c806374e6310e116100d1578063c354bd6e1161008a578063e60eb6ff11610064578063e60eb6ff146106d0578063f2325e38146106e5578063f2a1f767146106fa578063f5a983831461070f57610249565b8063c354bd6e14610668578063e17f212e1461067d578063e28ef1f7146106a657610249565b806374e6310e146104f25780637fd45d2b146105a55780639d6a890f146105d85780639f71043e1461060b578063ae67716114610620578063b5551ab71461063557610249565b80635aa6e675116101235780635aa6e6751461035e5780635ff270791461038f57806361235585146103c557806361d027b31461049457806362354e03146104a957806367fc4029146104be57610249565b80626a1d511461024e5780631e83409a146102755780632dafdbbf146102a857806344a8ace2146102db57806344d94b4b146103345780634bb5696a1461034957610249565b366102495760408051808201909152600d81526c7472656173757279206f6e6c7960981b6020820152336001600160a01b037f000000000000000000000000100000000000000000000000000000000000000416146102465760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561020b5781810151838201526020016101f3565b50505050905090810190601f1680156102385780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50005b600080fd5b34801561025a57600080fd5b50610263610724565b60408051918252519081900360200190f35b34801561028157600080fd5b506102636004803603602081101561029857600080fd5b50356001600160a01b031661072a565b3480156102b457600080fd5b506102bd610b2b565b60408051938452602084019290925282820152519081900360600190f35b3480156102e757600080fd5b5061030e600480360360208110156102fe57600080fd5b50356001600160a01b0316610b3f565b604080519485526020850193909352838301919091526060830152519081900360800190f35b34801561034057600080fd5b50610263610b68565b34801561035557600080fd5b50610263610b6e565b34801561036a57600080fd5b50610373610c03565b604080516001600160a01b039092168252519081900360200190f35b34801561039b57600080fd5b506103c3600480360360208110156103b257600080fd5b50356001600160e01b031916610c97565b005b3480156103d157600080fd5b506103c3600480360360408110156103e857600080fd5b81019060208101813564010000000081111561040357600080fd5b82018360208201111561041557600080fd5b8035906020019184602083028401116401000000008311171561043757600080fd5b91939092909160208101903564010000000081111561045557600080fd5b82018360208201111561046757600080fd5b8035906020019184602083028401116401000000008311171561048957600080fd5b509092509050610fec565b3480156104a057600080fd5b50610373611353565b3480156104b557600080fd5b50610373611377565b3480156104ca57600080fd5b506103c3600480360360208110156104e157600080fd5b50356001600160e01b031916611382565b3480156104fe57600080fd5b506105266004803603602081101561051557600080fd5b50356001600160e01b03191661146a565b6040518083815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610569578181015183820152602001610551565b50505050905090810190601f1680156105965780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b3480156105b157600080fd5b50610263600480360360208110156105c857600080fd5b50356001600160a01b0316611510565b3480156105e457600080fd5b506103c3600480360360208110156105fb57600080fd5b50356001600160a01b03166115a6565b34801561061757600080fd5b5061026361165f565b34801561062c57600080fd5b50610263611665565b34801561064157600080fd5b506102636004803603602081101561065857600080fd5b50356001600160a01b0316611689565b34801561067457600080fd5b5061026361195d565b34801561068957600080fd5b506106926119ed565b604080519115158252519081900360200190f35b3480156106b257600080fd5b506103c3600480360360208110156106c957600080fd5b50356119fd565b3480156106dc57600080fd5b50610263611c59565b3480156106f157600080fd5b50610263611c5f565b34801561070657600080fd5b506103c3611c65565b34801561071b57600080fd5b506103c3611ee8565b60075481565b6000600854600014158015610740575042600854105b6040518060400160405280600b81526020016a1b9bdd081cdd185c9d195960aa1b815250906107b05760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b50600280541415610808576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002805533600081815260036020818152604092839020909101548251808401909352600e83526d1b9bdd081c9959da5cdd195c995960921b918301919091526108935760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b506001600160a01b0381166000908152600360209081526040918290206002015482518084019093526011835270185b1c9958591e481bdc1d1959081bdd5d607a1b91830191909152156109285760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b503360008181526003602052604090209061094290611fa2565b9250600083116040518060400160405280601e81526020017f6e6f2062616c616e63652063757272656e746c7920617661696c61626c650000815250906109ca5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b50600181018054840190556005546109e29084612204565b60055560405133907f98220ba7e456cda59b84320240d405cb87d7d871ba13f798d6362297818d29fc90600090a26040516000906001600160a01b0386169085908381818185875af1925050503d8060008114610a5b576040519150601f19603f3d011682016040523d82523d6000602084013e610a60565b606091505b5050905080610a9e576040805162461bcd60e51b815260206004820152600560248201526432b93937b960d91b604482015290519081900360640190fd5b505060016002555047610aaf612265565b11156040518060400160405280600f81526020016e62616c616e636520746f6f206c6f7760881b81525090610b255760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b50919050565b600454600754600554919260009290910190565b600360208190526000918252604090912080546001820154600283015492909301549092919084565b60065481565b6000600854600014158015610b84575042600854105b6040518060400160405280600b81526020016a1b9bdd081cdd185c9d195960aa1b81525090610bf45760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b50610bfe3361228a565b905090565b60008054600160a81b900460ff16610c26576000546001600160a01b0316610bfe565b60076001609c1b016001600160a01b031663732524946040518163ffffffff1660e01b815260040160206040518083038186803b158015610c6657600080fd5b505afa158015610c7a573d6000803e3d6000fd5b505050506040513d6020811015610c9057600080fd5b5051905090565b60408051630debfda360e41b8152336004820152905160076001609c1b019163debfda30916024808301926020929190829003018186803b158015610cdb57600080fd5b505afa158015610cef573d6000803e3d6000fd5b505050506040513d6020811015610d0557600080fd5b5051610d48576040805162461bcd60e51b815260206004820152600d60248201526c37b7363c9032bc32b1baba37b960991b604482015290519081900360640190fd5b6001600160e01b0319811660009081526001602052604090208054610db4576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b8054421015610e0a576040805162461bcd60e51b815260206004820152601960248201527f74696d656c6f636b3a206e6f7420616c6c6f7765642079657400000000000000604482015290519081900360640190fd5b6000816001018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610ea45780601f10610e7957610100808354040283529160200191610ea4565b820191906000526020600020905b815481529060010190602001808311610e8757829003601f168201915b5050506001600160e01b0319861660009081526001602081905260408220828155949550909250610ed89150830182612afd565b50506000805460ff60b01b1916600160b01b178155604051825130918491819060208401908083835b60208310610f205780518252601f199092019160209182019101610f01565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114610f82576040519150601f19603f3d011682016040523d82523d6000602084013e610f87565b606091505b50506000805460ff60b01b19169055604080516001600160e01b03198716815242602082015281519293507fa7326b57fc9cfe267aaea5e7f0b01757154d265620a0585819416ee9ddd2c438929081900390910190a1610fe681612517565b50505050565b600054600160b01b900460ff168061100e5750600054600160a81b900460ff16155b156113485761101b612534565b604080518082019091526008815267746f6f206d616e7960c01b60208201526103e884111561108b5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b5060408051808201909152601781527f617272617973206c656e67746873206d69736d61746368000000000000000000602082015283821461110e5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b5060085460408051808201909152600f81526e185b1c9958591e481cdd185c9d1959608a1b602082015290156111855760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b506000600360008686600081811061119957fe5b905060200201356001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000015411156111d857611343565b60005b61ffff81168411156112de5760006112186105dc61271086868661ffff1681811061120257fe5b9050602002013561256b9092919063ffffffff16565b905060006112458286868661ffff1681811061123057fe5b9050602002013561267190919063ffffffff16565b905060405180608001604052808281526020016000815260200160008152602001838152506003600089898761ffff1681811061127e57fe5b602090810292909201356001600160a01b03168352508181019290925260409081016000208351815591830151600183015582015160028201556060909101516003909101556004546112d19082612204565b60045550506001016111db565b507fc21490756c6f0185a8ad2363084fd0a45b06707979f77786b5e681bddc1d2fa1848460405180806020018281038252848482818152602001925060200280828437600083820152604051601f909101601f19169092018290039550909350505050a15b610fe6565b610fe66000366126ce565b7f000000000000000000000000100000000000000000000000000000000000000481565b60076001609c1b0181565b61138a612851565b6001600160e01b031981166000908152600160205260409020546113f5576040805162461bcd60e51b815260206004820152601a60248201527f74696d656c6f636b3a20696e76616c69642073656c6563746f72000000000000604482015290519081900360640190fd5b604080516001600160e01b03198316815242602082015281517f7735b2391c38a81419c513e30ca578db7158eadd7101511b23e221c654d19cf8929181900390910190a16001600160e01b0319811660009081526001602081905260408220828155919061146590830182612afd565b505050565b600160208181526000928352604092839020805481840180548651600296821615610100026000190190911695909504601f810185900485028601850190965285855290949193929091908301828280156115065780601f106114db57610100808354040283529160200191611506565b820191906000526020600020905b8154815290600101906020018083116114e957829003601f168201915b5050505050905082565b6000600854600014158015611526575042600854105b6040518060400160405280600b81526020016a1b9bdd081cdd185c9d195960aa1b815250906115965760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b506115a082611fa2565b92915050565b600054600160a01b900460ff16156115fc576040805162461bcd60e51b8152602060048201526014602482015273696e697469616c6973656420213d2066616c736560601b604482015290519081900360640190fd5b60008054600160a01b60ff60a01b19909116176001600160a01b0319166001600160a01b03831690811790915560408051918252517f9789733827840833afc031fb2ef9ab6894271f77bad2085687cf4ae5c7bee4db916020908290030190a150565b60055481565b7f000000000000000000000000000000000000000000000000000000006460248081565b60008054600160b01b900460ff16806116ac5750600054600160a81b900460ff16155b1561194d576116b9612534565b600854158015906116cb575042600854105b6040518060400160405280600b81526020016a1b9bdd081cdd185c9d195960aa1b8152509061173b5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b506000600654116040518060400160405280601e81526020017f6e6f2062616c616e63652063757272656e746c7920617661696c61626c650000815250906117c45760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b5060075460065414156040518060400160405280601e81526020017f6e6f2062616c616e63652063757272656e746c7920617661696c61626c6500008152509061184f5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b5060075460065461185f91612671565b6006546007556040519091507f79d406fa3c1c020905a48c371f891e33f8210c0e4ab4d5221dc01f531f7342db90600090a16040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156118c7573d6000803e3d6000fd5b50476118d1612265565b11156040518060400160405280600f81526020016e62616c616e636520746f6f206c6f7760881b815250906119475760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b50611958565b6119586000366126ce565b919050565b6000600854600014158015611973575042600854105b6040518060400160405280600b81526020016a1b9bdd081cdd185c9d195960aa1b815250906119e35760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b50610bfe33611fa2565b600054600160a81b900460ff1681565b600054600160b01b900460ff1680611a1f5750600054600160a81b900460ff16155b15611c4b57611a2c612534565b6008541580611a3c575042600854115b6040518060400160405280600f81526020016e185b1c9958591e481cdd185c9d1959608a1b81525090611ab05760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b50428110158015611ae157507f00000000000000000000000000000000000000000000000000000000646024808111155b60405180604001604052806015815260200174077726f6e672073746172742074696d657374616d7605c1b81525090611b5b5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b506004547f00000000000000000000000010000000000000000000000000000000000000046001600160a01b031631101580611b9957506004544710155b6040518060400160405280600f81526020016e62616c616e636520746f6f206c6f7760881b81525090611c0d5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b5060088190556040805182815290517f6887b4fbe6e282072c586eed840058a3507439898b1521541253e5a78a41c69b9181900360200190a1611c56565b611c566000366126ce565b50565b60085481565b60045481565b33600081815260036020818152604092839020909101548251808401909352600e83526d1b9bdd081c9959da5cdd195c995960921b91830191909152611cec5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b506001600160a01b0381166000908152600360209081526040918290206002015482518084019093526011835270185b1c9958591e481bdc1d1959081bdd5d607a1b9183019190915215611d815760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b5060085415801590611d94575042600854105b6040518060400160405280600b81526020016a1b9bdd081cdd185c9d195960aa1b81525090611e045760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b50336000908152600360209081526040918290206001810154815484518086019095526015855274185b1c9958591e48199d5b1b1e4818db185a5b5959605a1b9385019390935290929111611e9a5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b5060405133907fdaa99ea0f252dcde78c690a59f1d9953dcca69dc3127eff6f919fc8b16ed873090600090a2600181015481540360028201819055600654611ee191612204565b6006555050565b611ef0612851565b600054600160a81b900460ff1615611f4f576040805162461bcd60e51b815260206004820152601a60248201527f616c726561647920696e2070726f64756374696f6e206d6f6465000000000000604482015290519081900360640190fd5b60008054600161ff0160a01b031916600160a81b1790556040805160076001609c1b01815290517f83af113638b5422f9e977cebc0aaf0eaf2188eb9a8baae7f9d46c42b33a1560c9181900360200190a1565b6000600854600014158015611fb8575042600854105b6040518060400160405280600b81526020016a1b9bdd081cdd185c9d195960aa1b815250906120285760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b508160036000826001600160a01b03166001600160a01b0316815260200190815260200160002060030154600014156040518060400160405280600e81526020016d1b9bdd081c9959da5cdd195c995960921b815250906120ca5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b506001600160a01b0381166000908152600360209081526040918290206002015482518084019093526011835270185b1c9958591e481bdc1d1959081bdd5d607a1b918301919091521561215f5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b506001600160a01b0383166000908152600360208181526040808420815160808101835281548152600182015493810193909352600281015491830191909152909101546060820152906121b16128b0565b82519091506000906121c6908361213461256b565b90506121de6121d9828560000151612978565b61298e565b6fffffffffffffffffffffffffffffffff16905082602001518103945050505050919050565b60008282018381101561225e576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6000610bfe60075461228460055460045461267190919063ffffffff16565b90612671565b60006008546000141580156122a0575042600854105b6040518060400160405280600b81526020016a1b9bdd081cdd185c9d195960aa1b815250906123105760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b508160036000826001600160a01b03166001600160a01b0316815260200190815260200160002060030154600014156040518060400160405280600e81526020016d1b9bdd081c9959da5cdd195c995960921b815250906123b25760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b506001600160a01b0381166000908152600360209081526040918290206002015482518084019093526011835270185b1c9958591e481bdc1d1959081bdd5d607a1b91830191909152156124475760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b50602461246c62278d006124666008544261267190919063ffffffff16565b906129d6565b1060405180604001604052806015815260200174185b1c9958591e48199d5b1b1e4818db185a5b5959605a1b815250906124e75760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b5061225e61250d62278d006125076008544261267190919063ffffffff16565b90612a3d565b62278d0090612671565b3d604051818101604052816000823e8215612530578181f35b8181fd5b600054600160b01b900460ff16156125615733301461254f57fe5b6000805460ff60b01b19169055612569565b612569612851565b565b60008082116125b4576040805162461bcd60e51b815260206004820152601060248201526f4469766973696f6e206279207a65726f60801b604482015290519081900360640190fd5b836125c15750600061225e565b838302838582816125ce57fe5b0414156125e7578281816125de57fe5b0491505061225e565b60008386816125f257fe5b049050600084878161260057fe5b069050600085878161260e57fe5b049050600086888161261c57fe5b069050612664612630886124668685612aa4565b61265e61263d8686612aa4565b61265e61264a8987612aa4565b61265e8d6126588c8b612aa4565b90612aa4565b90612204565b9998505050505050505050565b6000828211156126c8576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6126d6612851565b600082359050600060076001609c1b016001600160a01b0316636221a54b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561271e57600080fd5b505afa158015612732573d6000803e3d6000fd5b505050506040513d602081101561274857600080fd5b505160408051808201825242830180825282516020601f89018190048102820181019094528781529394509290918281019190889088908190840183828082843760009201829052509390945250506001600160e01b031986168152600160208181526040909220845181558483015180519194506127cc93928501920190612b41565b509050507fed948300a3694aa01d4a6b258bfd664350193d770c0b51f8387277f6d83ea3b68382878760405180856001600160e01b0319168152602001848152602001806020018281038252848482818152602001925080828437600083820152604051601f909101601f191690920182900397509095505050505050a15050505050565b612859610c03565b6001600160a01b0316336001600160a01b031614612569576040805162461bcd60e51b815260206004820152600f60248201526e6f6e6c7920676f7665726e616e636560881b604482015290519081900360640190fd5b60006008546000141580156128c6575042600854105b6040518060400160405280600b81526020016a1b9bdd081cdd185c9d195960aa1b815250906129365760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561020b5781810151838201526020016101f3565b506000612955620151806124666008544261267190919063ffffffff16565b905061297261296a60ed61265884601e6129d6565b612134612978565b91505090565b6000818310612987578161225e565b5090919050565b6000600160801b82106129d25760405162461bcd60e51b8152600401808060200182810382526027815260200180612bdb6027913960400191505060405180910390fd5b5090565b6000808211612a2c576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b818381612a3557fe5b049392505050565b6000808211612a93576040805162461bcd60e51b815260206004820152601860248201527f536166654d6174683a206d6f64756c6f206279207a65726f0000000000000000604482015290519081900360640190fd5b818381612a9c57fe5b069392505050565b600082612ab3575060006115a0565b82820282848281612ac057fe5b041461225e5760405162461bcd60e51b8152600401808060200182810382526021815260200180612c026021913960400191505060405180910390fd5b50805460018160011615610100020316600290046000825580601f10612b235750611c56565b601f016020900490600052602060002090810190611c569190612bc5565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282612b775760008555612bbd565b82601f10612b9057805160ff1916838001178555612bbd565b82800160010185558215612bbd579182015b82811115612bbd578251825591602001919060010190612ba2565b506129d29291505b5b808211156129d25760008155600101612bc656fe53616665436173743a2076616c756520646f65736e27742066697420696e203132382062697473536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a264697066735822122022cd343cbe905a8cc180ebbb51b7ae7ba4f794c1f940ad102ebd0933521bf79964736f6c63430007060033