Transaction Hash:
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 | ||
---|---|---|---|---|---|
0x105ee568...387dfFB4f | 179.102896402874595432 Eth | 179.122696402874595432 Eth | 0.0198 | ||
0x243f207F...35aa7b8f6 | (NEST Protocol: Nest Mining V1 Proxy) | ||||
0x829BD824...93333A830
Miner
| (F2Pool Old) | 2,823.060637086919751878 Eth | 2,823.089249948119751878 Eth | 0.0286128612 | |
0xaA7A74a4...6a8aa84eC | 312.919468651936202792 Eth | 312.998668651936202792 Eth | 0.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.0792
ETH 0.0198
AdminUpgradeabilityProxy.daa78c0f( )
- ETH 0.0198
NestDAO.addETHReward( ntoken=0x04abEdA201850aC0124161F037Efd70c74ddC74C )
- ETH 0.0198
-
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( )
-
NestDAO.addNestReward( amount=473600000000000000000 )
-
- ETH 0.099
MiningV1Calc.7b576fc9( )
- ETH 0.099
MiningV1Calc.7b576fc9( )
-
post2[NestMiningV1 (ln:332)]
getNTokenFromToken[NestMiningV1 (ln:345)]
div[NestMiningV1 (ln:348)]
mul[NestMiningV1 (ln:348)]
mul[NestMiningV1 (ln:348)]
sub[NestMiningV1 (ln:352)]
depositEth[NestMiningV1 (ln:353)]
sub[NestMiningV1 (ln:353)]
addETHReward[NestMiningV1 (ln:360)]
div[NestMiningV1 (ln:360)]
mul[NestMiningV1 (ln:360)]
addETHReward[NestMiningV1 (ln:362)]
div[NestMiningV1 (ln:362)]
mul[NestMiningV1 (ln:362)]
addETHReward[NestMiningV1 (ln:365)]
div[NestMiningV1 (ln:365)]
mul[NestMiningV1 (ln:365)]
addETHReward[NestMiningV1 (ln:367)]
div[NestMiningV1 (ln:367)]
mul[NestMiningV1 (ln:367)]
addETHReward[NestMiningV1 (ln:369)]
div[NestMiningV1 (ln:369)]
mul[NestMiningV1 (ln:369)]
freezeEthAndToken[NestMiningV1 (ln:372)]
mul[NestMiningV1 (ln:372)]
mul[NestMiningV1 (ln:373)]
freezeEthAndToken[NestMiningV1 (ln:374)]
mul[NestMiningV1 (ln:374)]
mul[NestMiningV1 (ln:375)]
freezeNest[NestMiningV1 (ln:376)]
mul[NestMiningV1 (ln:376)]
mul[NestMiningV1 (ln:376)]
push[NestMiningV1 (ln:390)]
PriceSheet[NestMiningV1 (ln:390)]
push[NestMiningV1 (ln:406)]
PriceSheet[NestMiningV1 (ln:406)]
PricePosted[NestMiningV1 (ln:420)]
mul[NestMiningV1 (ln:420)]
mul[NestMiningV1 (ln:420)]
PricePosted[NestMiningV1 (ln:421)]
mul[NestMiningV1 (ln:421)]
mul[NestMiningV1 (ln:421)]
div[NestMiningV1 (ln:438)]
mul[NestMiningV1 (ln:438)]
addNest[NestMiningV1 (ln:440)]
div[NestMiningV1 (ln:440)]
mul[NestMiningV1 (ln:440)]
addNNReward[NestMiningV1 (ln:441)]
div[NestMiningV1 (ln:441)]
mul[NestMiningV1 (ln:441)]
addNest[NestMiningV1 (ln:443)]
div[NestMiningV1 (ln:443)]
mul[NestMiningV1 (ln:443)]
addNestReward[NestMiningV1 (ln:444)]
div[NestMiningV1 (ln:444)]
mul[NestMiningV1 (ln:444)]
add[NestMiningV1 (ln:447)]
mineNToken[NestMiningV1 (ln:458)]
checkBidder[NestMiningV1 (ln:460)]
mint[NestMiningV1 (ln:466)]
increaseTotal[NestMiningV1 (ln:470)]
transfer[NestMiningV1 (ln:472)]
div[NestMiningV1 (ln:474)]
mul[NestMiningV1 (ln:474)]
addNToken[NestMiningV1 (ln:476)]
sub[NestMiningV1 (ln:476)]
add[NestMiningV1 (ln:480)]
_stat[NestMiningV1 (ln:486)]
_stat[NestMiningV1 (ln:487)]
File 1 of 9: AdminUpgradeabilityProxy
File 2 of 9: NNRewardPool
File 3 of 9: NestMiningV1
File 4 of 9: NestPool
File 5 of 9: AdminUpgradeabilityProxy
File 6 of 9: NestStaking
File 7 of 9: AdminUpgradeabilityProxy
File 8 of 9: NestDAO
File 9 of 9: MiningV1Calc
// 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"); } }