ETH Price: $1,962.44 (+1.56%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
NestMiningV1

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 16 : NestMiningV1.sol
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

import "./libminingv1/MiningV1Data.sol";
import "./libminingv1/MiningV1Calc.sol";
import "./libminingv1/MiningV1Op.sol";

import "./lib/SafeMath.sol";
import "./lib/SafeERC20.sol";
import './lib/TransferHelper.sol';
import "./lib/ABDKMath64x64.sol";

import "./iface/INestPool.sol";
import "./iface/INestStaking.sol";
import "./iface/INTokenLegacy.sol";
import "./iface/INestMining.sol";
import "./iface/INestDAO.sol";
// import "hardhat/console.sol";

/// @title  NestMiningV1
/// @author Inf Loop - <inf-loop@nestprotocol.org>
/// @author Paradox  - <paradox@nestprotocol.org>
contract NestMiningV1 {

    using SafeMath for uint256;

    using MiningV1Calc for MiningV1Data.State;
    using MiningV1Op for MiningV1Data.State;

    /* ========== STATE VARIABLES ============== */

    uint8       public  flag;  // 0:  | 1:  | 2:  | 3:
    uint64      public  version; 
    uint8       private _entrant_state; 
    uint176     private _reserved;

    MiningV1Data.State state;
    
    // NOTE: _NOT_ENTERED is set to ZERO such that it needn't constructor
    uint8 private constant _NOT_ENTERED = 0;
    uint8 private constant _ENTERED = 1;

    uint8 constant MINING_FLAG_UNINITIALIZED    = 0;
    uint8 constant MINING_FLAG_SETUP_NEEDED     = 1;
    uint8 constant MINING_FLAG_UPGRADE_NEEDED   = 2;
    uint8 constant MINING_FLAG_ACTIVE           = 3;

    /* ========== ADDRESSES ============== */

    address public  governance;
    address private C_NestPool;

    /* ========== STRUCTURES ============== */

    struct Params {
        uint8    miningEthUnit;     
        uint32   nestStakedNum1k;   
        uint8    biteFeeRate;     
        uint8    miningFeeRate;     
        uint8    priceDurationBlock; 
        uint8    maxBiteNestedLevel; 
        uint8    biteInflateFactor;
        uint8    biteNestInflateFactor;
    }

    /* ========== CONSTRUCTOR ========== */

    constructor() public { }

    function initialize(address NestPool) external 
    {
        // check flag
        require(flag == MINING_FLAG_UNINITIALIZED, "Nest:Mine:!flag");

        uint256 amount = MiningV1Data.MINING_NEST_YIELD_PER_BLOCK_BASE;
        for (uint i =0; i < 10; i++) {
            state._mining_nest_yield_per_block_amount[i] = amount;
            amount = amount.mul(MiningV1Data.MINING_NEST_YIELD_CUTBACK_RATE).div(100);
        }

        amount = MiningV1Data.MINING_NTOKEN_YIELD_PER_BLOCK_BASE;
        for (uint i =0; i < 10; i++) {
            state._mining_ntoken_yield_per_block_amount[i] = amount;
            amount = amount.mul(MiningV1Data.MINING_NTOKEN_YIELD_CUTBACK_RATE).div(100);
        }
        
        // set a temporary governance
        governance = msg.sender;

        // increase version number
        version = uint64(block.number);

        // set the address of NestPool 
        C_NestPool = NestPool;

        // set flag
        flag = MINING_FLAG_SETUP_NEEDED;
    }

    /// @dev This function can only be called once immediately right after deployment
    function setup(
            uint32   genesisBlockNumber, 
            uint128  latestMiningHeight,
            uint128  minedNestTotalAmount,
            Params calldata initParams
        ) external onlyGovernance
    {
        // check flag
        require(flag == MINING_FLAG_SETUP_NEEDED, "Nest:Mine:!flag");
        
        // set system-wide parameters
        state.miningEthUnit = initParams.miningEthUnit;
        state.nestStakedNum1k = initParams.nestStakedNum1k;
        state.biteFeeRate = initParams.biteFeeRate;    // 0.1%
        state.miningFeeRate = initParams.miningFeeRate;  // 0.1% on testnet
        state.priceDurationBlock = initParams.priceDurationBlock;  // 5 on testnet
        state.maxBiteNestedLevel = initParams.maxBiteNestedLevel;  
        state.biteInflateFactor = initParams.biteInflateFactor;   // 1 on testnet
        state.biteNestInflateFactor = initParams.biteNestInflateFactor; // 1 on testnet
        state.latestMiningHeight = latestMiningHeight;
        state.minedNestAmount = minedNestTotalAmount;
        
        // genesisBlock = 6236588 on mainnet
        state.genesisBlock = genesisBlockNumber;

        // increase version number
        version = uint64(block.number);
        
        // set flag
        flag = MINING_FLAG_UPGRADE_NEEDED;
    }

    /// @dev The function will be kicking off Nest Protocol v3.5.
    ///    After upgrading, `post/post2()` are ready to be invoked.
    ///    Before that, `post2Only4Upgrade()` is used to do posting.
    ///    The purpose is to limit post2Only4Upgrade() to run 
    function upgrade() external onlyGovernance
    {
        require(flag == MINING_FLAG_UPGRADE_NEEDED, "Nest:Mine:!flag");

        flag = MINING_FLAG_ACTIVE;
    }

    /// @notice Write the block number as a version number
    /// @dev It shall be invoked *manually* whenever the contract is upgraded(behind proxy)
    function incVersion() external onlyGovernance
    {
        version = uint64(block.number);
    }

    receive() external payable { }

    /* ========== MODIFIERS ========== */

    function _onlyGovernance() private view 
    {
        require(msg.sender == governance, "Nest:Mine:!GOV");
    }

    modifier onlyGovernance() 
    {
        _onlyGovernance();
        _;
    }

    function _noContract() private view {
        require(address(msg.sender) == address(tx.origin), "Nest:Mine:contract!");
    }

    modifier noContract() 
    {
        _noContract();
        _;
    }

    modifier noContractExcept(address _contract) 
    {
        require(address(msg.sender) == address(tx.origin) || address(msg.sender) == _contract, "Nest:Mine:contract!");
        _;
    }

    modifier onlyGovOrBy(address _contract) 
    {
        require(msg.sender == governance || msg.sender == _contract, "Nest:Mine:!sender");
        _;
    }

    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_entrant_state != _ENTERED, "ReentrancyGuard: reentrant call");

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

        _;

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

    modifier onlyByNestOrNoContract()
    {
        require(address(msg.sender) == address(tx.origin)
            || msg.sender == state.C_NestDAO 
            || msg.sender == state.C_NestStaking 
            || msg.sender == state.C_NNRewardPool 
            || msg.sender == state.C_NestQuery, "Nest:Mine:!Auth");
        _;
    }

    /* ========== GOVERNANCE ========== */

    /// @dev Load real governance from NestPool, invalidate the temporary 
    function loadGovernance() external
    {
        governance = INestPool(C_NestPool).governance();
    }

    function loadContracts() external onlyGovOrBy(C_NestPool)
    {
        state.C_NestPool = C_NestPool;
        state.C_NestToken = INestPool(state.C_NestPool).addrOfNestToken();
        state.C_NestStaking = INestPool(state.C_NestPool).addrOfNestStaking();
        state.C_NestQuery = INestPool(state.C_NestPool).addrOfNestQuery();
        state.C_NNRewardPool = INestPool(state.C_NestPool).addrOfNNRewardPool();
        state.C_NestDAO = INestPool(state.C_NestPool).addrOfNestDAO();
    }

    function setParams(Params calldata newParams) external 
        onlyGovernance
    {
        state.miningEthUnit = newParams.miningEthUnit;
        state.nestStakedNum1k = newParams.nestStakedNum1k;
        state.biteFeeRate = newParams.biteFeeRate;
        state.miningFeeRate = newParams.miningFeeRate;

        state.priceDurationBlock = newParams.priceDurationBlock;
        state.maxBiteNestedLevel = newParams.maxBiteNestedLevel;
        state.biteInflateFactor = newParams.biteInflateFactor;
        state.biteNestInflateFactor = newParams.biteNestInflateFactor;

        emit MiningV1Data.SetParams(state.miningEthUnit, state.nestStakedNum1k, state.biteFeeRate,
                                    state.miningFeeRate, state.priceDurationBlock, state.maxBiteNestedLevel,
                                    state.biteInflateFactor, state.biteNestInflateFactor);
    }

    /// @dev only be used when upgrading 3.0 to 3.5
    /// @dev when the upgrade is complete, this function is disabled
    function setParams1(
            uint128  latestMiningHeight,
            uint128  minedNestTotalAmount
        ) external onlyGovernance
    {
        require(flag == MINING_FLAG_UPGRADE_NEEDED, "Nest:Mine:!flag");
        state.latestMiningHeight = latestMiningHeight;
        state.minedNestAmount = minedNestTotalAmount;
    }

    /* ========== HELPERS ========== */

    function addrOfGovernance() view external
        returns (address) 
    {   
        return governance;
    }

    function parameters() view external 
        returns (Params memory params)
    {
        params.miningEthUnit = state.miningEthUnit;
        params.nestStakedNum1k = state.nestStakedNum1k;
        params.biteFeeRate = state.biteFeeRate;
        params.miningFeeRate = state.miningFeeRate;
        params.priceDurationBlock = state.priceDurationBlock;
        params.maxBiteNestedLevel = state.maxBiteNestedLevel;
        params.biteInflateFactor = state.biteInflateFactor;
        params.biteNestInflateFactor = state.biteNestInflateFactor;
    }

    /* ========== POST/CLOSE Price Sheets ========== */

    /// @notice Post a price sheet for TOKEN
    /// @dev  It is for TOKEN (except USDT and NTOKENs) whose NTOKEN has a total supply below a threshold (e.g. 5,000,000 * 1e18)
    /// @param token The address of TOKEN contract
    /// @param ethNum The numbers of ethers to post sheets
    /// @param tokenAmountPerEth The price of TOKEN
    function post(
            address token, 
            uint256 ethNum, 
            uint256 tokenAmountPerEth
        )
        external 
        payable 
        noContract
    {
        // check parameters
        require(ethNum == state.miningEthUnit, "Nest:Mine:!(ethNum)");
        require(tokenAmountPerEth > 0, "Nest:Mine:!(price)");

        INestPool _C_NestPool = INestPool(state.C_NestPool);
        address _ntoken = _C_NestPool.getNTokenFromToken(token);
        require(_ntoken != address(0) &&  _ntoken != address(state.C_NestToken) && token != _ntoken, "Nest:Mine:!(ntoken)");

        // check if the totalsupply of ntoken is less than MINING_NTOKEN_NON_DUAL_POST_THRESHOLD, otherwise use post2()
        require(INToken(_ntoken).totalSupply() < MiningV1Data.MINING_NTOKEN_NON_DUAL_POST_THRESHOLD, "Nest:Mine:!ntoken");

        // calculate eth fee
        // NOTE: fee = ethAmount * (feeRate * 1/10k)
        uint256 _ethFee = ethNum.mul(state.miningFeeRate).mul(1e18).div(10_000);

        { // settle ethers and tokens

            // save the changes into miner's virtual account
            if (msg.value.sub(_ethFee) > 0) {
                _C_NestPool.depositEth{value:msg.value.sub(_ethFee)}(address(msg.sender));
            }

            // load addresses
            INestStaking _C_NestStaking = INestStaking(state.C_NestStaking);
            INestDAO _C_NestDAO = INestDAO(state.C_NestDAO);

            // 60% fee => NestStaking
            _C_NestStaking.addETHReward{value:_ethFee.mul(MiningV1Data.MINING_NTOKEN_FEE_DIVIDEND_RATE).div(100)}(_ntoken);       
            // 20% fee => NestDAO[NTOKEN]
            _C_NestDAO.addETHReward{value:_ethFee.mul(MiningV1Data.MINING_NTOKEN_FEE_DAO_RATE).div(100)}(_ntoken);       
            // 20% fee => NestDAO[NEST]
            _C_NestDAO.addETHReward{value:_ethFee.mul(MiningV1Data.MINING_NTOKEN_FEE_NEST_DAO_RATE).div(100)}(address(state.C_NestToken));  

            // freeze eths and tokens inside NestPool
            _C_NestPool.freezeEthAndToken(msg.sender, ethNum.mul(1 ether), 
                token, tokenAmountPerEth.mul(ethNum));
            _C_NestPool.freezeNest(msg.sender, uint256(state.nestStakedNum1k).mul(1000 * 1e18));
        }

        {
            MiningV1Data.PriceSheet[] storage _sheetToken = state.priceSheetList[token];
            // append a new price sheet
            _sheetToken.push(MiningV1Data.PriceSheet(
                uint160(msg.sender),            // miner 
                uint32(block.number),           // atHeight
                uint32(ethNum),                 // ethNum
                uint32(ethNum),                 // remainNum
                uint8(0),                       // level
                uint8(MiningV1Data.PRICESHEET_TYPE_TOKEN),   // typ
                uint8(MiningV1Data.PRICESHEET_STATE_POSTED), // state 
                uint8(0),                       // _reserved
                uint32(ethNum),                 // ethNumBal
                uint32(ethNum),                 // tokenNumBal
                uint32(state.nestStakedNum1k),    // nestNum1k
                uint128(tokenAmountPerEth)      // tokenAmountPerEth
            ));
            emit MiningV1Data.PricePosted(msg.sender, token, (_sheetToken.length - 1), ethNum.mul(1 ether), tokenAmountPerEth.mul(ethNum)); 

        }

        { // mining; NTOKEN branch only
            // load mining record from `minedAtHeight`
            uint256 _minedH = state.minedAtHeight[token][block.number];
            // decode `_ntokenH` & `_ethH`
            uint256 _ntokenH = uint256(_minedH >> 128);
            uint256 _ethH = uint256(_minedH % (1 << 128));
            if (_ntokenH == 0) {  // the sheet is the first in the block
                // calculate the amount the NTOKEN to be mined
                uint256 _ntokenAmount = mineNToken(_ntoken);  
                // load `Bidder` from NTOKEN contract
                address _bidder = INToken(_ntoken).checkBidder();
                if (_bidder == state.C_NestPool) { // for new NTokens, 100% to miners
                    _ntokenH = _ntokenAmount;
                    INToken(_ntoken).mint(_ntokenAmount, address(state.C_NestPool));
                } else { // for old NTokens, 95% to miners, 5% to the bidder
                    _ntokenH = _ntokenAmount.mul(MiningV1Data.MINING_LEGACY_NTOKEN_MINER_REWARD_PERCENTAGE).div(100);
                    INTokenLegacy(_ntoken).increaseTotal(_ntokenAmount);
                    INTokenLegacy(_ntoken).transfer(state.C_NestPool, _ntokenAmount);
                    INestPool(state.C_NestPool).addNToken(_bidder, _ntoken, _ntokenAmount.sub(_ntokenH));
                }
            }
            
            // add up `_ethH`
            _ethH = _ethH.add(ethNum);
            // store `_ntokenH` & `_ethH` into `minedAtHeight`
            state.minedAtHeight[token][block.number] = (_ntokenH * (1<< 128) + _ethH);
        }

        // calculate averge and volatility
        state._stat(token);
        return; 
    }

    /// @notice Post two price sheets for a token and its ntoken simultaneously 
    /// @dev  Support dual-posts for TOKEN/NTOKEN, (ETH, TOKEN) + (ETH, NTOKEN)
    /// @param token The address of TOKEN contract
    /// @param ethNum The numbers of ethers to post sheets
    /// @param tokenAmountPerEth The price of TOKEN
    /// @param ntokenAmountPerEth The price of NTOKEN
    function post2(
            address token, 
            uint256 ethNum, 
            uint256 tokenAmountPerEth, 
            uint256 ntokenAmountPerEth
        )
        external 
        payable 
        noContract
    {
        // check parameters 
        require(ethNum == state.miningEthUnit, "Nest:Mine:!(ethNum)");
        require(tokenAmountPerEth > 0 && ntokenAmountPerEth > 0, "Nest:Mine:!(price)");
        address _ntoken = INestPool(state.C_NestPool).getNTokenFromToken(token);

        require(_ntoken != token && _ntoken != address(0), "Nest:Mine:!(ntoken)");

        // calculate eth fee
        uint256 _ethFee = ethNum.mul(state.miningFeeRate).mul(1e18).div(10_000);

        { // settle ethers and tokens
            INestPool _C_NestPool = INestPool(state.C_NestPool);

            // save the changes into miner's virtual account
            if (msg.value.sub(_ethFee) > 0) {
                _C_NestPool.depositEth{value:msg.value.sub(_ethFee)}(address(msg.sender));
            }

            // load addresses
            INestStaking _C_NestStaking = INestStaking(state.C_NestStaking);
            INestDAO _C_NestDAO = INestDAO(state.C_NestDAO);

            if (_ntoken == address(state.C_NestToken)) {
                // %80 => NestStaking
                _C_NestStaking.addETHReward{value:_ethFee.mul(MiningV1Data.MINING_NEST_FEE_DIVIDEND_RATE).div(100)}(_ntoken);       
                // %20 => NestDAO
                _C_NestDAO.addETHReward{value:_ethFee.mul(MiningV1Data.MINING_NEST_FEE_DAO_RATE).div(100)}(_ntoken);       
            } else {
                // 60% => NestStaking
                _C_NestStaking.addETHReward{value:_ethFee.mul(MiningV1Data.MINING_NTOKEN_FEE_DIVIDEND_RATE).div(100)}(_ntoken);       
                // 20% => NestDAO[NTOKEN]
                _C_NestDAO.addETHReward{value:_ethFee.mul(MiningV1Data.MINING_NTOKEN_FEE_DAO_RATE).div(100)}(_ntoken);       
                // 20% => NestDAO[NEST]
                _C_NestDAO.addETHReward{value:_ethFee.mul(MiningV1Data.MINING_NTOKEN_FEE_NEST_DAO_RATE).div(100)}(address(state.C_NestToken));  
            }

            // freeze assets inside NestPool
            _C_NestPool.freezeEthAndToken(msg.sender, ethNum.mul(1 ether), 
                token, tokenAmountPerEth.mul(ethNum));
            _C_NestPool.freezeEthAndToken(msg.sender, ethNum.mul(1 ether), 
                _ntoken, ntokenAmountPerEth.mul(ethNum));
            _C_NestPool.freezeNest(msg.sender, uint256(state.nestStakedNum1k).mul(2).mul(1000 * 1e18));
        }

        {
            uint8 typ1;
            uint8 typ2; 
            if (_ntoken == address(state.C_NestToken)) {
                typ1 = MiningV1Data.PRICESHEET_TYPE_USD;
                typ2 = MiningV1Data.PRICESHEET_TYPE_NEST;
            } else {
                typ1 = MiningV1Data.PRICESHEET_TYPE_TOKEN;
                typ2 = MiningV1Data.PRICESHEET_TYPE_NTOKEN;
            }
            MiningV1Data.PriceSheet[] storage _sheetToken = state.priceSheetList[token];
            // append a new price sheet
            _sheetToken.push(MiningV1Data.PriceSheet(
                uint160(msg.sender),            // miner 
                uint32(block.number),           // atHeight
                uint32(ethNum),                 // ethNum
                uint32(ethNum),                 // remainNum
                uint8(0),                       // level
                uint8(typ1),                    // typ
                uint8(MiningV1Data.PRICESHEET_STATE_POSTED), // state 
                uint8(0),                       // _reserved
                uint32(ethNum),                 // ethNumBal
                uint32(ethNum),                 // tokenNumBal
                uint32(state.nestStakedNum1k),        // nestNum1k
                uint128(tokenAmountPerEth)      // tokenAmountPerEth
            ));

            MiningV1Data.PriceSheet[] storage _sheetNToken = state.priceSheetList[_ntoken];
            // append a new price sheet for ntoken
            _sheetNToken.push(MiningV1Data.PriceSheet(
                uint160(msg.sender),            // miner 
                uint32(block.number),           // atHeight
                uint32(ethNum),                 // ethNum
                uint32(ethNum),                 // remainNum
                uint8(0),                       // level
                uint8(typ2),                    // typ
                uint8(MiningV1Data.PRICESHEET_STATE_POSTED), // state 
                uint8(0),                       // _reserved
                uint32(ethNum),                 // ethNumBal
                uint32(ethNum),                 // tokenNumBal
                uint32(state.nestStakedNum1k),  // nestNum1k
                uint128(ntokenAmountPerEth)     // tokenAmountPerEth
            ));
            emit MiningV1Data.PricePosted(msg.sender, token, (_sheetToken.length - 1), ethNum.mul(1 ether), tokenAmountPerEth.mul(ethNum)); 
            emit MiningV1Data.PricePosted(msg.sender, _ntoken, (_sheetNToken.length - 1), ethNum.mul(1 ether), ntokenAmountPerEth.mul(ethNum)); 
        }

        { // mining; NEST branch & NTOKEN branch
            if (_ntoken == address(state.C_NestToken)) {
                // load mining records `minedAtHeight` in the same block 
                uint256 _minedH = state.minedAtHeight[token][block.number];
                // decode `_nestH` and `_ethH` from `minedAtHeight`
                uint256 _nestH = uint256(_minedH >> 128);
                uint256 _ethH = uint256(_minedH % (1 << 128));

                if (_nestH == 0) { // the sheet is the first in the block

                    // calculate the amount of NEST to be mined
                    uint256 _nestAmount = mineNest(); 

                    // update `latestMiningHeight`, the lastest NEST-mining block 
                    state.latestMiningHeight = uint32(block.number); 

                    // accumulate the amount of NEST
                    state.minedNestAmount += uint128(_nestAmount);

                    // 
                    _nestH = _nestAmount.mul(MiningV1Data.MINER_NEST_REWARD_PERCENTAGE).div(100); 

                    // 15% of NEST to NNRewardPool
                    INestPool(state.C_NestPool).addNest(state.C_NNRewardPool, _nestAmount.mul(MiningV1Data.NN_NEST_REWARD_PERCENTAGE).div(100));
                    INNRewardPool(state.C_NNRewardPool).addNNReward(_nestAmount.mul(MiningV1Data.NN_NEST_REWARD_PERCENTAGE).div(100));

                    // 5% of NEST to NestDAO
                    INestPool(state.C_NestPool).addNest(state.C_NestDAO, _nestAmount.mul(MiningV1Data.DAO_NEST_REWARD_PERCENTAGE).div(100));
                    INestDAO(state.C_NestDAO).addNestReward(_nestAmount.mul(MiningV1Data.DAO_NEST_REWARD_PERCENTAGE).div(100));
                }

                // add up `ethNum` into `minedAtHeight`
                _ethH = _ethH.add(ethNum);
                // encode `_nestH` and `_ethH` into `minedAtHeight`
                state.minedAtHeight[token][block.number] = (_nestH * (1<< 128) + _ethH);
            } else {
                // load mining records `minedAtHeight` in the same block 
                uint256 _minedH = state.minedAtHeight[token][block.number];
                // decode `_ntokenH` and `_ethH` from `minedAtHeight`
                uint256 _ntokenH = uint256(_minedH >> 128);
                uint256 _ethH = uint256(_minedH % (1 << 128));

                if (_ntokenH == 0) { // the sheet is the first in the block

                    // calculate the amount of NEST to be mined
                    uint256 _ntokenAmount = mineNToken(_ntoken);

                    // load `Bidder` from NTOKEN contract
                    address _bidder = INToken(_ntoken).checkBidder();

                    if (_bidder == state.C_NestPool) { // for new NTokens, 100% to miners
                        
                        // save the amount of NTOKEN to be mined
                        _ntokenH = _ntokenAmount;
                        // mint NTOKEN(new, v3.5) to NestPool
                        INToken(_ntoken).mint(_ntokenAmount, address(state.C_NestPool));

                    } else {                           // for old NTokens, 95% to miners, 5% to the bidder
                        
                        // mint NTOKEN(old, v3.0)
                        INTokenLegacy(_ntoken).increaseTotal(_ntokenAmount);
                        // transfer NTOKEN(old) to NestPool
                        INTokenLegacy(_ntoken).transfer(state.C_NestPool, _ntokenAmount);
                        // calculate the amount of NTOKEN, 95% => miner
                        _ntokenH = _ntokenAmount.mul(MiningV1Data.MINING_LEGACY_NTOKEN_MINER_REWARD_PERCENTAGE).div(100);
                        // 5% NTOKEN =>  `Bidder`
                        INestPool(state.C_NestPool).addNToken(_bidder, _ntoken, _ntokenAmount.sub(_ntokenH));
                    }
                }
                // add up `ethNum` into `minedAtHeight`
                _ethH = _ethH.add(ethNum);
                // encode `_nestH` and `_ethH` into `minedAtHeight`
                state.minedAtHeight[token][block.number] = (_ntokenH * (1<< 128) + _ethH);
            }
        }

        // calculate the average-prices and volatilities for (TOKEN. NTOKEN)

        state._stat(token);
        state._stat(_ntoken);
        return; 
    }

    /// @notice Close a price sheet of (ETH, USDx) | (ETH, NEST) | (ETH, TOKEN) | (ETH, NTOKEN)
    /// @dev Here we allow an empty price sheet (still in VERIFICATION-PERIOD) to be closed 
    /// @param token The address of TOKEN contract
    /// @param index The index of the price sheet w.r.t. `token`
    function close(address token, uint256 index) 
        public 
        noContract 
    {
        // call library
        state._close(token, index);

        // calculate average-price and volatility (forward)
        state._stat(token);

    }

 
    /// @notice Close a price sheet and withdraw assets for WEB users.  
    /// @dev Contracts aren't allowed to call it.
    /// @param token The address of TOKEN contract
    /// @param index The index of the price sheet w.r.t. `token`
    function closeAndWithdraw(address token, uint256 index) 
        external 
        noContract
    {
        // call library
        state._closeAndWithdraw(token, index);
        // calculate average-price and volatility (forward)
        state._stat(token);
    }

    /// @notice Close a batch of price sheets passed VERIFICATION-PHASE
    /// @dev Empty sheets but in VERIFICATION-PHASE aren't allowed
    /// @param token The address of TOKEN contract
    /// @param indices A list of indices of sheets w.r.t. `token`
    function closeList(address token, uint32[] memory indices) 
        external 
        noContract
    {
        // call library
        state._closeList(token, indices);

        // calculate average-price and volatility (forward)
        state._stat(token);

    }


    /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet
    /// @dev bite TOKEN(NTOKEN) by ETH,  (+ethNumBal, -tokenNumBal)
    /// @param token The address of token(ntoken)
    /// @param index The position of the sheet in priceSheetList[token]
    /// @param biteNum The amount of bitting (in the unit of ETH), realAmount = biteNum * newTokenAmountPerEth
    /// @param newTokenAmountPerEth The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth
    function biteToken(address token, uint256 index, uint256 biteNum, uint256 newTokenAmountPerEth) 
        external 
        payable 
        noContract
    {
        // call library
        state._biteToken(token, index, biteNum, newTokenAmountPerEth);

        // calculate average-price and volatility (forward)
        state._stat(token);
    }

    /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet
    /// @dev bite TOKEN(NTOKEN) by ETH,  (+ethNumBal, -tokenNumBal)
    /// @param token The address of token(ntoken)
    /// @param index The position of the sheet in priceSheetList[token]
    /// @param biteNum The amount of bitting (in the unit of ETH), realAmount = biteNum * newTokenAmountPerEth
    /// @param newTokenAmountPerEth The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth
    function biteEth(address token, uint256 index, uint256 biteNum, uint256 newTokenAmountPerEth)
        external
        payable
        noContract
    {
        // call library
        state._biteEth(token, index, biteNum, newTokenAmountPerEth);

        // calculate average-price and volatility (forward)
        state._stat(token);
    }


    /* ========== CALCULATION ========== */

    function stat(address _token) public 
    {
        // call library
        return state._stat(_token);
    }
    
    /* ========== PRICE QUERIES ========== */

    /// @notice Get the latest effective price for a token
    /// @dev It shouldn't be read from any contracts other than NestQuery
    function latestPriceOf(address token) 
        public
        view
        onlyByNestOrNoContract
        returns(uint256 ethAmount, uint256 tokenAmount, uint256 blockNum) 
    {
        MiningV1Data.PriceSheet[] storage _plist = state.priceSheetList[token];
        uint256 len = _plist.length;
        uint256 _ethNum;
        MiningV1Data.PriceSheet memory _sheet;

        if (len == 0) {
            revert("Nest:Mine:no(price)");
        }

        uint256 _first = 0;
        for (uint i = 1; i <= len; i++) {
            _sheet = _plist[len-i];
            if (_first == 0 && uint256(_sheet.height) + state.priceDurationBlock < block.number) {
                _ethNum = uint256(_sheet.remainNum);
                if (_ethNum == 0) {
                    continue;  // jump over a bitten sheet
                }
                _first = uint256(_sheet.height);
                tokenAmount = _ethNum.mul(uint256(_sheet.tokenAmountPerEth));
                ethAmount = _ethNum.mul(1 ether);
                blockNum = _first;
            } else if (_first == uint256(_sheet.height)) {
                _ethNum = uint256(_sheet.remainNum);
                tokenAmount = tokenAmount.add(_ethNum.mul(uint256(_sheet.tokenAmountPerEth)));
                ethAmount = ethAmount.add(_ethNum.mul(1 ether));
            } else if (_first > uint256(_sheet.height)) {
                break;
            }
        }
        blockNum = blockNum + uint256(state.priceDurationBlock); // safe math
        require(ethAmount > 0 && tokenAmount > 0, "Nest:Mine:no(price)");
    }

    /// @dev It shouldn't be read from any contracts other than NestQuery
    function priceOf(address token)
        public
        view
        noContractExcept(state.C_NestQuery)
        returns(uint256 ethAmount, uint256 tokenAmount, uint256 blockNum) 
    {
        MiningV1Data.PriceInfo memory pi = state.priceInfo[token];
        require(pi.height > 0, "Nest:Mine:NO(price)");
        ethAmount = uint256(pi.ethNum).mul(1 ether);
        tokenAmount = uint256(pi.tokenAmount);
        blockNum = uint256(pi.height + state.priceDurationBlock);
        require(ethAmount > 0 && tokenAmount > 0, "Nest:Mine:no(price)");
    }

    /// @dev It shouldn't be read from any contracts other than NestQuery
    function priceAvgAndSigmaOf(address token) 
        public 
        view 
        onlyByNestOrNoContract
        returns (uint128 price, uint128 avgPrice, int128 vola, uint32 bn) 
    {
        MiningV1Data.PriceInfo memory pi = state.priceInfo[token];
        require(pi.height > 0, "Nest:Mine:NO(price)");
        vola = ABDKMath64x64.sqrt(ABDKMath64x64.abs(pi.volatility_sigma_sq));
        price = uint128(uint256(pi.tokenAmount).div(uint256(pi.ethNum)));
        avgPrice = pi.avgTokenAmount;
        bn = pi.height + uint32(state.priceDurationBlock);
        require(price > 0 && avgPrice > 0, "Nest:Mine:no(price)");
    }

    function priceOfTokenAtHeight(address token, uint64 atHeight)
        public 
        view 
        noContractExcept(state.C_NestQuery)
        returns(uint256 ethAmount, uint256 tokenAmount, uint256 bn) 
    {
        (ethAmount, tokenAmount, bn) = state._priceOfTokenAtHeight(token, atHeight);
        require(ethAmount > 0 && tokenAmount > 0, "Nest:Mine:no(price)");
    }

    /// @notice Return a consecutive price list for a token 
    /// @dev 
    /// @param token The address of token contract
    /// @param num   The length of price list
    function priceListOfToken(address token, uint8 num) 
        external view 
        noContractExcept(state.C_NestQuery)
        returns (uint128[] memory data, uint256 bn) 
    {
        return state._priceListOfToken(token, num);
    }

    /* ========== MINING ========== */
    
    function mineNest() public view returns (uint256) 
    {
        uint256 _period = block.number.sub(state.genesisBlock).div(MiningV1Data.MINING_NEST_YIELD_CUTBACK_PERIOD);
        uint256 _nestPerBlock;
        if (_period > 9) {
            _nestPerBlock = MiningV1Data.MINING_NEST_YIELD_OFF_PERIOD_AMOUNT;
            if (block.number > MiningV1Data.MINING_FINAL_BLOCK_NUMBER) {
                return 0;  // NEST is empty
            }
        } else {
            _nestPerBlock = state._mining_nest_yield_per_block_amount[_period];
        }
        
        return _nestPerBlock.mul(block.number.sub(state.latestMiningHeight));
    }

    function minedNestAmount() external view returns (uint256) 
    {
       return uint256(state.minedNestAmount);
    }

    function latestMinedHeight() external view returns (uint64) 
    {
       return uint64(state.latestMiningHeight);
    }

    function mineNToken(address ntoken) public view returns (uint256) 
    {
        (uint256 _genesis, uint256 _last) = INToken(ntoken).checkBlockInfo();

        uint256 _period = block.number.sub(_genesis).div(MiningV1Data.MINING_NEST_YIELD_CUTBACK_PERIOD);
        uint256 _ntokenPerBlock;
        if (_period > 9) {
            _ntokenPerBlock = MiningV1Data.MINING_NTOKEN_YIELD_OFF_PERIOD_AMOUNT;
        } else {
            _ntokenPerBlock = state._mining_ntoken_yield_per_block_amount[_period];
        }
        uint256 _interval = block.number.sub(_last);
        if (_interval > MiningV1Data.MINING_NTOKEN_YIELD_BLOCK_LIMIT) {
            _interval = MiningV1Data.MINING_NTOKEN_YIELD_BLOCK_LIMIT;
        }

        // NOTE: no NTOKEN rewards if the mining interval is greater than a pre-defined number
        uint256 yieldAmount = _ntokenPerBlock.mul(_interval);
        return yieldAmount;
    }

    /* ========== WITHDRAW ========== */

    function withdrawEth(uint256 ethAmount) 
        external nonReentrant
    {
        INestPool(state.C_NestPool).withdrawEth(address(msg.sender), ethAmount); 
    }

    function withdrawEthAndToken(uint256 ethAmount, address token, uint256 tokenAmount) 
        external nonReentrant
    {
        INestPool(state.C_NestPool).withdrawEthAndToken(address(msg.sender), ethAmount, token, tokenAmount); 
    }

    function withdrawNest(uint256 nestAmount) 
        external nonReentrant
    {
        INestPool(state.C_NestPool).withdrawNest(address(msg.sender), nestAmount); 
    }

    function withdrawEthAndTokenAndNest(uint256 ethAmount, address token, uint256 tokenAmount, uint256 nestAmount) 
        external nonReentrant
    {
        INestPool(state.C_NestPool).withdrawEthAndToken(address(msg.sender), ethAmount, token, tokenAmount); 
        INestPool(state.C_NestPool).withdrawNest(address(msg.sender), nestAmount);
    }

    /* ========== VIEWS ========== */

    function lengthOfPriceSheets(address token) 
        view 
        external 
        returns (uint256)
    {
        return state.priceSheetList[token].length;
    }

    function priceSheet(address token, uint256 index) 
        view external 
        returns (MiningV1Data.PriceSheetPub memory sheet) 
    {
        return state._priceSheet(token, index); 
    }

    function fullPriceSheet(address token, uint256 index) 
        view 
        public
        noContract
        returns (MiningV1Data.PriceSheet memory sheet) 
    {
        uint256 len = state.priceSheetList[token].length;
        require (index < len, "Nest:Mine:>(len)");
        return state.priceSheetList[token][index];
    }

    function unVerifiedSheetList(address token)
        view 
        public
        noContract
        returns (MiningV1Data.PriceSheetPub2[] memory sheets) 
    {
        return state.unVerifiedSheetList(token);
    }

    function unClosedSheetListOf(address miner, address token, uint256 fromIndex, uint256 num) 
        view 
        public
        noContract
        returns (MiningV1Data.PriceSheetPub2[] memory sheets) 
    {
        return state.unClosedSheetListOf(miner, token, fromIndex, num);
    }

    function sheetListOf(address miner, address token, uint256 fromIndex, uint256 num) 
        view 
        public
        noContract
        returns (MiningV1Data.PriceSheetPub2[] memory sheets) 
    {
        return state.sheetListOf(miner, token, fromIndex, num);
    }

    /*
     /// @dev The function will be disabled when the upgrading is completed
    /// TODO: (TBD) auth needed? 
    function post2Only4Upgrade(
            address token,
            uint256 ethNum,
            uint256 tokenAmountPerEth,
            uint256 ntokenAmountPerEth
        )
        external 
        noContract
    {
       // only avialble in upgrade phase
        require (flag == MINING_FLAG_UPGRADE_NEEDED, "Nest:Mine:!flag");
        state._post2Only4Upgrade(token, ethNum, tokenAmountPerEth, ntokenAmountPerEth);
        address _ntoken = INestPool(state.C_NestPool).getNTokenFromToken(token);

        // calculate average price and volatility
        state._stat(token);
        state._stat(_ntoken);
    }
    */
}

File 2 of 16 : MiningV1Data.sol
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.6.12;


import "../iface/INestPool.sol";
import "../iface/INestStaking.sol";
import "../iface/INToken.sol";
import "../iface/INNRewardPool.sol";

import "../lib/SafeERC20.sol";


/// @author Inf Loop - <inf-loop@nestprotocol.org>
/// @author 0x00  - <0x00@nestprotocol.org>
library MiningV1Data {

    /* ========== CONSTANTS ========== */

    uint256 constant MINING_NEST_YIELD_CUTBACK_PERIOD = 2400000; // ~ 1 years 
    uint256 constant MINING_NEST_YIELD_CUTBACK_RATE = 80;     // percentage = 80%

    // yield amount (per block) after the first ten years
    uint256 constant MINING_NEST_YIELD_OFF_PERIOD_AMOUNT = 40 ether;
    // yield amount (per block) in the first year, it drops to 80% in the following nine years
    uint256 constant MINING_NEST_YIELD_PER_BLOCK_BASE = 400 ether;

    uint256 constant MINING_NTOKEN_YIELD_CUTBACK_RATE = 80;
    uint256 constant MINING_NTOKEN_YIELD_OFF_PERIOD_AMOUNT = 0.4 ether;
    uint256 constant MINING_NTOKEN_YIELD_PER_BLOCK_BASE = 4 ether;

    uint256 constant MINING_FINAL_BLOCK_NUMBER = 173121488;


    uint256 constant MINING_NEST_FEE_DIVIDEND_RATE = 80;    // percentage = 80%
    uint256 constant MINING_NEST_FEE_DAO_RATE = 20;         // percentage = 20%

    uint256 constant MINING_NTOKEN_FEE_DIVIDEND_RATE        = 60;     // percentage = 60%
    uint256 constant MINING_NTOKEN_FEE_DAO_RATE             = 20;     // percentage = 20%
    uint256 constant MINING_NTOKEN_FEE_NEST_DAO_RATE        = 20;     // percentage = 20%

    uint256 constant MINING_NTOKEN_YIELD_BLOCK_LIMIT = 100;

    uint256 constant NN_NEST_REWARD_PERCENTAGE = 15;
    uint256 constant DAO_NEST_REWARD_PERCENTAGE = 5;
    uint256 constant MINER_NEST_REWARD_PERCENTAGE = 80;

    uint256 constant MINING_LEGACY_NTOKEN_MINER_REWARD_PERCENTAGE = 95;
    uint256 constant MINING_LEGACY_NTOKEN_BIDDER_REWARD_PERCENTAGE = 5;

    uint8 constant PRICESHEET_STATE_CLOSED = 0;
    uint8 constant PRICESHEET_STATE_POSTED = 1;
    uint8 constant PRICESHEET_STATE_BITTEN = 2;

    uint8 constant PRICESHEET_TYPE_USD     = 1;
    uint8 constant PRICESHEET_TYPE_NEST    = 2;
    uint8 constant PRICESHEET_TYPE_TOKEN   = 3;
    uint8 constant PRICESHEET_TYPE_NTOKEN  = 4;
    uint8 constant PRICESHEET_TYPE_BITTING = 8;


    uint8 constant STATE_FLAG_UNINITIALIZED    = 0;
    uint8 constant STATE_FLAG_SETUP_NEEDED     = 1;
    uint8 constant STATE_FLAG_ACTIVE           = 3;
    uint8 constant STATE_FLAG_MINING_STOPPED   = 4;
    uint8 constant STATE_FLAG_CLOSING_STOPPED  = 5;
    uint8 constant STATE_FLAG_WITHDRAW_STOPPED = 6;
    uint8 constant STATE_FLAG_PRICE_STOPPED    = 7;
    uint8 constant STATE_FLAG_SHUTDOWN         = 127;

    uint256 constant MINING_NTOKEN_NON_DUAL_POST_THRESHOLD = 5_000_000 ether;


    /// @dev size: (2 x 256 bit)
    struct PriceSheet {    
        uint160 miner;       //  miner who posted the price (most significant bits, or left-most)
        uint32  height;      //
        uint32  ethNum;   
        uint32  remainNum;    

        uint8   level;           // the level of bitting, 1-4: eth-doubling | 5 - 127: nest-doubling
        uint8   typ;             // 1: USD | 2: NEST | 3: TOKEN | 4: NTOKEN
        uint8   state;           // 0: closed | 1: posted | 2: bitten
        uint8   _reserved;       // for padding
        uint32  ethNumBal;
        uint32  tokenNumBal;
        uint32  nestNum1k;
        uint128 tokenAmountPerEth;
    }
    
    /// @dev size: (3 x 256 bit)
    struct PriceInfo {
        uint32  index;
        uint32  height;         // NOTE: the height of being posted
        uint32  ethNum;         //  the balance of eth
        uint32  _reserved;
        uint128 tokenAmount;    //  the balance of token 
        int128  volatility_sigma_sq;
        int128  volatility_ut_sq;
        uint128  avgTokenAmount;  // avg = (tokenAmount : perEth)
        uint128 _reserved2;     
    }


    /// @dev The struct is for public data in a price sheet, so as to protect prices from being read
    struct PriceSheetPub {
        uint160 miner;       //  miner who posted the price (most significant bits, or left-most)
        uint32  height;
        uint32  ethNum;   

        uint8   typ;             // 1: USD | 2: NEST | 3: TOKEN | 4: NTOKEN(Not Available)
        uint8   state;           // 0: closed | 1: posted | 2: bitten
        uint32  ethNumBal;
        uint32  tokenNumBal;
    }


    struct PriceSheetPub2 {
        uint160 miner;       //  miner who posted the price (most significant bits, or left-most)
        uint32  height;
        uint32  ethNum;   
        uint32  remainNum; 

        uint8   level;           // the level of bitting, 1-4: eth-doubling | 5 - 127: nest-doubling
        uint8   typ;             // 1: USD | 2: NEST | 3: TOKEN | 4: NTOKEN(Not Available)
        uint8   state;           // 0: closed | 1: posted | 2: bitten
        uint256 index;           // return to the quotation of index
        uint32  nestNum1k;
        uint128 tokenAmountPerEth;   
    }

    /* ========== EVENTS ========== */

    event PricePosted(address miner, address token, uint256 index, uint256 ethAmount, uint256 tokenAmount);
    event PriceClosed(address miner, address token, uint256 index);
    event Deposit(address miner, address token, uint256 amount);
    event Withdraw(address miner, address token, uint256 amount);
    event TokenBought(address miner, address token, uint256 index, uint256 biteEthAmount, uint256 biteTokenAmount);
    event TokenSold(address miner, address token, uint256 index, uint256 biteEthAmount, uint256 biteTokenAmount);

    event VolaComputed(uint32 h, uint32 pos, uint32 ethA, uint128 tokenA, int128 sigma_sq, int128 ut_sq);

    event SetParams(uint8 miningEthUnit, uint32 nestStakedNum1k, uint8 biteFeeRate,
                    uint8 miningFeeRate, uint8 priceDurationBlock, uint8 maxBiteNestedLevel,
                    uint8 biteInflateFactor, uint8 biteNestInflateFactor);

    // event GovSet(address oldGov, address newGov);

    /* ========== GIANT STATE VARIABLE ========== */

    struct State {
        // TODO: more comments

        uint8   miningEthUnit;      // = 30 on mainnet;
        uint32  nestStakedNum1k;    // = 100;
        uint8   biteFeeRate;        // 
        uint8   miningFeeRate;      // = 10;  
        uint8   priceDurationBlock; // = 25;
        uint8   maxBiteNestedLevel; // = 3;
        uint8   biteInflateFactor;  // = 2;
        uint8   biteNestInflateFactor; // = 2;

        uint32  genesisBlock;       // = 6236588;

        uint128  latestMiningHeight;  // latest block number of NEST mining
        uint128  minedNestAmount;     // the total amount of mined NEST
        
        address  _developer_address;  // WARNING: DO NOT delete this unused variable
        address  _NN_address;         // WARNING: DO NOT delete this unused variable

        address  C_NestPool;
        address  C_NestToken;
        address  C_NestStaking;
        address  C_NNRewardPool;
        address  C_NestQuery;
        address  C_NestDAO;

        uint256[10] _mining_nest_yield_per_block_amount;
        uint256[10] _mining_ntoken_yield_per_block_amount;

        // A mapping (from token(address) to an array of PriceSheet)
        mapping(address => PriceSheet[]) priceSheetList;

        // from token(address) to Price
        mapping(address => PriceInfo) priceInfo;

        // (token-address, block-number) => (ethFee-total, nest/ntoken-mined-total)
        mapping(address => mapping(uint256 => uint256)) minedAtHeight;

        // WARNING: DO NOT delete these variables, reserved for future use
        uint256  _reserved1;
        uint256  _reserved2;
        uint256  _reserved3;
        uint256  _reserved4;
    }

}

// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

import "../lib/SafeMath.sol";
import "../lib/SafeERC20.sol";
import '../lib/TransferHelper.sol';
import "../lib/ABDKMath64x64.sol";

import "../iface/INestPool.sol";
import "../iface/INestStaking.sol";
import "../iface/INToken.sol";
import "../iface/INNRewardPool.sol";
import "../libminingv1/MiningV1Data.sol";
//import "hardhat/console.sol";


/// @title  NestMiningV1/MiningV1Calc
/// @author Inf Loop - <inf-loop@nestprotocol.org>
/// @author Paradox  - <paradox@nestprotocol.org>
library MiningV1Calc {

    using SafeMath for uint256;
    
    /// @dev Average block mining interval, ~ 14s
    uint256 constant ETHEREUM_BLOCK_TIMESPAN = 14;

    function _calcVola(
            // uint256 ethA0, 
            uint256 tokenA0, 
            // uint256 ethA1, 
            uint256 tokenA1, 
            int128 _sigma_sq, 
            int128 _ut_sq,
            uint256 _interval
        )
        private
        pure
        // pure 
        returns (int128, int128)
    {
        int128 _ut_sq_2 = ABDKMath64x64.div(_ut_sq, 
            ABDKMath64x64.fromUInt(_interval.mul(ETHEREUM_BLOCK_TIMESPAN)));

        int128 _new_sigma_sq = ABDKMath64x64.add(
            ABDKMath64x64.mul(ABDKMath64x64.divu(95, 100), _sigma_sq),
            ABDKMath64x64.mul(ABDKMath64x64.divu(5,100), _ut_sq_2));

        int128 _new_ut_sq;
        _new_ut_sq = ABDKMath64x64.pow(ABDKMath64x64.sub(
                    ABDKMath64x64.divu(tokenA1, tokenA0), 
                    ABDKMath64x64.fromUInt(1)), 
                2);
        
        return (_new_sigma_sq, _new_ut_sq);
    }

    function _calcAvg(uint256 ethA, uint256 tokenA, uint256 _avg)
        private 
        pure
        returns(uint256)
    {
        uint256 _newP = tokenA.div(ethA);
        uint256 _newAvg;

        if (_avg == 0) {
            _newAvg = _newP;
        } else {
            _newAvg = (_avg.mul(95).div(100)).add(_newP.mul(5).div(100));
            // _newAvg = ABDKMath64x64.add(
            //     ABDKMath64x64.mul(ABDKMath64x64.divu(95, 100), _avg),
            //     ABDKMath64x64.mul(ABDKMath64x64.divu(5,100), _newP));
        }

        return _newAvg;
    }

    function _moveAndCalc(
            MiningV1Data.PriceInfo memory p0,
            MiningV1Data.PriceSheet[] storage pL,
            uint256 priceDurationBlock
        )
        private
        view
        returns (MiningV1Data.PriceInfo memory)
    {
        uint256 i = p0.index + 1;
        if (i >= pL.length) {
            return (MiningV1Data.PriceInfo(0,0,0,0,0,int128(0),int128(0), uint128(0), 0));
        }

        uint256 h = uint256(pL[i].height);
        if (h + priceDurationBlock >= block.number) {
            return (MiningV1Data.PriceInfo(0,0,0,0,0,int128(0),int128(0), uint128(0), 0));
        }

        uint256 ethA1 = 0;
        uint256 tokenA1 = 0;
        while (i < pL.length && pL[i].height == h) {
            uint256 _remain = uint256(pL[i].remainNum);
            if (_remain == 0) {
                i = i + 1;
                continue;  // jump over a bitten sheet
            }
            ethA1 = ethA1 + _remain;
            tokenA1 = tokenA1 + _remain.mul(pL[i].tokenAmountPerEth);
            i = i + 1;
        }
        i = i - 1;

        if (ethA1 == 0 || tokenA1 == 0) {
            return (MiningV1Data.PriceInfo(
                    uint32(i),  // index
                    uint32(0),  // height
                    uint32(0),  // ethNum
                    uint32(0),  // _reserved
                    uint32(0),  // tokenAmount
                    int128(0),  // volatility_sigma_sq
                    int128(0),  // volatility_ut_sq
                    uint128(0),  // avgTokenAmount
                    0           // _reserved2
            ));
        }
        int128 new_sigma_sq;
        int128 new_ut_sq;
        {
            if (uint256(p0.ethNum) != 0) {
                (new_sigma_sq, new_ut_sq) = _calcVola(
                    uint256(p0.tokenAmount).div(uint256(p0.ethNum)), 
                    uint256(tokenA1).div(uint256(ethA1)),
                p0.volatility_sigma_sq, p0.volatility_ut_sq,
                h - p0.height);
            }
        }
        uint256 _newAvg = _calcAvg(ethA1, tokenA1, p0.avgTokenAmount); 

        return(MiningV1Data.PriceInfo(
                uint32(i),          // index
                uint32(h),          // height
                uint32(ethA1),      // ethNum
                uint32(0),          // _reserved
                uint128(tokenA1),   // tokenAmount
                new_sigma_sq,       // volatility_sigma_sq
                new_ut_sq,          // volatility_ut_sq
                uint128(_newAvg),   // avgTokenAmount
                uint128(0)          // _reserved2
        ));
    }

    /// @dev The function updates the statistics of price sheets
    ///     It calculates from priceInfo to the newest that is effective.
    ///     Different from `_statOneBlock()`, it may cross multiple blocks.
    function _stat(MiningV1Data.State storage state, address token)
        external 
    {
        MiningV1Data.PriceInfo memory p0 = state.priceInfo[token];
        MiningV1Data.PriceSheet[] storage pL = state.priceSheetList[token];

        if (pL.length < 2) {
            return;
        }

        if (p0.height == 0) {

            MiningV1Data.PriceSheet memory _sheet = pL[0];
            p0.ethNum = _sheet.ethNum;
            p0.tokenAmount = uint128(uint256(_sheet.tokenAmountPerEth).mul(_sheet.ethNum));
            p0.height = _sheet.height;
            p0.volatility_sigma_sq = 0;
            p0.volatility_ut_sq = 0;
            p0.avgTokenAmount = uint128(_sheet.tokenAmountPerEth);
            // write back
            state.priceInfo[token] = p0;
        }

        MiningV1Data.PriceInfo memory p1;

        // record the gas usage
        uint256 startGas = gasleft();
        uint256 gasUsed;

        while (uint256(p0.index) < pL.length && uint256(p0.height) + state.priceDurationBlock < block.number){
            gasUsed = startGas - gasleft();
            // NOTE: check gas usage to prevent DOS attacks
            if (gasUsed > 1_000_000) {
                break; 
            }
            p1 = _moveAndCalc(p0, pL, state.priceDurationBlock);
            if (p1.index <= p0.index) {    // bootstraping
                break;
            } else if (p1.ethNum == 0) {   // jump cross a block with bitten prices
                p0.index = p1.index;
                continue;
            } else {                       // calculate one more block
                p0 = p1;
            }
        }

        if (p0.index > state.priceInfo[token].index) {
            state.priceInfo[token] = p0;
        }

        return;
    }

    /// @dev The function updates the statistics of price sheets across only one block.
    function _statOneBlock(MiningV1Data.State storage state, address token) 
        external 
    {
        MiningV1Data.PriceInfo memory p0 = state.priceInfo[token];
        MiningV1Data.PriceSheet[] storage pL = state.priceSheetList[token];
        if (pL.length < 2) {
            return;
        }
        (MiningV1Data.PriceInfo memory p1) = _moveAndCalc(p0, state.priceSheetList[token], state.priceDurationBlock);
        if (p1.index > p0.index && p1.ethNum != 0) {
            state.priceInfo[token] = p1;
        } else if (p1.index > p0.index && p1.ethNum == 0) {
            p0.index = p1.index;
            state.priceInfo[token] = p1;
        }
        return;
    }

    /// @notice Return a consecutive price list for a token 
    /// @dev 
    /// @param token The address of token contract
    /// @param num   The length of price list
    function _priceListOfToken(
            MiningV1Data.State storage state, 
            address token, 
            uint8 num
        )
        external 
        view
        returns (uint128[] memory data, uint256 bn) 
    {
        MiningV1Data.PriceSheet[] storage _list = state.priceSheetList[token];
        uint256 len = _list.length;
        uint256 _index = 0;
        data = new uint128[](num * 3);
        MiningV1Data.PriceSheet memory _sheet;
        uint256 _ethNum;

        // loop
        uint256 _curr = 0;
        uint256 _prev = 0;
        for (uint i = 1; i <= len; i++) {
            _sheet = _list[len - i];
            _curr = uint256(_sheet.height);
            if (_prev == 0) {
                if (_curr + state.priceDurationBlock < block.number) {
                    _ethNum = uint256(_sheet.remainNum);
                    if(_ethNum > 0) {
                        data[_index] = uint128(_curr + state.priceDurationBlock); // safe math
                        data[_index + 1] = uint128(_ethNum.mul(1 ether));
                        data[_index + 2] = uint128(_ethNum.mul(_sheet.tokenAmountPerEth));
                        bn = _curr + state.priceDurationBlock;  // safe math
                        _prev = _curr;
                    }
                }
            } else if (_prev == _curr) {
                _ethNum = uint256(_sheet.remainNum);
                data[_index + 1] += uint128(_ethNum.mul(1 ether));
                data[_index + 2] += uint128(_ethNum.mul(_sheet.tokenAmountPerEth));
            } else if (_prev > _curr) {
                _ethNum = uint256(_sheet.remainNum);
                if(_ethNum > 0){
                    _index += 3;
                    if (_index >= uint256(num * 3)) {
                        break;
                    }
                    data[_index] = uint128(_curr + state.priceDurationBlock); // safe math
                    data[_index + 1] = uint128(_ethNum.mul(1 ether));
                    data[_index + 2] = uint128(_ethNum.mul(_sheet.tokenAmountPerEth));
                    _prev = _curr;
                }
            }
        } 
        // require (data.length == uint256(num * 3), "Incorrect price list length");
    }

    function _priceOfTokenAtHeight(
            MiningV1Data.State storage state, 
            address token, 
            uint64 atHeight
        )
        external 
        view 
        returns(uint256 ethAmount, uint256 tokenAmount, uint256 blockNum) 
    {
        require(atHeight <= block.number, "Nest:Mine:!height");

        MiningV1Data.PriceSheet[] storage _list = state.priceSheetList[token];
        uint256 len = state.priceSheetList[token].length;
        MiningV1Data.PriceSheet memory _sheet;
        uint256 _ethNum;

        if (len == 0) {
            return (0, 0, 0);
        }

        uint256 _first = 0;
        uint256 _prev = 0;
        for (uint i = 1; i <= len; i++) {
            _sheet = _list[len - i];
            _first = uint256(_sheet.height);
            if (_prev == 0) {
                if (_first + state.priceDurationBlock < uint256(atHeight)) {
                    _ethNum = uint256(_sheet.remainNum);
                    if (_ethNum == 0) {
                        continue; // jump over a bitten sheet
                    }
                    ethAmount = _ethNum.mul(1 ether);
                    tokenAmount = _ethNum.mul(_sheet.tokenAmountPerEth);
                    blockNum = _first + state.priceDurationBlock;
                    _prev = _first;
                }
            } else if (_first == _prev) {
                _ethNum = uint256(_sheet.remainNum);
                ethAmount = ethAmount.add(_ethNum.mul(1 ether));
                tokenAmount = tokenAmount.add(_ethNum.mul(_sheet.tokenAmountPerEth));
            } else if (_prev > _first) {
                break;
            }
        }
    }

    function _priceSheet(
            MiningV1Data.State storage state, 
            address token, 
            uint256 index
        ) 
        view external 
        returns (MiningV1Data.PriceSheetPub memory sheet) 
    {
        uint256 len = state.priceSheetList[token].length;
        require (index < len, "Nest:Mine:!index");
        MiningV1Data.PriceSheet memory _sheet = state.priceSheetList[token][index];
        sheet.miner = _sheet.miner;
        sheet.height = _sheet.height;
        sheet.ethNum = _sheet.ethNum;
        sheet.typ = _sheet.typ;
        sheet.state = _sheet.state;
        sheet.ethNumBal = _sheet.ethNumBal;
        sheet.tokenNumBal = _sheet.tokenNumBal;
    }

    
    function unVerifiedSheetList(
            MiningV1Data.State storage state, 
            address token
        ) 
        view 
        public
        returns (MiningV1Data.PriceSheetPub2[] memory sheets) 
    {
        MiningV1Data.PriceSheet[] storage _list = state.priceSheetList[token]; 
        uint256 len = _list.length;
        uint256 num;
        for (uint i = 0; i < len; i++) {
            if (_list[len - 1 - i].height + state.priceDurationBlock < block.number) {
                break;
            }
            num += 1;
        }

        sheets = new MiningV1Data.PriceSheetPub2[](num);
        for (uint i = 0; i < num; i++) {
            MiningV1Data.PriceSheet memory _sheet = _list[len - 1 - i];
            if (uint256(_sheet.height) + state.priceDurationBlock < block.number) {
                break;
            }
            //sheets[i] = _sheet;
            sheets[i].miner = _sheet.miner;
            sheets[i].height = _sheet.height;
            sheets[i].ethNum = _sheet.ethNum;
            sheets[i].remainNum = _sheet.remainNum;
            sheets[i].level = _sheet.level;
            sheets[i].typ = _sheet.typ;
            sheets[i].state = _sheet.state;

            sheets[i].index = len - 1 - i;

            sheets[i].nestNum1k = _sheet.nestNum1k;
            sheets[i].tokenAmountPerEth = _sheet.tokenAmountPerEth;
        }
    }

    function unClosedSheetListOf(
            MiningV1Data.State storage state, 
            address miner, 
            address token, 
            uint256 fromIndex, 
            uint256 num) 
        view 
        external
        returns (MiningV1Data.PriceSheetPub2[] memory sheets) 
    {
        sheets = new MiningV1Data.PriceSheetPub2[](num);
        MiningV1Data.PriceSheet[] storage _list = state.priceSheetList[token]; 
        uint256 len = _list.length;
        require(fromIndex < len, "Nest:Mine:!from");

        for (uint i = 0; i < num; i++) {
            if (fromIndex < i) {
                break;
            }

            MiningV1Data.PriceSheet memory _sheet = _list[fromIndex - i];
            if (uint256(_sheet.miner) == uint256(miner)
                && (_sheet.state == MiningV1Data.PRICESHEET_STATE_POSTED 
                    || _sheet.state == MiningV1Data.PRICESHEET_STATE_BITTEN)) {
            
                sheets[i].miner = _sheet.miner;
                sheets[i].height = _sheet.height;
                sheets[i].ethNum = _sheet.ethNum;
                sheets[i].remainNum = _sheet.remainNum;
                sheets[i].level = _sheet.level;
                sheets[i].typ = _sheet.typ;
                sheets[i].state = _sheet.state;

                sheets[i].index = fromIndex - i;

                sheets[i].nestNum1k = _sheet.nestNum1k;
                sheets[i].tokenAmountPerEth = _sheet.tokenAmountPerEth;

            }
        }
    }

    function sheetListOf(
           MiningV1Data.State storage state, 
           address miner, 
           address token, 
           uint256 fromIndex, 
           uint256 num
        ) 
        view 
        external
        returns (MiningV1Data.PriceSheetPub2[] memory sheets) 
    {
        sheets = new MiningV1Data.PriceSheetPub2[](num);
        MiningV1Data.PriceSheet[] storage _list = state.priceSheetList[token]; 
        uint256 len = _list.length;
        require(fromIndex < len, "Nest:Mine:!from");

        for (uint i = 0; i < num; i++) {
            if (fromIndex < i) {
                break;
            }
            MiningV1Data.PriceSheet memory _sheet = _list[fromIndex - i];
            if (uint256(_sheet.miner) == uint256(miner)) {
            
                sheets[i].miner = _sheet.miner;
                sheets[i].height = _sheet.height;
                sheets[i].ethNum = _sheet.ethNum;
                sheets[i].remainNum = _sheet.remainNum;
                sheets[i].level = _sheet.level;
                sheets[i].typ = _sheet.typ;
                sheets[i].state = _sheet.state;

                sheets[i].index = fromIndex - i;
                sheets[i].nestNum1k = _sheet.nestNum1k;
                sheets[i].tokenAmountPerEth = _sheet.tokenAmountPerEth;

            }
        }
    }

}

// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

import "../lib/SafeMath.sol";
import "../lib/SafeERC20.sol";
import '../lib/TransferHelper.sol';
import "../lib/ABDKMath64x64.sol";

import "../iface/INestPool.sol";
import "../iface/INestStaking.sol";
import "../iface/INToken.sol";
import "../iface/INNRewardPool.sol";
import "../libminingv1/MiningV1Data.sol";

//import "hardhat/console.sol";

/// @title  NestMiningV1/MiningV1Calc
/// @author Inf Loop - <inf-loop@nestprotocol.org>
/// @author Paradox  - <paradox@nestprotocol.org>
library MiningV1Op {

    using SafeMath for uint256;

    /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet
    /// @dev bite TOKEN(NTOKEN) by ETH,  (+ethNumBal, -tokenNumBal)
    /// @param token The address of token(ntoken)
    /// @param index The position of the sheet in priceSheetList[token]
    /// @param biteNum The amount of bitting (in the unit of ETH), realAmount = biteNum * newTokenAmountPerEth
    /// @param newTokenAmountPerEth The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth
    function _biteToken(
            MiningV1Data.State storage state, 
            address token, 
            uint256 index, 
            uint256 biteNum, 
            uint256 newTokenAmountPerEth
        )
        external
    {
        // check parameters
        require(token != address(0x0), "Nest:Mine:(token)=0"); 
        require(newTokenAmountPerEth > 0, "Nest:Mine:(price)=0");
        require(biteNum >= state.miningEthUnit && biteNum % state.miningEthUnit == 0, "Nest:Mine:!(bite)");

        // check sheet
        MiningV1Data.PriceSheet memory _sheet = state.priceSheetList[token][index]; 
        require(uint256(_sheet.height) + state.priceDurationBlock >= block.number, "Nest:Mine:!EFF(sheet)");
        require(uint256(_sheet.remainNum) >= biteNum, "Nest:Mine:!(remain)");

        // load address of NestPool 
        INestPool _C_NestPool = INestPool(state.C_NestPool);

        // check sheet sate
        uint256 _state = uint256(_sheet.state);
        require(_state == MiningV1Data.PRICESHEET_STATE_POSTED 
             || _state == MiningV1Data.PRICESHEET_STATE_BITTEN,  "Nest:Mine:!(state)");

        {
            // load NTOKEN
            address _ntoken = _C_NestPool.getNTokenFromToken(token);
            // calculate fee
            uint256 _ethFee = biteNum.mul(1 ether).mul(state.biteFeeRate).div(1000);

            // save the changes into miner's virtual account
            if (msg.value.sub(_ethFee) > 0) {
                _C_NestPool.depositEth{value:msg.value.sub(_ethFee)}(address(msg.sender));
            }

            // pump fee into staking pool
            if (_ethFee > 0) {
                INestStaking(state.C_NestStaking).addETHReward{value:_ethFee}(_ntoken);
            }
        }
 
        // post a new price sheet
        { 
            // check bitting conditions
            uint256 _newEthNum;
            uint256 _newNestNum1k = uint256(_sheet.nestNum1k);
            {
                uint256 _level = uint256(_sheet.level);
                uint256 _newLevel;
                
                // calculate `(_newEthNum, _newNestNum1k, _newLevel)`
                if (_level > state.maxBiteNestedLevel && _level < 127) { // bitten sheet, nest doubling
                    _newEthNum = biteNum;
                    _newNestNum1k = _newNestNum1k.mul(biteNum.mul(state.biteNestInflateFactor)).div(_sheet.ethNum);
                    _newLevel = _level + 1;
                } else if (_level <= state.maxBiteNestedLevel) {  // bitten sheet, eth doubling 
                    _newEthNum = biteNum.mul(state.biteInflateFactor);
                    _newNestNum1k = _newNestNum1k.mul(biteNum.mul(state.biteNestInflateFactor)).div(_sheet.ethNum);
                    _newLevel = _level + 1;
                }

                // freeze NEST 
                _C_NestPool.freezeNest(address(msg.sender), _newNestNum1k.mul(1000 * 1e18));

                // freeze(TOKEN, ETH); or freeeze(ETH) but unfreeze(TOKEN)
                if (_newEthNum.mul(newTokenAmountPerEth) < biteNum * _sheet.tokenAmountPerEth) {
                    uint256 _unfreezetokenAmount;
                    _unfreezetokenAmount = uint256(_sheet.tokenAmountPerEth).mul(biteNum).sub((uint256(newTokenAmountPerEth)).mul(_newEthNum));               
                    _C_NestPool.unfreezeToken(msg.sender, token, _unfreezetokenAmount);
                    _C_NestPool.freezeEth(msg.sender, _newEthNum.add(biteNum).mul(1 ether));
                } else {
                    _C_NestPool.freezeEthAndToken(msg.sender, _newEthNum.add(biteNum).mul(1 ether), 
                        token, _newEthNum.mul(newTokenAmountPerEth)
                                         .sub(biteNum * _sheet.tokenAmountPerEth));
                }

                MiningV1Data.PriceSheet[] storage _sheetOfToken = state.priceSheetList[token];
                // append a new price sheet
                _sheetOfToken.push(MiningV1Data.PriceSheet(
                    uint160(msg.sender),                // miner 
                    uint32(block.number),               // atHeight
                    uint32(_newEthNum),                 // ethNum
                    uint32(_newEthNum),                 // remainNum
                    uint8(_newLevel),                   // level
                    uint8(_sheet.typ),                  // typ
                    uint8(MiningV1Data.PRICESHEET_STATE_POSTED),  // state 
                    uint8(0),                           // _reserved
                    uint32(_newEthNum),                 // ethNumBal
                    uint32(_newEthNum),                 // tokenNumBal
                    uint32(_newNestNum1k),              // nestNum1k
                    uint128(newTokenAmountPerEth)     // tokenAmountPerEth
                ));
              
            }

            // update the bitten sheet
            _sheet.state = MiningV1Data.PRICESHEET_STATE_BITTEN;
            _sheet.ethNumBal = uint32(uint256(_sheet.ethNumBal).add(biteNum));
            _sheet.tokenNumBal = uint32(uint256(_sheet.tokenNumBal).sub(biteNum));
            _sheet.remainNum = uint32(uint256(_sheet.remainNum).sub(biteNum));
            state.priceSheetList[token][index] = _sheet;
            
        }

        emit MiningV1Data.TokenBought(address(msg.sender), address(token), index, biteNum.mul(1 ether), biteNum.mul(_sheet.tokenAmountPerEth));
        return; 

    }

    /// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet
    /// @dev bite TOKEN(NTOKEN) by ETH,  (+ethNumBal, -tokenNumBal)
    /// @param token The address of token(ntoken)
    /// @param index The position of the sheet in priceSheetList[token]
    /// @param biteNum The amount of bitting (in the unit of ETH), realAmount = biteNum * newTokenAmountPerEth
    /// @param newTokenAmountPerEth The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth
    function _biteEth(
            MiningV1Data.State storage state, 
            address token, 
            uint256 index, 
            uint256 biteNum, 
            uint256 newTokenAmountPerEth
        )
        external
    {
        // check parameters
        require(token != address(0x0), "Nest:Mine:(token)=0"); 
        require(newTokenAmountPerEth > 0, "Nest:Mine:(price)=0");
        require(biteNum >= state.miningEthUnit && biteNum % state.miningEthUnit == 0, "Nest:Mine:!(bite)");

        MiningV1Data.PriceSheet memory _sheet = state.priceSheetList[token][index]; 
        require(uint256(_sheet.height) + state.priceDurationBlock >= block.number, "Nest:Mine:!EFF(sheet)");
        require(uint256(_sheet.remainNum) >= biteNum, "Nest:Mine:!(remain)");

        // load NestPool
        INestPool _C_NestPool = INestPool(state.C_NestPool);

        // check state
        uint256 _state = uint256(_sheet.state);
        require(_state == MiningV1Data.PRICESHEET_STATE_POSTED 
            || _state == MiningV1Data.PRICESHEET_STATE_BITTEN,  "Nest:Mine:!(state)");

        {
            // load NTOKEN
            address _ntoken = _C_NestPool.getNTokenFromToken(token);

            // calculate fee
            uint256 _ethFee = biteNum.mul(1 ether).mul(state.biteFeeRate).div(1000);

            // save the changes into miner's virtual account
            if (msg.value.sub(_ethFee) > 0) {
                _C_NestPool.depositEth{value:msg.value.sub(_ethFee)}(address(msg.sender));
            }

            // pump fee into NestStaking
            INestStaking(state.C_NestStaking).addETHReward{value:_ethFee}(_ntoken);
        }
        
        // post a new price sheet
        { 
            // check bitting conditions
            uint256 _newEthNum;
            uint256 _newNestNum1k = uint256(_sheet.nestNum1k);
            {
                uint256 _level = uint256(_sheet.level);
                uint256 _newLevel;

                if (_level > state.maxBiteNestedLevel && _level < 127) { // bitten sheet, nest doubling
                    _newEthNum = biteNum;
                    _newNestNum1k = _newNestNum1k.mul(biteNum.mul(state.biteNestInflateFactor)).div(_sheet.ethNum);
                    _newLevel = _level + 1;
                } else if (_level <= state.maxBiteNestedLevel) {  // bitten sheet, eth doubling 
                    _newEthNum = biteNum.mul(state.biteInflateFactor);
                    _newNestNum1k = _newNestNum1k.mul(biteNum.mul(state.biteNestInflateFactor)).div(_sheet.ethNum);
                    _newLevel = _level + 1;
                }

                MiningV1Data.PriceSheet[] storage _sheetOfToken = state.priceSheetList[token];
                // append a new price sheet
                _sheetOfToken.push(MiningV1Data.PriceSheet(
                    uint160(msg.sender),             // miner 
                    uint32(block.number),            // atHeight
                    uint32(_newEthNum),                 // ethNum
                    uint32(_newEthNum),                 // remainNum
                    uint8(_newLevel),                // level
                    uint8(_sheet.typ),               // typ
                    uint8(MiningV1Data.PRICESHEET_STATE_POSTED),  // state 
                    uint8(0),                        // _reserved
                    uint32(_newEthNum),                 // ethNumBal
                    uint32(_newEthNum),                 // tokenNumBal
                    uint32(_newNestNum1k),           // nestNum1k
                    uint128(newTokenAmountPerEth)    // tokenAmountPerEth
                ));
            }

            // freeze NEST 
            _C_NestPool.freezeNest(address(msg.sender), _newNestNum1k.mul(1000 * 1e18));

            // freeze(TOKEN, ETH)
            _C_NestPool.freezeEthAndToken(msg.sender, _newEthNum.sub(biteNum).mul(1 ether), 
                token, _newEthNum.mul(newTokenAmountPerEth)
                                    .add(biteNum.mul(_sheet.tokenAmountPerEth)));

            // update the bitten sheet
            _sheet.state = MiningV1Data.PRICESHEET_STATE_BITTEN;
            _sheet.ethNumBal = uint32(uint256(_sheet.ethNumBal).sub(biteNum));
            _sheet.tokenNumBal = uint32(uint256(_sheet.tokenNumBal).add(biteNum));
            _sheet.remainNum = uint32(uint256(_sheet.remainNum).sub(biteNum));
            state.priceSheetList[token][index] = _sheet;
        }

        emit MiningV1Data.TokenSold(address(msg.sender), address(token), index, biteNum.mul(1 ether), biteNum.mul(_sheet.tokenAmountPerEth));
        return; 
    }

    /// @notice Close a price sheet of (ETH, USDx) | (ETH, NEST) | (ETH, TOKEN) | (ETH, NTOKEN)
    /// @dev Here we allow an empty price sheet (still in VERIFICATION-PERIOD) to be closed 
    /// @param token The address of TOKEN contract
    /// @param index The index of the price sheet w.r.t. `token`
    function _close(
            MiningV1Data.State storage state, 
            address token, 
            uint256 index
        )
        external
    {
        // load sheet
        MiningV1Data.PriceSheet memory _sheet = state.priceSheetList[token][index];
        // check if the sheet is closable
        require(uint256(_sheet.height) + state.priceDurationBlock < block.number // safe_math
            || _sheet.remainNum == 0, "Nest:Mine:!(height)");

        // check owner
        require(address(_sheet.miner) == address(msg.sender), "Nest:Mine:!(miner)");
        // check state flag
        require(uint256(_sheet.state) != MiningV1Data.PRICESHEET_STATE_CLOSED, "Nest:Mine:!unclosed");

        // load ntoken
        INestPool _C_NestPool = INestPool(state.C_NestPool);
        address _ntoken = _C_NestPool.getNTokenFromToken(token);

        // distribute rewards (NEST or NTOKEN)
        {
            uint256 h = _sheet.height;
            if (_sheet.typ == MiningV1Data.PRICESHEET_TYPE_USD && _sheet.level == 0) {   // for (USDT, NEST)
                uint256 _nestH = uint256(state.minedAtHeight[token][h] / (1 << 128));
                uint256 _ethH = uint256(state.minedAtHeight[token][h] % (1 << 128));
                uint256 _reward = uint256(_sheet.ethNum).mul(_nestH).div(_ethH);
                _C_NestPool.addNest(address(msg.sender), _reward);
            } else if (_sheet.typ == MiningV1Data.PRICESHEET_TYPE_TOKEN && _sheet.level == 0) { // for (ERC20, NTOKEN)
                uint256 _ntokenH = uint256(state.minedAtHeight[token][h] / (1 << 128));
                uint256 _ethH = uint256(state.minedAtHeight[token][h] % (1 << 128));
                uint256 _reward = uint256(_sheet.ethNum).mul(_ntokenH).div(_ethH);
                _C_NestPool.addNToken(address(msg.sender), _ntoken, _reward);
            }
        }

        // unfreeze the assets withheld by the sheet
        {
            uint256 _ethAmount = uint256(_sheet.ethNumBal).mul(1 ether);
            uint256 _tokenAmount = uint256(_sheet.tokenNumBal).mul(_sheet.tokenAmountPerEth);
            uint256 _nestAmount = uint256(_sheet.nestNum1k).mul(1000 * 1e18);
            _sheet.ethNumBal = 0;
            _sheet.tokenNumBal = 0;
            _sheet.nestNum1k = 0;

            _C_NestPool.unfreezeEthAndToken(address(msg.sender), _ethAmount, token, _tokenAmount);
            _C_NestPool.unfreezeNest(address(msg.sender), _nestAmount); 
        }

        // update the state flag
        _sheet.state = MiningV1Data.PRICESHEET_STATE_CLOSED;

        // write back
        state.priceSheetList[token][index] = _sheet;

        // emit an event
        emit MiningV1Data.PriceClosed(address(msg.sender), token, index);
    }

    /// @notice Close a price sheet and withdraw assets for WEB users.  
    /// @dev Contracts aren't allowed to call it.
    /// @param token The address of TOKEN contract
    /// @param index The index of the price sheet w.r.t. `token`
    function _closeAndWithdraw(
            MiningV1Data.State storage state, 
            address token, 
            uint256 index
        ) 
        external 
    {
        // check sheet if passing verification
        MiningV1Data.PriceSheet memory _sheet = state.priceSheetList[token][index];
        require(uint256(_sheet.height) + state.priceDurationBlock < block.number // safe_math
            || _sheet.remainNum == 0, "Nest:Mine:!(height)");

        // check ownership and state
        require(address(_sheet.miner) == address(msg.sender), "Nest:Mine:!(miner)");
        require(uint256(_sheet.state) != MiningV1Data.PRICESHEET_STATE_CLOSED, "Nest:Mine:!unclosed");

        // get ntoken
        INestPool _C_NestPool = INestPool(state.C_NestPool);
        address _ntoken = _C_NestPool.getNTokenFromToken(token);

        {
            uint256 h = uint256(_sheet.height);
            if (_sheet.typ == MiningV1Data.PRICESHEET_TYPE_USD && _sheet.level == 0) {
                uint256 _nestH = uint256(state.minedAtHeight[token][h] / (1 << 128));
                uint256 _ethH = uint256(state.minedAtHeight[token][h] % (1 << 128));
                uint256 _reward = uint256(_sheet.ethNum).mul(_nestH).div(_ethH);
                _C_NestPool.addNest(address(msg.sender), _reward);
            } else if (_sheet.typ == MiningV1Data.PRICESHEET_TYPE_TOKEN && _sheet.level == 0) {
                uint256 _ntokenH = uint256(state.minedAtHeight[token][h] / (1 << 128));
                uint256 _ethH = uint256(state.minedAtHeight[token][h] % (1 << 128));
                uint256 _reward = uint256(_sheet.ethNum).mul(_ntokenH).div(_ethH);
                _C_NestPool.addNToken(address(msg.sender), _ntoken, _reward);
            }
        }

        {
            uint256 _ethAmount = uint256(_sheet.ethNumBal).mul(1 ether);
            uint256 _tokenAmount = uint256(_sheet.tokenNumBal).mul(_sheet.tokenAmountPerEth);
            uint256 _nestAmount = uint256(_sheet.nestNum1k).mul(1000 * 1e18);
            _sheet.ethNumBal = 0;
            _sheet.tokenNumBal = 0;
            _sheet.nestNum1k = 0;

            _C_NestPool.unfreezeEthAndToken(address(msg.sender), _ethAmount, token, _tokenAmount);
            _C_NestPool.unfreezeNest(address(msg.sender), _nestAmount); 
            _C_NestPool.withdrawEthAndToken(address(msg.sender), _ethAmount, token, _tokenAmount);
            _C_NestPool.withdrawNest(address(msg.sender), _nestAmount);
        }

        /*  
        - Issue #23: 
            Uncomment the following code to support withdrawing ethers cached 
        {
            uint256 _ethAmount = _C_NestPool.balanceOfEthInPool(address(msg.sender));
            if (_ethAmount > 0) {
                _C_NestPool.withdrawEth(address(msg.sender), _ethAmount);
            }
        }
        */

        _sheet.state = MiningV1Data.PRICESHEET_STATE_CLOSED;

        state.priceSheetList[token][index] = _sheet;

        emit MiningV1Data.PriceClosed(address(msg.sender), token, index);    
    }

    /// @notice Close a batch of price sheets passed VERIFICATION-PHASE
    /// @dev Empty sheets but in VERIFICATION-PHASE aren't allowed
    /// @param token The address of TOKEN contract
    /// @param indices A list of indices of sheets w.r.t. `token`
    function _closeList(
            MiningV1Data.State storage state, 
            address token, 
            uint32[] memory indices) 
        external 
    {
        uint256 _ethAmount;
        uint256 _tokenAmount;
        uint256 _nestAmount;
        uint256 _reward;

        // load storage point to the list of price sheets
        MiningV1Data.PriceSheet[] storage prices = state.priceSheetList[token];
        
        // loop
        for (uint i=0; i<indices.length; i++) {
            // load one sheet
            MiningV1Data.PriceSheet memory _sheet = prices[indices[i]];

            // check owner
            if (uint256(_sheet.miner) != uint256(msg.sender)) {
                continue;
            }

            // check state
            if(_sheet.state == MiningV1Data.PRICESHEET_STATE_CLOSED) {
                continue;
            }

            uint256 h = uint256(_sheet.height);
            // check if the sheet closable
            if (h + state.priceDurationBlock < block.number || _sheet.remainNum == 0) { // safe_math: untainted values

                // count up assets in the sheet
                _ethAmount = _ethAmount.add(uint256(_sheet.ethNumBal).mul(1 ether));
                _tokenAmount = _tokenAmount.add(uint256(_sheet.tokenNumBal).mul(_sheet.tokenAmountPerEth));
                _nestAmount = _nestAmount.add(uint256(_sheet.nestNum1k).mul(1000 * 1e18));

                // clear bits in the sheet
                _sheet.ethNumBal = 0;
                _sheet.tokenNumBal = 0;
                _sheet.nestNum1k = 0;
                
                // update state flag
                _sheet.state = MiningV1Data.PRICESHEET_STATE_CLOSED;
                
                // write back
                prices[indices[i]] = _sheet;

                // count up the reward
                if(_sheet.level == 0 && (_sheet.typ == MiningV1Data.PRICESHEET_TYPE_USD || _sheet.typ == MiningV1Data.PRICESHEET_TYPE_TOKEN)) {
                    uint256 _ntokenH = uint256(state.minedAtHeight[token][h] >> 128);
                    uint256 _ethH = uint256(state.minedAtHeight[token][h] << 128 >> 128);
                    _reward = _reward.add(uint256(_sheet.ethNum).mul(_ntokenH).div(_ethH));
                }
                emit MiningV1Data.PriceClosed(address(msg.sender), token, indices[i]);
            }
        }
        
        // load address of NestPool (for gas saving)
        INestPool _C_NestPool = INestPool(state.C_NestPool);

        // unfreeze assets
        if (_ethAmount > 0 || _tokenAmount > 0) {
            _C_NestPool.unfreezeEthAndToken(address(msg.sender), _ethAmount, token, _tokenAmount);
        }
        _C_NestPool.unfreezeNest(address(msg.sender), _nestAmount); 

        // distribute the rewards
        {
            uint256 _typ = prices[indices[0]].typ;
            if  (_typ == MiningV1Data.PRICESHEET_TYPE_USD) {
                _C_NestPool.addNest(address(msg.sender), _reward);
            } else if (_typ == MiningV1Data.PRICESHEET_TYPE_TOKEN) {
                address _ntoken = _C_NestPool.getNTokenFromToken(token);
                _C_NestPool.addNToken(address(msg.sender), _ntoken, _reward);
            }
        }
    }

    /*
    /// @dev This function is only for post dual-price-sheet before upgrading without assets
    function _post2Only4Upgrade(
            MiningV1Data.State storage state,
            address token,
            uint256 ethNum,
            uint256 tokenAmountPerEth,
            uint256 ntokenAmountPerEth
        )
        external 
    {
        // check parameters 
        require(ethNum == state.miningEthUnit, "Nest:Mine:!(ethNum)");
        require(tokenAmountPerEth > 0 && ntokenAmountPerEth > 0, "Nest:Mine:!(price)");
        address _ntoken = INestPool(state.C_NestPool).getNTokenFromToken(token);

        // no eth fee, no freezing

        // push sheets
        {
            uint8 typ1;
            uint8 typ2; 
            if (_ntoken == address(state.C_NestToken)) {
                typ1 = MiningV1Data.PRICESHEET_TYPE_USD;
                typ2 = MiningV1Data.PRICESHEET_TYPE_NEST;
            } else {
                typ1 = MiningV1Data.PRICESHEET_TYPE_TOKEN;
                typ2 = MiningV1Data.PRICESHEET_TYPE_NTOKEN;
            }
            MiningV1Data.PriceSheet[] storage _sheetToken = state.priceSheetList[token];
            // append a new price sheet
            _sheetToken.push(MiningV1Data.PriceSheet(
                uint160(msg.sender),            // miner 
                uint32(block.number),           // atHeight
                uint32(ethNum),                 // ethNum
                uint32(ethNum),                 // remainNum
                uint8(0),                       // level
                uint8(typ1),     // typ
                uint8(MiningV1Data.PRICESHEET_STATE_CLOSED), // state 
                uint8(0),                       // _reserved
                uint32(ethNum),                 // ethNumBal
                uint32(ethNum),                 // tokenNumBal
                uint32(state.nestStakedNum1k),        // nestNum1k
                uint128(tokenAmountPerEth)      // tokenAmountPerEth
            ));

            MiningV1Data.PriceSheet[] storage _sheetNToken = state.priceSheetList[_ntoken];
            // append a new price sheet for ntoken
            _sheetNToken.push(MiningV1Data.PriceSheet(
                uint160(msg.sender),            // miner 
                uint32(block.number),           // atHeight
                uint32(ethNum),                 // ethNum
                uint32(ethNum),                 // remainNum
                uint8(0),                       // level
                uint8(typ2),     // typ
                uint8(MiningV1Data.PRICESHEET_STATE_CLOSED), // state 
                uint8(0),                       // _reserved
                uint32(ethNum),                 // ethNumBal
                uint32(ethNum),                 // tokenNumBal
                uint32(state.nestStakedNum1k),        // nestNum1k
                uint128(ntokenAmountPerEth)      // tokenAmountPerEth
            ));
            emit MiningV1Data.PricePosted(msg.sender, token, (_sheetToken.length - 1), ethNum.mul(1 ether), tokenAmountPerEth.mul(ethNum)); 
            emit MiningV1Data.PricePosted(msg.sender, _ntoken, (_sheetNToken.length - 1), ethNum.mul(1 ether), ntokenAmountPerEth.mul(ethNum)); 
        }

        // no mining

        return; 
    }
    */

}

// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.6.12;

// a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)

library SafeMath {
    function add(uint x, uint y) internal pure returns (uint z) {
        require((z = x + y) >= x, 'ds-math-add-overflow');
    }

    function sub(uint x, uint y) internal pure returns (uint z) {
        require((z = x - y) <= x, 'ds-math-sub-underflow');
    }

    function mul(uint x, uint y) internal pure returns (uint z) {
        require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow');
    }

    function div(uint x, uint y) internal pure returns (uint z) {
        require(y > 0, "ds-math-div-zero");
        z = x / y;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    }
}

// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity 0.6.12;

import "./Address.sol";
import "./SafeMath.sol";

library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(ERC20 token, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(ERC20 token, address from, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    function safeApprove(ERC20 token, address spender, uint256 value) internal {
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(ERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(ERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value);
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }
    function callOptionalReturn(ERC20 token, bytes memory data) private {
        require(address(token).isContract(), "SafeERC20: call to non-contract");
        (bool success, bytes memory returndata) = address(token).call(data);
        require(success, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

interface ERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.6.12;

// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
    function safeApprove(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('approve(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
    }

    function safeTransfer(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
    }

    function safeTransferFrom(address token, address from, address to, uint value) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
    }

    function safeTransferETH(address to, uint value) internal {
        (bool success,) = to.call{value:value}(new bytes(0));
        require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
    }
}

// SPDX-License-Identifier: Copyright © 2019 by ABDK Consulting

/*
 * ABDK Math 64.64 Smart Contract Library.  Copyright © 2019 by ABDK Consulting.
 * Author: Mikhail Vladimirov <mikhail.vladimirov@gmail.com>
 */
pragma solidity 0.6.12;

/**
 * Smart contract library of mathematical functions operating with signed
 * 64.64-bit fixed point numbers.  Signed 64.64-bit fixed point number is
 * basically a simple fraction whose numerator is signed 128-bit integer and
 * denominator is 2^64.  As long as denominator is always the same, there is no
 * need to store it, thus in Solidity signed 64.64-bit fixed point numbers are
 * represented by int128 type holding only the numerator.
 */
library ABDKMath64x64 {
  /**
   * @dev Minimum value signed 64.64-bit fixed point number may have. 
   */
  int128 private constant MIN_64x64 = -0x80000000000000000000000000000000;

  /**
   * @dev Maximum value signed 64.64-bit fixed point number may have. 
   */
  int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

  /**
   * Convert signed 256-bit integer number into signed 64.64-bit fixed point
   * number.  Revert on overflow.
   *
   * @param x signed 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function fromInt (int256 x) internal pure returns (int128) {
    require (x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF);
    return int128 (x << 64);
  }

  /**
   * Convert signed 64.64 fixed point number into signed 64-bit integer number
   * rounding down.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64-bit integer number
   */
  function toInt (int128 x) internal pure returns (int64) {
    return int64 (x >> 64);
  }

  /**
   * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point
   * number.  Revert on overflow.
   *
   * @param x unsigned 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function fromUInt (uint256 x) internal pure returns (int128) {
    require (x <= 0x7FFFFFFFFFFFFFFF);
    return int128 (x << 64);
  }

  /**
   * Convert signed 64.64 fixed point number into unsigned 64-bit integer
   * number rounding down.  Revert on underflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return unsigned 64-bit integer number
   */
  function toUInt (int128 x) internal pure returns (uint64) {
    require (x >= 0);
    return uint64 (x >> 64);
  }

  /**
   * Convert signed 128.128 fixed point number into signed 64.64-bit fixed point
   * number rounding down.  Revert on overflow.
   *
   * @param x signed 128.128-bin fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function from128x128 (int256 x) internal pure returns (int128) {
    int256 result = x >> 64;
    require (result >= MIN_64x64 && result <= MAX_64x64);
    return int128 (result);
  }

  /**
   * Convert signed 64.64 fixed point number into signed 128.128 fixed point
   * number.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 128.128 fixed point number
   */
  function to128x128 (int128 x) internal pure returns (int256) {
    return int256 (x) << 64;
  }

  /**
   * Calculate x + y.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function add (int128 x, int128 y) internal pure returns (int128) {
    int256 result = int256(x) + y;
    require (result >= MIN_64x64 && result <= MAX_64x64);
    return int128 (result);
  }

  /**
   * Calculate x - y.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function sub (int128 x, int128 y) internal pure returns (int128) {
    int256 result = int256(x) - y;
    require (result >= MIN_64x64 && result <= MAX_64x64);
    return int128 (result);
  }

  /**
   * Calculate x * y rounding down.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function mul (int128 x, int128 y) internal pure returns (int128) {
    int256 result = int256(x) * y >> 64;
    require (result >= MIN_64x64 && result <= MAX_64x64);
    return int128 (result);
  }

  /**
   * Calculate x * y rounding towards zero, where x is signed 64.64 fixed point
   * number and y is signed 256-bit integer number.  Revert on overflow.
   *
   * @param x signed 64.64 fixed point number
   * @param y signed 256-bit integer number
   * @return signed 256-bit integer number
   */
  function muli (int128 x, int256 y) internal pure returns (int256) {
    if (x == MIN_64x64) {
      require (y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF &&
        y <= 0x1000000000000000000000000000000000000000000000000);
      return -y << 63;
    } else {
      bool negativeResult = false;
      if (x < 0) {
        x = -x;
        negativeResult = true;
      }
      if (y < 0) {
        y = -y; // We rely on overflow behavior here
        negativeResult = !negativeResult;
      }
      uint256 absoluteResult = mulu (x, uint256 (y));
      if (negativeResult) {
        require (absoluteResult <=
          0x8000000000000000000000000000000000000000000000000000000000000000);
        return -int256 (absoluteResult); // We rely on overflow behavior here
      } else {
        require (absoluteResult <=
          0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
        return int256 (absoluteResult);
      }
    }
  }

  /**
   * Calculate x * y rounding down, where x is signed 64.64 fixed point number
   * and y is unsigned 256-bit integer number.  Revert on overflow.
   *
   * @param x signed 64.64 fixed point number
   * @param y unsigned 256-bit integer number
   * @return unsigned 256-bit integer number
   */
  function mulu (int128 x, uint256 y) internal pure returns (uint256) {
    if (y == 0) return 0;

    require (x >= 0);

    uint256 lo = (uint256 (x) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64;
    uint256 hi = uint256 (x) * (y >> 128);

    require (hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
    hi <<= 64;

    require (hi <=
      0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo);
    return hi + lo;
  }

  /**
   * Calculate x / y rounding towards zero.  Revert on overflow or when y is
   * zero.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function div (int128 x, int128 y) internal pure returns (int128) {
    require (y != 0);
    int256 result = (int256 (x) << 64) / y;
    require (result >= MIN_64x64 && result <= MAX_64x64);
    return int128 (result);
  }

  /**
   * Calculate x / y rounding towards zero, where x and y are signed 256-bit
   * integer numbers.  Revert on overflow or when y is zero.
   *
   * @param x signed 256-bit integer number
   * @param y signed 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function divi (int256 x, int256 y) internal pure returns (int128) {
    require (y != 0);

    bool negativeResult = false;
    if (x < 0) {
      x = -x; // We rely on overflow behavior here
      negativeResult = true;
    }
    if (y < 0) {
      y = -y; // We rely on overflow behavior here
      negativeResult = !negativeResult;
    }
    uint128 absoluteResult = divuu (uint256 (x), uint256 (y));
    if (negativeResult) {
      require (absoluteResult <= 0x80000000000000000000000000000000);
      return -int128 (absoluteResult); // We rely on overflow behavior here
    } else {
      require (absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
      return int128 (absoluteResult); // We rely on overflow behavior here
    }
  }

  /**
   * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
   * integer numbers.  Revert on overflow or when y is zero.
   *
   * @param x unsigned 256-bit integer number
   * @param y unsigned 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function divu (uint256 x, uint256 y) internal pure returns (int128) {
    require (y != 0);
    uint128 result = divuu (x, y);
    require (result <= uint128 (MAX_64x64));
    return int128 (result);
  }

  /**
   * Calculate -x.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function neg (int128 x) internal pure returns (int128) {
    require (x != MIN_64x64);
    return -x;
  }

  /**
   * Calculate |x|.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function abs (int128 x) internal pure returns (int128) {
    require (x != MIN_64x64);
    return x < 0 ? -x : x;
  }

  /**
   * Calculate 1 / x rounding towards zero.  Revert on overflow or when x is
   * zero.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function inv (int128 x) internal pure returns (int128) {
    require (x != 0);
    int256 result = int256 (0x100000000000000000000000000000000) / x;
    require (result >= MIN_64x64 && result <= MAX_64x64);
    return int128 (result);
  }

  /**
   * Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function avg (int128 x, int128 y) internal pure returns (int128) {
    return int128 ((int256 (x) + int256 (y)) >> 1);
  }

  /**
   * Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down.
   * Revert on overflow or in case x * y is negative.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function gavg (int128 x, int128 y) internal pure returns (int128) {
    int256 m = int256 (x) * int256 (y);
    require (m >= 0);
    require (m <
        0x4000000000000000000000000000000000000000000000000000000000000000);
    return int128 (sqrtu (uint256 (m), uint256 (x) + uint256 (y) >> 1));
  }

  /**
   * Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number
   * and y is unsigned 256-bit integer number.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y uint256 value
   * @return signed 64.64-bit fixed point number
   */
  function pow (int128 x, uint256 y) internal pure returns (int128) {
    uint256 absoluteResult;
    bool negativeResult = false;
    if (x >= 0) {
      absoluteResult = powu (uint256 (x) << 63, y);
    } else {
      // We rely on overflow behavior here
      absoluteResult = powu (uint256 (uint128 (-x)) << 63, y);
      negativeResult = y & 1 > 0;
    }

    absoluteResult >>= 63;

    if (negativeResult) {
      require (absoluteResult <= 0x80000000000000000000000000000000);
      return -int128 (absoluteResult); // We rely on overflow behavior here
    } else {
      require (absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
      return int128 (absoluteResult); // We rely on overflow behavior here
    }
  }

  /**
   * Calculate sqrt (x) rounding down.  Revert if x < 0.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function sqrt (int128 x) internal pure returns (int128) {
    require (x >= 0);
    return int128 (sqrtu (uint256 (x) << 64, 0x10000000000000000));
  }

  /**
   * Calculate binary logarithm of x.  Revert if x <= 0.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function log_2 (int128 x) internal pure returns (int128) {
    require (x > 0);

    int256 msb = 0;
    int256 xc = x;
    if (xc >= 0x10000000000000000) { xc >>= 64; msb += 64; }
    if (xc >= 0x100000000) { xc >>= 32; msb += 32; }
    if (xc >= 0x10000) { xc >>= 16; msb += 16; }
    if (xc >= 0x100) { xc >>= 8; msb += 8; }
    if (xc >= 0x10) { xc >>= 4; msb += 4; }
    if (xc >= 0x4) { xc >>= 2; msb += 2; }
    if (xc >= 0x2) msb += 1;  // No need to shift xc anymore

    int256 result = msb - 64 << 64;
    uint256 ux = uint256 (x) << 127 - msb;
    for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) {
      ux *= ux;
      uint256 b = ux >> 255;
      ux >>= 127 + b;
      result += bit * int256 (b);
    }

    return int128 (result);
  }

  /**
   * Calculate natural logarithm of x.  Revert if x <= 0.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function ln (int128 x) internal pure returns (int128) {
    require (x > 0);

    return int128 (
        uint256 (log_2 (x)) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF >> 128);
  }

  /**
   * Calculate binary exponent of x.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function exp_2 (int128 x) internal pure returns (int128) {
    require (x < 0x400000000000000000); // Overflow

    if (x < -0x400000000000000000) return 0; // Underflow

    uint256 result = 0x80000000000000000000000000000000;

    if (x & 0x8000000000000000 > 0)
      result = result * 0x16A09E667F3BCC908B2FB1366EA957D3E >> 128;
    if (x & 0x4000000000000000 > 0)
      result = result * 0x1306FE0A31B7152DE8D5A46305C85EDEC >> 128;
    if (x & 0x2000000000000000 > 0)
      result = result * 0x1172B83C7D517ADCDF7C8C50EB14A791F >> 128;
    if (x & 0x1000000000000000 > 0)
      result = result * 0x10B5586CF9890F6298B92B71842A98363 >> 128;
    if (x & 0x800000000000000 > 0)
      result = result * 0x1059B0D31585743AE7C548EB68CA417FD >> 128;
    if (x & 0x400000000000000 > 0)
      result = result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8 >> 128;
    if (x & 0x200000000000000 > 0)
      result = result * 0x10163DA9FB33356D84A66AE336DCDFA3F >> 128;
    if (x & 0x100000000000000 > 0)
      result = result * 0x100B1AFA5ABCBED6129AB13EC11DC9543 >> 128;
    if (x & 0x80000000000000 > 0)
      result = result * 0x10058C86DA1C09EA1FF19D294CF2F679B >> 128;
    if (x & 0x40000000000000 > 0)
      result = result * 0x1002C605E2E8CEC506D21BFC89A23A00F >> 128;
    if (x & 0x20000000000000 > 0)
      result = result * 0x100162F3904051FA128BCA9C55C31E5DF >> 128;
    if (x & 0x10000000000000 > 0)
      result = result * 0x1000B175EFFDC76BA38E31671CA939725 >> 128;
    if (x & 0x8000000000000 > 0)
      result = result * 0x100058BA01FB9F96D6CACD4B180917C3D >> 128;
    if (x & 0x4000000000000 > 0)
      result = result * 0x10002C5CC37DA9491D0985C348C68E7B3 >> 128;
    if (x & 0x2000000000000 > 0)
      result = result * 0x1000162E525EE054754457D5995292026 >> 128;
    if (x & 0x1000000000000 > 0)
      result = result * 0x10000B17255775C040618BF4A4ADE83FC >> 128;
    if (x & 0x800000000000 > 0)
      result = result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB >> 128;
    if (x & 0x400000000000 > 0)
      result = result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9 >> 128;
    if (x & 0x200000000000 > 0)
      result = result * 0x10000162E43F4F831060E02D839A9D16D >> 128;
    if (x & 0x100000000000 > 0)
      result = result * 0x100000B1721BCFC99D9F890EA06911763 >> 128;
    if (x & 0x80000000000 > 0)
      result = result * 0x10000058B90CF1E6D97F9CA14DBCC1628 >> 128;
    if (x & 0x40000000000 > 0)
      result = result * 0x1000002C5C863B73F016468F6BAC5CA2B >> 128;
    if (x & 0x20000000000 > 0)
      result = result * 0x100000162E430E5A18F6119E3C02282A5 >> 128;
    if (x & 0x10000000000 > 0)
      result = result * 0x1000000B1721835514B86E6D96EFD1BFE >> 128;
    if (x & 0x8000000000 > 0)
      result = result * 0x100000058B90C0B48C6BE5DF846C5B2EF >> 128;
    if (x & 0x4000000000 > 0)
      result = result * 0x10000002C5C8601CC6B9E94213C72737A >> 128;
    if (x & 0x2000000000 > 0)
      result = result * 0x1000000162E42FFF037DF38AA2B219F06 >> 128;
    if (x & 0x1000000000 > 0)
      result = result * 0x10000000B17217FBA9C739AA5819F44F9 >> 128;
    if (x & 0x800000000 > 0)
      result = result * 0x1000000058B90BFCDEE5ACD3C1CEDC823 >> 128;
    if (x & 0x400000000 > 0)
      result = result * 0x100000002C5C85FE31F35A6A30DA1BE50 >> 128;
    if (x & 0x200000000 > 0)
      result = result * 0x10000000162E42FF0999CE3541B9FFFCF >> 128;
    if (x & 0x100000000 > 0)
      result = result * 0x100000000B17217F80F4EF5AADDA45554 >> 128;
    if (x & 0x80000000 > 0)
      result = result * 0x10000000058B90BFBF8479BD5A81B51AD >> 128;
    if (x & 0x40000000 > 0)
      result = result * 0x1000000002C5C85FDF84BD62AE30A74CC >> 128;
    if (x & 0x20000000 > 0)
      result = result * 0x100000000162E42FEFB2FED257559BDAA >> 128;
    if (x & 0x10000000 > 0)
      result = result * 0x1000000000B17217F7D5A7716BBA4A9AE >> 128;
    if (x & 0x8000000 > 0)
      result = result * 0x100000000058B90BFBE9DDBAC5E109CCE >> 128;
    if (x & 0x4000000 > 0)
      result = result * 0x10000000002C5C85FDF4B15DE6F17EB0D >> 128;
    if (x & 0x2000000 > 0)
      result = result * 0x1000000000162E42FEFA494F1478FDE05 >> 128;
    if (x & 0x1000000 > 0)
      result = result * 0x10000000000B17217F7D20CF927C8E94C >> 128;
    if (x & 0x800000 > 0)
      result = result * 0x1000000000058B90BFBE8F71CB4E4B33D >> 128;
    if (x & 0x400000 > 0)
      result = result * 0x100000000002C5C85FDF477B662B26945 >> 128;
    if (x & 0x200000 > 0)
      result = result * 0x10000000000162E42FEFA3AE53369388C >> 128;
    if (x & 0x100000 > 0)
      result = result * 0x100000000000B17217F7D1D351A389D40 >> 128;
    if (x & 0x80000 > 0)
      result = result * 0x10000000000058B90BFBE8E8B2D3D4EDE >> 128;
    if (x & 0x40000 > 0)
      result = result * 0x1000000000002C5C85FDF4741BEA6E77E >> 128;
    if (x & 0x20000 > 0)
      result = result * 0x100000000000162E42FEFA39FE95583C2 >> 128;
    if (x & 0x10000 > 0)
      result = result * 0x1000000000000B17217F7D1CFB72B45E1 >> 128;
    if (x & 0x8000 > 0)
      result = result * 0x100000000000058B90BFBE8E7CC35C3F0 >> 128;
    if (x & 0x4000 > 0)
      result = result * 0x10000000000002C5C85FDF473E242EA38 >> 128;
    if (x & 0x2000 > 0)
      result = result * 0x1000000000000162E42FEFA39F02B772C >> 128;
    if (x & 0x1000 > 0)
      result = result * 0x10000000000000B17217F7D1CF7D83C1A >> 128;
    if (x & 0x800 > 0)
      result = result * 0x1000000000000058B90BFBE8E7BDCBE2E >> 128;
    if (x & 0x400 > 0)
      result = result * 0x100000000000002C5C85FDF473DEA871F >> 128;
    if (x & 0x200 > 0)
      result = result * 0x10000000000000162E42FEFA39EF44D91 >> 128;
    if (x & 0x100 > 0)
      result = result * 0x100000000000000B17217F7D1CF79E949 >> 128;
    if (x & 0x80 > 0)
      result = result * 0x10000000000000058B90BFBE8E7BCE544 >> 128;
    if (x & 0x40 > 0)
      result = result * 0x1000000000000002C5C85FDF473DE6ECA >> 128;
    if (x & 0x20 > 0)
      result = result * 0x100000000000000162E42FEFA39EF366F >> 128;
    if (x & 0x10 > 0)
      result = result * 0x1000000000000000B17217F7D1CF79AFA >> 128;
    if (x & 0x8 > 0)
      result = result * 0x100000000000000058B90BFBE8E7BCD6D >> 128;
    if (x & 0x4 > 0)
      result = result * 0x10000000000000002C5C85FDF473DE6B2 >> 128;
    if (x & 0x2 > 0)
      result = result * 0x1000000000000000162E42FEFA39EF358 >> 128;
    if (x & 0x1 > 0)
      result = result * 0x10000000000000000B17217F7D1CF79AB >> 128;

    result >>= 63 - (x >> 64);
    require (result <= uint256 (MAX_64x64));

    return int128 (result);
  }

  /**
   * Calculate natural exponent of x.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function exp (int128 x) internal pure returns (int128) {
    require (x < 0x400000000000000000); // Overflow

    if (x < -0x400000000000000000) return 0; // Underflow

    return exp_2 (
        int128 (int256 (x) * 0x171547652B82FE1777D0FFDA0D23A7D12 >> 128));
  }

  /**
   * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
   * integer numbers.  Revert on overflow or when y is zero.
   *
   * @param x unsigned 256-bit integer number
   * @param y unsigned 256-bit integer number
   * @return unsigned 64.64-bit fixed point number
   */
  function divuu (uint256 x, uint256 y) private pure returns (uint128) {
    require (y != 0);

    uint256 result;

    if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
      result = (x << 64) / y;
    else {
      uint256 msb = 192;
      uint256 xc = x >> 192;
      if (xc >= 0x100000000) { xc >>= 32; msb += 32; }
      if (xc >= 0x10000) { xc >>= 16; msb += 16; }
      if (xc >= 0x100) { xc >>= 8; msb += 8; }
      if (xc >= 0x10) { xc >>= 4; msb += 4; }
      if (xc >= 0x4) { xc >>= 2; msb += 2; }
      if (xc >= 0x2) msb += 1;  // No need to shift xc anymore

      result = (x << 255 - msb) / ((y - 1 >> msb - 191) + 1);
      require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);

      uint256 hi = result * (y >> 128);
      uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);

      uint256 xh = x >> 192;
      uint256 xl = x << 64;

      if (xl < lo) xh -= 1;
      xl -= lo; // We rely on overflow behavior here
      lo = hi << 128;
      if (xl < lo) xh -= 1;
      xl -= lo; // We rely on overflow behavior here

      assert (xh == hi >> 128);

      result += xl / y;
    }

    require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
    return uint128 (result);
  }

  /**
   * Calculate x^y assuming 0^0 is 1, where x is unsigned 129.127 fixed point
   * number and y is unsigned 256-bit integer number.  Revert on overflow.
   *
   * @param x unsigned 129.127-bit fixed point number
   * @param y uint256 value
   * @return unsigned 129.127-bit fixed point number
   */
  function powu (uint256 x, uint256 y) private pure returns (uint256) {
    if (y == 0) return 0x80000000000000000000000000000000;
    else if (x == 0) return 0;
    else {
      int256 msb = 0;
      uint256 xc = x;
      if (xc >= 0x100000000000000000000000000000000) { xc >>= 128; msb += 128; }
      if (xc >= 0x10000000000000000) { xc >>= 64; msb += 64; }
      if (xc >= 0x100000000) { xc >>= 32; msb += 32; }
      if (xc >= 0x10000) { xc >>= 16; msb += 16; }
      if (xc >= 0x100) { xc >>= 8; msb += 8; }
      if (xc >= 0x10) { xc >>= 4; msb += 4; }
      if (xc >= 0x4) { xc >>= 2; msb += 2; }
      if (xc >= 0x2) msb += 1;  // No need to shift xc anymore

      int256 xe = msb - 127;
      if (xe > 0) x >>= xe;
      else x <<= -xe;

      uint256 result = 0x80000000000000000000000000000000;
      int256 re = 0;

      while (y > 0) {
        if (y & 1 > 0) {
          result = result * x;
          y -= 1;
          re += xe;
          if (result >=
            0x8000000000000000000000000000000000000000000000000000000000000000) {
            result >>= 128;
            re += 1;
          } else result >>= 127;
          if (re < -127) return 0; // Underflow
          require (re < 128); // Overflow
        } else {
          x = x * x;
          y >>= 1;
          xe <<= 1;
          if (x >=
            0x8000000000000000000000000000000000000000000000000000000000000000) {
            x >>= 128;
            xe += 1;
          } else x >>= 127;
          if (xe < -127) return 0; // Underflow
          require (xe < 128); // Overflow
        }
      }

      if (re > 0) result <<= re;
      else if (re < 0) result >>= -re;

      return result;
    }
  }

  /**
   * Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer
   * number.
   *
   * @param x unsigned 256-bit integer number
   * @return unsigned 128-bit integer number
   */
  function sqrtu (uint256 x, uint256 r) private pure returns (uint128) {
    if (x == 0) return 0;
    else {
      require (r > 0);
      while (true) {
        uint256 rr = x / r;
        if (r == rr || r + 1 == rr) return uint128 (r);
        else if (r == rr + 1) return uint128 (rr);
        r = r + rr + 1 >> 1;
      }
    }
  }
}

File 9 of 16 : INestPool.sol
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.6.12;

import "../lib/SafeERC20.sol";

interface INestPool {

    // function getNTokenFromToken(address token) view external returns (address);
    // function setNTokenToToken(address token, address ntoken) external; 

    function addNest(address miner, uint256 amount) external;
    function addNToken(address contributor, address ntoken, uint256 amount) external;

    function depositEth(address miner) external payable;
    function depositNToken(address miner,  address from, address ntoken, uint256 amount) external;

    function freezeEth(address miner, uint256 ethAmount) external; 
    function unfreezeEth(address miner, uint256 ethAmount) external;

    function freezeNest(address miner, uint256 nestAmount) external;
    function unfreezeNest(address miner, uint256 nestAmount) external;

    function freezeToken(address miner, address token, uint256 tokenAmount) external; 
    function unfreezeToken(address miner, address token, uint256 tokenAmount) external;

    function freezeEthAndToken(address miner, uint256 ethAmount, address token, uint256 tokenAmount) external;
    function unfreezeEthAndToken(address miner, uint256 ethAmount, address token, uint256 tokenAmount) external;

    function getNTokenFromToken(address token) external view returns (address); 
    function setNTokenToToken(address token, address ntoken) external; 

    function withdrawEth(address miner, uint256 ethAmount) external;
    function withdrawToken(address miner, address token, uint256 tokenAmount) external;

    function withdrawNest(address miner, uint256 amount) external;
    function withdrawEthAndToken(address miner, uint256 ethAmount, address token, uint256 tokenAmount) external;
    // function withdrawNToken(address miner, address ntoken, uint256 amount) external;
    function withdrawNTokenAndTransfer(address miner, address ntoken, uint256 amount, address to) external;


    function balanceOfNestInPool(address miner) external view returns (uint256);
    function balanceOfEthInPool(address miner) external view returns (uint256);
    function balanceOfTokenInPool(address miner, address token)  external view returns (uint256);

    function addrOfNestToken() external view returns (address);
    function addrOfNestMining() external view returns (address);
    function addrOfNTokenController() external view returns (address);
    function addrOfNNRewardPool() external view returns (address);
    function addrOfNNToken() external view returns (address);
    function addrOfNestStaking() external view returns (address);
    function addrOfNestQuery() external view returns (address);
    function addrOfNestDAO() external view returns (address);

    function addressOfBurnedNest() external view returns (address);

    function setGovernance(address _gov) external; 
    function governance() external view returns(address);
    function initNestLedger(uint256 amount) external;
    function drainNest(address to, uint256 amount, address gov) external;

}

// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.6.12;


interface INestStaking {
    // Views

    /// @dev How many stakingToken (XToken) deposited into to this reward pool (staking pool)
    /// @param  ntoken The address of NToken
    /// @return The total amount of XTokens deposited in this staking pool
    function totalStaked(address ntoken) external view returns (uint256);

    /// @dev How many stakingToken (XToken) deposited by the target account
    /// @param  ntoken The address of NToken
    /// @param  account The target account
    /// @return The total amount of XToken deposited in this staking pool
    function stakedBalanceOf(address ntoken, address account) external view returns (uint256);


    // Mutative
    /// @dev Stake/Deposit into the reward pool (staking pool)
    /// @param  ntoken The address of NToken
    /// @param  amount The target amount
    function stake(address ntoken, uint256 amount) external;

    function stakeFromNestPool(address ntoken, uint256 amount) external;

    /// @dev Withdraw from the reward pool (staking pool), get the original tokens back
    /// @param  ntoken The address of NToken
    /// @param  amount The target amount
    function unstake(address ntoken, uint256 amount) external;

    /// @dev Claim the reward the user earned
    /// @param ntoken The address of NToken
    /// @return The amount of ethers as rewards
    function claim(address ntoken) external returns (uint256);

    /// @dev Add ETH reward to the staking pool
    /// @param ntoken The address of NToken
    function addETHReward(address ntoken) external payable;

    /// @dev Only for governance
    function loadContracts() external; 

    /// @dev Only for governance
    function loadGovernance() external; 

    function pause() external;

    function resume() external;

    //function setParams(uint8 dividendShareRate) external;

    /* ========== EVENTS ========== */

    // Events
    event RewardAdded(address ntoken, address sender, uint256 reward);
    event NTokenStaked(address ntoken, address indexed user, uint256 amount);
    event NTokenUnstaked(address ntoken, address indexed user, uint256 amount);
    event SavingWithdrawn(address ntoken, address indexed to, uint256 amount);
    event RewardClaimed(address ntoken, address indexed user, uint256 reward);

    event FlagSet(address gov, uint256 flag);
}

// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.6.12;

interface INTokenLegacy {
    function increaseTotal(uint256 value) external;

    // the block height where the ntoken was created
    function checkBlockInfo() external view returns(uint256 createBlock, uint256 recentlyUsedBlock);
    // the owner (auction winner) of the ntoken
    function checkBidder() external view returns(address);
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

import "../lib/SafeERC20.sol";


interface INestMining {
    
    struct Params {
        uint8    miningEthUnit;     // = 10;
        uint32   nestStakedNum1k;   // = 1;
        uint8    biteFeeRate;       // = 1; 
        uint8    miningFeeRate;     // = 10;
        uint8    priceDurationBlock; 
        uint8    maxBiteNestedLevel; // = 3;
        uint8    biteInflateFactor;
        uint8    biteNestInflateFactor;
    }

    function priceOf(address token) external view returns(uint256 ethAmount, uint256 tokenAmount, uint256 bn);
    
    function priceListOfToken(address token, uint8 num) external view returns(uint128[] memory data, uint256 bn);

    // function priceOfTokenAtHeight(address token, uint64 atHeight) external view returns(uint256 ethAmount, uint256 tokenAmount, uint64 bn);

    function latestPriceOf(address token) external view returns (uint256 ethAmount, uint256 tokenAmount, uint256 bn);

    function priceAvgAndSigmaOf(address token) 
        external view returns (uint128, uint128, int128, uint32);

    function minedNestAmount() external view returns (uint256);

    /// @dev Only for governance
    function loadContracts() external; 
    
    function loadGovernance() external;

    function upgrade() external;

    function setup(uint32   genesisBlockNumber, uint128  latestMiningHeight, uint128  minedNestTotalAmount, Params calldata initParams) external;

    function setParams1(uint128  latestMiningHeight, uint128  minedNestTotalAmount) external;
}

// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.6.12;

interface INestDAO {

    function addETHReward(address ntoken) external payable; 

    function addNestReward(uint256 amount) external;

    /// @dev Only for governance
    function loadContracts() external; 

    /// @dev Only for governance
    function loadGovernance() external;
    
    /// @dev Only for governance
    function start() external; 

    function initEthLedger(address ntoken, uint256 amount) external;

    event NTokenRedeemed(address ntoken, address user, uint256 amount);

    event AssetsCollected(address user, uint256 ethAmount, uint256 nestAmount);

    event ParamsSetup(address gov, uint256 oldParam, uint256 newParam);

    event FlagSet(address gov, uint256 flag);

}

// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.6.12;

interface INToken {
    // mint ntoken for value
    function mint(uint256 amount, address account) external;

    // the block height where the ntoken was created
    function checkBlockInfo() external view returns(uint256 createBlock, uint256 recentlyUsedBlock);
    // the owner (auction winner) of the ntoken
    function checkBidder() external view returns(address);
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);

}

// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.6.12;

/// @title NNRewardPool
/// @author Inf Loop - <inf-loop@nestprotocol.org>
/// @author Paradox  - <paradox@nestprotocol.org>

interface INNRewardPool {
    
    /* [DEPRECATED]
        uint256 constant DEV_REWARD_PERCENTAGE   = 5;
        uint256 constant NN_REWARD_PERCENTAGE    = 15;
        uint256 constant MINER_REWARD_PERCENTAGE = 80;
    */

    /// @notice Add rewards for Nest-Nodes, only governance or NestMining (contract) are allowed
    /// @dev  The rewards need to pull from NestPool
    /// @param _amount The amount of Nest token as the rewards to each nest-node
    function addNNReward(uint256 _amount) external;

    /// @notice Claim rewards by Nest-Nodes
    /// @dev The rewards need to pull from NestPool
    function claimNNReward() external ;  

    /// @dev The callback function called by NNToken.transfer()
    /// @param fromAdd The address of 'from' to transfer
    /// @param toAdd The address of 'to' to transfer
    function nodeCount(address fromAdd, address toAdd) external;

    /// @notice Show the amount of rewards unclaimed
    /// @return reward The reward of a NN holder
    function unclaimedNNReward() external view returns (uint256 reward);

    /// @dev Only for governance
    function loadContracts() external; 

    /// @dev Only for governance
    function loadGovernance() external; 

    /* ========== EVENTS ============== */

    /// @notice When rewards are added to the pool
    /// @param reward The amount of Nest Token
    /// @param allRewards The snapshot of all rewards accumulated
    event NNRewardAdded(uint256 reward, uint256 allRewards);

    /// @notice When rewards are claimed by nodes 
    /// @param nnode The address of the nest node
    /// @param share The amount of Nest Token claimed by the nest node
    event NNRewardClaimed(address nnode, uint256 share);

    /// @notice When flag of state is set by governance 
    /// @param gov The address of the governance
    /// @param flag The value of the new flag
    event FlagSet(address gov, uint256 flag);
}

// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity 0.6.12;

library Address {
    function isContract(address account) internal view returns (bool) {
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");
        (bool success, ) = recipient.call{value:amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "libraries": {
    "contracts/libminingv1/MiningV1Calc.sol": {
      "MiningV1Calc": "0x265b6c10c606cd1c79545799ebe36bca9ce124a5"
    },
    "contracts/libminingv1/MiningV1Op.sol": {
      "MiningV1Op": "0xfe543efe9bb91b51a046157b73fdf0838833b841"
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"addrOfGovernance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"biteNum","type":"uint256"},{"internalType":"uint256","name":"newTokenAmountPerEth","type":"uint256"}],"name":"biteEth","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"biteNum","type":"uint256"},{"internalType":"uint256","name":"newTokenAmountPerEth","type":"uint256"}],"name":"biteToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"close","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"closeAndWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint32[]","name":"indices","type":"uint32[]"}],"name":"closeList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"flag","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"fullPriceSheet","outputs":[{"components":[{"internalType":"uint160","name":"miner","type":"uint160"},{"internalType":"uint32","name":"height","type":"uint32"},{"internalType":"uint32","name":"ethNum","type":"uint32"},{"internalType":"uint32","name":"remainNum","type":"uint32"},{"internalType":"uint8","name":"level","type":"uint8"},{"internalType":"uint8","name":"typ","type":"uint8"},{"internalType":"uint8","name":"state","type":"uint8"},{"internalType":"uint8","name":"_reserved","type":"uint8"},{"internalType":"uint32","name":"ethNumBal","type":"uint32"},{"internalType":"uint32","name":"tokenNumBal","type":"uint32"},{"internalType":"uint32","name":"nestNum1k","type":"uint32"},{"internalType":"uint128","name":"tokenAmountPerEth","type":"uint128"}],"internalType":"struct MiningV1Data.PriceSheet","name":"sheet","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"incVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"NestPool","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"latestMinedHeight","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"latestPriceOf","outputs":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"uint256","name":"blockNum","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"lengthOfPriceSheets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"loadContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"loadGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"ntoken","type":"address"}],"name":"mineNToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mineNest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minedNestAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"parameters","outputs":[{"components":[{"internalType":"uint8","name":"miningEthUnit","type":"uint8"},{"internalType":"uint32","name":"nestStakedNum1k","type":"uint32"},{"internalType":"uint8","name":"biteFeeRate","type":"uint8"},{"internalType":"uint8","name":"miningFeeRate","type":"uint8"},{"internalType":"uint8","name":"priceDurationBlock","type":"uint8"},{"internalType":"uint8","name":"maxBiteNestedLevel","type":"uint8"},{"internalType":"uint8","name":"biteInflateFactor","type":"uint8"},{"internalType":"uint8","name":"biteNestInflateFactor","type":"uint8"}],"internalType":"struct NestMiningV1.Params","name":"params","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"ethNum","type":"uint256"},{"internalType":"uint256","name":"tokenAmountPerEth","type":"uint256"}],"name":"post","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"ethNum","type":"uint256"},{"internalType":"uint256","name":"tokenAmountPerEth","type":"uint256"},{"internalType":"uint256","name":"ntokenAmountPerEth","type":"uint256"}],"name":"post2","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"priceAvgAndSigmaOf","outputs":[{"internalType":"uint128","name":"price","type":"uint128"},{"internalType":"uint128","name":"avgPrice","type":"uint128"},{"internalType":"int128","name":"vola","type":"int128"},{"internalType":"uint32","name":"bn","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"num","type":"uint8"}],"name":"priceListOfToken","outputs":[{"internalType":"uint128[]","name":"data","type":"uint128[]"},{"internalType":"uint256","name":"bn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"priceOf","outputs":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"uint256","name":"blockNum","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint64","name":"atHeight","type":"uint64"}],"name":"priceOfTokenAtHeight","outputs":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"uint256","name":"bn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"priceSheet","outputs":[{"components":[{"internalType":"uint160","name":"miner","type":"uint160"},{"internalType":"uint32","name":"height","type":"uint32"},{"internalType":"uint32","name":"ethNum","type":"uint32"},{"internalType":"uint8","name":"typ","type":"uint8"},{"internalType":"uint8","name":"state","type":"uint8"},{"internalType":"uint32","name":"ethNumBal","type":"uint32"},{"internalType":"uint32","name":"tokenNumBal","type":"uint32"}],"internalType":"struct MiningV1Data.PriceSheetPub","name":"sheet","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"miningEthUnit","type":"uint8"},{"internalType":"uint32","name":"nestStakedNum1k","type":"uint32"},{"internalType":"uint8","name":"biteFeeRate","type":"uint8"},{"internalType":"uint8","name":"miningFeeRate","type":"uint8"},{"internalType":"uint8","name":"priceDurationBlock","type":"uint8"},{"internalType":"uint8","name":"maxBiteNestedLevel","type":"uint8"},{"internalType":"uint8","name":"biteInflateFactor","type":"uint8"},{"internalType":"uint8","name":"biteNestInflateFactor","type":"uint8"}],"internalType":"struct NestMiningV1.Params","name":"newParams","type":"tuple"}],"name":"setParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"latestMiningHeight","type":"uint128"},{"internalType":"uint128","name":"minedNestTotalAmount","type":"uint128"}],"name":"setParams1","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"genesisBlockNumber","type":"uint32"},{"internalType":"uint128","name":"latestMiningHeight","type":"uint128"},{"internalType":"uint128","name":"minedNestTotalAmount","type":"uint128"},{"components":[{"internalType":"uint8","name":"miningEthUnit","type":"uint8"},{"internalType":"uint32","name":"nestStakedNum1k","type":"uint32"},{"internalType":"uint8","name":"biteFeeRate","type":"uint8"},{"internalType":"uint8","name":"miningFeeRate","type":"uint8"},{"internalType":"uint8","name":"priceDurationBlock","type":"uint8"},{"internalType":"uint8","name":"maxBiteNestedLevel","type":"uint8"},{"internalType":"uint8","name":"biteInflateFactor","type":"uint8"},{"internalType":"uint8","name":"biteNestInflateFactor","type":"uint8"}],"internalType":"struct NestMiningV1.Params","name":"initParams","type":"tuple"}],"name":"setup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"miner","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"fromIndex","type":"uint256"},{"internalType":"uint256","name":"num","type":"uint256"}],"name":"sheetListOf","outputs":[{"components":[{"internalType":"uint160","name":"miner","type":"uint160"},{"internalType":"uint32","name":"height","type":"uint32"},{"internalType":"uint32","name":"ethNum","type":"uint32"},{"internalType":"uint32","name":"remainNum","type":"uint32"},{"internalType":"uint8","name":"level","type":"uint8"},{"internalType":"uint8","name":"typ","type":"uint8"},{"internalType":"uint8","name":"state","type":"uint8"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint32","name":"nestNum1k","type":"uint32"},{"internalType":"uint128","name":"tokenAmountPerEth","type":"uint128"}],"internalType":"struct MiningV1Data.PriceSheetPub2[]","name":"sheets","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"stat","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"miner","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"fromIndex","type":"uint256"},{"internalType":"uint256","name":"num","type":"uint256"}],"name":"unClosedSheetListOf","outputs":[{"components":[{"internalType":"uint160","name":"miner","type":"uint160"},{"internalType":"uint32","name":"height","type":"uint32"},{"internalType":"uint32","name":"ethNum","type":"uint32"},{"internalType":"uint32","name":"remainNum","type":"uint32"},{"internalType":"uint8","name":"level","type":"uint8"},{"internalType":"uint8","name":"typ","type":"uint8"},{"internalType":"uint8","name":"state","type":"uint8"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint32","name":"nestNum1k","type":"uint32"},{"internalType":"uint128","name":"tokenAmountPerEth","type":"uint128"}],"internalType":"struct MiningV1Data.PriceSheetPub2[]","name":"sheets","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"unVerifiedSheetList","outputs":[{"components":[{"internalType":"uint160","name":"miner","type":"uint160"},{"internalType":"uint32","name":"height","type":"uint32"},{"internalType":"uint32","name":"ethNum","type":"uint32"},{"internalType":"uint32","name":"remainNum","type":"uint32"},{"internalType":"uint8","name":"level","type":"uint8"},{"internalType":"uint8","name":"typ","type":"uint8"},{"internalType":"uint8","name":"state","type":"uint8"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint32","name":"nestNum1k","type":"uint32"},{"internalType":"uint128","name":"tokenAmountPerEth","type":"uint128"}],"internalType":"struct MiningV1Data.PriceSheetPub2[]","name":"sheets","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"upgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"ethAmount","type":"uint256"}],"name":"withdrawEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"withdrawEthAndToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"uint256","name":"nestAmount","type":"uint256"}],"name":"withdrawEthAndTokenAndNest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nestAmount","type":"uint256"}],"name":"withdrawNest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

608060405234801561001057600080fd5b5061580180620000216000396000f3fe60806040526004361061023f5760003560e01c80639b0884e91161012e578063c4d66de8116100ab578063e25b667a1161006f578063e25b667a146106a0578063e49280cb146106b3578063e6adb1ab146106d3578063e6ba7f59146106f3578063ea5807f71461071357610246565b8063c4d66de81461060b578063d4422df61461062b578063d55ec6971461064b578063d5a16cc214610660578063dbb159fb1461068057610246565b8063b24b8b26116100f2578063b24b8b2614610541578063b320bd721461056e578063b51c11d81461059d578063b95ed06f146105cb578063c311d049146105eb57610246565b80639b0884e9146104a1578063a33b7384146104c1578063a5006b72146104ee578063a77ac27114610501578063b124bce51461052157610246565b806354fd4d50116101bc5780637bf43d94116101805780637bf43d94146103fa578063890357301461041a578063890eba681461043c5780638e1e280c1461045e5780639264bc731461047157610246565b806354fd4d50146103865780635aa6e675146103a857806361825a75146103bd5780636c94d6ef146103d057806376a162a3146103e557610246565b8063374147b011610203578063374147b0146102ed578063380f22d61461030f5780634267ee791461032f5780634416f0b81461034457806353950e521461037157610246565b8063034fa5161461024b57806309c255c71461026d5780630e49ab30146102985780631c1ab1a1146102b85780632cad4914146102cd57610246565b3661024657005b600080fd5b34801561025757600080fd5b5061026b610266366004614d45565b610733565b005b34801561027957600080fd5b5061028261085b565b60405161028f91906156ad565b60405180910390f35b3480156102a457600080fd5b506102826102b3366004614859565b610905565b3480156102c457600080fd5b50610282610920565b3480156102d957600080fd5b5061026b6102e83660046148d6565b61092f565b3480156102f957600080fd5b50610302610a11565b60405161028f9190614e7a565b34801561031b57600080fd5b5061026b61032a366004614cde565b610a20565b34801561033b57600080fd5b5061026b610ad4565b34801561035057600080fd5b5061036461035f366004614891565b610e12565b60405161028f9190614f26565b34801561037d57600080fd5b5061026b610eb9565b34801561039257600080fd5b5061039b610ee5565b60405161028f91906156cc565b3480156103b457600080fd5b50610302610efa565b61026b6103cb3660046149e7565b610f09565b3480156103dc57600080fd5b5061039b610ff1565b3480156103f157600080fd5b5061026b611007565b34801561040657600080fd5b50610364610415366004614891565b6110af565b34801561042657600080fd5b5061042f6110f9565b60405161028f9190615364565b34801561044857600080fd5b50610451611172565b60405161028f91906156e1565b61026b61046c3660046149e7565b61117b565b34801561047d57600080fd5b5061049161048c366004614859565b61249c565b60405161028f949392919061567c565b3480156104ad57600080fd5b506102826104bc366004614859565b612690565b3480156104cd57600080fd5b506104e16104dc366004614988565b61277e565b60405161028f9190615456565b61026b6104fc3660046149e7565b6128d1565b34801561050d57600080fd5b5061036461051c366004614859565b612919565b34801561052d57600080fd5b5061026b61053c366004614859565b6129b1565b34801561054d57600080fd5b5061056161055c366004614988565b612a1f565b60405161028f91906153ea565b34801561057a57600080fd5b5061058e610589366004614859565b612aba565b60405161028f939291906156b6565b3480156105a957600080fd5b506105bd6105b8366004614a65565b612dd9565b60405161028f929190615020565b3480156105d757600080fd5b5061058e6105e6366004614859565b612eb9565b3480156105f757600080fd5b5061026b610606366004614cde565b613064565b34801561061757600080fd5b5061026b610626366004614859565b6130d6565b34801561063757600080fd5b5061026b610646366004614988565b6131d9565b34801561065757600080fd5b5061026b61321d565b34801561066c57600080fd5b5061026b61067b366004614d0e565b613259565b34801561068c57600080fd5b5061026b61069b366004614bf4565b613313565b61026b6106ae3660046149b3565b61350e565b3480156106bf57600080fd5b5061026b6106ce366004614988565b614068565b3480156106df57600080fd5b5061026b6106ee366004614cb1565b6140ac565b3480156106ff57600080fd5b5061058e61070e366004614a21565b614115565b34801561071f57600080fd5b5061026b61072e366004614dd8565b614220565b600054600160481b900460ff16600114156107695760405162461bcd60e51b8152600401610760906152dc565b60405180910390fd5b6000805460ff60481b1916600160481b17905560055460405163a798e17d60e01b81526001600160a01b039091169063a798e17d906107b2903390889088908890600401614ed8565b600060405180830381600087803b1580156107cc57600080fd5b505af11580156107e0573d6000803e3d6000fd5b5050600554604051633d835e8960e21b81526001600160a01b03909116925063f60d7a2491506108169033908590600401614ebf565b600060405180830381600087803b15801561083057600080fd5b505af1158015610844573d6000803e3d6000fd5b50506000805460ff60481b19169055505050505050565b600154600090819061088e9062249f009061088890439063ffffffff600160581b90910481169061444916565b9061446c565b9050600060098211156108c2575068022b1c8c1227a00000630a519fd04311156108bd57600092505050610902565b6108d4565b600b82600a81106108cf57fe5b015490505b6001546108fd906108f6904390600160781b90046001600160801b0316614449565b829061449e565b925050505b90565b6001600160a01b03166000908152601f602052604090205490565b6002546001600160801b031690565b6109376144d5565b604051630e3e2b6560e31b815273fe543efe9bb91b51a046157b73fdf0838833b841906371f15b2890610973906001908690869060040161558f565b60006040518083038186803b15801561098b57600080fd5b505af415801561099f573d6000803e3d6000fd5b5050604051637b576fc960e01b815273265b6c10c606cd1c79545799ebe36bca9ce124a59250637b576fc991506109dd906001908690600401615549565b60006040518083038186803b1580156109f557600080fd5b505af4158015610a09573d6000803e3d6000fd5b505050505050565b6026546001600160a01b031690565b600054600160481b900460ff1660011415610a4d5760405162461bcd60e51b8152600401610760906152dc565b6000805460ff60481b1916600160481b179055600554604051633d835e8960e21b81526001600160a01b039091169063f60d7a2490610a929033908590600401614ebf565b600060405180830381600087803b158015610aac57600080fd5b505af1158015610ac0573d6000803e3d6000fd5b50506000805460ff60481b19169055505050565b6027546026546001600160a01b039182169116331480610afc5750336001600160a01b038216145b610b185760405162461bcd60e51b8152600401610760906151ad565b602754600580546001600160a01b0319166001600160a01b039283161790819055604080516397dcd0b360e01b8152905191909216916397dcd0b3916004828101926020929190829003018186803b158015610b7357600080fd5b505afa158015610b87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bab9190614875565b600680546001600160a01b0319166001600160a01b03928316179055600554604080516316733a0d60e31b81529051919092169163b399d068916004808301926020929190829003018186803b158015610c0457600080fd5b505afa158015610c18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3c9190614875565b600780546001600160a01b0319166001600160a01b039283161790556005546040805163c2c5c90960e01b81529051919092169163c2c5c909916004808301926020929190829003018186803b158015610c9557600080fd5b505afa158015610ca9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ccd9190614875565b600980546001600160a01b0319166001600160a01b0392831617905560055460408051634dee753360e01b815290519190921691634dee7533916004808301926020929190829003018186803b158015610d2657600080fd5b505afa158015610d3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5e9190614875565b600880546001600160a01b0319166001600160a01b0392831617905560055460408051630a1107d360e41b81529051919092169163a1107d30916004808301926020929190829003018186803b158015610db757600080fd5b505afa158015610dcb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610def9190614875565b600a80546001600160a01b0319166001600160a01b039290921691909117905550565b6060610e1c6144d5565b6040516331e0286360e01b815273265b6c10c606cd1c79545799ebe36bca9ce124a5906331e0286390610e5c906001908990899089908990600401615560565b60006040518083038186803b158015610e7457600080fd5b505af4158015610e88573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610eb09190810190614a92565b95945050505050565b610ec16144f6565b6000805468ffffffffffffffff0019166101004367ffffffffffffffff1602179055565b600054610100900467ffffffffffffffff1681565b6026546001600160a01b031681565b610f116144d5565b6040516335413fb560e01b815273fe543efe9bb91b51a046157b73fdf0838833b841906335413fb590610f51906001908890889088908890600401615605565b60006040518083038186803b158015610f6957600080fd5b505af4158015610f7d573d6000803e3d6000fd5b5050604051637b576fc960e01b815273265b6c10c606cd1c79545799ebe36bca9ce124a59250637b576fc99150610fbb906001908890600401615549565b60006040518083038186803b158015610fd357600080fd5b505af4158015610fe7573d6000803e3d6000fd5b5050505050505050565b600154600160781b90046001600160801b031690565b602760009054906101000a90046001600160a01b03166001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b15801561105557600080fd5b505afa158015611069573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108d9190614875565b602680546001600160a01b0319166001600160a01b0392909216919091179055565b60606110b96144d5565b6040516341850fdb60e11b815273265b6c10c606cd1c79545799ebe36bca9ce124a59063830a1fb690610e5c906001908990899089908990600401615560565b61110161460d565b60015460ff808216835263ffffffff6101008304166020840152600160281b820481166040840152600160301b820481166060840152600160381b820481166080840152600160401b8204811660a0840152600160481b8204811660c0840152600160501b9091041660e082015290565b60005460ff1681565b6111836144d5565b60015460ff1683146111a75760405162461bcd60e51b8152600401610760906150cd565b6000821180156111b75750600081115b6111d35760405162461bcd60e51b8152600401610760906150fa565b6005546040516372956b6960e01b81526000916001600160a01b0316906372956b6990611204908890600401614e7a565b60206040518083038186803b15801561121c57600080fd5b505afa158015611230573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112549190614875565b9050846001600160a01b0316816001600160a01b03161415801561128057506001600160a01b03811615155b61129c5760405162461bcd60e51b81526004016107609061522f565b6001546000906112d3906127109061088890670de0b6b3a7640000906112cd908a90600160301b900460ff1661449e565b9061449e565b6005549091506001600160a01b031660006112ee3484614449565b111561135d576001600160a01b03811663ad9d4ba361130d3485614449565b336040518363ffffffff1660e01b815260040161132a9190614e7a565b6000604051808303818588803b15801561134357600080fd5b505af1158015611357573d6000803e3d6000fd5b50505050505b600754600a546006546001600160a01b0392831692918216918681169116141561146b576001600160a01b03821663daa78c0f6113a0606461088888605061449e565b876040518363ffffffff1660e01b81526004016113bd9190614e7a565b6000604051808303818588803b1580156113d657600080fd5b505af11580156113ea573d6000803e3d6000fd5b5050505050806001600160a01b031663daa78c0f611417606461088860148961449e90919063ffffffff16565b876040518363ffffffff1660e01b81526004016114349190614e7a565b6000604051808303818588803b15801561144d57600080fd5b505af1158015611461573d6000803e3d6000fd5b50505050506115d8565b6001600160a01b03821663daa78c0f61148a606461088888603c61449e565b876040518363ffffffff1660e01b81526004016114a79190614e7a565b6000604051808303818588803b1580156114c057600080fd5b505af11580156114d4573d6000803e3d6000fd5b5050505050806001600160a01b031663daa78c0f611501606461088860148961449e90919063ffffffff16565b876040518363ffffffff1660e01b815260040161151e9190614e7a565b6000604051808303818588803b15801561153757600080fd5b505af115801561154b573d6000803e3d6000fd5b5050505050806001600160a01b031663daa78c0f611578606461088860148961449e90919063ffffffff16565b6006546040516001600160e01b031960e085901b1681526115a5916001600160a01b031690600401614e7a565b6000604051808303818588803b1580156115be57600080fd5b505af11580156115d2573d6000803e3d6000fd5b50505050505b6001600160a01b0383166361025502336115fa8b670de0b6b3a764000061449e565b8c6116058c8e61449e565b6040518563ffffffff1660e01b81526004016116249493929190614ed8565b600060405180830381600087803b15801561163e57600080fd5b505af1158015611652573d6000803e3d6000fd5b5050506001600160a01b03841690506361025502336116798b670de0b6b3a764000061449e565b886116848b8e61449e565b6040518563ffffffff1660e01b81526004016116a39493929190614ed8565b600060405180830381600087803b1580156116bd57600080fd5b505af11580156116d1573d6000803e3d6000fd5b50506001546001600160a01b0386169250632dc8decd9150339061171590683635c9adc5dea00000906112cd9063ffffffff61010090910481169060029061449e16565b6040518363ffffffff1660e01b8152600401611732929190614ebf565b600060405180830381600087803b15801561174c57600080fd5b505af1158015611760573d6000803e3d6000fd5b5050600654600095508594506001600160a01b038881169116141592506117909150505750600190506002611798565b506003905060045b60006001601e0160008a6001600160a01b03166001600160a01b03168152602001908152602001600020905080604051806101800160405280336001600160a01b031681526020014363ffffffff1681526020018a63ffffffff1681526020018a63ffffffff168152602001600060ff1681526020018560ff168152602001600160ff168152602001600060ff1681526020018a63ffffffff1681526020018a63ffffffff168152602001600160000160019054906101000a900463ffffffff1663ffffffff168152602001896001600160801b0316815250908060018154018082558091505060019003906000526020600020906002020160009091909190915060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160006101000a81548160ff021916908360ff16021790555060a08201518160010160016101000a81548160ff021916908360ff16021790555060c08201518160010160026101000a81548160ff021916908360ff16021790555060e08201518160010160036101000a81548160ff021916908360ff1602179055506101008201518160010160046101000a81548163ffffffff021916908363ffffffff1602179055506101208201518160010160086101000a81548163ffffffff021916908363ffffffff16021790555061014082015181600101600c6101000a81548163ffffffff021916908363ffffffff1602179055506101608201518160010160106101000a8154816001600160801b0302191690836001600160801b03160217905550505060006001601e016000876001600160a01b03166001600160a01b03168152602001908152602001600020905080604051806101800160405280336001600160a01b031681526020014363ffffffff1681526020018b63ffffffff1681526020018b63ffffffff168152602001600060ff1681526020018560ff168152602001600160ff168152602001600060ff1681526020018b63ffffffff1681526020018b63ffffffff168152602001600160000160019054906101000a900463ffffffff1663ffffffff168152602001896001600160801b0316815250908060018154018082558091505060019003906000526020600020906002020160009091909190915060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160006101000a81548160ff021916908360ff16021790555060a08201518160010160016101000a81548160ff021916908360ff16021790555060c08201518160010160026101000a81548160ff021916908360ff16021790555060e08201518160010160036101000a81548160ff021916908360ff1602179055506101008201518160010160046101000a81548163ffffffff021916908363ffffffff1602179055506101208201518160010160086101000a81548163ffffffff021916908363ffffffff16021790555061014082015181600101600c6101000a81548163ffffffff021916908363ffffffff1602179055506101608201518160010160106101000a8154816001600160801b0302191690836001600160801b0316021790555050507fee7aa1809348e0f32177d04baf37df86a10ef3337729271eeff50db46e199190338b6001858054905003611d7e670de0b6b3a76400008e61449e90919063ffffffff16565b611d888d8f61449e565b604051611d99959493929190614e8e565b60405180910390a180547fee7aa1809348e0f32177d04baf37df86a10ef3337729271eeff50db46e199190903390889060001901611ddf8d670de0b6b3a764000061449e565b611de98c8f61449e565b604051611dfa959493929190614e8e565b60405180910390a150506006546001600160a01b038581169116141591506120de9050576001600160a01b0386166000908152602160209081526040808320438452909152902054608081901c6001600160801b0382168161209d576000611e6061085b565b60018054600160781b600160f81b0319164363ffffffff908116600160781b0291909117909155600280546001600160801b031981166001600160801b039182168501909116179055909150611ec29060649061088890849060509061449e16565b6005546008549194506001600160a01b0390811691635c3a6cf29116611eee606461088886600f61449e565b6040518363ffffffff1660e01b8152600401611f0b929190614ebf565b600060405180830381600087803b158015611f2557600080fd5b505af1158015611f39573d6000803e3d6000fd5b50506008546001600160a01b0316915063ccaaf98b9050611f60606461088885600f61449e565b6040518263ffffffff1660e01b8152600401611f7c91906156ad565b600060405180830381600087803b158015611f9657600080fd5b505af1158015611faa573d6000803e3d6000fd5b505060058054600a546001600160a01b039182169450635c3a6cf293501690611fdb9060649061088890879061449e565b6040518363ffffffff1660e01b8152600401611ff8929190614ebf565b600060405180830381600087803b15801561201257600080fd5b505af1158015612026573d6000803e3d6000fd5b5050600a546001600160a01b03169150630c202bf7905061204d606461088885600561449e565b6040518263ffffffff1660e01b815260040161206991906156ad565b600060405180830381600087803b15801561208357600080fd5b505af1158015612097573d6000803e3d6000fd5b50505050505b6120a78189614520565b6001600160a01b038a1660009081526021602090815260408083204384529091529020600160801b90930201909155506123c09050565b6001600160a01b0386166000908152602160209081526040808320438452909152902054608081901c6001600160801b0382168161238457600061212186612690565b90506000866001600160a01b03166328e6a33f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561215e57600080fd5b505afa158015612172573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121969190614875565b6005549091506001600160a01b038083169116141561221d576005546040516394bf804d60e01b815292945084926001600160a01b03808a16926394bf804d926121e69287921690600401615549565b600060405180830381600087803b15801561220057600080fd5b505af1158015612214573d6000803e3d6000fd5b50505050612381565b6040516381fa543160e01b81526001600160a01b038816906381fa5431906122499085906004016156ad565b600060405180830381600087803b15801561226357600080fd5b505af1158015612277573d6000803e3d6000fd5b505060055460405163a9059cbb60e01b81526001600160a01b03808c16945063a9059cbb93506122ad9216908690600401614ebf565b602060405180830381600087803b1580156122c757600080fd5b505af11580156122db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ff9190614bd4565b50612310606461088884605f61449e565b6005549094506001600160a01b03166361bced9d82896123308689614449565b6040518463ffffffff1660e01b815260040161234e93929190614f02565b600060405180830381600087803b15801561236857600080fd5b505af115801561237c573d6000803e3d6000fd5b505050505b50505b61238e8189614520565b6001600160a01b038a1660009081526021602090815260408083204384529091529020600160801b9093020190915550505b604051637b576fc960e01b815273265b6c10c606cd1c79545799ebe36bca9ce124a590637b576fc9906123fa906001908a90600401615549565b60006040518083038186803b15801561241257600080fd5b505af4158015612426573d6000803e3d6000fd5b5050604051637b576fc960e01b815273265b6c10c606cd1c79545799ebe36bca9ce124a59250637b576fc99150612464906001908690600401615549565b60006040518083038186803b15801561247c57600080fd5b505af4158015612490573d6000803e3d6000fd5b50505050505050505050565b6000808080333214806124b95750600a546001600160a01b031633145b806124ce57506007546001600160a01b031633145b806124e357506008546001600160a01b031633145b806124f857506009546001600160a01b031633145b6125145760405162461bcd60e51b815260040161076090615313565b61251c614651565b506001600160a01b03851660009081526020808052604091829020825161012081018452815463ffffffff808216835264010000000082048116948301859052600160401b8204811695830195909552600160601b810490941660608201526001600160801b03600160801b94859004811660808301526001830154600f81810b810b810b60a085015290869004810b810b900b60c083015260029092015480831660e083015293909304166101008301526125ea5760405162461bcd60e51b8152600401610760906150a0565b6125ff6125fa8260a00151614543565b61457f565b925061262b816040015163ffffffff1682608001516001600160801b031661446c90919063ffffffff16565b60e08201516001546020840151929750909550600160381b900460ff160191506001600160801b0385161580159061266c57506000846001600160801b0316115b6126885760405162461bcd60e51b81526004016107609061525c565b509193509193565b6000806000836001600160a01b03166392c088716040518163ffffffff1660e01b8152600401604080518083038186803b1580156126cd57600080fd5b505afa1580156126e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127059190614d6c565b9092509050600061271d62249f006108884386614449565b905060006009821115612739575067058d15e17628000061274b565b601582600a811061274657fe5b015490505b60006127574385614449565b90506064811115612766575060645b6000612772838361449e565b98975050505050505050565b61278661469d565b61278e6144d5565b6001600160a01b0383166000908152601f60205260409020548083106127c65760405162461bcd60e51b8152600401610760906151d8565b6001600160a01b0384166000908152601f602052604090208054849081106127ea57fe5b6000918252602091829020604080516101808101825260029390930290910180546001600160a01b0381168452600160a01b810463ffffffff90811695850195909552600160c01b8104851692840192909252600160e01b909104831660608301526001015460ff8082166080840152610100808304821660a0850152620100008304821660c08501526301000000830490911660e08401526401000000008204841690830152600160401b81048316610120830152600160601b8104909216610140820152600160801b9091046001600160801b03166101608201529150505b92915050565b6128d96144d5565b604051630d26201760e31b815273fe543efe9bb91b51a046157b73fdf0838833b8419063693100b890610f51906001908890889088908890600401615605565b60606129236144d5565b6040516306d8420960e21b815273265b6c10c606cd1c79545799ebe36bca9ce124a590631b6108249061295d906001908690600401615549565b60006040518083038186803b15801561297557600080fd5b505af4158015612989573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128cb9190810190614a92565b604051637b576fc960e01b815273265b6c10c606cd1c79545799ebe36bca9ce124a590637b576fc9906129eb906001908590600401615549565b60006040518083038186803b158015612a0357600080fd5b505af4158015612a17573d6000803e3d6000fd5b505050505b50565b612a27614701565b604051631182622760e21b815273265b6c10c606cd1c79545799ebe36bca9ce124a590634609889c90612a6390600190879087906004016155e6565b60e06040518083038186803b158015612a7b57600080fd5b505af4158015612a8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ab39190614c10565b9392505050565b6000808033321480612ad65750600a546001600160a01b031633145b80612aeb57506007546001600160a01b031633145b80612b0057506008546001600160a01b031633145b80612b1557506009546001600160a01b031633145b612b315760405162461bcd60e51b815260040161076090615313565b6001600160a01b0384166000908152601f6020526040812080549091612b5561469d565b82612b725760405162461bcd60e51b81526004016107609061525c565b600060015b848111612d8f578581860381548110612b8c57fe5b6000918252602091829020604080516101808101825260029390930290910180546001600160a01b0381168452600160a01b810463ffffffff90811695850195909552600160c01b8104851692840192909252600160e01b909104831660608301526001015460ff8082166080840152610100808304821660a0850152620100008304821660c08501526301000000830490911660e08401526401000000008204841690830152600160401b81048316610120830152600160601b8104909216610140820152600160801b9091046001600160801b0316610160820152925081158015612c99575043600160000160079054906101000a900460ff1660ff16846020015163ffffffff1601105b15612d0157606083015163ffffffff16935083612cb557612d87565b826020015163ffffffff169150612ce38361016001516001600160801b03168561449e90919063ffffffff16565b9750612cf784670de0b6b3a764000061449e565b9850819650612d87565b826020015163ffffffff16821415612d7057826060015163ffffffff169350612d4b612d448461016001516001600160801b03168661449e90919063ffffffff16565b8990614520565b9750612d69612d6285670de0b6b3a764000061449e565b8a90614520565b9850612d87565b826020015163ffffffff16821115612d8757612d8f565b600101612b77565b50600154600160381b900460ff1695909501948715801590612db15750600087115b612dcd5760405162461bcd60e51b81526004016107609061525c565b50505050509193909250565b6009546060906000906001600160a01b031633321480612e015750336001600160a01b038216145b612e1d5760405162461bcd60e51b815260040161076090615202565b6040516353b847a960e01b815273265b6c10c606cd1c79545799ebe36bca9ce124a5906353b847a990612e59906001908990899060040161565a565b60006040518083038186803b158015612e7157600080fd5b505af4158015612e85573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612ead9190810190614b31565b92509250509250929050565b600954600090819081906001600160a01b031633321480612ee25750336001600160a01b038216145b612efe5760405162461bcd60e51b815260040161076090615202565b612f06614651565b506001600160a01b03851660009081526020808052604091829020825161012081018452815463ffffffff808216835264010000000082048116948301859052600160401b8204811695830195909552600160601b810490941660608201526001600160801b03600160801b94859004811660808301526001830154600f81810b810b810b60a085015290869004810b810b900b60c083015260029092015480831660e08301529390930416610100830152612fd45760405162461bcd60e51b8152600401610760906150a0565b612ff9670de0b6b3a7640000826040015163ffffffff1661449e90919063ffffffff16565b945080608001516001600160801b03169350600160000160079054906101000a900460ff1660ff1681602001510163ffffffff16925060008511801561303f5750600084115b61305b5760405162461bcd60e51b81526004016107609061525c565b50509193909250565b600054600160481b900460ff16600114156130915760405162461bcd60e51b8152600401610760906152dc565b6000805460ff60481b1916600160481b1790556005546040516306e6a46960e21b81526001600160a01b0390911690631b9a91a490610a929033908590600401614ebf565b60005460ff16156130f95760405162461bcd60e51b815260040161076090615289565b6815af1d78b58c40000060005b600a8110156131395781600b82600a811061311d57fe5b015561312f606461088884605061449e565b9150600101613106565b50673782dace9d900000905060005b600a81101561317b5781601582600a811061315f57fe5b0155613171606461088884605061449e565b9150600101613148565b505060268054336001600160a01b03199182161790915560008054602780549093166001600160a01b03949094169390931790915568ffffffffffffffff00199091166101004367ffffffffffffffff16021760ff19166001179055565b6131e16144d5565b604051633ebf3e8560e21b815273fe543efe9bb91b51a046157b73fdf0838833b8419063fafcfa149061097390600190869086906004016155e6565b6132256144f6565b60005460ff1660021461324a5760405162461bcd60e51b815260040161076090615289565b6000805460ff19166003179055565b600054600160481b900460ff16600114156132865760405162461bcd60e51b8152600401610760906152dc565b6000805460ff60481b1916600160481b17905560055460405163a798e17d60e01b81526001600160a01b039091169063a798e17d906132cf903390879087908790600401614ed8565b600060405180830381600087803b1580156132e957600080fd5b505af11580156132fd573d6000803e3d6000fd5b50506000805460ff60481b191690555050505050565b61331b6144f6565b6133286020820182614e33565b6001805460ff191660ff9290921691909117905561334c6040820160208301614dbc565b6001805463ffffffff929092166101000264ffffffff001990921691909117905561337d6060820160408301614e33565b6001805460ff92909216600160281b0265ff0000000000199092169190911790556133ae6080820160608301614e33565b6001805460ff92909216600160301b0266ff000000000000199092169190911790556133e060a0820160808301614e33565b6001805460ff92909216600160381b0260ff60381b1990921691909117905561340f60c0820160a08301614e33565b6001805460ff92909216600160401b0260ff60401b1990921691909117905561343e60e0820160c08301614e33565b6001805460ff92909216600160481b0260ff60481b1990921691909117905561346e610100820160e08301614e33565b6001805460ff60501b1916600160501b60ff938416810291909117918290556040517fd52ea55597dda83c654fca3762be1b95778ce32b5d67b2ddc77f14e4c5f778ce936135039380821693610100820463ffffffff1693600160281b8304841693600160301b8404811693600160381b8104821693600160401b8204831693600160481b83048416939190920416906156ef565b60405180910390a150565b6135166144d5565b60015460ff16821461353a5760405162461bcd60e51b8152600401610760906150cd565b6000811161355a5760405162461bcd60e51b8152600401610760906150fa565b6005546040516372956b6960e01b81526001600160a01b039091169060009082906372956b699061358f908890600401614e7a565b60206040518083038186803b1580156135a757600080fd5b505afa1580156135bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135df9190614875565b90506001600160a01b0381161580159061360757506006546001600160a01b03828116911614155b80156136255750806001600160a01b0316856001600160a01b031614155b6136415760405162461bcd60e51b81526004016107609061522f565b6a0422ca8b0a00a425000000816001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561368657600080fd5b505afa15801561369a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136be9190614cf6565b106136db5760405162461bcd60e51b815260040161076090615154565b60015460009061370c906127109061088890670de0b6b3a7640000906112cd908a90600160301b900460ff1661449e565b9050600061371a3483614449565b1115613789576001600160a01b03831663ad9d4ba36137393484614449565b336040518363ffffffff1660e01b81526004016137569190614e7a565b6000604051808303818588803b15801561376f57600080fd5b505af1158015613783573d6000803e3d6000fd5b50505050505b600754600a546001600160a01b0391821691168163daa78c0f6137b2606461088887603c61449e565b866040518363ffffffff1660e01b81526004016137cf9190614e7a565b6000604051808303818588803b1580156137e857600080fd5b505af11580156137fc573d6000803e3d6000fd5b5050505050806001600160a01b031663daa78c0f613829606461088860148861449e90919063ffffffff16565b866040518363ffffffff1660e01b81526004016138469190614e7a565b6000604051808303818588803b15801561385f57600080fd5b505af1158015613873573d6000803e3d6000fd5b5050505050806001600160a01b031663daa78c0f6138a0606461088860148861449e90919063ffffffff16565b6006546040516001600160e01b031960e085901b1681526138cd916001600160a01b031690600401614e7a565b6000604051808303818588803b1580156138e657600080fd5b505af11580156138fa573d6000803e3d6000fd5b5050505050846001600160a01b031663610255023361392a670de0b6b3a76400008b61449e90919063ffffffff16565b8b6139358b8d61449e565b6040518563ffffffff1660e01b81526004016139549493929190614ed8565b600060405180830381600087803b15801561396e57600080fd5b505af1158015613982573d6000803e3d6000fd5b50506001546001600160a01b0388169250632dc8decd915033906139bf9063ffffffff610100909104811690683635c9adc5dea000009061449e16565b6040518363ffffffff1660e01b81526004016139dc929190614ebf565b600060405180830381600087803b1580156139f657600080fd5b505af1158015613a0a573d6000803e3d6000fd5b50505050505060006001601e016000886001600160a01b03166001600160a01b03168152602001908152602001600020905080604051806101800160405280336001600160a01b031681526020014363ffffffff1681526020018863ffffffff1681526020018863ffffffff168152602001600060ff168152602001600360ff168152602001600160ff168152602001600060ff1681526020018863ffffffff1681526020018863ffffffff168152602001600160000160019054906101000a900463ffffffff1663ffffffff168152602001876001600160801b0316815250908060018154018082558091505060019003906000526020600020906002020160009091909190915060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160006101000a81548160ff021916908360ff16021790555060a08201518160010160016101000a81548160ff021916908360ff16021790555060c08201518160010160026101000a81548160ff021916908360ff16021790555060e08201518160010160036101000a81548160ff021916908360ff1602179055506101008201518160010160046101000a81548163ffffffff021916908363ffffffff1602179055506101208201518160010160086101000a81548163ffffffff021916908363ffffffff16021790555061014082015181600101600c6101000a81548163ffffffff021916908363ffffffff1602179055506101608201518160010160106101000a8154816001600160801b0302191690836001600160801b0316021790555050507fee7aa1809348e0f32177d04baf37df86a10ef3337729271eeff50db46e19919033886001848054905003613d27670de0b6b3a76400008b61449e90919063ffffffff16565b613d318a8c61449e565b604051613d42959493929190614e8e565b60405180910390a1506001600160a01b0386166000908152602160209081526040808320438452909152902054608081901c6001600160801b03821681613ff1576000613d8e86612690565b90506000866001600160a01b03166328e6a33f6040518163ffffffff1660e01b815260040160206040518083038186803b158015613dcb57600080fd5b505afa158015613ddf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e039190614875565b6005549091506001600160a01b0380831691161415613e8a576005546040516394bf804d60e01b815292945084926001600160a01b03808a16926394bf804d92613e539287921690600401615549565b600060405180830381600087803b158015613e6d57600080fd5b505af1158015613e81573d6000803e3d6000fd5b50505050613fee565b613e9a606461088884605f61449e565b6040516381fa543160e01b81529094506001600160a01b038816906381fa543190613ec99085906004016156ad565b600060405180830381600087803b158015613ee357600080fd5b505af1158015613ef7573d6000803e3d6000fd5b505060055460405163a9059cbb60e01b81526001600160a01b03808c16945063a9059cbb9350613f2d9216908690600401614ebf565b602060405180830381600087803b158015613f4757600080fd5b505af1158015613f5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f7f9190614bd4565b506005546001600160a01b03166361bced9d8289613f9d8689614449565b6040518463ffffffff1660e01b8152600401613fbb93929190614f02565b600060405180830381600087803b158015613fd557600080fd5b505af1158015613fe9573d6000803e3d6000fd5b505050505b50505b613ffb8189614520565b6001600160a01b038a16600090815260216020908152604080832043845290915290819020600160801b9094029091019092555051637b576fc960e01b815273265b6c10c606cd1c79545799ebe36bca9ce124a59150637b576fc990612464906001908a90600401615549565b6140706144d5565b604051638f2daafb60e01b815273fe543efe9bb91b51a046157b73fdf0838833b84190638f2daafb9061097390600190869086906004016155e6565b6140b46144f6565b60005460ff166002146140d95760405162461bcd60e51b815260040161076090615289565b60018054600160781b600160f81b031916600160781b6001600160801b0394851602179055600280546001600160801b03191691909216179055565b600954600090819081906001600160a01b03163332148061413e5750336001600160a01b038216145b61415a5760405162461bcd60e51b815260040161076090615202565b604051630da947f160e21b815273265b6c10c606cd1c79545799ebe36bca9ce124a5906336a51fc490614196906001908a908a90600401615631565b60606040518083038186803b1580156141ae57600080fd5b505af41580156141c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141e69190614d8f565b9195509350915083158015906141fc5750600083115b6142185760405162461bcd60e51b81526004016107609061525c565b509250925092565b6142286144f6565b60005460ff1660011461424d5760405162461bcd60e51b815260040161076090615289565b61425a6020820182614e33565b6001805460ff191660ff9290921691909117905561427e6040820160208301614dbc565b6001805463ffffffff929092166101000264ffffffff00199092169190911790556142af6060820160408301614e33565b6001805460ff92909216600160281b0265ff0000000000199092169190911790556142e06080820160608301614e33565b6001805460ff92909216600160301b0266ff0000000000001990921691909117905561431260a0820160808301614e33565b6001805460ff92909216600160381b0260ff60381b1990921691909117905561434160c0820160a08301614e33565b6001805460ff92909216600160401b0260ff60401b1990921691909117905561437060e0820160c08301614e33565b6001805460ff92909216600160481b0260ff60481b199092169190911790556143a0610100820160e08301614e33565b60018054600280546001600160801b0319166001600160801b0396871617815560ff60501b19909116600160501b60ff949094169390930292909217600160781b600160f81b031916600160781b95909416949094029290921763ffffffff60581b1916600160581b63ffffffff9590951694909402939093179091556000805468ffffffffffffffff0019166101004367ffffffffffffffff16021760ff1916909117905550565b808203828111156128cb5760405162461bcd60e51b815260040161076090615071565b600080821161448d5760405162461bcd60e51b8152600401610760906152b2565b81838161449657fe5b049392505050565b60008115806144b9575050808202828282816144b657fe5b04145b6128cb5760405162461bcd60e51b815260040161076090615126565b3332146144f45760405162461bcd60e51b815260040161076090615202565b565b6026546001600160a01b031633146144f45760405162461bcd60e51b81526004016107609061533c565b808201828110156128cb5760405162461bcd60e51b81526004016107609061517f565b6000600f82900b6f7fffffffffffffffffffffffffffffff19141561456757600080fd5b600082600f0b1261457857816128cb565b5060000390565b60008082600f0b121561459157600080fd5b6128cb604083600f0b901b600160401b6000826145b0575060006128cb565b600082116145bd57600080fd5b60008284816145c857fe5b049050808314806145db57508083600101145b156145e957829150506128cb565b806001018314156145fb5790506128cb565b6001818401600101901c9250506145bd565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915290565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b6000610100828403121561474f578081fd5b50919050565b6000610140808385031215614768578182fd5b61477181615739565b91505061477e838361482d565b815261478d8360208401614843565b602082015261479f8360408401614843565b60408201526147b18360608401614843565b60608201526147c3836080840161484e565b60808201526147d58360a0840161484e565b60a08201526147e78360c0840161484e565b60c082015260e082015160e082015261010061480584828501614843565b9082015261012061481884848301614822565b9082015292915050565b80516128cb81615795565b80516128cb81615780565b80356128cb816157aa565b80516128cb816157aa565b80516128cb816157bc565b60006020828403121561486a578081fd5b8135612ab381615780565b600060208284031215614886578081fd5b8151612ab381615780565b600080600080608085870312156148a6578283fd5b84356148b181615780565b935060208501356148c181615780565b93969395505050506040820135916060013590565b600080604083850312156148e8578182fd5b82356148f381615780565b915060208381013567ffffffffffffffff81111561490f578283fd5b8401601f8101861361491f578283fd5b803561493261492d82615760565b615739565b81815283810190838501858402850186018a101561494e578687fd5b8694505b83851015614978576149648a82614838565b835260019490940193918501918501614952565b5080955050505050509250929050565b6000806040838503121561499a578182fd5b82356149a581615780565b946020939093013593505050565b6000806000606084860312156149c7578081fd5b83356149d281615780565b95602085013595506040909401359392505050565b600080600080608085870312156149fc578182fd5b8435614a0781615780565b966020860135965060408601359560600135945092505050565b60008060408385031215614a33578182fd5b8235614a3e81615780565b9150602083013567ffffffffffffffff81168114614a5a578182fd5b809150509250929050565b60008060408385031215614a77578182fd5b8235614a8281615780565b91506020830135614a5a816157bc565b60006020808385031215614aa4578182fd5b825167ffffffffffffffff811115614aba578283fd5b8301601f81018513614aca578283fd5b8051614ad861492d82615760565b81815283810190838501610140808502860187018a1015614af7578788fd5b8795505b84861015614b2357614b0d8a83614755565b8452600195909501949286019290810190614afb565b509098975050505050505050565b60008060408385031215614b43578182fd5b825167ffffffffffffffff811115614b59578283fd5b8301601f81018513614b69578283fd5b8051614b7761492d82615760565b808282526020808301925080850189828387028801011115614b97578788fd5b8795505b84861015614bc2578051614bae81615795565b845260019590950194928101928101614b9b565b50969096015195979596505050505050565b600060208284031215614be5578081fd5b81518015158114612ab3578182fd5b60006101008284031215614c06578081fd5b612ab3838361473d565b600060e08284031215614c21578081fd5b614c2b60e0615739565b8251614c3681615780565b81526020830151614c46816157aa565b60208201526040830151614c59816157aa565b60408201526060830151614c6c816157bc565b60608201526080830151614c7f816157bc565b608082015260a0830151614c92816157aa565b60a082015260c0830151614ca5816157aa565b60c08201529392505050565b60008060408385031215614cc3578182fd5b8235614cce81615795565b91506020830135614a5a81615795565b600060208284031215614cef578081fd5b5035919050565b600060208284031215614d07578081fd5b5051919050565b600080600060608486031215614d22578081fd5b833592506020840135614d3481615780565b929592945050506040919091013590565b60008060008060808587031215614d5a578182fd5b8435935060208501356148c181615780565b60008060408385031215614d7e578182fd5b505080516020909101519092909150565b600080600060608486031215614da3578081fd5b8351925060208401519150604084015190509250925092565b600060208284031215614dcd578081fd5b8135612ab3816157aa565b6000806000806101608587031215614dee578182fd5b8435614df9816157aa565b93506020850135614e0981615795565b92506040850135614e1981615795565b9150614e28866060870161473d565b905092959194509250565b600060208284031215614e44578081fd5b8135612ab3816157bc565b6001600160801b03169052565b6001600160a01b03169052565b63ffffffff169052565b60ff169052565b6001600160a01b0391909116815260200190565b6001600160a01b03958616815293909416602084015260408301919091526060820152608081019190915260a00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039485168152602081019390935292166040820152606081019190915260800190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b602080825282518282018190526000919060409081850190868401855b82811015615013578151614f58858251614e5c565b86810151614f6888870182614e69565b5085810151614f7987870182614e69565b50606080820151614f8c82880182614e69565b5050608080820151614fa082880182614e73565b505060a080820151614fb482880182614e73565b505060c080820151614fc882880182614e73565b505060e0818101519086015261010080820151614fe782880182614e69565b50506101209081015190614ffd86820183614e4f565b5050610140939093019290850190600101614f43565b5091979650505050505050565b604080825283519082018190526000906020906060840190828701845b828110156150625781516001600160801b03168452928401929084019060010161503d565b50505092019290925292915050565b60208082526015908201527464732d6d6174682d7375622d756e646572666c6f7760581b604082015260600190565b6020808252601390820152724e6573743a4d696e653a4e4f2870726963652960681b604082015260600190565b6020808252601390820152724e6573743a4d696e653a21286574684e756d2960681b604082015260600190565b6020808252601290820152714e6573743a4d696e653a212870726963652960701b604082015260600190565b60208082526014908201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604082015260600190565b6020808252601190820152702732b9ba1d26b4b7329d10b73a37b5b2b760791b604082015260600190565b60208082526014908201527364732d6d6174682d6164642d6f766572666c6f7760601b604082015260600190565b6020808252601190820152702732b9ba1d26b4b7329d10b9b2b73232b960791b604082015260600190565b60208082526010908201526f4e6573743a4d696e653a3e286c656e2960801b604082015260600190565b6020808252601390820152724e6573743a4d696e653a636f6e74726163742160681b604082015260600190565b6020808252601390820152724e6573743a4d696e653a21286e746f6b656e2960681b604082015260600190565b6020808252601390820152724e6573743a4d696e653a6e6f2870726963652960681b604082015260600190565b6020808252600f908201526e4e6573743a4d696e653a21666c616760881b604082015260600190565b60208082526010908201526f64732d6d6174682d6469762d7a65726f60801b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6020808252600f908201526e09ccae6e8749ad2dcca744282eae8d608b1b604082015260600190565b6020808252600e908201526d2732b9ba1d26b4b7329d10a3a7ab60911b604082015260600190565b60006101008201905060ff835116825263ffffffff602084015116602083015260ff604084015116604083015260ff606084015116606083015260ff608084015116608083015260a08301516153bd60a0840182614e73565b5060c08301516153d060c0840182614e73565b5060e08301516153e360e0840182614e73565b5092915050565b600060e08201905060018060a01b038351168252602083015163ffffffff808216602085015280604086015116604085015260ff606086015116606085015260ff60808601511660808501528060a08601511660a08501528060c08601511660c0850152505092915050565b60006101808201905061546a828451614e5c565b602083015161547c6020840182614e69565b50604083015161548f6040840182614e69565b5060608301516154a26060840182614e69565b5060808301516154b56080840182614e73565b5060a08301516154c860a0840182614e73565b5060c08301516154db60c0840182614e73565b5060e08301516154ee60e0840182614e73565b506101008084015161550282850182614e69565b50506101208084015161551782850182614e69565b50506101408084015161552c82850182614e69565b50506101608084015161554182850182614e4f565b505092915050565b9182526001600160a01b0316602082015260400190565b9485526001600160a01b0393841660208601529190921660408401526060830191909152608082015260a00190565b8381526001600160a01b0383166020808301919091526060604083018190528351908301819052600091848101916080850190845b81811015614b2357845163ffffffff16835293830193918301916001016155c4565b9283526001600160a01b03919091166020830152604082015260600190565b9485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b9283526001600160a01b0391909116602083015267ffffffffffffffff16604082015260600190565b9283526001600160a01b0391909116602083015260ff16604082015260600190565b6001600160801b039485168152929093166020830152600f0b604082015263ffffffff909116606082015260800190565b90815260200190565b9283526020830191909152604082015260600190565b67ffffffffffffffff91909116815260200190565b60ff91909116815260200190565b60ff988916815263ffffffff979097166020880152948716604087015292861660608601529085166080850152841660a0840152831660c083015290911660e08201526101000190565b60405181810167ffffffffffffffff8111828210171561575857600080fd5b604052919050565b600067ffffffffffffffff821115615776578081fd5b5060209081020190565b6001600160a01b0381168114612a1c57600080fd5b6001600160801b0381168114612a1c57600080fd5b63ffffffff81168114612a1c57600080fd5b60ff81168114612a1c57600080fdfea2646970667358221220d93eef17cc519ed96e943ab106845bf42eba3c315bd881f3d3980f522e5e09e864736f6c634300060c0033

Deployed Bytecode

0x60806040526004361061023f5760003560e01c80639b0884e91161012e578063c4d66de8116100ab578063e25b667a1161006f578063e25b667a146106a0578063e49280cb146106b3578063e6adb1ab146106d3578063e6ba7f59146106f3578063ea5807f71461071357610246565b8063c4d66de81461060b578063d4422df61461062b578063d55ec6971461064b578063d5a16cc214610660578063dbb159fb1461068057610246565b8063b24b8b26116100f2578063b24b8b2614610541578063b320bd721461056e578063b51c11d81461059d578063b95ed06f146105cb578063c311d049146105eb57610246565b80639b0884e9146104a1578063a33b7384146104c1578063a5006b72146104ee578063a77ac27114610501578063b124bce51461052157610246565b806354fd4d50116101bc5780637bf43d94116101805780637bf43d94146103fa578063890357301461041a578063890eba681461043c5780638e1e280c1461045e5780639264bc731461047157610246565b806354fd4d50146103865780635aa6e675146103a857806361825a75146103bd5780636c94d6ef146103d057806376a162a3146103e557610246565b8063374147b011610203578063374147b0146102ed578063380f22d61461030f5780634267ee791461032f5780634416f0b81461034457806353950e521461037157610246565b8063034fa5161461024b57806309c255c71461026d5780630e49ab30146102985780631c1ab1a1146102b85780632cad4914146102cd57610246565b3661024657005b600080fd5b34801561025757600080fd5b5061026b610266366004614d45565b610733565b005b34801561027957600080fd5b5061028261085b565b60405161028f91906156ad565b60405180910390f35b3480156102a457600080fd5b506102826102b3366004614859565b610905565b3480156102c457600080fd5b50610282610920565b3480156102d957600080fd5b5061026b6102e83660046148d6565b61092f565b3480156102f957600080fd5b50610302610a11565b60405161028f9190614e7a565b34801561031b57600080fd5b5061026b61032a366004614cde565b610a20565b34801561033b57600080fd5b5061026b610ad4565b34801561035057600080fd5b5061036461035f366004614891565b610e12565b60405161028f9190614f26565b34801561037d57600080fd5b5061026b610eb9565b34801561039257600080fd5b5061039b610ee5565b60405161028f91906156cc565b3480156103b457600080fd5b50610302610efa565b61026b6103cb3660046149e7565b610f09565b3480156103dc57600080fd5b5061039b610ff1565b3480156103f157600080fd5b5061026b611007565b34801561040657600080fd5b50610364610415366004614891565b6110af565b34801561042657600080fd5b5061042f6110f9565b60405161028f9190615364565b34801561044857600080fd5b50610451611172565b60405161028f91906156e1565b61026b61046c3660046149e7565b61117b565b34801561047d57600080fd5b5061049161048c366004614859565b61249c565b60405161028f949392919061567c565b3480156104ad57600080fd5b506102826104bc366004614859565b612690565b3480156104cd57600080fd5b506104e16104dc366004614988565b61277e565b60405161028f9190615456565b61026b6104fc3660046149e7565b6128d1565b34801561050d57600080fd5b5061036461051c366004614859565b612919565b34801561052d57600080fd5b5061026b61053c366004614859565b6129b1565b34801561054d57600080fd5b5061056161055c366004614988565b612a1f565b60405161028f91906153ea565b34801561057a57600080fd5b5061058e610589366004614859565b612aba565b60405161028f939291906156b6565b3480156105a957600080fd5b506105bd6105b8366004614a65565b612dd9565b60405161028f929190615020565b3480156105d757600080fd5b5061058e6105e6366004614859565b612eb9565b3480156105f757600080fd5b5061026b610606366004614cde565b613064565b34801561061757600080fd5b5061026b610626366004614859565b6130d6565b34801561063757600080fd5b5061026b610646366004614988565b6131d9565b34801561065757600080fd5b5061026b61321d565b34801561066c57600080fd5b5061026b61067b366004614d0e565b613259565b34801561068c57600080fd5b5061026b61069b366004614bf4565b613313565b61026b6106ae3660046149b3565b61350e565b3480156106bf57600080fd5b5061026b6106ce366004614988565b614068565b3480156106df57600080fd5b5061026b6106ee366004614cb1565b6140ac565b3480156106ff57600080fd5b5061058e61070e366004614a21565b614115565b34801561071f57600080fd5b5061026b61072e366004614dd8565b614220565b600054600160481b900460ff16600114156107695760405162461bcd60e51b8152600401610760906152dc565b60405180910390fd5b6000805460ff60481b1916600160481b17905560055460405163a798e17d60e01b81526001600160a01b039091169063a798e17d906107b2903390889088908890600401614ed8565b600060405180830381600087803b1580156107cc57600080fd5b505af11580156107e0573d6000803e3d6000fd5b5050600554604051633d835e8960e21b81526001600160a01b03909116925063f60d7a2491506108169033908590600401614ebf565b600060405180830381600087803b15801561083057600080fd5b505af1158015610844573d6000803e3d6000fd5b50506000805460ff60481b19169055505050505050565b600154600090819061088e9062249f009061088890439063ffffffff600160581b90910481169061444916565b9061446c565b9050600060098211156108c2575068022b1c8c1227a00000630a519fd04311156108bd57600092505050610902565b6108d4565b600b82600a81106108cf57fe5b015490505b6001546108fd906108f6904390600160781b90046001600160801b0316614449565b829061449e565b925050505b90565b6001600160a01b03166000908152601f602052604090205490565b6002546001600160801b031690565b6109376144d5565b604051630e3e2b6560e31b815273fe543efe9bb91b51a046157b73fdf0838833b841906371f15b2890610973906001908690869060040161558f565b60006040518083038186803b15801561098b57600080fd5b505af415801561099f573d6000803e3d6000fd5b5050604051637b576fc960e01b815273265b6c10c606cd1c79545799ebe36bca9ce124a59250637b576fc991506109dd906001908690600401615549565b60006040518083038186803b1580156109f557600080fd5b505af4158015610a09573d6000803e3d6000fd5b505050505050565b6026546001600160a01b031690565b600054600160481b900460ff1660011415610a4d5760405162461bcd60e51b8152600401610760906152dc565b6000805460ff60481b1916600160481b179055600554604051633d835e8960e21b81526001600160a01b039091169063f60d7a2490610a929033908590600401614ebf565b600060405180830381600087803b158015610aac57600080fd5b505af1158015610ac0573d6000803e3d6000fd5b50506000805460ff60481b19169055505050565b6027546026546001600160a01b039182169116331480610afc5750336001600160a01b038216145b610b185760405162461bcd60e51b8152600401610760906151ad565b602754600580546001600160a01b0319166001600160a01b039283161790819055604080516397dcd0b360e01b8152905191909216916397dcd0b3916004828101926020929190829003018186803b158015610b7357600080fd5b505afa158015610b87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bab9190614875565b600680546001600160a01b0319166001600160a01b03928316179055600554604080516316733a0d60e31b81529051919092169163b399d068916004808301926020929190829003018186803b158015610c0457600080fd5b505afa158015610c18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3c9190614875565b600780546001600160a01b0319166001600160a01b039283161790556005546040805163c2c5c90960e01b81529051919092169163c2c5c909916004808301926020929190829003018186803b158015610c9557600080fd5b505afa158015610ca9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ccd9190614875565b600980546001600160a01b0319166001600160a01b0392831617905560055460408051634dee753360e01b815290519190921691634dee7533916004808301926020929190829003018186803b158015610d2657600080fd5b505afa158015610d3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d5e9190614875565b600880546001600160a01b0319166001600160a01b0392831617905560055460408051630a1107d360e41b81529051919092169163a1107d30916004808301926020929190829003018186803b158015610db757600080fd5b505afa158015610dcb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610def9190614875565b600a80546001600160a01b0319166001600160a01b039290921691909117905550565b6060610e1c6144d5565b6040516331e0286360e01b815273265b6c10c606cd1c79545799ebe36bca9ce124a5906331e0286390610e5c906001908990899089908990600401615560565b60006040518083038186803b158015610e7457600080fd5b505af4158015610e88573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610eb09190810190614a92565b95945050505050565b610ec16144f6565b6000805468ffffffffffffffff0019166101004367ffffffffffffffff1602179055565b600054610100900467ffffffffffffffff1681565b6026546001600160a01b031681565b610f116144d5565b6040516335413fb560e01b815273fe543efe9bb91b51a046157b73fdf0838833b841906335413fb590610f51906001908890889088908890600401615605565b60006040518083038186803b158015610f6957600080fd5b505af4158015610f7d573d6000803e3d6000fd5b5050604051637b576fc960e01b815273265b6c10c606cd1c79545799ebe36bca9ce124a59250637b576fc99150610fbb906001908890600401615549565b60006040518083038186803b158015610fd357600080fd5b505af4158015610fe7573d6000803e3d6000fd5b5050505050505050565b600154600160781b90046001600160801b031690565b602760009054906101000a90046001600160a01b03166001600160a01b0316635aa6e6756040518163ffffffff1660e01b815260040160206040518083038186803b15801561105557600080fd5b505afa158015611069573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108d9190614875565b602680546001600160a01b0319166001600160a01b0392909216919091179055565b60606110b96144d5565b6040516341850fdb60e11b815273265b6c10c606cd1c79545799ebe36bca9ce124a59063830a1fb690610e5c906001908990899089908990600401615560565b61110161460d565b60015460ff808216835263ffffffff6101008304166020840152600160281b820481166040840152600160301b820481166060840152600160381b820481166080840152600160401b8204811660a0840152600160481b8204811660c0840152600160501b9091041660e082015290565b60005460ff1681565b6111836144d5565b60015460ff1683146111a75760405162461bcd60e51b8152600401610760906150cd565b6000821180156111b75750600081115b6111d35760405162461bcd60e51b8152600401610760906150fa565b6005546040516372956b6960e01b81526000916001600160a01b0316906372956b6990611204908890600401614e7a565b60206040518083038186803b15801561121c57600080fd5b505afa158015611230573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112549190614875565b9050846001600160a01b0316816001600160a01b03161415801561128057506001600160a01b03811615155b61129c5760405162461bcd60e51b81526004016107609061522f565b6001546000906112d3906127109061088890670de0b6b3a7640000906112cd908a90600160301b900460ff1661449e565b9061449e565b6005549091506001600160a01b031660006112ee3484614449565b111561135d576001600160a01b03811663ad9d4ba361130d3485614449565b336040518363ffffffff1660e01b815260040161132a9190614e7a565b6000604051808303818588803b15801561134357600080fd5b505af1158015611357573d6000803e3d6000fd5b50505050505b600754600a546006546001600160a01b0392831692918216918681169116141561146b576001600160a01b03821663daa78c0f6113a0606461088888605061449e565b876040518363ffffffff1660e01b81526004016113bd9190614e7a565b6000604051808303818588803b1580156113d657600080fd5b505af11580156113ea573d6000803e3d6000fd5b5050505050806001600160a01b031663daa78c0f611417606461088860148961449e90919063ffffffff16565b876040518363ffffffff1660e01b81526004016114349190614e7a565b6000604051808303818588803b15801561144d57600080fd5b505af1158015611461573d6000803e3d6000fd5b50505050506115d8565b6001600160a01b03821663daa78c0f61148a606461088888603c61449e565b876040518363ffffffff1660e01b81526004016114a79190614e7a565b6000604051808303818588803b1580156114c057600080fd5b505af11580156114d4573d6000803e3d6000fd5b5050505050806001600160a01b031663daa78c0f611501606461088860148961449e90919063ffffffff16565b876040518363ffffffff1660e01b815260040161151e9190614e7a565b6000604051808303818588803b15801561153757600080fd5b505af115801561154b573d6000803e3d6000fd5b5050505050806001600160a01b031663daa78c0f611578606461088860148961449e90919063ffffffff16565b6006546040516001600160e01b031960e085901b1681526115a5916001600160a01b031690600401614e7a565b6000604051808303818588803b1580156115be57600080fd5b505af11580156115d2573d6000803e3d6000fd5b50505050505b6001600160a01b0383166361025502336115fa8b670de0b6b3a764000061449e565b8c6116058c8e61449e565b6040518563ffffffff1660e01b81526004016116249493929190614ed8565b600060405180830381600087803b15801561163e57600080fd5b505af1158015611652573d6000803e3d6000fd5b5050506001600160a01b03841690506361025502336116798b670de0b6b3a764000061449e565b886116848b8e61449e565b6040518563ffffffff1660e01b81526004016116a39493929190614ed8565b600060405180830381600087803b1580156116bd57600080fd5b505af11580156116d1573d6000803e3d6000fd5b50506001546001600160a01b0386169250632dc8decd9150339061171590683635c9adc5dea00000906112cd9063ffffffff61010090910481169060029061449e16565b6040518363ffffffff1660e01b8152600401611732929190614ebf565b600060405180830381600087803b15801561174c57600080fd5b505af1158015611760573d6000803e3d6000fd5b5050600654600095508594506001600160a01b038881169116141592506117909150505750600190506002611798565b506003905060045b60006001601e0160008a6001600160a01b03166001600160a01b03168152602001908152602001600020905080604051806101800160405280336001600160a01b031681526020014363ffffffff1681526020018a63ffffffff1681526020018a63ffffffff168152602001600060ff1681526020018560ff168152602001600160ff168152602001600060ff1681526020018a63ffffffff1681526020018a63ffffffff168152602001600160000160019054906101000a900463ffffffff1663ffffffff168152602001896001600160801b0316815250908060018154018082558091505060019003906000526020600020906002020160009091909190915060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160006101000a81548160ff021916908360ff16021790555060a08201518160010160016101000a81548160ff021916908360ff16021790555060c08201518160010160026101000a81548160ff021916908360ff16021790555060e08201518160010160036101000a81548160ff021916908360ff1602179055506101008201518160010160046101000a81548163ffffffff021916908363ffffffff1602179055506101208201518160010160086101000a81548163ffffffff021916908363ffffffff16021790555061014082015181600101600c6101000a81548163ffffffff021916908363ffffffff1602179055506101608201518160010160106101000a8154816001600160801b0302191690836001600160801b03160217905550505060006001601e016000876001600160a01b03166001600160a01b03168152602001908152602001600020905080604051806101800160405280336001600160a01b031681526020014363ffffffff1681526020018b63ffffffff1681526020018b63ffffffff168152602001600060ff1681526020018560ff168152602001600160ff168152602001600060ff1681526020018b63ffffffff1681526020018b63ffffffff168152602001600160000160019054906101000a900463ffffffff1663ffffffff168152602001896001600160801b0316815250908060018154018082558091505060019003906000526020600020906002020160009091909190915060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160006101000a81548160ff021916908360ff16021790555060a08201518160010160016101000a81548160ff021916908360ff16021790555060c08201518160010160026101000a81548160ff021916908360ff16021790555060e08201518160010160036101000a81548160ff021916908360ff1602179055506101008201518160010160046101000a81548163ffffffff021916908363ffffffff1602179055506101208201518160010160086101000a81548163ffffffff021916908363ffffffff16021790555061014082015181600101600c6101000a81548163ffffffff021916908363ffffffff1602179055506101608201518160010160106101000a8154816001600160801b0302191690836001600160801b0316021790555050507fee7aa1809348e0f32177d04baf37df86a10ef3337729271eeff50db46e199190338b6001858054905003611d7e670de0b6b3a76400008e61449e90919063ffffffff16565b611d888d8f61449e565b604051611d99959493929190614e8e565b60405180910390a180547fee7aa1809348e0f32177d04baf37df86a10ef3337729271eeff50db46e199190903390889060001901611ddf8d670de0b6b3a764000061449e565b611de98c8f61449e565b604051611dfa959493929190614e8e565b60405180910390a150506006546001600160a01b038581169116141591506120de9050576001600160a01b0386166000908152602160209081526040808320438452909152902054608081901c6001600160801b0382168161209d576000611e6061085b565b60018054600160781b600160f81b0319164363ffffffff908116600160781b0291909117909155600280546001600160801b031981166001600160801b039182168501909116179055909150611ec29060649061088890849060509061449e16565b6005546008549194506001600160a01b0390811691635c3a6cf29116611eee606461088886600f61449e565b6040518363ffffffff1660e01b8152600401611f0b929190614ebf565b600060405180830381600087803b158015611f2557600080fd5b505af1158015611f39573d6000803e3d6000fd5b50506008546001600160a01b0316915063ccaaf98b9050611f60606461088885600f61449e565b6040518263ffffffff1660e01b8152600401611f7c91906156ad565b600060405180830381600087803b158015611f9657600080fd5b505af1158015611faa573d6000803e3d6000fd5b505060058054600a546001600160a01b039182169450635c3a6cf293501690611fdb9060649061088890879061449e565b6040518363ffffffff1660e01b8152600401611ff8929190614ebf565b600060405180830381600087803b15801561201257600080fd5b505af1158015612026573d6000803e3d6000fd5b5050600a546001600160a01b03169150630c202bf7905061204d606461088885600561449e565b6040518263ffffffff1660e01b815260040161206991906156ad565b600060405180830381600087803b15801561208357600080fd5b505af1158015612097573d6000803e3d6000fd5b50505050505b6120a78189614520565b6001600160a01b038a1660009081526021602090815260408083204384529091529020600160801b90930201909155506123c09050565b6001600160a01b0386166000908152602160209081526040808320438452909152902054608081901c6001600160801b0382168161238457600061212186612690565b90506000866001600160a01b03166328e6a33f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561215e57600080fd5b505afa158015612172573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121969190614875565b6005549091506001600160a01b038083169116141561221d576005546040516394bf804d60e01b815292945084926001600160a01b03808a16926394bf804d926121e69287921690600401615549565b600060405180830381600087803b15801561220057600080fd5b505af1158015612214573d6000803e3d6000fd5b50505050612381565b6040516381fa543160e01b81526001600160a01b038816906381fa5431906122499085906004016156ad565b600060405180830381600087803b15801561226357600080fd5b505af1158015612277573d6000803e3d6000fd5b505060055460405163a9059cbb60e01b81526001600160a01b03808c16945063a9059cbb93506122ad9216908690600401614ebf565b602060405180830381600087803b1580156122c757600080fd5b505af11580156122db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ff9190614bd4565b50612310606461088884605f61449e565b6005549094506001600160a01b03166361bced9d82896123308689614449565b6040518463ffffffff1660e01b815260040161234e93929190614f02565b600060405180830381600087803b15801561236857600080fd5b505af115801561237c573d6000803e3d6000fd5b505050505b50505b61238e8189614520565b6001600160a01b038a1660009081526021602090815260408083204384529091529020600160801b9093020190915550505b604051637b576fc960e01b815273265b6c10c606cd1c79545799ebe36bca9ce124a590637b576fc9906123fa906001908a90600401615549565b60006040518083038186803b15801561241257600080fd5b505af4158015612426573d6000803e3d6000fd5b5050604051637b576fc960e01b815273265b6c10c606cd1c79545799ebe36bca9ce124a59250637b576fc99150612464906001908690600401615549565b60006040518083038186803b15801561247c57600080fd5b505af4158015612490573d6000803e3d6000fd5b50505050505050505050565b6000808080333214806124b95750600a546001600160a01b031633145b806124ce57506007546001600160a01b031633145b806124e357506008546001600160a01b031633145b806124f857506009546001600160a01b031633145b6125145760405162461bcd60e51b815260040161076090615313565b61251c614651565b506001600160a01b03851660009081526020808052604091829020825161012081018452815463ffffffff808216835264010000000082048116948301859052600160401b8204811695830195909552600160601b810490941660608201526001600160801b03600160801b94859004811660808301526001830154600f81810b810b810b60a085015290869004810b810b900b60c083015260029092015480831660e083015293909304166101008301526125ea5760405162461bcd60e51b8152600401610760906150a0565b6125ff6125fa8260a00151614543565b61457f565b925061262b816040015163ffffffff1682608001516001600160801b031661446c90919063ffffffff16565b60e08201516001546020840151929750909550600160381b900460ff160191506001600160801b0385161580159061266c57506000846001600160801b0316115b6126885760405162461bcd60e51b81526004016107609061525c565b509193509193565b6000806000836001600160a01b03166392c088716040518163ffffffff1660e01b8152600401604080518083038186803b1580156126cd57600080fd5b505afa1580156126e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127059190614d6c565b9092509050600061271d62249f006108884386614449565b905060006009821115612739575067058d15e17628000061274b565b601582600a811061274657fe5b015490505b60006127574385614449565b90506064811115612766575060645b6000612772838361449e565b98975050505050505050565b61278661469d565b61278e6144d5565b6001600160a01b0383166000908152601f60205260409020548083106127c65760405162461bcd60e51b8152600401610760906151d8565b6001600160a01b0384166000908152601f602052604090208054849081106127ea57fe5b6000918252602091829020604080516101808101825260029390930290910180546001600160a01b0381168452600160a01b810463ffffffff90811695850195909552600160c01b8104851692840192909252600160e01b909104831660608301526001015460ff8082166080840152610100808304821660a0850152620100008304821660c08501526301000000830490911660e08401526401000000008204841690830152600160401b81048316610120830152600160601b8104909216610140820152600160801b9091046001600160801b03166101608201529150505b92915050565b6128d96144d5565b604051630d26201760e31b815273fe543efe9bb91b51a046157b73fdf0838833b8419063693100b890610f51906001908890889088908890600401615605565b60606129236144d5565b6040516306d8420960e21b815273265b6c10c606cd1c79545799ebe36bca9ce124a590631b6108249061295d906001908690600401615549565b60006040518083038186803b15801561297557600080fd5b505af4158015612989573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128cb9190810190614a92565b604051637b576fc960e01b815273265b6c10c606cd1c79545799ebe36bca9ce124a590637b576fc9906129eb906001908590600401615549565b60006040518083038186803b158015612a0357600080fd5b505af4158015612a17573d6000803e3d6000fd5b505050505b50565b612a27614701565b604051631182622760e21b815273265b6c10c606cd1c79545799ebe36bca9ce124a590634609889c90612a6390600190879087906004016155e6565b60e06040518083038186803b158015612a7b57600080fd5b505af4158015612a8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ab39190614c10565b9392505050565b6000808033321480612ad65750600a546001600160a01b031633145b80612aeb57506007546001600160a01b031633145b80612b0057506008546001600160a01b031633145b80612b1557506009546001600160a01b031633145b612b315760405162461bcd60e51b815260040161076090615313565b6001600160a01b0384166000908152601f6020526040812080549091612b5561469d565b82612b725760405162461bcd60e51b81526004016107609061525c565b600060015b848111612d8f578581860381548110612b8c57fe5b6000918252602091829020604080516101808101825260029390930290910180546001600160a01b0381168452600160a01b810463ffffffff90811695850195909552600160c01b8104851692840192909252600160e01b909104831660608301526001015460ff8082166080840152610100808304821660a0850152620100008304821660c08501526301000000830490911660e08401526401000000008204841690830152600160401b81048316610120830152600160601b8104909216610140820152600160801b9091046001600160801b0316610160820152925081158015612c99575043600160000160079054906101000a900460ff1660ff16846020015163ffffffff1601105b15612d0157606083015163ffffffff16935083612cb557612d87565b826020015163ffffffff169150612ce38361016001516001600160801b03168561449e90919063ffffffff16565b9750612cf784670de0b6b3a764000061449e565b9850819650612d87565b826020015163ffffffff16821415612d7057826060015163ffffffff169350612d4b612d448461016001516001600160801b03168661449e90919063ffffffff16565b8990614520565b9750612d69612d6285670de0b6b3a764000061449e565b8a90614520565b9850612d87565b826020015163ffffffff16821115612d8757612d8f565b600101612b77565b50600154600160381b900460ff1695909501948715801590612db15750600087115b612dcd5760405162461bcd60e51b81526004016107609061525c565b50505050509193909250565b6009546060906000906001600160a01b031633321480612e015750336001600160a01b038216145b612e1d5760405162461bcd60e51b815260040161076090615202565b6040516353b847a960e01b815273265b6c10c606cd1c79545799ebe36bca9ce124a5906353b847a990612e59906001908990899060040161565a565b60006040518083038186803b158015612e7157600080fd5b505af4158015612e85573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612ead9190810190614b31565b92509250509250929050565b600954600090819081906001600160a01b031633321480612ee25750336001600160a01b038216145b612efe5760405162461bcd60e51b815260040161076090615202565b612f06614651565b506001600160a01b03851660009081526020808052604091829020825161012081018452815463ffffffff808216835264010000000082048116948301859052600160401b8204811695830195909552600160601b810490941660608201526001600160801b03600160801b94859004811660808301526001830154600f81810b810b810b60a085015290869004810b810b900b60c083015260029092015480831660e08301529390930416610100830152612fd45760405162461bcd60e51b8152600401610760906150a0565b612ff9670de0b6b3a7640000826040015163ffffffff1661449e90919063ffffffff16565b945080608001516001600160801b03169350600160000160079054906101000a900460ff1660ff1681602001510163ffffffff16925060008511801561303f5750600084115b61305b5760405162461bcd60e51b81526004016107609061525c565b50509193909250565b600054600160481b900460ff16600114156130915760405162461bcd60e51b8152600401610760906152dc565b6000805460ff60481b1916600160481b1790556005546040516306e6a46960e21b81526001600160a01b0390911690631b9a91a490610a929033908590600401614ebf565b60005460ff16156130f95760405162461bcd60e51b815260040161076090615289565b6815af1d78b58c40000060005b600a8110156131395781600b82600a811061311d57fe5b015561312f606461088884605061449e565b9150600101613106565b50673782dace9d900000905060005b600a81101561317b5781601582600a811061315f57fe5b0155613171606461088884605061449e565b9150600101613148565b505060268054336001600160a01b03199182161790915560008054602780549093166001600160a01b03949094169390931790915568ffffffffffffffff00199091166101004367ffffffffffffffff16021760ff19166001179055565b6131e16144d5565b604051633ebf3e8560e21b815273fe543efe9bb91b51a046157b73fdf0838833b8419063fafcfa149061097390600190869086906004016155e6565b6132256144f6565b60005460ff1660021461324a5760405162461bcd60e51b815260040161076090615289565b6000805460ff19166003179055565b600054600160481b900460ff16600114156132865760405162461bcd60e51b8152600401610760906152dc565b6000805460ff60481b1916600160481b17905560055460405163a798e17d60e01b81526001600160a01b039091169063a798e17d906132cf903390879087908790600401614ed8565b600060405180830381600087803b1580156132e957600080fd5b505af11580156132fd573d6000803e3d6000fd5b50506000805460ff60481b191690555050505050565b61331b6144f6565b6133286020820182614e33565b6001805460ff191660ff9290921691909117905561334c6040820160208301614dbc565b6001805463ffffffff929092166101000264ffffffff001990921691909117905561337d6060820160408301614e33565b6001805460ff92909216600160281b0265ff0000000000199092169190911790556133ae6080820160608301614e33565b6001805460ff92909216600160301b0266ff000000000000199092169190911790556133e060a0820160808301614e33565b6001805460ff92909216600160381b0260ff60381b1990921691909117905561340f60c0820160a08301614e33565b6001805460ff92909216600160401b0260ff60401b1990921691909117905561343e60e0820160c08301614e33565b6001805460ff92909216600160481b0260ff60481b1990921691909117905561346e610100820160e08301614e33565b6001805460ff60501b1916600160501b60ff938416810291909117918290556040517fd52ea55597dda83c654fca3762be1b95778ce32b5d67b2ddc77f14e4c5f778ce936135039380821693610100820463ffffffff1693600160281b8304841693600160301b8404811693600160381b8104821693600160401b8204831693600160481b83048416939190920416906156ef565b60405180910390a150565b6135166144d5565b60015460ff16821461353a5760405162461bcd60e51b8152600401610760906150cd565b6000811161355a5760405162461bcd60e51b8152600401610760906150fa565b6005546040516372956b6960e01b81526001600160a01b039091169060009082906372956b699061358f908890600401614e7a565b60206040518083038186803b1580156135a757600080fd5b505afa1580156135bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135df9190614875565b90506001600160a01b0381161580159061360757506006546001600160a01b03828116911614155b80156136255750806001600160a01b0316856001600160a01b031614155b6136415760405162461bcd60e51b81526004016107609061522f565b6a0422ca8b0a00a425000000816001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561368657600080fd5b505afa15801561369a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136be9190614cf6565b106136db5760405162461bcd60e51b815260040161076090615154565b60015460009061370c906127109061088890670de0b6b3a7640000906112cd908a90600160301b900460ff1661449e565b9050600061371a3483614449565b1115613789576001600160a01b03831663ad9d4ba36137393484614449565b336040518363ffffffff1660e01b81526004016137569190614e7a565b6000604051808303818588803b15801561376f57600080fd5b505af1158015613783573d6000803e3d6000fd5b50505050505b600754600a546001600160a01b0391821691168163daa78c0f6137b2606461088887603c61449e565b866040518363ffffffff1660e01b81526004016137cf9190614e7a565b6000604051808303818588803b1580156137e857600080fd5b505af11580156137fc573d6000803e3d6000fd5b5050505050806001600160a01b031663daa78c0f613829606461088860148861449e90919063ffffffff16565b866040518363ffffffff1660e01b81526004016138469190614e7a565b6000604051808303818588803b15801561385f57600080fd5b505af1158015613873573d6000803e3d6000fd5b5050505050806001600160a01b031663daa78c0f6138a0606461088860148861449e90919063ffffffff16565b6006546040516001600160e01b031960e085901b1681526138cd916001600160a01b031690600401614e7a565b6000604051808303818588803b1580156138e657600080fd5b505af11580156138fa573d6000803e3d6000fd5b5050505050846001600160a01b031663610255023361392a670de0b6b3a76400008b61449e90919063ffffffff16565b8b6139358b8d61449e565b6040518563ffffffff1660e01b81526004016139549493929190614ed8565b600060405180830381600087803b15801561396e57600080fd5b505af1158015613982573d6000803e3d6000fd5b50506001546001600160a01b0388169250632dc8decd915033906139bf9063ffffffff610100909104811690683635c9adc5dea000009061449e16565b6040518363ffffffff1660e01b81526004016139dc929190614ebf565b600060405180830381600087803b1580156139f657600080fd5b505af1158015613a0a573d6000803e3d6000fd5b50505050505060006001601e016000886001600160a01b03166001600160a01b03168152602001908152602001600020905080604051806101800160405280336001600160a01b031681526020014363ffffffff1681526020018863ffffffff1681526020018863ffffffff168152602001600060ff168152602001600360ff168152602001600160ff168152602001600060ff1681526020018863ffffffff1681526020018863ffffffff168152602001600160000160019054906101000a900463ffffffff1663ffffffff168152602001876001600160801b0316815250908060018154018082558091505060019003906000526020600020906002020160009091909190915060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160006101000a81548160ff021916908360ff16021790555060a08201518160010160016101000a81548160ff021916908360ff16021790555060c08201518160010160026101000a81548160ff021916908360ff16021790555060e08201518160010160036101000a81548160ff021916908360ff1602179055506101008201518160010160046101000a81548163ffffffff021916908363ffffffff1602179055506101208201518160010160086101000a81548163ffffffff021916908363ffffffff16021790555061014082015181600101600c6101000a81548163ffffffff021916908363ffffffff1602179055506101608201518160010160106101000a8154816001600160801b0302191690836001600160801b0316021790555050507fee7aa1809348e0f32177d04baf37df86a10ef3337729271eeff50db46e19919033886001848054905003613d27670de0b6b3a76400008b61449e90919063ffffffff16565b613d318a8c61449e565b604051613d42959493929190614e8e565b60405180910390a1506001600160a01b0386166000908152602160209081526040808320438452909152902054608081901c6001600160801b03821681613ff1576000613d8e86612690565b90506000866001600160a01b03166328e6a33f6040518163ffffffff1660e01b815260040160206040518083038186803b158015613dcb57600080fd5b505afa158015613ddf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e039190614875565b6005549091506001600160a01b0380831691161415613e8a576005546040516394bf804d60e01b815292945084926001600160a01b03808a16926394bf804d92613e539287921690600401615549565b600060405180830381600087803b158015613e6d57600080fd5b505af1158015613e81573d6000803e3d6000fd5b50505050613fee565b613e9a606461088884605f61449e565b6040516381fa543160e01b81529094506001600160a01b038816906381fa543190613ec99085906004016156ad565b600060405180830381600087803b158015613ee357600080fd5b505af1158015613ef7573d6000803e3d6000fd5b505060055460405163a9059cbb60e01b81526001600160a01b03808c16945063a9059cbb9350613f2d9216908690600401614ebf565b602060405180830381600087803b158015613f4757600080fd5b505af1158015613f5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f7f9190614bd4565b506005546001600160a01b03166361bced9d8289613f9d8689614449565b6040518463ffffffff1660e01b8152600401613fbb93929190614f02565b600060405180830381600087803b158015613fd557600080fd5b505af1158015613fe9573d6000803e3d6000fd5b505050505b50505b613ffb8189614520565b6001600160a01b038a16600090815260216020908152604080832043845290915290819020600160801b9094029091019092555051637b576fc960e01b815273265b6c10c606cd1c79545799ebe36bca9ce124a59150637b576fc990612464906001908a90600401615549565b6140706144d5565b604051638f2daafb60e01b815273fe543efe9bb91b51a046157b73fdf0838833b84190638f2daafb9061097390600190869086906004016155e6565b6140b46144f6565b60005460ff166002146140d95760405162461bcd60e51b815260040161076090615289565b60018054600160781b600160f81b031916600160781b6001600160801b0394851602179055600280546001600160801b03191691909216179055565b600954600090819081906001600160a01b03163332148061413e5750336001600160a01b038216145b61415a5760405162461bcd60e51b815260040161076090615202565b604051630da947f160e21b815273265b6c10c606cd1c79545799ebe36bca9ce124a5906336a51fc490614196906001908a908a90600401615631565b60606040518083038186803b1580156141ae57600080fd5b505af41580156141c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141e69190614d8f565b9195509350915083158015906141fc5750600083115b6142185760405162461bcd60e51b81526004016107609061525c565b509250925092565b6142286144f6565b60005460ff1660011461424d5760405162461bcd60e51b815260040161076090615289565b61425a6020820182614e33565b6001805460ff191660ff9290921691909117905561427e6040820160208301614dbc565b6001805463ffffffff929092166101000264ffffffff00199092169190911790556142af6060820160408301614e33565b6001805460ff92909216600160281b0265ff0000000000199092169190911790556142e06080820160608301614e33565b6001805460ff92909216600160301b0266ff0000000000001990921691909117905561431260a0820160808301614e33565b6001805460ff92909216600160381b0260ff60381b1990921691909117905561434160c0820160a08301614e33565b6001805460ff92909216600160401b0260ff60401b1990921691909117905561437060e0820160c08301614e33565b6001805460ff92909216600160481b0260ff60481b199092169190911790556143a0610100820160e08301614e33565b60018054600280546001600160801b0319166001600160801b0396871617815560ff60501b19909116600160501b60ff949094169390930292909217600160781b600160f81b031916600160781b95909416949094029290921763ffffffff60581b1916600160581b63ffffffff9590951694909402939093179091556000805468ffffffffffffffff0019166101004367ffffffffffffffff16021760ff1916909117905550565b808203828111156128cb5760405162461bcd60e51b815260040161076090615071565b600080821161448d5760405162461bcd60e51b8152600401610760906152b2565b81838161449657fe5b049392505050565b60008115806144b9575050808202828282816144b657fe5b04145b6128cb5760405162461bcd60e51b815260040161076090615126565b3332146144f45760405162461bcd60e51b815260040161076090615202565b565b6026546001600160a01b031633146144f45760405162461bcd60e51b81526004016107609061533c565b808201828110156128cb5760405162461bcd60e51b81526004016107609061517f565b6000600f82900b6f7fffffffffffffffffffffffffffffff19141561456757600080fd5b600082600f0b1261457857816128cb565b5060000390565b60008082600f0b121561459157600080fd5b6128cb604083600f0b901b600160401b6000826145b0575060006128cb565b600082116145bd57600080fd5b60008284816145c857fe5b049050808314806145db57508083600101145b156145e957829150506128cb565b806001018314156145fb5790506128cb565b6001818401600101901c9250506145bd565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915290565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b6000610100828403121561474f578081fd5b50919050565b6000610140808385031215614768578182fd5b61477181615739565b91505061477e838361482d565b815261478d8360208401614843565b602082015261479f8360408401614843565b60408201526147b18360608401614843565b60608201526147c3836080840161484e565b60808201526147d58360a0840161484e565b60a08201526147e78360c0840161484e565b60c082015260e082015160e082015261010061480584828501614843565b9082015261012061481884848301614822565b9082015292915050565b80516128cb81615795565b80516128cb81615780565b80356128cb816157aa565b80516128cb816157aa565b80516128cb816157bc565b60006020828403121561486a578081fd5b8135612ab381615780565b600060208284031215614886578081fd5b8151612ab381615780565b600080600080608085870312156148a6578283fd5b84356148b181615780565b935060208501356148c181615780565b93969395505050506040820135916060013590565b600080604083850312156148e8578182fd5b82356148f381615780565b915060208381013567ffffffffffffffff81111561490f578283fd5b8401601f8101861361491f578283fd5b803561493261492d82615760565b615739565b81815283810190838501858402850186018a101561494e578687fd5b8694505b83851015614978576149648a82614838565b835260019490940193918501918501614952565b5080955050505050509250929050565b6000806040838503121561499a578182fd5b82356149a581615780565b946020939093013593505050565b6000806000606084860312156149c7578081fd5b83356149d281615780565b95602085013595506040909401359392505050565b600080600080608085870312156149fc578182fd5b8435614a0781615780565b966020860135965060408601359560600135945092505050565b60008060408385031215614a33578182fd5b8235614a3e81615780565b9150602083013567ffffffffffffffff81168114614a5a578182fd5b809150509250929050565b60008060408385031215614a77578182fd5b8235614a8281615780565b91506020830135614a5a816157bc565b60006020808385031215614aa4578182fd5b825167ffffffffffffffff811115614aba578283fd5b8301601f81018513614aca578283fd5b8051614ad861492d82615760565b81815283810190838501610140808502860187018a1015614af7578788fd5b8795505b84861015614b2357614b0d8a83614755565b8452600195909501949286019290810190614afb565b509098975050505050505050565b60008060408385031215614b43578182fd5b825167ffffffffffffffff811115614b59578283fd5b8301601f81018513614b69578283fd5b8051614b7761492d82615760565b808282526020808301925080850189828387028801011115614b97578788fd5b8795505b84861015614bc2578051614bae81615795565b845260019590950194928101928101614b9b565b50969096015195979596505050505050565b600060208284031215614be5578081fd5b81518015158114612ab3578182fd5b60006101008284031215614c06578081fd5b612ab3838361473d565b600060e08284031215614c21578081fd5b614c2b60e0615739565b8251614c3681615780565b81526020830151614c46816157aa565b60208201526040830151614c59816157aa565b60408201526060830151614c6c816157bc565b60608201526080830151614c7f816157bc565b608082015260a0830151614c92816157aa565b60a082015260c0830151614ca5816157aa565b60c08201529392505050565b60008060408385031215614cc3578182fd5b8235614cce81615795565b91506020830135614a5a81615795565b600060208284031215614cef578081fd5b5035919050565b600060208284031215614d07578081fd5b5051919050565b600080600060608486031215614d22578081fd5b833592506020840135614d3481615780565b929592945050506040919091013590565b60008060008060808587031215614d5a578182fd5b8435935060208501356148c181615780565b60008060408385031215614d7e578182fd5b505080516020909101519092909150565b600080600060608486031215614da3578081fd5b8351925060208401519150604084015190509250925092565b600060208284031215614dcd578081fd5b8135612ab3816157aa565b6000806000806101608587031215614dee578182fd5b8435614df9816157aa565b93506020850135614e0981615795565b92506040850135614e1981615795565b9150614e28866060870161473d565b905092959194509250565b600060208284031215614e44578081fd5b8135612ab3816157bc565b6001600160801b03169052565b6001600160a01b03169052565b63ffffffff169052565b60ff169052565b6001600160a01b0391909116815260200190565b6001600160a01b03958616815293909416602084015260408301919091526060820152608081019190915260a00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039485168152602081019390935292166040820152606081019190915260800190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b602080825282518282018190526000919060409081850190868401855b82811015615013578151614f58858251614e5c565b86810151614f6888870182614e69565b5085810151614f7987870182614e69565b50606080820151614f8c82880182614e69565b5050608080820151614fa082880182614e73565b505060a080820151614fb482880182614e73565b505060c080820151614fc882880182614e73565b505060e0818101519086015261010080820151614fe782880182614e69565b50506101209081015190614ffd86820183614e4f565b5050610140939093019290850190600101614f43565b5091979650505050505050565b604080825283519082018190526000906020906060840190828701845b828110156150625781516001600160801b03168452928401929084019060010161503d565b50505092019290925292915050565b60208082526015908201527464732d6d6174682d7375622d756e646572666c6f7760581b604082015260600190565b6020808252601390820152724e6573743a4d696e653a4e4f2870726963652960681b604082015260600190565b6020808252601390820152724e6573743a4d696e653a21286574684e756d2960681b604082015260600190565b6020808252601290820152714e6573743a4d696e653a212870726963652960701b604082015260600190565b60208082526014908201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604082015260600190565b6020808252601190820152702732b9ba1d26b4b7329d10b73a37b5b2b760791b604082015260600190565b60208082526014908201527364732d6d6174682d6164642d6f766572666c6f7760601b604082015260600190565b6020808252601190820152702732b9ba1d26b4b7329d10b9b2b73232b960791b604082015260600190565b60208082526010908201526f4e6573743a4d696e653a3e286c656e2960801b604082015260600190565b6020808252601390820152724e6573743a4d696e653a636f6e74726163742160681b604082015260600190565b6020808252601390820152724e6573743a4d696e653a21286e746f6b656e2960681b604082015260600190565b6020808252601390820152724e6573743a4d696e653a6e6f2870726963652960681b604082015260600190565b6020808252600f908201526e4e6573743a4d696e653a21666c616760881b604082015260600190565b60208082526010908201526f64732d6d6174682d6469762d7a65726f60801b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6020808252600f908201526e09ccae6e8749ad2dcca744282eae8d608b1b604082015260600190565b6020808252600e908201526d2732b9ba1d26b4b7329d10a3a7ab60911b604082015260600190565b60006101008201905060ff835116825263ffffffff602084015116602083015260ff604084015116604083015260ff606084015116606083015260ff608084015116608083015260a08301516153bd60a0840182614e73565b5060c08301516153d060c0840182614e73565b5060e08301516153e360e0840182614e73565b5092915050565b600060e08201905060018060a01b038351168252602083015163ffffffff808216602085015280604086015116604085015260ff606086015116606085015260ff60808601511660808501528060a08601511660a08501528060c08601511660c0850152505092915050565b60006101808201905061546a828451614e5c565b602083015161547c6020840182614e69565b50604083015161548f6040840182614e69565b5060608301516154a26060840182614e69565b5060808301516154b56080840182614e73565b5060a08301516154c860a0840182614e73565b5060c08301516154db60c0840182614e73565b5060e08301516154ee60e0840182614e73565b506101008084015161550282850182614e69565b50506101208084015161551782850182614e69565b50506101408084015161552c82850182614e69565b50506101608084015161554182850182614e4f565b505092915050565b9182526001600160a01b0316602082015260400190565b9485526001600160a01b0393841660208601529190921660408401526060830191909152608082015260a00190565b8381526001600160a01b0383166020808301919091526060604083018190528351908301819052600091848101916080850190845b81811015614b2357845163ffffffff16835293830193918301916001016155c4565b9283526001600160a01b03919091166020830152604082015260600190565b9485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b9283526001600160a01b0391909116602083015267ffffffffffffffff16604082015260600190565b9283526001600160a01b0391909116602083015260ff16604082015260600190565b6001600160801b039485168152929093166020830152600f0b604082015263ffffffff909116606082015260800190565b90815260200190565b9283526020830191909152604082015260600190565b67ffffffffffffffff91909116815260200190565b60ff91909116815260200190565b60ff988916815263ffffffff979097166020880152948716604087015292861660608601529085166080850152841660a0840152831660c083015290911660e08201526101000190565b60405181810167ffffffffffffffff8111828210171561575857600080fd5b604052919050565b600067ffffffffffffffff821115615776578081fd5b5060209081020190565b6001600160a01b0381168114612a1c57600080fd5b6001600160801b0381168114612a1c57600080fd5b63ffffffff81168114612a1c57600080fd5b60ff81168114612a1c57600080fdfea2646970667358221220d93eef17cc519ed96e943ab106845bf42eba3c315bd881f3d3980f522e5e09e864736f6c634300060c0033

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

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.