NEST 预言机开发者调用文档

0 条评论 , 0 次修正,872 次阅读, 最后更新于 2020年07月13日

NEST 预言机调用价格

注意

  1. 合约中必须实现receive方法,用于接收回退ETH
receive() external payable
  1. 合约中使用价格合约地址必须通过投票合约查询,防止更换价格合约地址调用失效。
Nest_3_OfferPrice _offerPrice = Nest_3_OfferPrice(address(_voteFactory.checkAddress("nest.v3.offerPrice")));

3.每个token创建时收费标准是相同的,但是可能会通过配置修改,使用价格设置支付ETH时,建议一:使用大于使用量的ETH,多余的会回退给调用合约。建议二:去价格合约中查询对应token的收费标准,先计算好,再调用价格。

//  查看获取价格eth最少费用 
function checkPriceCostLeast(address tokenAddress) public view returns(uint256) {
    return _tokenInfo[tokenAddress].priceCostLeast;
}

//  查看获取价格eth最多费用 
function checkPriceCostMost(address tokenAddress) public view returns(uint256) {
    return _tokenInfo[tokenAddress].priceCostMost;
}

//  查看价格eth单条数据费用
function checkPriceCostSingle(address tokenAddress) public view returns(uint256) {
    return _tokenInfo[tokenAddress].priceCostSingle;
}

函数

激活预言机

调用价格前需要先激活调用权限

function activation() public

调用单个价格

输入属性 描述
tokenAddress 获取价格的erc20地址
输出属性 描述
ethAmount eth数量(所有报价eth数量和)
erc20Amount erc20数量(所有报价erc20数量和)
blockNum 价格所在区块
function updateAndCheckPriceNow(address tokenAddress) public payable returns(uint256 ethAmount, uint256 erc20Amount, uint256 blockNum)

调用历史价格

输入属性 描述
tokenAddress 获取价格的erc20地址
num 价格数量
输出属性 描述
uint256[] memory 价格数组

返回的数组是3的整数倍,3个数据为一个价格数据。分别对应,eth数量、erc20数量、价格区块号。

function updateAndCheckPriceList(address tokenAddress, uint256 num) public payable returns (uint256[] memory)

Demo

pragma solidity 0.6.0;

contract Nest_3_GetPrice {
    using SafeMath for uint256;
    using SafeERC20 for ERC20;

    // 投票合约
    Nest_3_VoteFactory _voteFactory;

    event price(uint256 ethAmount, uint256 tokenAmount, uint256 blockNum, uint256 ethMultiple, uint256 tokenForEth);
    event averagePrice(uint256 price);

    /**
     * @dev 初始化方法
     * @param voteFactory 投票合约
     */
    constructor (address voteFactory) public {
        _voteFactory = Nest_3_VoteFactory(address(voteFactory));
    }

    /**
     * @dev 获取单条价格
     * @param token 获取价格的 token 地址
     */
    function getSinglePrice(address token) public payable {
        // 考虑到未来升级,不排除升级价格合约的可能,必须使用投票合约查询价格合约地址。
        Nest_3_OfferPrice _offerPrice = Nest_3_OfferPrice(address(_voteFactory.checkAddress("nest.v3.offerPrice")));
        // 请求最新价格,返回 eth数量、token数量、价格区块号。费用暂定
        (uint256 ethAmount, uint256 tokenAmount, uint256 blockNum) = _offerPrice.updateAndCheckPriceNow.value(0.01 ether)(token);
        uint256 ethMultiple = ethAmount.div(1 ether);
        uint256 tokenForEth = tokenAmount.div(ethMultiple);
        // 如果支付价格的 eth 有剩余,需要处理
        // ........

        emit price(ethAmount, tokenAmount, blockNum, ethMultiple, tokenForEth);
    }

    /**
     * @dev 获取多条价格
     * @param token 获取价格的 token 地址
     * @param priceNum 获取价格的数量,从最新价格开始往后依次排序
     */
    function getBatchPrice(address token, uint256 priceNum) public payable {
        // 考虑到未来升级,不排除升级价格合约的可能,必须使用投票合约查询价格合约地址。
        Nest_3_OfferPrice _offerPrice = Nest_3_OfferPrice(address(_voteFactory.checkAddress("nest.v3.offerPrice")));
        /**
         * 返回的数组是3的整数倍,3个数据为一个价格数据
         * 分别对应,eth数量、token数量、价格区块号
         */
        uint256[] memory priceData = _offerPrice.updateAndCheckPriceList.value(0.1 ether)(token, priceNum);
        // 处理数据
        uint256 allTokenForEth = 0;
        uint256 priceDataNum = priceData.length.div(3);
        for (uint256 i = 0; i < priceData.length;) {
            uint256 ethMultiple = priceData[i].div(1 ether);
            uint256 tokenForEth = priceData[i.add(1)].div(ethMultiple);
            allTokenForEth = allTokenForEth.add(tokenForEth);
            i = i.add(3);
        }
        // 平均价格
        uint256 calculationPrice = allTokenForEth.div(priceDataNum);
        // 如果支付价格的 eth 有剩余,需要处理
        // ........


        emit averagePrice(calculationPrice);
    }

    /**
     * @dev 激活
     * @param nestAddress nestToken地址
     * @param nestAmount 激活销毁 Nest 数量
     */
    function activation(address nestAddress, uint256 nestAmount) public {
        // 考虑到未来升级,不排除升级价格合约的可能,必须使用投票合约查询价格合约地址。
        Nest_3_OfferPrice _offerPrice = Nest_3_OfferPrice(address(_voteFactory.checkAddress("nest.v3.offerPrice")));
        // 向价格合约授权 Nest,暂定数量为10万 
        ERC20(nestAddress).safeApprove(address(_offerPrice), nestAmount);
        // 激活
        _offerPrice.activation();
    }

    // 接收 eth 方法,必须实现
    receive() external payable {

    }

}

// 投票合约
interface Nest_3_VoteFactory {
    // 查询地址
    function checkAddress(string calldata name) external view returns (address contractAddress);
}

// 价格合约
interface Nest_3_OfferPrice {
    // 激活使用价格合约
    function activation() external;
    // 更新并查看最新价格
    function updateAndCheckPriceNow(address tokenAddress) external payable returns(uint256 ethAmount, uint256 erc20Amount, uint256 blockNum);
    // 更新并查看生效价格列表
    function updateAndCheckPriceList(address tokenAddress, uint256 num) external payable returns (uint256[] memory);
}


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