ETH Price: $2,629.19 (+3.76%)

Transaction Decoder

Block:
12244820 at Apr-15-2021 01:06:19 PM +UTC
Transaction Fee:
0.0286128612 ETH $75.23
Gas Used:
401,415 Gas / 71.28 Gwei

Emitted Events:

154 AdminUpgradeabilityProxy.0xee7aa1809348e0f32177d04baf37df86a10ef3337729271eeff50db46e199190( 0xee7aa1809348e0f32177d04baf37df86a10ef3337729271eeff50db46e199190, 000000000000000000000000bfb8d1109afc5064fab57805177f8655c388ef93, 000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7, 0000000000000000000000000000000000000000000000000000000000002d7b, 000000000000000000000000000000000000000000000001a055690d9db80000, 000000000000000000000000000000000000000000000000000000110b78a520 )
155 AdminUpgradeabilityProxy.0xee7aa1809348e0f32177d04baf37df86a10ef3337729271eeff50db46e199190( 0xee7aa1809348e0f32177d04baf37df86a10ef3337729271eeff50db46e199190, 000000000000000000000000bfb8d1109afc5064fab57805177f8655c388ef93, 00000000000000000000000004abeda201850ac0124161f037efd70c74ddc74c, 0000000000000000000000000000000000000000000000000000000000002e19, 000000000000000000000000000000000000000000000001a055690d9db80000, 000000000000000000000000000000000000000000012106239ff6db82fe6240 )
156 NNRewardPool.NNRewardAdded( reward=1420800000000000000000, allRewards=21398923776000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x105ee568...387dfFB4f 179.102896402874595432 Eth179.122696402874595432 Eth0.0198
0x243f207F...35aa7b8f6
(NEST Protocol: Nest Mining V1 Proxy)
(F2Pool Old)
2,823.060637086919751878 Eth2,823.089249948119751878 Eth0.0286128612
0xaA7A74a4...6a8aa84eC 312.919468651936202792 Eth312.998668651936202792 Eth0.0792
0xBfB8D110...5C388EF93
162.73982733524743304 Eth
Nonce: 5870
162.61221447404743304 Eth
Nonce: 5871
0.1276128612
0xCA208DCf...2222C8c8F
0xf1A72017...6bfECE757

Execution Trace

ETH 0.099 AdminUpgradeabilityProxy.8e1e280c( )
  • ETH 0.099 NestMiningV1.post2( token=0xdAC17F958D2ee523a2206206994597C13D831ec7, ethNum=30, tokenAmountPerEth=2440230000, ntokenAmountPerEth=45495905368516833484000 )
    • NestPool.getNTokenFromToken( token=0xdAC17F958D2ee523a2206206994597C13D831ec7 ) => ( 0x04abEdA201850aC0124161F037Efd70c74ddC74C )
    • ETH 0.0792 AdminUpgradeabilityProxy.daa78c0f( )
      • ETH 0.0792 NestStaking.addETHReward( ntoken=0x04abEdA201850aC0124161F037Efd70c74ddC74C )
      • ETH 0.0198 AdminUpgradeabilityProxy.daa78c0f( )
        • ETH 0.0198 NestDAO.addETHReward( ntoken=0x04abEdA201850aC0124161F037Efd70c74ddC74C )
        • NestPool.freezeEthAndToken( miner=0xBfB8D1109afc5064fab57805177f8655C388EF93, ethAmount=30000000000000000000, token=0xdAC17F958D2ee523a2206206994597C13D831ec7, tokenAmount=73206900000 )
        • NestPool.freezeEthAndToken( miner=0xBfB8D1109afc5064fab57805177f8655C388EF93, ethAmount=30000000000000000000, token=0x04abEdA201850aC0124161F037Efd70c74ddC74C, tokenAmount=1364877161055505004520000 )
        • NestPool.freezeNest( miner=0xBfB8D1109afc5064fab57805177f8655C388EF93, nestAmount=200000000000000000000000 )
        • NestPool.addNest( miner=0xf1A7201749fA81463799383D7D0565B6bfECE757, amount=1420800000000000000000 )
        • NNRewardPool.addNNReward( _amount=1420800000000000000000 )
        • NestPool.addNest( miner=0x105ee568DaB631b8ff84f328Bc48e95387dfFB4f, amount=473600000000000000000 )
        • AdminUpgradeabilityProxy.0c202bf7( )
        • ETH 0.099 MiningV1Calc.7b576fc9( )
        • ETH 0.099 MiningV1Calc.7b576fc9( )
          post2[NestMiningV1 (ln:332)]
          File 1 of 9: AdminUpgradeabilityProxy
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.6.0;
          import './UpgradeabilityProxy.sol';
          /**
           * @title AdminUpgradeabilityProxy
           * @dev This contract combines an upgradeability proxy with an authorization
           * mechanism for administrative tasks.
           * All external functions in this contract must be guarded by the
           * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity
           * feature proposal that would enable this to be done automatically.
           */
          contract AdminUpgradeabilityProxy is UpgradeabilityProxy {
            /**
             * Contract constructor.
             * @param _logic address of the initial implementation.
             * @param _admin Address of the proxy administrator.
             * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
             * It should include the signature and the parameters of the function to be called, as described in
             * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
             * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
             */
            constructor(address _logic, address _admin, bytes memory _data) UpgradeabilityProxy(_logic, _data) public payable {
              assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1));
              _setAdmin(_admin);
            }
            /**
             * @dev Emitted when the administration has been transferred.
             * @param previousAdmin Address of the previous admin.
             * @param newAdmin Address of the new admin.
             */
            event AdminChanged(address previousAdmin, address newAdmin);
            /**
             * @dev Storage slot with the admin of the contract.
             * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
             * validated in the constructor.
             */
            bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
            /**
             * @dev Modifier to check whether the `msg.sender` is the admin.
             * If it is, it will run the function. Otherwise, it will delegate the call
             * to the implementation.
             */
            modifier ifAdmin() {
              if (msg.sender == _admin()) {
                _;
              } else {
                _fallback();
              }
            }
            /**
             * @return The address of the proxy admin.
             */
            function admin() external ifAdmin returns (address) {
              return _admin();
            }
            /**
             * @return The address of the implementation.
             */
            function implementation() external ifAdmin returns (address) {
              return _implementation();
            }
            /**
             * @dev Changes the admin of the proxy.
             * Only the current admin can call this function.
             * @param newAdmin Address to transfer proxy administration to.
             */
            function changeAdmin(address newAdmin) external ifAdmin {
              require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address");
              emit AdminChanged(_admin(), newAdmin);
              _setAdmin(newAdmin);
            }
            /**
             * @dev Upgrade the backing implementation of the proxy.
             * Only the admin can call this function.
             * @param newImplementation Address of the new implementation.
             */
            function upgradeTo(address newImplementation) external ifAdmin {
              _upgradeTo(newImplementation);
            }
            /**
             * @dev Upgrade the backing implementation of the proxy and call a function
             * on the new implementation.
             * This is useful to initialize the proxied contract.
             * @param newImplementation Address of the new implementation.
             * @param data Data to send as msg.data in the low level call.
             * It should include the signature and the parameters of the function to be called, as described in
             * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
             */
            function upgradeToAndCall(address newImplementation, bytes calldata data) payable external ifAdmin {
              _upgradeTo(newImplementation);
              (bool success,) = newImplementation.delegatecall(data);
              require(success);
            }
            /**
             * @return adm The admin slot.
             */
            function _admin() internal view returns (address adm) {
              bytes32 slot = ADMIN_SLOT;
              assembly {
                adm := sload(slot)
              }
            }
            /**
             * @dev Sets the address of the proxy admin.
             * @param newAdmin Address of the new proxy admin.
             */
            function _setAdmin(address newAdmin) internal {
              bytes32 slot = ADMIN_SLOT;
              assembly {
                sstore(slot, newAdmin)
              }
            }
            /**
             * @dev Only fall back when the sender is not the admin.
             */
            function _willFallback() internal override virtual {
              require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin");
              super._willFallback();
            }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.6.0;
          import './Proxy.sol';
          import '@openzeppelin/contracts/utils/Address.sol';
          /**
           * @title UpgradeabilityProxy
           * @dev This contract implements a proxy that allows to change the
           * implementation address to which it will delegate.
           * Such a change is called an implementation upgrade.
           */
          contract UpgradeabilityProxy is Proxy {
            /**
             * @dev Contract constructor.
             * @param _logic Address of the initial implementation.
             * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
             * It should include the signature and the parameters of the function to be called, as described in
             * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
             * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
             */
            constructor(address _logic, bytes memory _data) public payable {
              assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1));
              _setImplementation(_logic);
              if(_data.length > 0) {
                (bool success,) = _logic.delegatecall(_data);
                require(success);
              }
            }  
            /**
             * @dev Emitted when the implementation is upgraded.
             * @param implementation Address of the new implementation.
             */
            event Upgraded(address indexed implementation);
            /**
             * @dev Storage slot with the address of the current implementation.
             * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
             * validated in the constructor.
             */
            bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
            /**
             * @dev Returns the current implementation.
             * @return impl Address of the current implementation
             */
            function _implementation() internal override view returns (address impl) {
              bytes32 slot = IMPLEMENTATION_SLOT;
              assembly {
                impl := sload(slot)
              }
            }
            /**
             * @dev Upgrades the proxy to a new implementation.
             * @param newImplementation Address of the new implementation.
             */
            function _upgradeTo(address newImplementation) internal {
              _setImplementation(newImplementation);
              emit Upgraded(newImplementation);
            }
            /**
             * @dev Sets the implementation address of the proxy.
             * @param newImplementation Address of the new implementation.
             */
            function _setImplementation(address newImplementation) internal {
              require(Address.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address");
              bytes32 slot = IMPLEMENTATION_SLOT;
              assembly {
                sstore(slot, newImplementation)
              }
            }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.6.0;
          /**
           * @title Proxy
           * @dev Implements delegation of calls to other contracts, with proper
           * forwarding of return values and bubbling of failures.
           * It defines a fallback function that delegates all calls to the address
           * returned by the abstract _implementation() internal function.
           */
          abstract contract Proxy {
            /**
             * @dev Fallback function.
             * Implemented entirely in `_fallback`.
             */
            fallback () payable external {
              _fallback();
            }
            /**
             * @dev Receive function.
             * Implemented entirely in `_fallback`.
             */
            receive () payable external {
              _fallback();
            }
            /**
             * @return The Address of the implementation.
             */
            function _implementation() internal virtual view returns (address);
            /**
             * @dev Delegates execution to an implementation contract.
             * This is a low level function that doesn't return to its internal call site.
             * It will return to the external caller whatever the implementation returns.
             * @param implementation Address to delegate.
             */
            function _delegate(address implementation) internal {
              assembly {
                // Copy msg.data. We take full control of memory in this inline assembly
                // block because it will not return to Solidity code. We overwrite the
                // Solidity scratch pad at memory position 0.
                calldatacopy(0, 0, calldatasize())
                // Call the implementation.
                // out and outsize are 0 because we don't know the size yet.
                let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                // Copy the returned data.
                returndatacopy(0, 0, returndatasize())
                switch result
                // delegatecall returns 0 on error.
                case 0 { revert(0, returndatasize()) }
                default { return(0, returndatasize()) }
              }
            }
            /**
             * @dev Function that is run as the first thing in the fallback function.
             * Can be redefined in derived contracts to add functionality.
             * Redefinitions must call super._willFallback().
             */
            function _willFallback() internal virtual {
            }
            /**
             * @dev fallback implementation.
             * Extracted to enable manual triggering.
             */
            function _fallback() internal {
              _willFallback();
              _delegate(_implementation());
            }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.2 <0.8.0;
          /**
           * @dev Collection of functions related to the address type
           */
          library Address {
              /**
               * @dev Returns true if `account` is a contract.
               *
               * [IMPORTANT]
               * ====
               * It is unsafe to assume that an address for which this function returns
               * false is an externally-owned account (EOA) and not a contract.
               *
               * Among others, `isContract` will return false for the following
               * types of addresses:
               *
               *  - an externally-owned account
               *  - a contract in construction
               *  - an address where a contract will be created
               *  - an address where a contract lived, but was destroyed
               * ====
               */
              function isContract(address account) internal view returns (bool) {
                  // This method relies on extcodesize, which returns 0 for contracts in
                  // construction, since the code is only stored at the end of the
                  // constructor execution.
                  uint256 size;
                  // solhint-disable-next-line no-inline-assembly
                  assembly { size := extcodesize(account) }
                  return size > 0;
              }
              /**
               * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
               * `recipient`, forwarding all available gas and reverting on errors.
               *
               * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
               * of certain opcodes, possibly making contracts go over the 2300 gas limit
               * imposed by `transfer`, making them unable to receive funds via
               * `transfer`. {sendValue} removes this limitation.
               *
               * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
               *
               * IMPORTANT: because control is transferred to `recipient`, care must be
               * taken to not create reentrancy vulnerabilities. Consider using
               * {ReentrancyGuard} or the
               * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
               */
              function sendValue(address payable recipient, uint256 amount) internal {
                  require(address(this).balance >= amount, "Address: insufficient balance");
                  // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                  (bool success, ) = recipient.call{ value: amount }("");
                  require(success, "Address: unable to send value, recipient may have reverted");
              }
              /**
               * @dev Performs a Solidity function call using a low level `call`. A
               * plain`call` is an unsafe replacement for a function call: use this
               * function instead.
               *
               * If `target` reverts with a revert reason, it is bubbled up by this
               * function (like regular Solidity function calls).
               *
               * Returns the raw returned data. To convert to the expected return value,
               * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
               *
               * Requirements:
               *
               * - `target` must be a contract.
               * - calling `target` with `data` must not revert.
               *
               * _Available since v3.1._
               */
              function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                return functionCall(target, data, "Address: low-level call failed");
              }
              /**
               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
               * `errorMessage` as a fallback revert reason when `target` reverts.
               *
               * _Available since v3.1._
               */
              function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                  return functionCallWithValue(target, data, 0, errorMessage);
              }
              /**
               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
               * but also transferring `value` wei to `target`.
               *
               * Requirements:
               *
               * - the calling contract must have an ETH balance of at least `value`.
               * - the called Solidity function must be `payable`.
               *
               * _Available since v3.1._
               */
              function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                  return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
              }
              /**
               * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
               * with `errorMessage` as a fallback revert reason when `target` reverts.
               *
               * _Available since v3.1._
               */
              function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                  require(address(this).balance >= value, "Address: insufficient balance for call");
                  require(isContract(target), "Address: call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.call{ value: value }(data);
                  return _verifyCallResult(success, returndata, errorMessage);
              }
              /**
               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
               * but performing a static call.
               *
               * _Available since v3.3._
               */
              function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                  return functionStaticCall(target, data, "Address: low-level static call failed");
              }
              /**
               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
               * but performing a static call.
               *
               * _Available since v3.3._
               */
              function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                  require(isContract(target), "Address: static call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.staticcall(data);
                  return _verifyCallResult(success, returndata, errorMessage);
              }
              function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                  if (success) {
                      return returndata;
                  } else {
                      // Look for revert reason and bubble it up if present
                      if (returndata.length > 0) {
                          // The easiest way to bubble the revert reason is using memory via assembly
                          // solhint-disable-next-line no-inline-assembly
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert(errorMessage);
                      }
                  }
              }
          }
          

          File 2 of 9: NNRewardPool
          // SPDX-License-Identifier: GPL-3.0-or-later
          pragma solidity ^0.6.12;
          import "./lib/SafeMath.sol";
          import "./iface/INestPool.sol";
          import "./lib/SafeERC20.sol";
          import './lib/TransferHelper.sol';
          import "./iface/INestMining.sol";
          import "./iface/INNRewardPool.sol";
          /// @title NNRewardPool
          /// @author Inf Loop - <[email protected]>
          /// @author Paradox  - <[email protected]>
          /// @notice The NNRewardPool contract distributes the mining rewards,
          ///     15% share of the amount of nest-token produced by miners
          /// @dev The nest-tokens are put in NestPool. This contract only traces 
          ///     the sum-amount of all of the rewards (nest-token)
          ///   - NNToken is pre-deployed in Nest v3.0, so we should connect (legacy)
          ///       with NNRewardPool. Whenever a NN holder transfers NN token to another,
          ///       NNToken will call back NNRewardPool.nodeCount() to settle rewards (decisively)
          ///       for both sender and receiver.
          ///   - After upgrading, NNRewardPool will count rewards from zero. Any NN holder should
          ///       claim rewards that had been issued before upgrading from the old contract. Old
          ///       data about NN rewards will be dropped in this contract, while it can also accessible
          ///       through OLD (Nest v3.0) contracts.
          contract NNRewardPool is INNRewardPool {
              using SafeMath for uint256;
              /* ========== STATE ============== */
              uint8   public flag;     // | 1: active 
                                      // | 0: uninitialized
                                      // | 2: shutdown
              uint8   constant NNREWARD_FLAG_UNINITIALIZED    = 0;
              uint8   constant NNREWARD_FLAG_ACTIVE           = 1;
              uint8   constant NNREWARD_FLAG_PAUSED           = 2;
              uint256 public rewardSum;
              uint256 public totalSupplyNN;
              /// @dev From nest-node address to checkpoints of reward-sum
              mapping(address => uint256) public rewardSumCheckpoint;
              /* ========== ADDRESSES ============== */
              address public C_NNToken;
              address public C_NestToken;
              address public C_NestPool;
              address public C_NestMining;
              address public governance;
              /* ========== CONSTRUCTOR ========== */
              /// @notice Constructor of NNRewardPool contract
              /// @dev The NNToken contract was created on the Ethereum mainnet 
              /// @param NestPool The address of NestPool Contract
              /// @param NNToken The address of NestNode Token Contract
              constructor(address NestPool, address NNToken) public
              {
                  C_NestPool = NestPool;
                  C_NNToken = NNToken;
                  totalSupplyNN = uint128(ERC20(C_NNToken).totalSupply());
                  governance = msg.sender;
                  flag = NNREWARD_FLAG_UNINITIALIZED;
              }
              function start() external onlyGovernance
              {
                  require(flag == NNREWARD_FLAG_UNINITIALIZED, "Nest:NTC:!flag");
                  flag = NNREWARD_FLAG_ACTIVE;
              }
              /* ========== MODIFIERS ========== */
              modifier onlyBy(address _account)
              {
                  require(msg.sender == _account, "Nest:NN:!Auth");
                  _;
              }
              modifier noContract() 
              {
                  require(address(msg.sender) == address(tx.origin), "Nest:NN:BAN(contract)");
                  _;
              }
              modifier onlyGovernance() 
              {
                  require(msg.sender == governance, "Nest:NN:!governance");
                  _;
              }
              modifier onlyGovOrBy(address _account)
              {
                  if (msg.sender != governance) { 
                      require(msg.sender == _account,
                          "Nest:NN:!Auth");
                  }
                  _;
              }
              /* ========== GOVERNANCE ========== */
              /// @dev To ensure that all of governance-addresses be consistent, every contract
              ///        besides NestPool must load newest `governance` from NestPool.
              function loadGovernance() override external 
              { 
                  governance = INestPool(C_NestPool).governance();
              }
              /// @dev The function loads all nest-contracts, it is supposed to be called by NestPool
              function loadContracts() override external onlyGovOrBy(C_NestPool)
              {
                  C_NestToken = INestPool(C_NestPool).addrOfNestToken();
                  C_NNToken = INestPool(C_NestPool).addrOfNNToken();
                  C_NestMining = INestPool(C_NestPool).addrOfNestMining();    
              }
              /// @dev Stop service for emergency
              function pause() external onlyGovernance
              {
                  require(flag == NNREWARD_FLAG_ACTIVE, "Nest:NN:!flag");
                  flag = NNREWARD_FLAG_PAUSED;
                  emit FlagSet(address(msg.sender), uint256(NNREWARD_FLAG_PAUSED));
              }
              /// @dev Resume service 
              function resume() external onlyGovernance
              {
                  require(flag == NNREWARD_FLAG_PAUSED, "Nest:NN:!flag");
                  flag = NNREWARD_FLAG_ACTIVE;
                  emit FlagSet(address(msg.sender), uint256(NNREWARD_FLAG_ACTIVE));
              }
              /* ========== ADDING REWARDS ========== */
              /// @notice Add rewards for Nest-Nodes, only 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) override external onlyBy(C_NestMining)
              {
                  if (_amount > 0) {
                      uint256 _newSum = uint256(rewardSum).add(_amount);
                      rewardSum = uint128(_newSum);
                      emit NNRewardAdded(_amount, _newSum);
                  }
                  return;
              }
              // /// @dev The updator is to update the sum of NEST tokens mined in NestMining
              // function updateNNReward() external
              // {
              //     require(flag == NNREWARD_FLAG_ACTIVE, "Nest:NN:!flag");
              //     uint256 _allMined = INestMining(C_NestMining).minedNestAmount();
              //     if (_allMined > rewardSum) {
              //         uint256 _amount = _allMined.mul(NN_REWARD_PERCENTAGE).div(100).sub(rewardSum);
              //         uint256 _newSum = uint256(rewardSum).add(_amount);
              //         rewardSum = uint128(_newSum);
              //         emit NNRewardAdded(_amount, _newSum);
              //     }
              // }
              // modifier updateNNReward1()
              // {
              //     require(flag == NNREWARD_FLAG_ACTIVE, "Nest:NN:!flag");
              //     uint256 _allMined = INestMining(C_NestMining).minedNestAmount();
              //     if (_allMined > rewardSum) {
              //         uint256 _amount = _allMined.mul(NN_REWARD_PERCENTAGE).div(100).sub(rewardSum);
              //         uint256 _newSum = uint256(rewardSum).add(_amount);
              //         rewardSum = uint128(_newSum);
              //         emit NNRewardAdded(_amount, _newSum);
              //     }
              //    _;
              // }
              /* ========== CLAIM/SETTLEMENT ========== */
              /// @notice Claim rewards by Nest-Nodes
              /// @dev The rewards need to pull from NestPool
              function claimNNReward() override external noContract 
              {
                  require(flag == NNREWARD_FLAG_ACTIVE, "Nest:NN:!flag");
                  uint256 blnc =  ERC20(C_NNToken).balanceOf(address(msg.sender));
                  require(blnc > 0, "Nest:NN:!(NNToken)");
                  uint256 total = totalSupplyNN;
                  uint256 sum = rewardSum;
                  uint256 reward = sum.sub(rewardSumCheckpoint[address(msg.sender)]);
                  uint256 share = reward.mul(blnc).div(total);
                  rewardSumCheckpoint[address(msg.sender)] = sum;
                  emit NNRewardClaimed(address(msg.sender), share);
               
                  INestPool(C_NestPool).withdrawNest(address(this), share);
                  require(ERC20(C_NestToken).transfer(address(msg.sender), share), "Nest:NN:!TRANS");
                  
                  return;
              }
              /// @notice Settle rewards for two NN holders
              /// @dev The function is for callback from NNToken. It is banned for contracts.
              /// @param from The address of the NN sender 
              /// @param to The address of the NN receiver 
              function settleNNReward(address from, address to) internal
              {
                  require(flag == NNREWARD_FLAG_ACTIVE, "Nest:NN:!flag");
                  uint256 fromBlnc = ERC20(C_NNToken).balanceOf(address(from));
                  require (fromBlnc > 0, "Nest:NN:!(fromBlnc)");
                  uint256 sum = rewardSum;
                  uint256 total = totalSupplyNN;
                  uint256 fromReward = sum.sub(rewardSumCheckpoint[from]).mul(fromBlnc).div(total);      
                  rewardSumCheckpoint[from] = sum;      
                 
                  uint256 toBlnc = ERC20(C_NNToken).balanceOf(address(to));
                  uint256 toReward = sum.sub(rewardSumCheckpoint[to]).mul(toBlnc).div(total);
                  rewardSumCheckpoint[to] = sum;
                  
                  if (fromReward > 0) {
                      INestPool(C_NestPool).withdrawNest(address(this), fromReward);
                      require(ERC20(C_NestToken).transfer(from, fromReward), "Nest:NN:!TRANS");
                      emit NNRewardClaimed(from, uint128(fromReward));
                  }
                  if (toReward > 0) { 
                      INestPool(C_NestPool).withdrawNest(address(this), toReward);
                      require(ERC20(C_NestToken).transfer(to, toReward), "Nest:NN:!TRANS");
                      emit NNRewardClaimed(to, uint128(toReward));
                  }
                  return;
              }
              /// @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) 
                  override
                  external
                  onlyBy(address(C_NNToken)) 
              {
                  settleNNReward(fromAdd, toAdd);
                  return;
              }
              /// @notice Show the amount of rewards unclaimed
              /// @return reward The reward of a NN holder
              function unclaimedNNReward() override external view returns (uint256 reward) 
              {
                  uint256 blnc = ERC20(C_NNToken).balanceOf(address(msg.sender));
                  uint256 sum = uint256(rewardSum);
                  uint256 total = uint256(totalSupplyNN);
               
                  reward = sum.sub(rewardSumCheckpoint[address(msg.sender)]).mul(blnc).div(total);
              }
          }// 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 "../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;
          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: 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;
          /// @title NNRewardPool
          /// @author Inf Loop - <[email protected]>
          /// @author Paradox  - <[email protected]>
          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");
              }
          }

          File 3 of 9: NestMiningV1
          // 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 - <[email protected]>
          /// @author Paradox  - <[email protected]>
          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);
              }
              */
          }// 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 - <[email protected]>
          /// @author 0x00  - <[email protected]>
          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 - <[email protected]>
          /// @author Paradox  - <[email protected]>
          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 - <[email protected]>
          /// @author Paradox  - <[email protected]>
          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 <[email protected]>
           */
          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;
                }
              }
            }
          }// 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 - <[email protected]>
          /// @author Paradox  - <[email protected]>
          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");
              }
          }

          File 4 of 9: NestPool
          // SPDX-License-Identifier: GPL-3.0-or-later
          pragma solidity ^0.6.12;
          import "./lib/SafeMath.sol";
          import "./lib/AddressPayable.sol";
          import "./lib/SafeERC20.sol";
          import './lib/TransferHelper.sol';
          import "./iface/INestPool.sol";
          import "./iface/INestDAO.sol";
          import "./iface/INestMining.sol";
          import "./iface/INestQuery.sol";
          import "./iface/INestStaking.sol";
          import "./iface/INNRewardPool.sol";
          import "./iface/INTokenController.sol";
          /// @title NestPool
          /// @author Inf Loop - <[email protected]>
          /// @author Paradox  - <[email protected]>
          /// @dev The contract is for bookkeeping ETH, NEST and Tokens. It is served as a vault, such that 
          ///     assets are transferred internally to save GAS.
          contract NestPool is INestPool {
              
              using address_make_payable for address;
              using SafeMath for uint256;
              using SafeERC20 for ERC20;
              uint8 private flag;  // 0: UNINITIALIZED  | 1: INITIALIZED
              uint256 public minedNestAmount; 
              address override public governance;
              address public addrOfNestBurning = address(0x1);
              // Contracts 
              address public C_NestDAO;
              address public C_NestMining;
              ERC20   public C_NestToken;
              address public C_NTokenController;
              address public C_NNToken;
              address public C_NNRewardPool;
              address public C_NestStaking;
              address public C_NestQuery;
              // eth ledger for all miners
              mapping(address => uint256) _eth_ledger;
              // token => miner => amount 
              mapping(address => mapping(address => uint256)) _token_ledger;
              // mapping(address => uint256) _nest_ledger;
              mapping(address => address) _token_ntoken_mapping;
              // parameters 
              constructor() public 
              {
                  governance = msg.sender;
              }
              receive() external payable { }
              /* ========== MODIFIERS ========== */
              modifier onlyGovernance() 
              {
                  require(msg.sender == governance, "Nest:Pool:!governance");
                  _;
              }
              modifier onlyBy(address _contract) 
              {
                  require(msg.sender == _contract, "Nest:Pool:!Auth");
                  _;
              }
              modifier onlyGovOrBy(address _contract) 
              {
                  require(msg.sender == governance || msg.sender == _contract, "Nest:Pool:!Auth");
                  _;
              }
              /*
              modifier onlyGovOrBy2(address _contract, address _contract2)
              {
                  require(msg.sender == governance || msg.sender == _contract || msg.sender == _contract2, "Nest:Pool:!Auth");
                  _;
              }
              modifier onlyGovOrBy3(address _contract1, address _contract2, address _contract3)
              {
                  require(msg.sender == governance
                      || msg.sender == _contract1
                      || msg.sender == _contract2
                      || msg.sender == _contract3, "Nest:Pool:!Auth");
                  _;
              }
              */
              modifier onlyByNest()
              {
                  require(msg.sender == C_NestMining
                      || msg.sender == C_NTokenController 
                      || msg.sender == C_NestDAO 
                      || msg.sender == C_NestStaking 
                      || msg.sender == C_NNRewardPool 
                      || msg.sender == C_NestQuery, "Nest:Pool:!Auth");
                  _;
              }
              modifier onlyMiningContract()
              {
                  require(address(msg.sender) == C_NestMining, "Nest:Pool:onlyMining");
                  _;
              }
              /* ========== GOVERNANCE ========== */
              function setGovernance(address _gov) 
                  override external onlyGovernance 
              { 
                  mapping(address => uint256) storage _nest_ledger = _token_ledger[address(C_NestToken)];
                  _nest_ledger[_gov] = _nest_ledger[governance];  
                  _nest_ledger[governance] = 0;
                  governance = _gov;
              }
              function setContracts(
                      address NestToken, address NestMining, 
                      address NestStaking, address NTokenController, 
                      address NNToken, address NNRewardPool, 
                      address NestQuery, address NestDAO
                  ) 
                  external onlyGovernance
              {
                  if (NestToken != address(0)) {
                      C_NestToken = ERC20(NestToken);
                  }
                  if (NestMining != address(0)) {
                      C_NestMining = NestMining;
                  }
                  if (NTokenController != address(0)) {
                      C_NTokenController = NTokenController;
                  }
                  if (NNToken != address(0)) {
                      C_NNToken = NNToken;
                  }
                  if (NNRewardPool != address(0)) {
                      C_NNRewardPool = NNRewardPool;
                  }
                  if (NestStaking != address(0)) {
                      C_NestStaking = NestStaking;
                  }
                  if (NestQuery != address(0)) {
                      C_NestQuery = NestQuery;
                  }
                  if (NestDAO != address(0)) {
                      C_NestDAO = NestDAO;
                  }
              }
              /// @dev Set the total amount of NEST in the pool. After Nest v3.5 upgrading, all 
              ///    of the unmined NEST will be transferred by the governer to this pool. 
              function initNestLedger(uint256 amount) 
                  override external onlyGovernance 
              {
                  require(_token_ledger[address(C_NestToken)][address(governance)] == 0, "Nest:Pool:!init"); 
                  _token_ledger[address(C_NestToken)][address(governance)] = amount;
              }
              function getNTokenFromToken(address token) 
                  override view public returns (address) 
              {
                  return _token_ntoken_mapping[token];
              }
              function setNTokenToToken(address token, address ntoken) 
                  override 
                  public
                  onlyGovOrBy(C_NTokenController) 
              {
                  _token_ntoken_mapping[token] = ntoken;
                  _token_ntoken_mapping[ntoken] = ntoken;
              }
              /* ========== ONLY FOR EMERGENCY ========== */
              // function drainEth(address to, uint256 amount) 
              //     external onlyGovernance
              // {
              //     TransferHelper.safeTransferETH(to, amount);
              // }
              function drainNest(address to, uint256 amount, address gov) 
                   override external onlyGovernance
              {
                   require(_token_ledger[address(C_NestToken)][gov] >= amount, "Nest:Pool:!amount");
                   C_NestToken.transfer(to, amount);
              }
              function transferNestInPool(address from, address to, uint256 amount) 
                  external onlyByNest
              {
                  if (amount == 0) {
                      return;
                  }
                  mapping(address => uint256) storage _nest_ledger = _token_ledger[address(C_NestToken)];
                  uint256 blnc = _nest_ledger[from];
                  require (blnc >= amount, "Nest:Pool:!amount");
                  _nest_ledger[from] = blnc.sub(amount);
                  _nest_ledger[to] = _nest_ledger[to].add(amount);
              }
              function transferTokenInPool(address token, address from, address to, uint256 amount) 
                  external onlyByNest
              {
                  if (amount == 0) {
                      return;
                  }
                  uint256 blnc = _token_ledger[token][from];
                  require (blnc >= amount, "Nest:Pool:!amount");
                  _token_ledger[token][from] = blnc.sub(amount);
                  _token_ledger[token][to] = _token_ledger[token][to].add(amount);
              }
              function transferEthInPool(address from, address to, uint256 amount) 
                  external onlyByNest
              {
                  if (amount == 0) {
                      return;
                  }
                  uint256 blnc = _eth_ledger[from];
                  require (blnc >= amount, "Nest:Pool:!amount");
                  _eth_ledger[from] = blnc.sub(amount);
                  _eth_ledger[to] = _eth_ledger[to].add(amount);
              }
              /* ========== FREEZING/UNFREEZING ========== */
              // NOTE: Guarded by onlyMiningContract
              function freezeEth(address miner, uint256 ethAmount) 
                  override public onlyBy(C_NestMining) 
              {
                  // emit LogAddress("freezeEthAndToken> miner", miner);
                  // emit LogAddress("freezeEthAndToken> token", token);
                  uint256 blncs = _eth_ledger[miner];
                  require(blncs >= ethAmount, "Nest:Pool:BAL(eth)<0");
                  _eth_ledger[miner] = blncs - ethAmount;  //safe_math: checked before
                  _eth_ledger[address(this)] =  _eth_ledger[address(this)].add(ethAmount);
              }
              function unfreezeEth(address miner, uint256 ethAmount) 
                  override public onlyBy(C_NestMining)  
              {
                  if (ethAmount > 0) {
                      // LogUint("unfreezeEthAndToken> _eth_ledger[address(0x0)]", _eth_ledger[address(0x0)]);
                      // LogUint("unfreezeEthAndToken> _eth_ledger[miner]", _eth_ledger[miner]);
                      // LogUint("unfreezeEthAndToken> ethAmount", ethAmount);
                      _eth_ledger[address(this)] =  _eth_ledger[address(this)].sub(ethAmount);
                      _eth_ledger[miner] = _eth_ledger[miner].add(ethAmount);
                  } 
              }
              function freezeNest(address miner, uint256 nestAmount) 
                  override public onlyBy(C_NestMining)  
              {
                  mapping(address => uint256) storage _nest_ledger = _token_ledger[address(C_NestToken)];
                  uint256 blncs = _nest_ledger[miner];
                  
                  _nest_ledger[address(this)] =  _nest_ledger[address(this)].add(nestAmount);
                  if (blncs < nestAmount) {
                      _nest_ledger[miner] = 0; 
                      require(C_NestToken.transferFrom(miner,  address(this), nestAmount - blncs), "Nest:Pool:!transfer"); //safe math
                  } else {
                      _nest_ledger[miner] = blncs - nestAmount;  //safe math
                  }
              }
              function unfreezeNest(address miner, uint256 nestAmount) 
                  override public onlyBy(C_NestMining)  
              {
                  mapping(address => uint256) storage _nest_ledger = _token_ledger[address(C_NestToken)];
                  if (nestAmount > 0) {
                      _nest_ledger[address(this)] =  _nest_ledger[address(this)].sub(nestAmount);
                      _nest_ledger[miner] = _nest_ledger[miner].add(nestAmount); 
                  }
              }
              function freezeToken(address miner, address token, uint256 tokenAmount) 
                  override external onlyBy(C_NestMining)  
              {
                  uint256 blncs = _token_ledger[token][miner];
                  _token_ledger[token][address(this)] =  _token_ledger[token][address(this)].add(tokenAmount);
                  if (blncs < tokenAmount) {
                      _token_ledger[token][miner] = 0; 
                      ERC20(token).safeTransferFrom(address(miner),  address(this), tokenAmount - blncs); //safe math
                  } else {
                      _token_ledger[token][miner] = blncs - tokenAmount;  //safe math
                  }
              }
              function unfreezeToken(address miner, address token, uint256 tokenAmount) 
                  override external onlyBy(C_NestMining)  
              {
                  if (tokenAmount > 0) {
                      _token_ledger[token][address(this)] =  _token_ledger[token][address(this)].sub(tokenAmount);
                      _token_ledger[token][miner] = _token_ledger[token][miner].add(tokenAmount); 
                  }
              }
              function freezeEthAndToken(address miner, uint256 ethAmount, address token, uint256 tokenAmount) 
                  override external onlyBy(C_NestMining)  
              {
                  uint256 blncs = _eth_ledger[miner];
                  require(blncs >= ethAmount, "Nest:Pool:!eth");
                  _eth_ledger[miner] = blncs - ethAmount;  //safe_math: checked before
                  _eth_ledger[address(this)] =  _eth_ledger[address(this)].add(ethAmount);
                  blncs = _token_ledger[token][miner];
                  _token_ledger[token][address(this)] =  _token_ledger[token][address(this)].add(tokenAmount);
                  if (blncs < tokenAmount) {
                      _token_ledger[token][miner] = 0;
                      ERC20(token).safeTransferFrom(address(miner),  address(this), tokenAmount - blncs); //safe math
                  } else {
                      _token_ledger[token][miner] = blncs - tokenAmount;  //safe math
                  }
              }
              function unfreezeEthAndToken(address miner, uint256 ethAmount, address token, uint256 tokenAmount) 
                  override external onlyBy(C_NestMining)  
              {
                  if (ethAmount > 0) {
                      _eth_ledger[address(this)] =  _eth_ledger[address(this)].sub(ethAmount);
                      _eth_ledger[miner] = _eth_ledger[miner].add(ethAmount);
                  } 
                  if (tokenAmount > 0) {
                      _token_ledger[token][address(this)] =  _token_ledger[token][address(this)].sub(tokenAmount);
                      _token_ledger[token][miner] = _token_ledger[token][miner].add(tokenAmount); 
                  }
              }
              /* ========== BALANCE ========== */
              function balanceOfNestInPool(address miner) 
                  override public view returns (uint256)
              {
                  mapping(address => uint256) storage _nest_ledger = _token_ledger[address(C_NestToken)];
                  return _nest_ledger[miner];
              }
              function balanceOfEthInPool(address miner) 
                  override public view returns (uint256)
              {
                  return _eth_ledger[miner];
              }
              function balanceOfTokenInPool(address miner, address token) 
                  override public view returns (uint256)
              {
                  return _token_ledger[token][miner];
              }
              function balanceOfEthFreezed() public view returns (uint256)
              {
                  return _eth_ledger[address(this)];
              }
              function balanceOfTokenFreezed(address token) public view returns (uint256)
              {
                  return _token_ledger[token][address(this)];
              }
              /* ========== DISTRIBUTING ========== */
              function addNest(address miner, uint256 amount) 
                  override public onlyBy(C_NestMining)
              {
                  mapping(address => uint256) storage _nest_ledger = _token_ledger[address(C_NestToken)];
                  _nest_ledger[governance] = _nest_ledger[governance].sub(amount);
                  _nest_ledger[miner] = _nest_ledger[miner].add(amount);
                  minedNestAmount = minedNestAmount.add(amount);
              }
              function addNToken(address miner, address ntoken, uint256 amount) 
                  override public onlyBy(C_NestMining)
              {
                  _token_ledger[ntoken][miner] = _token_ledger[ntoken][miner].add(amount);
              }
              /* ========== DEPOSIT ========== */
              // NOTE: Guarded by onlyMiningContract
              function depositEth(address miner) 
                  override payable external onlyGovOrBy(C_NestMining) 
              {
                  _eth_ledger[miner] =  _eth_ledger[miner].add(msg.value);
              }
              function depositNToken(address miner, address from, address ntoken, uint256 amount) 
                  override external onlyGovOrBy(C_NestMining) 
              {
                  ERC20(ntoken).transferFrom(from, address(this), amount);
                  _token_ledger[ntoken][miner] =  _token_ledger[ntoken][miner].add(amount);
              }
              /* ========== WITHDRAW ========== */
              // NOTE: Guarded by onlyGovOrBy(C_NestMining), onlyGovOrBy(C_NestStaking)
              
              /// @dev If amount == 0, it won't go stuck
              function withdrawEth(address miner, uint256 ethAmount) 
                  override public onlyByNest
              {
                  uint256 blncs = _eth_ledger[miner];
                  require(ethAmount <= blncs, "Nest:Pool:!blncs");
                  if (ethAmount > 0) {
                      _eth_ledger[miner] = blncs - ethAmount; // safe math
                      TransferHelper.safeTransferETH(miner, ethAmount);
                  }
              }
              /// @dev If amount == 0, it won't go stuck
              function withdrawToken(address miner, address token, uint256 tokenAmount) 
                  override public onlyByNest
              {
                  uint256 blncs = _token_ledger[token][miner];
                  require(tokenAmount <= blncs, "Nest:Pool:!blncs");
                  if (tokenAmount > 0) {
                      _token_ledger[token][miner] = blncs - tokenAmount; // safe math
                      ERC20(token).safeTransfer(miner, tokenAmount);
                  }
              }
              /// @dev If amount == 0, it won't go stuck
              function withdrawNest(address miner, uint256 amount) 
                  override public onlyByNest
              {
                  mapping(address => uint256) storage _nest_ledger = _token_ledger[address(C_NestToken)];
                  uint256 blncs = _nest_ledger[miner];
                  require(amount <= blncs, "Nest:Pool:!blncs");
                  if (amount > 0) {
                      _nest_ledger[miner] = blncs - amount;  // safe math
                      require(C_NestToken.transfer(miner, amount),"Nest:Pool:!TRANS");
                  }
              }
              /// @dev If amount == 0, it won't go stuck
              function withdrawEthAndToken(address miner, uint256 ethAmount, address token, uint256 tokenAmount) 
                  override public onlyBy(C_NestMining)
              {
                  uint256 blncs = _eth_ledger[miner];
                  if (ethAmount <= blncs && ethAmount > 0) {
                      _eth_ledger[miner] = blncs - ethAmount;  // safe math
                      TransferHelper.safeTransferETH(miner, ethAmount);
                  }
                  blncs = _token_ledger[token][miner];
                  if (tokenAmount <= blncs && tokenAmount > 0) {
                      _token_ledger[token][miner] = blncs - tokenAmount;  // safe math
                      ERC20(token).safeTransfer(miner, tokenAmount);
                  }
              }
              /// @dev If amount == 0, it won't go stuck
              function withdrawNTokenAndTransfer(address miner, address ntoken, uint256 amount, address to) 
                  override public onlyBy(C_NestStaking)
              {
                  uint256 blncs = _token_ledger[ntoken][miner];
                  require(amount <= blncs, "Nest:Pool:!blncs");
                  if (amount > 0) {
                      _token_ledger[ntoken][miner] = blncs - amount;  // safe math
                      require(ERC20(ntoken).transfer(to, amount),"Nest:Pool:!TRANS");
                  }
              }
              /* ========== HELPERS (VIEWS) ========== */
              // the user needs to be reminded of the parameter settings    
              function assetsList(uint256 len, address[] memory tokenList) 
                  public view returns (uint256[] memory) 
              {
                  // len < = length(tokenList) + 1
                  require(len == tokenList.length + 1, "Nest: Pool: !assetsList");
                  uint256[] memory list = new uint256[](len);
                  list[0] = _eth_ledger[address(msg.sender)];
                  for (uint i = 0; i < len - 1; i++) {
                      address _token = tokenList[i];
                      list[i+1] = _token_ledger[_token][address(msg.sender)];
                  }
                  return list;
              }
              function addrOfNestMining() override public view returns (address) 
              {
                  return C_NestMining;
              }
              function addrOfNestToken() override public view returns (address) 
              {
                  return address(C_NestToken);
              }
              function addrOfNTokenController() override public view returns (address) 
              {
                  return C_NTokenController;
              }
              
              function addrOfNNRewardPool() override public view returns (address) 
              {
                  return C_NNRewardPool;
              }
              function addrOfNNToken() override public view returns (address) 
              {
                  return C_NNToken;
              }
              function addrOfNestStaking() override public view returns (address) 
              {
                  return C_NestStaking;
              }
              function addrOfNestQuery() override public view returns (address) 
              {
                  return C_NestQuery;
              }
              function addrOfNestDAO() override public view returns (address) 
              {
                  return C_NestDAO;
              }
              function addressOfBurnedNest() override public view returns (address) 
              {
                  return addrOfNestBurning;
              }
              // function getMinerNToken(address miner, address token) public view returns (uint256 tokenAmount) 
              // {
              //     if (token != address(0x0)) {
              //         tokenAmount = _token_ledger[token][miner];
              //     }
              // } 
                  
              function getMinerEthAndToken(address miner, address token) 
                  public view returns (uint256 ethAmount, uint256 tokenAmount) 
              {
                  ethAmount = _eth_ledger[miner];
                  if (token != address(0x0)) {
                      tokenAmount = _token_ledger[token][miner];
                  }
              } 
              function getMinerNest(address miner) public view returns (uint256 nestAmount) 
              {
                  mapping(address => uint256) storage _nest_ledger = _token_ledger[address(C_NestToken)];
                  nestAmount = _nest_ledger[miner];
              } 
          }
          // 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;
          library address_make_payable {
             function make_payable(address x) internal pure returns (address payable) {
                return address(uint160(x));
             }
          }// 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: 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 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;
          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;
          /// @title The interface of NestQuery
          /// @author Inf Loop - <[email protected]>
          /// @author Paradox  - <[email protected]>
          interface INestQuery {
              /// @notice Activate a pay-per-query defi client with NEST tokens
              /// @dev No contract is allowed to call it
              /// @param defi The addres of client (DeFi DApp)
              function activate(address defi) external;
              /// @notice Deactivate a pay-per-query defi client
              /// @param defi The address of a client (DeFi DApp)
              function deactivate(address defi) external;
              /// @notice Query for PPQ (pay-per-query) clients
              /// @dev Consider that if a user call a DeFi that queries NestQuery, DeFi should
              ///     pass the user's wallet address to query() as `payback`.
              /// @param token The address of token contract
              /// @param payback The address of change
              function query(address token, address payback) 
                  external payable returns (uint256, uint256, uint256);
              /// @notice Query for PPQ (pay-per-query) clients
              /// @param token The address of token contract
              /// @param payback The address of change
              /// @return ethAmount The amount of ETH in pair (ETH, TOKEN)
              /// @return tokenAmount The amount of TOKEN in pair (ETH, TOKEN)
              /// @return avgPrice The average of last 50 prices 
              /// @return vola The volatility of prices 
              /// @return bn The block number when (ETH, TOKEN) takes into effective
              function queryPriceAvgVola(address token, address payback) 
                  external payable returns (uint256, uint256, uint128, int128, uint256);
              /// @notice The main function called by DeFi clients, compatible to Nest Protocol v3.0 
              /// @dev  The payback address is ZERO, so the changes are kept in this contract
              ///         The ABI keeps consist with Nest v3.0
              /// @param tokenAddress The address of token contract address
              /// @return ethAmount The amount of ETH in price pair (ETH, ERC20)
              /// @return erc20Amount The amount of ERC20 in price pair (ETH, ERC20)
              /// @return blockNum The block.number where the price is being in effect
              function updateAndCheckPriceNow(address tokenAddress) 
                  external payable returns (uint256, uint256, uint256);
              /// @notice A non-free function for querying price 
              /// @param token  The address of the token contract
              /// @param num    The number of price sheets in the list
              /// @param payback The address for change
              /// @return The array of prices, each of which is (blockNnumber, ethAmount, tokenAmount)
              function queryPriceList(address token, uint8 num, address payback) 
                  external payable returns (uint128[] memory);
              /// @notice A view function returning the historical price list from the current block
              /// @param token  The address of the token contract
              /// @param num    The number of price sheets in the list
              /// @return The array of prices, each of which is (blockNnumber, ethAmount, tokenAmount)
              function priceList(address token, uint8 num) 
                  external view returns (uint128[] memory);
              /// @notice A view function returning the latestPrice
              /// @param token  The address of the token contract
              function latestPrice(address token)
              external view returns (uint256 ethAmount, uint256 tokenAmount, uint128 avgPrice, int128 vola, uint256 bn) ;
              /// @dev Only for governance
              function loadContracts() external; 
              /// @dev Only for governance
              function loadGovernance() external; 
              event ClientActivated(address, uint256, uint256);
              // event ClientRenewed(address, uint256, uint256, uint256);
              event PriceQueried(address client, address token, uint256 ethAmount, uint256 tokenAmount, uint256 bn);
              event PriceAvgVolaQueried(address client, address token, uint256 bn, uint128 avgPrice, int128 vola);
              event PriceListQueried(address client, address token, uint256 bn, uint8 num);
              // governance events
              event ParamsSetup(address gov, uint256 oldParams, uint256 newParams);
              event FlagSet(address gov, uint256 flag);
          }// 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;
          /// @title NNRewardPool
          /// @author Inf Loop - <[email protected]>
          /// @author Paradox  - <[email protected]>
          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;
          pragma experimental ABIEncoderV2;
          interface INTokenController {
              /// @dev A struct for an ntoken
              ///     size: 2 x 256bit
              struct NTokenTag {
                  address owner;          // the owner with the highest bid
                  uint128 nestFee;        // NEST amount staked for opening a NToken
                  uint64  startTime;      // the start time of service
                  uint8   state;          // =0: normal | =1 disabled
                  uint56  _reserved;      // padding space
              }
              function open(address token) external;
              
              function NTokenTagOf(address token) external view returns (NTokenTag memory);
              /// @dev Only for governance
              function loadContracts() external; 
              function loadGovernance() external;
              function setParams(uint256 _openFeeNestAmount) external;
              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;
          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");
              }
          }

          File 5 of 9: AdminUpgradeabilityProxy
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.6.0;
          import './UpgradeabilityProxy.sol';
          /**
           * @title AdminUpgradeabilityProxy
           * @dev This contract combines an upgradeability proxy with an authorization
           * mechanism for administrative tasks.
           * All external functions in this contract must be guarded by the
           * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity
           * feature proposal that would enable this to be done automatically.
           */
          contract AdminUpgradeabilityProxy is UpgradeabilityProxy {
            /**
             * Contract constructor.
             * @param _logic address of the initial implementation.
             * @param _admin Address of the proxy administrator.
             * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
             * It should include the signature and the parameters of the function to be called, as described in
             * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
             * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
             */
            constructor(address _logic, address _admin, bytes memory _data) UpgradeabilityProxy(_logic, _data) public payable {
              assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1));
              _setAdmin(_admin);
            }
            /**
             * @dev Emitted when the administration has been transferred.
             * @param previousAdmin Address of the previous admin.
             * @param newAdmin Address of the new admin.
             */
            event AdminChanged(address previousAdmin, address newAdmin);
            /**
             * @dev Storage slot with the admin of the contract.
             * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
             * validated in the constructor.
             */
            bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
            /**
             * @dev Modifier to check whether the `msg.sender` is the admin.
             * If it is, it will run the function. Otherwise, it will delegate the call
             * to the implementation.
             */
            modifier ifAdmin() {
              if (msg.sender == _admin()) {
                _;
              } else {
                _fallback();
              }
            }
            /**
             * @return The address of the proxy admin.
             */
            function admin() external ifAdmin returns (address) {
              return _admin();
            }
            /**
             * @return The address of the implementation.
             */
            function implementation() external ifAdmin returns (address) {
              return _implementation();
            }
            /**
             * @dev Changes the admin of the proxy.
             * Only the current admin can call this function.
             * @param newAdmin Address to transfer proxy administration to.
             */
            function changeAdmin(address newAdmin) external ifAdmin {
              require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address");
              emit AdminChanged(_admin(), newAdmin);
              _setAdmin(newAdmin);
            }
            /**
             * @dev Upgrade the backing implementation of the proxy.
             * Only the admin can call this function.
             * @param newImplementation Address of the new implementation.
             */
            function upgradeTo(address newImplementation) external ifAdmin {
              _upgradeTo(newImplementation);
            }
            /**
             * @dev Upgrade the backing implementation of the proxy and call a function
             * on the new implementation.
             * This is useful to initialize the proxied contract.
             * @param newImplementation Address of the new implementation.
             * @param data Data to send as msg.data in the low level call.
             * It should include the signature and the parameters of the function to be called, as described in
             * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
             */
            function upgradeToAndCall(address newImplementation, bytes calldata data) payable external ifAdmin {
              _upgradeTo(newImplementation);
              (bool success,) = newImplementation.delegatecall(data);
              require(success);
            }
            /**
             * @return adm The admin slot.
             */
            function _admin() internal view returns (address adm) {
              bytes32 slot = ADMIN_SLOT;
              assembly {
                adm := sload(slot)
              }
            }
            /**
             * @dev Sets the address of the proxy admin.
             * @param newAdmin Address of the new proxy admin.
             */
            function _setAdmin(address newAdmin) internal {
              bytes32 slot = ADMIN_SLOT;
              assembly {
                sstore(slot, newAdmin)
              }
            }
            /**
             * @dev Only fall back when the sender is not the admin.
             */
            function _willFallback() internal override virtual {
              require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin");
              super._willFallback();
            }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.6.0;
          import './Proxy.sol';
          import '@openzeppelin/contracts/utils/Address.sol';
          /**
           * @title UpgradeabilityProxy
           * @dev This contract implements a proxy that allows to change the
           * implementation address to which it will delegate.
           * Such a change is called an implementation upgrade.
           */
          contract UpgradeabilityProxy is Proxy {
            /**
             * @dev Contract constructor.
             * @param _logic Address of the initial implementation.
             * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
             * It should include the signature and the parameters of the function to be called, as described in
             * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
             * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
             */
            constructor(address _logic, bytes memory _data) public payable {
              assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1));
              _setImplementation(_logic);
              if(_data.length > 0) {
                (bool success,) = _logic.delegatecall(_data);
                require(success);
              }
            }  
            /**
             * @dev Emitted when the implementation is upgraded.
             * @param implementation Address of the new implementation.
             */
            event Upgraded(address indexed implementation);
            /**
             * @dev Storage slot with the address of the current implementation.
             * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
             * validated in the constructor.
             */
            bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
            /**
             * @dev Returns the current implementation.
             * @return impl Address of the current implementation
             */
            function _implementation() internal override view returns (address impl) {
              bytes32 slot = IMPLEMENTATION_SLOT;
              assembly {
                impl := sload(slot)
              }
            }
            /**
             * @dev Upgrades the proxy to a new implementation.
             * @param newImplementation Address of the new implementation.
             */
            function _upgradeTo(address newImplementation) internal {
              _setImplementation(newImplementation);
              emit Upgraded(newImplementation);
            }
            /**
             * @dev Sets the implementation address of the proxy.
             * @param newImplementation Address of the new implementation.
             */
            function _setImplementation(address newImplementation) internal {
              require(Address.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address");
              bytes32 slot = IMPLEMENTATION_SLOT;
              assembly {
                sstore(slot, newImplementation)
              }
            }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.6.0;
          /**
           * @title Proxy
           * @dev Implements delegation of calls to other contracts, with proper
           * forwarding of return values and bubbling of failures.
           * It defines a fallback function that delegates all calls to the address
           * returned by the abstract _implementation() internal function.
           */
          abstract contract Proxy {
            /**
             * @dev Fallback function.
             * Implemented entirely in `_fallback`.
             */
            fallback () payable external {
              _fallback();
            }
            /**
             * @dev Receive function.
             * Implemented entirely in `_fallback`.
             */
            receive () payable external {
              _fallback();
            }
            /**
             * @return The Address of the implementation.
             */
            function _implementation() internal virtual view returns (address);
            /**
             * @dev Delegates execution to an implementation contract.
             * This is a low level function that doesn't return to its internal call site.
             * It will return to the external caller whatever the implementation returns.
             * @param implementation Address to delegate.
             */
            function _delegate(address implementation) internal {
              assembly {
                // Copy msg.data. We take full control of memory in this inline assembly
                // block because it will not return to Solidity code. We overwrite the
                // Solidity scratch pad at memory position 0.
                calldatacopy(0, 0, calldatasize())
                // Call the implementation.
                // out and outsize are 0 because we don't know the size yet.
                let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                // Copy the returned data.
                returndatacopy(0, 0, returndatasize())
                switch result
                // delegatecall returns 0 on error.
                case 0 { revert(0, returndatasize()) }
                default { return(0, returndatasize()) }
              }
            }
            /**
             * @dev Function that is run as the first thing in the fallback function.
             * Can be redefined in derived contracts to add functionality.
             * Redefinitions must call super._willFallback().
             */
            function _willFallback() internal virtual {
            }
            /**
             * @dev fallback implementation.
             * Extracted to enable manual triggering.
             */
            function _fallback() internal {
              _willFallback();
              _delegate(_implementation());
            }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.2 <0.8.0;
          /**
           * @dev Collection of functions related to the address type
           */
          library Address {
              /**
               * @dev Returns true if `account` is a contract.
               *
               * [IMPORTANT]
               * ====
               * It is unsafe to assume that an address for which this function returns
               * false is an externally-owned account (EOA) and not a contract.
               *
               * Among others, `isContract` will return false for the following
               * types of addresses:
               *
               *  - an externally-owned account
               *  - a contract in construction
               *  - an address where a contract will be created
               *  - an address where a contract lived, but was destroyed
               * ====
               */
              function isContract(address account) internal view returns (bool) {
                  // This method relies on extcodesize, which returns 0 for contracts in
                  // construction, since the code is only stored at the end of the
                  // constructor execution.
                  uint256 size;
                  // solhint-disable-next-line no-inline-assembly
                  assembly { size := extcodesize(account) }
                  return size > 0;
              }
              /**
               * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
               * `recipient`, forwarding all available gas and reverting on errors.
               *
               * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
               * of certain opcodes, possibly making contracts go over the 2300 gas limit
               * imposed by `transfer`, making them unable to receive funds via
               * `transfer`. {sendValue} removes this limitation.
               *
               * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
               *
               * IMPORTANT: because control is transferred to `recipient`, care must be
               * taken to not create reentrancy vulnerabilities. Consider using
               * {ReentrancyGuard} or the
               * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
               */
              function sendValue(address payable recipient, uint256 amount) internal {
                  require(address(this).balance >= amount, "Address: insufficient balance");
                  // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                  (bool success, ) = recipient.call{ value: amount }("");
                  require(success, "Address: unable to send value, recipient may have reverted");
              }
              /**
               * @dev Performs a Solidity function call using a low level `call`. A
               * plain`call` is an unsafe replacement for a function call: use this
               * function instead.
               *
               * If `target` reverts with a revert reason, it is bubbled up by this
               * function (like regular Solidity function calls).
               *
               * Returns the raw returned data. To convert to the expected return value,
               * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
               *
               * Requirements:
               *
               * - `target` must be a contract.
               * - calling `target` with `data` must not revert.
               *
               * _Available since v3.1._
               */
              function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                return functionCall(target, data, "Address: low-level call failed");
              }
              /**
               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
               * `errorMessage` as a fallback revert reason when `target` reverts.
               *
               * _Available since v3.1._
               */
              function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                  return functionCallWithValue(target, data, 0, errorMessage);
              }
              /**
               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
               * but also transferring `value` wei to `target`.
               *
               * Requirements:
               *
               * - the calling contract must have an ETH balance of at least `value`.
               * - the called Solidity function must be `payable`.
               *
               * _Available since v3.1._
               */
              function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                  return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
              }
              /**
               * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
               * with `errorMessage` as a fallback revert reason when `target` reverts.
               *
               * _Available since v3.1._
               */
              function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                  require(address(this).balance >= value, "Address: insufficient balance for call");
                  require(isContract(target), "Address: call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.call{ value: value }(data);
                  return _verifyCallResult(success, returndata, errorMessage);
              }
              /**
               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
               * but performing a static call.
               *
               * _Available since v3.3._
               */
              function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                  return functionStaticCall(target, data, "Address: low-level static call failed");
              }
              /**
               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
               * but performing a static call.
               *
               * _Available since v3.3._
               */
              function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                  require(isContract(target), "Address: static call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.staticcall(data);
                  return _verifyCallResult(success, returndata, errorMessage);
              }
              function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                  if (success) {
                      return returndata;
                  } else {
                      // Look for revert reason and bubble it up if present
                      if (returndata.length > 0) {
                          // The easiest way to bubble the revert reason is using memory via assembly
                          // solhint-disable-next-line no-inline-assembly
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert(errorMessage);
                      }
                  }
              }
          }
          

          File 6 of 9: NestStaking
          // SPDX-License-Identifier: GPL-3.0-or-later
          pragma solidity ^0.6.12;
          import "./lib/SafeMath.sol";
          import "./lib/AddressPayable.sol";
          import "./iface/INestPool.sol";
          import "./iface/INestStaking.sol";
          import "./lib/SafeERC20.sol";
          import "./lib/ReentrancyGuard.sol";
          import './lib/TransferHelper.sol';
          /// @title NestStaking
          /// @author Inf Loop - <[email protected]>
          /// @author Paradox  - <[email protected]>
          contract NestStaking is INestStaking, ReentrancyGuard {
              using SafeMath for uint256;
              /* ========== STATE ============== */
              /// @dev  The flag of staking global state
              uint8 public flag;      // = 0: uninitialized
                                      // = 1: active
                                      // = 2: no staking
                                      // = 3: paused 
              uint248 private _reserved1;
              uint8 constant STAKING_FLAG_UNINITIALIZED    = 0;
              uint8 constant STAKING_FLAG_ACTIVE           = 1;
              uint8 constant STAKING_FLAG_NO_STAKING       = 2;
              uint8 constant STAKING_FLAG_PAUSED           = 3;
              /// @dev The balance of savings w.r.t a ntoken(or nest-token)
              ///     _pending_saving_Amount: ntoken => saving amount
              //mapping(address => uint256) private _pending_saving_amount;
              /// @dev The per-ntoken-reward (ETH) w.r.t a ntoken(or nest-token)
              ///     _reward_per_ntoken_stored: ntoken => amount
              mapping(address => uint256) private _reward_per_ntoken_stored;
              // _reward_per_ntoken_claimed: (ntoken, acount, amount) => amount
              mapping(address => mapping(address => uint256)) _reward_per_ntoken_claimed;
              // ntoken => last reward 
              mapping(address => uint256) public lastRewardsTotal;
              // _ntoken_total: ntoken => amount
              mapping(address => uint256) _ntoken_staked_total;
              // _staked_balances: (ntoken, account) => amount
              mapping(address => mapping(address => uint256)) private _staked_balances;
              // rewardsTotal: (ntoken) => amount
              mapping(address => uint256) public rewardsTotal;
              
              // _rewards_balances: (ntoken, account) => amount
              mapping(address => mapping(address => uint256)) public rewardBalances;
              /* ========== PARAMETERS ============== */
              
              /// @dev The percentage of dividends 
              uint8 private _dividend_share; // = 100 as default;
              uint8 constant STAKING_DIVIDEND_SHARE_PRECENTAGE = 100;
              uint248 private _reserved2;
              /* ========== ADDRESSES ============== */
              address private C_NestToken;
              address private C_NestPool;
              address private governance;
              /* ========== CONSTRUCTOR ========== */
              receive() external payable {}
              // NOTE: to support open-zeppelin/upgrades, leave it blank
              constructor() public { }
              /// @dev It is called by the proxy (open-zeppelin/upgrades), only ONCE!
              function initialize(address NestPool) external 
              {
                  require(flag == STAKING_FLAG_UNINITIALIZED, "Nest:Stak:!flag");
                  governance = msg.sender;
                  _dividend_share = STAKING_DIVIDEND_SHARE_PRECENTAGE;
                  flag = STAKING_FLAG_ACTIVE;
                  C_NestPool = NestPool;
              }
              /* ========== MODIFIERS ========== */
              modifier onlyGovOrBy(address _contract) 
              {
                  require(msg.sender == governance || msg.sender == _contract, "Nest:Stak:!sender");
                  _;
              }
              modifier whenActive() 
              {
                  require(flag == STAKING_FLAG_ACTIVE, "Nest:Stak:!flag");
                  _;
              }
              modifier onlyGovernance() 
              {
                  require(msg.sender == governance, "Nest:Stak:!gov");
                  _;
              }
              mapping(uint256 => mapping(address => bool)) private _status;
              modifier onlyOneBlock() {
                  require(
                      !_status[block.number][tx.origin],
                      'Nest:Stak:!block'
                  );
                  require(
                      !_status[block.number][msg.sender],
                      'Nest:Stak:!block'
                  );
                  _;
                  _status[block.number][tx.origin] = true;
                  _status[block.number][msg.sender] = true;
              }
              /* ========== GOVERNANCE ========== */
              function loadContracts() override external onlyGovOrBy(C_NestPool)
              {
                  C_NestToken = INestPool(C_NestPool).addrOfNestToken();
              }
              /// @dev To ensure that all of governance-addresses be consist with each other
              function loadGovernance() override external 
              { 
                  governance = INestPool(C_NestPool).governance();
              }
              /// @dev Stop service for emergency
              function pause() override external onlyGovernance
              {
                  require(flag == STAKING_FLAG_ACTIVE, "Nest:Stak:!flag");
                  flag = STAKING_FLAG_PAUSED;
                  emit FlagSet(address(msg.sender), uint256(STAKING_FLAG_PAUSED));
              }
              /// @dev Resume service 
              function resume() override external onlyGovernance
              {
                  require(flag == STAKING_FLAG_PAUSED, "Nest:Stak:!flag");
                  flag = STAKING_FLAG_ACTIVE;
                  emit FlagSet(address(msg.sender), uint256(STAKING_FLAG_ACTIVE));
              }
              /*
              // exist bug
              function withdrawSavingByGov(address ntoken, address to, uint256 amount) 
                  external 
                  nonReentrant 
                  onlyGovernance 
              {
                  require(flag == STAKING_FLAG_PAUSED, "Nest:Stak:!flag");
                  _pending_saving_amount[ntoken] = _pending_saving_amount[ntoken].sub(amount);
                  // must refresh WETH balance record after updating WETH balance
                  // or lastRewardsTotal could be less than the newest WETH balance in the next update
                  uint256 _newTotal = rewardsTotal[ntoken].sub(amount);
                  lastRewardsTotal[ntoken] = _newTotal;
                  rewardsTotal[ntoken] = _newTotal;
                  emit SavingWithdrawn(ntoken, to, amount);
                  TransferHelper.safeTransferETH(to, amount);      
              }
             
              function setParams(uint8 dividendShareRate) override external onlyGovernance
              {
                  if (dividendShareRate > 0 && dividendShareRate <= 100) {
                      _dividend_share = dividendShareRate;
                  }
              }
              */
              /* ========== VIEWS ========== */
              /*
              function totalSaving(address ntoken)
                  external view returns (uint256) 
              {
                 return  _pending_saving_amount[ntoken];
              }
              */
              function totalRewards(address ntoken)
                  external view returns (uint256) 
              {
                 return  rewardsTotal[ntoken];
              }
              function totalStaked(address ntoken) 
                  external override view returns (uint256) 
              {
                  return _ntoken_staked_total[ntoken];
              }
              function stakedBalanceOf(address ntoken, address account) 
                  external override view returns (uint256) 
              {
                  return _staked_balances[ntoken][account];
              }
              // CM: <tokenShare> = <OldTokenShare> + (<NewTokenShare> * _dividend_share% / <tokenAmount>) 
              function rewardPerToken(address ntoken) 
                  public 
                  view 
                  returns (uint256) 
              {
                  uint256 _total = _ntoken_staked_total[ntoken];
                  if (_total == 0) {
                      // use the old rewardPerTokenStored
                      // if not, the new accrued amount will never be distributed to anyone
                      return _reward_per_ntoken_stored[ntoken];
                  }
                  uint256 _rewardPerToken = _reward_per_ntoken_stored[ntoken].add(
                          accrued(ntoken).mul(1e18).mul(_dividend_share).div(_total).div(100)
                      );
                  return _rewardPerToken;
              }
              // CM: <NewTokenShare> = <rewardToken blnc> - <last blnc>
              function accrued(address ntoken) 
                  public 
                  view 
                  returns (uint256) 
              {
                  // eth increment of eth since last update
                  uint256 _newest = rewardsTotal[ntoken];
                  // lastest must be larger than lastUpdate
                  return _newest.sub(lastRewardsTotal[ntoken]); 
              }
              // CM: <user share> = [<tokenAmonut> * (<tokenShare> - <tokenShareCollected>) / 1e18] + <reward>
              function earned(address ntoken, address account) 
                  public 
                  view 
                  returns (uint256) 
              {
                  return _staked_balances[ntoken][account].mul(
                                  rewardPerToken(ntoken).sub(_reward_per_ntoken_claimed[ntoken][account])
                              ).div(1e18).add(rewardBalances[ntoken][account]);
              }
              /*  // it is extra
              // calculate
              function _rewardPerTokenAndAccrued(address ntoken) 
                  internal
                  view 
                  returns (uint256, uint256) 
              {
                  uint256 _total = _ntoken_staked_total[ntoken];
                  if (_total == 0) {
                      // use the old rewardPerTokenStored, and accrued should be zero here
                      // if not the new accrued amount will never be distributed to anyone
                      return (_reward_per_ntoken_stored[ntoken], 0);
                  }
                  uint256 _accrued = accrued(ntoken);
                  uint256 _rewardPerToken = _reward_per_ntoken_stored[ntoken].add(
                          _accrued.mul(1e18).mul(_dividend_share).div(_total).div(100) 
                      ); // 80% of accrued to NEST holders as dividend
                  return (_rewardPerToken, _accrued);
              }
              */
              /* ========== STAK/UNSTAK/CLAIM ========== */
              modifier updateReward(address ntoken, address account) 
              {
                  uint256 _total = _ntoken_staked_total[ntoken];
                  uint256 _accrued = rewardsTotal[ntoken].sub(lastRewardsTotal[ntoken]);
                  uint256 _rewardPerToken;      
                  if (_total == 0) {
                      // use the old rewardPerTokenStored, and accrued should be zero here
                      // if not the new accrued amount will never be distributed to anyone
                      _rewardPerToken = _reward_per_ntoken_stored[ntoken];
                  } else {
                      // 80% of accrued to NEST holders as dividend
                      _rewardPerToken = _reward_per_ntoken_stored[ntoken].add(
                          _accrued.mul(1e18).mul(_dividend_share).div(_total).div(100) 
                      );
                      // update _reward_per_ntoken_stored
                      _reward_per_ntoken_stored[ntoken] = _rewardPerToken;
                      lastRewardsTotal[ntoken] = rewardsTotal[ntoken];
                      //uint256 _newSaving = _accrued.sub(_accrued.mul(_dividend_share).div(100)); // left 20%
                      //_pending_saving_amount[ntoken] = _pending_saving_amount[ntoken].add(_newSaving);
                  }
                  uint256 _newEarned = _staked_balances[ntoken][account].mul(
                          _rewardPerToken.sub(_reward_per_ntoken_claimed[ntoken][account])
                      ).div(1e18);
                  if (account != address(0)) { // Q: redundant
                      rewardBalances[ntoken][account] = rewardBalances[ntoken][account].add(_newEarned);
                      _reward_per_ntoken_claimed[ntoken][account] = _reward_per_ntoken_stored[ntoken];
                  }
                  _;
              }
              /// @notice Stake NTokens to get the dividends
              function stake(address ntoken, uint256 amount)
                  external 
                  override 
                  nonReentrant 
                  onlyOneBlock
                  whenActive
                  updateReward(ntoken, msg.sender) 
              {
                  require(amount > 0, "Nest:Stak:!amount");
                  _ntoken_staked_total[ntoken] = _ntoken_staked_total[ntoken].add(amount);
                  _staked_balances[ntoken][msg.sender] = _staked_balances[ntoken][msg.sender].add(amount);
                  //TransferHelper.safeTransferFrom(ntoken, msg.sender, address(this), amount);
                  emit NTokenStaked(ntoken, msg.sender, amount);
                  TransferHelper.safeTransferFrom(ntoken, msg.sender, address(this), amount);
              }
              /// @notice Stake NTokens to get the dividends
              function stakeFromNestPool(address ntoken, uint256 amount) 
                  external 
                  override 
                  nonReentrant 
                  onlyOneBlock
                  whenActive
                  updateReward(ntoken, msg.sender) 
              {
                  require(amount > 0, "Nest:Stak:!amount");
                  _ntoken_staked_total[ntoken] = _ntoken_staked_total[ntoken].add(amount);
                  _staked_balances[ntoken][msg.sender] = _staked_balances[ntoken][msg.sender].add(amount);
                  INestPool(C_NestPool).withdrawNTokenAndTransfer(msg.sender, ntoken, amount, address(this));
                  emit NTokenStaked(ntoken, msg.sender, amount);
              }
              /// @notice Unstake NTokens
              function unstake(address ntoken, uint256 amount) 
                  public 
                  override 
                  nonReentrant 
                  onlyOneBlock
                  whenActive
                  updateReward(ntoken, msg.sender)
              {
                  require(amount > 0, "Nest:Stak:!amount");
                  _ntoken_staked_total[ntoken] = _ntoken_staked_total[ntoken].sub(amount);
                  _staked_balances[ntoken][msg.sender] = _staked_balances[ntoken][msg.sender].sub(amount);
                  //TransferHelper.safeTransfer(ntoken, msg.sender, amount);
                  emit NTokenUnstaked(ntoken, msg.sender, amount);
                  TransferHelper.safeTransfer(ntoken, msg.sender, amount);
              }
              /// @notice Claim rewards
              function claim(address ntoken) 
                  public 
                  override 
                  nonReentrant 
                  whenActive
                  updateReward(ntoken, msg.sender) 
                  returns (uint256)
              {
                  uint256 _reward = rewardBalances[ntoken][msg.sender];
                  if (_reward > 0) {
                      rewardBalances[ntoken][msg.sender] = 0;
                      // WETH balance decreased after this
                      //TransferHelper.safeTransferETH(msg.sender, _reward);
                      // must refresh WETH balance record after updating WETH balance
                      // or lastRewardsTotal could be less than the newest WETH balance in the next update
                      uint256 _newTotal = rewardsTotal[ntoken].sub(_reward);
                      lastRewardsTotal[ntoken] = _newTotal;
                      rewardsTotal[ntoken] = _newTotal;         
                     
                      emit RewardClaimed(ntoken, msg.sender, _reward);
                       TransferHelper.safeTransferETH(msg.sender, _reward);
                  }
                  return _reward;
              }
              /* ========== INTER-CALLS ========== */
              function addETHReward(address ntoken) 
                  override 
                  external 
                  payable 
              {
                  // NOTE: no need to update reward here
                  // support for sending ETH for rewards
                  rewardsTotal[ntoken] = rewardsTotal[ntoken].add(msg.value); 
              }
          }
          // 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;
          library address_make_payable {
             function make_payable(address x) internal pure returns (address payable) {
                return address(uint160(x));
             }
          }// 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;
          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: MIT
          pragma solidity ^0.6.0;
          /// @dev The non-empty constructor is conflict with upgrades-openzeppelin. 
          /**
           * @dev Contract module that helps prevent reentrant calls to a function.
           *
           * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
           * available, which can be applied to functions to make sure there are no nested
           * (reentrant) calls to them.
           *
           * Note that because there is a single `nonReentrant` guard, functions marked as
           * `nonReentrant` may not call one another. This can be worked around by making
           * those functions `private`, and then adding `external` `nonReentrant` entry
           * points to them.
           *
           * TIP: If you would like to learn more about reentrancy and alternative ways
           * to protect against it, check out our blog post
           * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
           */
          contract ReentrancyGuard {
              // Booleans are more expensive than uint256 or any type that takes up a full
              // word because each write operation emits an extra SLOAD to first read the
              // slot's contents, replace the bits taken up by the boolean, and then write
              // back. This is the compiler's defense against contract upgrades and
              // pointer aliasing, and it cannot be disabled.
              // The values being non-zero value makes deployment a bit more expensive,
              // but in exchange the refund on every call to nonReentrant will be lower in
              // amount. Since refunds are capped to a percentage of the total
              // transaction's gas, it is best to keep them low in cases like this one, to
              // increase the likelihood of the full refund coming into effect.
              // NOTE: _NOT_ENTERED is set to ZERO such that it needn't constructor
              uint256 private constant _NOT_ENTERED = 0;
              uint256 private constant _ENTERED = 1;
              uint256 private _status;
              // constructor () internal {
              //     _status = _NOT_ENTERED;
              // }
              /**
               * @dev Prevents a contract from calling itself, directly or indirectly.
               * Calling a `nonReentrant` function from another `nonReentrant`
               * function is not supported. It is possible to prevent this from happening
               * by making the `nonReentrant` function external, and make it call a
               * `private` function that does the actual work.
               */
              modifier nonReentrant() {
                  // On the first call to nonReentrant, _notEntered will be true
                  require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
                  // Any calls to nonReentrant after this point will fail
                  _status = _ENTERED;
                  _;
                  // By storing the original value once again, a refund is triggered (see
                  // https://eips.ethereum.org/EIPS/eip-2200)
                  _status = _NOT_ENTERED;
              }
          }// 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: 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");
              }
          }

          File 7 of 9: AdminUpgradeabilityProxy
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.6.0;
          import './UpgradeabilityProxy.sol';
          /**
           * @title AdminUpgradeabilityProxy
           * @dev This contract combines an upgradeability proxy with an authorization
           * mechanism for administrative tasks.
           * All external functions in this contract must be guarded by the
           * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity
           * feature proposal that would enable this to be done automatically.
           */
          contract AdminUpgradeabilityProxy is UpgradeabilityProxy {
            /**
             * Contract constructor.
             * @param _logic address of the initial implementation.
             * @param _admin Address of the proxy administrator.
             * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
             * It should include the signature and the parameters of the function to be called, as described in
             * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
             * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
             */
            constructor(address _logic, address _admin, bytes memory _data) UpgradeabilityProxy(_logic, _data) public payable {
              assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1));
              _setAdmin(_admin);
            }
            /**
             * @dev Emitted when the administration has been transferred.
             * @param previousAdmin Address of the previous admin.
             * @param newAdmin Address of the new admin.
             */
            event AdminChanged(address previousAdmin, address newAdmin);
            /**
             * @dev Storage slot with the admin of the contract.
             * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
             * validated in the constructor.
             */
            bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
            /**
             * @dev Modifier to check whether the `msg.sender` is the admin.
             * If it is, it will run the function. Otherwise, it will delegate the call
             * to the implementation.
             */
            modifier ifAdmin() {
              if (msg.sender == _admin()) {
                _;
              } else {
                _fallback();
              }
            }
            /**
             * @return The address of the proxy admin.
             */
            function admin() external ifAdmin returns (address) {
              return _admin();
            }
            /**
             * @return The address of the implementation.
             */
            function implementation() external ifAdmin returns (address) {
              return _implementation();
            }
            /**
             * @dev Changes the admin of the proxy.
             * Only the current admin can call this function.
             * @param newAdmin Address to transfer proxy administration to.
             */
            function changeAdmin(address newAdmin) external ifAdmin {
              require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address");
              emit AdminChanged(_admin(), newAdmin);
              _setAdmin(newAdmin);
            }
            /**
             * @dev Upgrade the backing implementation of the proxy.
             * Only the admin can call this function.
             * @param newImplementation Address of the new implementation.
             */
            function upgradeTo(address newImplementation) external ifAdmin {
              _upgradeTo(newImplementation);
            }
            /**
             * @dev Upgrade the backing implementation of the proxy and call a function
             * on the new implementation.
             * This is useful to initialize the proxied contract.
             * @param newImplementation Address of the new implementation.
             * @param data Data to send as msg.data in the low level call.
             * It should include the signature and the parameters of the function to be called, as described in
             * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
             */
            function upgradeToAndCall(address newImplementation, bytes calldata data) payable external ifAdmin {
              _upgradeTo(newImplementation);
              (bool success,) = newImplementation.delegatecall(data);
              require(success);
            }
            /**
             * @return adm The admin slot.
             */
            function _admin() internal view returns (address adm) {
              bytes32 slot = ADMIN_SLOT;
              assembly {
                adm := sload(slot)
              }
            }
            /**
             * @dev Sets the address of the proxy admin.
             * @param newAdmin Address of the new proxy admin.
             */
            function _setAdmin(address newAdmin) internal {
              bytes32 slot = ADMIN_SLOT;
              assembly {
                sstore(slot, newAdmin)
              }
            }
            /**
             * @dev Only fall back when the sender is not the admin.
             */
            function _willFallback() internal override virtual {
              require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin");
              super._willFallback();
            }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.6.0;
          import './Proxy.sol';
          import '@openzeppelin/contracts/utils/Address.sol';
          /**
           * @title UpgradeabilityProxy
           * @dev This contract implements a proxy that allows to change the
           * implementation address to which it will delegate.
           * Such a change is called an implementation upgrade.
           */
          contract UpgradeabilityProxy is Proxy {
            /**
             * @dev Contract constructor.
             * @param _logic Address of the initial implementation.
             * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
             * It should include the signature and the parameters of the function to be called, as described in
             * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
             * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
             */
            constructor(address _logic, bytes memory _data) public payable {
              assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1));
              _setImplementation(_logic);
              if(_data.length > 0) {
                (bool success,) = _logic.delegatecall(_data);
                require(success);
              }
            }  
            /**
             * @dev Emitted when the implementation is upgraded.
             * @param implementation Address of the new implementation.
             */
            event Upgraded(address indexed implementation);
            /**
             * @dev Storage slot with the address of the current implementation.
             * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
             * validated in the constructor.
             */
            bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
            /**
             * @dev Returns the current implementation.
             * @return impl Address of the current implementation
             */
            function _implementation() internal override view returns (address impl) {
              bytes32 slot = IMPLEMENTATION_SLOT;
              assembly {
                impl := sload(slot)
              }
            }
            /**
             * @dev Upgrades the proxy to a new implementation.
             * @param newImplementation Address of the new implementation.
             */
            function _upgradeTo(address newImplementation) internal {
              _setImplementation(newImplementation);
              emit Upgraded(newImplementation);
            }
            /**
             * @dev Sets the implementation address of the proxy.
             * @param newImplementation Address of the new implementation.
             */
            function _setImplementation(address newImplementation) internal {
              require(Address.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address");
              bytes32 slot = IMPLEMENTATION_SLOT;
              assembly {
                sstore(slot, newImplementation)
              }
            }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.6.0;
          /**
           * @title Proxy
           * @dev Implements delegation of calls to other contracts, with proper
           * forwarding of return values and bubbling of failures.
           * It defines a fallback function that delegates all calls to the address
           * returned by the abstract _implementation() internal function.
           */
          abstract contract Proxy {
            /**
             * @dev Fallback function.
             * Implemented entirely in `_fallback`.
             */
            fallback () payable external {
              _fallback();
            }
            /**
             * @dev Receive function.
             * Implemented entirely in `_fallback`.
             */
            receive () payable external {
              _fallback();
            }
            /**
             * @return The Address of the implementation.
             */
            function _implementation() internal virtual view returns (address);
            /**
             * @dev Delegates execution to an implementation contract.
             * This is a low level function that doesn't return to its internal call site.
             * It will return to the external caller whatever the implementation returns.
             * @param implementation Address to delegate.
             */
            function _delegate(address implementation) internal {
              assembly {
                // Copy msg.data. We take full control of memory in this inline assembly
                // block because it will not return to Solidity code. We overwrite the
                // Solidity scratch pad at memory position 0.
                calldatacopy(0, 0, calldatasize())
                // Call the implementation.
                // out and outsize are 0 because we don't know the size yet.
                let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                // Copy the returned data.
                returndatacopy(0, 0, returndatasize())
                switch result
                // delegatecall returns 0 on error.
                case 0 { revert(0, returndatasize()) }
                default { return(0, returndatasize()) }
              }
            }
            /**
             * @dev Function that is run as the first thing in the fallback function.
             * Can be redefined in derived contracts to add functionality.
             * Redefinitions must call super._willFallback().
             */
            function _willFallback() internal virtual {
            }
            /**
             * @dev fallback implementation.
             * Extracted to enable manual triggering.
             */
            function _fallback() internal {
              _willFallback();
              _delegate(_implementation());
            }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.2 <0.8.0;
          /**
           * @dev Collection of functions related to the address type
           */
          library Address {
              /**
               * @dev Returns true if `account` is a contract.
               *
               * [IMPORTANT]
               * ====
               * It is unsafe to assume that an address for which this function returns
               * false is an externally-owned account (EOA) and not a contract.
               *
               * Among others, `isContract` will return false for the following
               * types of addresses:
               *
               *  - an externally-owned account
               *  - a contract in construction
               *  - an address where a contract will be created
               *  - an address where a contract lived, but was destroyed
               * ====
               */
              function isContract(address account) internal view returns (bool) {
                  // This method relies on extcodesize, which returns 0 for contracts in
                  // construction, since the code is only stored at the end of the
                  // constructor execution.
                  uint256 size;
                  // solhint-disable-next-line no-inline-assembly
                  assembly { size := extcodesize(account) }
                  return size > 0;
              }
              /**
               * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
               * `recipient`, forwarding all available gas and reverting on errors.
               *
               * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
               * of certain opcodes, possibly making contracts go over the 2300 gas limit
               * imposed by `transfer`, making them unable to receive funds via
               * `transfer`. {sendValue} removes this limitation.
               *
               * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
               *
               * IMPORTANT: because control is transferred to `recipient`, care must be
               * taken to not create reentrancy vulnerabilities. Consider using
               * {ReentrancyGuard} or the
               * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
               */
              function sendValue(address payable recipient, uint256 amount) internal {
                  require(address(this).balance >= amount, "Address: insufficient balance");
                  // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                  (bool success, ) = recipient.call{ value: amount }("");
                  require(success, "Address: unable to send value, recipient may have reverted");
              }
              /**
               * @dev Performs a Solidity function call using a low level `call`. A
               * plain`call` is an unsafe replacement for a function call: use this
               * function instead.
               *
               * If `target` reverts with a revert reason, it is bubbled up by this
               * function (like regular Solidity function calls).
               *
               * Returns the raw returned data. To convert to the expected return value,
               * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
               *
               * Requirements:
               *
               * - `target` must be a contract.
               * - calling `target` with `data` must not revert.
               *
               * _Available since v3.1._
               */
              function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                return functionCall(target, data, "Address: low-level call failed");
              }
              /**
               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
               * `errorMessage` as a fallback revert reason when `target` reverts.
               *
               * _Available since v3.1._
               */
              function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                  return functionCallWithValue(target, data, 0, errorMessage);
              }
              /**
               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
               * but also transferring `value` wei to `target`.
               *
               * Requirements:
               *
               * - the calling contract must have an ETH balance of at least `value`.
               * - the called Solidity function must be `payable`.
               *
               * _Available since v3.1._
               */
              function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                  return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
              }
              /**
               * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
               * with `errorMessage` as a fallback revert reason when `target` reverts.
               *
               * _Available since v3.1._
               */
              function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                  require(address(this).balance >= value, "Address: insufficient balance for call");
                  require(isContract(target), "Address: call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.call{ value: value }(data);
                  return _verifyCallResult(success, returndata, errorMessage);
              }
              /**
               * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
               * but performing a static call.
               *
               * _Available since v3.3._
               */
              function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                  return functionStaticCall(target, data, "Address: low-level static call failed");
              }
              /**
               * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
               * but performing a static call.
               *
               * _Available since v3.3._
               */
              function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                  require(isContract(target), "Address: static call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.staticcall(data);
                  return _verifyCallResult(success, returndata, errorMessage);
              }
              function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                  if (success) {
                      return returndata;
                  } else {
                      // Look for revert reason and bubble it up if present
                      if (returndata.length > 0) {
                          // The easiest way to bubble the revert reason is using memory via assembly
                          // solhint-disable-next-line no-inline-assembly
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert(errorMessage);
                      }
                  }
              }
          }
          

          File 8 of 9: NestDAO
          // SPDX-License-Identifier: GPL-3.0-or-later
          pragma solidity ^0.6.12;
          import "./lib/SafeMath.sol";
          import "./lib/TransferHelper.sol";
          import "./lib/ReentrancyGuard.sol";
          import "./iface/INestMining.sol";
          import "./iface/INToken.sol";
          import "./iface/INestPool.sol";
          import "./iface/INestDAO.sol";
          import "./iface/INestStaking.sol";
          import "./iface/INestQuery.sol";
          // import "hardhat/console.sol";
          /// @dev The contract is for redeeming nest token and getting ETH in return
          contract NestDAO is INestDAO, ReentrancyGuard {
              using SafeMath for uint256;
              /* ========== STATE ============== */
              uint8 public flag; 
              /// @dev the block height where DAO was started
              uint32  public startedBlock;
              uint32  public lastCollectingBlock;
              uint184 private _reserved;
              uint8 constant DAO_FLAG_UNINITIALIZED    = 0;
              uint8 constant DAO_FLAG_INITIALIZED      = 1;
              uint8 constant DAO_FLAG_ACTIVE           = 2;
              uint8 constant DAO_FLAG_NO_STAKING       = 3;
              uint8 constant DAO_FLAG_PAUSED           = 4;
              uint8 constant DAO_FLAG_SHUTDOWN         = 127;
              struct Ledger {
                  uint128 rewardedAmount;
                  uint128 redeemedAmount;
                  uint128 quotaAmount;
                  uint32  lastBlock;
                  uint96  _reserved;
              }
              /// @dev Mapping from ntoken => amount (of ntokens owned by DAO)
              mapping(address => Ledger) public ntokenLedger;
              /// @dev Mapping from ntoken => amount (of ethers owned by DAO)
              mapping(address => uint256) public ethLedger;
              /* ========== PARAMETERS ============== */
              uint256 public ntokenRepurchaseThreshold;
              uint256 public collectInterval;
              uint256 constant DAO_REPURCHASE_PRICE_DEVIATION = 5;  // price deviation < 5% 
              uint256 constant DAO_REPURCHASE_NTOKEN_TOTALSUPPLY = 5_000_000;  // total supply > 5 million 
              uint256 constant DAO_COLLECT_INTERVAL = 5_760;  // 24 hour * 60 min * 4 block/min ~= 1 day
              uint256 constant _ethFee = 0.01 ether;
              /* ========== ADDRESSES ============== */
              address public governance;
              address private C_NestPool;
              address private C_NestToken;
              address private C_NestMining;
              address private C_NestStaking;
              address private C_NestQuery;
              /* ========== CONSTRUCTOR ========== */
              receive() external payable {}
              // NOTE: to support open-zeppelin/upgrades, leave it blank
              constructor() public { }
              /// @dev It is called by the proxy (open-zeppelin/upgrades), only ONCE!
              function initialize(address NestPool) external 
              {
                  require(flag == DAO_FLAG_UNINITIALIZED, "Nest:DAO:!flag");
                  governance = msg.sender;
                  flag = DAO_FLAG_INITIALIZED;
                  C_NestPool = NestPool;
                  ntokenRepurchaseThreshold = DAO_REPURCHASE_NTOKEN_TOTALSUPPLY;
              }
              /* ========== MODIFIERS ========== */
              modifier onlyGovernance() 
              {
                  require(msg.sender == governance, "Nest:DAO:!governance");
                  _;
              }
              modifier onlyGovOrBy(address _contract) 
              {
                  require(msg.sender == governance || msg.sender == _contract, "Nest:DAO:!sender");
                  _;
              }
              modifier whenActive() 
              {
                  require(flag == DAO_FLAG_ACTIVE, "Nest:DAO:!flag");
                  _;
              }
              /* ========== GOVERNANCE ========== */
              /// @dev Ensure that all governance-addresses be consistent with each other
              function loadGovernance() override external 
              { 
                  governance = INestPool(C_NestPool).governance();
              }
              /// @dev The function loads all nest-contracts, it is supposed to be called by NestPool
              function loadContracts() override external onlyGovOrBy(C_NestPool)
              {
                  C_NestToken = INestPool(C_NestPool).addrOfNestToken();
                  C_NestStaking = INestPool(C_NestPool).addrOfNestStaking();
                  C_NestQuery = INestPool(C_NestPool).addrOfNestQuery();
                  C_NestMining = INestPool(C_NestPool).addrOfNestMining();
              }
              function start() override external onlyGovernance
              {  
                  require(flag == DAO_FLAG_INITIALIZED, "Nest:DAO:!flag");
                  ERC20(C_NestToken).approve(C_NestStaking, uint(-1));
                  startedBlock = uint32(block.number);
                  lastCollectingBlock = uint32(block.number);
                  flag = DAO_FLAG_ACTIVE;
                  collectInterval = DAO_COLLECT_INTERVAL;
                  emit FlagSet(address(msg.sender), uint256(DAO_FLAG_ACTIVE));
              }
              /// @dev Stop service for emergency
              function pause() external onlyGovernance
              {
                  require(flag == DAO_FLAG_ACTIVE, "Nest:DAO:!flag");
                  flag = DAO_FLAG_PAUSED;
                  emit FlagSet(address(msg.sender), uint256(DAO_FLAG_PAUSED));
              }
              /// @dev Resume service 
              function resume() external onlyGovernance
              {
                  require(flag == DAO_FLAG_ACTIVE || flag == DAO_FLAG_PAUSED, "Nest:DAO:!flag");
                  flag = DAO_FLAG_ACTIVE;
                  emit FlagSet(address(msg.sender), uint256(DAO_FLAG_ACTIVE));
              }
              function setParams(uint256 _ntokenRepurchaseThreshold, uint256 _collectInterval) external onlyGovernance
              {
                  emit ParamsSetup(address(msg.sender), ntokenRepurchaseThreshold, _ntokenRepurchaseThreshold);
                  ntokenRepurchaseThreshold = _ntokenRepurchaseThreshold;
                  emit ParamsSetup(address(msg.sender), collectInterval, _collectInterval);
                  collectInterval = _collectInterval;
              }
              function totalETHRewards(address ntoken)
                  external view returns (uint256) 
              {
                 return  ethLedger[ntoken];
              }
              /// @notice Migrate ethers to a new NestDAO
              /// @param newDAO_ The address of the new contract
              /// @param ntokenL_ The list of ntokens whose ethers are going to be migrated
              function migrateTo(address newDAO_, address[] memory ntokenL_) external onlyGovernance
              {
                  require(flag == DAO_FLAG_PAUSED, "Nest:DAO:!flag");
                  uint256 _len = ntokenL_.length;
                  for (uint256 i; i < _len; i++) {
                      address _ntoken = ntokenL_[i];
                      uint256 _blncs = ethLedger[_ntoken];
                      INestDAO(newDAO_).addETHReward{value:_blncs}(_ntoken);
                      
                      ethLedger[_ntoken] = 0;
                      uint256 _staked = INestStaking(C_NestStaking).stakedBalanceOf(_ntoken, address(this));
                      if (_staked > 0) {
                          INestStaking(C_NestStaking).unstake(_ntoken, _staked);
                      }
                      uint256 _ntokenAmount = ERC20(_ntoken).balanceOf(address(this));
                      if (_ntokenAmount > 0) {
                          ERC20(_ntoken).transfer(newDAO_, _ntokenAmount);
                      }
                  }
              }
              /// @dev The function shall be called when ethers are taken from Nestv3.0
              function initEthLedger(address ntoken, uint256 amount) 
                  override external
                  onlyGovernance 
              {
                  require (flag == DAO_FLAG_INITIALIZED, "Nest:DAO:!flag");
                  ethLedger[ntoken] = amount;
              }
              /* ========== MAIN ========== */
              /// @notice Pump eth rewards to NestDAO for repurchasing `ntoken`
              /// @param ntoken The address of ntoken in the ether Ledger
              function addETHReward(address ntoken) 
                  override
                  external
                  payable
              {
                  ethLedger[ntoken] = ethLedger[ntoken].add(msg.value);
              }
              /// @dev Called by NestMining
              function addNestReward(uint256 amount) 
                  override 
                  external 
                  onlyGovOrBy(C_NestMining)
              {
                  Ledger storage it = ntokenLedger[C_NestToken];
                  it.rewardedAmount = uint128(uint256(it.rewardedAmount).add(amount));
              }
              /// @dev Collect ethers from NestPool
              function collectNestReward() public returns(uint256)
              {
                  // withdraw NEST from NestPool (mined by miners)
                  uint256 nestAmount = INestPool(C_NestPool).balanceOfTokenInPool(address(this), C_NestToken);
                  if (nestAmount == 0) {
                      return 0;
                  }
                  INestPool(C_NestPool).withdrawNest(address(this), nestAmount);
                  return nestAmount;
              }
              /// @dev Collect ethers from NestStaking
              function collectETHReward(address ntoken) public returns (uint256)
              {
                  // check if ntoken is a NTOKEN
                  address _ntoken = INestPool(C_NestPool).getNTokenFromToken(ntoken);
                  require (_ntoken == ntoken, "Nest:DAO:!ntoken");
                  uint256 ntokenAmount = ERC20(ntoken).balanceOf(address(this));
                  // if (ntokenAmount == 0) {
                  //     return 0;
                  // }
                  // // stake new NEST/NTOKENs into StakingPool
                  // INestStaking(C_NestStaking).stake(ntoken, ntokenAmount);
                  if (ntokenAmount != 0) {
                      // stake new NEST/NTOKENs into StakingPool
                      INestStaking(C_NestStaking).stake(ntoken, ntokenAmount);
                  }
                  // claim rewards from StakingPool 
                  uint256 _rewards = INestStaking(C_NestStaking).claim(ntoken);
                  ethLedger[ntoken] = ethLedger[ntoken].add(_rewards);
                  return _rewards;
              }
              function _collect(address ntoken) internal
              {
                  if (block.number < uint256(lastCollectingBlock).add(collectInterval)) {
                      return;
                  }
                  uint256 ethAmount = collectETHReward(ntoken);
                  
                  uint256 nestAmount = collectNestReward();
                  
                  lastCollectingBlock = uint32(block.number);
                  emit AssetsCollected(address(msg.sender), ethAmount, nestAmount);
              }
              /// @dev Redeem ntokens for ethers
              function redeem(address ntoken, uint256 amount) 
                  external payable nonReentrant whenActive
              {
                  // check if ntoken is a NTOKEN
                  address _ntoken = INestPool(C_NestPool).getNTokenFromToken(ntoken);
                  require (_ntoken == ntoken, "Nest:DAO:!ntoken");
                  require (msg.value >= _ethFee, "Nest:DAO:!ethFee");
                  require(INToken(ntoken).totalSupply() >= ntokenRepurchaseThreshold, "Nest:DAO:!total");
                  // check if there is sufficient ethers for repurchase
                  uint256 bal = ethLedger[ntoken];
                  require(bal > 0, "Nest:DAO:!bal");
                  // check the repurchasing quota
                  uint256 quota = quotaOf(ntoken);
                  // check if the price is steady
                  uint256 price;
                  bool isDeviated;
                  
                  
                  {
                      (uint256 ethAmount, uint256 tokenAmount,) = INestMining(C_NestMining).latestPriceOf(ntoken);
                      (, uint256 avg, ,) = INestMining(C_NestMining).priceAvgAndSigmaOf(ntoken);
                      price = tokenAmount.mul(1e18).div(ethAmount);
                      uint256 diff = price > avg? (price - avg) : (avg - price);
                      isDeviated = (diff.mul(100) < avg.mul(DAO_REPURCHASE_PRICE_DEVIATION))? false : true;
                      if(msg.value > _ethFee){
                          TransferHelper.safeTransferETH(msg.sender, msg.value.sub(_ethFee));
                      }
                      this.addETHReward{value:_ethFee}(address(ntoken));
                  }
                  require(isDeviated == false, "Nest:DAO:!price");
                  // check if there is sufficient quota for repurchase
                  require (amount <= quota, "Nest:DAO:!quota");
                  // amount.mul(1e18).div(price) < bal
                  require (amount.mul(1e18) <= bal.mul(price), "Nest:DAO:!bal2");
                  // update the ledger
                  Ledger memory it = ntokenLedger[ntoken];
                  it.redeemedAmount = uint128(amount.add(it.redeemedAmount));
                  it.quotaAmount = uint128(quota.sub(amount));
                  it.lastBlock = uint32(block.number);
                  ntokenLedger[ntoken] = it;
                  // transactions
                  ethLedger[ntoken] = ethLedger[ntoken].sub(amount.mul(1e18).div(price));
                  ERC20(ntoken).transferFrom(address(msg.sender), address(this), amount);
                  TransferHelper.safeTransferETH(msg.sender, amount.mul(1e18).div(price));
                  _collect(ntoken); 
              }
              // function _price(address ntoken) internal view 
              //     returns (uint256 price, uint256 avg, bool isDeviated)
              // {
              //     (price, avg, , ) = 
              //         INestQuery(C_NestQuery).queryPriceAvgVola(ntoken, );
              //     uint256 diff = price > avg? (price - avg) : (avg - price);
              //     isDeviated = (diff.mul(100) < avg.mul(DAO_REPURCHASE_PRICE_DEVIATION))? false : true;
              // }
              function _quota(address ntoken) internal view returns (uint256 quota) 
              {
                  if (INToken(ntoken).totalSupply() < ntokenRepurchaseThreshold) {
                      return 0;
                  }
                  //  calculate the accumulated amount of NEST/NTOKEN available to repurchasing
                  Ledger memory it = ntokenLedger[ntoken];
                  uint256 _acc;
                  uint256 n;
                  if(ntoken == C_NestToken){
                       n = 1000;
                      uint256 intv = (it.lastBlock == 0) ? 
                          (block.number).sub(startedBlock) : (block.number).sub(uint256(it.lastBlock));
                      _acc = (n * intv > 300_000)? 300_000 : (n * intv);
                  }else{
                      n = 10;
                      uint256 intv = (it.lastBlock == 0) ? 
                          (block.number).sub(startedBlock) : (block.number).sub(uint256(it.lastBlock));
                      _acc = (n * intv > 3000)? 3000 : (n * intv);
                  }
                  uint256 total;
                   total = _acc.mul(1e18).add(it.quotaAmount);
                  if(ntoken == C_NestToken){
                      if(total > uint256(300_000).mul(1e18)){
                          quota = uint256(300_000).mul(1e18);
                      }else{
                          quota = total;
                      }   
                  }else{
                      if(total > uint256(3000).mul(1e18)){
                          quota = uint256(3000).mul(1e18);
                      }else{
                          quota = total;
                      }   
                  }
                  
              }
              /* ========== VIEWS ========== */
              function quotaOf(address ntoken) public view returns (uint256 quota) 
              {
                 // check if ntoken is a NTOKEN
                  address _ntoken = INestPool(C_NestPool).getNTokenFromToken(ntoken);
                  require (_ntoken == ntoken, "Nest:DAO:!ntoken");
                  return _quota(ntoken);
              }
          }// 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;
          // 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: MIT
          pragma solidity ^0.6.0;
          /// @dev The non-empty constructor is conflict with upgrades-openzeppelin. 
          /**
           * @dev Contract module that helps prevent reentrant calls to a function.
           *
           * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
           * available, which can be applied to functions to make sure there are no nested
           * (reentrant) calls to them.
           *
           * Note that because there is a single `nonReentrant` guard, functions marked as
           * `nonReentrant` may not call one another. This can be worked around by making
           * those functions `private`, and then adding `external` `nonReentrant` entry
           * points to them.
           *
           * TIP: If you would like to learn more about reentrancy and alternative ways
           * to protect against it, check out our blog post
           * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
           */
          contract ReentrancyGuard {
              // Booleans are more expensive than uint256 or any type that takes up a full
              // word because each write operation emits an extra SLOAD to first read the
              // slot's contents, replace the bits taken up by the boolean, and then write
              // back. This is the compiler's defense against contract upgrades and
              // pointer aliasing, and it cannot be disabled.
              // The values being non-zero value makes deployment a bit more expensive,
              // but in exchange the refund on every call to nonReentrant will be lower in
              // amount. Since refunds are capped to a percentage of the total
              // transaction's gas, it is best to keep them low in cases like this one, to
              // increase the likelihood of the full refund coming into effect.
              // NOTE: _NOT_ENTERED is set to ZERO such that it needn't constructor
              uint256 private constant _NOT_ENTERED = 0;
              uint256 private constant _ENTERED = 1;
              uint256 private _status;
              // constructor () internal {
              //     _status = _NOT_ENTERED;
              // }
              /**
               * @dev Prevents a contract from calling itself, directly or indirectly.
               * Calling a `nonReentrant` function from another `nonReentrant`
               * function is not supported. It is possible to prevent this from happening
               * by making the `nonReentrant` function external, and make it call a
               * `private` function that does the actual work.
               */
              modifier nonReentrant() {
                  // On the first call to nonReentrant, _notEntered will be true
                  require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
                  // Any calls to nonReentrant after this point will fail
                  _status = _ENTERED;
                  _;
                  // By storing the original value once again, a refund is triggered (see
                  // https://eips.ethereum.org/EIPS/eip-2200)
                  _status = _NOT_ENTERED;
              }
          }// 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 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;
          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 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 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;
          /// @title The interface of NestQuery
          /// @author Inf Loop - <[email protected]>
          /// @author Paradox  - <[email protected]>
          interface INestQuery {
              /// @notice Activate a pay-per-query defi client with NEST tokens
              /// @dev No contract is allowed to call it
              /// @param defi The addres of client (DeFi DApp)
              function activate(address defi) external;
              /// @notice Deactivate a pay-per-query defi client
              /// @param defi The address of a client (DeFi DApp)
              function deactivate(address defi) external;
              /// @notice Query for PPQ (pay-per-query) clients
              /// @dev Consider that if a user call a DeFi that queries NestQuery, DeFi should
              ///     pass the user's wallet address to query() as `payback`.
              /// @param token The address of token contract
              /// @param payback The address of change
              function query(address token, address payback) 
                  external payable returns (uint256, uint256, uint256);
              /// @notice Query for PPQ (pay-per-query) clients
              /// @param token The address of token contract
              /// @param payback The address of change
              /// @return ethAmount The amount of ETH in pair (ETH, TOKEN)
              /// @return tokenAmount The amount of TOKEN in pair (ETH, TOKEN)
              /// @return avgPrice The average of last 50 prices 
              /// @return vola The volatility of prices 
              /// @return bn The block number when (ETH, TOKEN) takes into effective
              function queryPriceAvgVola(address token, address payback) 
                  external payable returns (uint256, uint256, uint128, int128, uint256);
              /// @notice The main function called by DeFi clients, compatible to Nest Protocol v3.0 
              /// @dev  The payback address is ZERO, so the changes are kept in this contract
              ///         The ABI keeps consist with Nest v3.0
              /// @param tokenAddress The address of token contract address
              /// @return ethAmount The amount of ETH in price pair (ETH, ERC20)
              /// @return erc20Amount The amount of ERC20 in price pair (ETH, ERC20)
              /// @return blockNum The block.number where the price is being in effect
              function updateAndCheckPriceNow(address tokenAddress) 
                  external payable returns (uint256, uint256, uint256);
              /// @notice A non-free function for querying price 
              /// @param token  The address of the token contract
              /// @param num    The number of price sheets in the list
              /// @param payback The address for change
              /// @return The array of prices, each of which is (blockNnumber, ethAmount, tokenAmount)
              function queryPriceList(address token, uint8 num, address payback) 
                  external payable returns (uint128[] memory);
              /// @notice A view function returning the historical price list from the current block
              /// @param token  The address of the token contract
              /// @param num    The number of price sheets in the list
              /// @return The array of prices, each of which is (blockNnumber, ethAmount, tokenAmount)
              function priceList(address token, uint8 num) 
                  external view returns (uint128[] memory);
              /// @notice A view function returning the latestPrice
              /// @param token  The address of the token contract
              function latestPrice(address token)
              external view returns (uint256 ethAmount, uint256 tokenAmount, uint128 avgPrice, int128 vola, uint256 bn) ;
              /// @dev Only for governance
              function loadContracts() external; 
              /// @dev Only for governance
              function loadGovernance() external; 
              event ClientActivated(address, uint256, uint256);
              // event ClientRenewed(address, uint256, uint256, uint256);
              event PriceQueried(address client, address token, uint256 ethAmount, uint256 tokenAmount, uint256 bn);
              event PriceAvgVolaQueried(address client, address token, uint256 bn, uint128 avgPrice, int128 vola);
              event PriceListQueried(address client, address token, uint256 bn, uint8 num);
              // governance events
              event ParamsSetup(address gov, uint256 oldParams, uint256 newParams);
              event FlagSet(address gov, uint256 flag);
          }// 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;
          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");
              }
          }

          File 9 of 9: MiningV1Calc
          // 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 - <[email protected]>
          /// @author Paradox  - <[email protected]>
          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;
          // 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 <[email protected]>
           */
          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;
                }
              }
            }
          }// 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 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 - <[email protected]>
          /// @author Paradox  - <[email protected]>
          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;
          import "../iface/INestPool.sol";
          import "../iface/INestStaking.sol";
          import "../iface/INToken.sol";
          import "../iface/INNRewardPool.sol";
          import "../lib/SafeERC20.sol";
          /// @author Inf Loop - <[email protected]>
          /// @author 0x00  - <[email protected]>
          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;
          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");
              }
          }