DeFi developers: How to call NEST oracle price data

avatar
NEST爱好者
3 years ago
This article is approximately 1289 words,and reading the entire article takes about 2 minutes
NEST ecological developer experience sharing, teaching you to easily call NEST oracle price data.

introduce

introduce

first level title

white paper:https://nestprotocol.org/doc/zhnestwhitepaper.pdf

GitHub:https://github.com/NEST-Protocol

NEST Protocol:https://nestprotocol.org/

Try to get the on-chain price

understand the mechanism

The NEST oracle machine generates prices in units of blocks. If there is no price in the block, the most recent block price will be used.

The block price is generated by means of quotes, and if there are multiple quotes in a block, the weighted average is used.

Each quotation has a verification time of 25 blocks (take order). If no order is taken within the verification time, it means that the market approves the quotation, and the price will take effect 25 blocks after the quotation block.

NEST oracle price contract sol file

GitHub:

https://github.com/NEST-Protocol/NEST-oracle-V3/blob/master/NestOffer/Nest_3_OfferPrice.sol

code analysis

text

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;
       }
   }

This method is limited to only the quote contract that can be called to ensure that the data source of the price data added to the price contract is correct.

Input parameters                 describe

ethAmount quote ETH amount

tokenAmount Quotation ERC20 Token quantity

endBlock price effective block number

tokenAddress ERC20 Token contract address of quotation

offerOwner Offeror wallet address

PriceInfo storage priceInfo = tokenInfo.priceInfoList[endBlock];
priceInfo.ethAmount = priceInfo.ethAmount.add(ethAmount);
priceInfo.erc20Amount = priceInfo.erc20Amount.add(tokenAmount);

These three lines of code implement weighted averaging within the same block.

Modify the 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);
   }

It is also restricted that only the Quotation Contract has permission to call. Only after the taker operation is triggered, the price in the corresponding effective block will be modified, and the quotation quantity at the time of adding price will be subtracted according to the scale of taker.

Input parameters            describe

ethAmount Taker amount of ETH

tokenAmount Taker ERC20 Quantity

tokenAddress Quotation ERC20 address

endBlock price effective block number

Get Price (Latest)

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);
   }


Input parameter Description

tokenAddress ERC20 Token contract address

Output parameter Description

ethAmount ETH amount

erc20Amount ERC20 Token quantity

blockNum effective price block

require(checkUseNestPrice(address(msg.sender)));

Check for permission to use NEST prices.

mapping(uint256 => PriceInfo) storage priceInfoList = _tokenInfo[tokenAddress].priceInfoList;

Get the price data source of the corresponding Token.

uint256 checkBlock = _tokenInfo[tokenAddress].latestOffer;
while(checkBlock > 0 && (checkBlock >= block.number || priceInfoList[checkBlock].ethAmount == 0)) {
checkBlock = priceInfoList[checkBlock].frontBlock;
}

To explain the judgment of the while loop, you need to work backwards from the latest quotation block to find the block number (checkBlock) where the price data that is currently in effect and has not been taken.

require(checkBlock != 0);

This judgment is a personal guess to prevent some tokens from quoting at the beginning, and no effective price has been generated yet, and because calling the price requires payment. Therefore, restrictions are added. If the block number of the effective price is not found, the transaction will directly fail.

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));
       }

This part of the code distributes the oracle fee paid by the caller to the corresponding revenue pool. Excess charges are refunded to the caller.

Get price off-chain (latest price)

// 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 cant 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);
   }

The principle is the same as the previous method. The difference is that contract calls are prohibited and no payment is required. It should be used to check prices for off-chain applications.

Activate calling privileges

function activation() public {
       _nestToken.safeTransferFrom(address(msg.sender), _destructionAddress, destructionAmount);
       _addressEffect[address(msg.sender)] = now.add(effectTime);
   }

official document

DEMO

official document

/**
    * @dev Get a single price
    * @param token Token address of the price
    */
   function getSinglePrice(address token) public payable {
       // In consideration of future upgrades, the possibility of upgrading the price contract is not ruled out, and the voting contract must be used to query the price contract address.
       Nest_3_OfferPrice _offerPrice = Nest_3_OfferPrice(address(_voteFactory.checkAddress("nest.v3.offerPrice")));
       // Request the latest price, return the eth quantity, token quantity, and effective price block number. Tentative fee.
       (uint256 ethAmount, uint256 tokenAmount, uint256 blockNum) = _offerPrice.updateAndCheckPriceNow.value(0.001 ether)(token);
       uint256 ethMultiple = ethAmount.div(1 ether);
       uint256 tokenForEth = tokenAmount.div(ethMultiple);
       // If the eth paid for the price is left, it needs to be processed.
       // ........
       
       emit price(ethAmount, tokenAmount, blockNum, ethMultiple, tokenForEth);
   }
   
   /**
    * @dev Get multiple prices
    * @param token The token address of the price
    * @param priceNum Get the number of prices, sorted from the latest price
    */
   function getBatchPrice(address token, uint256 priceNum) public payable {
       // In consideration of future upgrades, the possibility of upgrading the price contract is not ruled out, and the voting contract must be used to query the price contract address.
       Nest_3_OfferPrice _offerPrice = Nest_3_OfferPrice(address(_voteFactory.checkAddress("nest.v3.offerPrice")));
       /**
        * The returned array is an integer multiple of 3, 3 data is a price data.
        * Corresponding respectively, eth quantity, token quantity, effective price block number.
        */
       uint256[] memory priceData = _offerPrice.updateAndCheckPriceList.value(0.01 ether)(token, priceNum);
       // Data processing
       uint256 allTokenForEth = 0;
       uint256 priceDataNum = priceData.length.div(3);
       for (uint256 i = 0; i 0) TransferHelper.safeTransferETH(msg.sender, oracleFeeChange);
       return (_rawPriceList[0], _rawPriceList[1], _rawPriceList[2]);
       // return (K_EXPECTED_VALUE, _rawPriceList[0], _rawPriceList[1], _rawPriceList[2], KInfoMap[token][2]);
   }

NEST Developer Communication:https://t.me/nestdevs(Revenue collection, oracle price call, front-end access and other development exchanges)

Original article, author:NEST爱好者。Reprint/Content Collaboration/For Reporting, Please Contact report@odaily.email;Illegal reprinting must be punished by law.

ODAILY reminds readers to establish correct monetary and investment concepts, rationally view blockchain, and effectively improve risk awareness; We can actively report and report any illegal or criminal clues discovered to relevant departments.

Recommended Reading
Editor’s Picks