ETH Price: $2,393.93 (-0.88%)

Transaction Decoder

Block:
11520569 at Dec-25-2020 04:23:09 AM +UTC
Transaction Fee:
0.0108839088 ETH $26.06
Gas Used:
104,252 Gas / 104.4 Gwei

Emitted Events:

218 Nest_3_TokenAbonus.GetTokenLog( tokenAddress=0x04abEdA2...c74ddC74C, tokenAmount=1523850499173213164 )

Account State Difference:

  Address   Before After State Difference Code
0x19E1d193...8726e67c5
0x2A461673...d5393Cf11
0.239070945095348645 Eth
Nonce: 266
1.752037535468561809 Eth
Nonce: 267
1.512966590373213164
0x43121397...e39D44852
(NEST Protocol: Revenue Pool)
459.058971234815197047 Eth457.535120735641983883 Eth1.523850499173213164
(Ethermine)
819.19222140056427547 Eth819.20310530936427547 Eth0.0108839088

Execution Trace

Nest_3_TokenAbonus.getAbonus( token=0x04abEdA201850aC0124161F037Efd70c74ddC74C )
  • Nest_3_TokenSave.checkAmount( sender=0x2A461673861ED4fD299FbE5a8567785d5393Cf11, token=0x04abEdA201850aC0124161F037Efd70c74ddC74C ) => ( 6721075000000000000000000 )
  • Nest_3_Abonus.getETH( num=1523850499173213164, token=0x04abEdA201850aC0124161F037Efd70c74ddC74C, target=0x2A461673861ED4fD299FbE5a8567785d5393Cf11 )
    • Nest_3_VoteFactory.checkAddress( name=nest.v3.tokenAbonus ) => ( contractAddress=0x19E1d193A448bD13097EFC2aea867468726e67c5 )
    • ETH 1.523850499173213164 0x2a461673861ed4fd299fbe5a8567785d5393cf11.CALL( )
      getAbonus[Nest_3_TokenAbonus (ln:116)]
      File 1 of 4: Nest_3_TokenAbonus
      pragma solidity 0.6.0;
      
      /**
       * @title Dividend logic
       * @dev Some operations about dividend,logic and asset separation
       */
      contract Nest_3_TokenAbonus {
          using address_make_payable for address;
          using SafeMath for uint256;
          
          ERC20 _nestContract;
          Nest_3_TokenSave _tokenSave;                                                                //  Lock-up contract
          Nest_3_Abonus _abonusContract;                                                              //  ETH bonus pool
          Nest_3_VoteFactory _voteFactory;                                                            //  Voting contract
          Nest_3_Leveling _nestLeveling;                                                              //  Leveling contract
          address _destructionAddress;                                                                //  Destroy contract address
          
          uint256 _timeLimit = 168 hours;                                                             //  Bonus period
          uint256 _nextTime = 1596168000;                                                             //  Next bonus time
          uint256 _getAbonusTimeLimit = 60 hours;                                                     //  During of triggering calculation of bonus
          uint256 _times = 0;                                                                         //  Bonus ledger
          uint256 _expectedIncrement = 3;                                                             //  Expected bonus increment ratio
          uint256 _expectedSpanForNest = 100000000 ether;                                             //  NEST expected bonus increment threshold
          uint256 _expectedSpanForNToken = 1000000 ether;                                             //  NToken expected bonus increment threshold
          uint256 _expectedMinimum = 100 ether;                                                       //  Expected minimum bonus
          uint256 _savingLevelOne = 10;                                                               //  Saving threshold level 1
          uint256 _savingLevelTwo = 20;                                                               //  Saving threshold level 2 
          uint256 _savingLevelTwoSub = 100 ether;                                                     //  Function parameters of savings threshold level 2  
          uint256 _savingLevelThree = 30;                                                             //  Function parameters of savings threshold level 3
          uint256 _savingLevelThreeSub = 600 ether;                                                   //  Function parameters of savings threshold level 3
          
          mapping(address => uint256) _abonusMapping;                                                 //  Bonus pool snapshot - token address (NEST or NToken) => number of ETH in the bonus pool 
          mapping(address => uint256) _tokenAllValueMapping;                                          //  Number of tokens (circulation) - token address (NEST or NToken) ) => total circulation 
          mapping(address => mapping(uint256 => uint256)) _tokenAllValueHistory;                      //  NEST or NToken circulation snapshot - token address (NEST or NToken) => number of periods => total circulation 
          mapping(address => mapping(uint256 => mapping(address => uint256))) _tokenSelfHistory;      //  Personal lockup - NEST or NToken snapshot token address (NEST or NToken) => period => user address => total circulation
          mapping(address => mapping(uint256 => bool)) _snapshot;                                     //  Whether snapshot - token address (NEST or NToken) => number of periods => whether to take a snapshot
          mapping(uint256 => mapping(address => mapping(address => bool))) _getMapping;               //  Receiving records - period => token address (NEST or NToken) => user address => whether received
          
          //  Log token address, amount
          event GetTokenLog(address tokenAddress, uint256 tokenAmount);
          
         /**
          * @dev Initialization method
          * @param voteFactory Voting contract address
          */
          constructor (address voteFactory) public {
              Nest_3_VoteFactory voteFactoryMap = Nest_3_VoteFactory(address(voteFactory));
              _voteFactory = voteFactoryMap; 
              _nestContract = ERC20(address(voteFactoryMap.checkAddress("nest")));
              _tokenSave = Nest_3_TokenSave(address(voteFactoryMap.checkAddress("nest.v3.tokenSave")));
              address payable addr = address(voteFactoryMap.checkAddress("nest.v3.abonus")).make_payable();
              _abonusContract = Nest_3_Abonus(addr);
              address payable levelingAddr = address(voteFactoryMap.checkAddress("nest.v3.leveling")).make_payable();
              _nestLeveling = Nest_3_Leveling(levelingAddr);
              _destructionAddress = address(voteFactoryMap.checkAddress("nest.v3.destruction"));
          }
          
          /**
          * @dev Modify voting contract
          * @param voteFactory Voting contract address
          */
          function changeMapping(address voteFactory) public onlyOwner {
              Nest_3_VoteFactory voteFactoryMap = Nest_3_VoteFactory(address(voteFactory));
              _voteFactory = voteFactoryMap; 
              _nestContract = ERC20(address(voteFactoryMap.checkAddress("nest")));
              _tokenSave = Nest_3_TokenSave(address(voteFactoryMap.checkAddress("nest.v3.tokenSave")));
              address payable addr = address(voteFactoryMap.checkAddress("nest.v3.abonus")).make_payable();
              _abonusContract = Nest_3_Abonus(addr);
              address payable levelingAddr = address(voteFactoryMap.checkAddress("nest.v3.leveling")).make_payable();
              _nestLeveling = Nest_3_Leveling(levelingAddr);
              _destructionAddress = address(voteFactoryMap.checkAddress("nest.v3.destruction"));
          }
          
          /**
          * @dev Deposit 
          * @param amount Deposited amount
          * @param token Locked token address
          */
          function depositIn(uint256 amount, address token) public {
              uint256 nowTime = now;
              uint256 nextTime = _nextTime;
              uint256 timeLimit = _timeLimit;
              if (nowTime < nextTime) {
                  //  Bonus triggered
                  require(!(nowTime >= nextTime.sub(timeLimit) && nowTime <= nextTime.sub(timeLimit).add(_getAbonusTimeLimit)));
              } else {
                  //  Bonus not triggered
                  uint256 times = (nowTime.sub(_nextTime)).div(_timeLimit);
                  //  Calculate the time when bonus should be started
                  uint256 startTime = _nextTime.add((times).mul(_timeLimit));  
                  //  Calculate the time when bonus should be stopped
                  uint256 endTime = startTime.add(_getAbonusTimeLimit);                                                                    
                  require(!(nowTime >= startTime && nowTime <= endTime));
              }
              _tokenSave.depositIn(amount, token, address(msg.sender));                 
          }
          
          /**
          * @dev Withdrawing
          * @param amount Withdrawing amount
          * @param token Token address
          */
          function takeOut(uint256 amount, address token) public {
              require(amount > 0, "Parameter needs to be greater than 0");                                                                
              require(amount <= _tokenSave.checkAmount(address(msg.sender), token), "Insufficient storage balance");
              if (token == address(_nestContract)) {
                  require(!_voteFactory.checkVoteNow(address(tx.origin)), "Voting");
              }
              _tokenSave.takeOut(amount, token, address(msg.sender));                                                             
          }                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
          
          /**
          * @dev Receiving
          * @param token Receiving token address
          */
          function getAbonus(address token) public {
              uint256 tokenAmount = _tokenSave.checkAmount(address(msg.sender), token);
              require(tokenAmount > 0, "Insufficient storage balance");
              reloadTime();
              reloadToken(token);                                                                                                      
              uint256 nowTime = now;
              require(nowTime >= _nextTime.sub(_timeLimit) && nowTime <= _nextTime.sub(_timeLimit).add(_getAbonusTimeLimit), "Not time to draw");
              require(!_getMapping[_times.sub(1)][token][address(msg.sender)], "Have received");                                     
              _tokenSelfHistory[token][_times.sub(1)][address(msg.sender)] = tokenAmount;                                         
              require(_tokenAllValueMapping[token] > 0, "Total flux error");
              uint256 selfNum = tokenAmount.mul(_abonusMapping[token]).div(_tokenAllValueMapping[token]);
              require(selfNum > 0, "No limit available");
              _getMapping[_times.sub(1)][token][address(msg.sender)] = true;
              _abonusContract.getETH(selfNum, token,address(msg.sender)); 
              emit GetTokenLog(token, selfNum);
          }
          
          /**
          * @dev Update bonus time and stage ledger
          */
          function reloadTime() private {
              uint256 nowTime = now;
              //  The current time must exceed the bonus time
              if (nowTime >= _nextTime) {                                                                                                 
                  uint256 time = (nowTime.sub(_nextTime)).div(_timeLimit);
                  uint256 startTime = _nextTime.add((time).mul(_timeLimit));                                                              
                  uint256 endTime = startTime.add(_getAbonusTimeLimit);                                                                   
                  if (nowTime >= startTime && nowTime <= endTime) {
                      _nextTime = getNextTime();                                                                                      
                      _times = _times.add(1);                                                                                       
                  }
              }
          }
          
          /**
          * @dev Snapshot of the amount of tokens
          * @param token Receiving token address
          */
          function reloadToken(address token) private {
              if (!_snapshot[token][_times.sub(1)]) {
                  levelingResult(token);                                                                                          
                  _abonusMapping[token] = _abonusContract.getETHNum(token); 
                  _tokenAllValueMapping[token] = allValue(token);
                  _tokenAllValueHistory[token][_times.sub(1)] = allValue(token);
                  _snapshot[token][_times.sub(1)] = true;
              }
          }
          
          /**
          * @dev Leveling settlement
          * @param token Receiving token address
          */
          function levelingResult(address token) private {
              uint256 steps;
              if (token == address(_nestContract)) {
                  steps = allValue(token).div(_expectedSpanForNest);
              } else {
                  steps = allValue(token).div(_expectedSpanForNToken);
              }
              uint256 minimumAbonus = _expectedMinimum;
              for (uint256 i = 0; i < steps; i++) {
                  minimumAbonus = minimumAbonus.add(minimumAbonus.mul(_expectedIncrement).div(100));
              }
              uint256 thisAbonus = _abonusContract.getETHNum(token);
              if (thisAbonus > minimumAbonus) {
                  uint256 levelAmount = 0;
                  if (thisAbonus > 5000 ether) {
                      levelAmount = thisAbonus.mul(_savingLevelThree).div(100).sub(_savingLevelThreeSub);
                  } else if (thisAbonus > 1000 ether) {
                      levelAmount = thisAbonus.mul(_savingLevelTwo).div(100).sub(_savingLevelTwoSub);
                  } else {
                      levelAmount = thisAbonus.mul(_savingLevelOne).div(100);
                  }
                  if (thisAbonus.sub(levelAmount) < minimumAbonus) {
                      _abonusContract.getETH(thisAbonus.sub(minimumAbonus), token, address(this));
                      _nestLeveling.switchToEth.value(thisAbonus.sub(minimumAbonus))(token);
                  } else {
                      _abonusContract.getETH(levelAmount, token, address(this));
                      _nestLeveling.switchToEth.value(levelAmount)(token);
                  }
              } else {
                  uint256 ethValue = _nestLeveling.tranEth(minimumAbonus.sub(thisAbonus), token, address(this));
                  _abonusContract.switchToEth.value(ethValue)(token);
              }
          }
          
           // Next bonus time, current bonus deadline, ETH number, NEST number, NEST participating in bonus, bonus to receive, approved amount, balance, whether bonus can be paid 
          function getInfo(address token) public view returns (uint256 nextTime, uint256 getAbonusTime, uint256 ethNum, uint256 tokenValue, uint256 myJoinToken, uint256 getEth, uint256 allowNum, uint256 leftNum, bool allowAbonus)  {
              uint256 nowTime = now;
              if (nowTime >= _nextTime.sub(_timeLimit) && nowTime <= _nextTime.sub(_timeLimit).add(_getAbonusTimeLimit) && _times > 0 && _snapshot[token][_times.sub(1)]) {
                  //  Bonus have been triggered, and during the time of this bonus, display snapshot data 
                  allowAbonus = _getMapping[_times.sub(1)][token][address(msg.sender)];
                  ethNum = _abonusMapping[token];
                  tokenValue = _tokenAllValueMapping[token];
              } else {
                  //  Display real-time data 
                  ethNum = _abonusContract.getETHNum(token);
                  tokenValue = allValue(token);
                  allowAbonus = _getMapping[_times][token][address(msg.sender)];
              }
              myJoinToken = _tokenSave.checkAmount(address(msg.sender), token);
              if (allowAbonus == true) {
                  getEth = 0; 
              } else {
                  getEth = myJoinToken.mul(ethNum).div(tokenValue);
              }
              nextTime = getNextTime();
              getAbonusTime = nextTime.sub(_timeLimit).add(_getAbonusTimeLimit);
              allowNum = ERC20(token).allowance(address(msg.sender), address(_tokenSave));
              leftNum = ERC20(token).balanceOf(address(msg.sender));
          }
          
          /**
          * @dev View next bonus time 
          * @return Next bonus time 
          */
          function getNextTime() public view returns (uint256) {
              uint256 nowTime = now;
              if (_nextTime > nowTime) { 
                  return _nextTime; 
              } else {
                  uint256 time = (nowTime.sub(_nextTime)).div(_timeLimit);
                  return _nextTime.add(_timeLimit.mul(time.add(1)));
              }
          }
          
          /**
          * @dev View total circulation 
          * @return Total circulation
          */
          function allValue(address token) public view returns (uint256) {
              if (token == address(_nestContract)) {
                  uint256 all = 10000000000 ether;
                  uint256 leftNum = all.sub(_nestContract.balanceOf(address(_voteFactory.checkAddress("nest.v3.miningSave")))).sub(_nestContract.balanceOf(address(_destructionAddress)));
                  return leftNum;
              } else {
                  return ERC20(token).totalSupply();
              }
          }
          
          /**
          * @dev View bonus period
          * @return Bonus period
          */
          function checkTimeLimit() public view returns (uint256) {
              return _timeLimit;
          }
          
          /**
          * @dev View duration of triggering calculation of bonus
          * @return Bonus period
          */
          function checkGetAbonusTimeLimit() public view returns (uint256) {
              return _getAbonusTimeLimit;
          }
          
          /**
          * @dev View current lowest expected bonus
          * @return Current lowest expected bonus
          */
          function checkMinimumAbonus(address token) public view returns (uint256) {
              uint256 miningAmount;
              if (token == address(_nestContract)) {
                  miningAmount = allValue(token).div(_expectedSpanForNest);
              } else {
                  miningAmount = allValue(token).div(_expectedSpanForNToken);
              }
              uint256 minimumAbonus = _expectedMinimum;
              for (uint256 i = 0; i < miningAmount; i++) {
                  minimumAbonus = minimumAbonus.add(minimumAbonus.mul(_expectedIncrement).div(100));
              }
              return minimumAbonus;
          }
          
          /**
          * @dev Check whether the bonus token is snapshoted
          * @param token Token address
          * @return Whether snapshoted
          */
          function checkSnapshot(address token) public view returns (bool) {
              return _snapshot[token][_times.sub(1)];
          }
          
          /**
          * @dev Check the expected bonus incremental ratio
          * @return Expected bonus increment ratio
          */
          function checkeExpectedIncrement() public view returns (uint256) {
              return _expectedIncrement;
          }
          
          /**
          * @dev View expected minimum bonus
          * @return Expected minimum bonus
          */
          function checkExpectedMinimum() public view returns (uint256) {
              return _expectedMinimum;
          }
          
          /**
          * @dev View savings threshold
          * @return Save threshold
          */
          function checkSavingLevelOne() public view returns (uint256) {
              return _savingLevelOne;
          }
          function checkSavingLevelTwo() public view returns (uint256) {
              return _savingLevelTwo;
          }
          function checkSavingLevelThree() public view returns (uint256) {
              return _savingLevelThree;
          }
          
          /**
          * @dev View NEST liquidity snapshot
          * @param token Locked token address
          * @param times Bonus snapshot period
          */
          function checkTokenAllValueHistory(address token, uint256 times) public view returns (uint256) {
              return _tokenAllValueHistory[token][times];
          }
          
          /**
          * @dev View personal lock-up NEST snapshot
          * @param times Bonus snapshot period
          * @param user User address
          * @return The number of personal locked NEST snapshots
          */
          function checkTokenSelfHistory(address token, uint256 times, address user) public view returns (uint256) {
              return _tokenSelfHistory[token][times][user];
          }
          
          // View the period number of bonus
          function checkTimes() public view returns (uint256) {
              return _times;
          }
          
          // NEST expected bonus increment threshold
          function checkExpectedSpanForNest() public view returns (uint256) {
              return _expectedSpanForNest;
          }
          
          // NToken expected bonus increment threshold
          function checkExpectedSpanForNToken() public view returns (uint256) {
              return _expectedSpanForNToken;
          }
          
          // View the function parameters of savings threshold level 3
          function checkSavingLevelTwoSub() public view returns (uint256) {
              return _savingLevelTwoSub;
          }
          
          // View the function parameters of savings threshold level 3
          function checkSavingLevelThreeSub() public view returns (uint256) {
              return _savingLevelThreeSub;
          }
          
          /**
          * @dev Update bonus period
          * @param hour Bonus period (hours)
          */
          function changeTimeLimit(uint256 hour) public onlyOwner {
              require(hour > 0, "Parameter needs to be greater than 0");
              _timeLimit = hour.mul(1 hours);
          }
          
          /**
          * @dev Update collection period
          * @param hour Collection period (hours)
          */
          function changeGetAbonusTimeLimit(uint256 hour) public onlyOwner {
              require(hour > 0, "Parameter needs to be greater than 0");
              _getAbonusTimeLimit = hour;
          }
          
          /**
          * @dev Update expected bonus increment ratio
          * @param num Expected bonus increment ratio
          */
          function changeExpectedIncrement(uint256 num) public onlyOwner {
              require(num > 0, "Parameter needs to be greater than 0");
              _expectedIncrement = num;
          }
          
          /**
          * @dev Update expected minimum bonus
          * @param num Expected minimum bonus
          */
          function changeExpectedMinimum(uint256 num) public onlyOwner {
              require(num > 0, "Parameter needs to be greater than 0");
              _expectedMinimum = num;
          }
          
          /**
          * @dev  Update saving threshold
          * @param threshold Saving threshold
          */
          function changeSavingLevelOne(uint256 threshold) public onlyOwner {
              _savingLevelOne = threshold;
          }
          function changeSavingLevelTwo(uint256 threshold) public onlyOwner {
              _savingLevelTwo = threshold;
          }
          function changeSavingLevelThree(uint256 threshold) public onlyOwner {
              _savingLevelThree = threshold;
          }
          
          /**
          * @dev Update the function parameters of savings threshold level 2
          */
          function changeSavingLevelTwoSub(uint256 num) public onlyOwner {
              _savingLevelTwoSub = num;
          }
          
          /**
          * @dev Update the function parameters of savings threshold level 3
          */
          function changeSavingLevelThreeSub(uint256 num) public onlyOwner {
              _savingLevelThreeSub = num;
          }
          
          /**
          * @dev Update NEST expected bonus incremental threshold
          * @param num Threshold
          */
          function changeExpectedSpanForNest(uint256 num) public onlyOwner {
              _expectedSpanForNest = num;
          }
          
          /**
          * @dev Update NToken expected bonus incremental threshold
          * @param num Threshold
          */
          function changeExpectedSpanForNToken(uint256 num) public onlyOwner {
              _expectedSpanForNToken = num;
          }
          
          receive() external payable {
              
          }
          
          // Administrator only
          modifier onlyOwner(){
              require(_voteFactory.checkOwners(address(msg.sender)), "No authority");
              _;
          }
      }
      
      // NEST and NToken lock-up contracts
      interface Nest_3_TokenSave {
          function depositIn(uint256 num, address token, address target) external;
          function checkAmount(address sender, address token) external view returns(uint256);
          function takeOut(uint256 num, address token, address target) external;
      }
      
      // ETH bonus pool
      interface Nest_3_Abonus {
          function getETH(uint256 num, address token, address target) external;
          function getETHNum(address token) external view returns (uint256);
          function switchToEth(address token) external payable;
      }
      
      // Leveling contract
      interface Nest_3_Leveling {
          function tranEth(uint256 amount, address token, address target) external returns (uint256);
          function switchToEth(address token) external payable;
      }
      
      // Voting factory contract
      interface Nest_3_VoteFactory {
          // Check if there is a vote currently participating
          function checkVoteNow(address user) external view returns(bool);
          // Check address
      	function checkAddress(string calldata name) external view returns (address contractAddress);
      	// Check whether the administrator
      	function checkOwners(address man) external view returns (bool);
      }
      
      // ERC20 contract
      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);
      }
      
      library SafeMath {
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              require(c >= a, "SafeMath: addition overflow");
      
              return c;
          }
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              return sub(a, b, "SafeMath: subtraction overflow");
          }
          function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b <= a, errorMessage);
              uint256 c = a - b;
      
              return c;
          }
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) {
                  return 0;
              }
              uint256 c = a * b;
              require(c / a == b, "SafeMath: multiplication overflow");
      
              return c;
          }
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              return div(a, b, "SafeMath: division by zero");
          }
          function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b > 0, errorMessage);
              uint256 c = a / b;
              return c;
          }
          function mod(uint256 a, uint256 b) internal pure returns (uint256) {
              return mod(a, b, "SafeMath: modulo by zero");
          }
          function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b != 0, errorMessage);
              return a % b;
          }
      }
      
      library address_make_payable {
         function make_payable(address x) internal pure returns (address payable) {
            return address(uint160(x));
         }
      }

      File 2 of 4: Nest_3_TokenSave
      pragma solidity 0.6.0;
      
      /**
       * @title NEST and NToken lock-up contract
       * @dev NEST and NToken deposit and withdrawal
       */
      contract Nest_3_TokenSave {
          using SafeMath for uint256;
          
          Nest_3_VoteFactory _voteFactory;                                 //  Voting contract
          mapping(address => mapping(address => uint256))  _baseMapping;   //  Ledger token=>user=>amount
          
          /**
          * @dev initialization method
          * @param voteFactory Voting contract address
          */
          constructor(address voteFactory) public {
              _voteFactory = Nest_3_VoteFactory(voteFactory); 
          }
          
          /**
          * @dev Reset voting contract
          * @param voteFactory Voting contract address
          */
          function changeMapping(address voteFactory) public onlyOwner {
              _voteFactory = Nest_3_VoteFactory(voteFactory); 
          }
          
          /**
          * @dev Withdrawing
          * @param num Withdrawing amount
          * @param token Lock-up token address
          * @param target Transfer target
          */
          function takeOut(uint256 num, address token, address target) public onlyContract {
              require(num <= _baseMapping[token][address(target)], "Insufficient storage balance");
              _baseMapping[token][address(target)] = _baseMapping[token][address(target)].sub(num);
              ERC20(token).transfer(address(target), num);
          }
          
          /**
          * @dev Depositing
          * @param num Depositing amount
          * @param token Lock-up token address
          * @param target Depositing target
          */
          function depositIn(uint256 num, address token, address target) public onlyContract {
              require(ERC20(token).transferFrom(address(target),address(this),num), "Authorization transfer failed");  
              _baseMapping[token][address(target)] = _baseMapping[token][address(target)].add(num);
          }
          
          /**
          * @dev Check the amount
          * @param sender Check address
          * @param token Lock-up token address
          * @return uint256 Check address corresponding lock-up limit 
          */
          function checkAmount(address sender, address token) public view returns(uint256) {
              return _baseMapping[token][address(sender)];
          }
          
          // Administrators only
          modifier onlyOwner(){
              require(_voteFactory.checkOwners(address(msg.sender)), "No authority");
              _;
          }
          
          // Only for bonus logic contract
          modifier onlyContract(){
              require(_voteFactory.checkAddress("nest.v3.tokenAbonus") == address(msg.sender), "No authority");
              _;
          }
      }
      
      // ERC20 contract
      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);
      }
      
      // Voting factory
      interface Nest_3_VoteFactory {
          // Check address
      	function checkAddress(string calldata name) external view returns (address contractAddress);
      	// Check whether the administrator
      	function checkOwners(address man) external view returns (bool);
      }
      
      library SafeMath {
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              require(c >= a, "SafeMath: addition overflow");
      
              return c;
          }
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              return sub(a, b, "SafeMath: subtraction overflow");
          }
          function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b <= a, errorMessage);
              uint256 c = a - b;
      
              return c;
          }
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) {
                  return 0;
              }
              uint256 c = a * b;
              require(c / a == b, "SafeMath: multiplication overflow");
      
              return c;
          }
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              return div(a, b, "SafeMath: division by zero");
          }
          function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b > 0, errorMessage);
              uint256 c = a / b;
              return c;
          }
          function mod(uint256 a, uint256 b) internal pure returns (uint256) {
              return mod(a, b, "SafeMath: modulo by zero");
          }
          function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b != 0, errorMessage);
              return a % b;
          }
      }

      File 3 of 4: Nest_3_Abonus
      pragma solidity 0.6.0;
      
      /**
       * @title ETH bonus pool
       * @dev ETH collection and inquiry
       */
      contract Nest_3_Abonus {
          using address_make_payable for address;
          using SafeMath for uint256;
          
          Nest_3_VoteFactory _voteFactory;                                //  Voting contract
          address _nestAddress;                                           //  NEST contract address
          mapping (address => uint256) ethMapping;                        //  ETH bonus ledger of corresponding tokens
          uint256 _mostDistribution = 40;                                 //  The highest allocation ratio of NEST bonus pool
          uint256 _leastDistribution = 20;                                //  The lowest allocation ratio of NEST bonus pool
          uint256 _distributionTime = 1200000;                            //  The decay time interval of NEST bonus pool allocation ratio 
          uint256 _distributionSpan = 5;                                  //  The decay degree of NEST bonus pool allocation ratio
          
          /**
          * @dev Initialization method
          * @param voteFactory Voting contract address
          */
          constructor(address voteFactory) public {
              _voteFactory = Nest_3_VoteFactory(voteFactory);
              _nestAddress = address(_voteFactory.checkAddress("nest"));
          }
       
          /**
          * @dev Reset voting contract
          * @param voteFactory Voting contract address
          */
          function changeMapping(address voteFactory) public onlyOwner{
              _voteFactory = Nest_3_VoteFactory(voteFactory);
              _nestAddress = address(_voteFactory.checkAddress("nest"));
          }
          
          /**
          * @dev Transfer in bonus
          * @param token Corresponding to lock-up Token
          */
          function switchToEth(address token) public payable {
              ethMapping[token] = ethMapping[token].add(msg.value);
          }
          
          /**
          * @dev Transferin bonus - NToken offering fee
          * @param token Corresponding to lock-up NToken
          */
          function switchToEthForNTokenOffer(address token) public payable {
              Nest_NToken nToken = Nest_NToken(token);
              (uint256 createBlock,) = nToken.checkBlockInfo();
              uint256 subBlock = block.number.sub(createBlock);
              uint256 times = subBlock.div(_distributionTime);
              uint256 distributionValue = times.mul(_distributionSpan);
              uint256 distribution = _mostDistribution;
              if (_leastDistribution.add(distributionValue) > _mostDistribution) {
                  distribution = _leastDistribution;
              } else {
                  distribution = _mostDistribution.sub(distributionValue);
              }
              uint256 nestEth = msg.value.mul(distribution).div(100);
              ethMapping[_nestAddress] = ethMapping[_nestAddress].add(nestEth);
              ethMapping[token] = ethMapping[token].add(msg.value.sub(nestEth));
          }
          
          /**
          * @dev Receive ETH
          * @param num Receive amount 
          * @param token Correspond to locked Token
          * @param target Transfer target
          */
          function getETH(uint256 num, address token, address target) public onlyContract {
              require(num <= ethMapping[token], "Insufficient storage balance");
              ethMapping[token] = ethMapping[token].sub(num);
              address payable addr = target.make_payable();
              addr.transfer(num);
          }
          
          /**
          * @dev Get bonus pool balance
          * @param token Corresponded locked Token
          * @return uint256 Bonus pool balance
          */
          function getETHNum(address token) public view returns (uint256) {
              return ethMapping[token];
          }
          
          // View NEST address
          function checkNestAddress() public view returns(address) {
              return _nestAddress;
          }
          
          // View the highest NEST bonus pool allocation ratio
          function checkMostDistribution() public view returns(uint256) {
              return _mostDistribution;
          }
          
          // View the lowest NEST bonus pool allocation ratio
          function checkLeastDistribution() public view returns(uint256) {
              return _leastDistribution;
          }
          
          // View the decay time interval of NEST bonus pool allocation ratio 
          function checkDistributionTime() public view returns(uint256) {
              return _distributionTime;
          }
          
          // View the decay degree of NEST bonus pool allocation ratio
          function checkDistributionSpan() public view returns(uint256) {
              return _distributionSpan;
          }
          
          // Modify the highest NEST bonus pool allocation ratio
          function changeMostDistribution(uint256 num) public onlyOwner  {
              _mostDistribution = num;
          }
          
          // Modify the lowest NEST bonus pool allocation ratio
          function changeLeastDistribution(uint256 num) public onlyOwner  {
              _leastDistribution = num;
          }
          
          // Modify the decay time interval of NEST bonus pool allocation ratio 
          function changeDistributionTime(uint256 num) public onlyOwner  {
              _distributionTime = num;
          }
          
          // Modify the decay degree of NEST bonus pool allocation ratio
          function changeDistributionSpan(uint256 num) public onlyOwner  {
              _distributionSpan = num;
          }
          
          // Withdraw ETH
          function turnOutAllEth(uint256 amount, address target) public onlyOwner {
              address payable addr = target.make_payable();
              addr.transfer(amount);  
          }
          
          // Only bonus logic contract
          modifier onlyContract(){
              require(_voteFactory.checkAddress("nest.v3.tokenAbonus") == address(msg.sender), "No authority");
              _;
          }
          
          // Administrator only
          modifier onlyOwner(){
              require(_voteFactory.checkOwners(address(msg.sender)), "No authority");
              _;
          }
      }
      
      // Voting factory
      interface Nest_3_VoteFactory {
          // Check address
      	function checkAddress(string calldata name) external view returns (address contractAddress);
      	// Check whether the administrator
      	function checkOwners(address man) external view returns (bool);
      }
      
      // NToken
      interface Nest_NToken {
          // Increase token
          function increaseTotal(uint256 value) external;
          // Query mining information
          function checkBlockInfo() external view returns(uint256 createBlock, uint256 recentlyUsedBlock);
          // Query creator
          function checkOwner() 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);
      }
      
      library SafeMath {
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              require(c >= a, "SafeMath: addition overflow");
      
              return c;
          }
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              return sub(a, b, "SafeMath: subtraction overflow");
          }
          function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b <= a, errorMessage);
              uint256 c = a - b;
      
              return c;
          }
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) {
                  return 0;
              }
              uint256 c = a * b;
              require(c / a == b, "SafeMath: multiplication overflow");
      
              return c;
          }
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              return div(a, b, "SafeMath: division by zero");
          }
          function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b > 0, errorMessage);
              uint256 c = a / b;
              return c;
          }
          function mod(uint256 a, uint256 b) internal pure returns (uint256) {
              return mod(a, b, "SafeMath: modulo by zero");
          }
          function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b != 0, errorMessage);
              return a % b;
          }
      }
      
      library address_make_payable {
         function make_payable(address x) internal pure returns (address payable) {
            return address(uint160(x));
         }
      }

      File 4 of 4: Nest_3_VoteFactory
      pragma solidity 0.6.0;
      
      /**
       * @title Voting factory + mapping
       * @dev Vote creating method
       */
      contract Nest_3_VoteFactory {
          using SafeMath for uint256;
          
          uint256 _limitTime = 7 days;                                    //  Vote duration
          uint256 _NNLimitTime = 1 days;                                  //  NestNode raising time
          uint256 _circulationProportion = 51;                            //  Proportion of votes to pass
          uint256 _NNUsedCreate = 10;                                     //  The minimum number of NNs to create a voting contract
          uint256 _NNCreateLimit = 100;                                   //  The minimum number of NNs needed to start voting
          uint256 _emergencyTime = 0;                                     //  The emergency state start time
          uint256 _emergencyTimeLimit = 3 days;                           //  The emergency state duration
          uint256 _emergencyNNAmount = 1000;                              //  The number of NNs required to switch the emergency state
          ERC20 _NNToken;                                                 //  NestNode Token
          ERC20 _nestToken;                                               //  NestToken
          mapping(string => address) _contractAddress;                    //  Voting contract mapping
          mapping(address => bool) _modifyAuthority;                      //  Modify permissions
          mapping(address => address) _myVote;                            //  Personal voting address
          mapping(address => uint256) _emergencyPerson;                   //  Emergency state personal voting number
          mapping(address => bool) _contractData;                         //  Voting contract data
          bool _stateOfEmergency = false;                                 //  Emergency state
          address _destructionAddress;                                    //  Destroy contract address
      
          event ContractAddress(address contractAddress);
          
          /**
          * @dev Initialization method
          */
          constructor () public {
              _modifyAuthority[address(msg.sender)] = true;
          }
          
          /**
          * @dev Reset contract
          */
          function changeMapping() public onlyOwner {
              _NNToken = ERC20(checkAddress("nestNode"));
              _destructionAddress = address(checkAddress("nest.v3.destruction"));
              _nestToken = ERC20(address(checkAddress("nest")));
          }
          
          /**
          * @dev Create voting contract
          * @param implementContract The executable contract address for voting
          * @param nestNodeAmount Number of NNs to pledge
          */
          function createVote(address implementContract, uint256 nestNodeAmount) public {
              require(address(tx.origin) == address(msg.sender), "It can't be a contract");
              require(nestNodeAmount >= _NNUsedCreate);
              Nest_3_VoteContract newContract = new Nest_3_VoteContract(implementContract, _stateOfEmergency, nestNodeAmount);
              require(_NNToken.transferFrom(address(tx.origin), address(newContract), nestNodeAmount), "Authorization transfer failed");
              _contractData[address(newContract)] = true;
              emit ContractAddress(address(newContract));
          }
          
          /**
          * @dev Use NEST to vote
          * @param contractAddress Vote contract address
          */
          function nestVote(address contractAddress) public {
              require(address(msg.sender) == address(tx.origin), "It can't be a contract");
              require(_contractData[contractAddress], "It's not a voting contract");
              require(!checkVoteNow(address(msg.sender)));
              Nest_3_VoteContract newContract = Nest_3_VoteContract(contractAddress);
              newContract.nestVote();
              _myVote[address(tx.origin)] = contractAddress;
          }
          
          /**
          * @dev Vote using NestNode Token
          * @param contractAddress Vote contract address
          * @param NNAmount Amount of NNs to pledge
          */
          function nestNodeVote(address contractAddress, uint256 NNAmount) public {
              require(address(msg.sender) == address(tx.origin), "It can't be a contract");
              require(_contractData[contractAddress], "It's not a voting contract");
              Nest_3_VoteContract newContract = Nest_3_VoteContract(contractAddress);
              require(_NNToken.transferFrom(address(tx.origin), address(newContract), NNAmount), "Authorization transfer failed");
              newContract.nestNodeVote(NNAmount);
          }
          
          /**
          * @dev Excecute contract
          * @param contractAddress Vote contract address
          */
          function startChange(address contractAddress) public {
              require(address(msg.sender) == address(tx.origin), "It can't be a contract");
              require(_contractData[contractAddress], "It's not a voting contract");
              Nest_3_VoteContract newContract = Nest_3_VoteContract(contractAddress);
              require(_stateOfEmergency == newContract.checkStateOfEmergency());
              addSuperManPrivate(address(newContract));
              newContract.startChange();
              deleteSuperManPrivate(address(newContract));
          }
          
          /**
          * @dev Switch emergency state-transfer in NestNode Token
          * @param amount Amount of NNs to transfer
          */
          function sendNestNodeForStateOfEmergency(uint256 amount) public {
              require(_NNToken.transferFrom(address(tx.origin), address(this), amount));
              _emergencyPerson[address(tx.origin)] = _emergencyPerson[address(tx.origin)].add(amount);
          }
          
          /**
          * @dev Switch emergency state-transfer out NestNode Token
          */
          function turnOutNestNodeForStateOfEmergency() public {
              require(_emergencyPerson[address(tx.origin)] > 0);
              require(_NNToken.transfer(address(tx.origin), _emergencyPerson[address(tx.origin)]));
              _emergencyPerson[address(tx.origin)] = 0;
              uint256 nestAmount = _nestToken.balanceOf(address(this));
              require(_nestToken.transfer(address(_destructionAddress), nestAmount));
          }
          
          /**
          * @dev Modify emergency state
          */
          function changeStateOfEmergency() public {
              if (_stateOfEmergency) {
                  require(now > _emergencyTime.add(_emergencyTimeLimit));
                  _stateOfEmergency = false;
                  _emergencyTime = 0;
              } else {
                  require(_emergencyPerson[address(msg.sender)] > 0);
                  require(_NNToken.balanceOf(address(this)) >= _emergencyNNAmount);
                  _stateOfEmergency = true;
                  _emergencyTime = now;
              }
          }
          
          /**
          * @dev Check whether participating in the voting
          * @param user Address to check
          * @return bool Whether voting
          */
          function checkVoteNow(address user) public view returns (bool) {
              if (_myVote[user] == address(0x0)) {
                  return false;
              } else {
                  Nest_3_VoteContract vote = Nest_3_VoteContract(_myVote[user]);
                  if (vote.checkContractEffective() || vote.checkPersonalAmount(user) == 0) {
                      return false;
                  }
                  return true;
              }
          }
          
          /**
          * @dev Check my voting
          * @param user Address to check
          * @return address Address recently participated in the voting contract address
          */
          function checkMyVote(address user) public view returns (address) {
              return _myVote[user];
          }
          
          //  Check the voting time
          function checkLimitTime() public view returns (uint256) {
              return _limitTime;
          }
          
          //  Check the NestNode raising time
          function checkNNLimitTime() public view returns (uint256) {
              return _NNLimitTime;
          }
          
          //  Check the voting proportion to pass
          function checkCirculationProportion() public view returns (uint256) {
              return _circulationProportion;
          }
          
          //  Check the minimum number of NNs to create a voting contract
          function checkNNUsedCreate() public view returns (uint256) {
              return _NNUsedCreate;
          }
          
          //  Check the minimum number of NNs raised to start a vote
          function checkNNCreateLimit() public view returns (uint256) {
              return _NNCreateLimit;
          }
          
          //  Check whether in emergency state
          function checkStateOfEmergency() public view returns (bool) {
              return _stateOfEmergency;
          }
          
          //  Check the start time of the emergency state
          function checkEmergencyTime() public view returns (uint256) {
              return _emergencyTime;
          }
          
          //  Check the duration of the emergency state
          function checkEmergencyTimeLimit() public view returns (uint256) {
              return _emergencyTimeLimit;
          }
          
          //  Check the amount of personal pledged NNs
          function checkEmergencyPerson(address user) public view returns (uint256) {
              return _emergencyPerson[user];
          }
          
          //  Check the number of NNs required for the emergency
          function checkEmergencyNNAmount() public view returns (uint256) {
              return _emergencyNNAmount;
          }
          
          //  Verify voting contract data
          function checkContractData(address contractAddress) public view returns (bool) {
              return _contractData[contractAddress];
          }
          
          //  Modify voting time
          function changeLimitTime(uint256 num) public onlyOwner {
              require(num > 0, "Parameter needs to be greater than 0");
              _limitTime = num;
          }
          
          //  Modify the NestNode raising time
          function changeNNLimitTime(uint256 num) public onlyOwner {
              require(num > 0, "Parameter needs to be greater than 0");
              _NNLimitTime = num;
          }
          
          //  Modify the voting proportion
          function changeCirculationProportion(uint256 num) public onlyOwner {
              require(num > 0, "Parameter needs to be greater than 0");
              _circulationProportion = num;
          }
          
          //  Modify the minimum number of NNs to create a voting contract
          function changeNNUsedCreate(uint256 num) public onlyOwner {
              _NNUsedCreate = num;
          }
          
          //  Modify the minimum number of NNs to raised to start a voting
          function checkNNCreateLimit(uint256 num) public onlyOwner {
              _NNCreateLimit = num;
          }
          
          //  Modify the emergency state duration
          function changeEmergencyTimeLimit(uint256 num) public onlyOwner {
              require(num > 0);
              _emergencyTimeLimit = num.mul(1 days);
          }
          
          //  Modify the number of NNs required for emergency state
          function changeEmergencyNNAmount(uint256 num) public onlyOwner {
              require(num > 0);
              _emergencyNNAmount = num;
          }
          
          //  Check address
          function checkAddress(string memory name) public view returns (address contractAddress) {
              return _contractAddress[name];
          }
          
          //  Add contract mapping address
          function addContractAddress(string memory name, address contractAddress) public onlyOwner {
              _contractAddress[name] = contractAddress;
          }
          
          //  Add administrator address 
          function addSuperMan(address superMan) public onlyOwner {
              _modifyAuthority[superMan] = true;
          }
          function addSuperManPrivate(address superMan) private {
              _modifyAuthority[superMan] = true;
          }
          
          //  Delete administrator address
          function deleteSuperMan(address superMan) public onlyOwner {
              _modifyAuthority[superMan] = false;
          }
          function deleteSuperManPrivate(address superMan) private {
              _modifyAuthority[superMan] = false;
          }
          
          //  Delete voting contract data
          function deleteContractData(address contractAddress) public onlyOwner {
              _contractData[contractAddress] = false;
          }
          
          //  Check whether the administrator
          function checkOwners(address man) public view returns (bool) {
              return _modifyAuthority[man];
          }
          
          //  Administrator only
          modifier onlyOwner() {
              require(checkOwners(msg.sender), "No authority");
              _;
          }
      }
      
      /**
       * @title Voting contract
       */
      contract Nest_3_VoteContract {
          using SafeMath for uint256;
          
          Nest_3_Implement _implementContract;                //  Executable contract
          Nest_3_TokenSave _tokenSave;                        //  Lock-up contract
          Nest_3_VoteFactory _voteFactory;                    //  Voting factory contract
          Nest_3_TokenAbonus _tokenAbonus;                    //  Bonus logic contract
          ERC20 _nestToken;                                   //  NestToken
          ERC20 _NNToken;                                     //  NestNode Token
          address _miningSave;                                //  Mining pool contract
          address _implementAddress;                          //  Executable contract address
          address _destructionAddress;                        //  Destruction contract address
          uint256 _createTime;                                //  Creation time
          uint256 _endTime;                                   //  End time
          uint256 _totalAmount;                               //  Total votes
          uint256 _circulation;                               //  Passed votes
          uint256 _destroyedNest;                             //  Destroyed NEST
          uint256 _NNLimitTime;                               //  NestNode raising time
          uint256 _NNCreateLimit;                             //  Minimum number of NNs to create votes
          uint256 _abonusTimes;                               //  Period number of used snapshot in emergency state
          uint256 _allNNAmount;                               //  Total number of NNs
          bool _effective = false;                            //  Whether vote is effective
          bool _nestVote = false;                             //  Whether NEST vote can be performed
          bool _isChange = false;                             //  Whether NEST vote is executed
          bool _stateOfEmergency;                             //  Whether the contract is in emergency state
          mapping(address => uint256) _personalAmount;        //  Number of personal votes
          mapping(address => uint256) _personalNNAmount;      //  Number of NN personal votes
          
          /**
          * @dev Initialization method
          * @param contractAddress Executable contract address
          * @param stateOfEmergency Whether in emergency state
          * @param NNAmount Amount of NNs
          */
          constructor (address contractAddress, bool stateOfEmergency, uint256 NNAmount) public {
              Nest_3_VoteFactory voteFactory = Nest_3_VoteFactory(address(msg.sender));
              _voteFactory = voteFactory;
              _nestToken = ERC20(voteFactory.checkAddress("nest"));
              _NNToken = ERC20(voteFactory.checkAddress("nestNode"));
              _implementContract = Nest_3_Implement(address(contractAddress));
              _implementAddress = address(contractAddress);
              _destructionAddress = address(voteFactory.checkAddress("nest.v3.destruction"));
              _personalNNAmount[address(tx.origin)] = NNAmount;
              _allNNAmount = NNAmount;
              _createTime = now;                                    
              _endTime = _createTime.add(voteFactory.checkLimitTime());
              _NNLimitTime = voteFactory.checkNNLimitTime();
              _NNCreateLimit = voteFactory.checkNNCreateLimit();
              _stateOfEmergency = stateOfEmergency;
              if (stateOfEmergency) {
                  //  If in emergency state, read the last two periods of bonus lock-up and total circulation data
                  _tokenAbonus = Nest_3_TokenAbonus(voteFactory.checkAddress("nest.v3.tokenAbonus"));
                  _abonusTimes = _tokenAbonus.checkTimes().sub(2);
                  require(_abonusTimes > 0);
                  _circulation = _tokenAbonus.checkTokenAllValueHistory(address(_nestToken),_abonusTimes).mul(voteFactory.checkCirculationProportion()).div(100);
              } else {
                  _miningSave = address(voteFactory.checkAddress("nest.v3.miningSave"));
                  _tokenSave = Nest_3_TokenSave(voteFactory.checkAddress("nest.v3.tokenSave"));
                  _circulation = (uint256(10000000000 ether).sub(_nestToken.balanceOf(address(_miningSave))).sub(_nestToken.balanceOf(address(_destructionAddress)))).mul(voteFactory.checkCirculationProportion()).div(100);
              }
              if (_allNNAmount >= _NNCreateLimit) {
                  _nestVote = true;
              }
          }
          
          /**
          * @dev NEST voting
          */
          function nestVote() public onlyFactory {
              require(now <= _endTime, "Voting time exceeded");
              require(!_effective, "Vote in force");
              require(_nestVote);
              require(_personalAmount[address(tx.origin)] == 0, "Have voted");
              uint256 amount;
              if (_stateOfEmergency) {
                  //  If in emergency state, read the last two periods of bonus lock-up and total circulation data
                  amount = _tokenAbonus.checkTokenSelfHistory(address(_nestToken),_abonusTimes, address(tx.origin));
              } else {
                  amount = _tokenSave.checkAmount(address(tx.origin), address(_nestToken));
              }
              _personalAmount[address(tx.origin)] = amount;
              _totalAmount = _totalAmount.add(amount);
              ifEffective();
          }
          
          /**
          * @dev NEST voting cancellation
          */
          function nestVoteCancel() public {
              require(address(msg.sender) == address(tx.origin), "It can't be a contract");
              require(now <= _endTime, "Voting time exceeded");
              require(!_effective, "Vote in force");
              require(_personalAmount[address(tx.origin)] > 0, "No vote");                     
              _totalAmount = _totalAmount.sub(_personalAmount[address(tx.origin)]);
              _personalAmount[address(tx.origin)] = 0;
          }
          
          /**
          * @dev  NestNode voting
          * @param NNAmount Amount of NNs
          */
          function nestNodeVote(uint256 NNAmount) public onlyFactory {
              require(now <= _createTime.add(_NNLimitTime), "Voting time exceeded");
              require(!_nestVote);
              _personalNNAmount[address(tx.origin)] = _personalNNAmount[address(tx.origin)].add(NNAmount);
              _allNNAmount = _allNNAmount.add(NNAmount);
              if (_allNNAmount >= _NNCreateLimit) {
                  _nestVote = true;
              }
          }
          
          /**
          * @dev Withdrawing lock-up NNs
          */
          function turnOutNestNode() public {
              if (_nestVote) {
                  //  Normal NEST voting
                  if (!_stateOfEmergency || !_effective) {
                      //  Non-emergency state
                      require(now > _endTime, "Vote unenforceable");
                  }
              } else {
                  //  NN voting
                  require(now > _createTime.add(_NNLimitTime));
              }
              require(_personalNNAmount[address(tx.origin)] > 0);
              //  Reverting back the NNs
              require(_NNToken.transfer(address(tx.origin), _personalNNAmount[address(tx.origin)]));
              _personalNNAmount[address(tx.origin)] = 0;
              //  Destroying NEST Tokens 
              uint256 nestAmount = _nestToken.balanceOf(address(this));
              _destroyedNest = _destroyedNest.add(nestAmount);
              require(_nestToken.transfer(address(_destructionAddress), nestAmount));
          }
          
          /**
          * @dev Execute the contract
          */
          function startChange() public onlyFactory {
              require(!_isChange);
              _isChange = true;
              if (_stateOfEmergency) {
                  require(_effective, "Vote unenforceable");
              } else {
                  require(_effective && now > _endTime, "Vote unenforceable");
              }
              //  Add the executable contract to the administrator list
              _voteFactory.addSuperMan(address(_implementContract));
              //  Execute
              _implementContract.doit();
              //  Delete the authorization
              _voteFactory.deleteSuperMan(address(_implementContract));
          }
          
          /**
          * @dev check whether the vote is effective
          */
          function ifEffective() private {
              if (_totalAmount >= _circulation) {
                  _effective = true;
              }
          }
          
          /**
          * @dev Check whether the vote is over
          */
          function checkContractEffective() public view returns (bool) {
              if (_effective || now > _endTime) {
                  return true;
              } 
              return false;
          }
          
          //  Check the executable implement contract address
          function checkImplementAddress() public view returns (address) {
              return _implementAddress;
          }
          
          //  Check the voting start time
          function checkCreateTime() public view returns (uint256) {
              return _createTime;
          }
          
          //  Check the voting end time
          function checkEndTime() public view returns (uint256) {
              return _endTime;
          }
          
          //  Check the current total number of votes
          function checkTotalAmount() public view returns (uint256) {
              return _totalAmount;
          }
          
          //  Check the number of votes to pass
          function checkCirculation() public view returns (uint256) {
              return _circulation;
          }
          
          //  Check the number of personal votes
          function checkPersonalAmount(address user) public view returns (uint256) {
              return _personalAmount[user];
          }
          
          //  Check the destroyed NEST
          function checkDestroyedNest() public view returns (uint256) {
              return _destroyedNest;
          }
          
          //  Check whether the contract is effective
          function checkEffective() public view returns (bool) {
              return _effective;
          }
          
          //  Check whether in emergency state
          function checkStateOfEmergency() public view returns (bool) {
              return _stateOfEmergency;
          }
          
          //  Check NestNode raising time
          function checkNNLimitTime() public view returns (uint256) {
              return _NNLimitTime;
          }
          
          //  Check the minimum number of NNs to create a vote
          function checkNNCreateLimit() public view returns (uint256) {
              return _NNCreateLimit;
          }
          
          //  Check the period number of snapshot used in the emergency state
          function checkAbonusTimes() public view returns (uint256) {
              return _abonusTimes;
          }
          
          //  Check number of personal votes
          function checkPersonalNNAmount(address user) public view returns (uint256) {
              return _personalNNAmount[address(user)];
          }
          
          //  Check the total number of NNs
          function checkAllNNAmount() public view returns (uint256) {
              return _allNNAmount;
          }
          
          //  Check whether NEST voting is available
          function checkNestVote() public view returns (bool) {
              return _nestVote;
          }
          
          //  Check whether it has been excecuted
          function checkIsChange() public view returns (bool) {
              return _isChange;
          }
          
          //  Vote Factory contract only
          modifier onlyFactory() {
              require(address(_voteFactory) == address(msg.sender), "No authority");
              _;
          }
      }
      
      //  Executable contract
      interface Nest_3_Implement {
          //  Execute
          function doit() external;
      }
      
      //  NEST lock-up contract
      interface Nest_3_TokenSave {
          //  Check lock-up amount
          function checkAmount(address sender, address token) external view returns (uint256);
      }
      
      //  Bonus logic contract
      interface Nest_3_TokenAbonus {
          //  Check NEST circulation snapshot
          function checkTokenAllValueHistory(address token, uint256 times) external view returns (uint256);
          //  Check NEST user balance snapshot
          function checkTokenSelfHistory(address token, uint256 times, address user) external view returns (uint256);
          //  Check bonus ledger period
          function checkTimes() external view returns (uint256);
      }
      
      //  Erc20 contract
      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);
      }
      
      library SafeMath {
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              require(c >= a, "SafeMath: addition overflow");
      
              return c;
          }
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              return sub(a, b, "SafeMath: subtraction overflow");
          }
          function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b <= a, errorMessage);
              uint256 c = a - b;
      
              return c;
          }
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) {
                  return 0;
              }
              uint256 c = a * b;
              require(c / a == b, "SafeMath: multiplication overflow");
      
              return c;
          }
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              return div(a, b, "SafeMath: division by zero");
          }
          function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b > 0, errorMessage);
              uint256 c = a / b;
              return c;
          }
          function mod(uint256 a, uint256 b) internal pure returns (uint256) {
              return mod(a, b, "SafeMath: modulo by zero");
          }
          function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b != 0, errorMessage);
              return a % b;
          }
      }