ETH Price: $1,915.24 (-3.68%)

Transaction Decoder

Block:
10756849 at Aug-29-2020 04:55:40 PM +UTC
Transaction Fee:
0.008258956992 ETH $15.82
Gas Used:
66,846 Gas / 123.552 Gwei

Emitted Events:

131 TetherToken.Transfer( from=[Receiver] Nest_3_OfferMain, to=0x21cD7c7AEEBbE898F18D03D1C540a0205682309b, value=4030800000 )
132 IBNEST.Transfer( from=[Receiver] Nest_3_OfferMain, to=0x21cD7c7AEEBbE898F18D03D1C540a0205682309b, value=1024000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x04abEdA2...c74ddC74C
0x21cD7c7A...05682309b 250.840395805922324122 Eth260.840395805922324122 Eth10
0x4ee14D79...8adFb53e6
58.172735746179984028 Eth
Nonce: 7387
58.164476789187984028 Eth
Nonce: 7388
0.008258956992
(Nanopool)
3,169.301385269270208066 Eth3,169.309644226262208066 Eth0.008258956992
0xc83E009c...Fc4D039F6
(NEST Protocol: Oracle ETH/USDT)
270 Eth260 Eth10
0xdAC17F95...13D831ec7

Execution Trace

Nest_3_OfferMain.turnOut( contractAddress=0x000000000000000000000000000000000001699F )
  • ETH 10 0x21cd7c7aeebbe898f18d03d1c540a0205682309b.CALL( )
  • TetherToken.transfer( _to=0x21cD7c7AEEBbE898F18D03D1C540a0205682309b, _value=4030800000 )
  • IBNEST.transfer( _to=0x21cD7c7AEEBbE898F18D03D1C540a0205682309b, _value=1024000000000000000000 ) => ( True )
    • IterableMapping.4c5e1cae( )
    • IterableMapping.4c5e1cae( )
    • IterableMapping.ab517b4f( )
    • IterableMapping.4c5e1cae( )
    • IterableMapping.ab517b4f( )
      File 1 of 4: Nest_3_OfferMain
      pragma solidity 0.6.0;
      
      /**
       * @title Offering contract
       * @dev Offering + take order + NEST allocation
       */
      contract Nest_3_OfferMain {
          using SafeMath for uint256;
          using address_make_payable for address;
          using SafeERC20 for ERC20;
          
          struct Nest_3_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_3_OfferPriceData [] _prices;                   //  Array used to save offers
      
          mapping(address => bool) _tokenAllow;               //  List of allowed mining token
          Nest_3_VoteFactory _voteFactory;                    //  Vote contract
          Nest_3_OfferPrice _offerPrice;                      //  Price contract
          Nest_3_MiningContract _miningContract;              //  Mining contract
          Nest_NodeAssignment _NNcontract;                    //  NestNode contract
          ERC20 _nestToken;                                   //  NestToken
          Nest_3_Abonus _abonus;                              //  Bonus pool
          address _coderAddress;                              //  Developer address
          uint256 _miningETH = 10;                            //  Offering mining fee ratio
          uint256 _tranEth = 1;                               //  Taker fee ratio
          uint256 _tranAddition = 2;                          //  Additional transaction multiple
          uint256 _coderAmount = 5;                           //  Developer ratio
          uint256 _NNAmount = 15;                             //  NestNode ratio
          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
          uint32 _blockLimit = 25;                            //  Block interval upper limit
          mapping(uint256 => uint256) _offerBlockEth;         //  Block offer fee
          mapping(uint256 => uint256) _offerBlockMining;      //  Block mining amount
          
          //  Log offering contract, token address, number of eth, number of erc20, number of continuous blocks, number of fees
          event OfferContractAddress(address contractAddress, address tokenAddress, uint256 ethAmount, uint256 erc20Amount, uint256 continued, uint256 serviceCharge);
          //  Log transaction, transaction initiator, transaction token address, number of transaction token, token address, number of token, traded offering contract address, traded user address
          event OfferTran(address tranSender, address tranToken, uint256 tranAmount,address otherToken, uint256 otherAmount, address tradedContract, address tradedOwner);        
          
           /**
          * @dev 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")));            
              _miningContract = Nest_3_MiningContract(address(voteFactoryMap.checkAddress("nest.v3.miningSave")));
              _abonus = Nest_3_Abonus(voteFactoryMap.checkAddress("nest.v3.abonus"));
              _nestToken = ERC20(voteFactoryMap.checkAddress("nest"));                                         
              _NNcontract = Nest_NodeAssignment(address(voteFactoryMap.checkAddress("nodeAssignment")));      
              _coderAddress = voteFactoryMap.checkAddress("nest.v3.coder");
              require(_nestToken.approve(address(_NNcontract), uint256(10000000000 ether)), "Authorization failed");
          }
          
           /**
          * @dev Reset voting contract
          * @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")));            
              _miningContract = Nest_3_MiningContract(address(voteFactoryMap.checkAddress("nest.v3.miningSave")));
              _abonus = Nest_3_Abonus(voteFactoryMap.checkAddress("nest.v3.abonus"));
              _nestToken = ERC20(voteFactoryMap.checkAddress("nest"));                                           
              _NNcontract = Nest_NodeAssignment(address(voteFactoryMap.checkAddress("nodeAssignment")));      
              _coderAddress = voteFactoryMap.checkAddress("nest.v3.coder");
              require(_nestToken.approve(address(_NNcontract), uint256(10000000000 ether)), "Authorization failed");
          }
          
          /**
          * @dev Offering mining
          * @param ethAmount Offering ETH amount 
          * @param erc20Amount Offering erc20 token amount
          * @param erc20Address Offering 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");
              require(_tokenAllow[erc20Address], "Token not allow");
              //  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, ethMining, isDeviate);
              //  Transfer in offer asset - erc20 to this contract
              ERC20(erc20Address).safeTransferFrom(address(msg.sender), address(this), erc20Amount);
              //  Mining
              uint256 miningAmount = _miningContract.oreDrawing();
              _abonus.switchToEth.value(ethMining)(address(_nestToken));
              if (miningAmount > 0) {
                  uint256 coder = miningAmount.mul(_coderAmount).div(100);
                  uint256 NN = miningAmount.mul(_NNAmount).div(100);
                  uint256 other = miningAmount.sub(coder).sub(NN);
                  _offerBlockMining[block.number] = other;
                  _NNcontract.bookKeeping(NN);   
                  if (coder > 0) {
                      _nestToken.safeTransfer(_coderAddress, coder);  
                  }
              }
              _offerBlockEth[block.number] = _offerBlockEth[block.number].add(ethMining);
          }
          
          /**
          * @dev Create offer
          * @param ethAmount Offering ETH amount
          * @param erc20Amount Offering erc20 amount
          * @param erc20Address Offering erc20 address
          * @param mining Offering mining fee (0 for takers)
          * @param isDeviate Whether the current price chain deviates
          */
          function createOffer(uint256 ethAmount, uint256 erc20Amount, address erc20Address, uint256 mining, bool isDeviate) 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_3_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));
          }
          
          /**
          * @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");
              // Get the offer data structure
              uint256 index = toIndex(contractAddress);
              Nest_3_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");
                  }
              }
              
              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 transaction handling fee");
              require(tranEthAmount % _offerSpan == 0, "Transaction size does not meet asset span");
              
              // 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, 0, isDeviate);
              // 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) {
                  _abonus.switchToEth.value(serviceCharge)(address(_nestToken));
              }
          }
          
          /**
          * @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");
              // Get the offer data structure
              uint256 index = toIndex(contractAddress);
              Nest_3_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");
                  }
              }
              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");
              
              // 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, 0, isDeviate);
              // 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) {
                  _abonus.switchToEth.value(serviceCharge)(address(_nestToken));
              }
          }
          
          /**
          * @dev Withdraw the assets, and settle the mining
          * @param contractAddress The offer address to withdraw
          */
          function turnOut(address contractAddress) public {
              require(address(msg.sender) == address(tx.origin), "It can't be a contract");
              uint256 index = toIndex(contractAddress);
              Nest_3_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(offerPriceData.owner, payErc);
                  
              }
              // Mining settlement
              if (offerPriceData.serviceCharge > 0) {
                  uint256 myMiningAmount = offerPriceData.serviceCharge.mul(_offerBlockMining[offerPriceData.blockNum]).div(_offerBlockEth[offerPriceData.blockNum]);
                  _nestToken.safeTransfer(offerPriceData.owner, myMiningAmount);
                  offerPriceData.serviceCharge = 0;
              }
              
          }
          
          // 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);
          }
          
          // View contract state
          function checkContractState(uint256 createBlock) public view returns (uint256) {
              if (block.number.sub(createBlock) > _blockLimit) {
                  return 1;
              }
              return 0;
          }
      
          // Compare the order price
          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;
          }
          
          // 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(uint32) {
              return _blockLimit;
          }
          
          // View offering mining fee ratio
          function checkMiningETH() public view returns (uint256) {
              return _miningETH;
          }
          
          // View whether the token is allowed to mine
          function checkTokenAllow(address token) public view returns(bool) {
              return _tokenAllow[token];
          }
          
          // View additional transaction multiple
          function checkTranAddition() public view returns(uint256) {
              return _tranAddition;
          }
          
          // View the development allocation ratio
          function checkCoderAmount() public view returns(uint256) {
              return _coderAmount;
          }
          
          // View the NestNode allocation ratio
          function checkNNAmount() public view returns(uint256) {
              return _NNAmount;
          }
          
          // View the least offering ETH 
          function checkleastEth() public view returns(uint256) {
              return _leastEth;
          }
          
          // View offering ETH span
          function checkOfferSpan() public view returns(uint256) {
              return _offerSpan;
          }
          
          // View the price deviation
          function checkDeviate() public view returns(uint256){
              return _deviate;
          }
          
          // View deviation from scale
          function checkDeviationFromScale() public view returns(uint256) {
              return _deviationFromScale;
          }
          
          // View block offer fee
          function checkOfferBlockEth(uint256 blockNum) public view returns(uint256) {
              return _offerBlockEth[blockNum];
          }
          
          // View taker order fee ratio
          function checkTranEth() public view returns (uint256) {
              return _tranEth;
          }
          
          // View block mining amount of user
          function checkOfferBlockMining(uint256 blockNum) public view returns(uint256) {
              return _offerBlockMining[blockNum];
          }
      
          // View offer mining amount
          function checkOfferMining(uint256 blockNum, uint256 serviceCharge) public view returns (uint256) {
              if (serviceCharge == 0) {
                  return 0;
              } else {
                  return _offerBlockMining[blockNum].mul(serviceCharge).div(_offerBlockEth[blockNum]);
              }
          }
          
          // Change offering mining fee ratio
          function changeMiningETH(uint256 num) public onlyOwner {
              _miningETH = num;
          }
          
          // Modify taker fee ratio
          function changeTranEth(uint256 num) public onlyOwner {
              _tranEth = num;
          }
          
          // Modify the upper limit of the block interval
          function changeBlockLimit(uint32 num) public onlyOwner {
              _blockLimit = num;
          }
          
          // Modify whether the token allows mining
          function changeTokenAllow(address token, bool allow) public onlyOwner {
              _tokenAllow[token] = allow;
          }
          
          // Modify additional transaction multiple
          function changeTranAddition(uint256 num) public onlyOwner {
              require(num > 0, "Parameter needs to be greater than 0");
              _tranAddition = num;
          }
          
          // Modify the initial allocation ratio
          function changeInitialRatio(uint256 coderNum, uint256 NNNum) public onlyOwner {
              require(coderNum.add(NNNum) <= 100, "User allocation ratio error");
              _coderAmount = coderNum;
              _NNAmount = NNNum;
          }
          
          // Modify the minimum offering ETH
          function changeLeastEth(uint256 num) public onlyOwner {
              require(num > 0);
              _leastEth = num;
          }
          
          //  Modify the offering ETH span
          function changeOfferSpan(uint256 num) public onlyOwner {
              require(num > 0);
              _offerSpan = num;
          }
          
          // Modify the price deviation
          function changekDeviate(uint256 num) public onlyOwner {
              _deviate = num;
          }
          
          // Modify the deviation from scale 
          function changeDeviationFromScale(uint256 num) public onlyOwner {
              _deviationFromScale = num;
          }
          
          /**
           * 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_3_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_3_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 and write it 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;
          }
          
          // Vote administrator only
          modifier onlyOwner(){
              require(_voteFactory.checkOwners(msg.sender), "No authority");
              _;
          }
      }
      
      // NestNode assignment contract
      interface Nest_NodeAssignment {
          function bookKeeping(uint256 amount) external;
      }
      
      // Mining pool logic
      interface Nest_3_MiningContract {
          // Offering mining
          function oreDrawing() external returns (uint256);
      }
      
      // 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);
      }
      
      // Price contract
      interface Nest_3_OfferPrice {
          function addPrice(uint256 ethAmount, uint256 tokenAmount, uint256 endBlock, address tokenAddress, address offerOwner) external;
          function changePrice(uint256 ethAmount, uint256 tokenAmount, address tokenAddress, uint256 endBlock) external;
          function updateAndCheckPricePrivate(address tokenAddress) external view returns(uint256 ethAmount, uint256 erc20Amount);
      }
      
      // 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 2 of 4: TetherToken
      pragma solidity ^0.4.17;
      
      /**
       * @title SafeMath
       * @dev Math operations with safety checks that throw on error
       */
      library SafeMath {
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) {
                  return 0;
              }
              uint256 c = a * b;
              assert(c / a == b);
              return c;
          }
      
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              // assert(b > 0); // Solidity automatically throws when dividing by 0
              uint256 c = a / b;
              // assert(a == b * c + a % b); // There is no case in which this doesn't hold
              return c;
          }
      
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              assert(b <= a);
              return a - b;
          }
      
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              assert(c >= a);
              return c;
          }
      }
      
      /**
       * @title Ownable
       * @dev The Ownable contract has an owner address, and provides basic authorization control
       * functions, this simplifies the implementation of "user permissions".
       */
      contract Ownable {
          address public owner;
      
          /**
            * @dev The Ownable constructor sets the original `owner` of the contract to the sender
            * account.
            */
          function Ownable() public {
              owner = msg.sender;
          }
      
          /**
            * @dev Throws if called by any account other than the owner.
            */
          modifier onlyOwner() {
              require(msg.sender == owner);
              _;
          }
      
          /**
          * @dev Allows the current owner to transfer control of the contract to a newOwner.
          * @param newOwner The address to transfer ownership to.
          */
          function transferOwnership(address newOwner) public onlyOwner {
              if (newOwner != address(0)) {
                  owner = newOwner;
              }
          }
      
      }
      
      /**
       * @title ERC20Basic
       * @dev Simpler version of ERC20 interface
       * @dev see https://github.com/ethereum/EIPs/issues/20
       */
      contract ERC20Basic {
          uint public _totalSupply;
          function totalSupply() public constant returns (uint);
          function balanceOf(address who) public constant returns (uint);
          function transfer(address to, uint value) public;
          event Transfer(address indexed from, address indexed to, uint value);
      }
      
      /**
       * @title ERC20 interface
       * @dev see https://github.com/ethereum/EIPs/issues/20
       */
      contract ERC20 is ERC20Basic {
          function allowance(address owner, address spender) public constant returns (uint);
          function transferFrom(address from, address to, uint value) public;
          function approve(address spender, uint value) public;
          event Approval(address indexed owner, address indexed spender, uint value);
      }
      
      /**
       * @title Basic token
       * @dev Basic version of StandardToken, with no allowances.
       */
      contract BasicToken is Ownable, ERC20Basic {
          using SafeMath for uint;
      
          mapping(address => uint) public balances;
      
          // additional variables for use if transaction fees ever became necessary
          uint public basisPointsRate = 0;
          uint public maximumFee = 0;
      
          /**
          * @dev Fix for the ERC20 short address attack.
          */
          modifier onlyPayloadSize(uint size) {
              require(!(msg.data.length < size + 4));
              _;
          }
      
          /**
          * @dev transfer token for a specified address
          * @param _to The address to transfer to.
          * @param _value The amount to be transferred.
          */
          function transfer(address _to, uint _value) public onlyPayloadSize(2 * 32) {
              uint fee = (_value.mul(basisPointsRate)).div(10000);
              if (fee > maximumFee) {
                  fee = maximumFee;
              }
              uint sendAmount = _value.sub(fee);
              balances[msg.sender] = balances[msg.sender].sub(_value);
              balances[_to] = balances[_to].add(sendAmount);
              if (fee > 0) {
                  balances[owner] = balances[owner].add(fee);
                  Transfer(msg.sender, owner, fee);
              }
              Transfer(msg.sender, _to, sendAmount);
          }
      
          /**
          * @dev Gets the balance of the specified address.
          * @param _owner The address to query the the balance of.
          * @return An uint representing the amount owned by the passed address.
          */
          function balanceOf(address _owner) public constant returns (uint balance) {
              return balances[_owner];
          }
      
      }
      
      /**
       * @title Standard ERC20 token
       *
       * @dev Implementation of the basic standard token.
       * @dev https://github.com/ethereum/EIPs/issues/20
       * @dev Based oncode by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
       */
      contract StandardToken is BasicToken, ERC20 {
      
          mapping (address => mapping (address => uint)) public allowed;
      
          uint public constant MAX_UINT = 2**256 - 1;
      
          /**
          * @dev Transfer tokens from one address to another
          * @param _from address The address which you want to send tokens from
          * @param _to address The address which you want to transfer to
          * @param _value uint the amount of tokens to be transferred
          */
          function transferFrom(address _from, address _to, uint _value) public onlyPayloadSize(3 * 32) {
              var _allowance = allowed[_from][msg.sender];
      
              // Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
              // if (_value > _allowance) throw;
      
              uint fee = (_value.mul(basisPointsRate)).div(10000);
              if (fee > maximumFee) {
                  fee = maximumFee;
              }
              if (_allowance < MAX_UINT) {
                  allowed[_from][msg.sender] = _allowance.sub(_value);
              }
              uint sendAmount = _value.sub(fee);
              balances[_from] = balances[_from].sub(_value);
              balances[_to] = balances[_to].add(sendAmount);
              if (fee > 0) {
                  balances[owner] = balances[owner].add(fee);
                  Transfer(_from, owner, fee);
              }
              Transfer(_from, _to, sendAmount);
          }
      
          /**
          * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
          * @param _spender The address which will spend the funds.
          * @param _value The amount of tokens to be spent.
          */
          function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
      
              // To change the approve amount you first have to reduce the addresses`
              //  allowance to zero by calling `approve(_spender, 0)` if it is not
              //  already 0 to mitigate the race condition described here:
              //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
              require(!((_value != 0) && (allowed[msg.sender][_spender] != 0)));
      
              allowed[msg.sender][_spender] = _value;
              Approval(msg.sender, _spender, _value);
          }
      
          /**
          * @dev Function to check the amount of tokens than an owner allowed to a spender.
          * @param _owner address The address which owns the funds.
          * @param _spender address The address which will spend the funds.
          * @return A uint specifying the amount of tokens still available for the spender.
          */
          function allowance(address _owner, address _spender) public constant returns (uint remaining) {
              return allowed[_owner][_spender];
          }
      
      }
      
      
      /**
       * @title Pausable
       * @dev Base contract which allows children to implement an emergency stop mechanism.
       */
      contract Pausable is Ownable {
        event Pause();
        event Unpause();
      
        bool public paused = false;
      
      
        /**
         * @dev Modifier to make a function callable only when the contract is not paused.
         */
        modifier whenNotPaused() {
          require(!paused);
          _;
        }
      
        /**
         * @dev Modifier to make a function callable only when the contract is paused.
         */
        modifier whenPaused() {
          require(paused);
          _;
        }
      
        /**
         * @dev called by the owner to pause, triggers stopped state
         */
        function pause() onlyOwner whenNotPaused public {
          paused = true;
          Pause();
        }
      
        /**
         * @dev called by the owner to unpause, returns to normal state
         */
        function unpause() onlyOwner whenPaused public {
          paused = false;
          Unpause();
        }
      }
      
      contract BlackList is Ownable, BasicToken {
      
          /////// Getters to allow the same blacklist to be used also by other contracts (including upgraded Tether) ///////
          function getBlackListStatus(address _maker) external constant returns (bool) {
              return isBlackListed[_maker];
          }
      
          function getOwner() external constant returns (address) {
              return owner;
          }
      
          mapping (address => bool) public isBlackListed;
          
          function addBlackList (address _evilUser) public onlyOwner {
              isBlackListed[_evilUser] = true;
              AddedBlackList(_evilUser);
          }
      
          function removeBlackList (address _clearedUser) public onlyOwner {
              isBlackListed[_clearedUser] = false;
              RemovedBlackList(_clearedUser);
          }
      
          function destroyBlackFunds (address _blackListedUser) public onlyOwner {
              require(isBlackListed[_blackListedUser]);
              uint dirtyFunds = balanceOf(_blackListedUser);
              balances[_blackListedUser] = 0;
              _totalSupply -= dirtyFunds;
              DestroyedBlackFunds(_blackListedUser, dirtyFunds);
          }
      
          event DestroyedBlackFunds(address _blackListedUser, uint _balance);
      
          event AddedBlackList(address _user);
      
          event RemovedBlackList(address _user);
      
      }
      
      contract UpgradedStandardToken is StandardToken{
          // those methods are called by the legacy contract
          // and they must ensure msg.sender to be the contract address
          function transferByLegacy(address from, address to, uint value) public;
          function transferFromByLegacy(address sender, address from, address spender, uint value) public;
          function approveByLegacy(address from, address spender, uint value) public;
      }
      
      contract TetherToken is Pausable, StandardToken, BlackList {
      
          string public name;
          string public symbol;
          uint public decimals;
          address public upgradedAddress;
          bool public deprecated;
      
          //  The contract can be initialized with a number of tokens
          //  All the tokens are deposited to the owner address
          //
          // @param _balance Initial supply of the contract
          // @param _name Token Name
          // @param _symbol Token symbol
          // @param _decimals Token decimals
          function TetherToken(uint _initialSupply, string _name, string _symbol, uint _decimals) public {
              _totalSupply = _initialSupply;
              name = _name;
              symbol = _symbol;
              decimals = _decimals;
              balances[owner] = _initialSupply;
              deprecated = false;
          }
      
          // Forward ERC20 methods to upgraded contract if this one is deprecated
          function transfer(address _to, uint _value) public whenNotPaused {
              require(!isBlackListed[msg.sender]);
              if (deprecated) {
                  return UpgradedStandardToken(upgradedAddress).transferByLegacy(msg.sender, _to, _value);
              } else {
                  return super.transfer(_to, _value);
              }
          }
      
          // Forward ERC20 methods to upgraded contract if this one is deprecated
          function transferFrom(address _from, address _to, uint _value) public whenNotPaused {
              require(!isBlackListed[_from]);
              if (deprecated) {
                  return UpgradedStandardToken(upgradedAddress).transferFromByLegacy(msg.sender, _from, _to, _value);
              } else {
                  return super.transferFrom(_from, _to, _value);
              }
          }
      
          // Forward ERC20 methods to upgraded contract if this one is deprecated
          function balanceOf(address who) public constant returns (uint) {
              if (deprecated) {
                  return UpgradedStandardToken(upgradedAddress).balanceOf(who);
              } else {
                  return super.balanceOf(who);
              }
          }
      
          // Forward ERC20 methods to upgraded contract if this one is deprecated
          function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
              if (deprecated) {
                  return UpgradedStandardToken(upgradedAddress).approveByLegacy(msg.sender, _spender, _value);
              } else {
                  return super.approve(_spender, _value);
              }
          }
      
          // Forward ERC20 methods to upgraded contract if this one is deprecated
          function allowance(address _owner, address _spender) public constant returns (uint remaining) {
              if (deprecated) {
                  return StandardToken(upgradedAddress).allowance(_owner, _spender);
              } else {
                  return super.allowance(_owner, _spender);
              }
          }
      
          // deprecate current contract in favour of a new one
          function deprecate(address _upgradedAddress) public onlyOwner {
              deprecated = true;
              upgradedAddress = _upgradedAddress;
              Deprecate(_upgradedAddress);
          }
      
          // deprecate current contract if favour of a new one
          function totalSupply() public constant returns (uint) {
              if (deprecated) {
                  return StandardToken(upgradedAddress).totalSupply();
              } else {
                  return _totalSupply;
              }
          }
      
          // Issue a new amount of tokens
          // these tokens are deposited into the owner address
          //
          // @param _amount Number of tokens to be issued
          function issue(uint amount) public onlyOwner {
              require(_totalSupply + amount > _totalSupply);
              require(balances[owner] + amount > balances[owner]);
      
              balances[owner] += amount;
              _totalSupply += amount;
              Issue(amount);
          }
      
          // Redeem tokens.
          // These tokens are withdrawn from the owner address
          // if the balance must be enough to cover the redeem
          // or the call will fail.
          // @param _amount Number of tokens to be issued
          function redeem(uint amount) public onlyOwner {
              require(_totalSupply >= amount);
              require(balances[owner] >= amount);
      
              _totalSupply -= amount;
              balances[owner] -= amount;
              Redeem(amount);
          }
      
          function setParams(uint newBasisPoints, uint newMaxFee) public onlyOwner {
              // Ensure transparency by hardcoding limit beyond which fees can never be added
              require(newBasisPoints < 20);
              require(newMaxFee < 50);
      
              basisPointsRate = newBasisPoints;
              maximumFee = newMaxFee.mul(10**decimals);
      
              Params(basisPointsRate, maximumFee);
          }
      
          // Called when new token are issued
          event Issue(uint amount);
      
          // Called when tokens are redeemed
          event Redeem(uint amount);
      
          // Called when contract is deprecated
          event Deprecate(address newAddress);
      
          // Called if contract ever adds fees
          event Params(uint feeBasisPoints, uint maxFee);
      }

      File 3 of 4: IBNEST
      pragma solidity ^0.5.1;
      
      library IterableMapping {
        struct itmap
        {
          mapping(address => IndexValue) data;
          KeyFlag[] keys;
          uint size;
        }
        struct IndexValue { uint keyIndex; uint value; }
        struct KeyFlag { address key; bool deleted; }
        function insert(itmap storage self, address key, uint value) public returns (bool replaced)
        {
          uint keyIndex = self.data[key].keyIndex;
          self.data[key].value = value;
          if (keyIndex > 0)
            return true;
          else
          {
            keyIndex = self.keys.length++;
            self.data[key].keyIndex = keyIndex + 1;
            self.keys[keyIndex].key = key;
            self.size++;
            return false;
          }
        }
        function remove(itmap storage self, address key) public returns (bool success)
        {
          uint keyIndex = self.data[key].keyIndex;
          if (keyIndex == 0)
            return false;
          delete self.data[key];
          self.keys[keyIndex - 1].deleted = true;
          self.size --;
        }
        function contains(itmap storage self, address key) public view returns (bool)
        {
          return self.data[key].keyIndex > 0;
        }
        function iterate_start(itmap storage self) public view returns (uint keyIndex)
        {
          return iterate_next(self, uint(-1));
        }
        function iterate_valid(itmap storage self, uint keyIndex) public view returns (bool)
        {
          return keyIndex < self.keys.length;
        }
        function iterate_next(itmap storage self, uint keyIndex) public view returns (uint r_keyIndex)
        {
          keyIndex++;
          while (keyIndex < self.keys.length && self.keys[keyIndex].deleted)
            keyIndex++;
          return keyIndex;
        }
        function iterate_get(itmap storage self, uint keyIndex) public view returns (address key, uint value)
        {
          key = self.keys[keyIndex].key;
          value = self.data[key].value;
        }
        function iterate_getValue(itmap storage self, address key) public view returns (uint value) {
            return self.data[key].value;
        }
      }
      
      /**
       * @title SafeMath
       * @dev Math operations with safety checks that throw on error
       */
      library SafeMath {
      
        /**
        * @dev Multiplies two numbers, throws on overflow.
        */
        function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
          // Gas optimization: this is cheaper than asserting 'a' not being zero, but the
          // benefit is lost if 'b' is also tested.
          // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
          if (_a == 0) {
            return 0;
          }
      
          c = _a * _b;
          assert(c / _a == _b);
          return c;
        }
      
        /**
        * @dev Integer division of two numbers, truncating the quotient.
        */
        function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
          assert(_b > 0); // Solidity automatically throws when dividing by 0
          uint256 c = _a / _b;
          assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
          return _a / _b;
        }
      
        /**
        * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
        */
        function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
          assert(_b <= _a);
          return _a - _b;
        }
      
        /**
        * @dev Adds two numbers, throws on overflow.
        */
        function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
          c = _a + _b;
          assert(c >= _a);
          return c;
        }
      }
      
      /**
       * @title ERC20Basic
       * @dev Simpler version of ERC20 interface
       * See https://github.com/ethereum/EIPs/issues/179
       */
      contract ERC20Basic {
        function totalSupply() public view returns (uint256);
        function balanceOf(address _who) public view returns (uint256);
        function transfer(address _to, uint256 _value) public returns (bool);
        event Transfer(address indexed from, address indexed to, uint256 value);
      }
      
      
      /**
       * @title Basic token
       * @dev Basic version of StandardToken, with no allowances.
       */
      contract BasicToken is ERC20Basic {
        using SafeMath for uint256;
        IterableMapping.itmap balances;
      
        uint256 internal totalSupply_;
      
        /**
        * @dev Total number of tokens in existence
        */
        function totalSupply() public view returns (uint256) {
          return totalSupply_;
        }
      
        /**
        * @dev Transfer token for a specified address
        * @param _to The address to transfer to.
        * @param _value The amount to be transferred.
        */
        function transfer(address _to, uint256 _value) public returns (bool) {
            
          require(_value <= IterableMapping.iterate_getValue(balances, msg.sender));
          require(_to != address(0));
          
          IterableMapping.insert(balances, msg.sender, IterableMapping.iterate_getValue(balances, msg.sender).sub(_value));
          IterableMapping.insert(balances, _to, IterableMapping.iterate_getValue(balances, _to).add(_value));
          emit Transfer(msg.sender, _to, _value);
          return true;
        }
      
        /**
        * @dev Gets the balance of the specified address.
        * @param _owner The address to query the the balance of.
        * @return An uint256 representing the amount owned by the passed address.
        */
        function balanceOf(address _owner) public view returns (uint256) {
            return IterableMapping.iterate_getValue(balances, _owner);
        }
      
      }
      
      
      
      /**
       * @title ERC20 interface
       * @dev see https://github.com/ethereum/EIPs/issues/20
       */
      contract ERC20 is ERC20Basic {
        function allowance(address _owner, address _spender)
          public view returns (uint256);
      
        function transferFrom(address _from, address _to, uint256 _value)
          public returns (bool);
      
        function approve(address _spender, uint256 _value) public returns (bool);
        event Approval(
          address indexed owner,
          address indexed spender,
          uint256 value
        );
      }
      
      /**
       * @title Standard ERC20 token
       *
       * @dev Implementation of the basic standard token.
       * https://github.com/ethereum/EIPs/issues/20
       * Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
       */
      contract StandardToken is ERC20, BasicToken {
      
        mapping (address => mapping (address => uint256)) internal allowed;
      
      
        /**
         * @dev Transfer tokens from one address to another
         * @param _from address The address which you want to send tokens from
         * @param _to address The address which you want to transfer to
         * @param _value uint256 the amount of tokens to be transferred
         */
        function transferFrom(
          address _from,
          address _to,
          uint256 _value
        )
          public
          returns (bool)
        {
            
          require(_value <= IterableMapping.iterate_getValue(balances, _from));
      
          require(_value <= allowed[_from][msg.sender]);
          require(_to != address(0));
      
          IterableMapping.insert(balances, _from, IterableMapping.iterate_getValue(balances, _from).sub(_value));
          IterableMapping.insert(balances, _to, IterableMapping.iterate_getValue(balances, _to).add(_value));
      
          allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
          emit Transfer(_from, _to, _value);
          return true;
        }
      
        /**
         * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
         * Beware that changing an allowance with this method brings the risk that someone may use both the old
         * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
         * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
         * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
         * @param _spender The address which will spend the funds.
         * @param _value The amount of tokens to be spent.
         */
        function approve(address _spender, uint256 _value) public returns (bool) {
          allowed[msg.sender][_spender] = _value;
          emit Approval(msg.sender, _spender, _value);
          return true;
        }
      
        /**
         * @dev Function to check the amount of tokens that an owner allowed to a spender.
         * @param _owner address The address which owns the funds.
         * @param _spender address The address which will spend the funds.
         * @return A uint256 specifying the amount of tokens still available for the spender.
         */
        function allowance(
          address _owner,
          address _spender
         )
          public
          view
          returns (uint256)
        {
          return allowed[_owner][_spender];
        }
      
        /**
         * @dev Increase the amount of tokens that an owner allowed to a spender.
         * approve should be called when allowed[_spender] == 0. To increment
         * allowed value is better to use this function to avoid 2 calls (and wait until
         * the first transaction is mined)
         * From MonolithDAO Token.sol
         * @param _spender The address which will spend the funds.
         * @param _addedValue The amount of tokens to increase the allowance by.
         */
        function increaseApproval(
          address _spender,
          uint256 _addedValue
        )
          public
          returns (bool)
        {
          allowed[msg.sender][_spender] = (
            allowed[msg.sender][_spender].add(_addedValue));
          emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
          return true;
        }
      
        /**
         * @dev Decrease the amount of tokens that an owner allowed to a spender.
         * approve should be called when allowed[_spender] == 0. To decrement
         * allowed value is better to use this function to avoid 2 calls (and wait until
         * the first transaction is mined)
         * From MonolithDAO Token.sol
         * @param _spender The address which will spend the funds.
         * @param _subtractedValue The amount of tokens to decrease the allowance by.
         */
        function decreaseApproval(
          address _spender,
          uint256 _subtractedValue
        )
          public
          returns (bool)
        {
          uint256 oldValue = allowed[msg.sender][_spender];
          if (_subtractedValue >= oldValue) {
            allowed[msg.sender][_spender] = 0;
          } else {
            allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
          }
          emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
          return true;
        }
      
      }
      
      contract IBNEST is StandardToken {
          
          string public name = "NEST";
          string public symbol = "NEST";
          uint8 public decimals = 18;
          uint256 public INITIAL_SUPPLY = 10000000000 ether;
      
          constructor () public {
          	totalSupply_ = INITIAL_SUPPLY;
          	IterableMapping.insert(balances, tx.origin, INITIAL_SUPPLY);
          }
          
          function balancesStart() public view returns(uint256) {
              return IterableMapping.iterate_start(balances);
          }
          
          function balancesGetBool(uint256 num) public view returns(bool){
              return IterableMapping.iterate_valid(balances, num);
          }
          
          function balancesGetNext(uint256 num) public view returns(uint256) {
              return IterableMapping.iterate_next(balances, num);
          }
          
          function balancesGetValue(uint256 num) public view returns(address, uint256) {
              address key;                           
              uint256 value;                         
              (key, value) = IterableMapping.iterate_get(balances, num);
              return (key, value);
          }
          
      }

      File 4 of 4: IterableMapping
      library IterableMapping {
        struct itmap
        {
          mapping(address => IndexValue) data;
          KeyFlag[] keys;
          uint size;
        }
        struct IndexValue { uint keyIndex; uint value; }
        struct KeyFlag { address key; bool deleted; }
        function insert(itmap storage self, address key, uint value) public returns (bool replaced)
        {
          uint keyIndex = self.data[key].keyIndex;
          self.data[key].value = value;
          if (keyIndex > 0)
            return true;
          else
          {
            keyIndex = self.keys.length++;
            self.data[key].keyIndex = keyIndex + 1;
            self.keys[keyIndex].key = key;
            self.size++;
            return false;
          }
        }
        function remove(itmap storage self, address key) public returns (bool success)
        {
          uint keyIndex = self.data[key].keyIndex;
          if (keyIndex == 0)
            return false;
          delete self.data[key];
          self.keys[keyIndex - 1].deleted = true;
          self.size --;
        }
        function contains(itmap storage self, address key) public view returns (bool)
        {
          return self.data[key].keyIndex > 0;
        }
        function iterate_start(itmap storage self) public view returns (uint keyIndex)
        {
          return iterate_next(self, uint(-1));
        }
        function iterate_valid(itmap storage self, uint keyIndex) public view returns (bool)
        {
          return keyIndex < self.keys.length;
        }
        function iterate_next(itmap storage self, uint keyIndex) public view returns (uint r_keyIndex)
        {
          keyIndex++;
          while (keyIndex < self.keys.length && self.keys[keyIndex].deleted)
            keyIndex++;
          return keyIndex;
        }
        function iterate_get(itmap storage self, uint keyIndex) public view returns (address key, uint value)
        {
          key = self.keys[keyIndex].key;
          value = self.data[key].value;
        }
        function iterate_getValue(itmap storage self, address key) public view returns (uint value) {
            return self.data[key].value;
        }
      }