ETH Price: $2,416.21 (+0.45%)

Contract

0x6D2b24947680FCE35D5C9dD6a4E32649f12C176C
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x60806040114467752020-12-13 20:18:101392 days ago1607890690IN
 Create: Curation
0 ETH0.1845487860

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Curation

Compiler Version
v0.7.4+commit.3f05b770

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 20 : Curation.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.3;

import "@openzeppelin/contracts/math/SafeMath.sol";

import "../bancor/BancorFormula.sol";
import "../upgrades/GraphUpgradeable.sol";

import "./CurationStorage.sol";
import "./ICuration.sol";
import "./GraphCurationToken.sol";

/**
 * @title Curation contract
 * @dev Allows curators to signal on subgraph deployments that might be relevant to indexers by
 * staking Graph Tokens (GRT). Additionally, curators earn fees from the Query Market related to the
 * subgraph deployment they curate.
 * A curators deposit goes to a curation pool along with the deposits of other curators,
 * only one such pool exists for each subgraph deployment.
 * The contract mints Graph Curation Shares (GCS) according to a bonding curve for each individual
 * curation pool where GRT is deposited.
 * Holders can burn GCS using this contract to get GRT tokens back according to the
 * bonding curve.
 */
contract Curation is CurationV1Storage, GraphUpgradeable, ICuration {
    using SafeMath for uint256;

    // 100% in parts per million
    uint32 private constant MAX_PPM = 1000000;

    // Amount of signal you get with your minimum token deposit
    uint256 private constant SIGNAL_PER_MINIMUM_DEPOSIT = 1e18; // 1 signal as 18 decimal number

    // -- Events --

    /**
     * @dev Emitted when `curator` deposited `tokens` on `subgraphDeploymentID` as curation signal.
     * The `curator` receives `signal` amount according to the curation pool bonding curve.
     * An amount of `curationTax` will be collected and burned.
     */
    event Signalled(
        address indexed curator,
        bytes32 indexed subgraphDeploymentID,
        uint256 tokens,
        uint256 signal,
        uint256 curationTax
    );

    /**
     * @dev Emitted when `curator` burned `signal` for a `subgraphDeploymentID`.
     * The curator will receive `tokens` according to the value of the bonding curve.
     */
    event Burned(
        address indexed curator,
        bytes32 indexed subgraphDeploymentID,
        uint256 tokens,
        uint256 signal
    );

    /**
     * @dev Emitted when `tokens` amount were collected for `subgraphDeploymentID` as part of fees
     * distributed by an indexer from query fees received from state channels.
     */
    event Collected(bytes32 indexed subgraphDeploymentID, uint256 tokens);

    /**
     * @dev Initialize this contract.
     */
    function initialize(
        address _controller,
        address _bondingCurve,
        uint32 _defaultReserveRatio,
        uint32 _curationTaxPercentage,
        uint256 _minimumCurationDeposit
    ) external onlyImpl {
        Managed._initialize(_controller);

        require(_bondingCurve != address(0), "Bonding curve must be set");
        bondingCurve = _bondingCurve;

        // Settings
        _setDefaultReserveRatio(_defaultReserveRatio);
        _setCurationTaxPercentage(_curationTaxPercentage);
        _setMinimumCurationDeposit(_minimumCurationDeposit);
    }

    /**
     * @dev Set the default reserve ratio percentage for a curation pool.
     * @notice Update the default reserver ratio to `_defaultReserveRatio`
     * @param _defaultReserveRatio Reserve ratio (in PPM)
     */
    function setDefaultReserveRatio(uint32 _defaultReserveRatio) external override onlyGovernor {
        _setDefaultReserveRatio(_defaultReserveRatio);
    }

    /**
     * @dev Internal: Set the default reserve ratio percentage for a curation pool.
     * @notice Update the default reserver ratio to `_defaultReserveRatio`
     * @param _defaultReserveRatio Reserve ratio (in PPM)
     */
    function _setDefaultReserveRatio(uint32 _defaultReserveRatio) private {
        // Reserve Ratio must be within 0% to 100% (inclusive, in PPM)
        require(_defaultReserveRatio > 0, "Default reserve ratio must be > 0");
        require(
            _defaultReserveRatio <= MAX_PPM,
            "Default reserve ratio cannot be higher than MAX_PPM"
        );

        defaultReserveRatio = _defaultReserveRatio;
        emit ParameterUpdated("defaultReserveRatio");
    }

    /**
     * @dev Set the minimum deposit amount for curators.
     * @notice Update the minimum deposit amount to `_minimumCurationDeposit`
     * @param _minimumCurationDeposit Minimum amount of tokens required deposit
     */
    function setMinimumCurationDeposit(uint256 _minimumCurationDeposit)
        external
        override
        onlyGovernor
    {
        _setMinimumCurationDeposit(_minimumCurationDeposit);
    }

    /**
     * @dev Internal: Set the minimum deposit amount for curators.
     * @notice Update the minimum deposit amount to `_minimumCurationDeposit`
     * @param _minimumCurationDeposit Minimum amount of tokens required deposit
     */
    function _setMinimumCurationDeposit(uint256 _minimumCurationDeposit) private {
        require(_minimumCurationDeposit > 0, "Minimum curation deposit cannot be 0");

        minimumCurationDeposit = _minimumCurationDeposit;
        emit ParameterUpdated("minimumCurationDeposit");
    }

    /**
     * @dev Set the curation tax percentage to charge when a curator deposits GRT tokens.
     * @param _percentage Curation tax percentage charged when depositing GRT tokens
     */
    function setCurationTaxPercentage(uint32 _percentage) external override onlyGovernor {
        _setCurationTaxPercentage(_percentage);
    }

    /**
     * @dev Internal: Set the curation tax percentage to charge when a curator deposits GRT tokens.
     * @param _percentage Curation tax percentage charged when depositing GRT tokens
     */
    function _setCurationTaxPercentage(uint32 _percentage) private {
        require(
            _percentage <= MAX_PPM,
            "Curation tax percentage must be below or equal to MAX_PPM"
        );

        _curationTaxPercentage = _percentage;
        emit ParameterUpdated("curationTaxPercentage");
    }

    /**
     * @dev Assign Graph Tokens collected as curation fees to the curation pool reserve.
     * This function can only be called by the Staking contract and will do the bookeeping of
     * transferred tokens into this contract.
     * @param _subgraphDeploymentID SubgraphDeployment where funds should be allocated as reserves
     * @param _tokens Amount of Graph Tokens to add to reserves
     */
    function collect(bytes32 _subgraphDeploymentID, uint256 _tokens) external override {
        // Only Staking contract is authorized as caller
        require(msg.sender == address(staking()), "Caller must be the staking contract");

        // Must be curated to accept tokens
        require(
            isCurated(_subgraphDeploymentID),
            "Subgraph deployment must be curated to collect fees"
        );

        // Collect new funds into reserve
        CurationPool storage curationPool = pools[_subgraphDeploymentID];
        curationPool.tokens = curationPool.tokens.add(_tokens);

        emit Collected(_subgraphDeploymentID, _tokens);
    }

    /**
     * @dev Deposit Graph Tokens in exchange for signal of a SubgraphDeployment curation pool.
     * @param _subgraphDeploymentID Subgraph deployment pool from where to mint signal
     * @param _tokensIn Amount of Graph Tokens to deposit
     * @param _signalOutMin Expected minimum amount of signal to receive
     * @return Signal minted and deposit tax
     */
    function mint(
        bytes32 _subgraphDeploymentID,
        uint256 _tokensIn,
        uint256 _signalOutMin
    ) external override notPartialPaused returns (uint256, uint256) {
        // Need to deposit some funds
        require(_tokensIn > 0, "Cannot deposit zero tokens");

        // Exchange GRT tokens for GCS of the subgraph pool
        (uint256 signalOut, uint256 curationTax) = tokensToSignal(_subgraphDeploymentID, _tokensIn);

        // Slippage protection
        require(signalOut >= _signalOutMin, "Slippage protection");

        address curator = msg.sender;
        CurationPool storage curationPool = pools[_subgraphDeploymentID];

        // If it hasn't been curated before then initialize the curve
        if (!isCurated(_subgraphDeploymentID)) {
            // Initialize
            curationPool.reserveRatio = defaultReserveRatio;

            // If no signal token for the pool - create one
            if (address(curationPool.gcs) == address(0)) {
                // TODO: Use a minimal proxy to reduce gas cost
                // https://github.com/graphprotocol/contracts/issues/405
                // --abarmat-- 20201113
                curationPool.gcs = IGraphCurationToken(
                    address(new GraphCurationToken(address(this)))
                );
            }
        }

        // Trigger update rewards calculation snapshot
        _updateRewards(_subgraphDeploymentID);

        // Transfer tokens from the curator to this contract
        // This needs to happen after _updateRewards snapshot as that function
        // is using balanceOf(curation)
        IGraphToken graphToken = graphToken();
        require(
            graphToken.transferFrom(curator, address(this), _tokensIn),
            "Cannot transfer tokens to deposit"
        );

        // Burn withdrawal fees
        if (curationTax > 0) {
            graphToken.burn(curationTax);
        }

        // Update curation pool
        curationPool.tokens = curationPool.tokens.add(_tokensIn.sub(curationTax));
        curationPool.gcs.mint(curator, signalOut);

        emit Signalled(curator, _subgraphDeploymentID, _tokensIn, signalOut, curationTax);

        return (signalOut, curationTax);
    }

    /**
     * @dev Return an amount of signal to get tokens back.
     * @notice Burn _signal from the SubgraphDeployment curation pool
     * @param _subgraphDeploymentID SubgraphDeployment the curator is returning signal
     * @param _signalIn Amount of signal to return
     * @param _tokensOutMin Expected minimum amount of tokens to receive
     * @return Tokens returned
     */
    function burn(
        bytes32 _subgraphDeploymentID,
        uint256 _signalIn,
        uint256 _tokensOutMin
    ) external override notPartialPaused returns (uint256) {
        address curator = msg.sender;

        // Validations
        require(_signalIn > 0, "Cannot burn zero signal");
        require(
            getCuratorSignal(curator, _subgraphDeploymentID) >= _signalIn,
            "Cannot burn more signal than you own"
        );

        // Get the amount of tokens to refund based on returned signal
        uint256 tokensOut = signalToTokens(_subgraphDeploymentID, _signalIn);

        // Slippage protection
        require(tokensOut >= _tokensOutMin, "Slippage protection");

        // Trigger update rewards calculation
        _updateRewards(_subgraphDeploymentID);

        // Update curation pool
        CurationPool storage curationPool = pools[_subgraphDeploymentID];
        curationPool.tokens = curationPool.tokens.sub(tokensOut);
        curationPool.gcs.burnFrom(curator, _signalIn);

        // If all signal burnt delete the curation pool
        if (getCurationPoolSignal(_subgraphDeploymentID) == 0) {
            delete pools[_subgraphDeploymentID];
        }

        // Return the tokens to the curator
        require(graphToken().transfer(curator, tokensOut), "Error sending curator tokens");

        emit Burned(curator, _subgraphDeploymentID, tokensOut, _signalIn);

        return tokensOut;
    }

    /**
     * @dev Check if any GRT tokens are deposited for a SubgraphDeployment.
     * @param _subgraphDeploymentID SubgraphDeployment to check if curated
     * @return True if curated
     */
    function isCurated(bytes32 _subgraphDeploymentID) public override view returns (bool) {
        return pools[_subgraphDeploymentID].tokens > 0;
    }

    /**
     * @dev Get the amount of signal a curator has in a curation pool.
     * @param _curator Curator owning the signal tokens
     * @param _subgraphDeploymentID Subgraph deployment curation pool
     * @return Amount of signal owned by a curator for the subgraph deployment
     */
    function getCuratorSignal(address _curator, bytes32 _subgraphDeploymentID)
        public
        override
        view
        returns (uint256)
    {
        if (address(pools[_subgraphDeploymentID].gcs) == address(0)) {
            return 0;
        }
        return pools[_subgraphDeploymentID].gcs.balanceOf(_curator);
    }

    /**
     * @dev Get the amount of signal in a curation pool.
     * @param _subgraphDeploymentID Subgraph deployment curation poool
     * @return Amount of signal minted for the subgraph deployment
     */
    function getCurationPoolSignal(bytes32 _subgraphDeploymentID)
        public
        override
        view
        returns (uint256)
    {
        if (address(pools[_subgraphDeploymentID].gcs) == address(0)) {
            return 0;
        }
        return pools[_subgraphDeploymentID].gcs.totalSupply();
    }

    /**
     * @dev Get the amount of token reserves in a curation pool.
     * @param _subgraphDeploymentID Subgraph deployment curation poool
     * @return Amount of token reserves in the curation pool
     */
    function getCurationPoolTokens(bytes32 _subgraphDeploymentID)
        external
        override
        view
        returns (uint256)
    {
        return pools[_subgraphDeploymentID].tokens;
    }

    /**
     * @dev Get curation tax percentage
     * @return Amount the curation tax percentage in PPM
     */
    function curationTaxPercentage() external override view returns (uint32) {
        return _curationTaxPercentage;
    }

    /**
     * @dev Calculate amount of signal that can be bought with tokens in a curation pool.
     * This function considers and excludes the deposit tax.
     * @param _subgraphDeploymentID Subgraph deployment to mint signal
     * @param _tokensIn Amount of tokens used to mint signal
     * @return Amount of signal that can be bought and tokens subtracted for the tax
     */
    function tokensToSignal(bytes32 _subgraphDeploymentID, uint256 _tokensIn)
        public
        override
        view
        returns (uint256, uint256)
    {
        uint256 curationTax = _tokensIn.mul(uint256(_curationTaxPercentage)).div(MAX_PPM);
        uint256 signalOut = _tokensToSignal(_subgraphDeploymentID, _tokensIn.sub(curationTax));
        return (signalOut, curationTax);
    }

    /**
     * @dev Calculate amount of signal that can be bought with tokens in a curation pool.
     * @param _subgraphDeploymentID Subgraph deployment to mint signal
     * @param _tokensIn Amount of tokens used to mint signal
     * @return Amount of signal that can be bought with tokens
     */
    function _tokensToSignal(bytes32 _subgraphDeploymentID, uint256 _tokensIn)
        private
        view
        returns (uint256)
    {
        // Get curation pool tokens and signal
        CurationPool memory curationPool = pools[_subgraphDeploymentID];

        // Init curation pool
        if (curationPool.tokens == 0) {
            require(
                _tokensIn >= minimumCurationDeposit,
                "Curation deposit is below minimum required"
            );
            return
                BancorFormula(bondingCurve)
                    .calculatePurchaseReturn(
                    SIGNAL_PER_MINIMUM_DEPOSIT,
                    minimumCurationDeposit,
                    defaultReserveRatio,
                    _tokensIn.sub(minimumCurationDeposit)
                )
                    .add(SIGNAL_PER_MINIMUM_DEPOSIT);
        }

        return
            BancorFormula(bondingCurve).calculatePurchaseReturn(
                getCurationPoolSignal(_subgraphDeploymentID),
                curationPool.tokens,
                curationPool.reserveRatio,
                _tokensIn
            );
    }

    /**
     * @dev Calculate number of tokens to get when burning signal from a curation pool.
     * @param _subgraphDeploymentID Subgraph deployment to burn signal
     * @param _signalIn Amount of signal to burn
     * @return Amount of tokens to get for an amount of signal
     */
    function signalToTokens(bytes32 _subgraphDeploymentID, uint256 _signalIn)
        public
        override
        view
        returns (uint256)
    {
        CurationPool memory curationPool = pools[_subgraphDeploymentID];
        uint256 curationPoolSignal = getCurationPoolSignal(_subgraphDeploymentID);
        require(
            curationPool.tokens > 0,
            "Subgraph deployment must be curated to perform calculations"
        );
        require(
            curationPoolSignal >= _signalIn,
            "Signal must be above or equal to signal issued in the curation pool"
        );

        return
            BancorFormula(bondingCurve).calculateSaleReturn(
                curationPoolSignal,
                curationPool.tokens,
                curationPool.reserveRatio,
                _signalIn
            );
    }

    /**
     * @dev Triggers an update of rewards due to a change in signal.
     * @param _subgraphDeploymentID Subgraph deployment updated
     */
    function _updateRewards(bytes32 _subgraphDeploymentID) private {
        IRewardsManager rewardsManager = rewardsManager();
        if (address(rewardsManager) != address(0)) {
            rewardsManager.onSubgraphSignalUpdate(_subgraphDeploymentID);
        }
    }
}

File 2 of 20 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.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, 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) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * 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);
        uint256 c = a - b;

        return c;
    }

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

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts 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) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message 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, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts 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) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message 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, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

File 3 of 20 : BancorFormula.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.7.3;

import "@openzeppelin/contracts/math/SafeMath.sol";

contract BancorFormula {
    using SafeMath for uint256;

    uint16 public constant version = 6;

    uint256 private constant ONE = 1;
    uint32 private constant MAX_RATIO = 1000000;
    uint8 private constant MIN_PRECISION = 32;
    uint8 private constant MAX_PRECISION = 127;

    /**
     * @dev Auto-generated via 'PrintIntScalingFactors.py'
     */
    uint256 private constant FIXED_1 = 0x080000000000000000000000000000000;
    uint256 private constant FIXED_2 = 0x100000000000000000000000000000000;
    uint256 private constant MAX_NUM = 0x200000000000000000000000000000000;

    /**
     * @dev Auto-generated via 'PrintLn2ScalingFactors.py'
     */
    uint256 private constant LN2_NUMERATOR = 0x3f80fe03f80fe03f80fe03f80fe03f8;
    uint256 private constant LN2_DENOMINATOR = 0x5b9de1d10bf4103d647b0955897ba80;

    /**
     * @dev Auto-generated via 'PrintFunctionOptimalLog.py' and 'PrintFunctionOptimalExp.py'
     */
    uint256 private constant OPT_LOG_MAX_VAL = 0x15bf0a8b1457695355fb8ac404e7a79e3;
    uint256 private constant OPT_EXP_MAX_VAL = 0x800000000000000000000000000000000;

    /**
     * @dev Auto-generated via 'PrintFunctionConstructor.py'
     */
    uint256[128] private maxExpArray;

    constructor() {
        //  maxExpArray[  0] = 0x6bffffffffffffffffffffffffffffffff;
        //  maxExpArray[  1] = 0x67ffffffffffffffffffffffffffffffff;
        //  maxExpArray[  2] = 0x637fffffffffffffffffffffffffffffff;
        //  maxExpArray[  3] = 0x5f6fffffffffffffffffffffffffffffff;
        //  maxExpArray[  4] = 0x5b77ffffffffffffffffffffffffffffff;
        //  maxExpArray[  5] = 0x57b3ffffffffffffffffffffffffffffff;
        //  maxExpArray[  6] = 0x5419ffffffffffffffffffffffffffffff;
        //  maxExpArray[  7] = 0x50a2ffffffffffffffffffffffffffffff;
        //  maxExpArray[  8] = 0x4d517fffffffffffffffffffffffffffff;
        //  maxExpArray[  9] = 0x4a233fffffffffffffffffffffffffffff;
        //  maxExpArray[ 10] = 0x47165fffffffffffffffffffffffffffff;
        //  maxExpArray[ 11] = 0x4429afffffffffffffffffffffffffffff;
        //  maxExpArray[ 12] = 0x415bc7ffffffffffffffffffffffffffff;
        //  maxExpArray[ 13] = 0x3eab73ffffffffffffffffffffffffffff;
        //  maxExpArray[ 14] = 0x3c1771ffffffffffffffffffffffffffff;
        //  maxExpArray[ 15] = 0x399e96ffffffffffffffffffffffffffff;
        //  maxExpArray[ 16] = 0x373fc47fffffffffffffffffffffffffff;
        //  maxExpArray[ 17] = 0x34f9e8ffffffffffffffffffffffffffff;
        //  maxExpArray[ 18] = 0x32cbfd5fffffffffffffffffffffffffff;
        //  maxExpArray[ 19] = 0x30b5057fffffffffffffffffffffffffff;
        //  maxExpArray[ 20] = 0x2eb40f9fffffffffffffffffffffffffff;
        //  maxExpArray[ 21] = 0x2cc8340fffffffffffffffffffffffffff;
        //  maxExpArray[ 22] = 0x2af09481ffffffffffffffffffffffffff;
        //  maxExpArray[ 23] = 0x292c5bddffffffffffffffffffffffffff;
        //  maxExpArray[ 24] = 0x277abdcdffffffffffffffffffffffffff;
        //  maxExpArray[ 25] = 0x25daf6657fffffffffffffffffffffffff;
        //  maxExpArray[ 26] = 0x244c49c65fffffffffffffffffffffffff;
        //  maxExpArray[ 27] = 0x22ce03cd5fffffffffffffffffffffffff;
        //  maxExpArray[ 28] = 0x215f77c047ffffffffffffffffffffffff;
        //  maxExpArray[ 29] = 0x1fffffffffffffffffffffffffffffffff;
        //  maxExpArray[ 30] = 0x1eaefdbdabffffffffffffffffffffffff;
        //  maxExpArray[ 31] = 0x1d6bd8b2ebffffffffffffffffffffffff;
        maxExpArray[32] = 0x1c35fedd14ffffffffffffffffffffffff;
        maxExpArray[33] = 0x1b0ce43b323fffffffffffffffffffffff;
        maxExpArray[34] = 0x19f0028ec1ffffffffffffffffffffffff;
        maxExpArray[35] = 0x18ded91f0e7fffffffffffffffffffffff;
        maxExpArray[36] = 0x17d8ec7f0417ffffffffffffffffffffff;
        maxExpArray[37] = 0x16ddc6556cdbffffffffffffffffffffff;
        maxExpArray[38] = 0x15ecf52776a1ffffffffffffffffffffff;
        maxExpArray[39] = 0x15060c256cb2ffffffffffffffffffffff;
        maxExpArray[40] = 0x1428a2f98d72ffffffffffffffffffffff;
        maxExpArray[41] = 0x13545598e5c23fffffffffffffffffffff;
        maxExpArray[42] = 0x1288c4161ce1dfffffffffffffffffffff;
        maxExpArray[43] = 0x11c592761c666fffffffffffffffffffff;
        maxExpArray[44] = 0x110a688680a757ffffffffffffffffffff;
        maxExpArray[45] = 0x1056f1b5bedf77ffffffffffffffffffff;
        maxExpArray[46] = 0x0faadceceeff8bffffffffffffffffffff;
        maxExpArray[47] = 0x0f05dc6b27edadffffffffffffffffffff;
        maxExpArray[48] = 0x0e67a5a25da4107fffffffffffffffffff;
        maxExpArray[49] = 0x0dcff115b14eedffffffffffffffffffff;
        maxExpArray[50] = 0x0d3e7a392431239fffffffffffffffffff;
        maxExpArray[51] = 0x0cb2ff529eb71e4fffffffffffffffffff;
        maxExpArray[52] = 0x0c2d415c3db974afffffffffffffffffff;
        maxExpArray[53] = 0x0bad03e7d883f69bffffffffffffffffff;
        maxExpArray[54] = 0x0b320d03b2c343d5ffffffffffffffffff;
        maxExpArray[55] = 0x0abc25204e02828dffffffffffffffffff;
        maxExpArray[56] = 0x0a4b16f74ee4bb207fffffffffffffffff;
        maxExpArray[57] = 0x09deaf736ac1f569ffffffffffffffffff;
        maxExpArray[58] = 0x0976bd9952c7aa957fffffffffffffffff;
        maxExpArray[59] = 0x09131271922eaa606fffffffffffffffff;
        maxExpArray[60] = 0x08b380f3558668c46fffffffffffffffff;
        maxExpArray[61] = 0x0857ddf0117efa215bffffffffffffffff;
        maxExpArray[62] = 0x07ffffffffffffffffffffffffffffffff;
        maxExpArray[63] = 0x07abbf6f6abb9d087fffffffffffffffff;
        maxExpArray[64] = 0x075af62cbac95f7dfa7fffffffffffffff;
        maxExpArray[65] = 0x070d7fb7452e187ac13fffffffffffffff;
        maxExpArray[66] = 0x06c3390ecc8af379295fffffffffffffff;
        maxExpArray[67] = 0x067c00a3b07ffc01fd6fffffffffffffff;
        maxExpArray[68] = 0x0637b647c39cbb9d3d27ffffffffffffff;
        maxExpArray[69] = 0x05f63b1fc104dbd39587ffffffffffffff;
        maxExpArray[70] = 0x05b771955b36e12f7235ffffffffffffff;
        maxExpArray[71] = 0x057b3d49dda84556d6f6ffffffffffffff;
        maxExpArray[72] = 0x054183095b2c8ececf30ffffffffffffff;
        maxExpArray[73] = 0x050a28be635ca2b888f77fffffffffffff;
        maxExpArray[74] = 0x04d5156639708c9db33c3fffffffffffff;
        maxExpArray[75] = 0x04a23105873875bd52dfdfffffffffffff;
        maxExpArray[76] = 0x0471649d87199aa990756fffffffffffff;
        maxExpArray[77] = 0x04429a21a029d4c1457cfbffffffffffff;
        maxExpArray[78] = 0x0415bc6d6fb7dd71af2cb3ffffffffffff;
        maxExpArray[79] = 0x03eab73b3bbfe282243ce1ffffffffffff;
        maxExpArray[80] = 0x03c1771ac9fb6b4c18e229ffffffffffff;
        maxExpArray[81] = 0x0399e96897690418f785257fffffffffff;
        maxExpArray[82] = 0x0373fc456c53bb779bf0ea9fffffffffff;
        maxExpArray[83] = 0x034f9e8e490c48e67e6ab8bfffffffffff;
        maxExpArray[84] = 0x032cbfd4a7adc790560b3337ffffffffff;
        maxExpArray[85] = 0x030b50570f6e5d2acca94613ffffffffff;
        maxExpArray[86] = 0x02eb40f9f620fda6b56c2861ffffffffff;
        maxExpArray[87] = 0x02cc8340ecb0d0f520a6af58ffffffffff;
        maxExpArray[88] = 0x02af09481380a0a35cf1ba02ffffffffff;
        maxExpArray[89] = 0x0292c5bdd3b92ec810287b1b3fffffffff;
        maxExpArray[90] = 0x0277abdcdab07d5a77ac6d6b9fffffffff;
        maxExpArray[91] = 0x025daf6654b1eaa55fd64df5efffffffff;
        maxExpArray[92] = 0x0244c49c648baa98192dce88b7ffffffff;
        maxExpArray[93] = 0x022ce03cd5619a311b2471268bffffffff;
        maxExpArray[94] = 0x0215f77c045fbe885654a44a0fffffffff;
        maxExpArray[95] = 0x01ffffffffffffffffffffffffffffffff;
        maxExpArray[96] = 0x01eaefdbdaaee7421fc4d3ede5ffffffff;
        maxExpArray[97] = 0x01d6bd8b2eb257df7e8ca57b09bfffffff;
        maxExpArray[98] = 0x01c35fedd14b861eb0443f7f133fffffff;
        maxExpArray[99] = 0x01b0ce43b322bcde4a56e8ada5afffffff;
        maxExpArray[100] = 0x019f0028ec1fff007f5a195a39dfffffff;
        maxExpArray[101] = 0x018ded91f0e72ee74f49b15ba527ffffff;
        maxExpArray[102] = 0x017d8ec7f04136f4e5615fd41a63ffffff;
        maxExpArray[103] = 0x016ddc6556cdb84bdc8d12d22e6fffffff;
        maxExpArray[104] = 0x015ecf52776a1155b5bd8395814f7fffff;
        maxExpArray[105] = 0x015060c256cb23b3b3cc3754cf40ffffff;
        maxExpArray[106] = 0x01428a2f98d728ae223ddab715be3fffff;
        maxExpArray[107] = 0x013545598e5c23276ccf0ede68034fffff;
        maxExpArray[108] = 0x01288c4161ce1d6f54b7f61081194fffff;
        maxExpArray[109] = 0x011c592761c666aa641d5a01a40f17ffff;
        maxExpArray[110] = 0x0110a688680a7530515f3e6e6cfdcdffff;
        maxExpArray[111] = 0x01056f1b5bedf75c6bcb2ce8aed428ffff;
        maxExpArray[112] = 0x00faadceceeff8a0890f3875f008277fff;
        maxExpArray[113] = 0x00f05dc6b27edad306388a600f6ba0bfff;
        maxExpArray[114] = 0x00e67a5a25da41063de1495d5b18cdbfff;
        maxExpArray[115] = 0x00dcff115b14eedde6fc3aa5353f2e4fff;
        maxExpArray[116] = 0x00d3e7a3924312399f9aae2e0f868f8fff;
        maxExpArray[117] = 0x00cb2ff529eb71e41582cccd5a1ee26fff;
        maxExpArray[118] = 0x00c2d415c3db974ab32a51840c0b67edff;
        maxExpArray[119] = 0x00bad03e7d883f69ad5b0a186184e06bff;
        maxExpArray[120] = 0x00b320d03b2c343d4829abd6075f0cc5ff;
        maxExpArray[121] = 0x00abc25204e02828d73c6e80bcdb1a95bf;
        maxExpArray[122] = 0x00a4b16f74ee4bb2040a1ec6c15fbbf2df;
        maxExpArray[123] = 0x009deaf736ac1f569deb1b5ae3f36c130f;
        maxExpArray[124] = 0x00976bd9952c7aa957f5937d790ef65037;
        maxExpArray[125] = 0x009131271922eaa6064b73a22d0bd4f2bf;
        maxExpArray[126] = 0x008b380f3558668c46c91c49a2f8e967b9;
        maxExpArray[127] = 0x00857ddf0117efa215952912839f6473e6;
    }

    /**
     * @dev given a token supply, reserve balance, ratio and a deposit amount (in the reserve token),
     * calculates the return for a given conversion (in the main token)
     *
     * Formula:
     * Return = _supply * ((1 + _depositAmount / _reserveBalance) ^ (_reserveRatio / 1000000) - 1)
     *
     * @param _supply              token total supply
     * @param _reserveBalance      total reserve balance
     * @param _reserveRatio        reserve ratio, represented in ppm, 1-1000000
     * @param _depositAmount       deposit amount, in reserve token
     *
     * @return purchase return amount
     */
    function calculatePurchaseReturn(
        uint256 _supply,
        uint256 _reserveBalance,
        uint32 _reserveRatio,
        uint256 _depositAmount
    ) public view returns (uint256) {
        // validate input
        require(
            _supply > 0 && _reserveBalance > 0 && _reserveRatio > 0 && _reserveRatio <= MAX_RATIO,
            "invalid parameters"
        );

        // special case for 0 deposit amount
        if (_depositAmount == 0) return 0;

        // special case if the ratio = 100%
        if (_reserveRatio == MAX_RATIO) return _supply.mul(_depositAmount) / _reserveBalance;

        uint256 result;
        uint8 precision;
        uint256 baseN = _depositAmount.add(_reserveBalance);
        (result, precision) = power(baseN, _reserveBalance, _reserveRatio, MAX_RATIO);
        uint256 temp = _supply.mul(result) >> precision;
        return temp - _supply;
    }

    /**
     * @dev given a token supply, reserve balance, ratio and a sell amount (in the main token),
     * calculates the return for a given conversion (in the reserve token)
     *
     * Formula:
     * Return = _reserveBalance * (1 - (1 - _sellAmount / _supply) ^ (1000000 / _reserveRatio))
     *
     * @param _supply              token total supply
     * @param _reserveBalance      total reserve
     * @param _reserveRatio        constant reserve Ratio, represented in ppm, 1-1000000
     * @param _sellAmount          sell amount, in the token itself
     *
     * @return sale return amount
     */
    function calculateSaleReturn(
        uint256 _supply,
        uint256 _reserveBalance,
        uint32 _reserveRatio,
        uint256 _sellAmount
    ) public view returns (uint256) {
        // validate input
        require(
            _supply > 0 &&
                _reserveBalance > 0 &&
                _reserveRatio > 0 &&
                _reserveRatio <= MAX_RATIO &&
                _sellAmount <= _supply,
            "invalid parameters"
        );

        // special case for 0 sell amount
        if (_sellAmount == 0) return 0;

        // special case for selling the entire supply
        if (_sellAmount == _supply) return _reserveBalance;

        // special case if the ratio = 100%
        if (_reserveRatio == MAX_RATIO) return _reserveBalance.mul(_sellAmount) / _supply;

        uint256 result;
        uint8 precision;
        uint256 baseD = _supply - _sellAmount;
        (result, precision) = power(_supply, baseD, MAX_RATIO, _reserveRatio);
        uint256 temp1 = _reserveBalance.mul(result);
        uint256 temp2 = _reserveBalance << precision;
        return (temp1 - temp2) / result;
    }

    /**
     * @dev given two reserve balances/ratios and a sell amount (in the first reserve token),
     * calculates the return for a conversion from the first reserve token to the second reserve token (in the second reserve token)
     * note that prior to version 4, you should use 'calculateCrossConnectorReturn' instead
     *
     * Formula:
     * Return = _toReserveBalance * (1 - (_fromReserveBalance / (_fromReserveBalance + _amount)) ^ (_fromReserveRatio / _toReserveRatio))
     *
     * @param _fromReserveBalance      input reserve balance
     * @param _fromReserveRatio        input reserve ratio, represented in ppm, 1-1000000
     * @param _toReserveBalance        output reserve balance
     * @param _toReserveRatio          output reserve ratio, represented in ppm, 1-1000000
     * @param _amount                  input reserve amount
     *
     * @return second reserve amount
     */
    function calculateCrossReserveReturn(
        uint256 _fromReserveBalance,
        uint32 _fromReserveRatio,
        uint256 _toReserveBalance,
        uint32 _toReserveRatio,
        uint256 _amount
    ) public view returns (uint256) {
        // validate input
        require(
            _fromReserveBalance > 0 &&
                _fromReserveRatio > 0 &&
                _fromReserveRatio <= MAX_RATIO &&
                _toReserveBalance > 0 &&
                _toReserveRatio > 0 &&
                _toReserveRatio <= MAX_RATIO
        );

        // special case for equal ratios
        if (_fromReserveRatio == _toReserveRatio)
            return _toReserveBalance.mul(_amount) / _fromReserveBalance.add(_amount);

        uint256 result;
        uint8 precision;
        uint256 baseN = _fromReserveBalance.add(_amount);
        (result, precision) = power(baseN, _fromReserveBalance, _fromReserveRatio, _toReserveRatio);
        uint256 temp1 = _toReserveBalance.mul(result);
        uint256 temp2 = _toReserveBalance << precision;
        return (temp1 - temp2) / result;
    }

    /**
     * @dev given a smart token supply, reserve balance, total ratio and an amount of requested smart tokens,
     * calculates the amount of reserve tokens required for purchasing the given amount of smart tokens
     *
     * Formula:
     * Return = _reserveBalance * (((_supply + _amount) / _supply) ^ (MAX_RATIO / _totalRatio) - 1)
     *
     * @param _supply              smart token supply
     * @param _reserveBalance      reserve token balance
     * @param _totalRatio          total ratio, represented in ppm, 2-2000000
     * @param _amount              requested amount of smart tokens
     *
     * @return amount of reserve tokens
     */
    function calculateFundCost(
        uint256 _supply,
        uint256 _reserveBalance,
        uint32 _totalRatio,
        uint256 _amount
    ) public view returns (uint256) {
        // validate input
        require(
            _supply > 0 && _reserveBalance > 0 && _totalRatio > 1 && _totalRatio <= MAX_RATIO * 2
        );

        // special case for 0 amount
        if (_amount == 0) return 0;

        // special case if the total ratio = 100%
        if (_totalRatio == MAX_RATIO) return (_amount.mul(_reserveBalance) - 1) / _supply + 1;

        uint256 result;
        uint8 precision;
        uint256 baseN = _supply.add(_amount);
        (result, precision) = power(baseN, _supply, MAX_RATIO, _totalRatio);
        uint256 temp = ((_reserveBalance.mul(result) - 1) >> precision) + 1;
        return temp - _reserveBalance;
    }

    /**
     * @dev given a smart token supply, reserve balance, total ratio and an amount of smart tokens to liquidate,
     * calculates the amount of reserve tokens received for selling the given amount of smart tokens
     *
     * Formula:
     * Return = _reserveBalance * (1 - ((_supply - _amount) / _supply) ^ (MAX_RATIO / _totalRatio))
     *
     * @param _supply              smart token supply
     * @param _reserveBalance      reserve token balance
     * @param _totalRatio          total ratio, represented in ppm, 2-2000000
     * @param _amount              amount of smart tokens to liquidate
     *
     * @return amount of reserve tokens
     */
    function calculateLiquidateReturn(
        uint256 _supply,
        uint256 _reserveBalance,
        uint32 _totalRatio,
        uint256 _amount
    ) public view returns (uint256) {
        // validate input
        require(
            _supply > 0 &&
                _reserveBalance > 0 &&
                _totalRatio > 1 &&
                _totalRatio <= MAX_RATIO * 2 &&
                _amount <= _supply
        );

        // special case for 0 amount
        if (_amount == 0) return 0;

        // special case for liquidating the entire supply
        if (_amount == _supply) return _reserveBalance;

        // special case if the total ratio = 100%
        if (_totalRatio == MAX_RATIO) return _amount.mul(_reserveBalance) / _supply;

        uint256 result;
        uint8 precision;
        uint256 baseD = _supply - _amount;
        (result, precision) = power(_supply, baseD, MAX_RATIO, _totalRatio);
        uint256 temp1 = _reserveBalance.mul(result);
        uint256 temp2 = _reserveBalance << precision;
        return (temp1 - temp2) / result;
    }

    /**
     * @dev General Description:
     *     Determine a value of precision.
     *     Calculate an integer approximation of (_baseN / _baseD) ^ (_expN / _expD) * 2 ^ precision.
     *     Return the result along with the precision used.
     *
     * Detailed Description:
     *     Instead of calculating "base ^ exp", we calculate "e ^ (log(base) * exp)".
     *     The value of "log(base)" is represented with an integer slightly smaller than "log(base) * 2 ^ precision".
     *     The larger "precision" is, the more accurately this value represents the real value.
     *     However, the larger "precision" is, the more bits are required in order to store this value.
     *     And the exponentiation function, which takes "x" and calculates "e ^ x", is limited to a maximum exponent (maximum value of "x").
     *     This maximum exponent depends on the "precision" used, and it is given by "maxExpArray[precision] >> (MAX_PRECISION - precision)".
     *     Hence we need to determine the highest precision which can be used for the given input, before calling the exponentiation function.
     *     This allows us to compute "base ^ exp" with maximum accuracy and without exceeding 256 bits in any of the intermediate computations.
     *     This functions assumes that "_expN < 2 ^ 256 / log(MAX_NUM - 1)", otherwise the multiplication should be replaced with a "safeMul".
     *     Since we rely on unsigned-integer arithmetic and "base < 1" ==> "log(base) < 0", this function does not support "_baseN < _baseD".
     */
    function power(
        uint256 _baseN,
        uint256 _baseD,
        uint32 _expN,
        uint32 _expD
    ) internal view returns (uint256, uint8) {
        require(_baseN < MAX_NUM);

        uint256 baseLog;
        uint256 base = (_baseN * FIXED_1) / _baseD;
        if (base < OPT_LOG_MAX_VAL) {
            baseLog = optimalLog(base);
        } else {
            baseLog = generalLog(base);
        }

        uint256 baseLogTimesExp = (baseLog * _expN) / _expD;
        if (baseLogTimesExp < OPT_EXP_MAX_VAL) {
            return (optimalExp(baseLogTimesExp), MAX_PRECISION);
        } else {
            uint8 precision = findPositionInMaxExpArray(baseLogTimesExp);
            return (
                generalExp(baseLogTimesExp >> (MAX_PRECISION - precision), precision),
                precision
            );
        }
    }

    /**
     * @dev computes log(x / FIXED_1) * FIXED_1.
     * This functions assumes that "x >= FIXED_1", because the output would be negative otherwise.
     */
    function generalLog(uint256 x) internal pure returns (uint256) {
        uint256 res = 0;

        // If x >= 2, then we compute the integer part of log2(x), which is larger than 0.
        if (x >= FIXED_2) {
            uint8 count = floorLog2(x / FIXED_1);
            x >>= count; // now x < 2
            res = count * FIXED_1;
        }

        // If x > 1, then we compute the fraction part of log2(x), which is larger than 0.
        if (x > FIXED_1) {
            for (uint8 i = MAX_PRECISION; i > 0; --i) {
                x = (x * x) / FIXED_1; // now 1 < x < 4
                if (x >= FIXED_2) {
                    x >>= 1; // now 1 < x < 2
                    res += ONE << (i - 1);
                }
            }
        }

        return (res * LN2_NUMERATOR) / LN2_DENOMINATOR;
    }

    /**
     * @dev computes the largest integer smaller than or equal to the binary logarithm of the input.
     */
    function floorLog2(uint256 _n) internal pure returns (uint8) {
        uint8 res = 0;

        if (_n < 256) {
            // At most 8 iterations
            while (_n > 1) {
                _n >>= 1;
                res += 1;
            }
        } else {
            // Exactly 8 iterations
            for (uint8 s = 128; s > 0; s >>= 1) {
                if (_n >= (ONE << s)) {
                    _n >>= s;
                    res |= s;
                }
            }
        }

        return res;
    }

    /**
     * @dev the global "maxExpArray" is sorted in descending order, and therefore the following statements are equivalent:
     * - This function finds the position of [the smallest value in "maxExpArray" larger than or equal to "x"]
     * - This function finds the highest position of [a value in "maxExpArray" larger than or equal to "x"]
     */
    function findPositionInMaxExpArray(uint256 _x) internal view returns (uint8) {
        uint8 lo = MIN_PRECISION;
        uint8 hi = MAX_PRECISION;

        while (lo + 1 < hi) {
            uint8 mid = (lo + hi) / 2;
            if (maxExpArray[mid] >= _x) lo = mid;
            else hi = mid;
        }

        if (maxExpArray[hi] >= _x) return hi;
        if (maxExpArray[lo] >= _x) return lo;

        require(false);
        return 0;
    }

    /**
     * @dev this function can be auto-generated by the script 'PrintFunctionGeneralExp.py'.
     * it approximates "e ^ x" via maclaurin summation: "(x^0)/0! + (x^1)/1! + ... + (x^n)/n!".
     * it returns "e ^ (x / 2 ^ precision) * 2 ^ precision", that is, the result is upshifted for accuracy.
     * the global "maxExpArray" maps each "precision" to "((maximumExponent + 1) << (MAX_PRECISION - precision)) - 1".
     * the maximum permitted value for "x" is therefore given by "maxExpArray[precision] >> (MAX_PRECISION - precision)".
     */
    function generalExp(uint256 _x, uint8 _precision) internal pure returns (uint256) {
        uint256 xi = _x;
        uint256 res = 0;

        xi = (xi * _x) >> _precision;
        res += xi * 0x3442c4e6074a82f1797f72ac0000000; // add x^02 * (33! / 02!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x116b96f757c380fb287fd0e40000000; // add x^03 * (33! / 03!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x045ae5bdd5f0e03eca1ff4390000000; // add x^04 * (33! / 04!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x00defabf91302cd95b9ffda50000000; // add x^05 * (33! / 05!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x002529ca9832b22439efff9b8000000; // add x^06 * (33! / 06!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x00054f1cf12bd04e516b6da88000000; // add x^07 * (33! / 07!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x0000a9e39e257a09ca2d6db51000000; // add x^08 * (33! / 08!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x000012e066e7b839fa050c309000000; // add x^09 * (33! / 09!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x000001e33d7d926c329a1ad1a800000; // add x^10 * (33! / 10!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x0000002bee513bdb4a6b19b5f800000; // add x^11 * (33! / 11!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x00000003a9316fa79b88eccf2a00000; // add x^12 * (33! / 12!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x0000000048177ebe1fa812375200000; // add x^13 * (33! / 13!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x0000000005263fe90242dcbacf00000; // add x^14 * (33! / 14!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x000000000057e22099c030d94100000; // add x^15 * (33! / 15!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x0000000000057e22099c030d9410000; // add x^16 * (33! / 16!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x00000000000052b6b54569976310000; // add x^17 * (33! / 17!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x00000000000004985f67696bf748000; // add x^18 * (33! / 18!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x000000000000003dea12ea99e498000; // add x^19 * (33! / 19!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x00000000000000031880f2214b6e000; // add x^20 * (33! / 20!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x000000000000000025bcff56eb36000; // add x^21 * (33! / 21!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x000000000000000001b722e10ab1000; // add x^22 * (33! / 22!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x0000000000000000001317c70077000; // add x^23 * (33! / 23!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x00000000000000000000cba84aafa00; // add x^24 * (33! / 24!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x00000000000000000000082573a0a00; // add x^25 * (33! / 25!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x00000000000000000000005035ad900; // add x^26 * (33! / 26!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x000000000000000000000002f881b00; // add x^27 * (33! / 27!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x0000000000000000000000001b29340; // add x^28 * (33! / 28!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x00000000000000000000000000efc40; // add x^29 * (33! / 29!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x0000000000000000000000000007fe0; // add x^30 * (33! / 30!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x0000000000000000000000000000420; // add x^31 * (33! / 31!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x0000000000000000000000000000021; // add x^32 * (33! / 32!)
        xi = (xi * _x) >> _precision;
        res += xi * 0x0000000000000000000000000000001; // add x^33 * (33! / 33!)

        return res / 0x688589cc0e9505e2f2fee5580000000 + _x + (ONE << _precision); // divide by 33! and then add x^1 / 1! + x^0 / 0!
    }

    /**
     * @dev computes log(x / FIXED_1) * FIXED_1
     * Input range: FIXED_1 <= x <= LOG_EXP_MAX_VAL - 1
     * Auto-generated via 'PrintFunctionOptimalLog.py'
     * Detailed description:
     * - Rewrite the input as a product of natural exponents and a single residual r, such that 1 < r < 2
     * - The natural logarithm of each (pre-calculated) exponent is the degree of the exponent
     * - The natural logarithm of r is calculated via Taylor series for log(1 + x), where x = r - 1
     * - The natural logarithm of the input is calculated by summing up the intermediate results above
     * - For example: log(250) = log(e^4 * e^1 * e^0.5 * 1.021692859) = 4 + 1 + 0.5 + log(1 + 0.021692859)
     */
    function optimalLog(uint256 x) internal pure returns (uint256) {
        uint256 res = 0;

        uint256 y;
        uint256 z;
        uint256 w;

        if (x >= 0xd3094c70f034de4b96ff7d5b6f99fcd8) {
            res += 0x40000000000000000000000000000000;
            x = (x * FIXED_1) / 0xd3094c70f034de4b96ff7d5b6f99fcd8;
        } // add 1 / 2^1
        if (x >= 0xa45af1e1f40c333b3de1db4dd55f29a7) {
            res += 0x20000000000000000000000000000000;
            x = (x * FIXED_1) / 0xa45af1e1f40c333b3de1db4dd55f29a7;
        } // add 1 / 2^2
        if (x >= 0x910b022db7ae67ce76b441c27035c6a1) {
            res += 0x10000000000000000000000000000000;
            x = (x * FIXED_1) / 0x910b022db7ae67ce76b441c27035c6a1;
        } // add 1 / 2^3
        if (x >= 0x88415abbe9a76bead8d00cf112e4d4a8) {
            res += 0x08000000000000000000000000000000;
            x = (x * FIXED_1) / 0x88415abbe9a76bead8d00cf112e4d4a8;
        } // add 1 / 2^4
        if (x >= 0x84102b00893f64c705e841d5d4064bd3) {
            res += 0x04000000000000000000000000000000;
            x = (x * FIXED_1) / 0x84102b00893f64c705e841d5d4064bd3;
        } // add 1 / 2^5
        if (x >= 0x8204055aaef1c8bd5c3259f4822735a2) {
            res += 0x02000000000000000000000000000000;
            x = (x * FIXED_1) / 0x8204055aaef1c8bd5c3259f4822735a2;
        } // add 1 / 2^6
        if (x >= 0x810100ab00222d861931c15e39b44e99) {
            res += 0x01000000000000000000000000000000;
            x = (x * FIXED_1) / 0x810100ab00222d861931c15e39b44e99;
        } // add 1 / 2^7
        if (x >= 0x808040155aabbbe9451521693554f733) {
            res += 0x00800000000000000000000000000000;
            x = (x * FIXED_1) / 0x808040155aabbbe9451521693554f733;
        } // add 1 / 2^8

        z = y = x - FIXED_1;
        w = (y * y) / FIXED_1;
        res +=
            (z * (0x100000000000000000000000000000000 - y)) /
            0x100000000000000000000000000000000;
        z = (z * w) / FIXED_1; // add y^01 / 01 - y^02 / 02
        res +=
            (z * (0x0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - y)) /
            0x200000000000000000000000000000000;
        z = (z * w) / FIXED_1; // add y^03 / 03 - y^04 / 04
        res +=
            (z * (0x099999999999999999999999999999999 - y)) /
            0x300000000000000000000000000000000;
        z = (z * w) / FIXED_1; // add y^05 / 05 - y^06 / 06
        res +=
            (z * (0x092492492492492492492492492492492 - y)) /
            0x400000000000000000000000000000000;
        z = (z * w) / FIXED_1; // add y^07 / 07 - y^08 / 08
        res +=
            (z * (0x08e38e38e38e38e38e38e38e38e38e38e - y)) /
            0x500000000000000000000000000000000;
        z = (z * w) / FIXED_1; // add y^09 / 09 - y^10 / 10
        res +=
            (z * (0x08ba2e8ba2e8ba2e8ba2e8ba2e8ba2e8b - y)) /
            0x600000000000000000000000000000000;
        z = (z * w) / FIXED_1; // add y^11 / 11 - y^12 / 12
        res +=
            (z * (0x089d89d89d89d89d89d89d89d89d89d89 - y)) /
            0x700000000000000000000000000000000;
        z = (z * w) / FIXED_1; // add y^13 / 13 - y^14 / 14
        res +=
            (z * (0x088888888888888888888888888888888 - y)) /
            0x800000000000000000000000000000000; // add y^15 / 15 - y^16 / 16

        return res;
    }

    /**
     * @dev computes e ^ (x / FIXED_1) * FIXED_1
     * input range: 0 <= x <= OPT_EXP_MAX_VAL - 1
     * auto-generated via 'PrintFunctionOptimalExp.py'
     * Detailed description:
     * - Rewrite the input as a sum of binary exponents and a single residual r, as small as possible
     * - The exponentiation of each binary exponent is given (pre-calculated)
     * - The exponentiation of r is calculated via Taylor series for e^x, where x = r
     * - The exponentiation of the input is calculated by multiplying the intermediate results above
     * - For example: e^5.521692859 = e^(4 + 1 + 0.5 + 0.021692859) = e^4 * e^1 * e^0.5 * e^0.021692859
     */
    function optimalExp(uint256 x) internal pure returns (uint256) {
        uint256 res = 0;

        uint256 y;
        uint256 z;

        z = y = x % 0x10000000000000000000000000000000; // get the input modulo 2^(-3)
        z = (z * y) / FIXED_1;
        res += z * 0x10e1b3be415a0000; // add y^02 * (20! / 02!)
        z = (z * y) / FIXED_1;
        res += z * 0x05a0913f6b1e0000; // add y^03 * (20! / 03!)
        z = (z * y) / FIXED_1;
        res += z * 0x0168244fdac78000; // add y^04 * (20! / 04!)
        z = (z * y) / FIXED_1;
        res += z * 0x004807432bc18000; // add y^05 * (20! / 05!)
        z = (z * y) / FIXED_1;
        res += z * 0x000c0135dca04000; // add y^06 * (20! / 06!)
        z = (z * y) / FIXED_1;
        res += z * 0x0001b707b1cdc000; // add y^07 * (20! / 07!)
        z = (z * y) / FIXED_1;
        res += z * 0x000036e0f639b800; // add y^08 * (20! / 08!)
        z = (z * y) / FIXED_1;
        res += z * 0x00000618fee9f800; // add y^09 * (20! / 09!)
        z = (z * y) / FIXED_1;
        res += z * 0x0000009c197dcc00; // add y^10 * (20! / 10!)
        z = (z * y) / FIXED_1;
        res += z * 0x0000000e30dce400; // add y^11 * (20! / 11!)
        z = (z * y) / FIXED_1;
        res += z * 0x000000012ebd1300; // add y^12 * (20! / 12!)
        z = (z * y) / FIXED_1;
        res += z * 0x0000000017499f00; // add y^13 * (20! / 13!)
        z = (z * y) / FIXED_1;
        res += z * 0x0000000001a9d480; // add y^14 * (20! / 14!)
        z = (z * y) / FIXED_1;
        res += z * 0x00000000001c6380; // add y^15 * (20! / 15!)
        z = (z * y) / FIXED_1;
        res += z * 0x000000000001c638; // add y^16 * (20! / 16!)
        z = (z * y) / FIXED_1;
        res += z * 0x0000000000001ab8; // add y^17 * (20! / 17!)
        z = (z * y) / FIXED_1;
        res += z * 0x000000000000017c; // add y^18 * (20! / 18!)
        z = (z * y) / FIXED_1;
        res += z * 0x0000000000000014; // add y^19 * (20! / 19!)
        z = (z * y) / FIXED_1;
        res += z * 0x0000000000000001; // add y^20 * (20! / 20!)
        res = res / 0x21c3677c82b40000 + y + FIXED_1; // divide by 20! and then add y^1 / 1! + y^0 / 0!

        if ((x & 0x010000000000000000000000000000000) != 0)
            res = (res * 0x1c3d6a24ed82218787d624d3e5eba95f9) / 0x18ebef9eac820ae8682b9793ac6d1e776; // multiply by e^2^(-3)
        if ((x & 0x020000000000000000000000000000000) != 0)
            res = (res * 0x18ebef9eac820ae8682b9793ac6d1e778) / 0x1368b2fc6f9609fe7aceb46aa619baed4; // multiply by e^2^(-2)
        if ((x & 0x040000000000000000000000000000000) != 0)
            res = (res * 0x1368b2fc6f9609fe7aceb46aa619baed5) / 0x0bc5ab1b16779be3575bd8f0520a9f21f; // multiply by e^2^(-1)
        if ((x & 0x080000000000000000000000000000000) != 0)
            res = (res * 0x0bc5ab1b16779be3575bd8f0520a9f21e) / 0x0454aaa8efe072e7f6ddbab84b40a55c9; // multiply by e^2^(+0)
        if ((x & 0x100000000000000000000000000000000) != 0)
            res = (res * 0x0454aaa8efe072e7f6ddbab84b40a55c5) / 0x00960aadc109e7a3bf4578099615711ea; // multiply by e^2^(+1)
        if ((x & 0x200000000000000000000000000000000) != 0)
            res = (res * 0x00960aadc109e7a3bf4578099615711d7) / 0x0002bf84208204f5977f9a8cf01fdce3d; // multiply by e^2^(+2)
        if ((x & 0x400000000000000000000000000000000) != 0)
            res = (res * 0x0002bf84208204f5977f9a8cf01fdc307) / 0x0000003c6ab775dd0b95b4cbee7e65d11; // multiply by e^2^(+3)

        return res;
    }

    /**
     * @dev deprecated, backward compatibility
     */
    function calculateCrossConnectorReturn(
        uint256 _fromConnectorBalance,
        uint32 _fromConnectorWeight,
        uint256 _toConnectorBalance,
        uint32 _toConnectorWeight,
        uint256 _amount
    ) public view returns (uint256) {
        return
            calculateCrossReserveReturn(
                _fromConnectorBalance,
                _fromConnectorWeight,
                _toConnectorBalance,
                _toConnectorWeight,
                _amount
            );
    }
}

File 4 of 20 : GraphUpgradeable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.3;

import "./IGraphProxy.sol";

/**
 * @title Graph Upgradeable
 * @dev This contract is intended to be inherited from upgradeable contracts.
 */
contract GraphUpgradeable {
    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32
        internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev Check if the caller is the proxy admin.
     */
    modifier onlyProxyAdmin(IGraphProxy _proxy) {
        require(msg.sender == _proxy.admin(), "Caller must be the proxy admin");
        _;
    }

    /**
     * @dev Check if the caller is the implementation.
     */
    modifier onlyImpl {
        require(msg.sender == _implementation(), "Caller must be the implementation");
        _;
    }

    /**
     * @dev Returns the current implementation.
     * @return impl Address of the current implementation
     */
    function _implementation() internal view returns (address impl) {
        bytes32 slot = IMPLEMENTATION_SLOT;
        assembly {
            impl := sload(slot)
        }
    }

    /**
     * @dev Accept to be an implementation of proxy.
     */
    function acceptProxy(IGraphProxy _proxy) external onlyProxyAdmin(_proxy) {
        _proxy.acceptUpgrade();
    }

    /**
     * @dev Accept to be an implementation of proxy and then call a function from the new
     * implementation as specified by `_data`, which should be an encoded function call. This is
     * useful to initialize new storage variables in the proxied contract.
     */
    function acceptProxyAndCall(IGraphProxy _proxy, bytes calldata _data)
        external
        onlyProxyAdmin(_proxy)
    {
        _proxy.acceptUpgradeAndCall(_data);
    }
}

File 5 of 20 : CurationStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.3;

import "./ICuration.sol";
import "../governance/Managed.sol";

contract CurationV1Storage is Managed {
    // -- State --

    // Tax charged when curator deposit funds
    // Parts per million. (Allows for 4 decimal points, 999,999 = 99.9999%)
    uint32 internal _curationTaxPercentage;

    // Default reserve ratio to configure curator shares bonding curve
    // Parts per million. (Allows for 4 decimal points, 999,999 = 99.9999%)
    uint32 public defaultReserveRatio;

    // Minimum amount allowed to be deposited by curators to initialize a pool
    // This is the `startPoolBalance` for the bonding curve
    uint256 public minimumCurationDeposit;

    // Bonding curve formula
    address public bondingCurve;

    // Mapping of subgraphDeploymentID => CurationPool
    // There is only one CurationPool per SubgraphDeploymentID
    mapping(bytes32 => ICuration.CurationPool) public pools;
}

File 6 of 20 : ICuration.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.3;

import "./IGraphCurationToken.sol";

interface ICuration {
    // -- Pool --

    struct CurationPool {
        uint256 tokens; // GRT Tokens stored as reserves for the subgraph deployment
        uint32 reserveRatio; // Ratio for the bonding curve
        IGraphCurationToken gcs; // Curation token contract for this curation pool
    }

    // -- Configuration --

    function setDefaultReserveRatio(uint32 _defaultReserveRatio) external;

    function setMinimumCurationDeposit(uint256 _minimumCurationDeposit) external;

    function setCurationTaxPercentage(uint32 _percentage) external;

    // -- Curation --

    function mint(
        bytes32 _subgraphDeploymentID,
        uint256 _tokensIn,
        uint256 _signalOutMin
    ) external returns (uint256, uint256);

    function burn(
        bytes32 _subgraphDeploymentID,
        uint256 _signalIn,
        uint256 _tokensOutMin
    ) external returns (uint256);

    function collect(bytes32 _subgraphDeploymentID, uint256 _tokens) external;

    // -- Getters --

    function isCurated(bytes32 _subgraphDeploymentID) external view returns (bool);

    function getCuratorSignal(address _curator, bytes32 _subgraphDeploymentID)
        external
        view
        returns (uint256);

    function getCurationPoolSignal(bytes32 _subgraphDeploymentID) external view returns (uint256);

    function getCurationPoolTokens(bytes32 _subgraphDeploymentID) external view returns (uint256);

    function tokensToSignal(bytes32 _subgraphDeploymentID, uint256 _tokensIn)
        external
        view
        returns (uint256, uint256);

    function signalToTokens(bytes32 _subgraphDeploymentID, uint256 _signalIn)
        external
        view
        returns (uint256);

    function curationTaxPercentage() external view returns (uint32);
}

File 7 of 20 : GraphCurationToken.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.3;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

import "../governance/Governed.sol";

/**
 * @title GraphCurationToken contract
 * @dev This is the implementation of the Curation ERC20 token (GCS).
 * GCS are created for each subgraph deployment curated in the Curation contract.
 * The Curation contract is the owner of GCS tokens and the only one allowed to mint or
 * burn them. GCS tokens are transferrable and their holders can do any action allowed
 * in a standard ERC20 token implementation except for burning them.
 */
contract GraphCurationToken is ERC20, Governed {
    /**
     * @dev Graph Curation Token Contract Constructor.
     * @param _owner Address of the contract issuing this token
     */
    constructor(address _owner) ERC20("Graph Curation Share", "GCS") {
        Governed._initialize(_owner);
    }

    /**
     * @dev Mint new tokens.
     * @param _to Address to send the newly minted tokens
     * @param _amount Amount of tokens to mint
     */
    function mint(address _to, uint256 _amount) public onlyGovernor {
        _mint(_to, _amount);
    }

    /**
     * @dev Burn tokens from an address.
     * @param _account Address from where tokens will be burned
     * @param _amount Amount of tokens to burn
     */
    function burnFrom(address _account, uint256 _amount) public onlyGovernor {
        _burn(_account, _amount);
    }
}

File 8 of 20 : IGraphProxy.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.3;

interface IGraphProxy {
    function admin() external returns (address);

    function setAdmin(address _newAdmin) external;

    function implementation() external returns (address);

    function pendingImplementation() external returns (address);

    function upgradeTo(address _newImplementation) external;

    function acceptUpgrade() external;

    function acceptUpgradeAndCall(bytes calldata data) external;
}

File 9 of 20 : Managed.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.3;

import "./IManaged.sol";
import "./IController.sol";
import "../curation/ICuration.sol";
import "../epochs/IEpochManager.sol";
import "../rewards/IRewardsManager.sol";
import "../staking/IStaking.sol";
import "../token/IGraphToken.sol";

/**
 * @title Graph Managed contract
 * @dev The Managed contract provides an interface for contracts to interact with the Controller
 * Inspired by Livepeer:
 * https://github.com/livepeer/protocol/blob/streamflow/contracts/Controller.sol
 */
contract Managed {
    // Controller that contract is registered with
    IController public controller;
    mapping(bytes32 => address) public addressCache;
    uint256[10] private __gap;

    event ParameterUpdated(string param);
    event SetController(address controller);

    function _notPartialPaused() internal view {
        require(!controller.paused(), "Paused");
        require(!controller.partialPaused(), "Partial-paused");
    }

    function _notPaused() internal view {
        require(!controller.paused(), "Paused");
    }

    function _onlyGovernor() internal view {
        require(msg.sender == controller.getGovernor(), "Caller must be Controller governor");
    }

    modifier notPartialPaused {
        _notPartialPaused();
        _;
    }

    modifier notPaused {
        _notPaused();
        _;
    }

    // Check if sender is controller
    modifier onlyController() {
        require(msg.sender == address(controller), "Caller must be Controller");
        _;
    }

    modifier onlyGovernor() {
        _onlyGovernor();
        _;
    }

    /**
     * @dev Initialize the controller
     */
    function _initialize(address _controller) internal {
        _setController(_controller);
    }

    /**
     * @notice Set Controller. Only callable by current controller
     * @param _controller Controller contract address
     */
    function setController(address _controller) external onlyController {
        _setController(_controller);
    }

    /**
     * @dev Set controller.
     * @param _controller Controller contract address
     */
    function _setController(address _controller) internal {
        require(_controller != address(0), "Controller must be set");
        controller = IController(_controller);
        emit SetController(_controller);
    }

    /**
     * @dev Return Curation interface
     * @return Curation contract registered with Controller
     */
    function curation() internal view returns (ICuration) {
        return ICuration(controller.getContractProxy(keccak256("Curation")));
    }

    /**
     * @dev Return EpochManager interface
     * @return Epoch manager contract registered with Controller
     */
    function epochManager() internal view returns (IEpochManager) {
        return IEpochManager(controller.getContractProxy(keccak256("EpochManager")));
    }

    /**
     * @dev Return RewardsManager interface
     * @return Rewards manager contract registered with Controller
     */
    function rewardsManager() internal view returns (IRewardsManager) {
        return IRewardsManager(controller.getContractProxy(keccak256("RewardsManager")));
    }

    /**
     * @dev Return Staking interface
     * @return Staking contract registered with Controller
     */
    function staking() internal view returns (IStaking) {
        return IStaking(controller.getContractProxy(keccak256("Staking")));
    }

    /**
     * @dev Return GraphToken interface
     * @return Graph token contract registered with Controller
     */
    function graphToken() internal view returns (IGraphToken) {
        return IGraphToken(controller.getContractProxy(keccak256("GraphToken")));
    }
}

File 10 of 20 : IGraphCurationToken.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.3;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IGraphCurationToken is IERC20 {
    function burnFrom(address _account, uint256 _amount) external;

    function mint(address _to, uint256 _amount) external;
}

File 11 of 20 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

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

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

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

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

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

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

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

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

File 12 of 20 : IManaged.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.3;

interface IManaged {
    function setController(address _controller) external;
}

File 13 of 20 : IController.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.12 <0.8.0;

interface IController {
    function getGovernor() external view returns (address);

    // -- Registry --

    function setContractProxy(bytes32 _id, address _contractAddress) external;

    function unsetContractProxy(bytes32 _id) external;

    function updateController(bytes32 _id, address _controller) external;

    function getContractProxy(bytes32 _id) external view returns (address);

    // -- Pausing --

    function setPartialPaused(bool _partialPaused) external;

    function setPaused(bool _paused) external;

    function setPauseGuardian(address _newPauseGuardian) external;

    function paused() external view returns (bool);

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

File 14 of 20 : IEpochManager.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.3;

interface IEpochManager {
    // -- Configuration --

    function setEpochLength(uint256 _epochLength) external;

    // -- Epochs

    function runEpoch() external;

    // -- Getters --

    function isCurrentEpochRun() external view returns (bool);

    function blockNum() external view returns (uint256);

    function blockHash(uint256 _block) external view returns (bytes32);

    function currentEpoch() external view returns (uint256);

    function currentEpochBlock() external view returns (uint256);

    function currentEpochBlockSinceStart() external view returns (uint256);

    function epochsSince(uint256 _epoch) external view returns (uint256);

    function epochsSinceUpdate() external view returns (uint256);
}

File 15 of 20 : IRewardsManager.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.3;

interface IRewardsManager {
    /**
     * @dev Stores accumulated rewards and snapshots related to a particular SubgraphDeployment.
     */
    struct Subgraph {
        uint256 accRewardsForSubgraph;
        uint256 accRewardsForSubgraphSnapshot;
        uint256 accRewardsPerSignalSnapshot;
        uint256 accRewardsPerAllocatedToken;
    }

    // -- Params --

    function setIssuanceRate(uint256 _issuanceRate) external;

    // -- Denylist --

    function setSubgraphAvailabilityOracle(address _subgraphAvailabilityOracle) external;

    function setDenied(bytes32 _subgraphDeploymentID, bool _deny) external;

    function setDeniedMany(bytes32[] calldata _subgraphDeploymentID, bool[] calldata _deny)
        external;

    function isDenied(bytes32 _subgraphDeploymentID) external view returns (bool);

    // -- Getters --

    function getNewRewardsPerSignal() external view returns (uint256);

    function getAccRewardsPerSignal() external view returns (uint256);

    function getAccRewardsForSubgraph(bytes32 _subgraphDeploymentID)
        external
        view
        returns (uint256);

    function getAccRewardsPerAllocatedToken(bytes32 _subgraphDeploymentID)
        external
        view
        returns (uint256, uint256);

    function getRewards(address _allocationID) external view returns (uint256);

    // -- Updates --

    function updateAccRewardsPerSignal() external returns (uint256);

    function takeRewards(address _allocationID) external returns (uint256);

    // -- Hooks --

    function onSubgraphSignalUpdate(bytes32 _subgraphDeploymentID) external returns (uint256);

    function onSubgraphAllocationUpdate(bytes32 _subgraphDeploymentID) external returns (uint256);
}

File 16 of 20 : IStaking.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.12 <0.8.0;
pragma experimental ABIEncoderV2;

interface IStaking {
    // -- Allocation Data --

    /**
     * @dev Possible states an allocation can be
     * States:
     * - Null = indexer == address(0)
     * - Active = not Null && tokens > 0
     * - Closed = Active && closedAtEpoch != 0
     * - Finalized = Closed && closedAtEpoch + channelDisputeEpochs > now()
     * - Claimed = not Null && tokens == 0
     */
    enum AllocationState { Null, Active, Closed, Finalized, Claimed }

    /**
     * @dev Allocate GRT tokens for the purpose of serving queries of a subgraph deployment
     * An allocation is created in the allocate() function and consumed in claim()
     */
    struct Allocation {
        address indexer;
        bytes32 subgraphDeploymentID;
        uint256 tokens; // Tokens allocated to a SubgraphDeployment
        uint256 createdAtEpoch; // Epoch when it was created
        uint256 closedAtEpoch; // Epoch when it was closed
        uint256 collectedFees; // Collected fees for the allocation
        uint256 effectiveAllocation; // Effective allocation when closed
        uint256 accRewardsPerAllocatedToken; // Snapshot used for reward calc
    }

    /**
     * @dev Represents a request to close an allocation with a specific proof of indexing.
     * This is passed when calling closeAllocationMany to define the closing parameters for
     * each allocation.
     */
    struct CloseAllocationRequest {
        address allocationID;
        bytes32 poi;
    }

    // -- Delegation Data --

    /**
     * @dev Delegation pool information. One per indexer.
     */
    struct DelegationPool {
        uint32 cooldownBlocks; // Blocks to wait before updating parameters
        uint32 indexingRewardCut; // in PPM
        uint32 queryFeeCut; // in PPM
        uint256 updatedAtBlock; // Block when the pool was last updated
        uint256 tokens; // Total tokens as pool reserves
        uint256 shares; // Total shares minted in the pool
        mapping(address => Delegation) delegators; // Mapping of delegator => Delegation
    }

    /**
     * @dev Individual delegation data of a delegator in a pool.
     */
    struct Delegation {
        uint256 shares; // Shares owned by a delegator in the pool
        uint256 tokensLocked; // Tokens locked for undelegation
        uint256 tokensLockedUntil; // Block when locked tokens can be withdrawn
    }

    // -- Configuration --

    function setMinimumIndexerStake(uint256 _minimumIndexerStake) external;

    function setThawingPeriod(uint32 _thawingPeriod) external;

    function setCurationPercentage(uint32 _percentage) external;

    function setProtocolPercentage(uint32 _percentage) external;

    function setChannelDisputeEpochs(uint32 _channelDisputeEpochs) external;

    function setMaxAllocationEpochs(uint32 _maxAllocationEpochs) external;

    function setRebateRatio(uint32 _alphaNumerator, uint32 _alphaDenominator) external;

    function setDelegationRatio(uint32 _delegationRatio) external;

    function setDelegationParameters(
        uint32 _indexingRewardCut,
        uint32 _queryFeeCut,
        uint32 _cooldownBlocks
    ) external;

    function setDelegationParametersCooldown(uint32 _blocks) external;

    function setDelegationUnbondingPeriod(uint32 _delegationUnbondingPeriod) external;

    function setDelegationTaxPercentage(uint32 _percentage) external;

    function setSlasher(address _slasher, bool _allowed) external;

    function setAssetHolder(address _assetHolder, bool _allowed) external;

    // -- Operation --

    function setOperator(address _operator, bool _allowed) external;

    function isOperator(address _operator, address _indexer) external view returns (bool);

    // -- Staking --

    function stake(uint256 _tokens) external;

    function stakeTo(address _indexer, uint256 _tokens) external;

    function unstake(uint256 _tokens) external;

    function slash(
        address _indexer,
        uint256 _tokens,
        uint256 _reward,
        address _beneficiary
    ) external;

    function withdraw() external;

    // -- Delegation --

    function delegate(address _indexer, uint256 _tokens) external returns (uint256);

    function undelegate(address _indexer, uint256 _shares) external returns (uint256);

    function withdrawDelegated(address _indexer, address _newIndexer) external returns (uint256);

    // -- Channel management and allocations --

    function allocate(
        bytes32 _subgraphDeploymentID,
        uint256 _tokens,
        address _allocationID,
        bytes32 _metadata,
        bytes calldata _proof
    ) external;

    function allocateFrom(
        address _indexer,
        bytes32 _subgraphDeploymentID,
        uint256 _tokens,
        address _allocationID,
        bytes32 _metadata,
        bytes calldata _proof
    ) external;

    function closeAllocation(address _allocationID, bytes32 _poi) external;

    function closeAllocationMany(CloseAllocationRequest[] calldata _requests) external;

    function closeAndAllocate(
        address _oldAllocationID,
        bytes32 _poi,
        address _indexer,
        bytes32 _subgraphDeploymentID,
        uint256 _tokens,
        address _allocationID,
        bytes32 _metadata,
        bytes calldata _proof
    ) external;

    function collect(uint256 _tokens, address _allocationID) external;

    function claim(address _allocationID, bool _restake) external;

    function claimMany(address[] calldata _allocationID, bool _restake) external;

    // -- Getters and calculations --

    function hasStake(address _indexer) external view returns (bool);

    function getIndexerStakedTokens(address _indexer) external view returns (uint256);

    function getIndexerCapacity(address _indexer) external view returns (uint256);

    function getAllocation(address _allocationID) external view returns (Allocation memory);

    function getAllocationState(address _allocationID) external view returns (AllocationState);

    function isAllocation(address _allocationID) external view returns (bool);

    function getSubgraphAllocatedTokens(bytes32 _subgraphDeploymentID)
        external
        view
        returns (uint256);

    function getDelegation(address _indexer, address _delegator)
        external
        view
        returns (Delegation memory);

    function isDelegator(address _indexer, address _delegator) external view returns (bool);
}

File 17 of 20 : IGraphToken.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.3;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IGraphToken is IERC20 {
    // -- Mint and Burn --

    function burn(uint256 amount) external;

    function mint(address _to, uint256 _amount) external;

    // -- Mint Admin --

    function addMinter(address _account) external;

    function removeMinter(address _account) external;

    function renounceMinter() external;

    function isMinter(address _account) external view returns (bool);

    // -- Permit --

    function permit(
        address _owner,
        address _spender,
        uint256 _value,
        uint256 _deadline,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    ) external;
}

File 18 of 20 : ERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

import "../../GSN/Context.sol";
import "./IERC20.sol";
import "../../math/SafeMath.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of returning `false` on failure. This behavior is nonetheless conventional
 * and does not conflict with the expectations of ERC20 applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20 {
    using SafeMath for uint256;

    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;
    uint8 private _decimals;

    /**
     * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
     * a default value of 18.
     *
     * To select a different value for {decimals}, use {_setupDecimals}.
     *
     * All three of these values are immutable: they can only be set once during
     * construction.
     */
    constructor (string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
        _decimals = 18;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
     * called.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view returns (uint8) {
        return _decimals;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * Requirements:
     *
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for ``sender``'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
        return true;
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);

        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        emit Transfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
        _totalSupply = _totalSupply.sub(amount);
        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Sets {decimals} to a value other than the default one of 18.
     *
     * WARNING: This function should only be called from the constructor. Most
     * applications that interact with token contracts will not expect
     * {decimals} to ever change, and may work incorrectly if it does.
     */
    function _setupDecimals(uint8 decimals_) internal {
        _decimals = decimals_;
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be to transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}

File 19 of 20 : Governed.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.3;

/**
 * @title Graph Governance contract
 * @dev All contracts that will be owned by a Governor entity should extend this contract.
 */
contract Governed {
    // -- State --

    address public governor;
    address public pendingGovernor;

    // -- Events --

    event NewPendingOwnership(address indexed from, address indexed to);
    event NewOwnership(address indexed from, address indexed to);

    /**
     * @dev Check if the caller is the governor.
     */
    modifier onlyGovernor {
        require(msg.sender == governor, "Only Governor can call");
        _;
    }

    /**
     * @dev Initialize the governor to the contract caller.
     */
    function _initialize(address _initGovernor) internal {
        governor = _initGovernor;
    }

    /**
     * @dev Admin function to begin change of governor. The `_newGovernor` must call
     * `acceptOwnership` to finalize the transfer.
     * @param _newGovernor Address of new `governor`
     */
    function transferOwnership(address _newGovernor) external onlyGovernor {
        require(_newGovernor != address(0), "Governor must be set");

        address oldPendingGovernor = pendingGovernor;
        pendingGovernor = _newGovernor;

        emit NewPendingOwnership(oldPendingGovernor, pendingGovernor);
    }

    /**
     * @dev Admin function for pending governor to accept role and update governor.
     * This function must called by the pending governor.
     */
    function acceptOwnership() external {
        require(
            pendingGovernor != address(0) && msg.sender == pendingGovernor,
            "Caller must be pending governor"
        );

        address oldGovernor = governor;
        address oldPendingGovernor = pendingGovernor;

        governor = pendingGovernor;
        pendingGovernor = address(0);

        emit NewOwnership(oldGovernor, governor);
        emit NewPendingOwnership(oldPendingGovernor, pendingGovernor);
    }
}

File 20 of 20 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"curator","type":"address"},{"indexed":true,"internalType":"bytes32","name":"subgraphDeploymentID","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"signal","type":"uint256"}],"name":"Burned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"subgraphDeploymentID","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"Collected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"param","type":"string"}],"name":"ParameterUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"controller","type":"address"}],"name":"SetController","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"curator","type":"address"},{"indexed":true,"internalType":"bytes32","name":"subgraphDeploymentID","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"signal","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"curationTax","type":"uint256"}],"name":"Signalled","type":"event"},{"inputs":[{"internalType":"contract IGraphProxy","name":"_proxy","type":"address"}],"name":"acceptProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IGraphProxy","name":"_proxy","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"acceptProxyAndCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"addressCache","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bondingCurve","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_subgraphDeploymentID","type":"bytes32"},{"internalType":"uint256","name":"_signalIn","type":"uint256"},{"internalType":"uint256","name":"_tokensOutMin","type":"uint256"}],"name":"burn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_subgraphDeploymentID","type":"bytes32"},{"internalType":"uint256","name":"_tokens","type":"uint256"}],"name":"collect","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"contract IController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"curationTaxPercentage","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultReserveRatio","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_subgraphDeploymentID","type":"bytes32"}],"name":"getCurationPoolSignal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_subgraphDeploymentID","type":"bytes32"}],"name":"getCurationPoolTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curator","type":"address"},{"internalType":"bytes32","name":"_subgraphDeploymentID","type":"bytes32"}],"name":"getCuratorSignal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_controller","type":"address"},{"internalType":"address","name":"_bondingCurve","type":"address"},{"internalType":"uint32","name":"_defaultReserveRatio","type":"uint32"},{"internalType":"uint32","name":"_curationTaxPercentage","type":"uint32"},{"internalType":"uint256","name":"_minimumCurationDeposit","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_subgraphDeploymentID","type":"bytes32"}],"name":"isCurated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumCurationDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_subgraphDeploymentID","type":"bytes32"},{"internalType":"uint256","name":"_tokensIn","type":"uint256"},{"internalType":"uint256","name":"_signalOutMin","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"pools","outputs":[{"internalType":"uint256","name":"tokens","type":"uint256"},{"internalType":"uint32","name":"reserveRatio","type":"uint32"},{"internalType":"contract IGraphCurationToken","name":"gcs","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_controller","type":"address"}],"name":"setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_percentage","type":"uint32"}],"name":"setCurationTaxPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_defaultReserveRatio","type":"uint32"}],"name":"setDefaultReserveRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minimumCurationDeposit","type":"uint256"}],"name":"setMinimumCurationDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_subgraphDeploymentID","type":"bytes32"},{"internalType":"uint256","name":"_signalIn","type":"uint256"}],"name":"signalToTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_subgraphDeploymentID","type":"bytes32"},{"internalType":"uint256","name":"_tokensIn","type":"uint256"}],"name":"tokensToSignal","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b506136c0806100206000396000f3fe60806040523480156200001157600080fd5b50600436106200016c5760003560e01c80639ce7abe511620000d5578063dc675a651162000087578063dc675a6514620004cc578063eba0c8a11462000508578063eff1d50e146200052b578063f049b9001462000535578063f115c427146200055b578063f77c47911462000565576200016c565b80639ce7abe514620003585780639f94c66714620003dc578063a2594d82146200040b578063b5217bb41462000434578063cd0ad4a21462000480578063cd18119e14620004a6576200016c565b80634c4ea0ed116200012f5780634c4ea0ed14620002445780636536fe32146200027857806381573288146200029a57806392eefe9b14620002c057806399439fee14620002e95780639ae3824c1462000309576200016c565b80630faaf87f1462000171578063185360f914620001a957806324bdeec714620001b3578063375a54ab14620001df57806346e855da1462000224575b600080fd5b62000197600480360360408110156200018957600080fd5b50803590602001356200056f565b60408051918252519081900360200190f35b62000197620006f6565b6200019760048036036060811015620001cb57600080fd5b5080359060208101359060400135620006fc565b6200020b60048036036060811015620001f757600080fd5b508035906020810135906040013562000a0e565b6040805192835260208301919091528051918290030190f35b62000197600480360360208110156200023c57600080fd5b503562000dc2565b62000264600480360360208110156200025c57600080fd5b503562000dd7565b604080519115158252519081900360200190f35b62000298600480360360208110156200029057600080fd5b503562000deb565b005b6200029860048036036040811015620002b257600080fd5b508035906020013562000e03565b6200029860048036036020811015620002d857600080fd5b50356001600160a01b031662000eff565b62000197600480360360208110156200030157600080fd5b503562000f6a565b62000298600480360360a08110156200032157600080fd5b506001600160a01b03813581169160208101359091169063ffffffff60408201358116916060810135909116906080013562001031565b62000298600480360360408110156200037057600080fd5b6001600160a01b038235169190810190604081016020820135600160201b8111156200039b57600080fd5b820183602082011115620003ae57600080fd5b803590602001918460018302840111600160201b83111715620003d057600080fd5b50909250905062001136565b6200019760048036036040811015620003f457600080fd5b506001600160a01b03813516906020013562001292565b62000298600480360360208110156200042357600080fd5b50356001600160a01b03166200135a565b62000454600480360360208110156200044c57600080fd5b50356200147b565b6040805193845263ffffffff90921660208401526001600160a01b031682820152519081900360600190f35b62000298600480360360208110156200049857600080fd5b503563ffffffff16620014ac565b6200029860048036036020811015620004be57600080fd5b503563ffffffff16620014c1565b620004ec60048036036020811015620004e457600080fd5b5035620014d6565b604080516001600160a01b039092168252519081900360200190f35b62000512620014f1565b6040805163ffffffff9092168252519081900360200190f35b620004ec62001504565b6200020b600480360360408110156200054d57600080fd5b508035906020013562001513565b620005126200156c565b620004ec62001578565b60006200057b6200217d565b506000838152600f6020908152604080832081516060810183528154815260019091015463ffffffff811693820193909352600160201b9092046001600160a01b03169082015290620005ce8562000f6a565b8251909150620006105760405162461bcd60e51b815260040180806020018281038252603b815260200180620034f7603b913960400191505060405180910390fd5b83811015620006515760405162461bcd60e51b8152600401808060200182810382526043815260200180620034b46043913960600191505060405180910390fd5b600e548251602080850151604080516349f9b0f760e01b815260048101879052602481019490945263ffffffff909116604484015260648301889052516001600160a01b03909316926349f9b0f7926084808201939291829003018186803b158015620006bd57600080fd5b505afa158015620006d2573d6000803e3d6000fd5b505050506040513d6020811015620006e957600080fd5b5051925050505b92915050565b600d5481565b60006200070862001587565b33836200075c576040805162461bcd60e51b815260206004820152601760248201527f43616e6e6f74206275726e207a65726f207369676e616c000000000000000000604482015290519081900360640190fd5b8362000769828762001292565b1015620007a85760405162461bcd60e51b8152600401808060200182810382526024815260200180620034906024913960400191505060405180910390fd5b6000620007b686866200056f565b90508381101562000804576040805162461bcd60e51b815260206004820152601360248201527229b634b83830b3b290383937ba32b1ba34b7b760691b604482015290519081900360640190fd5b6200080f86620016ff565b6000868152600f6020526040902080546200082b908362001797565b815560018101546040805163079cc67960e41b81526001600160a01b038681166004830152602482018a90529151600160201b909304909116916379cc67909160448082019260009290919082900301818387803b1580156200088d57600080fd5b505af1158015620008a2573d6000803e3d6000fd5b50505050620008b18762000f6a565b620008d9576000878152600f6020526040812090815560010180546001600160c01b03191690555b620008e3620017e2565b6001600160a01b031663a9059cbb84846040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b1580156200093a57600080fd5b505af11580156200094f573d6000803e3d6000fd5b505050506040513d60208110156200096657600080fd5b5051620009ba576040805162461bcd60e51b815260206004820152601c60248201527f4572726f722073656e64696e672063757261746f7220746f6b656e7300000000604482015290519081900360640190fd5b86836001600160a01b03167fe14cd5e80f6821ded0538e85a537487acf10bb5e97a12176df56a099e90bfb348489604051808381526020018281526020019250505060405180910390a35095945050505050565b60008062000a1b62001587565b6000841162000a71576040805162461bcd60e51b815260206004820152601a60248201527f43616e6e6f74206465706f736974207a65726f20746f6b656e73000000000000604482015290519081900360640190fd5b60008062000a80878762001513565b915091508482101562000ad0576040805162461bcd60e51b815260206004820152601360248201527229b634b83830b3b290383937ba32b1ba34b7b760691b604482015290519081900360640190fd5b6000878152600f60205260409020339062000aeb8962000dd7565b62000b8a57600c5460018201805463ffffffff191663ffffffff600160201b93849004161790819055046001600160a01b031662000b8a573060405162000b32906200219d565b6001600160a01b03909116815260405190819003602001906000f08015801562000b60573d6000803e3d6000fd5b508160010160046101000a8154816001600160a01b0302191690836001600160a01b031602179055505b62000b9589620016ff565b600062000ba1620017e2565b604080516323b872dd60e01b81526001600160a01b038681166004830152306024830152604482018d90529151929350908316916323b872dd916064808201926020929091908290030181600087803b15801562000bfe57600080fd5b505af115801562000c13573d6000803e3d6000fd5b505050506040513d602081101562000c2a57600080fd5b505162000c695760405162461bcd60e51b81526004018080602001828103825260218152602001806200366a6021913960400191505060405180910390fd5b831562000cd157806001600160a01b03166342966c68856040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801562000cb757600080fd5b505af115801562000ccc573d6000803e3d6000fd5b505050505b62000cea62000ce18a8662001797565b83549062001882565b82556001820154604080516340c10f1960e01b81526001600160a01b038681166004830152602482018990529151600160201b909304909116916340c10f199160448082019260009290919082900301818387803b15801562000d4c57600080fd5b505af115801562000d61573d6000803e3d6000fd5b5050604080518c81526020810189905280820188905290518d93506001600160a01b03871692507fb7bf5f4e5b23ef992df9875ecea572620d18dab0c1a5486a9b695d20d9ec50cf9181900360600190a35092989197509095505050505050565b6000818152600f60205260409020545b919050565b6000908152600f6020526040902054151590565b62000df5620018dd565b62000e0081620019a0565b50565b62000e0d62001a42565b6001600160a01b0316336001600160a01b03161462000e5e5760405162461bcd60e51b8152600401808060200182810382526023815260200180620035ed6023913960400191505060405180910390fd5b62000e698262000dd7565b62000ea65760405162461bcd60e51b81526004018080602001828103825260338152602001806200345d6033913960400191505060405180910390fd5b6000828152600f60205260409020805462000ec2908362001882565b815560408051838152905184917ff17fdee613a92b35db6b7598eb43750b24d4072eb304e6eca80121e40402e34b919081900360200190a2505050565b6000546001600160a01b0316331462000f5f576040805162461bcd60e51b815260206004820152601960248201527f43616c6c6572206d75737420626520436f6e74726f6c6c657200000000000000604482015290519081900360640190fd5b62000e008162001aaf565b6000818152600f6020526040812060010154600160201b90046001600160a01b031662000f9a5750600062000dd2565b600f600083815260200190815260200160002060010160049054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801562000ffd57600080fd5b505afa15801562001012573d6000803e3d6000fd5b505050506040513d60208110156200102957600080fd5b505192915050565b6200103b62001b58565b6001600160a01b0316336001600160a01b0316146200108c5760405162461bcd60e51b8152600401808060200182810382526021815260200180620036496021913960400191505060405180910390fd5b620010978562000f5f565b6001600160a01b038416620010f3576040805162461bcd60e51b815260206004820152601960248201527f426f6e64696e67206375727665206d7573742062652073657400000000000000604482015290519081900360640190fd5b600e80546001600160a01b0319166001600160a01b038616179055620011198362001b7d565b620011248262001c87565b6200112f81620019a0565b5050505050565b82806001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156200117357600080fd5b505af115801562001188573d6000803e3d6000fd5b505050506040513d60208110156200119f57600080fd5b50516001600160a01b03163314620011fe576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206d757374206265207468652070726f78792061646d696e0000604482015290519081900360640190fd5b60405163623faf6160e01b8152602060048201908152602482018490526001600160a01b0386169163623faf619186918691908190604401848480828437600081840152601f19601f8201169050808301925050509350505050600060405180830381600087803b1580156200127357600080fd5b505af115801562001288573d6000803e3d6000fd5b5050505050505050565b6000818152600f6020526040812060010154600160201b90046001600160a01b0316620012c257506000620006f0565b6000828152600f60209081526040918290206001015482516370a0823160e01b81526001600160a01b0387811660048301529351600160201b909204909316926370a08231926024808301939192829003018186803b1580156200132557600080fd5b505afa1580156200133a573d6000803e3d6000fd5b505050506040513d60208110156200135157600080fd5b50519392505050565b80806001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156200139757600080fd5b505af1158015620013ac573d6000803e3d6000fd5b505050506040513d6020811015620013c357600080fd5b50516001600160a01b0316331462001422576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206d757374206265207468652070726f78792061646d696e0000604482015290519081900360640190fd5b816001600160a01b03166359fc20bb6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200145e57600080fd5b505af115801562001473573d6000803e3d6000fd5b505050505050565b600f602052600090815260409020805460019091015463ffffffff811690600160201b90046001600160a01b031683565b620014b6620018dd565b62000e008162001b7d565b620014cb620018dd565b62000e008162001c87565b6001602052600090815260409020546001600160a01b031681565b600c54600160201b900463ffffffff1681565b600e546001600160a01b031681565b600c54600090819081906200154590620f4240906200153e90879063ffffffff9081169062001d4216565b9062001da0565b9050600062001560866200155a878562001797565b62001de4565b96919550909350505050565b600c5463ffffffff1690565b6000546001600160a01b031681565b60008054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b815260040160206040518083038186803b158015620015d457600080fd5b505afa158015620015e9573d6000803e3d6000fd5b505050506040513d60208110156200160057600080fd5b5051156200163e576040805162461bcd60e51b815260206004820152600660248201526514185d5cd95960d21b604482015290519081900360640190fd5b60008054906101000a90046001600160a01b03166001600160a01b0316632e292fc76040518163ffffffff1660e01b815260040160206040518083038186803b1580156200168b57600080fd5b505afa158015620016a0573d6000803e3d6000fd5b505050506040513d6020811015620016b757600080fd5b505115620016fd576040805162461bcd60e51b815260206004820152600e60248201526d14185c9d1a585b0b5c185d5cd95960921b604482015290519081900360640190fd5b565b60006200170b6200200c565b90506001600160a01b038116156200179357806001600160a01b0316631d1c2fec836040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b1580156200176457600080fd5b505af115801562001779573d6000803e3d6000fd5b505050506040513d60208110156200179057600080fd5b50505b5050565b6000620017db83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525062002079565b9392505050565b6000805460408051637bb20d2f60e11b81527f45fc200c7e4544e457d3c5709bfe0d520442c30bbcbdaede89e8d4a4bbc19247600482015290516001600160a01b039092169163f7641a5e91602480820192602092909190829003018186803b1580156200184f57600080fd5b505afa15801562001864573d6000803e3d6000fd5b505050506040513d60208110156200187b57600080fd5b5051905090565b600082820183811015620017db576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60008054906101000a90046001600160a01b03166001600160a01b0316634fc07d756040518163ffffffff1660e01b815260040160206040518083038186803b1580156200192a57600080fd5b505afa1580156200193f573d6000803e3d6000fd5b505050506040513d60208110156200195657600080fd5b50516001600160a01b03163314620016fd5760405162461bcd60e51b8152600401808060200182810382526022815260200180620035776022913960400191505060405180910390fd5b60008111620019e15760405162461bcd60e51b8152600401808060200182810382526024815260200180620035326024913960400191505060405180910390fd5b600d819055604080516020808252601690820152751b5a5b9a5b5d5b50dd5c985d1a5bdb91195c1bdcda5d60521b8183015290517f96d5a4b4edf1cefd0900c166d64447f8da1d01d1861a6a60894b5b82a2c15c3c9181900360600190a150565b6000805460408051637bb20d2f60e11b81527f1df41cd916959d1163dc8f0671a666ea8a3e434c13e40faef527133b5d167034600482015290516001600160a01b039092169163f7641a5e91602480820192602092909190829003018186803b1580156200184f57600080fd5b6001600160a01b03811662001b04576040805162461bcd60e51b815260206004820152601660248201527510dbdb9d1c9bdb1b195c881b5d5cdd081899481cd95d60521b604482015290519081900360640190fd5b600080546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f4ff638452bbf33c012645d18ae6f05515ff5f2d1dfb0cece8cbf018c60903f709181900360200190a150565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b60008163ffffffff161162001bc45760405162461bcd60e51b8152600401808060200182810382526021815260200180620035996021913960400191505060405180910390fd5b620f424063ffffffff8216111562001c0e5760405162461bcd60e51b8152600401808060200182810382526033815260200180620035ba6033913960400191505060405180910390fd5b600c805467ffffffff000000001916600160201b63ffffffff8416021790556040805160208082526013908201527264656661756c7452657365727665526174696f60681b8183015290517f96d5a4b4edf1cefd0900c166d64447f8da1d01d1861a6a60894b5b82a2c15c3c916060908290030190a150565b620f424063ffffffff8216111562001cd15760405162461bcd60e51b8152600401808060200182810382526039815260200180620036106039913960400191505060405180910390fd5b600c805463ffffffff191663ffffffff8316179055604080516020808252601590820152746375726174696f6e54617850657263656e7461676560581b8183015290517f96d5a4b4edf1cefd0900c166d64447f8da1d01d1861a6a60894b5b82a2c15c3c916060908290030190a150565b60008262001d5357506000620006f0565b8282028284828162001d6157fe5b0414620017db5760405162461bcd60e51b8152600401808060200182810382526021815260200180620035566021913960400191505060405180910390fd5b6000620017db83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525062002114565b600062001df06200217d565b506000838152600f60209081526040918290208251606081018452815480825260019092015463ffffffff811693820193909352600160201b9092046001600160a01b0316928201929092529062001f5f57600d5483101562001e855760405162461bcd60e51b815260040180806020018281038252602a81526020018062003433602a913960400191505060405180910390fd5b600e54600d54600c5462001f5692670de0b6b3a7640000926001600160a01b03909116916329a00e7c91849163ffffffff600160201b90910481169062001ed1908b9084906200179716565b6040518563ffffffff1660e01b8152600401808581526020018481526020018363ffffffff16815260200182815260200194505050505060206040518083038186803b15801562001f2157600080fd5b505afa15801562001f36573d6000803e3d6000fd5b505050506040513d602081101562001f4d57600080fd5b50519062001882565b915050620006f0565b600e546001600160a01b03166329a00e7c62001f7b8662000f6a565b83600001518460200151876040518563ffffffff1660e01b8152600401808581526020018481526020018363ffffffff16815260200182815260200194505050505060206040518083038186803b15801562001fd657600080fd5b505afa15801562001feb573d6000803e3d6000fd5b505050506040513d60208110156200200257600080fd5b5051949350505050565b6000805460408051637bb20d2f60e11b81527f966f1e8d8d8014e05f6ec4a57138da9be1f7c5a7f802928a18072f7c53180761600482015290516001600160a01b039092169163f7641a5e91602480820192602092909190829003018186803b1580156200184f57600080fd5b600081848411156200210c5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620020d0578181015183820152602001620020b6565b50505050905090810190601f168015620020fe5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b60008183620021665760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315620020d0578181015183820152602001620020b6565b5060008385816200217357fe5b0495945050505050565b604080516060810182526000808252602082018190529181019190915290565b61128780620021ac8339019056fe60806040523480156200001157600080fd5b506040516200128738038062001287833981810160405260208110156200003757600080fd5b5051604080518082018252601481527f4772617068204375726174696f6e2053686172650000000000000000000000006020828101918252835180850190945260038085526247435360e81b9185019190915282519293926200009b929062000109565b508051620000b190600490602084019062000109565b505060058054601260ff1990911617905550620000da81620000e1602090811b620009aa17901c565b50620001b5565b600580546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b828054600181600116156101000203166002900490600052602060002090601f0160209004810192826200014157600085556200018c565b82601f106200015c57805160ff19168380011785556200018c565b828001600101855582156200018c579182015b828111156200018c5782518255916020019190600101906200016f565b506200019a9291506200019e565b5090565b5b808211156200019a57600081556001016200019f565b6110c280620001c56000396000f3fe608060405234801561001057600080fd5b506004361061010b5760003560e01c806370a08231116100a2578063a457c2d711610071578063a457c2d71461031b578063a9059cbb14610347578063dd62ed3e14610373578063e3056a34146103a1578063f2fde38b146103a95761010b565b806370a08231146102b957806379ba5097146102df57806379cc6790146102e757806395d89b41146103135761010b565b806323b872dd116100de57806323b872dd1461020b578063313ce56714610241578063395093511461025f57806340c10f191461028b5761010b565b806306fdde0314610110578063095ea7b31461018d5780630c340a24146101cd57806318160ddd146101f1575b600080fd5b6101186103cf565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561015257818101518382015260200161013a565b50505050905090810190601f16801561017f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101b9600480360360408110156101a357600080fd5b506001600160a01b038135169060200135610465565b604080519115158252519081900360200190f35b6101d5610482565b604080516001600160a01b039092168252519081900360200190f35b6101f9610496565b60408051918252519081900360200190f35b6101b96004803603606081101561022157600080fd5b506001600160a01b0381358116916020810135909116906040013561049c565b610249610523565b6040805160ff9092168252519081900360200190f35b6101b96004803603604081101561027557600080fd5b506001600160a01b03813516906020013561052c565b6102b7600480360360408110156102a157600080fd5b506001600160a01b03813516906020013561057a565b005b6101f9600480360360208110156102cf57600080fd5b50356001600160a01b03166105e5565b6102b7610600565b6102b7600480360360408110156102fd57600080fd5b506001600160a01b038135169060200135610729565b610118610790565b6101b96004803603604081101561033157600080fd5b506001600160a01b0381351690602001356107f1565b6101b96004803603604081101561035d57600080fd5b506001600160a01b038135169060200135610859565b6101f96004803603604081101561038957600080fd5b506001600160a01b038135811691602001351661086d565b6101d5610898565b6102b7600480360360208110156103bf57600080fd5b50356001600160a01b03166108a7565b60038054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561045b5780601f106104305761010080835404028352916020019161045b565b820191906000526020600020905b81548152906001019060200180831161043e57829003601f168201915b5050505050905090565b60006104796104726109d2565b84846109d6565b50600192915050565b60055461010090046001600160a01b031681565b60025490565b60006104a9848484610ac2565b610519846104b56109d2565b61051485604051806060016040528060288152602001610fd6602891396001600160a01b038a166000908152600160205260408120906104f36109d2565b6001600160a01b031681526020810191909152604001600020549190610c1d565b6109d6565b5060019392505050565b60055460ff1690565b60006104796105396109d2565b84610514856001600061054a6109d2565b6001600160a01b03908116825260208083019390935260409182016000908120918c168152925290205490610cb4565b60055461010090046001600160a01b031633146105d7576040805162461bcd60e51b815260206004820152601660248201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604482015290519081900360640190fd5b6105e18282610d15565b5050565b6001600160a01b031660009081526020819052604090205490565b6006546001600160a01b03161580159061062457506006546001600160a01b031633145b610675576040805162461bcd60e51b815260206004820152601f60248201527f43616c6c6572206d7573742062652070656e64696e6720676f7665726e6f7200604482015290519081900360640190fd5b60058054600680546001600160a01b03818116610100818102610100600160a81b0319871617968790556001600160a01b0319909316909355604051938290048116949293919092049091169083907f0ac6deed30eef60090c749850e10f2fa469e3e25fec1d1bef2853003f6e6f18f90600090a36006546040516001600160a01b03918216918316907f76563ad561b7036ae716b9b25cb521b21463240f104c97e12f25877f2235f33d90600090a35050565b60055461010090046001600160a01b03163314610786576040805162461bcd60e51b815260206004820152601660248201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604482015290519081900360640190fd5b6105e18282610e05565b60048054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561045b5780601f106104305761010080835404028352916020019161045b565b60006104796107fe6109d2565b846105148560405180606001604052806025815260200161106860259139600160006108286109d2565b6001600160a01b03908116825260208083019390935260409182016000908120918d16815292529020549190610c1d565b60006104796108666109d2565b8484610ac2565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6006546001600160a01b031681565b60055461010090046001600160a01b03163314610904576040805162461bcd60e51b815260206004820152601660248201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604482015290519081900360640190fd5b6001600160a01b038116610956576040805162461bcd60e51b815260206004820152601460248201527311dbdd995c9b9bdc881b5d5cdd081899481cd95d60621b604482015290519081900360640190fd5b600680546001600160a01b038381166001600160a01b03198316179283905560405191811692169082907f76563ad561b7036ae716b9b25cb521b21463240f104c97e12f25877f2235f33d90600090a35050565b600580546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b3390565b6001600160a01b038316610a1b5760405162461bcd60e51b81526004018080602001828103825260248152602001806110446024913960400191505060405180910390fd5b6001600160a01b038216610a605760405162461bcd60e51b8152600401808060200182810382526022815260200180610f8e6022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b038316610b075760405162461bcd60e51b815260040180806020018281038252602581526020018061101f6025913960400191505060405180910390fd5b6001600160a01b038216610b4c5760405162461bcd60e51b8152600401808060200182810382526023815260200180610f496023913960400191505060405180910390fd5b610b57838383610f01565b610b9481604051806060016040528060268152602001610fb0602691396001600160a01b0386166000908152602081905260409020549190610c1d565b6001600160a01b038085166000908152602081905260408082209390935590841681522054610bc39082610cb4565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b60008184841115610cac5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610c71578181015183820152602001610c59565b50505050905090810190601f168015610c9e5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600082820183811015610d0e576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6001600160a01b038216610d70576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b610d7c60008383610f01565b600254610d899082610cb4565b6002556001600160a01b038216600090815260208190526040902054610daf9082610cb4565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6001600160a01b038216610e4a5760405162461bcd60e51b8152600401808060200182810382526021815260200180610ffe6021913960400191505060405180910390fd5b610e5682600083610f01565b610e9381604051806060016040528060228152602001610f6c602291396001600160a01b0385166000908152602081905260409020549190610c1d565b6001600160a01b038316600090815260208190526040902055600254610eb99082610f06565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b505050565b6000610d0e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250610c1d56fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa26469706673582212204cb1015622950d635ba48cf5ee6af298ab114e15b9265ae471beca741183788564736f6c634300070400334375726174696f6e206465706f7369742069732062656c6f77206d696e696d756d2072657175697265645375626772617068206465706c6f796d656e74206d757374206265206375726174656420746f20636f6c6c656374206665657343616e6e6f74206275726e206d6f7265207369676e616c207468616e20796f75206f776e5369676e616c206d7573742062652061626f7665206f7220657175616c20746f207369676e616c2069737375656420696e20746865206375726174696f6e20706f6f6c5375626772617068206465706c6f796d656e74206d757374206265206375726174656420746f20706572666f726d2063616c63756c6174696f6e734d696e696d756d206375726174696f6e206465706f7369742063616e6e6f742062652030536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7743616c6c6572206d75737420626520436f6e74726f6c6c657220676f7665726e6f7244656661756c74207265736572766520726174696f206d757374206265203e203044656661756c74207265736572766520726174696f2063616e6e6f7420626520686967686572207468616e204d41585f50504d43616c6c6572206d75737420626520746865207374616b696e6720636f6e74726163744375726174696f6e207461782070657263656e74616765206d7573742062652062656c6f77206f7220657175616c20746f204d41585f50504d43616c6c6572206d7573742062652074686520696d706c656d656e746174696f6e43616e6e6f74207472616e7366657220746f6b656e7320746f206465706f736974a26469706673582212206264c30885d86e62b7838b4a997d40aae88812e93904b3faf9131cf287eaf3de64736f6c63430007040033

Deployed Bytecode

0x60806040523480156200001157600080fd5b50600436106200016c5760003560e01c80639ce7abe511620000d5578063dc675a651162000087578063dc675a6514620004cc578063eba0c8a11462000508578063eff1d50e146200052b578063f049b9001462000535578063f115c427146200055b578063f77c47911462000565576200016c565b80639ce7abe514620003585780639f94c66714620003dc578063a2594d82146200040b578063b5217bb41462000434578063cd0ad4a21462000480578063cd18119e14620004a6576200016c565b80634c4ea0ed116200012f5780634c4ea0ed14620002445780636536fe32146200027857806381573288146200029a57806392eefe9b14620002c057806399439fee14620002e95780639ae3824c1462000309576200016c565b80630faaf87f1462000171578063185360f914620001a957806324bdeec714620001b3578063375a54ab14620001df57806346e855da1462000224575b600080fd5b62000197600480360360408110156200018957600080fd5b50803590602001356200056f565b60408051918252519081900360200190f35b62000197620006f6565b6200019760048036036060811015620001cb57600080fd5b5080359060208101359060400135620006fc565b6200020b60048036036060811015620001f757600080fd5b508035906020810135906040013562000a0e565b6040805192835260208301919091528051918290030190f35b62000197600480360360208110156200023c57600080fd5b503562000dc2565b62000264600480360360208110156200025c57600080fd5b503562000dd7565b604080519115158252519081900360200190f35b62000298600480360360208110156200029057600080fd5b503562000deb565b005b6200029860048036036040811015620002b257600080fd5b508035906020013562000e03565b6200029860048036036020811015620002d857600080fd5b50356001600160a01b031662000eff565b62000197600480360360208110156200030157600080fd5b503562000f6a565b62000298600480360360a08110156200032157600080fd5b506001600160a01b03813581169160208101359091169063ffffffff60408201358116916060810135909116906080013562001031565b62000298600480360360408110156200037057600080fd5b6001600160a01b038235169190810190604081016020820135600160201b8111156200039b57600080fd5b820183602082011115620003ae57600080fd5b803590602001918460018302840111600160201b83111715620003d057600080fd5b50909250905062001136565b6200019760048036036040811015620003f457600080fd5b506001600160a01b03813516906020013562001292565b62000298600480360360208110156200042357600080fd5b50356001600160a01b03166200135a565b62000454600480360360208110156200044c57600080fd5b50356200147b565b6040805193845263ffffffff90921660208401526001600160a01b031682820152519081900360600190f35b62000298600480360360208110156200049857600080fd5b503563ffffffff16620014ac565b6200029860048036036020811015620004be57600080fd5b503563ffffffff16620014c1565b620004ec60048036036020811015620004e457600080fd5b5035620014d6565b604080516001600160a01b039092168252519081900360200190f35b62000512620014f1565b6040805163ffffffff9092168252519081900360200190f35b620004ec62001504565b6200020b600480360360408110156200054d57600080fd5b508035906020013562001513565b620005126200156c565b620004ec62001578565b60006200057b6200217d565b506000838152600f6020908152604080832081516060810183528154815260019091015463ffffffff811693820193909352600160201b9092046001600160a01b03169082015290620005ce8562000f6a565b8251909150620006105760405162461bcd60e51b815260040180806020018281038252603b815260200180620034f7603b913960400191505060405180910390fd5b83811015620006515760405162461bcd60e51b8152600401808060200182810382526043815260200180620034b46043913960600191505060405180910390fd5b600e548251602080850151604080516349f9b0f760e01b815260048101879052602481019490945263ffffffff909116604484015260648301889052516001600160a01b03909316926349f9b0f7926084808201939291829003018186803b158015620006bd57600080fd5b505afa158015620006d2573d6000803e3d6000fd5b505050506040513d6020811015620006e957600080fd5b5051925050505b92915050565b600d5481565b60006200070862001587565b33836200075c576040805162461bcd60e51b815260206004820152601760248201527f43616e6e6f74206275726e207a65726f207369676e616c000000000000000000604482015290519081900360640190fd5b8362000769828762001292565b1015620007a85760405162461bcd60e51b8152600401808060200182810382526024815260200180620034906024913960400191505060405180910390fd5b6000620007b686866200056f565b90508381101562000804576040805162461bcd60e51b815260206004820152601360248201527229b634b83830b3b290383937ba32b1ba34b7b760691b604482015290519081900360640190fd5b6200080f86620016ff565b6000868152600f6020526040902080546200082b908362001797565b815560018101546040805163079cc67960e41b81526001600160a01b038681166004830152602482018a90529151600160201b909304909116916379cc67909160448082019260009290919082900301818387803b1580156200088d57600080fd5b505af1158015620008a2573d6000803e3d6000fd5b50505050620008b18762000f6a565b620008d9576000878152600f6020526040812090815560010180546001600160c01b03191690555b620008e3620017e2565b6001600160a01b031663a9059cbb84846040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b1580156200093a57600080fd5b505af11580156200094f573d6000803e3d6000fd5b505050506040513d60208110156200096657600080fd5b5051620009ba576040805162461bcd60e51b815260206004820152601c60248201527f4572726f722073656e64696e672063757261746f7220746f6b656e7300000000604482015290519081900360640190fd5b86836001600160a01b03167fe14cd5e80f6821ded0538e85a537487acf10bb5e97a12176df56a099e90bfb348489604051808381526020018281526020019250505060405180910390a35095945050505050565b60008062000a1b62001587565b6000841162000a71576040805162461bcd60e51b815260206004820152601a60248201527f43616e6e6f74206465706f736974207a65726f20746f6b656e73000000000000604482015290519081900360640190fd5b60008062000a80878762001513565b915091508482101562000ad0576040805162461bcd60e51b815260206004820152601360248201527229b634b83830b3b290383937ba32b1ba34b7b760691b604482015290519081900360640190fd5b6000878152600f60205260409020339062000aeb8962000dd7565b62000b8a57600c5460018201805463ffffffff191663ffffffff600160201b93849004161790819055046001600160a01b031662000b8a573060405162000b32906200219d565b6001600160a01b03909116815260405190819003602001906000f08015801562000b60573d6000803e3d6000fd5b508160010160046101000a8154816001600160a01b0302191690836001600160a01b031602179055505b62000b9589620016ff565b600062000ba1620017e2565b604080516323b872dd60e01b81526001600160a01b038681166004830152306024830152604482018d90529151929350908316916323b872dd916064808201926020929091908290030181600087803b15801562000bfe57600080fd5b505af115801562000c13573d6000803e3d6000fd5b505050506040513d602081101562000c2a57600080fd5b505162000c695760405162461bcd60e51b81526004018080602001828103825260218152602001806200366a6021913960400191505060405180910390fd5b831562000cd157806001600160a01b03166342966c68856040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801562000cb757600080fd5b505af115801562000ccc573d6000803e3d6000fd5b505050505b62000cea62000ce18a8662001797565b83549062001882565b82556001820154604080516340c10f1960e01b81526001600160a01b038681166004830152602482018990529151600160201b909304909116916340c10f199160448082019260009290919082900301818387803b15801562000d4c57600080fd5b505af115801562000d61573d6000803e3d6000fd5b5050604080518c81526020810189905280820188905290518d93506001600160a01b03871692507fb7bf5f4e5b23ef992df9875ecea572620d18dab0c1a5486a9b695d20d9ec50cf9181900360600190a35092989197509095505050505050565b6000818152600f60205260409020545b919050565b6000908152600f6020526040902054151590565b62000df5620018dd565b62000e0081620019a0565b50565b62000e0d62001a42565b6001600160a01b0316336001600160a01b03161462000e5e5760405162461bcd60e51b8152600401808060200182810382526023815260200180620035ed6023913960400191505060405180910390fd5b62000e698262000dd7565b62000ea65760405162461bcd60e51b81526004018080602001828103825260338152602001806200345d6033913960400191505060405180910390fd5b6000828152600f60205260409020805462000ec2908362001882565b815560408051838152905184917ff17fdee613a92b35db6b7598eb43750b24d4072eb304e6eca80121e40402e34b919081900360200190a2505050565b6000546001600160a01b0316331462000f5f576040805162461bcd60e51b815260206004820152601960248201527f43616c6c6572206d75737420626520436f6e74726f6c6c657200000000000000604482015290519081900360640190fd5b62000e008162001aaf565b6000818152600f6020526040812060010154600160201b90046001600160a01b031662000f9a5750600062000dd2565b600f600083815260200190815260200160002060010160049054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801562000ffd57600080fd5b505afa15801562001012573d6000803e3d6000fd5b505050506040513d60208110156200102957600080fd5b505192915050565b6200103b62001b58565b6001600160a01b0316336001600160a01b0316146200108c5760405162461bcd60e51b8152600401808060200182810382526021815260200180620036496021913960400191505060405180910390fd5b620010978562000f5f565b6001600160a01b038416620010f3576040805162461bcd60e51b815260206004820152601960248201527f426f6e64696e67206375727665206d7573742062652073657400000000000000604482015290519081900360640190fd5b600e80546001600160a01b0319166001600160a01b038616179055620011198362001b7d565b620011248262001c87565b6200112f81620019a0565b5050505050565b82806001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156200117357600080fd5b505af115801562001188573d6000803e3d6000fd5b505050506040513d60208110156200119f57600080fd5b50516001600160a01b03163314620011fe576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206d757374206265207468652070726f78792061646d696e0000604482015290519081900360640190fd5b60405163623faf6160e01b8152602060048201908152602482018490526001600160a01b0386169163623faf619186918691908190604401848480828437600081840152601f19601f8201169050808301925050509350505050600060405180830381600087803b1580156200127357600080fd5b505af115801562001288573d6000803e3d6000fd5b5050505050505050565b6000818152600f6020526040812060010154600160201b90046001600160a01b0316620012c257506000620006f0565b6000828152600f60209081526040918290206001015482516370a0823160e01b81526001600160a01b0387811660048301529351600160201b909204909316926370a08231926024808301939192829003018186803b1580156200132557600080fd5b505afa1580156200133a573d6000803e3d6000fd5b505050506040513d60208110156200135157600080fd5b50519392505050565b80806001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156200139757600080fd5b505af1158015620013ac573d6000803e3d6000fd5b505050506040513d6020811015620013c357600080fd5b50516001600160a01b0316331462001422576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206d757374206265207468652070726f78792061646d696e0000604482015290519081900360640190fd5b816001600160a01b03166359fc20bb6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200145e57600080fd5b505af115801562001473573d6000803e3d6000fd5b505050505050565b600f602052600090815260409020805460019091015463ffffffff811690600160201b90046001600160a01b031683565b620014b6620018dd565b62000e008162001b7d565b620014cb620018dd565b62000e008162001c87565b6001602052600090815260409020546001600160a01b031681565b600c54600160201b900463ffffffff1681565b600e546001600160a01b031681565b600c54600090819081906200154590620f4240906200153e90879063ffffffff9081169062001d4216565b9062001da0565b9050600062001560866200155a878562001797565b62001de4565b96919550909350505050565b600c5463ffffffff1690565b6000546001600160a01b031681565b60008054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b815260040160206040518083038186803b158015620015d457600080fd5b505afa158015620015e9573d6000803e3d6000fd5b505050506040513d60208110156200160057600080fd5b5051156200163e576040805162461bcd60e51b815260206004820152600660248201526514185d5cd95960d21b604482015290519081900360640190fd5b60008054906101000a90046001600160a01b03166001600160a01b0316632e292fc76040518163ffffffff1660e01b815260040160206040518083038186803b1580156200168b57600080fd5b505afa158015620016a0573d6000803e3d6000fd5b505050506040513d6020811015620016b757600080fd5b505115620016fd576040805162461bcd60e51b815260206004820152600e60248201526d14185c9d1a585b0b5c185d5cd95960921b604482015290519081900360640190fd5b565b60006200170b6200200c565b90506001600160a01b038116156200179357806001600160a01b0316631d1c2fec836040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b1580156200176457600080fd5b505af115801562001779573d6000803e3d6000fd5b505050506040513d60208110156200179057600080fd5b50505b5050565b6000620017db83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525062002079565b9392505050565b6000805460408051637bb20d2f60e11b81527f45fc200c7e4544e457d3c5709bfe0d520442c30bbcbdaede89e8d4a4bbc19247600482015290516001600160a01b039092169163f7641a5e91602480820192602092909190829003018186803b1580156200184f57600080fd5b505afa15801562001864573d6000803e3d6000fd5b505050506040513d60208110156200187b57600080fd5b5051905090565b600082820183811015620017db576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60008054906101000a90046001600160a01b03166001600160a01b0316634fc07d756040518163ffffffff1660e01b815260040160206040518083038186803b1580156200192a57600080fd5b505afa1580156200193f573d6000803e3d6000fd5b505050506040513d60208110156200195657600080fd5b50516001600160a01b03163314620016fd5760405162461bcd60e51b8152600401808060200182810382526022815260200180620035776022913960400191505060405180910390fd5b60008111620019e15760405162461bcd60e51b8152600401808060200182810382526024815260200180620035326024913960400191505060405180910390fd5b600d819055604080516020808252601690820152751b5a5b9a5b5d5b50dd5c985d1a5bdb91195c1bdcda5d60521b8183015290517f96d5a4b4edf1cefd0900c166d64447f8da1d01d1861a6a60894b5b82a2c15c3c9181900360600190a150565b6000805460408051637bb20d2f60e11b81527f1df41cd916959d1163dc8f0671a666ea8a3e434c13e40faef527133b5d167034600482015290516001600160a01b039092169163f7641a5e91602480820192602092909190829003018186803b1580156200184f57600080fd5b6001600160a01b03811662001b04576040805162461bcd60e51b815260206004820152601660248201527510dbdb9d1c9bdb1b195c881b5d5cdd081899481cd95d60521b604482015290519081900360640190fd5b600080546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f4ff638452bbf33c012645d18ae6f05515ff5f2d1dfb0cece8cbf018c60903f709181900360200190a150565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b60008163ffffffff161162001bc45760405162461bcd60e51b8152600401808060200182810382526021815260200180620035996021913960400191505060405180910390fd5b620f424063ffffffff8216111562001c0e5760405162461bcd60e51b8152600401808060200182810382526033815260200180620035ba6033913960400191505060405180910390fd5b600c805467ffffffff000000001916600160201b63ffffffff8416021790556040805160208082526013908201527264656661756c7452657365727665526174696f60681b8183015290517f96d5a4b4edf1cefd0900c166d64447f8da1d01d1861a6a60894b5b82a2c15c3c916060908290030190a150565b620f424063ffffffff8216111562001cd15760405162461bcd60e51b8152600401808060200182810382526039815260200180620036106039913960400191505060405180910390fd5b600c805463ffffffff191663ffffffff8316179055604080516020808252601590820152746375726174696f6e54617850657263656e7461676560581b8183015290517f96d5a4b4edf1cefd0900c166d64447f8da1d01d1861a6a60894b5b82a2c15c3c916060908290030190a150565b60008262001d5357506000620006f0565b8282028284828162001d6157fe5b0414620017db5760405162461bcd60e51b8152600401808060200182810382526021815260200180620035566021913960400191505060405180910390fd5b6000620017db83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525062002114565b600062001df06200217d565b506000838152600f60209081526040918290208251606081018452815480825260019092015463ffffffff811693820193909352600160201b9092046001600160a01b0316928201929092529062001f5f57600d5483101562001e855760405162461bcd60e51b815260040180806020018281038252602a81526020018062003433602a913960400191505060405180910390fd5b600e54600d54600c5462001f5692670de0b6b3a7640000926001600160a01b03909116916329a00e7c91849163ffffffff600160201b90910481169062001ed1908b9084906200179716565b6040518563ffffffff1660e01b8152600401808581526020018481526020018363ffffffff16815260200182815260200194505050505060206040518083038186803b15801562001f2157600080fd5b505afa15801562001f36573d6000803e3d6000fd5b505050506040513d602081101562001f4d57600080fd5b50519062001882565b915050620006f0565b600e546001600160a01b03166329a00e7c62001f7b8662000f6a565b83600001518460200151876040518563ffffffff1660e01b8152600401808581526020018481526020018363ffffffff16815260200182815260200194505050505060206040518083038186803b15801562001fd657600080fd5b505afa15801562001feb573d6000803e3d6000fd5b505050506040513d60208110156200200257600080fd5b5051949350505050565b6000805460408051637bb20d2f60e11b81527f966f1e8d8d8014e05f6ec4a57138da9be1f7c5a7f802928a18072f7c53180761600482015290516001600160a01b039092169163f7641a5e91602480820192602092909190829003018186803b1580156200184f57600080fd5b600081848411156200210c5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620020d0578181015183820152602001620020b6565b50505050905090810190601f168015620020fe5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b60008183620021665760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315620020d0578181015183820152602001620020b6565b5060008385816200217357fe5b0495945050505050565b604080516060810182526000808252602082018190529181019190915290565b61128780620021ac8339019056fe60806040523480156200001157600080fd5b506040516200128738038062001287833981810160405260208110156200003757600080fd5b5051604080518082018252601481527f4772617068204375726174696f6e2053686172650000000000000000000000006020828101918252835180850190945260038085526247435360e81b9185019190915282519293926200009b929062000109565b508051620000b190600490602084019062000109565b505060058054601260ff1990911617905550620000da81620000e1602090811b620009aa17901c565b50620001b5565b600580546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b828054600181600116156101000203166002900490600052602060002090601f0160209004810192826200014157600085556200018c565b82601f106200015c57805160ff19168380011785556200018c565b828001600101855582156200018c579182015b828111156200018c5782518255916020019190600101906200016f565b506200019a9291506200019e565b5090565b5b808211156200019a57600081556001016200019f565b6110c280620001c56000396000f3fe608060405234801561001057600080fd5b506004361061010b5760003560e01c806370a08231116100a2578063a457c2d711610071578063a457c2d71461031b578063a9059cbb14610347578063dd62ed3e14610373578063e3056a34146103a1578063f2fde38b146103a95761010b565b806370a08231146102b957806379ba5097146102df57806379cc6790146102e757806395d89b41146103135761010b565b806323b872dd116100de57806323b872dd1461020b578063313ce56714610241578063395093511461025f57806340c10f191461028b5761010b565b806306fdde0314610110578063095ea7b31461018d5780630c340a24146101cd57806318160ddd146101f1575b600080fd5b6101186103cf565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561015257818101518382015260200161013a565b50505050905090810190601f16801561017f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101b9600480360360408110156101a357600080fd5b506001600160a01b038135169060200135610465565b604080519115158252519081900360200190f35b6101d5610482565b604080516001600160a01b039092168252519081900360200190f35b6101f9610496565b60408051918252519081900360200190f35b6101b96004803603606081101561022157600080fd5b506001600160a01b0381358116916020810135909116906040013561049c565b610249610523565b6040805160ff9092168252519081900360200190f35b6101b96004803603604081101561027557600080fd5b506001600160a01b03813516906020013561052c565b6102b7600480360360408110156102a157600080fd5b506001600160a01b03813516906020013561057a565b005b6101f9600480360360208110156102cf57600080fd5b50356001600160a01b03166105e5565b6102b7610600565b6102b7600480360360408110156102fd57600080fd5b506001600160a01b038135169060200135610729565b610118610790565b6101b96004803603604081101561033157600080fd5b506001600160a01b0381351690602001356107f1565b6101b96004803603604081101561035d57600080fd5b506001600160a01b038135169060200135610859565b6101f96004803603604081101561038957600080fd5b506001600160a01b038135811691602001351661086d565b6101d5610898565b6102b7600480360360208110156103bf57600080fd5b50356001600160a01b03166108a7565b60038054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561045b5780601f106104305761010080835404028352916020019161045b565b820191906000526020600020905b81548152906001019060200180831161043e57829003601f168201915b5050505050905090565b60006104796104726109d2565b84846109d6565b50600192915050565b60055461010090046001600160a01b031681565b60025490565b60006104a9848484610ac2565b610519846104b56109d2565b61051485604051806060016040528060288152602001610fd6602891396001600160a01b038a166000908152600160205260408120906104f36109d2565b6001600160a01b031681526020810191909152604001600020549190610c1d565b6109d6565b5060019392505050565b60055460ff1690565b60006104796105396109d2565b84610514856001600061054a6109d2565b6001600160a01b03908116825260208083019390935260409182016000908120918c168152925290205490610cb4565b60055461010090046001600160a01b031633146105d7576040805162461bcd60e51b815260206004820152601660248201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604482015290519081900360640190fd5b6105e18282610d15565b5050565b6001600160a01b031660009081526020819052604090205490565b6006546001600160a01b03161580159061062457506006546001600160a01b031633145b610675576040805162461bcd60e51b815260206004820152601f60248201527f43616c6c6572206d7573742062652070656e64696e6720676f7665726e6f7200604482015290519081900360640190fd5b60058054600680546001600160a01b03818116610100818102610100600160a81b0319871617968790556001600160a01b0319909316909355604051938290048116949293919092049091169083907f0ac6deed30eef60090c749850e10f2fa469e3e25fec1d1bef2853003f6e6f18f90600090a36006546040516001600160a01b03918216918316907f76563ad561b7036ae716b9b25cb521b21463240f104c97e12f25877f2235f33d90600090a35050565b60055461010090046001600160a01b03163314610786576040805162461bcd60e51b815260206004820152601660248201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604482015290519081900360640190fd5b6105e18282610e05565b60048054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561045b5780601f106104305761010080835404028352916020019161045b565b60006104796107fe6109d2565b846105148560405180606001604052806025815260200161106860259139600160006108286109d2565b6001600160a01b03908116825260208083019390935260409182016000908120918d16815292529020549190610c1d565b60006104796108666109d2565b8484610ac2565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6006546001600160a01b031681565b60055461010090046001600160a01b03163314610904576040805162461bcd60e51b815260206004820152601660248201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604482015290519081900360640190fd5b6001600160a01b038116610956576040805162461bcd60e51b815260206004820152601460248201527311dbdd995c9b9bdc881b5d5cdd081899481cd95d60621b604482015290519081900360640190fd5b600680546001600160a01b038381166001600160a01b03198316179283905560405191811692169082907f76563ad561b7036ae716b9b25cb521b21463240f104c97e12f25877f2235f33d90600090a35050565b600580546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b3390565b6001600160a01b038316610a1b5760405162461bcd60e51b81526004018080602001828103825260248152602001806110446024913960400191505060405180910390fd5b6001600160a01b038216610a605760405162461bcd60e51b8152600401808060200182810382526022815260200180610f8e6022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b038316610b075760405162461bcd60e51b815260040180806020018281038252602581526020018061101f6025913960400191505060405180910390fd5b6001600160a01b038216610b4c5760405162461bcd60e51b8152600401808060200182810382526023815260200180610f496023913960400191505060405180910390fd5b610b57838383610f01565b610b9481604051806060016040528060268152602001610fb0602691396001600160a01b0386166000908152602081905260409020549190610c1d565b6001600160a01b038085166000908152602081905260408082209390935590841681522054610bc39082610cb4565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b60008184841115610cac5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610c71578181015183820152602001610c59565b50505050905090810190601f168015610c9e5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600082820183811015610d0e576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6001600160a01b038216610d70576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b610d7c60008383610f01565b600254610d899082610cb4565b6002556001600160a01b038216600090815260208190526040902054610daf9082610cb4565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6001600160a01b038216610e4a5760405162461bcd60e51b8152600401808060200182810382526021815260200180610ffe6021913960400191505060405180910390fd5b610e5682600083610f01565b610e9381604051806060016040528060228152602001610f6c602291396001600160a01b0385166000908152602081905260409020549190610c1d565b6001600160a01b038316600090815260208190526040902055600254610eb99082610f06565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b505050565b6000610d0e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250610c1d56fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa26469706673582212204cb1015622950d635ba48cf5ee6af298ab114e15b9265ae471beca741183788564736f6c634300070400334375726174696f6e206465706f7369742069732062656c6f77206d696e696d756d2072657175697265645375626772617068206465706c6f796d656e74206d757374206265206375726174656420746f20636f6c6c656374206665657343616e6e6f74206275726e206d6f7265207369676e616c207468616e20796f75206f776e5369676e616c206d7573742062652061626f7665206f7220657175616c20746f207369676e616c2069737375656420696e20746865206375726174696f6e20706f6f6c5375626772617068206465706c6f796d656e74206d757374206265206375726174656420746f20706572666f726d2063616c63756c6174696f6e734d696e696d756d206375726174696f6e206465706f7369742063616e6e6f742062652030536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7743616c6c6572206d75737420626520436f6e74726f6c6c657220676f7665726e6f7244656661756c74207265736572766520726174696f206d757374206265203e203044656661756c74207265736572766520726174696f2063616e6e6f7420626520686967686572207468616e204d41585f50504d43616c6c6572206d75737420626520746865207374616b696e6720636f6e74726163744375726174696f6e207461782070657263656e74616765206d7573742062652062656c6f77206f7220657175616c20746f204d41585f50504d43616c6c6572206d7573742062652074686520696d706c656d656e746174696f6e43616e6e6f74207472616e7366657220746f6b656e7320746f206465706f736974a26469706673582212206264c30885d86e62b7838b4a997d40aae88812e93904b3faf9131cf287eaf3de64736f6c63430007040033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.