Feature Tip: Add private address tag to any address under My Name Tag !
Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 9 from a total of 9 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Set Gov | 11684796 | 1860 days ago | IN | 0 ETH | 0.0127341 | ||||
| Transfer ETH | 11684793 | 1860 days ago | IN | 0 ETH | 0.0049602 | ||||
| Transfer ETH Fro... | 11684771 | 1860 days ago | IN | 0 ETH | 0.0214251 | ||||
| Switch On Nest35 | 11684581 | 1860 days ago | IN | 0 ETH | 0.02289585 | ||||
| Transfer ETH | 11684577 | 1860 days ago | IN | 0 ETH | 0.0049602 | ||||
| Transfer ETH Fro... | 11684557 | 1860 days ago | IN | 0 ETH | 0.56110171 | ||||
| Transfer Nest Fr... | 11684541 | 1860 days ago | IN | 0 ETH | 0.0447372 | ||||
| Setup Params Of ... | 11684505 | 1860 days ago | IN | 0 ETH | 0.02908305 | ||||
| Set Pairs Of Tok... | 11684222 | 1860 days ago | IN | 0 ETH | 0.22914262 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| - | 11684793 | 1860 days ago | 4,223.35555755 ETH | ||||
| - | 11684771 | 1860 days ago | 4,142.9645335 ETH | ||||
| - | 11684771 | 1860 days ago | 80.39102404 ETH | ||||
| - | 11684577 | 1860 days ago | 69.55534054 ETH | ||||
| - | 11684557 | 1860 days ago | 0.14481595 ETH | ||||
| - | 11684557 | 1860 days ago | 0.15471882 ETH | ||||
| - | 11684557 | 1860 days ago | 0.3677678 ETH | ||||
| - | 11684557 | 1860 days ago | 0.24782964 ETH | ||||
| - | 11684557 | 1860 days ago | 0.06436596 ETH | ||||
| - | 11684557 | 1860 days ago | 0.00427389 ETH | ||||
| - | 11684557 | 1860 days ago | 0.06315752 ETH | ||||
| - | 11684557 | 1860 days ago | 0.06000003 ETH | ||||
| - | 11684557 | 1860 days ago | 0.00000005 ETH | ||||
| - | 11684557 | 1860 days ago | 0.03906665 ETH | ||||
| - | 11684557 | 1860 days ago | 0.00412309 ETH | ||||
| - | 11684557 | 1860 days ago | 0.08256707 ETH | ||||
| - | 11684557 | 1860 days ago | 0.07737544 ETH | ||||
| - | 11684557 | 1860 days ago | 0.22416242 ETH | ||||
| - | 11684557 | 1860 days ago | 0.13759911 ETH | ||||
| - | 11684557 | 1860 days ago | 0.14461628 ETH | ||||
| - | 11684557 | 1860 days ago | 0.06944746 ETH | ||||
| - | 11684557 | 1860 days ago | 0.06901916 ETH | ||||
| - | 11684557 | 1860 days ago | 0.06947426 ETH | ||||
| - | 11684557 | 1860 days ago | 0.01503232 ETH | ||||
| - | 11684557 | 1860 days ago | 0.08432439 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
NestUpgrade
Compiler Version
v0.6.12+commit.27d51765
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "./lib/SafeMath.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";
import "./iface/INest_3_Abonus.sol";
import "./iface/INest_3_Leveling.sol";
import "./iface/INest_3_MiningContract.sol";
import "./iface/INest_NToken_TokenAuction.sol";
import "./iface/INest_NToken_TokenMapping.sol";
// import "hardhat/console.sol";
/*
steps:
Attention: no new quote pairs are allowed when executing upgrade contracts !!!
//==================== set params ====================//
1. nest3Admin: Set nest3Admin address to NestUpgrade.address
2. nest3.5: gov: NestPool.setGovernance(NestUpgrade.address)
3. nest3.5: NestUpgrade.setPairsOfTokens(..., tokanL), can be run multiple times,
all token-ntoken settings must be completed before proceeding to the next step,
USDT-NEST included. tokenL[i] != USDT.address
4. nest3.5: NestUpgrade.SetupParamsOfNestMining(...), this function can only be
executed once
//========================================================//
Attention: nest 3 stops running when funds are transferred !!!!
//===================== transfer funds ===================//
5. nest3.5: gov: NestPool.setGovernance(NestUpgrade.address)
6. nest3.5: NestUpgrade.transferNestFromNest3(), transfer NEST(umined) to NestPool
if failed:
all right, no funds are transferred to the new contract at this time;
if succeeded:
go to next step;
7. nest3.5: gov: NestPool.setGovernance(NestUpgrade.address)
8. nest3.5: NestUpgrade.transferETHFromNest3(...), transfer ETH to address(this),
can be run multiple times, each tokens should be applied once, USDT must be included
if falied:
run NestUpgrade.transferNestInUrgent() to revert
if succeeded:
go to next step
9. nest3.5: NestUpgrade.transferETHToNestDAO(...), transfer ETH to NestDAO.addr,
if failed: can run NestUpgrade.transferETH()
if succeeded: next step
10. nest3.5: NestUpgrade.initNest35(), NestMining.upgrade() / NestDAO.start()
if failed: NestDAO.migrateTo(...), transfer eth to new DAO
if succeeded: end
*/
contract NestUpgrade {
using SafeMath for uint256;
address public governance;
address public C_NestToken;
address public C_NestPool;
address public C_NestMining;
address public C_NestDAO;
uint8 public flag;
uint256 public latestHeight;
uint256 public nestBal;
uint256 public minedNestAmount;
uint256 public nest;
uint256 public tokenNum; // Nest_NToken_TokenAuction.checkTokenNum()
uint256 public ntoken_num1 = 0; // record how many pairs of tokens have been set
// finally,the value should be equal to
// Nest_NToken_TokenAuction.checkTokenNum()
uint256 public ntoken_num2 = 0; // record the number of tokens for which funds have been transferred
uint256 constant total_nest = 10_000_000_000; // total nest == 10 billion
mapping(address => address) _token_ntoken_mapping;
receive() external payable {}
modifier onlyGovernance()
{
require(msg.sender == governance, "Nest:Upg:!gov");
_;
}
constructor(address NestPool) public
{
governance = msg.sender;
C_NestPool = NestPool;
flag = 0;
}
function shutdown() public onlyGovernance
{
flag = 2;
}
function resume() public onlyGovernance
{
flag = 0;
}
/// @notice Upgrade from Nest v3.0 to v3.5
/// @dev setNtokenToToken(token, ntoken)
/// If the number of ntokens is too large
/// and gas consumption exceeds the limit,
/// you can execute setPairsOfTokens() multiple times.
/// open new ntoken in nest3 should not be allowed.
function setPairsOfTokens(
address usdtToken,
address Nest_NToken_TokenMapping,
address[] memory tokenL) public onlyGovernance
{
address[] memory ntokenL = new address[](tokenL.length);
require(flag < 2, "Nest:Upg:!flag");
require(tokenL.length == ntokenL.length, "Ntoken:Upg:!len");
for(uint i=0; i<tokenL.length; i++)
{
require(tokenL[i] != usdtToken, "Token:Upg:!USDT");
ntokenL[i] = INest_NToken_TokenMapping(Nest_NToken_TokenMapping).checkTokenMapping(tokenL[i]);
require(ntokenL[i] != address(0), "Ntoken:Upg:!addr");
}
INestPool _C_NestPool = INestPool(C_NestPool);
C_NestToken = _C_NestPool.addrOfNestToken();
if(_C_NestPool.getNTokenFromToken(usdtToken) == address(0))
{
_C_NestPool.setNTokenToToken(usdtToken, C_NestToken);
ntoken_num1 += 1;
}
for (uint i = 0; i < tokenL.length; i++)
{
require(ntokenL[i] != C_NestToken, "Ntoken:Upg: !nest");
if(_C_NestPool.getNTokenFromToken(tokenL[i]) == address(0))
{
_C_NestPool.setNTokenToToken(tokenL[i], ntokenL[i]);
ntoken_num1 += 1;
}
}
return;
}
/// @notice Set up params about NestMining
/// @dev This function can only be executed once
function setupParamsOfNestMining(
address Nest_3_MiningContract,
address Nest_NToken_TokenAuction,
address Nest_NToken_TokenMapping,
INestMining.Params memory params
) public onlyGovernance
{
uint32 genesisBlockNumber = 6236588;
uint256 latestMiningHeight;
uint256 nestBalance;
uint256 minedNestTotalAmount;
require(flag < 2, "Nest:Upg:!flag");
tokenNum = INest_NToken_TokenAuction(Nest_NToken_TokenAuction).checkTokenNum();
require(tokenNum == ntoken_num1, "ntoken_num1:Upg: !sufficient");
latestMiningHeight = INest_3_MiningContract(Nest_3_MiningContract).checkLatestMining();
nestBalance = INest_3_MiningContract(Nest_3_MiningContract).checkNestBalance();
minedNestTotalAmount = uint256(total_nest).mul(1e18).sub(nestBalance);
INestPool _C_NestPool = INestPool(C_NestPool);
C_NestMining = _C_NestPool.addrOfNestMining();
INestMining(C_NestMining).loadGovernance();
INestMining(C_NestMining).setup(genesisBlockNumber, uint128(latestMiningHeight), uint128(minedNestTotalAmount), params);
_C_NestPool.setGovernance(governance);
INestMining(C_NestMining).loadGovernance();
return;
}
/// @dev Transfer nest from nest3 to nest3.5
/// @param Nest_3_MiningContract Address of Nest_3_MiningContract
function transferNestFromNest3(address Nest_3_MiningContract) public onlyGovernance
{
require(flag < 2, "Nest:Upg:!flag");
INestPool _C_NestPool = INestPool(C_NestPool);
C_NestToken = _C_NestPool.addrOfNestToken();
C_NestMining = _C_NestPool.addrOfNestMining();
// set latestMiningHeight and minedNestTotalAmount
latestHeight = INest_3_MiningContract(Nest_3_MiningContract).checkLatestMining();
nestBal = INest_3_MiningContract(Nest_3_MiningContract).checkNestBalance();
minedNestAmount = uint256(total_nest).mul(1e18).sub(nestBal);
require(latestHeight > 0, "LatestHeight:Upg: err");
INestMining(C_NestMining).setParams1(uint128(latestHeight), uint128(minedNestAmount));
// send nest to nestpool.addr
INest_3_MiningContract(Nest_3_MiningContract).takeOutNest(C_NestPool);
nest = ERC20(C_NestToken).balanceOf(C_NestPool);
_C_NestPool.initNestLedger(nest);
_C_NestPool.setGovernance(governance);
INestMining(C_NestMining).loadGovernance();
return;
}
/// @notice Transfer NEST from nest3 to nest3.5
/// @param Nest_3_MiningContract Address of Nest_3_MiningContract
/// @param Nest_NToken_TokenAuction Address of Nest_NToken_TokenAuction
/// @param Nest_3_Abonus Address of Nest_NToken_TokenMapping
/// @param Nest_3_Leveling Address of Nest_NToken_TokenMapping
/// @param tokenL Lists of tokens addresses, usdt included
/// @dev This function could be executed many times
function transferETHFromNest3(
address Nest_3_MiningContract,
address Nest_NToken_TokenAuction,
address Nest_3_Abonus,
address Nest_3_Leveling,
address[] memory tokenL
) public onlyGovernance
{
address[] memory ntokenL = new address[](tokenL.length);
require(flag < 2, "Nest:Upg:!flag");
INestPool _C_NestPool = INestPool(C_NestPool);
C_NestToken = _C_NestPool.addrOfNestToken();
C_NestMining = _C_NestPool.addrOfNestMining();
C_NestDAO = _C_NestPool.addrOfNestDAO();
INestMining(C_NestMining).loadGovernance();
INestDAO(C_NestDAO).loadGovernance();
for(uint i=0; i<tokenL.length; i++){
ntokenL[i] = _C_NestPool.getNTokenFromToken(tokenL[i]);
require(ntokenL[i] != address(0), "Ntoken:Upg: err");
}
require(tokenL.length == ntokenL.length, "Ntoken:Upg:!len");
for(uint i=0; i < ntokenL.length; i++)
{
if(_token_ntoken_mapping[tokenL[i]] == address(0))
{
uint256 amount = 0;
uint256 amount_bonus = 0;
uint256 amount_leveling = 0;
amount_bonus = INest_3_Abonus(Nest_3_Abonus).getETHNum(ntokenL[i]);
if(amount_bonus > 0)
{
INest_3_Abonus(Nest_3_Abonus).turnOutAllEth(amount_bonus, address(this));
}
amount_leveling = INest_3_Leveling(Nest_3_Leveling).checkEthMapping(ntokenL[i]);
if(amount_leveling > 0)
{
INest_3_Leveling(Nest_3_Leveling).turnOutAllEth(amount_leveling, address(this));
}
amount = amount_bonus.add(amount_leveling);
if(amount > 0)
{
INestDAO(C_NestDAO).initEthLedger(ntokenL[i], amount);
}
_token_ntoken_mapping[tokenL[i]] = ntokenL[i];
ntoken_num2 += 1;
}
}
return;
}
/// @notice Transfer ETH to NestDAO
/// @param NestDAO Address of NestDAO contract
/// @param Nest_NToken_TokenAuction Address of Nest_NToken_TokenAuction
/// @dev All ETH(ntoken) must be transfered to address(this)
function transferETHToNestDAO(address NestDAO, address Nest_NToken_TokenAuction)
public onlyGovernance
{
tokenNum = INest_NToken_TokenAuction(Nest_NToken_TokenAuction).checkTokenNum();
require(tokenNum == ntoken_num2, "ntoken_num2:Upg: !sufficient");
(bool success, ) = NestDAO.call{value: address(this).balance}(new bytes(0));
require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
}
/// @dev Initialize nest3.5, NestMining.upgrade() / NestDAO.start()
/// @dev This function can only be executed once
/// @dev New ntoken not turned on at this time, set ntokenCounter by C_NTokenController.start(...)
function switchOnNest35() public onlyGovernance
{
require(flag < 2, "Nest:Upg:!flag");
INestPool _C_NestPool = INestPool(C_NestPool);
C_NestToken = _C_NestPool.addrOfNestToken();
C_NestMining = _C_NestPool.addrOfNestMining();
C_NestDAO = _C_NestPool.addrOfNestDAO();
INestMining(C_NestMining).loadGovernance();
INestDAO(C_NestDAO).loadGovernance();
// start nest3.5
INestMining(C_NestMining).upgrade();
INestDAO(C_NestDAO).loadContracts();
_C_NestPool.setGovernance(governance);
INestMining(C_NestMining).loadGovernance();
INestDAO(C_NestDAO).loadGovernance();
return;
}
//================== urgent, if deployment failed ================//
/// @dev If the upgrading failed, transfer ETH to an temporary address
function transferETH(address to) public onlyGovernance
{
(bool success, ) = to.call{value: address(this).balance}(new bytes(0));
require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
}
/// @dev if the upgrading failed, withdraw nest from nestpool
/// @param to Address where you want to transfer
/// @param amount NEST amount
/// @param upgrade Address of NestUpgrade
function transferNestInUrgent(address to, uint256 amount, address upgrade)
public onlyGovernance
{
require(flag < 2, "Nest:Upg:!flag");
INestPool _C_NestPool = INestPool(C_NestPool);
_C_NestPool.drainNest(to, amount, upgrade);
}
///@dev set NestPool gov
/// NestPool.setGovernance(NestUpgrade.address) at first
function setGov() public onlyGovernance
{
INestPool _C_NestPool = INestPool(C_NestPool);
_C_NestPool.setGovernance(governance);
C_NestMining = _C_NestPool.addrOfNestMining();
C_NestDAO = _C_NestPool.addrOfNestDAO();
INestMining(C_NestMining).loadGovernance();
INestDAO(C_NestDAO).loadGovernance();
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.6.0;
interface INest_3_Abonus {
function getETHNum(address token) external view returns (uint256);
function turnOutAllEth(uint256 amount, address target) external;
}// 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;
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 - <inf-loop@nestprotocol.org>
/// @author Paradox - <paradox@nestprotocol.org>
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 - <inf-loop@nestprotocol.org>
/// @author Paradox - <paradox@nestprotocol.org>
interface INNRewardPool {
/* [DEPRECATED]
uint256 constant DEV_REWARD_PERCENTAGE = 5;
uint256 constant NN_REWARD_PERCENTAGE = 15;
uint256 constant MINER_REWARD_PERCENTAGE = 80;
*/
/// @notice Add rewards for Nest-Nodes, only governance or NestMining (contract) are allowed
/// @dev The rewards need to pull from NestPool
/// @param _amount The amount of Nest token as the rewards to each nest-node
function addNNReward(uint256 _amount) external;
/// @notice Claim rewards by Nest-Nodes
/// @dev The rewards need to pull from NestPool
function claimNNReward() external ;
/// @dev The callback function called by NNToken.transfer()
/// @param fromAdd The address of 'from' to transfer
/// @param toAdd The address of 'to' to transfer
function nodeCount(address fromAdd, address toAdd) external;
/// @notice Show the amount of rewards unclaimed
/// @return reward The reward of a NN holder
function unclaimedNNReward() external view returns (uint256 reward);
/// @dev Only for governance
function loadContracts() external;
/// @dev Only for governance
function loadGovernance() external;
/* ========== EVENTS ============== */
/// @notice When rewards are added to the pool
/// @param reward The amount of Nest Token
/// @param allRewards The snapshot of all rewards accumulated
event NNRewardAdded(uint256 reward, uint256 allRewards);
/// @notice When rewards are claimed by nodes
/// @param nnode The address of the nest node
/// @param share The amount of Nest Token claimed by the nest node
event NNRewardClaimed(address nnode, uint256 share);
/// @notice When flag of state is set by governance
/// @param gov The address of the governance
/// @param flag The value of the new flag
event FlagSet(address gov, uint256 flag);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.6.12;
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.0;
interface INest_3_Leveling {
function checkEthMapping(address token) external view returns (uint256);
function turnOutAllEth(uint256 amount, address target) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.6.0;
interface INest_3_MiningContract {
function takeOutNest(address target) external;
function checkLatestMining() external view returns(uint256);
function checkNestBalance() external view returns(uint256);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.6.0;
interface INest_NToken_TokenAuction {
function checkTokenNum() external view returns (uint256);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.6.0;
interface INest_NToken_TokenMapping {
function checkTokenMapping(address token) external view returns (address);
}// 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");
}
}// 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/ReentrancyGuard.sol";
import "./iface/INestPool.sol";
import "./iface/INTokenController.sol";
import "./iface/INToken.sol";
import "./NToken.sol";
// import "./NestMining.sol";
// import "./iface/INNRewardPool.sol";
/// @title NTokenController
/// @author Inf Loop - <inf-loop@nestprotocol.org>
/// @author Paradox - <paradox@nestprotocol.org>
contract NTokenController is INTokenController, ReentrancyGuard {
using SafeMath for uint256;
using SafeERC20 for ERC20;
/* ========== STATE VARIABLES ============== */
/// @dev A number counter for generating ntoken name
uint32 public ntokenCounter;
uint8 public flag; // 0: uninitialized | 1: active | 2: shutdown
uint216 private _reserved;
uint8 constant NTCTRL_FLAG_UNINITIALIZED = 0;
uint8 constant NTCTRL_FLAG_ACTIVE = 1;
uint8 constant NTCTRL_FLAG_PAUSED = 2;
/// @dev A mapping for all auctions
/// token(address) => NTokenTag
mapping(address => NTokenTag) private nTokenTagList;
/* ========== PARAMETERS ============== */
uint256 public openFeeNestAmount = 10_000; // default = 10_000
/* ========== ADDRESSES ============== */
/// @dev Contract address of NestPool
address public C_NestPool;
/// @dev Contract address of NestToken
address public C_NestToken;
/// @dev Contract address of NestDAO
address public C_NestDAO;
address private governance;
/* ========== EVENTS ============== */
/// @notice when the auction of a token gets started
/// @param token The address of the (ERC20) token
/// @param ntoken The address of the ntoken w.r.t. token for incentives
/// @param owner The address of miner who opened the oracle
event NTokenOpened(address token, address ntoken, address owner);
event NTokenDisabled(address token);
event NTokenEnabled(address token);
/* ========== CONSTRUCTOR ========== */
constructor(address NestPool) public
{
governance = msg.sender;
flag = NTCTRL_FLAG_UNINITIALIZED;
C_NestPool = NestPool;
}
/// @dev The initialization function takes `_ntokenCounter` as argument,
/// which shall be migrated from Nest v3.0
function start(uint32 _ntokenCounter) public onlyGovernance
{
require(flag == NTCTRL_FLAG_UNINITIALIZED, "Nest:NTC:!flag");
ntokenCounter = _ntokenCounter;
flag = NTCTRL_FLAG_ACTIVE;
emit FlagSet(address(msg.sender), uint256(NTCTRL_FLAG_ACTIVE));
}
modifier noContract()
{
require(address(msg.sender) == address(tx.origin), "Nest:NTC:^(contract)");
_;
}
modifier whenActive()
{
require(flag == NTCTRL_FLAG_ACTIVE, "Nest:NTC:!flag");
_;
}
modifier onlyGovOrBy(address _account)
{
if (msg.sender != governance) {
require(msg.sender == _account,
"Nest:NTC:!Auth");
}
_;
}
/* ========== GOVERNANCE ========== */
modifier onlyGovernance()
{
require(msg.sender == governance, "Nest:NTC:!governance");
_;
}
function loadGovernance() override external
{
governance = INestPool(C_NestPool).governance();
}
/// @dev It should be called immediately after the depolyment
function loadContracts() override external onlyGovOrBy(C_NestPool)
{
C_NestToken = INestPool(C_NestPool).addrOfNestToken();
C_NestDAO = INestPool(C_NestPool).addrOfNestDAO();
}
function setParams(uint256 _openFeeNestAmount) override external onlyGovernance
{
emit ParamsSetup(address(msg.sender), openFeeNestAmount, _openFeeNestAmount);
openFeeNestAmount = _openFeeNestAmount;
}
/// @dev Bad tokens should be banned
function disable(address token) external onlyGovernance
{
NTokenTag storage _to = nTokenTagList[token];
_to.state = 1;
emit NTokenDisabled(token);
}
function enable(address token) external onlyGovernance
{
NTokenTag storage _to = nTokenTagList[token];
_to.state = 0;
emit NTokenEnabled(token);
}
/// @dev Stop service for emergency
function pause() external onlyGovernance
{
require(flag == NTCTRL_FLAG_ACTIVE, "Nest:NTC:!flag");
flag = NTCTRL_FLAG_PAUSED;
emit FlagSet(address(msg.sender), uint256(NTCTRL_FLAG_PAUSED));
}
/// @dev Resume service
function resume() external onlyGovernance
{
require(flag == NTCTRL_FLAG_PAUSED, "Nest:NTC:!flag");
flag = NTCTRL_FLAG_ACTIVE;
emit FlagSet(address(msg.sender), uint256(NTCTRL_FLAG_ACTIVE));
}
/* ========== OPEN ========== */
/// @notice Open a NToken for a token by anyone (contracts aren't allowed)
/// @dev Create and map the (Token, NToken) pair in NestPool
/// @param token The address of token contract
function open(address token) override external noContract whenActive
{
require(INestPool(C_NestPool).getNTokenFromToken(token) == address(0x0),
"Nest:NTC:EX(token)");
require(nTokenTagList[token].state == 0,
"Nest:NTC:DIS(token)");
nTokenTagList[token] = NTokenTag(
address(msg.sender), // owner
uint128(0), // nestFee
uint64(block.timestamp), // startTime
0, // state
0 // _reserved
);
// create ntoken
NToken ntoken = new NToken(strConcat("NToken",
getAddressStr(ntokenCounter)),
strConcat("N", getAddressStr(ntokenCounter)),
address(governance),
// NOTE: here `bidder`, we use `C_NestPool` to separate new NTokens
// from old ones, whose bidders are the miners creating NTokens
address(C_NestPool)
);
// increase the counter
ntokenCounter = ntokenCounter + 1; // safe math
INestPool(C_NestPool).setNTokenToToken(token, address(ntoken));
// is token valid ?
ERC20 tokenERC20 = ERC20(token);
tokenERC20.safeTransferFrom(address(msg.sender), address(this), 1);
require(tokenERC20.balanceOf(address(this)) >= 1,
"Nest:NTC:!TEST(token)");
tokenERC20.safeTransfer(address(msg.sender), 1);
// charge nest
ERC20(C_NestToken).transferFrom(address(msg.sender), address(C_NestDAO), openFeeNestAmount);
// raise an event
emit NTokenOpened(token, address(ntoken), address(msg.sender));
}
/* ========== VIEWS ========== */
function NTokenTagOf(address token) override public view returns (NTokenTag memory)
{
return nTokenTagList[token];
}
/* ========== HELPERS ========== */
/// @dev from NESTv3.0
function strConcat(string memory _a, string memory _b) public pure returns (string memory)
{
bytes memory _ba = bytes(_a);
bytes memory _bb = bytes(_b);
string memory ret = new string(_ba.length + _bb.length);
bytes memory bret = bytes(ret);
uint k = 0;
for (uint i = 0; i < _ba.length; i++) {
bret[k++] = _ba[i];
}
for (uint i = 0; i < _bb.length; i++) {
bret[k++] = _bb[i];
}
return string(ret);
}
/// @dev Convert a 4-digital number into a string, from NestV3.0
function getAddressStr(uint256 iv) public pure returns (string memory)
{
bytes memory buf = new bytes(64);
uint256 index = 0;
do {
buf[index++] = byte(uint8(iv % 10 + 48));
iv /= 10;
} while (iv > 0 || index < 4);
bytes memory str = new bytes(index);
for(uint256 i = 0; i < index; ++i) {
str[i] = buf[index - i - 1];
}
return string(str);
}
}// 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;
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/SafeMath.sol";
import "./iface/INToken.sol";
import "./iface/INestPool.sol";
/// @title NNRewardPool
/// @author MLY0813 - <mly0813@nestprotocol.org>
/// @author Inf Loop - <inf-loop@nestprotocol.org>
/// @author Paradox - <paradox@nestprotocol.org>
// The contract is based on Nest_NToken from Nest Protocol v3.0. Considering compatibility, the interface
// keeps the same.
contract NToken is INToken {
using SafeMath for uint256;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowed;
uint256 public _totalSupply = 0 ether;
string public name;
string public symbol;
uint8 public decimals = 18;
uint256 public createdAtHeight;
uint256 public lastestMintAtHeight;
address public governance;
/// @dev The address of NestPool (Nest Protocol v3.5)
address C_NestPool;
address C_NestMining;
/// @notice Constructor
/// @dev Given the address of NestPool, NToken can get other contracts by calling addrOfxxx()
/// @param _name The name of NToken
/// @param _symbol The symbol of NToken
/// @param gov The address of admin
/// @param NestPool The address of NestPool
constructor (string memory _name, string memory _symbol, address gov, address NestPool) public {
name = _name;
symbol = _symbol;
createdAtHeight = block.number;
lastestMintAtHeight = block.number;
governance = gov;
C_NestPool = NestPool;
C_NestMining = INestPool(C_NestPool).addrOfNestMining();
}
modifier onlyGovernance()
{
require(msg.sender == governance, "Nest:NTK:!gov");
_;
}
/// @dev To ensure that all of governance-addresses be consist with each other
function loadGovernance() external
{
governance = INestPool(C_NestPool).governance();
}
function loadContracts() external onlyGovernance
{
C_NestMining = INestPool(C_NestPool).addrOfNestMining();
}
function resetNestPool(address _NestPool) external onlyGovernance
{
C_NestPool = _NestPool;
}
/// @dev Mint
/// @param amount The amount of NToken to add
/// @param account The account of NToken to add
function mint(uint256 amount, address account) override public {
require(address(msg.sender) == C_NestMining, "Nest:NTK:!Auth");
_balances[account] = _balances[account].add(amount);
_totalSupply = _totalSupply.add(amount);
lastestMintAtHeight = block.number;
}
/// @notice The view of totalSupply
/// @return The total supply of ntoken
function totalSupply() override public view returns (uint256) {
return _totalSupply;
}
/// @dev The view of balances
/// @param owner The address of an account
/// @return The balance of the account
function balanceOf(address owner) override public view returns (uint256) {
return _balances[owner];
}
/// @notice The view of variables about minting
/// @dev The naming follows Nestv3.0
/// @return createBlock The block number where the contract was created
/// @return recentlyUsedBlock The block number where the last minting went
function checkBlockInfo()
override public view
returns(uint256 createBlock, uint256 recentlyUsedBlock)
{
return (createdAtHeight, lastestMintAtHeight);
}
function allowance(address owner, address spender) override public view returns (uint256)
{
return _allowed[owner][spender];
}
function transfer(address to, uint256 value) override public returns (bool)
{
_transfer(msg.sender, to, value);
return true;
}
function approve(address spender, uint256 value) override public returns (bool)
{
require(spender != address(0));
_allowed[msg.sender][spender] = value;
emit Approval(msg.sender, spender, value);
return true;
}
function transferFrom(address from, address to, uint256 value) override public returns (bool)
{
_allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value);
_transfer(from, to, value);
emit Approval(from, msg.sender, _allowed[from][msg.sender]);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public returns (bool)
{
require(spender != address(0));
_allowed[msg.sender][spender] = _allowed[msg.sender][spender].add(addedValue);
emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool)
{
require(spender != address(0));
_allowed[msg.sender][spender] = _allowed[msg.sender][spender].sub(subtractedValue);
emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
return true;
}
function _transfer(address from, address to, uint256 value) internal {
_balances[from] = _balances[from].sub(value);
_balances[to] = _balances[to].add(value);
emit Transfer(from, to, value);
}
/// @dev The ABI keeps unchanged with old NTokens, so as to support token-and-ntoken-mining
/// @return The address of bidder
function checkBidder() override public view returns(address) {
return C_NestPool;
}
}// 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 - <inf-loop@nestprotocol.org>
/// @author Paradox - <paradox@nestprotocol.org>
/// @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;
import "../lib/SafeMath.sol";
import "../iface/INNRewardPool.sol";
/// @dev This contract is only for debugging. It will be replaced with `Superman` deployed on the mainnet.
contract NNToken {
using SafeMath for uint;
event Log(string msg);
event LogUint(string msg, uint256 v);
event LogAddress(string msg, address a);
INNRewardPool _C_NNRewardPool;
// string public constant name = "Test Token";
// string public constant symbol = "TT";
// uint8 public constant decimals = 18;
string public name;
string public symbol;
uint8 public decimals;
uint public totalSupply;
mapping(address => uint) public balanceOf;
mapping(address => mapping(address => uint)) public allowance;
// bytes32 public DOMAIN_SEPARATOR;
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
mapping(address => uint) public nonces;
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
constructor(uint _totalSupply, string memory _symbol) public {
// _totalSupply = 1500;
_mint(msg.sender, _totalSupply);
name = "xxx";
symbol = _symbol;
decimals = 0;
}
function setContracts(address C_NNRewardPool) external {
_C_NNRewardPool = INNRewardPool(C_NNRewardPool);
}
function _mint(address to, uint value) internal {
totalSupply = totalSupply.add(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(address(0), to, value);
}
function _burn(address from, uint value) internal {
balanceOf[from] = balanceOf[from].sub(value);
totalSupply = totalSupply.sub(value);
emit Transfer(from, address(0), value);
}
function _approve(address owner, address spender, uint value) private {
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
function _transfer(address from, address to, uint value) private {
require (to != address(0), "Cannot transfer to address(0)");
_C_NNRewardPool.nodeCount(from, to);
balanceOf[from] = balanceOf[from].sub(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(from, to, value);
}
function approve(address spender, uint value) external returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
function transfer(address to, uint value) external returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function transferFrom(address from, address to, uint value) external returns (bool) {
if (allowance[from][msg.sender] != uint(-1)) {
// LogAddress("USDT.transferFrom> from", from );
// LogAddress("USDT.transferFrom> msg.sender", msg.sender );
// LogUint("USDT.transferFrom> allowance[from][msg.sender]", allowance[from][msg.sender]);
// LogUint("USDT.transferFrom> value", value);
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
}
_transfer(from, to, value);
return true;
}
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
require(deadline >= block.timestamp, "EXPIRED");
bytes32 digest = keccak256(
abi.encodePacked(
'\x19\x01',
// DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, 'INVALID_SIGNATURE');
_approve(owner, spender, value);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.6.12;
import "../lib/SafeMath.sol";
contract UERC20 {
using SafeMath for uint;
event Log(string msg);
event LogUint(string msg, uint256 v);
event LogAddress(string msg, address a);
// string public constant name = "Test Token";
// string public constant symbol = "TT";
// uint8 public constant decimals = 18;
string public name;
string public symbol;
uint8 public decimals;
uint public totalSupply;
mapping(address => uint) public balanceOf;
mapping(address => mapping(address => uint)) public allowance;
bytes32 public DOMAIN_SEPARATOR;
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
mapping(address => uint) public nonces;
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
constructor(uint _totalSupply, string memory _name, string memory _symbol, uint8 _decimals) public {
uint chainId;
assembly {
chainId := chainid()
}
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256(bytes("1")),
chainId,
address(this)
)
);
_mint(msg.sender, _totalSupply);
name = _name;
symbol = _symbol;
decimals = _decimals;
}
function _mint(address to, uint value) internal {
totalSupply = totalSupply.add(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(address(0), to, value);
}
function _burn(address from, uint value) internal {
balanceOf[from] = balanceOf[from].sub(value);
totalSupply = totalSupply.sub(value);
emit Transfer(from, address(0), value);
}
function _approve(address owner, address spender, uint value) private {
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
function _transfer(address from, address to, uint value) private {
balanceOf[from] = balanceOf[from].sub(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(from, to, value);
}
function approve(address spender, uint value) external returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
function transfer(address to, uint value) external returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function transferFrom(address from, address to, uint value) external returns (bool) {
if (allowance[from][msg.sender] != uint(-1)) {
// LogAddress("USDT.transferFrom> from", from );
// LogAddress("USDT.transferFrom> msg.sender", msg.sender );
// LogUint("USDT.transferFrom> allowance[from][msg.sender]", allowance[from][msg.sender]);
// LogUint("USDT.transferFrom> value", value);
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
}
_transfer(from, to, value);
return true;
}
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
require(deadline >= block.timestamp, "EXPIRED");
bytes32 digest = keccak256(
abi.encodePacked(
'\x19\x01',
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, 'INVALID_SIGNATURE');
_approve(owner, spender, value);
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
import "./lib/SafeMath.sol";
import "./lib/AddressPayable.sol";
import "./iface/INestMining.sol";
import "./iface/INestPool.sol";
import "./lib/SafeERC20.sol";
import "./lib/ReentrancyGuard.sol";
import './lib/TransferHelper.sol';
// import "hardhat/console.sol";
/// @title NestVote
/// @author Inf Loop - <inf-loop@nestprotocol.org>
/// @author Paradox - <paradox@nestprotocol.org>
contract NestVote is ReentrancyGuard {
using SafeMath for uint256;
/* ========== STATE ============== */
uint32 public voteDuration = 7 days;
uint32 public acceptance = 51;
uint256 public proposalStaking = 100_000 * 1e18;
struct Proposal {
string description;
uint32 state; // 0: proposed | 1: accepted | 2: rejected
uint32 startTime;
uint32 endTime;
uint64 voters;
uint128 stakedNestAmount;
address contractAddr;
address proposer;
address executor;
}
Proposal[] public proposalList;
mapping(uint256 => mapping(address => uint256)) public stakedNestAmount;
address private C_NestToken;
address private C_NestPool;
address private C_NestDAO;
address private C_NestMining;
address public governance;
uint8 public flag;
uint8 constant NESTVOTE_FLAG_UNINITIALIZED = 0;
uint8 constant NESTVOTE_FLAG_INITIALIZED = 1;
/* ========== EVENTS ========== */
event NIPSubmitted(address proposer, uint256 id);
event NIPVoted(address voter, uint256 id, uint256 amount);
event NIPWithdraw(address voter, uint256 id, uint256 blnc);
event NIPRevoke(address voter, uint256 id, uint256 amount);
event NIPExecute(address executor, uint256 id);
/* ========== CONSTRUCTOR ========== */
receive() external payable {}
// NOTE: to support open-zeppelin/upgrades, leave it blank
constructor() public
{ }
// NOTE: can only be executed once
function initialize(address NestPool) external
{
require(flag == NESTVOTE_FLAG_UNINITIALIZED, "Vote:init:!flag" );
governance = msg.sender;
C_NestPool = NestPool;
flag = NESTVOTE_FLAG_INITIALIZED;
}
/* ========== MODIFIERS ========== */
modifier onlyGovernance()
{
require(msg.sender == governance);
_;
}
modifier noContract()
{
require(address(msg.sender) == address(tx.origin), "Nest:Vote:BAN(contract)");
_;
}
/* ========== GOVERNANCE ========== */
function loadGovernance() external
{
governance = INestPool(C_NestPool).governance();
}
function setGovernance(address _gov) external onlyGovernance
{
INestPool(C_NestPool).setGovernance(_gov);
}
function loadContracts() public onlyGovernance
{
C_NestToken = INestPool(C_NestPool).addrOfNestToken();
C_NestDAO = INestPool(C_NestPool).addrOfNestDAO();
C_NestMining = INestPool(C_NestPool).addrOfNestMining();
}
function releaseGovTo(address gov) public onlyGovernance
{
governance = gov;
}
function setParams(uint32 voteDuration_, uint32 acceptance_, uint256 proposalStaking_)
public onlyGovernance
{
acceptance = acceptance_;
voteDuration = voteDuration_;
proposalStaking = proposalStaking_;
}
/* ========== VOTE ========== */
function propose(address contract_, string memory description) external
{
uint256 id = proposalList.length;
proposalList.push(Proposal(
string(description),
uint32(0), // state
uint32(block.timestamp), //startTime
uint32(block.timestamp + voteDuration), //endTime
uint64(0), // voters
uint128(0), // stakedNestAmount
contract_, //contractAddr
address(msg.sender), // proposer
address(0) // executor
));
ERC20(C_NestToken).transferFrom(address(msg.sender), address(this), proposalStaking);
emit NIPSubmitted(msg.sender, id);
}
function vote(uint256 id, uint256 amount) external noContract
{
Proposal memory p = proposalList[id];
require (block.timestamp <= p.endTime, "Nest:Vote:!time");
uint256 blncs = stakedNestAmount[id][address(msg.sender)];
stakedNestAmount[id][address(msg.sender)] = blncs.add(amount);
p.stakedNestAmount = uint128(uint256(p.stakedNestAmount).add(amount));
if (blncs == 0) {
p.voters = uint64(uint256(p.voters).add(1));
}
proposalList[id] = p;
ERC20(C_NestToken).transferFrom(address(msg.sender), address(this), amount);
emit NIPVoted(msg.sender, id, amount);
}
function withdraw(uint256 id) external noContract
{
Proposal memory p = proposalList[id];
require (p.state > 0, "Nest:Vote:!state");
uint256 blnc = stakedNestAmount[id][address(msg.sender)];
p.stakedNestAmount = uint128(uint256(p.stakedNestAmount).sub(blnc));
stakedNestAmount[id][address(msg.sender)] = 0;
proposalList[id] = p;
ERC20(C_NestToken).transfer(address(msg.sender), blnc);
emit NIPWithdraw(msg.sender, id, blnc);
}
function revoke(uint256 id, uint256 amount) external noContract
{
Proposal memory p = proposalList[id];
require (uint256(block.timestamp) <= uint256(p.endTime), "Nest:Vote:!time");
uint256 blnc = stakedNestAmount[id][address(msg.sender)];
require(blnc >= amount, "Nest:Vote:!amount");
if (blnc == amount) {
p.voters = uint64(uint256(p.voters).sub(1));
}
p.stakedNestAmount = uint128(uint256(p.stakedNestAmount).sub(amount));
stakedNestAmount[id][address(msg.sender)] = blnc.sub(amount);
proposalList[id] = p;
ERC20(C_NestToken).transfer(address(msg.sender), amount);
emit NIPRevoke(msg.sender, id, amount);
}
function execute(uint256 id) external
{
uint256 _total_mined = INestMining(C_NestMining).minedNestAmount();
uint256 _burned = ERC20(C_NestToken).balanceOf(address(0x1));
uint256 _repurchased = ERC20(C_NestToken).balanceOf(C_NestDAO);
uint256 _circulation = _total_mined.sub(_repurchased).sub(_burned);
Proposal storage p = proposalList[id];
require (p.state == 0, "Nest:Vote:!state");
require (p.endTime < block.timestamp, "Nest:Vote:!time");
if (p.stakedNestAmount > _circulation.mul(acceptance).div(100)) {
address _contract = p.contractAddr;
(bool success, bytes memory result) = _contract.delegatecall(abi.encodeWithSignature("run()"));
require(success, "Nest:Vote:!exec");
p.state = 1;
} else {
p.state = 2;
}
p.executor = address(msg.sender);
proposalList[id] = p;
ERC20(C_NestToken).transfer(p.proposer, proposalStaking);
emit NIPExecute(msg.sender, id);
}
function stakedNestNum(uint256 id) public view returns (uint256)
{
Proposal storage p = proposalList[id];
//return (uint256(p.stakedNestAmount).div(1e18));
return (uint256(p.stakedNestAmount));
}
function numberOfVoters(uint256 id) public view returns (uint256)
{
Proposal storage p = proposalList[id];
return (uint256(p.voters));
}
}// 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/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 - <inf-loop@nestprotocol.org>
/// @author Paradox - <paradox@nestprotocol.org>
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;
pragma experimental ABIEncoderV2;
import "./lib/SafeMath.sol";
import "./lib/SafeERC20.sol";
import './lib/TransferHelper.sol';
import "./lib/ReentrancyGuard.sol";
import "./iface/INestPool.sol";
import "./iface/INestStaking.sol";
import "./iface/INToken.sol";
import "./iface/INestQuery.sol";
import "./iface/INestMining.sol";
import "./iface/INestDAO.sol";
/// @title NestQuery
/// @author Inf Loop - <inf-loop@nestprotocol.org>
/// @author Paradox - <paradox@nestprotocol.org>
contract NestQuery is INestQuery, ReentrancyGuard {
using SafeMath for uint256;
/* ========== STATE ============== */
/// @notice The flag is the running status of NestQuery contract
/// @dev The flag is in {0, 1, 2}
/// @return The value of flag
uint8 public flag;
uint248 private _reserved;
// flag == 0: the contract needs initialization
// flag == 1: the contract is active after initialization
// flag == 2: the contract is shutdown, user interfaces like query() are closed,
// while the governor has privileges to rescue
uint8 constant QUERY_FLAG_UNINITIALIZED = 0;
uint8 constant QUERY_FLAG_ACTIVE = 1;
uint8 constant QUERY_FLAG_PAUSED = 2;
struct Client {
uint64 startTime;
uint64 endTime; // endTime==0 for non-monthly clients
uint32 fee;
uint32 typ; // =1: PPQ | =2: PPM (forbidden for the moment)
uint64 _reserved;
}
/// @dev Here we only support pay-per-query clients.
/// The other type (pay-per-month) isn't supported currently.
uint32 constant CLIENT_TYPE_PAY_PER_QUERY = 1;
// uint32 constant CLIENT_TYPE_PAY_PER_MONTH = 2;
mapping(address => uint256) public clientList;
mapping(address => address) public clientOp;
/* ========== PARAMETERS ============== */
/// @dev The four paramters are encoded into a uin256 slot to save GAS. Currently only four
/// uint32 pieces are used, leaving sufficient spaces for later upgrading.
struct Params {
uint32 singleFeeEthTWei; // Twei = 1e12
uint32 activationTime; // second
uint32 activationFeeNestNum; // 1 NEST = 1e18
uint32 _reserved2;
}
uint256 private paramsEncoded;
/// @dev The default values of parameters. They shall be setup via `setParams()` before
/// the contract starts to rotates.
uint32 constant CLIENT_QUERY_FEE_ETH_TWEI = (0.01 ether) / 1e12;
uint32 constant CLIENT_ACTIVATION_NEST_AMOUNT = 0;
uint32 constant CLIENT_MONTHLY_FEE_NEST_AMOUNT = 0;
uint32 constant CLIENT_ACTIVATION_DURATION_SECOND = 10;
/* ========== ADDRESSES ============== */
/// @dev The contract variables for other contracts' addresses, loaded from NestPool
address private C_NestToken;
address private C_NestMining;
address private C_NestPool;
address private C_NestStaking;
address private C_NestDAO;
/// @dev The governor's address, which is loaded from NestPool.
address public governance;
/* ========== CONSTRUCTOR ============== */
receive() external payable { }
// NOTE: to support open-zeppelin/upgrades, leave it blank
constructor() public { }
/// @dev It is supposedly called by the proxy (open-zeppelin/upgrades), only ONCE!
function initialize(address NestPool) external
{
require(flag == QUERY_FLAG_UNINITIALIZED, "Nest:Qury:!flag");
governance = address(msg.sender);
C_NestPool = NestPool;
uint32 _actFee = CLIENT_ACTIVATION_NEST_AMOUNT;
uint32 _singleFee = CLIENT_QUERY_FEE_ETH_TWEI;
uint32 _actTime = CLIENT_ACTIVATION_DURATION_SECOND;
paramsEncoded = encode_4x32_256(_singleFee, _actTime, _actFee, 0);
flag = QUERY_FLAG_ACTIVE;
}
/* ========== MODIFIERS ========== */
modifier whenActive()
{
require(flag == QUERY_FLAG_ACTIVE, "Nest:Qury:!flag");
_;
}
modifier onlyGovernance()
{
require(msg.sender == governance, "Nest:Qury:!governance");
_;
}
modifier onlyGovOrBy(address _account)
{
if (msg.sender != governance) {
require(msg.sender == _account,
"Nest:Qury:!Auth");
}
_;
}
/*
modifier onlyBy(address _contract)
{
require(msg.sender == _contract, "Nest:Qury:!Auth");
_;
}*/
modifier noContract()
{
require(address(msg.sender) == address(tx.origin), "Nest:Qury:BAN(contract)");
_;
}
/* ========== GOVERNANCE ========== */
/// @dev To ensure that all of governance-addresses be consist with each other, every contract
/// besides NestPool must load newest `governance` from NestPool.
function loadGovernance() override external
{
governance = INestPool(C_NestPool).governance();
}
/// @notice Setup the parameters for queryings, one price for all token
/// @dev Parameters can be reset by set time to zero
function setParams(uint256 single, uint32 time, uint256 nestAmount)
public
onlyGovernance
{
(uint32 _singleFee, uint32 _time, uint32 _actFee, uint32 _res) = decode_4x32_256(paramsEncoded);
_singleFee = uint32(single);
_time = uint32(time);
_actFee = uint32(nestAmount / 1e18);
uint256 oldParamsEncoded = paramsEncoded;
paramsEncoded = encode_4x32_256(_singleFee, _time, _actFee, _res);
emit ParamsSetup(address(msg.sender), oldParamsEncoded, paramsEncoded);
}
function params() external view
returns(uint256 single, uint64 leadTime, uint256 nestAmount)
{
(uint32 _singleFee, uint32 _time, uint32 _actFee, uint32 _res) = decode_4x32_256(paramsEncoded);
single = uint256(_singleFee).mul(1e12);
leadTime = uint64(_time);
nestAmount = uint256(_actFee).mul(1e18);
}
function loadContracts() override external onlyGovOrBy(C_NestPool)
{
C_NestToken = INestPool(C_NestPool).addrOfNestToken();
C_NestMining = INestPool(C_NestPool).addrOfNestMining();
C_NestStaking = INestPool(C_NestPool).addrOfNestStaking();
C_NestDAO = INestPool(C_NestPool).addrOfNestDAO();
}
/// @dev Remove a client if something goes wrong
/// @param defi The address of a client (defi DApp)
function remove(address defi)
external
onlyGovernance
{
clientList[defi] = encodeClient(0, 0, 0, 0);
clientOp[defi] = address(0);
}
// /// @dev The balance of NEST
// /// @return The amount of NEST tokens for this contract
// function balanceNest() override external view returns (uint256)
// {
// return ERC20(C_NestToken).balanceOf(address(this));
// }
// /// @dev The balance of NEST
// /// @return The amount of ethers withheld by this contract
// function balanceEth() override external view returns (uint256)
// {
// return address(this).balance;
// }
/* ========== EMERGENCY ========== */
/// @dev Stop service for emergency
function pause() external onlyGovernance
{
require(flag == QUERY_FLAG_ACTIVE, "Nest:Qury:!flag");
flag = QUERY_FLAG_PAUSED;
emit FlagSet(address(msg.sender), uint256(QUERY_FLAG_PAUSED));
}
/// @dev Resume service
function resume() external onlyGovernance
{
require(flag == QUERY_FLAG_PAUSED, "Nest:Qury:!flag");
flag = QUERY_FLAG_ACTIVE;
emit FlagSet(address(msg.sender), uint256(QUERY_FLAG_ACTIVE));
}
/* ========== CLIENT ========== */
/// @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)
override external noContract whenActive
{
if (defi == address(0)) {
defi = address(msg.sender);
}
Client memory _c = decodeClient(clientList[defi]);
require (_c.typ == 0, "Nest:Qury:EX(client)");
(, uint32 _actTime, uint256 _actFee, ) = decode_4x32_256(paramsEncoded);
uint256 _nestFee = _actFee.mul(1e18);
uint256 _start = uint64(block.timestamp.add(_actTime));
uint256 _end = 0;
uint256 _mfee = 0;
clientList[defi] = encodeClient(uint64(_start), uint64(_end), uint32(_mfee), 0x1);
clientOp[defi] = address(msg.sender);
emit ClientActivated(defi, _start, _end);
require(ERC20(C_NestToken).transferFrom(
address(msg.sender),
address(C_NestDAO),
_nestFee), "Nest:Qury:!transfer");
}
/// @notice Deactivate a pay-per-query defi client
/// @param defi The address of a client (DeFi DApp)
function deactivate(address defi)
override
external
whenActive
{
if (defi == address(0)) {
defi = address(msg.sender);
}
require(address(msg.sender) == clientOp[defi], "Nest:Qury:!Op");
clientList[defi] = encodeClient(0, 0, 0, 0);
clientOp[defi] = address(0);
}
/// @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)
override
public
payable
whenActive
nonReentrant
returns (uint256, uint256, uint256)
{
// check parameters
Client memory c = decodeClient(clientList[address(msg.sender)]);
require(c.typ == CLIENT_TYPE_PAY_PER_QUERY, "Nest:Qury:=!(client.typ)");
require(c.startTime != 0 && uint256(c.startTime) < block.timestamp
&& uint256(c.endTime) == 0, "Nest:Qury:!(client.time)");
// lookup the latest effective price
(uint256 ethAmount, uint256 tokenAmount, uint256 bn) = INestMining(C_NestMining).latestPriceOf(token);
(uint256 _single, , , ) = decode_4x32_256(paramsEncoded);
{
address _ntoken = INestPool(C_NestPool).getNTokenFromToken(token);
uint256 _ethFee = _single.mul(1e12); // NOTE: the unit of _single is TWei
INestDAO(C_NestDAO).addETHReward{value:_ethFee}(address(_ntoken));
// return change
if (payback != address(0) && msg.value > _ethFee) {
TransferHelper.safeTransferETH(payback, msg.value.sub(_ethFee));
}
}
emit PriceQueried(address(msg.sender), token, ethAmount, tokenAmount, bn);
return (ethAmount, tokenAmount, uint256(bn));
}
/// @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)
override
external
payable
whenActive
nonReentrant
returns (uint256 ethAmount, uint256 tokenAmount, uint128 avgPrice, int128 vola, uint256 bn)
{
// check parameters
Client memory c = decodeClient(clientList[address(msg.sender)]);
require (c.typ == CLIENT_TYPE_PAY_PER_QUERY, "Nest:Qury:=!(client.typ)");
require(c.startTime != 0 && uint256(c.startTime) < block.timestamp
&& uint256(c.endTime) == 0, "Nest:Qury:!(client.time)");
(ethAmount, tokenAmount, bn) = INestMining(C_NestMining).latestPriceOf(token);
(, avgPrice, vola,) = INestMining(C_NestMining).priceAvgAndSigmaOf(token);
{
(uint256 _single, , , ) = decode_4x32_256(paramsEncoded);
address _ntoken = INestPool(C_NestPool).getNTokenFromToken(token);
uint256 _ethFee = _single.mul(1e12); // NOTE: the unit of _single is TWei
INestDAO(C_NestDAO).addETHReward{value:_ethFee}(address(_ntoken));
// charge back
if (payback != address(0) && msg.value > _ethFee) {
TransferHelper.safeTransferETH(payback, msg.value.sub(_ethFee));
}
}
emit PriceAvgVolaQueried(address(msg.sender), token, bn, avgPrice, vola);
}
/// @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
)
override
public
payable
whenActive
returns(uint256 ethAmount, uint256 erc20Amount, uint256 blockNum)
{
return query(tokenAddress, address(msg.sender));
}
/// @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)
override public payable
whenActive
returns (uint128[] memory)
{
// check client
Client memory c = decodeClient(clientList[address(msg.sender)]);
require(c.typ == CLIENT_TYPE_PAY_PER_QUERY, "Nest:Qury:=!(client.typ)");
require(c.startTime != 0 && uint256(c.startTime) < block.timestamp
&& uint256(c.endTime) == 0, "Nest:Qury:!(client.time)");
// retrieve the historical price list
(uint128[] memory data, uint256 bn) = INestMining(C_NestMining).priceListOfToken(token, num);
// require(miner != address(0x0), "miner null");
// get the associated NTOKEN with token
address _ntoken = INestPool(C_NestPool).getNTokenFromToken(token);
// calculate the fee rate
(uint256 _single, , , ) = decode_4x32_256(paramsEncoded);
uint256 _ethFee = _single.mul(1e12); // NOTE: the unit of _single is TWei
// transfer fee into NestDAO
INestDAO(C_NestDAO).addETHReward{value:_ethFee}(address(_ntoken));
// pay back the change
if (payback != address(0) && msg.value > _ethFee) {
TransferHelper.safeTransferETH(payback, msg.value.sub(_ethFee));
}
// notify client
emit PriceListQueried(address(msg.sender), token, bn, num);
return data;
}
/// @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)
override public view
whenActive
noContract
returns (uint128[] memory)
{
// retrieve the historical price list
(uint128[] memory data, uint256 bn) = INestMining(C_NestMining).priceListOfToken(token, num);
// // get the associated NTOKEN with token
// address _ntoken = INestPool(C_NestPool).getNTokenFromToken(token);
return data;
}
function latestPrice(address token)
override
public
view
whenActive
noContract
returns (uint256 ethAmount, uint256 tokenAmount, uint128 avgPrice, int128 vola, uint256 bn)
{
(ethAmount, tokenAmount, bn) = INestMining(C_NestMining).latestPriceOf(token);
(, avgPrice, vola,) = INestMining(C_NestMining).priceAvgAndSigmaOf(token);
}
/* ========== INTER-CALLS ========== */
// /// @dev Withdraw NEST only when emergency or governance
// /// @param to The address of recipient
// /// @param amount The amount of NEST tokens
// function withdrawNest(uint256 amount)
// override external onlyBy(C_NestDAO)
// {
// ERC20(C_NestToken).transfer(address(msg.sender), amount);
// }
// /// @dev Withdraw ethers only when emergency or governance
// /// @param to The address of recipient
// /// @param amount The amount of ethers
// function withdrawEth(uint256 amount)
// override external onlyBy(C_NestDAO)
// {
// TransferHelper.safeTransferETH(address(msg.sender), amount);
// }
/* ========== HELPERS ========== */
/// @dev For saving GAS
function encode_4x32_256(uint32 p1, uint32 p2, uint32 p3, uint32 p4)
internal
pure
returns (uint256 enc)
{
assembly {
mstore(0x20, p1)
mstore(0x18, p2)
mstore(0x10, p3)
mstore(0x8, p4)
enc := mload(0x20)
}
}
/// @dev For saving GAS
function decode_4x32_256(uint256 enc)
internal
pure
returns (uint32 p1, uint32 p2, uint32 p3, uint32 p4)
{
assembly {
p1 := enc
mstore(0x18, enc)
p4 := mload(0)
mstore(0x10, enc)
p3 := mload(0)
mstore(0x8, enc)
p2 := mload(0)
}
}
/// @dev For saving GAS
function encodeClient(uint64 _start, uint64 _end, uint32 _fee, uint32 _typ)
internal pure returns (uint256 enc)
{
assembly {
let y := 0
mstore(0x20, 0)
mstore(0x18, _typ)
mstore(0x14, _fee)
mstore(0x10, _end)
mstore(0x8, _start)
enc := mload(0x20)
}
}
/// @dev For saving GAS
function decodeClient(uint256 enc)
internal pure returns (Client memory client)
{
uint32 _typ;
uint32 _fee;
uint64 _start;
uint64 _end;
assembly {
mstore(0x18, enc)
_start := mload(0)
mstore(0x10, enc)
_end := mload(0)
mstore(0xc, enc)
_fee := mload(0)
mstore(0x8, enc)
_typ := mload(0)
}
client = Client(_start, _end, _fee, _typ, 0);
}
}// 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 - <inf-loop@nestprotocol.org>
/// @author Paradox - <paradox@nestprotocol.org>
/// @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;
pragma experimental ABIEncoderV2;
import "./libminingv1/MiningV1Data.sol";
import "./libminingv1/MiningV1Calc.sol";
import "./libminingv1/MiningV1Op.sol";
import "./lib/SafeMath.sol";
import "./lib/SafeERC20.sol";
import './lib/TransferHelper.sol';
import "./lib/ABDKMath64x64.sol";
import "./iface/INestPool.sol";
import "./iface/INestStaking.sol";
import "./iface/INTokenLegacy.sol";
import "./iface/INestMining.sol";
import "./iface/INestDAO.sol";
// import "hardhat/console.sol";
/// @title NestMiningV1
/// @author Inf Loop - <inf-loop@nestprotocol.org>
/// @author Paradox - <paradox@nestprotocol.org>
contract NestMiningV1 {
using SafeMath for uint256;
using MiningV1Calc for MiningV1Data.State;
using MiningV1Op for MiningV1Data.State;
/* ========== STATE VARIABLES ============== */
uint8 public flag;
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; // = 10;
uint32 nestStakedNum1k; // = 1;
uint8 biteFeeRate; // = 1;
uint8 miningFeeRate; // = 10;
uint8 priceDurationBlock;
uint8 maxBiteNestedLevel; // = 3;
uint8 biteInflateFactor;
uint8 biteNestInflateFactor;
}
/* ========== CONSTRUCTOR ========== */
constructor() public { }
function initialize(address NestPool) external
{
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);
}
governance = msg.sender;
version = uint64(block.number);
flag = MINING_FLAG_SETUP_NEEDED;
C_NestPool = NestPool;
}
/// @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
{
require(flag == MINING_FLAG_SETUP_NEEDED, "Nest:Mine:!flag");
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 testnet or mainnet
state.genesisBlock = genesisBlockNumber;
flag = MINING_FLAG_UPGRADE_NEEDED;
version = uint64(block.number);
}
/// @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 onlyByNest()
{
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 ========== */
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
{
if (newParams.miningEthUnit != 0) {
state.miningEthUnit = newParams.miningEthUnit;
}
if (newParams.nestStakedNum1k != 0) {
state.nestStakedNum1k = newParams.nestStakedNum1k;
}
state.biteFeeRate = newParams.biteFeeRate;
if (newParams.miningFeeRate != 0) {
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 at upgrade 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 USDx) whose total supply is below 1,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(ethNum >= state.miningEthUnit && ethNum % state.miningEthUnit == 0, "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
uint256 _ethFee = ethNum.mul(state.miningFeeRate).mul(1e18).div(10000);
{ // 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));
}
INestStaking _C_NestStaking = INestStaking(state.C_NestStaking);
INestDAO _C_NestDAO = INestDAO(state.C_NestDAO);
_C_NestStaking.addETHReward{value:_ethFee.mul(MiningV1Data.MINING_NTOKEN_FEE_DIVIDEND_RATE).div(100)}(_ntoken);
_C_NestDAO.addETHReward{value:_ethFee.mul(MiningV1Data.MINING_NTOKEN_FEE_DAO_RATE).div(100)}(_ntoken);
_C_NestDAO.addETHReward{value:_ethFee.mul(MiningV1Data.MINING_NTOKEN_FEE_NEST_DAO_RATE).div(100)}(address(state.C_NestToken));
// freeze eths and tokens in the nest pool
_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
uint256 _minedH = state.minedAtHeight[token][block.number];
uint256 _ntokenH = uint256(_minedH >> 128);
uint256 _ethH = uint256(_minedH % (1 << 128));
if (_ntokenH == 0) {
uint256 _ntokenAmount = mineNToken(_ntoken);
state.latestMiningHeight = uint32(block.number);
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));
}
}
_ethH = _ethH.add(ethNum);
// require(_nestH < (1 << 128) && _ethH < (1 << 128), "nestAtHeight/ethAtHeight error");
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);
// NOTE: uncomment the line below to ensure that only (ETH, NEST) can be dual-posted
require(_ntoken != token, "Nest:Mine:!(ntoken)");
// calculate eth fee
uint256 _ethFee = ethNum.mul(state.miningFeeRate).mul(1e18).div(10000);
{ // 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));
}
INestStaking _C_NestStaking = INestStaking(state.C_NestStaking);
INestDAO _C_NestDAO = INestDAO(state.C_NestDAO);
if (_ntoken == address(state.C_NestToken)) {
_C_NestStaking.addETHReward{value:_ethFee.mul(MiningV1Data.MINING_NEST_FEE_DIVIDEND_RATE).div(100)}(_ntoken);
_C_NestDAO.addETHReward{value:_ethFee.mul(MiningV1Data.MINING_NEST_FEE_DAO_RATE).div(100)}(_ntoken);
} else {
_C_NestStaking.addETHReward{value:_ethFee.mul(MiningV1Data.MINING_NTOKEN_FEE_DIVIDEND_RATE).div(100)}(_ntoken);
_C_NestDAO.addETHReward{value:_ethFee.mul(MiningV1Data.MINING_NTOKEN_FEE_DAO_RATE).div(100)}(_ntoken);
_C_NestDAO.addETHReward{value:_ethFee.mul(MiningV1Data.MINING_NTOKEN_FEE_NEST_DAO_RATE).div(100)}(address(state.C_NestToken));
}
// freeze assets in the nest pool
_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
if (_ntoken == address(state.C_NestToken)) {
uint256 _minedH = state.minedAtHeight[token][block.number];
uint256 _nestH = uint256(_minedH >> 128);
uint256 _ethH = uint256(_minedH % (1 << 128));
if (_nestH == 0) {
uint256 _nestAmount = mineNest();
state.latestMiningHeight = uint32(block.number);
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));
}
_ethH = _ethH.add(ethNum);
state.minedAtHeight[token][block.number] = (_nestH * (1<< 128) + _ethH);
} else {
uint256 _minedH = state.minedAtHeight[token][block.number];
uint256 _ntokenH = uint256(_minedH >> 128);
uint256 _ethH = uint256(_minedH % (1 << 128));
if (_ntokenH == 0) {
uint256 _ntokenAmount = mineNToken(_ntoken);
state.latestMiningHeight = uint32(block.number);
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));
}
}
_ethH = _ethH.add(ethNum);
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
{
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
{
state._closeAndWithdraw(token, index);
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
{
state._closeList(token, indices);
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
{
state._biteToken(token, index, biteNum, newTokenAmountPerEth);
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
{
state._biteEth(token, index, biteNum, newTokenAmountPerEth);
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
onlyByNest
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) {
return (0, 0, 0);
}
uint256 _first = 0;
for (uint i = 1; i <= len; i++) {
_sheet = _plist[len-i];
if (_first == 0 && _sheet.height + state.priceDurationBlock < block.number) {
_first = uint256(_sheet.height);
_ethNum = uint256(_sheet.remainNum);
tokenAmount = uint256(_sheet.tokenAmountPerEth).mul(_ethNum);
ethAmount = _ethNum.mul(1 ether);
blockNum = _first;
} else if (_first == uint256(_sheet.height)) {
_ethNum = _ethNum.add(_sheet.remainNum);
tokenAmount = tokenAmount.add(uint256(_sheet.tokenAmountPerEth).mul(_ethNum));
ethAmount = _ethNum.mul(1 ether);
} else if (_first > uint256(_sheet.height)) {
break;
}
}
blockNum = blockNum + uint256(state.priceDurationBlock); // safe math
}
/// @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)");
return (uint256(pi.ethNum).mul(1 ether), pi.tokenAmount, pi.height + state.priceDurationBlock);
}
/// @dev It shouldn't be read from any contracts other than NestQuery
function priceAvgAndSigmaOf(address token)
public
view
onlyByNest
returns (uint128, uint128, int128, uint32)
{
MiningV1Data.PriceInfo memory pi = state.priceInfo[token];
require(pi.height > 0, "Nest:Mine:NO(price)");
int128 v = ABDKMath64x64.sqrt(ABDKMath64x64.abs(pi.volatility_sigma_sq));
uint128 p = uint128(uint256(pi.tokenAmount).div(uint256(pi.ethNum)));
return (p, pi.avgTokenAmount, v, pi.height + uint32(state.priceDurationBlock)); // safe math
}
function priceOfTokenAtHeight(address token, uint64 atHeight)
public
view
noContractExcept(state.C_NestQuery)
returns(uint256 ethAmount, uint256 tokenAmount, uint256 height)
{
return state._priceOfTokenAtHeight(token, atHeight);
}
/// @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(MiningV1Data.MINING_NEST_GENESIS_BLOCK_HEIGHT).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 yieldAmountAtHeight(uint64 height) public view returns (uint128) {
uint256 period = uint256(height).sub(MINING_NEST_GENESIS_BLOCK_HEIGHT).div(MINING_NEST_YIELD_CUTBACK_PERIOD);
uint256 nestPerBlock;
if (period > 9) {
nestPerBlock = MINING_NEST_YIELD_OFF_PERIOD_AMOUNT;
} else {
nestPerBlock = _mining_nest_yield_per_block_amount[period];
}
uint256 yieldAmount = nestPerBlock.mul(uint256(height).sub(latestMiningHeight));
return uint128(yieldAmount);
}
*/
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);
}
/* ========== CALCULATION ========== */
function stat(address _token) public
{
return state._stat(_token);
}
/* ========== ENCODING/DECODING ========== */
// function decodeU256Two(uint256 enc) public pure returns (uint128, uint128) {
// return (uint128(enc / (1 << 128)), uint128(enc % (1 << 128)));
// }
/*
function decode(bytes32 x) internal pure returns (uint64 a, uint64 b, uint64 c, uint64 d) {
assembly {
d := x
mstore(0x18, x)
a := mload(0)
mstore(0x10, x)
b := mload(0)
mstore(0x8, x)
c := mload(0)
}
}
/// @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 - <inf-loop@nestprotocol.org>
/// @author 0x00 - <0x00@nestprotocol.org>
library MiningV1Data {
/* ========== CONSTANTS ========== */
// uint256 constant PRICE_DURATION_BLOCK = 25;
// uint256 constant MINING_NEST_GENESIS_BLOCK_HEIGHT = 6236588;
uint256 constant MINING_NEST_GENESIS_BLOCK_HEIGHT = 1; // for testing
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_GENESIS_BLOCK_NUMBER = 6236588;
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 = 80%
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[10] private _mining_ntoken_yield_per_block_amount;
//uint256 constant c_mining_eth_unit = 10; // 10 ether
// uint256 constant c_mining_price_deviateion_factor = 10; // removed
//uint256 constant c_mining_fee_thousandth = 10;
uint256 constant NN_NEST_REWARD_PERCENTAGE = 15;
uint256 constant DAO_NEST_REWARD_PERCENTAGE = 5;
uint256 constant MINER_NEST_REWARD_PERCENTAGE = 80;
// uint256 constant BIDDER_NTOKEN_REWARD_PERCENTAGE = 5;
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(Not Available)
uint8 state; // 0: closed | 1: posted | 2: bitten
uint8 _reserved;
uint32 ethNumBal;
uint32 tokenNumBal;
uint32 nestNum1k;
uint128 tokenAmountPerEth;
}
/// @dev size: (3 x 256 bit)
struct PriceInfo {
uint32 index;
uint32 height;
uint32 ethNum; // the balance of eth
uint32 _reserved;
uint128 tokenAmount; // the balance of token
int128 volatility_sigma_sq;
int128 volatility_ut_sq;
uint128 avgTokenAmount;
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; // = 10;
uint32 nestStakedNum1k; // = 100;
uint8 biteFeeRate; // = 1;
uint8 miningFeeRate; // = 10;
uint8 priceDurationBlock; // = 25;
uint8 maxBiteNestedLevel; // = 3;
uint8 biteInflateFactor; // = 2;
uint8 biteNestInflateFactor; // = 2;
uint32 genesisBlock; // = 6236588;
uint128 latestMiningHeight;
uint128 minedNestAmount;
address _developer_address;
address _NN_address;
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;
uint256 _reserved1;
uint256 _reserved2;
uint256 _reserved3;
uint256 _reserved4;
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
import "../lib/SafeMath.sol";
import "../lib/SafeERC20.sol";
import '../lib/TransferHelper.sol';
import "../lib/ABDKMath64x64.sol";
import "../iface/INestPool.sol";
import "../iface/INestStaking.sol";
import "../iface/INToken.sol";
import "../iface/INNRewardPool.sol";
import "../libminingv1/MiningV1Data.sol";
//import "hardhat/console.sol";
/// @title NestMiningV1/MiningV1Calc
/// @author Inf Loop - <inf-loop@nestprotocol.org>
/// @author Paradox - <paradox@nestprotocol.org>
library MiningV1Calc {
using SafeMath for uint256;
// average block-out time: 14s
uint8 constant 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(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;
}
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,
i - p0.index);
}
}
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);
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) {
data[_index] = uint128(_curr + state.priceDurationBlock); // safe math
_ethNum = uint256(_sheet.remainNum);
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) {
_index += 3;
if (_index >= uint256(num * 3)) {
break;
}
data[_index] = uint128(_curr + state.priceDurationBlock); // safe math
_ethNum = uint256(_sheet.remainNum);
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)
{
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 <= uint256(atHeight) && _first + state.priceDurationBlock < block.number) {
_ethNum = uint256(_sheet.remainNum);
ethAmount = _ethNum.mul(1 ether);
tokenAmount = _ethNum.mul(_sheet.tokenAmountPerEth);
blockNum = _first;
_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 (_sheet.height + state.priceDurationBlock < block.number) {
break;
}
//sheets[i] = _sheet;
sheets[i].miner = _sheet.miner;
sheets[i].height = _sheet.height;
sheets[i].ethNum = _sheet.ethNum;
sheets[i].remainNum = _sheet.remainNum;
sheets[i].level = _sheet.level;
sheets[i].typ = _sheet.typ;
sheets[i].state = _sheet.state;
sheets[i].index = len - 1 - i;
sheets[i].nestNum1k = _sheet.nestNum1k;
sheets[i].tokenAmountPerEth = _sheet.tokenAmountPerEth;
}
}
function unClosedSheetListOf(
MiningV1Data.State storage state,
address miner,
address token,
uint256 fromIndex,
uint256 num)
view
external
returns (MiningV1Data.PriceSheetPub2[] memory sheets)
{
sheets = new MiningV1Data.PriceSheetPub2[](num);
MiningV1Data.PriceSheet[] storage _list = state.priceSheetList[token];
uint256 len = _list.length;
require(fromIndex < len, "Nest:Mine:!from");
for (uint i = 0; i < num; i++) {
if (fromIndex < i) {
break;
}
MiningV1Data.PriceSheet memory _sheet = _list[fromIndex - i];
if (uint256(_sheet.miner) == uint256(miner)
&& (_sheet.state == MiningV1Data.PRICESHEET_STATE_POSTED
|| _sheet.state == MiningV1Data.PRICESHEET_STATE_BITTEN)) {
sheets[i].miner = _sheet.miner;
sheets[i].height = _sheet.height;
sheets[i].ethNum = _sheet.ethNum;
sheets[i].remainNum = _sheet.remainNum;
sheets[i].level = _sheet.level;
sheets[i].typ = _sheet.typ;
sheets[i].state = _sheet.state;
sheets[i].index = fromIndex - i;
sheets[i].nestNum1k = _sheet.nestNum1k;
sheets[i].tokenAmountPerEth = _sheet.tokenAmountPerEth;
}
}
}
function sheetListOf(
MiningV1Data.State storage state,
address miner,
address token,
uint256 fromIndex,
uint256 num
)
view
external
returns (MiningV1Data.PriceSheetPub2[] memory sheets)
{
sheets = new MiningV1Data.PriceSheetPub2[](num);
MiningV1Data.PriceSheet[] storage _list = state.priceSheetList[token];
uint256 len = _list.length;
require(fromIndex < len, "Nest:Mine:!from");
for (uint i = 0; i < num; i++) {
if (fromIndex < i) {
break;
}
MiningV1Data.PriceSheet memory _sheet = _list[fromIndex - i];
if (uint256(_sheet.miner) == uint256(miner)) {
sheets[i].miner = _sheet.miner;
sheets[i].height = _sheet.height;
sheets[i].ethNum = _sheet.ethNum;
sheets[i].remainNum = _sheet.remainNum;
sheets[i].level = _sheet.level;
sheets[i].typ = _sheet.typ;
sheets[i].state = _sheet.state;
sheets[i].index = fromIndex - i;
sheets[i].nestNum1k = _sheet.nestNum1k;
sheets[i].tokenAmountPerEth = _sheet.tokenAmountPerEth;
}
}
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
import "../lib/SafeMath.sol";
import "../lib/SafeERC20.sol";
import '../lib/TransferHelper.sol';
import "../lib/ABDKMath64x64.sol";
import "../iface/INestPool.sol";
import "../iface/INestStaking.sol";
import "../iface/INToken.sol";
import "../iface/INNRewardPool.sol";
import "../libminingv1/MiningV1Data.sol";
//import "hardhat/console.sol";
/// @title NestMiningV1/MiningV1Calc
/// @author Inf Loop - <inf-loop@nestprotocol.org>
/// @author Paradox - <paradox@nestprotocol.org>
library MiningV1Op {
using SafeMath for uint256;
/// @notice Call the function to buy TOKEN/NTOKEN from a posted price sheet
/// @dev bite TOKEN(NTOKEN) by ETH, (+ethNumBal, -tokenNumBal)
/// @param token The address of token(ntoken)
/// @param index The position of the sheet in priceSheetList[token]
/// @param biteNum The amount of bitting (in the unit of ETH), realAmount = biteNum * newTokenAmountPerEth
/// @param newTokenAmountPerEth The new price of token (1 ETH : some TOKEN), here some means newTokenAmountPerEth
function _biteToken(
MiningV1Data.State storage state,
address token,
uint256 index,
uint256 biteNum,
uint256 newTokenAmountPerEth
)
external
{
// check parameters
require(token != address(0x0), "Nest:Mine:(token)=0");
require(newTokenAmountPerEth > 0, "Nest:Mine:(price)=0");
require(biteNum >= state.miningEthUnit && biteNum % state.miningEthUnit == 0, "Nest:Mine:!(bite)");
// check sheet
MiningV1Data.PriceSheet memory _sheet = state.priceSheetList[token][index];
require(_sheet.height + state.priceDurationBlock >= block.number, "Nest:Mine:!EFF(sheet)");
require(_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)");
{
address _ntoken = _C_NestPool.getNTokenFromToken(token);
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 = _level;
if (_level > state.maxBiteNestedLevel && _level < 127) { // bitten sheet, nest doubling
_newEthNum = biteNum;
_newNestNum1k = _newNestNum1k.mul(state.biteNestInflateFactor * biteNum).div(_sheet.ethNum);
_newLevel = _level + 1;
} else if (_level <= state.maxBiteNestedLevel) { // bitten sheet, eth doubling
_newEthNum = biteNum.mul(state.biteInflateFactor);
_newNestNum1k = _newNestNum1k.mul(state.biteNestInflateFactor * biteNum).div(_sheet.ethNum);
_newLevel = _level + 1;
}
_C_NestPool.freezeNest(address(msg.sender), _newNestNum1k.mul(1000 * 1e18));
if( _newEthNum.mul(newTokenAmountPerEth) < biteNum * _sheet.tokenAmountPerEth) {
uint256 _unfreezetokenAmount;
//_unfreezetokenAmount = uint256(_sheet.tokenAmountPerEth).sub(uint256(newTokenAmountPerEth)).mul(biteNum);
_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
));
}
_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
{
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(block.number.sub(_sheet.height) <= state.priceDurationBlock, "Nest:Mine:!EFF(sheet)");
require(_sheet.remainNum >= biteNum, "Nest:Mine:!(remain)");
INestPool _C_NestPool = INestPool(state.C_NestPool);
uint256 _state = uint256(_sheet.state);
require(_state == MiningV1Data.PRICESHEET_STATE_POSTED
|| _state == MiningV1Data.PRICESHEET_STATE_BITTEN, "Nest:Mine:!(state)");
{
address _ntoken = _C_NestPool.getNTokenFromToken(token);
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
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 = _level;
if (_level > state.maxBiteNestedLevel && _level < 127) { // bitten sheet, nest doubling
_newEthNum = biteNum;
_newNestNum1k = _newNestNum1k.mul(state.biteNestInflateFactor * biteNum).div(_sheet.ethNum);
_newLevel = _level + 1;
} else if (_level <= state.maxBiteNestedLevel) { // bitten sheet, eth doubling
_newEthNum = biteNum.mul(state.biteInflateFactor);
_newNestNum1k = _newNestNum1k.mul(state.biteNestInflateFactor * biteNum).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
));
}
_C_NestPool.freezeNest(address(msg.sender), _newNestNum1k.mul(1000 * 1e18));
_C_NestPool.freezeEthAndToken(msg.sender, _newEthNum.sub(biteNum).mul(1 ether),
token, _newEthNum.mul(newTokenAmountPerEth)
.add(biteNum * _sheet.tokenAmountPerEth));
_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(_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 backs
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(_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 = _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: Copyright © 2019 by ABDK Consulting
/*
* ABDK Math 64.64 Smart Contract Library. Copyright © 2019 by ABDK Consulting.
* Author: Mikhail Vladimirov <mikhail.vladimirov@gmail.com>
*/
pragma solidity 0.6.12;
/**
* Smart contract library of mathematical functions operating with signed
* 64.64-bit fixed point numbers. Signed 64.64-bit fixed point number is
* basically a simple fraction whose numerator is signed 128-bit integer and
* denominator is 2^64. As long as denominator is always the same, there is no
* need to store it, thus in Solidity signed 64.64-bit fixed point numbers are
* represented by int128 type holding only the numerator.
*/
library ABDKMath64x64 {
/**
* @dev Minimum value signed 64.64-bit fixed point number may have.
*/
int128 private constant MIN_64x64 = -0x80000000000000000000000000000000;
/**
* @dev Maximum value signed 64.64-bit fixed point number may have.
*/
int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
/**
* Convert signed 256-bit integer number into signed 64.64-bit fixed point
* number. Revert on overflow.
*
* @param x signed 256-bit integer number
* @return signed 64.64-bit fixed point number
*/
function fromInt (int256 x) internal pure returns (int128) {
require (x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF);
return int128 (x << 64);
}
/**
* Convert signed 64.64 fixed point number into signed 64-bit integer number
* rounding down.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64-bit integer number
*/
function toInt (int128 x) internal pure returns (int64) {
return int64 (x >> 64);
}
/**
* Convert unsigned 256-bit integer number into signed 64.64-bit fixed point
* number. Revert on overflow.
*
* @param x unsigned 256-bit integer number
* @return signed 64.64-bit fixed point number
*/
function fromUInt (uint256 x) internal pure returns (int128) {
require (x <= 0x7FFFFFFFFFFFFFFF);
return int128 (x << 64);
}
/**
* Convert signed 64.64 fixed point number into unsigned 64-bit integer
* number rounding down. Revert on underflow.
*
* @param x signed 64.64-bit fixed point number
* @return unsigned 64-bit integer number
*/
function toUInt (int128 x) internal pure returns (uint64) {
require (x >= 0);
return uint64 (x >> 64);
}
/**
* Convert signed 128.128 fixed point number into signed 64.64-bit fixed point
* number rounding down. Revert on overflow.
*
* @param x signed 128.128-bin fixed point number
* @return signed 64.64-bit fixed point number
*/
function from128x128 (int256 x) internal pure returns (int128) {
int256 result = x >> 64;
require (result >= MIN_64x64 && result <= MAX_64x64);
return int128 (result);
}
/**
* Convert signed 64.64 fixed point number into signed 128.128 fixed point
* number.
*
* @param x signed 64.64-bit fixed point number
* @return signed 128.128 fixed point number
*/
function to128x128 (int128 x) internal pure returns (int256) {
return int256 (x) << 64;
}
/**
* Calculate x + y. Revert on overflow.
*
* @param x signed 64.64-bit fixed point number
* @param y signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function add (int128 x, int128 y) internal pure returns (int128) {
int256 result = int256(x) + y;
require (result >= MIN_64x64 && result <= MAX_64x64);
return int128 (result);
}
/**
* Calculate x - y. Revert on overflow.
*
* @param x signed 64.64-bit fixed point number
* @param y signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function sub (int128 x, int128 y) internal pure returns (int128) {
int256 result = int256(x) - y;
require (result >= MIN_64x64 && result <= MAX_64x64);
return int128 (result);
}
/**
* Calculate x * y rounding down. Revert on overflow.
*
* @param x signed 64.64-bit fixed point number
* @param y signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function mul (int128 x, int128 y) internal pure returns (int128) {
int256 result = int256(x) * y >> 64;
require (result >= MIN_64x64 && result <= MAX_64x64);
return int128 (result);
}
/**
* Calculate x * y rounding towards zero, where x is signed 64.64 fixed point
* number and y is signed 256-bit integer number. Revert on overflow.
*
* @param x signed 64.64 fixed point number
* @param y signed 256-bit integer number
* @return signed 256-bit integer number
*/
function muli (int128 x, int256 y) internal pure returns (int256) {
if (x == MIN_64x64) {
require (y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF &&
y <= 0x1000000000000000000000000000000000000000000000000);
return -y << 63;
} else {
bool negativeResult = false;
if (x < 0) {
x = -x;
negativeResult = true;
}
if (y < 0) {
y = -y; // We rely on overflow behavior here
negativeResult = !negativeResult;
}
uint256 absoluteResult = mulu (x, uint256 (y));
if (negativeResult) {
require (absoluteResult <=
0x8000000000000000000000000000000000000000000000000000000000000000);
return -int256 (absoluteResult); // We rely on overflow behavior here
} else {
require (absoluteResult <=
0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
return int256 (absoluteResult);
}
}
}
/**
* Calculate x * y rounding down, where x is signed 64.64 fixed point number
* and y is unsigned 256-bit integer number. Revert on overflow.
*
* @param x signed 64.64 fixed point number
* @param y unsigned 256-bit integer number
* @return unsigned 256-bit integer number
*/
function mulu (int128 x, uint256 y) internal pure returns (uint256) {
if (y == 0) return 0;
require (x >= 0);
uint256 lo = (uint256 (x) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64;
uint256 hi = uint256 (x) * (y >> 128);
require (hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
hi <<= 64;
require (hi <=
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo);
return hi + lo;
}
/**
* Calculate x / y rounding towards zero. Revert on overflow or when y is
* zero.
*
* @param x signed 64.64-bit fixed point number
* @param y signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function div (int128 x, int128 y) internal pure returns (int128) {
require (y != 0);
int256 result = (int256 (x) << 64) / y;
require (result >= MIN_64x64 && result <= MAX_64x64);
return int128 (result);
}
/**
* Calculate x / y rounding towards zero, where x and y are signed 256-bit
* integer numbers. Revert on overflow or when y is zero.
*
* @param x signed 256-bit integer number
* @param y signed 256-bit integer number
* @return signed 64.64-bit fixed point number
*/
function divi (int256 x, int256 y) internal pure returns (int128) {
require (y != 0);
bool negativeResult = false;
if (x < 0) {
x = -x; // We rely on overflow behavior here
negativeResult = true;
}
if (y < 0) {
y = -y; // We rely on overflow behavior here
negativeResult = !negativeResult;
}
uint128 absoluteResult = divuu (uint256 (x), uint256 (y));
if (negativeResult) {
require (absoluteResult <= 0x80000000000000000000000000000000);
return -int128 (absoluteResult); // We rely on overflow behavior here
} else {
require (absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
return int128 (absoluteResult); // We rely on overflow behavior here
}
}
/**
* Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
* integer numbers. Revert on overflow or when y is zero.
*
* @param x unsigned 256-bit integer number
* @param y unsigned 256-bit integer number
* @return signed 64.64-bit fixed point number
*/
function divu (uint256 x, uint256 y) internal pure returns (int128) {
require (y != 0);
uint128 result = divuu (x, y);
require (result <= uint128 (MAX_64x64));
return int128 (result);
}
/**
* Calculate -x. Revert on overflow.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function neg (int128 x) internal pure returns (int128) {
require (x != MIN_64x64);
return -x;
}
/**
* Calculate |x|. Revert on overflow.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function abs (int128 x) internal pure returns (int128) {
require (x != MIN_64x64);
return x < 0 ? -x : x;
}
/**
* Calculate 1 / x rounding towards zero. Revert on overflow or when x is
* zero.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function inv (int128 x) internal pure returns (int128) {
require (x != 0);
int256 result = int256 (0x100000000000000000000000000000000) / x;
require (result >= MIN_64x64 && result <= MAX_64x64);
return int128 (result);
}
/**
* Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down.
*
* @param x signed 64.64-bit fixed point number
* @param y signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function avg (int128 x, int128 y) internal pure returns (int128) {
return int128 ((int256 (x) + int256 (y)) >> 1);
}
/**
* Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down.
* Revert on overflow or in case x * y is negative.
*
* @param x signed 64.64-bit fixed point number
* @param y signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function gavg (int128 x, int128 y) internal pure returns (int128) {
int256 m = int256 (x) * int256 (y);
require (m >= 0);
require (m <
0x4000000000000000000000000000000000000000000000000000000000000000);
return int128 (sqrtu (uint256 (m), uint256 (x) + uint256 (y) >> 1));
}
/**
* Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number
* and y is unsigned 256-bit integer number. Revert on overflow.
*
* @param x signed 64.64-bit fixed point number
* @param y uint256 value
* @return signed 64.64-bit fixed point number
*/
function pow (int128 x, uint256 y) internal pure returns (int128) {
uint256 absoluteResult;
bool negativeResult = false;
if (x >= 0) {
absoluteResult = powu (uint256 (x) << 63, y);
} else {
// We rely on overflow behavior here
absoluteResult = powu (uint256 (uint128 (-x)) << 63, y);
negativeResult = y & 1 > 0;
}
absoluteResult >>= 63;
if (negativeResult) {
require (absoluteResult <= 0x80000000000000000000000000000000);
return -int128 (absoluteResult); // We rely on overflow behavior here
} else {
require (absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
return int128 (absoluteResult); // We rely on overflow behavior here
}
}
/**
* Calculate sqrt (x) rounding down. Revert if x < 0.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function sqrt (int128 x) internal pure returns (int128) {
require (x >= 0);
return int128 (sqrtu (uint256 (x) << 64, 0x10000000000000000));
}
/**
* Calculate binary logarithm of x. Revert if x <= 0.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function log_2 (int128 x) internal pure returns (int128) {
require (x > 0);
int256 msb = 0;
int256 xc = x;
if (xc >= 0x10000000000000000) { xc >>= 64; msb += 64; }
if (xc >= 0x100000000) { xc >>= 32; msb += 32; }
if (xc >= 0x10000) { xc >>= 16; msb += 16; }
if (xc >= 0x100) { xc >>= 8; msb += 8; }
if (xc >= 0x10) { xc >>= 4; msb += 4; }
if (xc >= 0x4) { xc >>= 2; msb += 2; }
if (xc >= 0x2) msb += 1; // No need to shift xc anymore
int256 result = msb - 64 << 64;
uint256 ux = uint256 (x) << 127 - msb;
for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) {
ux *= ux;
uint256 b = ux >> 255;
ux >>= 127 + b;
result += bit * int256 (b);
}
return int128 (result);
}
/**
* Calculate natural logarithm of x. Revert if x <= 0.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function ln (int128 x) internal pure returns (int128) {
require (x > 0);
return int128 (
uint256 (log_2 (x)) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF >> 128);
}
/**
* Calculate binary exponent of x. Revert on overflow.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function exp_2 (int128 x) internal pure returns (int128) {
require (x < 0x400000000000000000); // Overflow
if (x < -0x400000000000000000) return 0; // Underflow
uint256 result = 0x80000000000000000000000000000000;
if (x & 0x8000000000000000 > 0)
result = result * 0x16A09E667F3BCC908B2FB1366EA957D3E >> 128;
if (x & 0x4000000000000000 > 0)
result = result * 0x1306FE0A31B7152DE8D5A46305C85EDEC >> 128;
if (x & 0x2000000000000000 > 0)
result = result * 0x1172B83C7D517ADCDF7C8C50EB14A791F >> 128;
if (x & 0x1000000000000000 > 0)
result = result * 0x10B5586CF9890F6298B92B71842A98363 >> 128;
if (x & 0x800000000000000 > 0)
result = result * 0x1059B0D31585743AE7C548EB68CA417FD >> 128;
if (x & 0x400000000000000 > 0)
result = result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8 >> 128;
if (x & 0x200000000000000 > 0)
result = result * 0x10163DA9FB33356D84A66AE336DCDFA3F >> 128;
if (x & 0x100000000000000 > 0)
result = result * 0x100B1AFA5ABCBED6129AB13EC11DC9543 >> 128;
if (x & 0x80000000000000 > 0)
result = result * 0x10058C86DA1C09EA1FF19D294CF2F679B >> 128;
if (x & 0x40000000000000 > 0)
result = result * 0x1002C605E2E8CEC506D21BFC89A23A00F >> 128;
if (x & 0x20000000000000 > 0)
result = result * 0x100162F3904051FA128BCA9C55C31E5DF >> 128;
if (x & 0x10000000000000 > 0)
result = result * 0x1000B175EFFDC76BA38E31671CA939725 >> 128;
if (x & 0x8000000000000 > 0)
result = result * 0x100058BA01FB9F96D6CACD4B180917C3D >> 128;
if (x & 0x4000000000000 > 0)
result = result * 0x10002C5CC37DA9491D0985C348C68E7B3 >> 128;
if (x & 0x2000000000000 > 0)
result = result * 0x1000162E525EE054754457D5995292026 >> 128;
if (x & 0x1000000000000 > 0)
result = result * 0x10000B17255775C040618BF4A4ADE83FC >> 128;
if (x & 0x800000000000 > 0)
result = result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB >> 128;
if (x & 0x400000000000 > 0)
result = result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9 >> 128;
if (x & 0x200000000000 > 0)
result = result * 0x10000162E43F4F831060E02D839A9D16D >> 128;
if (x & 0x100000000000 > 0)
result = result * 0x100000B1721BCFC99D9F890EA06911763 >> 128;
if (x & 0x80000000000 > 0)
result = result * 0x10000058B90CF1E6D97F9CA14DBCC1628 >> 128;
if (x & 0x40000000000 > 0)
result = result * 0x1000002C5C863B73F016468F6BAC5CA2B >> 128;
if (x & 0x20000000000 > 0)
result = result * 0x100000162E430E5A18F6119E3C02282A5 >> 128;
if (x & 0x10000000000 > 0)
result = result * 0x1000000B1721835514B86E6D96EFD1BFE >> 128;
if (x & 0x8000000000 > 0)
result = result * 0x100000058B90C0B48C6BE5DF846C5B2EF >> 128;
if (x & 0x4000000000 > 0)
result = result * 0x10000002C5C8601CC6B9E94213C72737A >> 128;
if (x & 0x2000000000 > 0)
result = result * 0x1000000162E42FFF037DF38AA2B219F06 >> 128;
if (x & 0x1000000000 > 0)
result = result * 0x10000000B17217FBA9C739AA5819F44F9 >> 128;
if (x & 0x800000000 > 0)
result = result * 0x1000000058B90BFCDEE5ACD3C1CEDC823 >> 128;
if (x & 0x400000000 > 0)
result = result * 0x100000002C5C85FE31F35A6A30DA1BE50 >> 128;
if (x & 0x200000000 > 0)
result = result * 0x10000000162E42FF0999CE3541B9FFFCF >> 128;
if (x & 0x100000000 > 0)
result = result * 0x100000000B17217F80F4EF5AADDA45554 >> 128;
if (x & 0x80000000 > 0)
result = result * 0x10000000058B90BFBF8479BD5A81B51AD >> 128;
if (x & 0x40000000 > 0)
result = result * 0x1000000002C5C85FDF84BD62AE30A74CC >> 128;
if (x & 0x20000000 > 0)
result = result * 0x100000000162E42FEFB2FED257559BDAA >> 128;
if (x & 0x10000000 > 0)
result = result * 0x1000000000B17217F7D5A7716BBA4A9AE >> 128;
if (x & 0x8000000 > 0)
result = result * 0x100000000058B90BFBE9DDBAC5E109CCE >> 128;
if (x & 0x4000000 > 0)
result = result * 0x10000000002C5C85FDF4B15DE6F17EB0D >> 128;
if (x & 0x2000000 > 0)
result = result * 0x1000000000162E42FEFA494F1478FDE05 >> 128;
if (x & 0x1000000 > 0)
result = result * 0x10000000000B17217F7D20CF927C8E94C >> 128;
if (x & 0x800000 > 0)
result = result * 0x1000000000058B90BFBE8F71CB4E4B33D >> 128;
if (x & 0x400000 > 0)
result = result * 0x100000000002C5C85FDF477B662B26945 >> 128;
if (x & 0x200000 > 0)
result = result * 0x10000000000162E42FEFA3AE53369388C >> 128;
if (x & 0x100000 > 0)
result = result * 0x100000000000B17217F7D1D351A389D40 >> 128;
if (x & 0x80000 > 0)
result = result * 0x10000000000058B90BFBE8E8B2D3D4EDE >> 128;
if (x & 0x40000 > 0)
result = result * 0x1000000000002C5C85FDF4741BEA6E77E >> 128;
if (x & 0x20000 > 0)
result = result * 0x100000000000162E42FEFA39FE95583C2 >> 128;
if (x & 0x10000 > 0)
result = result * 0x1000000000000B17217F7D1CFB72B45E1 >> 128;
if (x & 0x8000 > 0)
result = result * 0x100000000000058B90BFBE8E7CC35C3F0 >> 128;
if (x & 0x4000 > 0)
result = result * 0x10000000000002C5C85FDF473E242EA38 >> 128;
if (x & 0x2000 > 0)
result = result * 0x1000000000000162E42FEFA39F02B772C >> 128;
if (x & 0x1000 > 0)
result = result * 0x10000000000000B17217F7D1CF7D83C1A >> 128;
if (x & 0x800 > 0)
result = result * 0x1000000000000058B90BFBE8E7BDCBE2E >> 128;
if (x & 0x400 > 0)
result = result * 0x100000000000002C5C85FDF473DEA871F >> 128;
if (x & 0x200 > 0)
result = result * 0x10000000000000162E42FEFA39EF44D91 >> 128;
if (x & 0x100 > 0)
result = result * 0x100000000000000B17217F7D1CF79E949 >> 128;
if (x & 0x80 > 0)
result = result * 0x10000000000000058B90BFBE8E7BCE544 >> 128;
if (x & 0x40 > 0)
result = result * 0x1000000000000002C5C85FDF473DE6ECA >> 128;
if (x & 0x20 > 0)
result = result * 0x100000000000000162E42FEFA39EF366F >> 128;
if (x & 0x10 > 0)
result = result * 0x1000000000000000B17217F7D1CF79AFA >> 128;
if (x & 0x8 > 0)
result = result * 0x100000000000000058B90BFBE8E7BCD6D >> 128;
if (x & 0x4 > 0)
result = result * 0x10000000000000002C5C85FDF473DE6B2 >> 128;
if (x & 0x2 > 0)
result = result * 0x1000000000000000162E42FEFA39EF358 >> 128;
if (x & 0x1 > 0)
result = result * 0x10000000000000000B17217F7D1CF79AB >> 128;
result >>= 63 - (x >> 64);
require (result <= uint256 (MAX_64x64));
return int128 (result);
}
/**
* Calculate natural exponent of x. Revert on overflow.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function exp (int128 x) internal pure returns (int128) {
require (x < 0x400000000000000000); // Overflow
if (x < -0x400000000000000000) return 0; // Underflow
return exp_2 (
int128 (int256 (x) * 0x171547652B82FE1777D0FFDA0D23A7D12 >> 128));
}
/**
* Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
* integer numbers. Revert on overflow or when y is zero.
*
* @param x unsigned 256-bit integer number
* @param y unsigned 256-bit integer number
* @return unsigned 64.64-bit fixed point number
*/
function divuu (uint256 x, uint256 y) private pure returns (uint128) {
require (y != 0);
uint256 result;
if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
result = (x << 64) / y;
else {
uint256 msb = 192;
uint256 xc = x >> 192;
if (xc >= 0x100000000) { xc >>= 32; msb += 32; }
if (xc >= 0x10000) { xc >>= 16; msb += 16; }
if (xc >= 0x100) { xc >>= 8; msb += 8; }
if (xc >= 0x10) { xc >>= 4; msb += 4; }
if (xc >= 0x4) { xc >>= 2; msb += 2; }
if (xc >= 0x2) msb += 1; // No need to shift xc anymore
result = (x << 255 - msb) / ((y - 1 >> msb - 191) + 1);
require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
uint256 hi = result * (y >> 128);
uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
uint256 xh = x >> 192;
uint256 xl = x << 64;
if (xl < lo) xh -= 1;
xl -= lo; // We rely on overflow behavior here
lo = hi << 128;
if (xl < lo) xh -= 1;
xl -= lo; // We rely on overflow behavior here
assert (xh == hi >> 128);
result += xl / y;
}
require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
return uint128 (result);
}
/**
* Calculate x^y assuming 0^0 is 1, where x is unsigned 129.127 fixed point
* number and y is unsigned 256-bit integer number. Revert on overflow.
*
* @param x unsigned 129.127-bit fixed point number
* @param y uint256 value
* @return unsigned 129.127-bit fixed point number
*/
function powu (uint256 x, uint256 y) private pure returns (uint256) {
if (y == 0) return 0x80000000000000000000000000000000;
else if (x == 0) return 0;
else {
int256 msb = 0;
uint256 xc = x;
if (xc >= 0x100000000000000000000000000000000) { xc >>= 128; msb += 128; }
if (xc >= 0x10000000000000000) { xc >>= 64; msb += 64; }
if (xc >= 0x100000000) { xc >>= 32; msb += 32; }
if (xc >= 0x10000) { xc >>= 16; msb += 16; }
if (xc >= 0x100) { xc >>= 8; msb += 8; }
if (xc >= 0x10) { xc >>= 4; msb += 4; }
if (xc >= 0x4) { xc >>= 2; msb += 2; }
if (xc >= 0x2) msb += 1; // No need to shift xc anymore
int256 xe = msb - 127;
if (xe > 0) x >>= xe;
else x <<= -xe;
uint256 result = 0x80000000000000000000000000000000;
int256 re = 0;
while (y > 0) {
if (y & 1 > 0) {
result = result * x;
y -= 1;
re += xe;
if (result >=
0x8000000000000000000000000000000000000000000000000000000000000000) {
result >>= 128;
re += 1;
} else result >>= 127;
if (re < -127) return 0; // Underflow
require (re < 128); // Overflow
} else {
x = x * x;
y >>= 1;
xe <<= 1;
if (x >=
0x8000000000000000000000000000000000000000000000000000000000000000) {
x >>= 128;
xe += 1;
} else x >>= 127;
if (xe < -127) return 0; // Underflow
require (xe < 128); // Overflow
}
}
if (re > 0) result <<= re;
else if (re < 0) result >>= -re;
return result;
}
}
/**
* Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer
* number.
*
* @param x unsigned 256-bit integer number
* @return unsigned 128-bit integer number
*/
function sqrtu (uint256 x, uint256 r) private pure returns (uint128) {
if (x == 0) return 0;
else {
require (r > 0);
while (true) {
uint256 rr = x / r;
if (r == rr || r + 1 == rr) return uint128 (r);
else if (r == rr + 1) return uint128 (rr);
r = r + rr + 1 >> 1;
}
}
}
}// 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;
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;
pragma experimental ABIEncoderV2;
import "../iface/INestQuery.sol";
contract DeFiMock {
INestQuery _NestQuery;
struct PriceInfo {
address token;
uint256 atHeight;
uint256 ethAmount;
uint256 tokenAmount;
}
PriceInfo[] public prices;
constructor(address Oracle) public {
_NestQuery = INestQuery(Oracle);
}
function simu() public {
return;
}
function query(address token) payable public {
(uint256 ethAmount, uint256 tokenAmount, uint256 bn) = _NestQuery.query{value:msg.value}(token, msg.sender);
prices.push(PriceInfo(token, bn, ethAmount, tokenAmount));
}
// function queryOracle(address token) payable public {
// uint128[] memory data = _NestOracle.queryPriceList{value:msg.value}(token, uint8(4), msg.sender);
// for (uint256 i=0; i<data.length; i=i+3) {
// _prices.push(PriceInfo(token, data[i], data[i+1], data[i+2]));
// }
// }
function lengthOfPrices() public view returns (uint256) {
return prices.length;
}
function priceByIndex(uint256 index) public view returns (PriceInfo memory) {
return prices[index];
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.6.12;
import "../lib/SafeMath.sol";
import "../iface/INToken.sol";
import "../iface/INTokenLegacy.sol";
contract NestNToken is INTokenLegacy {
using SafeMath for uint256;
mapping (address => uint256) private _balances; // 账本
mapping (address => mapping (address => uint256)) private _allowed; // 授权账本
uint256 private _totalSupply = 1e9 ether; // 总量
string public name; // 名称
string public symbol; // 简称
uint8 public decimals = 18; // 精度
uint256 public _createBlock; // 创建区块
uint256 public _recentlyUsedBlock; // 最近使用区块
address _voteFactory; // 投票合约
// Nest_3_VoteFactory _voteFactory; // 投票合约
address _bidder; // 拥有者
address offerMain;
constructor (uint256 total, string memory _name, string memory _symbol, address bidder) public
{
_totalSupply = total;
_bidder = bidder;
name = _name;
_createBlock = block.number;
_recentlyUsedBlock = block.number;
_balances[bidder] = _totalSupply;
}
function setOfferMain(address _offerMain) public {
offerMain = _offerMain;
}
// constructor (string memory _name, string memory _symbol, address voteFactory, address bidder) public {
// name = _name;
// symbol = _symbol;
// _createBlock = block.number;
// _recentlyUsedBlock = block.number;
// _voteFactory = address(voteFactory);
// // _voteFactory = Nest_3_VoteFactory(address(voteFactory));
// _bidder = bidder;
// _balances[bidder] = _totalSupply;
// }
/**
* @dev 重置投票合约方法
* @param voteFactory 投票合约地址
*/
function changeMapping (address voteFactory) public onlyOwner {
_voteFactory = address(voteFactory);
// _voteFactory = Nest_3_VoteFactory(address(voteFactory));
}
/**
* @dev 增发
* @param value 增发数量
*/
function increaseTotal(uint256 value) override public {
// address offerMain = address(_voteFactory.checkAddress("nest.nToken.offerMain"));
// require(address(msg.sender) == offerMain, "No authority");
_balances[offerMain] = _balances[offerMain].add(value);
_totalSupply = _totalSupply.add(value);
_recentlyUsedBlock = block.number;
}
// TODO: only for debugging
function increaseTotal2(uint256 value, address offerMain) public {
// address offerMain = address(_voteFactory.checkAddress("nest.nToken.offerMain"));
// require(address(msg.sender) == offerMain, "No authority");
_balances[offerMain] = _balances[offerMain].add(value);
_totalSupply = _totalSupply.add(value);
_recentlyUsedBlock = block.number;
}
/**
* @dev 查询token总量
* @return token总量
*/
function totalSupply() override public view returns (uint256) {
return _totalSupply;
}
/**
* @dev 查询地址余额
* @param owner 要查询的地址
* @return 返回对应地址的余额
*/
function balanceOf(address owner) override public view returns (uint256) {
return _balances[owner];
}
/**
* @dev 查询区块信息
* @return createBlock 初始区块数
* @return recentlyUsedBlock 最近挖矿增发区块
*/
function checkBlockInfo() override public view returns(uint256 createBlock, uint256 recentlyUsedBlock) {
return (_createBlock, _recentlyUsedBlock);
}
/**
* @dev 查询 owner 对 spender 的授权额度
* @param owner 发起授权的地址
* @param spender 被授权的地址
* @return 已授权的金额
*/
function allowance(address owner, address spender) override public view returns (uint256) {
return _allowed[owner][spender];
}
/**
* @dev 转账方法
* @param to 转账目标
* @param value 转账金额
* @return 转账是否成功
*/
function transfer(address to, uint256 value) override public returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
/**
* @dev 授权方法
* @param spender 授权目标
* @param value 授权数量
* @return 授权是否成功
*/
function approve(address spender, uint256 value) override public returns (bool) {
require(spender != address(0));
_allowed[msg.sender][spender] = value;
emit Approval(msg.sender, spender, value);
return true;
}
/**
* @dev 已授权状态下,从 from地址转账到to地址
* @param from 转出的账户地址
* @param to 转入的账户地址
* @param value 转账金额
* @return 授权转账是否成功
*/
function transferFrom(address from, address to, uint256 value) override public returns (bool) {
_allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value);
_transfer(from, to, value);
emit Approval(from, msg.sender, _allowed[from][msg.sender]);
return true;
}
/**
* @dev 增加授权额度
* @param spender 授权目标
* @param addedValue 增加的额度
* @return 增加授权额度是否成功
*/
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
require(spender != address(0));
_allowed[msg.sender][spender] = _allowed[msg.sender][spender].add(addedValue);
emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
return true;
}
/**
* @dev 减少授权额度
* @param spender 授权目标
* @param subtractedValue 减少的额度
* @return 减少授权额度是否成功
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
require(spender != address(0));
_allowed[msg.sender][spender] = _allowed[msg.sender][spender].sub(subtractedValue);
emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
return true;
}
/**
* @dev 转账方法
* @param to 转账目标
* @param value 转账金额
*/
function _transfer(address from, address to, uint256 value) internal {
_balances[from] = _balances[from].sub(value);
_balances[to] = _balances[to].add(value);
emit Transfer(from, to, value);
}
/**
* @dev 查询创建者
* @return 创建者地址
*/
function checkBidder() override public view returns(address) {
return _bidder;
}
/**
* @dev 转让创建者
* @param bidder 新创建者地址
*/
function changeBidder(address bidder) public {
require(address(msg.sender) == _bidder);
_bidder = bidder;
}
// 仅限管理员操作
modifier onlyOwner(){
// require(_voteFactory.checkOwners(msg.sender));
_;
}
}pragma solidity 0.6.12;
import "../lib/SafeMath.sol";
import "../iface/INNRewardPool.sol";
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address who) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
/**
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
* Originally based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*
* This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for
* all accounts just by listening to said events. Note that this isn't required by the specification, and other
* compliant implementations may not do it.
*/
contract SuperMan is IERC20 {
using SafeMath for uint256;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowed;
IBMapping mappingContract; //映射合约
uint256 private _totalSupply = 1500;
string public name = "NestNode";
string public symbol = "NN";
uint8 public decimals = 0;
constructor (address map) public {
_balances[msg.sender] = _totalSupply;
mappingContract = IBMapping(map);
}
function changeMapping(address map) public onlyOwner{
mappingContract = IBMapping(map);
}
/**
* @dev Total number of tokens in existence
*/
function totalSupply() override public view returns (uint256) {
return _totalSupply;
}
/**
* @dev Gets the balance of the specified address.
* @param owner The address to query the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address owner) override public view returns (uint256) {
return _balances[owner];
}
/**
* @dev Function to check the amount of tokens that an owner allowed to a spender.
* @param owner address The address which owns the funds.
* @param spender address The address which will spend the funds.
* @return A uint256 specifying the amount of tokens still available for the spender.
*/
function allowance(address owner, address spender) override public view returns (uint256) {
return _allowed[owner][spender];
}
/**
* @dev Transfer token for a specified address
* @param to The address to transfer to.
* @param value The amount to be transferred.
*/
function transfer(address to, uint256 value) override public returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
* Beware that changing an allowance with this method brings the risk that someone may use both the old
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
*/
function approve(address spender, uint256 value) override public returns (bool) {
require(spender != address(0));
_allowed[msg.sender][spender] = value;
emit Approval(msg.sender, spender, value);
return true;
}
/**
* @dev Transfer tokens from one address to another.
* Note that while this function emits an Approval event, this is not required as per the specification,
* and other compliant implementations may not emit the event.
* @param from address The address which you want to send tokens from
* @param to address The address which you want to transfer to
* @param value uint256 the amount of tokens to be transferred
*/
function transferFrom(address from, address to, uint256 value) override public returns (bool) {
_allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value);
_transfer(from, to, value);
emit Approval(from, msg.sender, _allowed[from][msg.sender]);
return true;
}
/**
* @dev Increase the amount of tokens that an owner allowed to a spender.
* approve should be called when allowed_[_spender] == 0. To increment
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* Emits an Approval event.
* @param spender The address which will spend the funds.
* @param addedValue The amount of tokens to increase the allowance by.
*/
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
require(spender != address(0));
_allowed[msg.sender][spender] = _allowed[msg.sender][spender].add(addedValue);
emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
return true;
}
/**
* @dev Decrease the amount of tokens that an owner allowed to a spender.
* approve should be called when allowed_[_spender] == 0. To decrement
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* Emits an Approval event.
* @param spender The address which will spend the funds.
* @param subtractedValue The amount of tokens to decrease the allowance by.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
require(spender != address(0));
_allowed[msg.sender][spender] = _allowed[msg.sender][spender].sub(subtractedValue);
emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
return true;
}
/**
* @dev Transfer token for a specified addresses
* @param from The address to transfer from.
* @param to The address to transfer to.
* @param value The amount to be transferred.
*/
function _transfer(address from, address to, uint256 value) internal {
require(to != address(0));
INNRewardPool nodeAssignment = INNRewardPool(address(mappingContract.checkAddress("nodeAssignment")));
nodeAssignment.nodeCount(from, to);
_balances[from] = _balances[from].sub(value);
_balances[to] = _balances[to].add(value);
emit Transfer(from, to, value);
}
// 仅限管理员
modifier onlyOwner(){
require(mappingContract.checkOwners(msg.sender) == true);
_;
}
}
// 映射合约
contract IBMapping {
mapping(string => address) _contractAddress; // 投票合约映射
// 查询地址
function checkAddress(string memory name) public view returns (address contractAddress) {
return _contractAddress[name];
}
// // 添加合约映射地址
// function addContractAddress(string memory name, address contractAddress) public onlyOwner {
// _contractAddress[name] = contractAddress;
// }
// 查看是否管理员 //TODO:
function checkOwners(address man) public view returns (bool) {
return true;
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"NestPool","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"C_NestDAO","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"C_NestMining","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"C_NestPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"C_NestToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flag","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestHeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minedNestAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nestBal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ntoken_num1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ntoken_num2","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"resume","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setGov","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"usdtToken","type":"address"},{"internalType":"address","name":"Nest_NToken_TokenMapping","type":"address"},{"internalType":"address[]","name":"tokenL","type":"address[]"}],"name":"setPairsOfTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"Nest_3_MiningContract","type":"address"},{"internalType":"address","name":"Nest_NToken_TokenAuction","type":"address"},{"internalType":"address","name":"Nest_NToken_TokenMapping","type":"address"},{"components":[{"internalType":"uint8","name":"miningEthUnit","type":"uint8"},{"internalType":"uint32","name":"nestStakedNum1k","type":"uint32"},{"internalType":"uint8","name":"biteFeeRate","type":"uint8"},{"internalType":"uint8","name":"miningFeeRate","type":"uint8"},{"internalType":"uint8","name":"priceDurationBlock","type":"uint8"},{"internalType":"uint8","name":"maxBiteNestedLevel","type":"uint8"},{"internalType":"uint8","name":"biteInflateFactor","type":"uint8"},{"internalType":"uint8","name":"biteNestInflateFactor","type":"uint8"}],"internalType":"struct INestMining.Params","name":"params","type":"tuple"}],"name":"setupParamsOfNestMining","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shutdown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"switchOnNest35","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenNum","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"Nest_3_MiningContract","type":"address"},{"internalType":"address","name":"Nest_NToken_TokenAuction","type":"address"},{"internalType":"address","name":"Nest_3_Abonus","type":"address"},{"internalType":"address","name":"Nest_3_Leveling","type":"address"},{"internalType":"address[]","name":"tokenL","type":"address[]"}],"name":"transferETHFromNest3","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"NestDAO","type":"address"},{"internalType":"address","name":"Nest_NToken_TokenAuction","type":"address"}],"name":"transferETHToNestDAO","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"Nest_3_MiningContract","type":"address"}],"name":"transferNestFromNest3","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"upgrade","type":"address"}],"name":"transferNestInUrgent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040526000600a556000600b553480156200001b57600080fd5b5060405162002e0538038062002e058339810160408190526200003e916200007f565b60008054336001600160a01b031991821617909155600280549091166001600160a01b03929092169190911790556004805460ff60a01b19169055620000af565b60006020828403121562000091578081fd5b81516001600160a01b0381168114620000a8578182fd5b9392505050565b612d4680620000bf6000396000f3fe60806040526004361061014f5760003560e01c8063aacc1f94116100b6578063e405bbc31161006f578063e405bbc314610333578063e81bac6e14610348578063ea4463c414610368578063f13c7eb314610388578063f2c7fb05146103a8578063fc0e74d1146103bd57610156565b8063aacc1f941461029f578063bf8aeef4146102b4578063bfa87e46146102d4578063d50f6bf0146102e9578063dac3874514610309578063dfcdd6c31461031e57610156565b80634f94637b116101085780634f94637b146102075780635aa6e675146102295780636e6604271461023e5780637c175a0114610253578063890eba6814610268578063a1c7962e1461028a57610156565b8063046f7da21461015b5780630fccd1a8146101725780631c1ab1a11461019257806321afcad3146101bd578063294d9697146101d257806343a048bd146101e757610156565b3661015657005b600080fd5b34801561016757600080fd5b506101706103d2565b005b34801561017e57600080fd5b5061017061018d3660046127bd565b610414565b34801561019e57600080fd5b506101a761095f565b6040516101b49190612bdf565b60405180910390f35b3480156101c957600080fd5b50610170610965565b3480156101de57600080fd5b506101a7610bcf565b3480156101f357600080fd5b5061017061020236600461281d565b610bd5565b34801561021357600080fd5b5061021c610c9a565b6040516101b491906128c0565b34801561023557600080fd5b5061021c610ca9565b34801561024a57600080fd5b5061021c610cb8565b34801561025f57600080fd5b5061021c610cc7565b34801561027457600080fd5b5061027d610cd6565b6040516101b49190612cc6565b34801561029657600080fd5b5061021c610ce6565b3480156102ab57600080fd5b506101a7610cf5565b3480156102c057600080fd5b506101706102cf366004612632565b610cfb565b3480156102e057600080fd5b506101a7611496565b3480156102f557600080fd5b506101706103043660046125bb565b61149c565b34801561031557600080fd5b50610170611557565b34801561032a57600080fd5b506101a761199b565b34801561033f57600080fd5b506101a76119a1565b34801561035457600080fd5b506101706103633660046125bb565b6119a7565b34801561037457600080fd5b506101706103833660046125fa565b611ee3565b34801561039457600080fd5b506101706103a33660046126b8565b612030565b3480156103b457600080fd5b506101a7612459565b3480156103c957600080fd5b5061017061245f565b6000546001600160a01b031633146104055760405162461bcd60e51b81526004016103fc90612b9e565b60405180910390fd5b6004805460ff60a01b19169055565b6000546001600160a01b0316331461043e5760405162461bcd60e51b81526004016103fc90612b9e565b6060815167ffffffffffffffff8111801561045857600080fd5b50604051908082528060200260200182016040528015610482578160200160208202803683370190505b506004549091506002600160a01b90910460ff16106104b35760405162461bcd60e51b81526004016103fc90612a92565b80518251146104d45760405162461bcd60e51b81526004016103fc9061292a565b60005b825181101561062e57846001600160a01b03168382815181106104f657fe5b60200260200101516001600160a01b031614156105255760405162461bcd60e51b81526004016103fc90612b75565b836001600160a01b0316636468858684838151811061054057fe5b60200260200101516040518263ffffffff1660e01b815260040161056491906128c0565b60206040518083038186803b15801561057c57600080fd5b505afa158015610590573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b491906125de565b8282815181106105c057fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060006001600160a01b03168282815181106105f757fe5b60200260200101516001600160a01b031614156106265760405162461bcd60e51b81526004016103fc90612b20565b6001016104d7565b50600254604080516397dcd0b360e01b815290516001600160a01b039092169182916397dcd0b3916004808301926020929190829003018186803b15801561067557600080fd5b505afa158015610689573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ad91906125de565b600180546001600160a01b0319166001600160a01b039283161790556040516372956b6960e01b81526000918316906372956b69906106f09089906004016128c0565b60206040518083038186803b15801561070857600080fd5b505afa15801561071c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074091906125de565b6001600160a01b031614156107bd57600154604051630bce207960e31b81526001600160a01b0380841692635e7103c892610781928a9216906004016128d4565b600060405180830381600087803b15801561079b57600080fd5b505af11580156107af573d6000803e3d6000fd5b5050600a8054600101905550505b60005b83518110156109565760015483516001600160a01b03909116908490839081106107e657fe5b60200260200101516001600160a01b031614156108155760405162461bcd60e51b81526004016103fc90612b4a565b60006001600160a01b0316826001600160a01b03166372956b6986848151811061083b57fe5b60200260200101516040518263ffffffff1660e01b815260040161085f91906128c0565b60206040518083038186803b15801561087757600080fd5b505afa15801561088b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108af91906125de565b6001600160a01b0316141561094e57816001600160a01b0316635e7103c88583815181106108d957fe5b60200260200101518584815181106108ed57fe5b60200260200101516040518363ffffffff1660e01b81526004016109129291906128d4565b600060405180830381600087803b15801561092c57600080fd5b505af1158015610940573d6000803e3d6000fd5b5050600a8054600101905550505b6001016107c0565b5050505b505050565b60075481565b6000546001600160a01b0316331461098f5760405162461bcd60e51b81526004016103fc90612b9e565b60025460005460405163ab033ea960e01b81526001600160a01b0392831692839263ab033ea9926109c692909116906004016128c0565b600060405180830381600087803b1580156109e057600080fd5b505af11580156109f4573d6000803e3d6000fd5b50505050806001600160a01b031663bd4291c16040518163ffffffff1660e01b815260040160206040518083038186803b158015610a3157600080fd5b505afa158015610a45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a6991906125de565b600360006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001600160a01b031663a1107d306040518163ffffffff1660e01b815260040160206040518083038186803b158015610ac857600080fd5b505afa158015610adc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0091906125de565b600480546001600160a01b0319166001600160a01b03928316178155600354604080516376a162a360e01b8152905191909316926376a162a3928181019260009290919082900301818387803b158015610b5957600080fd5b505af1158015610b6d573d6000803e3d6000fd5b505060048054604080516376a162a360e01b815290516001600160a01b0390921694506376a162a39350808301926000929182900301818387803b158015610bb457600080fd5b505af1158015610bc8573d6000803e3d6000fd5b5050505050565b60065481565b6000546001600160a01b03163314610bff5760405162461bcd60e51b81526004016103fc90612b9e565b6004546002600160a01b90910460ff1610610c2c5760405162461bcd60e51b81526004016103fc90612a92565b60025460405163872f196160e01b81526001600160a01b0390911690819063872f196190610c6290879087908790600401612907565b600060405180830381600087803b158015610c7c57600080fd5b505af1158015610c90573d6000803e3d6000fd5b5050505050505050565b6004546001600160a01b031681565b6000546001600160a01b031681565b6003546001600160a01b031681565b6002546001600160a01b031681565b600454600160a01b900460ff1681565b6001546001600160a01b031681565b600a5481565b6000546001600160a01b03163314610d255760405162461bcd60e51b81526004016103fc90612b9e565b6060815167ffffffffffffffff81118015610d3f57600080fd5b50604051908082528060200260200182016040528015610d69578160200160208202803683370190505b506004549091506002600160a01b90910460ff1610610d9a5760405162461bcd60e51b81526004016103fc90612a92565b600254604080516397dcd0b360e01b815290516001600160a01b039092169182916397dcd0b3916004808301926020929190829003018186803b158015610de057600080fd5b505afa158015610df4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e1891906125de565b600160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001600160a01b031663bd4291c16040518163ffffffff1660e01b815260040160206040518083038186803b158015610e7757600080fd5b505afa158015610e8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eaf91906125de565b600360006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001600160a01b031663a1107d306040518163ffffffff1660e01b815260040160206040518083038186803b158015610f0e57600080fd5b505afa158015610f22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4691906125de565b600480546001600160a01b0319166001600160a01b03928316178155600354604080516376a162a360e01b8152905191909316926376a162a3928181019260009290919082900301818387803b158015610f9f57600080fd5b505af1158015610fb3573d6000803e3d6000fd5b505060048054604080516376a162a360e01b815290516001600160a01b0390921694506376a162a39350808301926000929182900301818387803b158015610ffa57600080fd5b505af115801561100e573d6000803e3d6000fd5b5050505060005b835181101561112757816001600160a01b03166372956b6985838151811061103957fe5b60200260200101516040518263ffffffff1660e01b815260040161105d91906128c0565b60206040518083038186803b15801561107557600080fd5b505afa158015611089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ad91906125de565b8382815181106110b957fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060006001600160a01b03168382815181106110f057fe5b60200260200101516001600160a01b0316141561111f5760405162461bcd60e51b81526004016103fc90612a69565b600101611015565b5081518351146111495760405162461bcd60e51b81526004016103fc9061292a565b60005b8251811015610c905760006001600160a01b0316600c600086848151811061117057fe5b6020908102919091018101516001600160a01b039081168352908201929092526040016000205416141561148e576000806000886001600160a01b03166386895d038786815181106111be57fe5b60200260200101516040518263ffffffff1660e01b81526004016111e291906128c0565b60206040518083038186803b1580156111fa57600080fd5b505afa15801561120e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611232919061285e565b9150811561129b5760405163779c5cd960e01b81526001600160a01b038a169063779c5cd9906112689085903090600401612be8565b600060405180830381600087803b15801561128257600080fd5b505af1158015611296573d6000803e3d6000fd5b505050505b876001600160a01b0316631078eef68786815181106112b657fe5b60200260200101516040518263ffffffff1660e01b81526004016112da91906128c0565b60206040518083038186803b1580156112f257600080fd5b505afa158015611306573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061132a919061285e565b905080156113935760405163779c5cd960e01b81526001600160a01b0389169063779c5cd9906113609084903090600401612be8565b600060405180830381600087803b15801561137a57600080fd5b505af115801561138e573d6000803e3d6000fd5b505050505b61139d828261249e565b925082156114215760045486516001600160a01b039091169063e7691f2f908890879081106113c857fe5b6020026020010151856040518363ffffffff1660e01b81526004016113ee9291906128ee565b600060405180830381600087803b15801561140857600080fd5b505af115801561141c573d6000803e3d6000fd5b505050505b85848151811061142d57fe5b6020026020010151600c600089878151811061144557fe5b6020908102919091018101516001600160a01b0390811683529082019290925260400160002080546001600160a01b031916929091169190911790555050600b80546001019055505b60010161114c565b60095481565b6000546001600160a01b031633146114c65760405162461bcd60e51b81526004016103fc90612b9e565b604080516000808252602082019092526001600160a01b0383169047906040516114f09190612887565b60006040518083038185875af1925050503d806000811461152d576040519150601f19603f3d011682016040523d82523d6000602084013e611532565b606091505b50509050806115535760405162461bcd60e51b81526004016103fc90612a15565b5050565b6000546001600160a01b031633146115815760405162461bcd60e51b81526004016103fc90612b9e565b6004546002600160a01b90910460ff16106115ae5760405162461bcd60e51b81526004016103fc90612a92565b600254604080516397dcd0b360e01b815290516001600160a01b039092169182916397dcd0b3916004808301926020929190829003018186803b1580156115f457600080fd5b505afa158015611608573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162c91906125de565b600160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001600160a01b031663bd4291c16040518163ffffffff1660e01b815260040160206040518083038186803b15801561168b57600080fd5b505afa15801561169f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116c391906125de565b600360006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001600160a01b031663a1107d306040518163ffffffff1660e01b815260040160206040518083038186803b15801561172257600080fd5b505afa158015611736573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061175a91906125de565b600480546001600160a01b0319166001600160a01b03928316178155600354604080516376a162a360e01b8152905191909316926376a162a3928181019260009290919082900301818387803b1580156117b357600080fd5b505af11580156117c7573d6000803e3d6000fd5b505060048054604080516376a162a360e01b815290516001600160a01b0390921694506376a162a39350808301926000929182900301818387803b15801561180e57600080fd5b505af1158015611822573d6000803e3d6000fd5b50505050600360009054906101000a90046001600160a01b03166001600160a01b031663d55ec6976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561187657600080fd5b505af115801561188a573d6000803e3d6000fd5b50506004805460408051634267ee7960e01b815290516001600160a01b039092169450634267ee799350808301926000929182900301818387803b1580156118d157600080fd5b505af11580156118e5573d6000803e3d6000fd5b505060005460405163ab033ea960e01b81526001600160a01b03808616945063ab033ea993506119199216906004016128c0565b600060405180830381600087803b15801561193357600080fd5b505af1158015611947573d6000803e3d6000fd5b50505050600360009054906101000a90046001600160a01b03166001600160a01b03166376a162a36040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610b5957600080fd5b600b5481565b60055481565b6000546001600160a01b031633146119d15760405162461bcd60e51b81526004016103fc90612b9e565b6004546002600160a01b90910460ff16106119fe5760405162461bcd60e51b81526004016103fc90612a92565b600254604080516397dcd0b360e01b815290516001600160a01b039092169182916397dcd0b3916004808301926020929190829003018186803b158015611a4457600080fd5b505afa158015611a58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a7c91906125de565b600160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001600160a01b031663bd4291c16040518163ffffffff1660e01b815260040160206040518083038186803b158015611adb57600080fd5b505afa158015611aef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b1391906125de565b600360006101000a8154816001600160a01b0302191690836001600160a01b03160217905550816001600160a01b031663920f5e376040518163ffffffff1660e01b815260040160206040518083038186803b158015611b7257600080fd5b505afa158015611b86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611baa919061285e565b600581905550816001600160a01b031663e246ac396040518163ffffffff1660e01b815260040160206040518083038186803b158015611be957600080fd5b505afa158015611bfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c21919061285e565b6006819055611c4790611c416402540be400670de0b6b3a76400006124c7565b906124fe565b600755600554611c695760405162461bcd60e51b81526004016103fc90612af1565b60035460055460075460405163e6adb1ab60e01b81526001600160a01b039093169263e6adb1ab92611c9f929091600401612bc5565b600060405180830381600087803b158015611cb957600080fd5b505af1158015611ccd573d6000803e3d6000fd5b505060025460405163cd0a6f6360e01b81526001600160a01b03808716945063cd0a6f639350611d019216906004016128c0565b600060405180830381600087803b158015611d1b57600080fd5b505af1158015611d2f573d6000803e3d6000fd5b50506001546002546040516370a0823160e01b81526001600160a01b0392831694506370a082319350611d6892909116906004016128c0565b60206040518083038186803b158015611d8057600080fd5b505afa158015611d94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611db8919061285e565b60088190556040516384a70acf60e01b81526001600160a01b038316916384a70acf91611de89190600401612bdf565b600060405180830381600087803b158015611e0257600080fd5b505af1158015611e16573d6000803e3d6000fd5b505060005460405163ab033ea960e01b81526001600160a01b03808616945063ab033ea99350611e4a9216906004016128c0565b600060405180830381600087803b158015611e6457600080fd5b505af1158015611e78573d6000803e3d6000fd5b50505050600360009054906101000a90046001600160a01b03166001600160a01b03166376a162a36040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611ecc57600080fd5b505af1158015610956573d6000803e3d6000fd5b50565b6000546001600160a01b03163314611f0d5760405162461bcd60e51b81526004016103fc90612b9e565b806001600160a01b031663dea8cf026040518163ffffffff1660e01b815260040160206040518083038186803b158015611f4657600080fd5b505afa158015611f5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f7e919061285e565b6009819055600b5414611fa35760405162461bcd60e51b81526004016103fc90612aba565b604080516000808252602082019092526001600160a01b038416904790604051611fcd9190612887565b60006040518083038185875af1925050503d806000811461200a576040519150601f19603f3d011682016040523d82523d6000602084013e61200f565b606091505b505090508061095a5760405162461bcd60e51b81526004016103fc90612a15565b6000546001600160a01b0316331461205a5760405162461bcd60e51b81526004016103fc90612b9e565b600454625f29ac90600090819081906002600160a01b90910460ff16106120935760405162461bcd60e51b81526004016103fc90612a92565b866001600160a01b031663dea8cf026040518163ffffffff1660e01b815260040160206040518083038186803b1580156120cc57600080fd5b505afa1580156120e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612104919061285e565b6009819055600a54146121295760405162461bcd60e51b81526004016103fc90612982565b876001600160a01b031663920f5e376040518163ffffffff1660e01b815260040160206040518083038186803b15801561216257600080fd5b505afa158015612176573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061219a919061285e565b9250876001600160a01b031663e246ac396040518163ffffffff1660e01b815260040160206040518083038186803b1580156121d557600080fd5b505afa1580156121e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061220d919061285e565b915061222a82611c416402540be400670de0b6b3a76400006124c7565b6002546040805163bd4291c160e01b815290519293506001600160a01b0390911691829163bd4291c1916004808301926020929190829003018186803b15801561227357600080fd5b505afa158015612287573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ab91906125de565b600380546001600160a01b0319166001600160a01b039283161790819055604080516376a162a360e01b8152905191909216916376a162a391600480830192600092919082900301818387803b15801561230457600080fd5b505af1158015612318573d6000803e3d6000fd5b505060035460405163ea5807f760e01b81526001600160a01b03909116925063ea5807f79150612352908890889087908c90600401612bff565b600060405180830381600087803b15801561236c57600080fd5b505af1158015612380573d6000803e3d6000fd5b505060005460405163ab033ea960e01b81526001600160a01b03808616945063ab033ea993506123b49216906004016128c0565b600060405180830381600087803b1580156123ce57600080fd5b505af11580156123e2573d6000803e3d6000fd5b50505050600360009054906101000a90046001600160a01b03166001600160a01b03166376a162a36040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561243657600080fd5b505af115801561244a573d6000803e3d6000fd5b50505050505050505050505050565b60085481565b6000546001600160a01b031633146124895760405162461bcd60e51b81526004016103fc90612b9e565b6004805460ff60a01b1916600160a11b179055565b808201828110156124c15760405162461bcd60e51b81526004016103fc906129e7565b92915050565b60008115806124e2575050808202828282816124df57fe5b04145b6124c15760405162461bcd60e51b81526004016103fc906129b9565b808203828111156124c15760405162461bcd60e51b81526004016103fc90612953565b600082601f830112612531578081fd5b813567ffffffffffffffff811115612547578182fd5b6020808202612557828201612cd4565b8381529350818401858301828701840188101561257357600080fd5b600092505b8483101561259f57803561258b81612cfb565b825260019290920191908301908301612578565b505050505092915050565b803560ff811681146124c157600080fd5b6000602082840312156125cc578081fd5b81356125d781612cfb565b9392505050565b6000602082840312156125ef578081fd5b81516125d781612cfb565b6000806040838503121561260c578081fd5b823561261781612cfb565b9150602083013561262781612cfb565b809150509250929050565b600080600080600060a08688031215612649578081fd5b853561265481612cfb565b9450602086013561266481612cfb565b9350604086013561267481612cfb565b9250606086013561268481612cfb565b9150608086013567ffffffffffffffff81111561269f578182fd5b6126ab88828901612521565b9150509295509295909350565b6000806000808486036101608112156126cf578485fd5b85356126da81612cfb565b945060208601356126ea81612cfb565b935060408601356126fa81612cfb565b9250610100605f19820181131561270f578283fd5b61271881612cd4565b915061272788606089016125aa565b8252608087013563ffffffff8116811461273f578384fd5b60208301526127518860a089016125aa565b60408301526127638860c089016125aa565b60608301526127758860e089016125aa565b6080830152612786888289016125aa565b60a08301525061279a8761012088016125aa565b60c08201526127ad8761014088016125aa565b60e0820152939692955090935050565b6000806000606084860312156127d1578283fd5b83356127dc81612cfb565b925060208401356127ec81612cfb565b9150604084013567ffffffffffffffff811115612807578182fd5b61281386828701612521565b9150509250925092565b600080600060608486031215612831578283fd5b833561283c81612cfb565b925060208401359150604084013561285381612cfb565b809150509250925092565b60006020828403121561286f578081fd5b5051919050565b63ffffffff169052565b60ff169052565b60008251815b818110156128a7576020818601810151858301520161288d565b818111156128b55782828501525b509190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b6020808252600f908201526e273a37b5b2b71d2ab8339d10b632b760891b604082015260600190565b60208082526015908201527464732d6d6174682d7375622d756e646572666c6f7760581b604082015260600190565b6020808252601c908201527f6e746f6b656e5f6e756d313a5570673a202173756666696369656e7400000000604082015260600190565b60208082526014908201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604082015260600190565b60208082526014908201527364732d6d6174682d6164642d6f766572666c6f7760601b604082015260600190565b60208082526034908201527f5472616e7366657248656c7065723a3a736166655472616e736665724554483a60408201527308115512081d1c985b9cd9995c8819985a5b195960621b606082015260800190565b6020808252600f908201526e273a37b5b2b71d2ab8339d1032b93960891b604082015260600190565b6020808252600e908201526d4e6573743a5570673a21666c616760901b604082015260600190565b6020808252601c908201527f6e746f6b656e5f6e756d323a5570673a202173756666696369656e7400000000604082015260600190565b6020808252601590820152742630ba32b9ba2432b4b3b43a1d2ab8339d1032b93960591b604082015260600190565b60208082526010908201526f273a37b5b2b71d2ab8339d10b0b2323960811b604082015260600190565b602080825260119082015270139d1bdad95b8e955c19ce88085b995cdd607a1b604082015260600190565b6020808252600f908201526e151bdad95b8e955c19ce885554d115608a1b604082015260600190565b6020808252600d908201526c2732b9ba1d2ab8339d10b3b7bb60991b604082015260600190565b6001600160801b0392831681529116602082015260400190565b90815260200190565b9182526001600160a01b0316602082015260400190565b63ffffffff851681526001600160801b038481166020830152831660408201528151610160820190612c35906060840190612880565b6020830151612c476080840182612876565b506040830151612c5a60a0840182612880565b506060830151612c6d60c0840182612880565b506080830151612c8060e0840182612880565b5060a0830151612c94610100840182612880565b5060c0830151612ca8610120840182612880565b5060e0830151612cbc610140840182612880565b5095945050505050565b60ff91909116815260200190565b60405181810167ffffffffffffffff81118282101715612cf357600080fd5b604052919050565b6001600160a01b0381168114611ee057600080fdfea2646970667358221220fd44c8a0c22d9ef5c6f554035db0af6190a9c7ad8f46e7211c0c8bd62d8bf3e464736f6c634300060c0033000000000000000000000000ca208dcfbef22941d176858a640190c2222c8c8f
Deployed Bytecode
0x60806040526004361061014f5760003560e01c8063aacc1f94116100b6578063e405bbc31161006f578063e405bbc314610333578063e81bac6e14610348578063ea4463c414610368578063f13c7eb314610388578063f2c7fb05146103a8578063fc0e74d1146103bd57610156565b8063aacc1f941461029f578063bf8aeef4146102b4578063bfa87e46146102d4578063d50f6bf0146102e9578063dac3874514610309578063dfcdd6c31461031e57610156565b80634f94637b116101085780634f94637b146102075780635aa6e675146102295780636e6604271461023e5780637c175a0114610253578063890eba6814610268578063a1c7962e1461028a57610156565b8063046f7da21461015b5780630fccd1a8146101725780631c1ab1a11461019257806321afcad3146101bd578063294d9697146101d257806343a048bd146101e757610156565b3661015657005b600080fd5b34801561016757600080fd5b506101706103d2565b005b34801561017e57600080fd5b5061017061018d3660046127bd565b610414565b34801561019e57600080fd5b506101a761095f565b6040516101b49190612bdf565b60405180910390f35b3480156101c957600080fd5b50610170610965565b3480156101de57600080fd5b506101a7610bcf565b3480156101f357600080fd5b5061017061020236600461281d565b610bd5565b34801561021357600080fd5b5061021c610c9a565b6040516101b491906128c0565b34801561023557600080fd5b5061021c610ca9565b34801561024a57600080fd5b5061021c610cb8565b34801561025f57600080fd5b5061021c610cc7565b34801561027457600080fd5b5061027d610cd6565b6040516101b49190612cc6565b34801561029657600080fd5b5061021c610ce6565b3480156102ab57600080fd5b506101a7610cf5565b3480156102c057600080fd5b506101706102cf366004612632565b610cfb565b3480156102e057600080fd5b506101a7611496565b3480156102f557600080fd5b506101706103043660046125bb565b61149c565b34801561031557600080fd5b50610170611557565b34801561032a57600080fd5b506101a761199b565b34801561033f57600080fd5b506101a76119a1565b34801561035457600080fd5b506101706103633660046125bb565b6119a7565b34801561037457600080fd5b506101706103833660046125fa565b611ee3565b34801561039457600080fd5b506101706103a33660046126b8565b612030565b3480156103b457600080fd5b506101a7612459565b3480156103c957600080fd5b5061017061245f565b6000546001600160a01b031633146104055760405162461bcd60e51b81526004016103fc90612b9e565b60405180910390fd5b6004805460ff60a01b19169055565b6000546001600160a01b0316331461043e5760405162461bcd60e51b81526004016103fc90612b9e565b6060815167ffffffffffffffff8111801561045857600080fd5b50604051908082528060200260200182016040528015610482578160200160208202803683370190505b506004549091506002600160a01b90910460ff16106104b35760405162461bcd60e51b81526004016103fc90612a92565b80518251146104d45760405162461bcd60e51b81526004016103fc9061292a565b60005b825181101561062e57846001600160a01b03168382815181106104f657fe5b60200260200101516001600160a01b031614156105255760405162461bcd60e51b81526004016103fc90612b75565b836001600160a01b0316636468858684838151811061054057fe5b60200260200101516040518263ffffffff1660e01b815260040161056491906128c0565b60206040518083038186803b15801561057c57600080fd5b505afa158015610590573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b491906125de565b8282815181106105c057fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060006001600160a01b03168282815181106105f757fe5b60200260200101516001600160a01b031614156106265760405162461bcd60e51b81526004016103fc90612b20565b6001016104d7565b50600254604080516397dcd0b360e01b815290516001600160a01b039092169182916397dcd0b3916004808301926020929190829003018186803b15801561067557600080fd5b505afa158015610689573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ad91906125de565b600180546001600160a01b0319166001600160a01b039283161790556040516372956b6960e01b81526000918316906372956b69906106f09089906004016128c0565b60206040518083038186803b15801561070857600080fd5b505afa15801561071c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074091906125de565b6001600160a01b031614156107bd57600154604051630bce207960e31b81526001600160a01b0380841692635e7103c892610781928a9216906004016128d4565b600060405180830381600087803b15801561079b57600080fd5b505af11580156107af573d6000803e3d6000fd5b5050600a8054600101905550505b60005b83518110156109565760015483516001600160a01b03909116908490839081106107e657fe5b60200260200101516001600160a01b031614156108155760405162461bcd60e51b81526004016103fc90612b4a565b60006001600160a01b0316826001600160a01b03166372956b6986848151811061083b57fe5b60200260200101516040518263ffffffff1660e01b815260040161085f91906128c0565b60206040518083038186803b15801561087757600080fd5b505afa15801561088b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108af91906125de565b6001600160a01b0316141561094e57816001600160a01b0316635e7103c88583815181106108d957fe5b60200260200101518584815181106108ed57fe5b60200260200101516040518363ffffffff1660e01b81526004016109129291906128d4565b600060405180830381600087803b15801561092c57600080fd5b505af1158015610940573d6000803e3d6000fd5b5050600a8054600101905550505b6001016107c0565b5050505b505050565b60075481565b6000546001600160a01b0316331461098f5760405162461bcd60e51b81526004016103fc90612b9e565b60025460005460405163ab033ea960e01b81526001600160a01b0392831692839263ab033ea9926109c692909116906004016128c0565b600060405180830381600087803b1580156109e057600080fd5b505af11580156109f4573d6000803e3d6000fd5b50505050806001600160a01b031663bd4291c16040518163ffffffff1660e01b815260040160206040518083038186803b158015610a3157600080fd5b505afa158015610a45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a6991906125de565b600360006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001600160a01b031663a1107d306040518163ffffffff1660e01b815260040160206040518083038186803b158015610ac857600080fd5b505afa158015610adc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0091906125de565b600480546001600160a01b0319166001600160a01b03928316178155600354604080516376a162a360e01b8152905191909316926376a162a3928181019260009290919082900301818387803b158015610b5957600080fd5b505af1158015610b6d573d6000803e3d6000fd5b505060048054604080516376a162a360e01b815290516001600160a01b0390921694506376a162a39350808301926000929182900301818387803b158015610bb457600080fd5b505af1158015610bc8573d6000803e3d6000fd5b5050505050565b60065481565b6000546001600160a01b03163314610bff5760405162461bcd60e51b81526004016103fc90612b9e565b6004546002600160a01b90910460ff1610610c2c5760405162461bcd60e51b81526004016103fc90612a92565b60025460405163872f196160e01b81526001600160a01b0390911690819063872f196190610c6290879087908790600401612907565b600060405180830381600087803b158015610c7c57600080fd5b505af1158015610c90573d6000803e3d6000fd5b5050505050505050565b6004546001600160a01b031681565b6000546001600160a01b031681565b6003546001600160a01b031681565b6002546001600160a01b031681565b600454600160a01b900460ff1681565b6001546001600160a01b031681565b600a5481565b6000546001600160a01b03163314610d255760405162461bcd60e51b81526004016103fc90612b9e565b6060815167ffffffffffffffff81118015610d3f57600080fd5b50604051908082528060200260200182016040528015610d69578160200160208202803683370190505b506004549091506002600160a01b90910460ff1610610d9a5760405162461bcd60e51b81526004016103fc90612a92565b600254604080516397dcd0b360e01b815290516001600160a01b039092169182916397dcd0b3916004808301926020929190829003018186803b158015610de057600080fd5b505afa158015610df4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e1891906125de565b600160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001600160a01b031663bd4291c16040518163ffffffff1660e01b815260040160206040518083038186803b158015610e7757600080fd5b505afa158015610e8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eaf91906125de565b600360006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001600160a01b031663a1107d306040518163ffffffff1660e01b815260040160206040518083038186803b158015610f0e57600080fd5b505afa158015610f22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4691906125de565b600480546001600160a01b0319166001600160a01b03928316178155600354604080516376a162a360e01b8152905191909316926376a162a3928181019260009290919082900301818387803b158015610f9f57600080fd5b505af1158015610fb3573d6000803e3d6000fd5b505060048054604080516376a162a360e01b815290516001600160a01b0390921694506376a162a39350808301926000929182900301818387803b158015610ffa57600080fd5b505af115801561100e573d6000803e3d6000fd5b5050505060005b835181101561112757816001600160a01b03166372956b6985838151811061103957fe5b60200260200101516040518263ffffffff1660e01b815260040161105d91906128c0565b60206040518083038186803b15801561107557600080fd5b505afa158015611089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ad91906125de565b8382815181106110b957fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060006001600160a01b03168382815181106110f057fe5b60200260200101516001600160a01b0316141561111f5760405162461bcd60e51b81526004016103fc90612a69565b600101611015565b5081518351146111495760405162461bcd60e51b81526004016103fc9061292a565b60005b8251811015610c905760006001600160a01b0316600c600086848151811061117057fe5b6020908102919091018101516001600160a01b039081168352908201929092526040016000205416141561148e576000806000886001600160a01b03166386895d038786815181106111be57fe5b60200260200101516040518263ffffffff1660e01b81526004016111e291906128c0565b60206040518083038186803b1580156111fa57600080fd5b505afa15801561120e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611232919061285e565b9150811561129b5760405163779c5cd960e01b81526001600160a01b038a169063779c5cd9906112689085903090600401612be8565b600060405180830381600087803b15801561128257600080fd5b505af1158015611296573d6000803e3d6000fd5b505050505b876001600160a01b0316631078eef68786815181106112b657fe5b60200260200101516040518263ffffffff1660e01b81526004016112da91906128c0565b60206040518083038186803b1580156112f257600080fd5b505afa158015611306573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061132a919061285e565b905080156113935760405163779c5cd960e01b81526001600160a01b0389169063779c5cd9906113609084903090600401612be8565b600060405180830381600087803b15801561137a57600080fd5b505af115801561138e573d6000803e3d6000fd5b505050505b61139d828261249e565b925082156114215760045486516001600160a01b039091169063e7691f2f908890879081106113c857fe5b6020026020010151856040518363ffffffff1660e01b81526004016113ee9291906128ee565b600060405180830381600087803b15801561140857600080fd5b505af115801561141c573d6000803e3d6000fd5b505050505b85848151811061142d57fe5b6020026020010151600c600089878151811061144557fe5b6020908102919091018101516001600160a01b0390811683529082019290925260400160002080546001600160a01b031916929091169190911790555050600b80546001019055505b60010161114c565b60095481565b6000546001600160a01b031633146114c65760405162461bcd60e51b81526004016103fc90612b9e565b604080516000808252602082019092526001600160a01b0383169047906040516114f09190612887565b60006040518083038185875af1925050503d806000811461152d576040519150601f19603f3d011682016040523d82523d6000602084013e611532565b606091505b50509050806115535760405162461bcd60e51b81526004016103fc90612a15565b5050565b6000546001600160a01b031633146115815760405162461bcd60e51b81526004016103fc90612b9e565b6004546002600160a01b90910460ff16106115ae5760405162461bcd60e51b81526004016103fc90612a92565b600254604080516397dcd0b360e01b815290516001600160a01b039092169182916397dcd0b3916004808301926020929190829003018186803b1580156115f457600080fd5b505afa158015611608573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162c91906125de565b600160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001600160a01b031663bd4291c16040518163ffffffff1660e01b815260040160206040518083038186803b15801561168b57600080fd5b505afa15801561169f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116c391906125de565b600360006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001600160a01b031663a1107d306040518163ffffffff1660e01b815260040160206040518083038186803b15801561172257600080fd5b505afa158015611736573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061175a91906125de565b600480546001600160a01b0319166001600160a01b03928316178155600354604080516376a162a360e01b8152905191909316926376a162a3928181019260009290919082900301818387803b1580156117b357600080fd5b505af11580156117c7573d6000803e3d6000fd5b505060048054604080516376a162a360e01b815290516001600160a01b0390921694506376a162a39350808301926000929182900301818387803b15801561180e57600080fd5b505af1158015611822573d6000803e3d6000fd5b50505050600360009054906101000a90046001600160a01b03166001600160a01b031663d55ec6976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561187657600080fd5b505af115801561188a573d6000803e3d6000fd5b50506004805460408051634267ee7960e01b815290516001600160a01b039092169450634267ee799350808301926000929182900301818387803b1580156118d157600080fd5b505af11580156118e5573d6000803e3d6000fd5b505060005460405163ab033ea960e01b81526001600160a01b03808616945063ab033ea993506119199216906004016128c0565b600060405180830381600087803b15801561193357600080fd5b505af1158015611947573d6000803e3d6000fd5b50505050600360009054906101000a90046001600160a01b03166001600160a01b03166376a162a36040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610b5957600080fd5b600b5481565b60055481565b6000546001600160a01b031633146119d15760405162461bcd60e51b81526004016103fc90612b9e565b6004546002600160a01b90910460ff16106119fe5760405162461bcd60e51b81526004016103fc90612a92565b600254604080516397dcd0b360e01b815290516001600160a01b039092169182916397dcd0b3916004808301926020929190829003018186803b158015611a4457600080fd5b505afa158015611a58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a7c91906125de565b600160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001600160a01b031663bd4291c16040518163ffffffff1660e01b815260040160206040518083038186803b158015611adb57600080fd5b505afa158015611aef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b1391906125de565b600360006101000a8154816001600160a01b0302191690836001600160a01b03160217905550816001600160a01b031663920f5e376040518163ffffffff1660e01b815260040160206040518083038186803b158015611b7257600080fd5b505afa158015611b86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611baa919061285e565b600581905550816001600160a01b031663e246ac396040518163ffffffff1660e01b815260040160206040518083038186803b158015611be957600080fd5b505afa158015611bfd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c21919061285e565b6006819055611c4790611c416402540be400670de0b6b3a76400006124c7565b906124fe565b600755600554611c695760405162461bcd60e51b81526004016103fc90612af1565b60035460055460075460405163e6adb1ab60e01b81526001600160a01b039093169263e6adb1ab92611c9f929091600401612bc5565b600060405180830381600087803b158015611cb957600080fd5b505af1158015611ccd573d6000803e3d6000fd5b505060025460405163cd0a6f6360e01b81526001600160a01b03808716945063cd0a6f639350611d019216906004016128c0565b600060405180830381600087803b158015611d1b57600080fd5b505af1158015611d2f573d6000803e3d6000fd5b50506001546002546040516370a0823160e01b81526001600160a01b0392831694506370a082319350611d6892909116906004016128c0565b60206040518083038186803b158015611d8057600080fd5b505afa158015611d94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611db8919061285e565b60088190556040516384a70acf60e01b81526001600160a01b038316916384a70acf91611de89190600401612bdf565b600060405180830381600087803b158015611e0257600080fd5b505af1158015611e16573d6000803e3d6000fd5b505060005460405163ab033ea960e01b81526001600160a01b03808616945063ab033ea99350611e4a9216906004016128c0565b600060405180830381600087803b158015611e6457600080fd5b505af1158015611e78573d6000803e3d6000fd5b50505050600360009054906101000a90046001600160a01b03166001600160a01b03166376a162a36040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611ecc57600080fd5b505af1158015610956573d6000803e3d6000fd5b50565b6000546001600160a01b03163314611f0d5760405162461bcd60e51b81526004016103fc90612b9e565b806001600160a01b031663dea8cf026040518163ffffffff1660e01b815260040160206040518083038186803b158015611f4657600080fd5b505afa158015611f5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f7e919061285e565b6009819055600b5414611fa35760405162461bcd60e51b81526004016103fc90612aba565b604080516000808252602082019092526001600160a01b038416904790604051611fcd9190612887565b60006040518083038185875af1925050503d806000811461200a576040519150601f19603f3d011682016040523d82523d6000602084013e61200f565b606091505b505090508061095a5760405162461bcd60e51b81526004016103fc90612a15565b6000546001600160a01b0316331461205a5760405162461bcd60e51b81526004016103fc90612b9e565b600454625f29ac90600090819081906002600160a01b90910460ff16106120935760405162461bcd60e51b81526004016103fc90612a92565b866001600160a01b031663dea8cf026040518163ffffffff1660e01b815260040160206040518083038186803b1580156120cc57600080fd5b505afa1580156120e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612104919061285e565b6009819055600a54146121295760405162461bcd60e51b81526004016103fc90612982565b876001600160a01b031663920f5e376040518163ffffffff1660e01b815260040160206040518083038186803b15801561216257600080fd5b505afa158015612176573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061219a919061285e565b9250876001600160a01b031663e246ac396040518163ffffffff1660e01b815260040160206040518083038186803b1580156121d557600080fd5b505afa1580156121e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061220d919061285e565b915061222a82611c416402540be400670de0b6b3a76400006124c7565b6002546040805163bd4291c160e01b815290519293506001600160a01b0390911691829163bd4291c1916004808301926020929190829003018186803b15801561227357600080fd5b505afa158015612287573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ab91906125de565b600380546001600160a01b0319166001600160a01b039283161790819055604080516376a162a360e01b8152905191909216916376a162a391600480830192600092919082900301818387803b15801561230457600080fd5b505af1158015612318573d6000803e3d6000fd5b505060035460405163ea5807f760e01b81526001600160a01b03909116925063ea5807f79150612352908890889087908c90600401612bff565b600060405180830381600087803b15801561236c57600080fd5b505af1158015612380573d6000803e3d6000fd5b505060005460405163ab033ea960e01b81526001600160a01b03808616945063ab033ea993506123b49216906004016128c0565b600060405180830381600087803b1580156123ce57600080fd5b505af11580156123e2573d6000803e3d6000fd5b50505050600360009054906101000a90046001600160a01b03166001600160a01b03166376a162a36040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561243657600080fd5b505af115801561244a573d6000803e3d6000fd5b50505050505050505050505050565b60085481565b6000546001600160a01b031633146124895760405162461bcd60e51b81526004016103fc90612b9e565b6004805460ff60a01b1916600160a11b179055565b808201828110156124c15760405162461bcd60e51b81526004016103fc906129e7565b92915050565b60008115806124e2575050808202828282816124df57fe5b04145b6124c15760405162461bcd60e51b81526004016103fc906129b9565b808203828111156124c15760405162461bcd60e51b81526004016103fc90612953565b600082601f830112612531578081fd5b813567ffffffffffffffff811115612547578182fd5b6020808202612557828201612cd4565b8381529350818401858301828701840188101561257357600080fd5b600092505b8483101561259f57803561258b81612cfb565b825260019290920191908301908301612578565b505050505092915050565b803560ff811681146124c157600080fd5b6000602082840312156125cc578081fd5b81356125d781612cfb565b9392505050565b6000602082840312156125ef578081fd5b81516125d781612cfb565b6000806040838503121561260c578081fd5b823561261781612cfb565b9150602083013561262781612cfb565b809150509250929050565b600080600080600060a08688031215612649578081fd5b853561265481612cfb565b9450602086013561266481612cfb565b9350604086013561267481612cfb565b9250606086013561268481612cfb565b9150608086013567ffffffffffffffff81111561269f578182fd5b6126ab88828901612521565b9150509295509295909350565b6000806000808486036101608112156126cf578485fd5b85356126da81612cfb565b945060208601356126ea81612cfb565b935060408601356126fa81612cfb565b9250610100605f19820181131561270f578283fd5b61271881612cd4565b915061272788606089016125aa565b8252608087013563ffffffff8116811461273f578384fd5b60208301526127518860a089016125aa565b60408301526127638860c089016125aa565b60608301526127758860e089016125aa565b6080830152612786888289016125aa565b60a08301525061279a8761012088016125aa565b60c08201526127ad8761014088016125aa565b60e0820152939692955090935050565b6000806000606084860312156127d1578283fd5b83356127dc81612cfb565b925060208401356127ec81612cfb565b9150604084013567ffffffffffffffff811115612807578182fd5b61281386828701612521565b9150509250925092565b600080600060608486031215612831578283fd5b833561283c81612cfb565b925060208401359150604084013561285381612cfb565b809150509250925092565b60006020828403121561286f578081fd5b5051919050565b63ffffffff169052565b60ff169052565b60008251815b818110156128a7576020818601810151858301520161288d565b818111156128b55782828501525b509190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b6020808252600f908201526e273a37b5b2b71d2ab8339d10b632b760891b604082015260600190565b60208082526015908201527464732d6d6174682d7375622d756e646572666c6f7760581b604082015260600190565b6020808252601c908201527f6e746f6b656e5f6e756d313a5570673a202173756666696369656e7400000000604082015260600190565b60208082526014908201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604082015260600190565b60208082526014908201527364732d6d6174682d6164642d6f766572666c6f7760601b604082015260600190565b60208082526034908201527f5472616e7366657248656c7065723a3a736166655472616e736665724554483a60408201527308115512081d1c985b9cd9995c8819985a5b195960621b606082015260800190565b6020808252600f908201526e273a37b5b2b71d2ab8339d1032b93960891b604082015260600190565b6020808252600e908201526d4e6573743a5570673a21666c616760901b604082015260600190565b6020808252601c908201527f6e746f6b656e5f6e756d323a5570673a202173756666696369656e7400000000604082015260600190565b6020808252601590820152742630ba32b9ba2432b4b3b43a1d2ab8339d1032b93960591b604082015260600190565b60208082526010908201526f273a37b5b2b71d2ab8339d10b0b2323960811b604082015260600190565b602080825260119082015270139d1bdad95b8e955c19ce88085b995cdd607a1b604082015260600190565b6020808252600f908201526e151bdad95b8e955c19ce885554d115608a1b604082015260600190565b6020808252600d908201526c2732b9ba1d2ab8339d10b3b7bb60991b604082015260600190565b6001600160801b0392831681529116602082015260400190565b90815260200190565b9182526001600160a01b0316602082015260400190565b63ffffffff851681526001600160801b038481166020830152831660408201528151610160820190612c35906060840190612880565b6020830151612c476080840182612876565b506040830151612c5a60a0840182612880565b506060830151612c6d60c0840182612880565b506080830151612c8060e0840182612880565b5060a0830151612c94610100840182612880565b5060c0830151612ca8610120840182612880565b5060e0830151612cbc610140840182612880565b5095945050505050565b60ff91909116815260200190565b60405181810167ffffffffffffffff81118282101715612cf357600080fd5b604052919050565b6001600160a01b0381168114611ee057600080fdfea2646970667358221220fd44c8a0c22d9ef5c6f554035db0af6190a9c7ad8f46e7211c0c8bd62d8bf3e464736f6c634300060c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ca208dcfbef22941d176858a640190c2222c8c8f
-----Decoded View---------------
Arg [0] : NestPool (address): 0xCA208DCfbEF22941D176858A640190C2222C8c8F
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000ca208dcfbef22941d176858a640190c2222c8c8f
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.