ETH Price: $1,982.94 (-1.83%)

Transaction Decoder

Block:
11242474 at Nov-12-2020 11:15:24 AM +UTC
Transaction Fee:
0.01962709749 ETH $38.92
Gas Used:
435,722 Gas / 45.045 Gwei

Emitted Events:

81 Nest_NToken_OfferMain.OfferContractAddress( contractAddress=0x00000000...00000A5E0, tokenAddress=YFI, ethAmount=10000000000000000000, erc20Amount=287672927388476390, continued=25, mining=100000000000000000 )
82 YFI.Transfer( from=[Sender] 0x07cb1ef8f2d8485fa19898272f13de2021417a7f, to=[Receiver] Nest_NToken_OfferMain, value=287672927388476390 )
83 YFI.Approval( owner=[Sender] 0x07cb1ef8f2d8485fa19898272f13de2021417a7f, spender=[Receiver] Nest_NToken_OfferMain, value=999999999999999999998747863518543254221199 )
84 Nest_NToken_OfferMain.OreDrawingLog( nowBlock=11242474, blockAmount=160000000000000000000, tokenAddress=Nest_NToken )
85 Nest_NToken.Transfer( from=[Receiver] Nest_NToken_OfferMain, to=0x8e79eF9e545Fa14e205D89970d50E7caA3456683, value=8000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x075190c6...Ea8f38fE2
0x07CB1EF8...021417A7F
49.082057130461835054 Eth
Nonce: 18690
38.962430032971835054 Eth
Nonce: 18691
10.11962709749
0x0bc529c0...67F6Ad93e
0x1542E790...E7794EEf4 40 Eth50 Eth10
0x43121397...e39D44852
(NEST Protocol: Revenue Pool)
942.760085237888071644 Eth942.860085237888071644 Eth0.1
0x94F36FAa...CcD3e80Eb
(Babel Pool)
19,490.38743100589039757 Eth19,490.40705810338039757 Eth0.01962709749

Execution Trace

ETH 10.1 Nest_NToken_OfferMain.offer( ethAmount=10000000000000000000, erc20Amount=287672927388476390, erc20Address=0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e )
  • Nest_NToken_TokenMapping.checkTokenMapping( token=0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e ) => ( 0x075190c6130EA0a3A7E40802F1D77F4Ea8f38fE2 )
  • Nest_3_OfferPrice.updateAndCheckPricePrivate( tokenAddress=0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e ) => ( ethAmount=10000000000000000000, erc20Amount=285317000000000000 )
  • Nest_3_OfferPrice.addPrice( ethAmount=10000000000000000000, tokenAmount=287672927388476390, endBlock=11242499, tokenAddress=0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e, offerOwner=0x07CB1EF8F2d8485Fa19898272f13dE2021417A7F )
  • YFI.transferFrom( sender=0x07CB1EF8F2d8485Fa19898272f13dE2021417A7F, recipient=0x1542E790a742333EA6A2F171c5d07A2E7794EEf4, amount=287672927388476390 ) => ( True )
  • ETH 0.1 Nest_3_Abonus.switchToEthForNTokenOffer( token=0x075190c6130EA0a3A7E40802F1D77F4Ea8f38fE2 )
    • Nest_NToken.STATICCALL( )
    • Nest_NToken.STATICCALL( )
    • Nest_NToken.increaseTotal( value=160000000000000000000 )
      • Nest_3_VoteFactory.checkAddress( name=nest.nToken.offerMain ) => ( contractAddress=0x1542E790a742333EA6A2F171c5d07A2E7794EEf4 )
      • Nest_NToken.STATICCALL( )
      • Nest_NToken.transfer( to=0x8e79eF9e545Fa14e205D89970d50E7caA3456683, value=8000000000000000000 ) => ( True )
        offer[Nest_NToken_OfferMain (ln:106)]
        File 1 of 7: Nest_NToken_OfferMain
        /**
         *Submitted for verification at Etherscan.io on 2020-08-11
        */
        
        pragma solidity 0.6.0;
        
        /**
         * @title Offering contract
         * @dev Offering logic and mining logic
         */
        contract Nest_NToken_OfferMain {
            
            using SafeMath for uint256;
            using address_make_payable for address;
            using SafeERC20 for ERC20;
            
            // Offering data structure
            struct Nest_NToken_OfferPriceData {
                // The unique identifier is determined by the position of the offer in the array, and is converted to each other through a fixed algorithm (toindex(), toaddress())
                address owner;                                  //  Offering owner
                bool deviate;                                   //  Whether it deviates 
                address tokenAddress;                           //  The erc20 contract address of the target offer token
                
                uint256 ethAmount;                              //  The ETH amount in the offer list
                uint256 tokenAmount;                            //  The token amount in the offer list
                
                uint256 dealEthAmount;                          //  The remaining number of tradable ETH
                uint256 dealTokenAmount;                        //  The remaining number of tradable tokens
                
                uint256 blockNum;                               //  The block number where the offer is located
                uint256 serviceCharge;                          //  The fee for mining
                // Determine whether the asset has been collected by judging that ethamount, tokenamount, and servicecharge are all 0
            }
            
            Nest_NToken_OfferPriceData [] _prices;                              //  Array used to save offers
            Nest_3_VoteFactory _voteFactory;                                    //  Voting contract
            Nest_3_OfferPrice _offerPrice;                                      //  Price contract
            Nest_NToken_TokenMapping _tokenMapping;                             //  NToken mapping contract
            ERC20 _nestToken;                                                   //  nestToken
            Nest_3_Abonus _abonus;                                              //  Bonus pool
            uint256 _miningETH = 10;                                            //  Offering mining fee ratio
            uint256 _tranEth = 1;                                               //  Taker fee ratio
            uint256 _tranAddition = 2;                                          //  Additional transaction multiple
            uint256 _leastEth = 10 ether;                                       //  Minimum offer of ETH
            uint256 _offerSpan = 10 ether;                                      //  ETH Offering span
            uint256 _deviate = 10;                                              //  Price deviation - 10%
            uint256 _deviationFromScale = 10;                                   //  Deviation from asset scale
            uint256 _ownerMining = 5;                                           //  Creator ratio
            uint256 _afterMiningAmount = 0.4 ether;                             //  Stable period mining amount
            uint32 _blockLimit = 25;                                            //  Block interval upper limit
            
            uint256 _blockAttenuation = 2400000;                                //  Block decay interval
            mapping(uint256 => mapping(address => uint256)) _blockOfferAmount;  //  Block offer times - block number=>token address=>offer fee
            mapping(uint256 => mapping(address => uint256)) _blockMining;       //  Offering block mining amount - block number=>token address=>mining amount
            uint256[10] _attenuationAmount;                                     //  Mining decay list
            
            //  Log token contract address
            event OfferTokenContractAddress(address contractAddress);           
            //  Log offering contract, token address, amount of ETH, amount of ERC20, delayed block, mining fee
            event OfferContractAddress(address contractAddress, address tokenAddress, uint256 ethAmount, uint256 erc20Amount, uint256 continued,uint256 mining);         
            //  Log transaction sender, transaction token, transaction amount, purchase token address, purchase token amount, transaction offering contract address, transaction user address
            event OfferTran(address tranSender, address tranToken, uint256 tranAmount,address otherToken, uint256 otherAmount, address tradedContract, address tradedOwner);        
            //  Log current block, current block mined amount, token address
            event OreDrawingLog(uint256 nowBlock, uint256 blockAmount, address tokenAddress);
            //  Log offering block, token address, token offered times
            event MiningLog(uint256 blockNum, address tokenAddress, uint256 offerTimes);
            
            /**
             * Initialization method
             * @param voteFactory Voting contract address
             **/
            constructor (address voteFactory) public {
                Nest_3_VoteFactory voteFactoryMap = Nest_3_VoteFactory(address(voteFactory));
                _voteFactory = voteFactoryMap;                                                                 
                _offerPrice = Nest_3_OfferPrice(address(voteFactoryMap.checkAddress("nest.v3.offerPrice")));            
                _nestToken = ERC20(voteFactoryMap.checkAddress("nest"));                                                          
                _abonus = Nest_3_Abonus(voteFactoryMap.checkAddress("nest.v3.abonus"));
                _tokenMapping = Nest_NToken_TokenMapping(address(voteFactoryMap.checkAddress("nest.nToken.tokenMapping")));
                
                uint256 blockAmount = 4 ether;
                for (uint256 i = 0; i < 10; i ++) {
                    _attenuationAmount[i] = blockAmount;
                    blockAmount = blockAmount.mul(8).div(10);
                }
            }
            
            /**
             * Reset voting contract method
             * @param voteFactory Voting contract address
             **/
            function changeMapping(address voteFactory) public onlyOwner {
                Nest_3_VoteFactory voteFactoryMap = Nest_3_VoteFactory(address(voteFactory));
                _voteFactory = voteFactoryMap;                                                          
                _offerPrice = Nest_3_OfferPrice(address(voteFactoryMap.checkAddress("nest.v3.offerPrice")));      
                _nestToken = ERC20(voteFactoryMap.checkAddress("nest"));                                                   
                _abonus = Nest_3_Abonus(voteFactoryMap.checkAddress("nest.v3.abonus"));
                _tokenMapping = Nest_NToken_TokenMapping(address(voteFactoryMap.checkAddress("nest.nToken.tokenMapping")));
            }
            
            /**
             * Offering method
             * @param ethAmount ETH amount
             * @param erc20Amount Erc20 token amount
             * @param erc20Address Erc20 token address
             **/
            function offer(uint256 ethAmount, uint256 erc20Amount, address erc20Address) public payable {
                require(address(msg.sender) == address(tx.origin), "It can't be a contract");
                address nTokenAddress = _tokenMapping.checkTokenMapping(erc20Address);
                require(nTokenAddress != address(0x0));
                //  Judge whether the price deviates
                uint256 ethMining;
                bool isDeviate = comparativePrice(ethAmount,erc20Amount,erc20Address);
                if (isDeviate) {
                    require(ethAmount >= _leastEth.mul(_deviationFromScale), "EthAmount needs to be no less than 10 times of the minimum scale");
                    ethMining = _leastEth.mul(_miningETH).div(1000);
                } else {
                    ethMining = ethAmount.mul(_miningETH).div(1000);
                }
                require(msg.value >= ethAmount.add(ethMining), "msg.value needs to be equal to the quoted eth quantity plus Mining handling fee");
                uint256 subValue = msg.value.sub(ethAmount.add(ethMining));
                if (subValue > 0) {
                    repayEth(address(msg.sender), subValue);
                }
                //  Create an offer
                createOffer(ethAmount, erc20Amount, erc20Address,isDeviate, ethMining);
                //  Transfer in offer asset - erc20 to this contract
                ERC20(erc20Address).safeTransferFrom(address(msg.sender), address(this), erc20Amount);
                _abonus.switchToEthForNTokenOffer.value(ethMining)(nTokenAddress);
                //  Mining
                if (_blockOfferAmount[block.number][erc20Address] == 0) {
                    uint256 miningAmount = oreDrawing(nTokenAddress);
                    Nest_NToken nToken = Nest_NToken(nTokenAddress);
                    nToken.transfer(nToken.checkBidder(), miningAmount.mul(_ownerMining).div(100));
                    _blockMining[block.number][erc20Address] = miningAmount.sub(miningAmount.mul(_ownerMining).div(100));
                }
                _blockOfferAmount[block.number][erc20Address] = _blockOfferAmount[block.number][erc20Address].add(ethMining);
            }
            
            /**
             * @dev Create offer
             * @param ethAmount Offering ETH amount
             * @param erc20Amount Offering erc20 amount
             * @param erc20Address Offering erc20 address
             **/
            function createOffer(uint256 ethAmount, uint256 erc20Amount, address erc20Address, bool isDeviate, uint256 mining) private {
                // Check offer conditions
                require(ethAmount >= _leastEth, "Eth scale is smaller than the minimum scale");                                                 
                require(ethAmount % _offerSpan == 0, "Non compliant asset span");
                require(erc20Amount % (ethAmount.div(_offerSpan)) == 0, "Asset quantity is not divided");
                require(erc20Amount > 0);
                // Create offering contract
                emit OfferContractAddress(toAddress(_prices.length), address(erc20Address), ethAmount, erc20Amount,_blockLimit,mining);
                _prices.push(Nest_NToken_OfferPriceData(
                    msg.sender,
                    isDeviate,
                    erc20Address,
                    
                    ethAmount,
                    erc20Amount,
                    
                    ethAmount, 
                    erc20Amount, 
                    
                    block.number,
                    mining
                ));
                // Record price
                _offerPrice.addPrice(ethAmount, erc20Amount, block.number.add(_blockLimit), erc20Address, address(msg.sender));
            }
            
            // Convert offer address into index in offer array
            function toIndex(address contractAddress) public pure returns(uint256) {
                return uint256(contractAddress);
            }
            
            // Convert index in offer array into offer address 
            function toAddress(uint256 index) public pure returns(address) {
                return address(index);
            }
            
            /**
             * Withdraw offer assets
             * @param contractAddress Offer address
             **/
            function turnOut(address contractAddress) public {
                require(address(msg.sender) == address(tx.origin), "It can't be a contract");
                uint256 index = toIndex(contractAddress);
                Nest_NToken_OfferPriceData storage offerPriceData = _prices[index];
                require(checkContractState(offerPriceData.blockNum) == 1, "Offer status error");
                // Withdraw ETH
                if (offerPriceData.ethAmount > 0) {
                    uint256 payEth = offerPriceData.ethAmount;
                    offerPriceData.ethAmount = 0;
                    repayEth(offerPriceData.owner, payEth);
                }
                // Withdraw erc20
                if (offerPriceData.tokenAmount > 0) {
                    uint256 payErc = offerPriceData.tokenAmount;
                    offerPriceData.tokenAmount = 0;
                    ERC20(address(offerPriceData.tokenAddress)).safeTransfer(address(offerPriceData.owner), payErc);
                    
                }
                // Mining settlement
                if (offerPriceData.serviceCharge > 0) {
                    mining(offerPriceData.blockNum, offerPriceData.tokenAddress, offerPriceData.serviceCharge, offerPriceData.owner);
                    offerPriceData.serviceCharge = 0;
                }
            }
            
            /**
            * @dev Taker order - pay ETH and buy erc20
            * @param ethAmount The amount of ETH of this offer
            * @param tokenAmount The amount of erc20 of this offer
            * @param contractAddress The target offer address
            * @param tranEthAmount The amount of ETH of taker order
            * @param tranTokenAmount The amount of erc20 of taker order
            * @param tranTokenAddress The erc20 address of taker order
            */
            function sendEthBuyErc(uint256 ethAmount, uint256 tokenAmount, address contractAddress, uint256 tranEthAmount, uint256 tranTokenAmount, address tranTokenAddress) public payable {
                require(address(msg.sender) == address(tx.origin), "It can't be a contract");
                uint256 serviceCharge = tranEthAmount.mul(_tranEth).div(1000);
                require(msg.value == ethAmount.add(tranEthAmount).add(serviceCharge), "msg.value needs to be equal to the quotation eth quantity plus transaction eth plus");
                require(tranEthAmount % _offerSpan == 0, "Transaction size does not meet asset span");
                
                //  Get the offer data structure
                uint256 index = toIndex(contractAddress);
                Nest_NToken_OfferPriceData memory offerPriceData = _prices[index]; 
                //  Check the price, compare the current offer to the last effective price
                bool thisDeviate = comparativePrice(ethAmount,tokenAmount,tranTokenAddress);
                bool isDeviate;
                if (offerPriceData.deviate == true) {
                    isDeviate = true;
                } else {
                    isDeviate = thisDeviate;
                }
                //  Limit the taker order only be twice the amount of the offer to prevent large-amount attacks
                if (offerPriceData.deviate) {
                    //  The taker order deviates  x2
                    require(ethAmount >= tranEthAmount.mul(_tranAddition), "EthAmount needs to be no less than 2 times of transaction scale");
                } else {
                    if (isDeviate) {
                        //  If the taken offer is normal and the taker order deviates x10
                        require(ethAmount >= tranEthAmount.mul(_deviationFromScale), "EthAmount needs to be no less than 10 times of transaction scale");
                    } else {
                        //  If the taken offer is normal and the taker order is normal x2
                        require(ethAmount >= tranEthAmount.mul(_tranAddition), "EthAmount needs to be no less than 2 times of transaction scale");
                    }
                }
                
                // Check whether the conditions for taker order are satisfied
                require(checkContractState(offerPriceData.blockNum) == 0, "Offer status error");
                require(offerPriceData.dealEthAmount >= tranEthAmount, "Insufficient trading eth");
                require(offerPriceData.dealTokenAmount >= tranTokenAmount, "Insufficient trading token");
                require(offerPriceData.tokenAddress == tranTokenAddress, "Wrong token address");
                require(tranTokenAmount == offerPriceData.dealTokenAmount * tranEthAmount / offerPriceData.dealEthAmount, "Wrong token amount");
                
                // Update the offer information
                offerPriceData.ethAmount = offerPriceData.ethAmount.add(tranEthAmount);
                offerPriceData.tokenAmount = offerPriceData.tokenAmount.sub(tranTokenAmount);
                offerPriceData.dealEthAmount = offerPriceData.dealEthAmount.sub(tranEthAmount);
                offerPriceData.dealTokenAmount = offerPriceData.dealTokenAmount.sub(tranTokenAmount);
                _prices[index] = offerPriceData;
                // Create a new offer
                createOffer(ethAmount, tokenAmount, tranTokenAddress, isDeviate, 0);
                // Transfer in erc20 + offer asset to this contract
                if (tokenAmount > tranTokenAmount) {
                    ERC20(tranTokenAddress).safeTransferFrom(address(msg.sender), address(this), tokenAmount.sub(tranTokenAmount));
                } else {
                    ERC20(tranTokenAddress).safeTransfer(address(msg.sender), tranTokenAmount.sub(tokenAmount));
                }
        
                // Modify price
                _offerPrice.changePrice(tranEthAmount, tranTokenAmount, tranTokenAddress, offerPriceData.blockNum.add(_blockLimit));
                emit OfferTran(address(msg.sender), address(0x0), tranEthAmount, address(tranTokenAddress), tranTokenAmount, contractAddress, offerPriceData.owner);
                
                // Transfer fee
                if (serviceCharge > 0) {
                    address nTokenAddress = _tokenMapping.checkTokenMapping(tranTokenAddress);
                    _abonus.switchToEth.value(serviceCharge)(nTokenAddress);
                }
            }
            
            /**
            * @dev Taker order - pay erc20 and buy ETH
            * @param ethAmount The amount of ETH of this offer
            * @param tokenAmount The amount of erc20 of this offer
            * @param contractAddress The target offer address
            * @param tranEthAmount The amount of ETH of taker order
            * @param tranTokenAmount The amount of erc20 of taker order
            * @param tranTokenAddress The erc20 address of taker order
            */
            function sendErcBuyEth(uint256 ethAmount, uint256 tokenAmount, address contractAddress, uint256 tranEthAmount, uint256 tranTokenAmount, address tranTokenAddress) public payable {
                require(address(msg.sender) == address(tx.origin), "It can't be a contract");
                uint256 serviceCharge = tranEthAmount.mul(_tranEth).div(1000);
                require(msg.value == ethAmount.sub(tranEthAmount).add(serviceCharge), "msg.value needs to be equal to the quoted eth quantity plus transaction handling fee");
                require(tranEthAmount % _offerSpan == 0, "Transaction size does not meet asset span");
                //  Get the offer data structure
                uint256 index = toIndex(contractAddress);
                Nest_NToken_OfferPriceData memory offerPriceData = _prices[index]; 
                //  Check the price, compare the current offer to the last effective price
                bool thisDeviate = comparativePrice(ethAmount,tokenAmount,tranTokenAddress);
                bool isDeviate;
                if (offerPriceData.deviate == true) {
                    isDeviate = true;
                } else {
                    isDeviate = thisDeviate;
                }
                //  Limit the taker order only be twice the amount of the offer to prevent large-amount attacks
                if (offerPriceData.deviate) {
                    //  The taker order deviates  x2
                    require(ethAmount >= tranEthAmount.mul(_tranAddition), "EthAmount needs to be no less than 2 times of transaction scale");
                } else {
                    if (isDeviate) {
                        //  If the taken offer is normal and the taker order deviates x10
                        require(ethAmount >= tranEthAmount.mul(_deviationFromScale), "EthAmount needs to be no less than 10 times of transaction scale");
                    } else {
                        //  If the taken offer is normal and the taker order is normal x2
                        require(ethAmount >= tranEthAmount.mul(_tranAddition), "EthAmount needs to be no less than 2 times of transaction scale");
                    }
                }
                // Check whether the conditions for taker order are satisfied
                require(checkContractState(offerPriceData.blockNum) == 0, "Offer status error");
                require(offerPriceData.dealEthAmount >= tranEthAmount, "Insufficient trading eth");
                require(offerPriceData.dealTokenAmount >= tranTokenAmount, "Insufficient trading token");
                require(offerPriceData.tokenAddress == tranTokenAddress, "Wrong token address");
                require(tranTokenAmount == offerPriceData.dealTokenAmount * tranEthAmount / offerPriceData.dealEthAmount, "Wrong token amount");
                // Update the offer information
                offerPriceData.ethAmount = offerPriceData.ethAmount.sub(tranEthAmount);
                offerPriceData.tokenAmount = offerPriceData.tokenAmount.add(tranTokenAmount);
                offerPriceData.dealEthAmount = offerPriceData.dealEthAmount.sub(tranEthAmount);
                offerPriceData.dealTokenAmount = offerPriceData.dealTokenAmount.sub(tranTokenAmount);
                _prices[index] = offerPriceData;
                // Create a new offer
                createOffer(ethAmount, tokenAmount, tranTokenAddress, isDeviate, 0);
                // Transfer in erc20 + offer asset to this contract
                ERC20(tranTokenAddress).safeTransferFrom(address(msg.sender), address(this), tranTokenAmount.add(tokenAmount));
                // Modify price
                _offerPrice.changePrice(tranEthAmount, tranTokenAmount, tranTokenAddress, offerPriceData.blockNum.add(_blockLimit));
                emit OfferTran(address(msg.sender), address(tranTokenAddress), tranTokenAmount, address(0x0), tranEthAmount, contractAddress, offerPriceData.owner);
                // Transfer fee
                if (serviceCharge > 0) {
                    address nTokenAddress = _tokenMapping.checkTokenMapping(tranTokenAddress);
                    _abonus.switchToEth.value(serviceCharge)(nTokenAddress);
                }
            }
            
            /**
             * Offering mining
             * @param ntoken NToken address
             **/
            function oreDrawing(address ntoken) private returns(uint256) {
                Nest_NToken miningToken = Nest_NToken(ntoken);
                (uint256 createBlock, uint256 recentlyUsedBlock) = miningToken.checkBlockInfo();
                uint256 attenuationPointNow = block.number.sub(createBlock).div(_blockAttenuation);
                uint256 miningAmount = 0;
                uint256 attenuation;
                if (attenuationPointNow > 9) {
                    attenuation = _afterMiningAmount;
                } else {
                    attenuation = _attenuationAmount[attenuationPointNow];
                }
                miningAmount = attenuation.mul(block.number.sub(recentlyUsedBlock));
                miningToken.increaseTotal(miningAmount);
                emit OreDrawingLog(block.number, miningAmount, ntoken);
                return miningAmount;
            }
            
            /**
             * Retrieve mining
             * @param token Token address
             **/
            function mining(uint256 blockNum, address token, uint256 serviceCharge, address owner) private returns(uint256) {
                //  Block mining amount*offer fee/block offer fee
                uint256 miningAmount = _blockMining[blockNum][token].mul(serviceCharge).div(_blockOfferAmount[blockNum][token]);        
                //  Transfer NToken 
                Nest_NToken nToken = Nest_NToken(address(_tokenMapping.checkTokenMapping(token)));
                require(nToken.transfer(address(owner), miningAmount), "Transfer failure");
                
                emit MiningLog(blockNum, token,_blockOfferAmount[blockNum][token]);
                return miningAmount;
            }
            
            // Compare order prices
            function comparativePrice(uint256 myEthValue, uint256 myTokenValue, address token) private view returns(bool) {
                (uint256 frontEthValue, uint256 frontTokenValue) = _offerPrice.updateAndCheckPricePrivate(token);
                if (frontEthValue == 0 || frontTokenValue == 0) {
                    return false;
                }
                uint256 maxTokenAmount = myEthValue.mul(frontTokenValue).mul(uint256(100).add(_deviate)).div(frontEthValue.mul(100));
                if (myTokenValue <= maxTokenAmount) {
                    uint256 minTokenAmount = myEthValue.mul(frontTokenValue).mul(uint256(100).sub(_deviate)).div(frontEthValue.mul(100));
                    if (myTokenValue >= minTokenAmount) {
                        return false;
                    }
                }
                return true;
            }
            
            // Check contract status
            function checkContractState(uint256 createBlock) public view returns (uint256) {
                if (block.number.sub(createBlock) > _blockLimit) {
                    return 1;
                }
                return 0;
            }
            
            // Transfer ETH
            function repayEth(address accountAddress, uint256 asset) private {
                address payable addr = accountAddress.make_payable();
                addr.transfer(asset);
            }
            
            // View the upper limit of the block interval
            function checkBlockLimit() public view returns(uint256) {
                return _blockLimit;
            }
            
            // View taker fee ratio
            function checkTranEth() public view returns (uint256) {
                return _tranEth;
            }
            
            // View additional transaction multiple
            function checkTranAddition() public view returns(uint256) {
                return _tranAddition;
            }
            
            // View minimum offering ETH
            function checkleastEth() public view returns(uint256) {
                return _leastEth;
            }
            
            // View offering ETH span
            function checkOfferSpan() public view returns(uint256) {
                return _offerSpan;
            }
        
            // View block offering amount
            function checkBlockOfferAmount(uint256 blockNum, address token) public view returns (uint256) {
                return _blockOfferAmount[blockNum][token];
            }
            
            // View offering block mining amount
            function checkBlockMining(uint256 blockNum, address token) public view returns (uint256) {
                return _blockMining[blockNum][token];
            }
            
            // View offering mining amount
            function checkOfferMining(uint256 blockNum, address token, uint256 serviceCharge) public view returns (uint256) {
                if (serviceCharge == 0) {
                    return 0;
                } else {
                    return _blockMining[blockNum][token].mul(serviceCharge).div(_blockOfferAmount[blockNum][token]);
                }
            }
            
            //  View the owner allocation ratio
            function checkOwnerMining() public view returns(uint256) {
                return _ownerMining;
            }
            
            // View the mining decay
            function checkAttenuationAmount(uint256 num) public view returns(uint256) {
                return _attenuationAmount[num];
            }
            
            // Modify taker order fee ratio
            function changeTranEth(uint256 num) public onlyOwner {
                _tranEth = num;
            }
            
            // Modify block interval upper limit
            function changeBlockLimit(uint32 num) public onlyOwner {
                _blockLimit = num;
            }
            
            // Modify additional transaction multiple
            function changeTranAddition(uint256 num) public onlyOwner {
                require(num > 0, "Parameter needs to be greater than 0");
                _tranAddition = num;
            }
            
            // Modify minimum offering ETH
            function changeLeastEth(uint256 num) public onlyOwner {
                require(num > 0, "Parameter needs to be greater than 0");
                _leastEth = num;
            }
            
            // Modify offering ETH span
            function changeOfferSpan(uint256 num) public onlyOwner {
                require(num > 0, "Parameter needs to be greater than 0");
                _offerSpan = num;
            }
            
            // Modify price deviation
            function changekDeviate(uint256 num) public onlyOwner {
                _deviate = num;
            }
            
            // Modify the deviation from scale 
            function changeDeviationFromScale(uint256 num) public onlyOwner {
                _deviationFromScale = num;
            }
            
            // Modify the owner allocation ratio
            function changeOwnerMining(uint256 num) public onlyOwner {
                _ownerMining = num;
            }
            
            // Modify the mining decay
            function changeAttenuationAmount(uint256 firstAmount, uint256 top, uint256 bottom) public onlyOwner {
                uint256 blockAmount = firstAmount;
                for (uint256 i = 0; i < 10; i ++) {
                    _attenuationAmount[i] = blockAmount;
                    blockAmount = blockAmount.mul(top).div(bottom);
                }
            }
            
            // Vote administrators only
            modifier onlyOwner(){
                require(_voteFactory.checkOwners(msg.sender), "No authority");
                _;
            }
            
            /**
             * Get the number of offers stored in the offer array
             * @return The number of offers stored in the offer array
             **/
            function getPriceCount() view public returns (uint256) {
                return _prices.length;
            }
            
            /**
             * Get offer information according to the index
             * @param priceIndex Offer index
             * @return Offer information
             **/
            function getPrice(uint256 priceIndex) view public returns (string memory) {
                //  The buffer array used to generate the result string
                bytes memory buf = new bytes(500000);
                uint256 index = 0;
                index = writeOfferPriceData(priceIndex, _prices[priceIndex], buf, index);
                // Generate the result string and return
                bytes memory str = new bytes(index);
                while(index-- > 0) {
                    str[index] = buf[index];
                }
                return string(str);
            }
            
            /**
             * Search the contract address list of the target account (reverse order)
             * @param start Search forward from the index corresponding to the given contract address (not including the record corresponding to start address)
             * @param count Maximum number of records to return
             * @param maxFindCount The max index to search
             * @param owner Target account address
             * @return Separate the offer records with symbols. use , to divide fields:  
             * uuid,owner,tokenAddress,ethAmount,tokenAmount,dealEthAmount,dealTokenAmount,blockNum,serviceCharge
             **/
            function find(address start, uint256 count, uint256 maxFindCount, address owner) view public returns (string memory) {
                // Buffer array used to generate result string
                bytes memory buf = new bytes(500000);
                uint256 index = 0;
                // Calculate search interval i and end
                uint256 i = _prices.length;
                uint256 end = 0;
                if (start != address(0)) {
                    i = toIndex(start);
                }
                if (i > maxFindCount) {
                    end = i - maxFindCount;
                }
                // Loop search, write qualified records into buffer
                while (count > 0 && i-- > end) {
                    Nest_NToken_OfferPriceData memory price = _prices[i];
                    if (price.owner == owner) {
                        --count;
                        index = writeOfferPriceData(i, price, buf, index);
                    }
                }
                // Generate result string and return
                bytes memory str = new bytes(index);
                while(index-- > 0) {
                    str[index] = buf[index];
                }
                return string(str);
            }
            
            /**
             * Get the list of offers by page
             * @param offset Skip the first offset records
             * @param count Maximum number of records to return
             * @param order Sort rules. 0 means reverse order, non-zero means positive order
             * @return Separate the offer records with symbols. use , to divide fields: 
             * uuid,owner,tokenAddress,ethAmount,tokenAmount,dealEthAmount,dealTokenAmount,blockNum,serviceCharge
             **/
            function list(uint256 offset, uint256 count, uint256 order) view public returns (string memory) {
                
                // Buffer array used to generate result string 
                bytes memory buf = new bytes(500000);
                uint256 index = 0;
                
                // Find search interval i and end
                uint256 i = 0;
                uint256 end = 0;
                
                if (order == 0) {
                    // Reverse order, in default 
                    // Calculate search interval i and end
                    if (offset < _prices.length) {
                        i = _prices.length - offset;
                    } 
                    if (count < i) {
                        end = i - count;
                    }
                    
                    // Write records in the target interval into the buffer
                    while (i-- > end) {
                        index = writeOfferPriceData(i, _prices[i], buf, index);
                    }
                } else {
                    // Ascending order
                    // Calculate the search interval i and end
                    if (offset < _prices.length) {
                        i = offset;
                    } else {
                        i = _prices.length;
                    }
                    end = i + count;
                    if(end > _prices.length) {
                        end = _prices.length;
                    }
                    
                    // Write the records in the target interval into the buffer
                    while (i < end) {
                        index = writeOfferPriceData(i, _prices[i], buf, index);
                        ++i;
                    }
                }
                
                // Generate the result string and return
                bytes memory str = new bytes(index);
                while(index-- > 0) {
                    str[index] = buf[index];
                }
                return string(str);
            }   
             
            // Write the offer data into the buffer and return the buffer index
            function writeOfferPriceData(uint256 priceIndex, Nest_NToken_OfferPriceData memory price, bytes memory buf, uint256 index) pure private returns (uint256) {
                
                index = writeAddress(toAddress(priceIndex), buf, index);
                buf[index++] = byte(uint8(44));
                
                index = writeAddress(price.owner, buf, index);
                buf[index++] = byte(uint8(44));
                
                index = writeAddress(price.tokenAddress, buf, index);
                buf[index++] = byte(uint8(44));
                
                index = writeUInt(price.ethAmount, buf, index);
                buf[index++] = byte(uint8(44));
                
                index = writeUInt(price.tokenAmount, buf, index);
                buf[index++] = byte(uint8(44));
               
                index = writeUInt(price.dealEthAmount, buf, index);
                buf[index++] = byte(uint8(44));
                
                index = writeUInt(price.dealTokenAmount, buf, index);
                buf[index++] = byte(uint8(44));
                
                index = writeUInt(price.blockNum, buf, index);
                buf[index++] = byte(uint8(44));
                
                index = writeUInt(price.serviceCharge, buf, index);
                buf[index++] = byte(uint8(44));
                
                return index;
            }
             
            // Convert integer to string in decimal form, write the string into the buffer, and return the buffer index
            function writeUInt(uint256 iv, bytes memory buf, uint256 index) pure public returns (uint256) {
                uint256 i = index;
                do {
                    buf[index++] = byte(uint8(iv % 10 +48));
                    iv /= 10;
                } while (iv > 0);
                
                for (uint256 j = index; j > i; ++i) {
                    byte t = buf[i];
                    buf[i] = buf[--j];
                    buf[j] = t;
                }
                
                return index;
            }
        
            // Convert the address to a hexadecimal string and write it into the buffer, and return the buffer index
            function writeAddress(address addr, bytes memory buf, uint256 index) pure private returns (uint256) {
                
                uint256 iv = uint256(addr);
                uint256 i = index + 40;
                do {
                    uint256 w = iv % 16;
                    if(w < 10) {
                        buf[index++] = byte(uint8(w +48));
                    } else {
                        buf[index++] = byte(uint8(w +87));
                    }
                    
                    iv /= 16;
                } while (index < i);
                
                i -= 40;
                for (uint256 j = index; j > i; ++i) {
                    byte t = buf[i];
                    buf[i] = buf[--j];
                    buf[j] = t;
                }
                
                return index;
            }
        }
        
        // Price contract
        interface Nest_3_OfferPrice {
            // Add price data
            function addPrice(uint256 ethAmount, uint256 tokenAmount, uint256 endBlock, address tokenAddress, address offerOwner) external;
            // Modify price
            function changePrice(uint256 ethAmount, uint256 tokenAmount, address tokenAddress, uint256 endBlock) external;
            function updateAndCheckPricePrivate(address tokenAddress) external view returns(uint256 ethAmount, uint256 erc20Amount);
        }
        
        // Voting contract
        interface Nest_3_VoteFactory {
            //  Check address
        	function checkAddress(string calldata name) external view returns (address contractAddress);
        	// Check whether an administrator
        	function checkOwners(address man) external view returns (bool);
        }
        
        // NToken contract
        interface Nest_NToken {
            // Additional issuance
            function increaseTotal(uint256 value) external;
            // Check mining information
            function checkBlockInfo() external view returns(uint256 createBlock, uint256 recentlyUsedBlock);
            // Check creator
            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);
        }
        
        // NToken mapping contract
        interface Nest_NToken_TokenMapping {
            // Check token mapping
            function checkTokenMapping(address token) external view returns (address);
        }
        
        // Bonus pool contract
        interface Nest_3_Abonus {
            function switchToEth(address token) external payable;
            function switchToEthForNTokenOffer(address token) external payable;
        }
        
        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));
           }
        }
        
        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, "SafeERC20: decreased allowance below zero");
                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);
        }
        
        library Address {
            function isContract(address account) internal view returns (bool) {
                bytes32 codehash;
                bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
                assembly { codehash := extcodehash(account) }
                return (codehash != accountHash && codehash != 0x0);
            }
            function sendValue(address payable recipient, uint256 amount) internal {
                require(address(this).balance >= amount, "Address: insufficient balance");
                (bool success, ) = recipient.call.value(amount)("");
                require(success, "Address: unable to send value, recipient may have reverted");
            }
        }

        File 2 of 7: YFI
        pragma solidity ^0.5.16;
        
        interface IERC20 {
            function totalSupply() external view returns (uint);
            function balanceOf(address account) external view returns (uint);
            function transfer(address recipient, uint amount) external returns (bool);
            function allowance(address owner, address spender) external view returns (uint);
            function approve(address spender, uint amount) external returns (bool);
            function transferFrom(address sender, address recipient, uint amount) external returns (bool);
            event Transfer(address indexed from, address indexed to, uint value);
            event Approval(address indexed owner, address indexed spender, uint value);
        }
        
        contract Context {
            constructor () internal { }
            // solhint-disable-previous-line no-empty-blocks
        
            function _msgSender() internal view returns (address payable) {
                return msg.sender;
            }
        }
        
        contract ERC20 is Context, IERC20 {
            using SafeMath for uint;
        
            mapping (address => uint) private _balances;
        
            mapping (address => mapping (address => uint)) private _allowances;
        
            uint private _totalSupply;
            function totalSupply() public view returns (uint) {
                return _totalSupply;
            }
            function balanceOf(address account) public view returns (uint) {
                return _balances[account];
            }
            function transfer(address recipient, uint amount) public returns (bool) {
                _transfer(_msgSender(), recipient, amount);
                return true;
            }
            function allowance(address owner, address spender) public view returns (uint) {
                return _allowances[owner][spender];
            }
            function approve(address spender, uint amount) public returns (bool) {
                _approve(_msgSender(), spender, amount);
                return true;
            }
            function transferFrom(address sender, address recipient, uint amount) public returns (bool) {
                _transfer(sender, recipient, amount);
                _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
                return true;
            }
            function increaseAllowance(address spender, uint addedValue) public returns (bool) {
                _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
                return true;
            }
            function decreaseAllowance(address spender, uint subtractedValue) public returns (bool) {
                _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                return true;
            }
            function _transfer(address sender, address recipient, uint amount) internal {
                require(sender != address(0), "ERC20: transfer from the zero address");
                require(recipient != address(0), "ERC20: transfer to the zero address");
        
                _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
                _balances[recipient] = _balances[recipient].add(amount);
                emit Transfer(sender, recipient, amount);
            }
            function _mint(address account, uint amount) internal {
                require(account != address(0), "ERC20: mint to the zero address");
        
                _totalSupply = _totalSupply.add(amount);
                _balances[account] = _balances[account].add(amount);
                emit Transfer(address(0), account, amount);
            }
            function _burn(address account, uint amount) internal {
                require(account != address(0), "ERC20: burn from the zero address");
        
                _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
                _totalSupply = _totalSupply.sub(amount);
                emit Transfer(account, address(0), amount);
            }
            function _approve(address owner, address spender, uint amount) internal {
                require(owner != address(0), "ERC20: approve from the zero address");
                require(spender != address(0), "ERC20: approve to the zero address");
        
                _allowances[owner][spender] = amount;
                emit Approval(owner, spender, amount);
            }
        }
        
        contract ERC20Detailed is IERC20 {
            string private _name;
            string private _symbol;
            uint8 private _decimals;
        
            constructor (string memory name, string memory symbol, uint8 decimals) public {
                _name = name;
                _symbol = symbol;
                _decimals = decimals;
            }
            function name() public view returns (string memory) {
                return _name;
            }
            function symbol() public view returns (string memory) {
                return _symbol;
            }
            function decimals() public view returns (uint8) {
                return _decimals;
            }
        }
        
        library SafeMath {
            function add(uint a, uint b) internal pure returns (uint) {
                uint c = a + b;
                require(c >= a, "SafeMath: addition overflow");
        
                return c;
            }
            function sub(uint a, uint b) internal pure returns (uint) {
                return sub(a, b, "SafeMath: subtraction overflow");
            }
            function sub(uint a, uint b, string memory errorMessage) internal pure returns (uint) {
                require(b <= a, errorMessage);
                uint c = a - b;
        
                return c;
            }
            function mul(uint a, uint b) internal pure returns (uint) {
                if (a == 0) {
                    return 0;
                }
        
                uint c = a * b;
                require(c / a == b, "SafeMath: multiplication overflow");
        
                return c;
            }
            function div(uint a, uint b) internal pure returns (uint) {
                return div(a, b, "SafeMath: division by zero");
            }
            function div(uint a, uint b, string memory errorMessage) internal pure returns (uint) {
                // Solidity only automatically asserts when dividing by 0
                require(b > 0, errorMessage);
                uint c = a / b;
        
                return c;
            }
        }
        
        library Address {
            function isContract(address account) internal view returns (bool) {
                bytes32 codehash;
                bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
                // solhint-disable-next-line no-inline-assembly
                assembly { codehash := extcodehash(account) }
                return (codehash != 0x0 && codehash != accountHash);
            }
        }
        
        library SafeERC20 {
            using SafeMath for uint;
            using Address for address;
        
            function safeTransfer(IERC20 token, address to, uint value) internal {
                callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
            }
        
            function safeTransferFrom(IERC20 token, address from, address to, uint value) internal {
                callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
            }
        
            function safeApprove(IERC20 token, address spender, uint 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 callOptionalReturn(IERC20 token, bytes memory data) private {
                require(address(token).isContract(), "SafeERC20: call to non-contract");
        
                // solhint-disable-next-line avoid-low-level-calls
                (bool success, bytes memory returndata) = address(token).call(data);
                require(success, "SafeERC20: low-level call failed");
        
                if (returndata.length > 0) { // Return data is optional
                    // solhint-disable-next-line max-line-length
                    require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
                }
            }
        }
        
        contract YFI is ERC20, ERC20Detailed {
          using SafeERC20 for IERC20;
          using Address for address;
          using SafeMath for uint;
          
          
          address public governance;
          mapping (address => bool) public minters;
        
          constructor () public ERC20Detailed("yearn.finance", "YFI", 18) {
              governance = msg.sender;
          }
        
          function mint(address account, uint amount) public {
              require(minters[msg.sender], "!minter");
              _mint(account, amount);
          }
          
          function setGovernance(address _governance) public {
              require(msg.sender == governance, "!governance");
              governance = _governance;
          }
          
          function addMinter(address _minter) public {
              require(msg.sender == governance, "!governance");
              minters[_minter] = true;
          }
          
          function removeMinter(address _minter) public {
              require(msg.sender == governance, "!governance");
              minters[_minter] = false;
          }
        }

        File 3 of 7: Nest_NToken
        pragma solidity 0.6.0;
        
        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;
            }
        }
        
        //  voting contract 
        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);
        }
        
        /**
         * @title NToken contract 
         * @dev Include standard erc20 method, mining method, and mining data 
         */
        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);
        }
        
        contract Nest_NToken is IERC20 {
            using SafeMath for uint256;
            
            mapping (address => uint256) private _balances;                                 //  Balance ledger 
            mapping (address => mapping (address => uint256)) private _allowed;             //  Approval ledger 
            uint256 private _totalSupply = 0 ether;                                         //  Total supply 
            string public name;                                                             //  Token name 
            string public symbol;                                                           //  Token symbol 
            uint8 public decimals = 18;                                                     //  Precision
            uint256 public _createBlock;                                                    //  Create block number
            uint256 public _recentlyUsedBlock;                                              //  Recently used block number
            Nest_3_VoteFactory _voteFactory;                                                //  Voting factory contract
            address _bidder;                                                                //  Owner
            
            /**
            * @dev Initialization method
            * @param _name Token name
            * @param _symbol Token symbol
            * @param voteFactory Voting factory contract address
            * @param bidder Successful bidder address
            */
            constructor (string memory _name, string memory _symbol, address voteFactory, address bidder) public {
            	name = _name;                                                               
            	symbol = _symbol;
            	_createBlock = block.number;
            	_recentlyUsedBlock = block.number;
            	_voteFactory = Nest_3_VoteFactory(address(voteFactory));
            	_bidder = bidder;
            }
            
            /**
            * @dev Reset voting contract method
            * @param voteFactory Voting contract address
            */
            function changeMapping (address voteFactory) public onlyOwner {
            	_voteFactory = Nest_3_VoteFactory(address(voteFactory));
            }
            
            /**
            * @dev Additional issuance
            * @param value Additional issuance amount
            */
            function increaseTotal(uint256 value) 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 Check the total amount of tokens
            * @return Total supply
            */
            function totalSupply() override public view returns (uint256) {
                return _totalSupply;
            }
        
            /**
            * @dev Check address balance
            * @param owner Address to be checked
            * @return Return the balance of the corresponding address
            */
            function balanceOf(address owner) override public view returns (uint256) {
                return _balances[owner];
            }
            
            /**
            * @dev Check block information
            * @return createBlock Initial block number
            * @return recentlyUsedBlock Recently mined and issued block
            */
            function checkBlockInfo() public view returns(uint256 createBlock, uint256 recentlyUsedBlock) {
                return (_createBlock, _recentlyUsedBlock);
            }
        
            /**
             * @dev Check owner's approved allowance to the spender
             * @param owner Approving address
             * @param spender Approved address
             * @return Approved amount
             */
            function allowance(address owner, address spender) override public view returns (uint256) {
                return _allowed[owner][spender];
            }
        
            /**
            * @dev Transfer method
            * @param to Transfer target
            * @param value Transfer amount
            * @return Whether the transfer is successful
            */
            function transfer(address to, uint256 value) override public returns (bool) {
                _transfer(msg.sender, to, value);
                return true;
            }
        
            /**
             * @dev Approval method
             * @param spender Approval target
             * @param value Approval amount
             * @return Whether the approval is successful
             */
            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 when approved
             * @param from Transfer-out account address
             * @param to Transfer-in account address
             * @param value Transfer amount
             * @return Whether approved transfer is successful
             */
            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 allowance
             * @param spender Approval target
             * @param addedValue Amount to increase
             * @return whether increase is successful
             */
            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 allowance
             * @param spender Approval target
             * @param subtractedValue Amount to decrease
             * @return Whether decrease is successful
             */
            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 method
            * @param to Transfer target
            * @param value Transfer amount
            */
            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 Check the creator
            * @return Creator address
            */
            function checkBidder() public view returns(address) {
                return _bidder;
            }
            
            /**
            * @dev Transfer creator
            * @param bidder New creator address
            */
            function changeBidder(address bidder) public {
                require(address(msg.sender) == _bidder);
                _bidder = bidder; 
            }
            
            // Administrator only
            modifier onlyOwner(){
                require(_voteFactory.checkOwners(msg.sender));
                _;
            }
        }

        File 4 of 7: Nest_NToken_TokenMapping
        pragma solidity 0.6.0;
        
        /**
         * @title NToken mapping contract
         * @dev Add, modify and check offering token mapping
         */
        contract Nest_NToken_TokenMapping {
            
            mapping (address => address) _tokenMapping;                 //  Token mapping - offering token => NToken
            Nest_3_VoteFactory _voteFactory;                            //  Voting contract
            
            event TokenMappingLog(address token, address nToken);
            
            /**
            * @dev Initialization method
            * @param voteFactory Voting contract address
            */
            constructor(address voteFactory) public {
                _voteFactory = Nest_3_VoteFactory(address(voteFactory));
            }
            
            /**
            * @dev Reset voting contract
            * @param voteFactory  voting contract address
            */
            function changeMapping(address voteFactory) public onlyOwner {
            	_voteFactory = Nest_3_VoteFactory(address(voteFactory));
            }
            
            /**
            * @dev Add token mapping
            * @param token Offering token address
            * @param nToken Mining NToken address
            */
            function addTokenMapping(address token, address nToken) public {
                require(address(msg.sender) == address(_voteFactory.checkAddress("nest.nToken.tokenAuction")), "No authority");
                require(_tokenMapping[token] == address(0x0), "Token already exists");
                _tokenMapping[token] = nToken;
                emit TokenMappingLog(token, nToken);
            }
            
            /**
            * @dev Change token mapping
            * @param token Offering token address
            * @param nToken Mining NToken address
            */
            function changeTokenMapping(address token, address nToken) public onlyOwner {
                _tokenMapping[token] = nToken;
                emit TokenMappingLog(token, nToken);
            }
            
            /**
            * @dev Check token mapping
            * @param token Offering token address
            * @return Mining NToken address
            */
            function checkTokenMapping(address token) public view returns (address) {
                return _tokenMapping[token];
            }
            
            // Only for administrator
            modifier onlyOwner(){
                require(_voteFactory.checkOwners(msg.sender), "No authority");
                _;
            }
        }
        
        // Voting contract
        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);
        }

        File 5 of 7: Nest_3_OfferPrice
        pragma solidity 0.6.0;
        
        /**
         * @title Price contract
         * @dev Price check and call
         */
        contract Nest_3_OfferPrice{
            using SafeMath for uint256;
            using address_make_payable for address;
            using SafeERC20 for ERC20;
            
            Nest_3_VoteFactory _voteFactory;                                //  Voting contract
            ERC20 _nestToken;                                               //  NestToken
            Nest_NToken_TokenMapping _tokenMapping;                         //  NToken mapping
            Nest_3_OfferMain _offerMain;                                    //  Offering main contract
            Nest_3_Abonus _abonus;                                          //  Bonus pool
            address _nTokeOfferMain;                                        //  NToken offering main contract
            address _destructionAddress;                                    //  Destruction contract address
            address _nTokenAuction;                                         //  NToken auction contract address
            struct PriceInfo {                                              //  Block price
                uint256 ethAmount;                                          //  ETH amount
                uint256 erc20Amount;                                        //  Erc20 amount
                uint256 frontBlock;                                         //  Last effective block
                address offerOwner;                                         //  Offering address
            }
            struct TokenInfo {                                              //  Token offer information
                mapping(uint256 => PriceInfo) priceInfoList;                //  Block price list, block number => block price
                uint256 latestOffer;                                        //  Latest effective block
            }
            uint256 destructionAmount = 0 ether;                            //  Amount of NEST to destroy to call prices
            uint256 effectTime = 0 days;                                    //  Waiting time to start calling prices
            mapping(address => TokenInfo) _tokenInfo;                       //  Token offer information
            mapping(address => bool) _blocklist;                            //  Block list
            mapping(address => uint256) _addressEffect;                     //  Effective time of address to call prices 
            mapping(address => bool) _offerMainMapping;                     //  Offering contract mapping
            uint256 _priceCost = 0.01 ether;                                //  Call price fee
        
            //  Real-time price  token, ETH amount, erc20 amount
            event NowTokenPrice(address a, uint256 b, uint256 c);
            
            /**
            * @dev Initialization method
            * @param voteFactory Voting contract address
            */
            constructor (address voteFactory) public {
                Nest_3_VoteFactory voteFactoryMap = Nest_3_VoteFactory(address(voteFactory));
                _voteFactory = voteFactoryMap;
                _offerMain = Nest_3_OfferMain(address(voteFactoryMap.checkAddress("nest.v3.offerMain")));
                _nTokeOfferMain = address(voteFactoryMap.checkAddress("nest.nToken.offerMain"));
                _abonus = Nest_3_Abonus(address(voteFactoryMap.checkAddress("nest.v3.abonus")));
                _destructionAddress = address(voteFactoryMap.checkAddress("nest.v3.destruction"));
                _nestToken = ERC20(address(voteFactoryMap.checkAddress("nest")));
                _tokenMapping = Nest_NToken_TokenMapping(address(voteFactoryMap.checkAddress("nest.nToken.tokenMapping")));
                _nTokenAuction = address(voteFactoryMap.checkAddress("nest.nToken.tokenAuction"));
                _offerMainMapping[address(_offerMain)] = true;
                _offerMainMapping[address(_nTokeOfferMain)] = true;
            }
            
            /**
            * @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;                                   
                _offerMain = Nest_3_OfferMain(address(voteFactoryMap.checkAddress("nest.v3.offerMain")));
                _nTokeOfferMain = address(voteFactoryMap.checkAddress("nest.nToken.offerMain"));
                _abonus = Nest_3_Abonus(address(voteFactoryMap.checkAddress("nest.v3.abonus")));
                _destructionAddress = address(voteFactoryMap.checkAddress("nest.v3.destruction"));
                _nestToken = ERC20(address(voteFactoryMap.checkAddress("nest")));
                _tokenMapping = Nest_NToken_TokenMapping(address(voteFactoryMap.checkAddress("nest.nToken.tokenMapping")));
                _nTokenAuction = address(voteFactoryMap.checkAddress("nest.nToken.tokenAuction"));
                _offerMainMapping[address(_offerMain)] = true;
                _offerMainMapping[address(_nTokeOfferMain)] = true;
            }
            
            /**
            * @dev Initialize token price charge parameters
            * @param tokenAddress Token address
            */
            function addPriceCost(address tokenAddress) public {
               
            }
            
            /**
            * @dev Add price
            * @param ethAmount ETH amount
            * @param tokenAmount Erc20 amount
            * @param endBlock Effective price block
            * @param tokenAddress Erc20 address
            * @param offerOwner Offering address
            */
            function addPrice(uint256 ethAmount, uint256 tokenAmount, uint256 endBlock, address tokenAddress, address offerOwner) public onlyOfferMain{
                // Add effective block price information
                TokenInfo storage tokenInfo = _tokenInfo[tokenAddress];
                PriceInfo storage priceInfo = tokenInfo.priceInfoList[endBlock];
                priceInfo.ethAmount = priceInfo.ethAmount.add(ethAmount);
                priceInfo.erc20Amount = priceInfo.erc20Amount.add(tokenAmount);
                if (endBlock != tokenInfo.latestOffer) {
                    // If different block offer
                    priceInfo.frontBlock = tokenInfo.latestOffer;
                    tokenInfo.latestOffer = endBlock;
                }
            }
            
            /**
            * @dev Price modification in taker orders
            * @param ethAmount ETH amount
            * @param tokenAmount Erc20 amount
            * @param tokenAddress Token address 
            * @param endBlock Block of effective price
            */
            function changePrice(uint256 ethAmount, uint256 tokenAmount, address tokenAddress, uint256 endBlock) public onlyOfferMain {
                TokenInfo storage tokenInfo = _tokenInfo[tokenAddress];
                PriceInfo storage priceInfo = tokenInfo.priceInfoList[endBlock];
                priceInfo.ethAmount = priceInfo.ethAmount.sub(ethAmount);
                priceInfo.erc20Amount = priceInfo.erc20Amount.sub(tokenAmount);
            }
            
            /**
            * @dev Update and check the latest price
            * @param tokenAddress Token address
            * @return ethAmount ETH amount
            * @return erc20Amount Erc20 amount
            * @return blockNum Price block
            */
            function updateAndCheckPriceNow(address tokenAddress) public payable returns(uint256 ethAmount, uint256 erc20Amount, uint256 blockNum) {
                require(checkUseNestPrice(address(msg.sender)));
                mapping(uint256 => PriceInfo) storage priceInfoList = _tokenInfo[tokenAddress].priceInfoList;
                uint256 checkBlock = _tokenInfo[tokenAddress].latestOffer;
                while(checkBlock > 0 && (checkBlock >= block.number || priceInfoList[checkBlock].ethAmount == 0)) {
                    checkBlock = priceInfoList[checkBlock].frontBlock;
                }
                require(checkBlock != 0);
                PriceInfo memory priceInfo = priceInfoList[checkBlock];
                address nToken = _tokenMapping.checkTokenMapping(tokenAddress);
                if (nToken == address(0x0)) {
                    _abonus.switchToEth.value(_priceCost)(address(_nestToken));
                } else {
                    _abonus.switchToEth.value(_priceCost)(address(nToken));
                }
                if (msg.value > _priceCost) {
                    repayEth(address(msg.sender), msg.value.sub(_priceCost));
                }
                emit NowTokenPrice(tokenAddress,priceInfo.ethAmount, priceInfo.erc20Amount);
                return (priceInfo.ethAmount,priceInfo.erc20Amount, checkBlock);
            }
            
            /**
            * @dev Update and check the latest price-internal use
            * @param tokenAddress Token address
            * @return ethAmount ETH amount
            * @return erc20Amount Erc20 amount
            */
            function updateAndCheckPricePrivate(address tokenAddress) public view onlyOfferMain returns(uint256 ethAmount, uint256 erc20Amount) {
                mapping(uint256 => PriceInfo) storage priceInfoList = _tokenInfo[tokenAddress].priceInfoList;
                uint256 checkBlock = _tokenInfo[tokenAddress].latestOffer;
                while(checkBlock > 0 && (checkBlock >= block.number || priceInfoList[checkBlock].ethAmount == 0)) {
                    checkBlock = priceInfoList[checkBlock].frontBlock;
                }
                if (checkBlock == 0) {
                    return (0,0);
                }
                PriceInfo memory priceInfo = priceInfoList[checkBlock];
                return (priceInfo.ethAmount,priceInfo.erc20Amount);
            }
            
            /**
            * @dev Update and check the effective price list
            * @param tokenAddress Token address
            * @param num Number of prices to check
            * @return uint256[] price list
            */
            function updateAndCheckPriceList(address tokenAddress, uint256 num) public payable returns (uint256[] memory) {
                require(checkUseNestPrice(address(msg.sender)));
                mapping(uint256 => PriceInfo) storage priceInfoList = _tokenInfo[tokenAddress].priceInfoList;
                // Extract data
                uint256 length = num.mul(3);
                uint256 index = 0;
                uint256[] memory data = new uint256[](length);
                uint256 checkBlock = _tokenInfo[tokenAddress].latestOffer;
                while(index < length && checkBlock > 0){
                    if (checkBlock < block.number && priceInfoList[checkBlock].ethAmount != 0) {
                        // Add return data
                        data[index++] = priceInfoList[checkBlock].ethAmount;
                        data[index++] = priceInfoList[checkBlock].erc20Amount;
                        data[index++] = checkBlock;
                    }
                    checkBlock = priceInfoList[checkBlock].frontBlock;
                }
                require(length == data.length);
                // Allocation
                address nToken = _tokenMapping.checkTokenMapping(tokenAddress);
                if (nToken == address(0x0)) {
                    _abonus.switchToEth.value(_priceCost)(address(_nestToken));
                } else {
                    _abonus.switchToEth.value(_priceCost)(address(nToken));
                }
                if (msg.value > _priceCost) {
                    repayEth(address(msg.sender), msg.value.sub(_priceCost));
                }
                return data;
            }
            
            // Activate the price checking function
            function activation() public {
                _nestToken.safeTransferFrom(address(msg.sender), _destructionAddress, destructionAmount);
                _addressEffect[address(msg.sender)] = now.add(effectTime);
            }
            
            // Transfer ETH
            function repayEth(address accountAddress, uint256 asset) private {
                address payable addr = accountAddress.make_payable();
                addr.transfer(asset);
            }
            
            // Check block price - user account only
            function checkPriceForBlock(address tokenAddress, uint256 blockNum) public view returns (uint256 ethAmount, uint256 erc20Amount) {
                require(address(msg.sender) == address(tx.origin), "It can't be a contract");
                TokenInfo storage tokenInfo = _tokenInfo[tokenAddress];
                return (tokenInfo.priceInfoList[blockNum].ethAmount, tokenInfo.priceInfoList[blockNum].erc20Amount);
            }    
            
            // Check real-time price - user account only
            function checkPriceNow(address tokenAddress) public view returns (uint256 ethAmount, uint256 erc20Amount, uint256 blockNum) {
                require(address(msg.sender) == address(tx.origin), "It can't be a contract");
                mapping(uint256 => PriceInfo) storage priceInfoList = _tokenInfo[tokenAddress].priceInfoList;
                uint256 checkBlock = _tokenInfo[tokenAddress].latestOffer;
                while(checkBlock > 0 && (checkBlock >= block.number || priceInfoList[checkBlock].ethAmount == 0)) {
                    checkBlock = priceInfoList[checkBlock].frontBlock;
                }
                if (checkBlock == 0) {
                    return (0,0,0);
                }
                PriceInfo storage priceInfo = priceInfoList[checkBlock];
                return (priceInfo.ethAmount,priceInfo.erc20Amount, checkBlock);
            }
            
            // Check whether the price-checking functions can be called
            function checkUseNestPrice(address target) public view returns (bool) {
                if (!_blocklist[target] && _addressEffect[target] < now && _addressEffect[target] != 0) {
                    return true;
                } else {
                    return false;
                }
            }
            
            // Check whether the address is in the blocklist
            function checkBlocklist(address add) public view returns(bool) {
                return _blocklist[add];
            }
            
            // Check the amount of NEST to destroy to call prices
            function checkDestructionAmount() public view returns(uint256) {
                return destructionAmount;
            }
            
            // Check the waiting time to start calling prices
            function checkEffectTime() public view returns (uint256) {
                return effectTime;
            }
            
            // Check call price fee
            function checkPriceCost() public view returns (uint256) {
                return _priceCost;
            }
            
            // Modify the blocklist 
            function changeBlocklist(address add, bool isBlock) public onlyOwner {
                _blocklist[add] = isBlock;
            }
            
            // Amount of NEST to destroy to call price-checking functions
            function changeDestructionAmount(uint256 amount) public onlyOwner {
                destructionAmount = amount;
            }
            
            // Modify the waiting time to start calling prices
            function changeEffectTime(uint256 num) public onlyOwner {
                effectTime = num;
            }
            
            // Modify call price fee
            function changePriceCost(uint256 num) public onlyOwner {
                _priceCost = num;
            }
        
            // Offering contract only
            modifier onlyOfferMain(){
                require(_offerMainMapping[address(msg.sender)], "No authority");
                _;
            }
            
            // Vote administrators only
            modifier onlyOwner(){
                require(_voteFactory.checkOwners(msg.sender), "No authority");
                _;
            }
        }
        
        // Voting contract
        interface Nest_3_VoteFactory {
            // Check address
        	function checkAddress(string calldata name) external view returns (address contractAddress);
        	// Check whether administrator
        	function checkOwners(address man) external view returns (bool);
        }
        
        // NToken mapping contract
        interface Nest_NToken_TokenMapping {
            function checkTokenMapping(address token) external view returns (address);
        }
        
        // NEST offer main contract
        interface Nest_3_OfferMain {
            function checkTokenAllow(address token) external view returns(bool);
        }
        
        // Bonus pool contract
        interface Nest_3_Abonus {
            function switchToEth(address token) external payable;
        }
        
        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));
           }
        }
        
        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, "SafeERC20: decreased allowance below zero");
                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);
        }
        
        library Address {
            function isContract(address account) internal view returns (bool) {
                bytes32 codehash;
                bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
                assembly { codehash := extcodehash(account) }
                return (codehash != accountHash && codehash != 0x0);
            }
            function sendValue(address payable recipient, uint256 amount) internal {
                require(address(this).balance >= amount, "Address: insufficient balance");
                (bool success, ) = recipient.call.value(amount)("");
                require(success, "Address: unable to send value, recipient may have reverted");
            }
        }

        File 6 of 7: 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 7 of 7: 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;
            }
        }