chainlink喂价讲解

基本可以了解喂价服务了。

data feed(喂价)

业务流程

数据提供商收集数据源,chainlink 节点接收数据,在chainlink的分布式网络进行共识,之后再输入数据给到专门部署再区块链上的chainlink合约,最后再将数据传给用户的智能合约。

具体流程

chainlink在链上有两个合约,一个是代理合约(Proxy),另一个是聚合合约(Aggregator),我们用户使用的合约相当于是消费合约,我们先与代理合约进行交互,之后代理合约会与聚合合约交互,聚合合约从多个预言机节点收集数据,并通过特定的算法(如中位数算法)对数据进行聚合,以生成最终的可信数据,在返还给链上的代理合约,最后再传给消费合约

调用的chainlink接口

AggregatorV3Interface

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// solhint-disable-next-line interface-starts-with-i
interface AggregatorV3Interface {
  function decimals() external view returns (uint8);

  function description() external view returns (string memory);

  function version() external view returns (uint256);

  function getRoundData(
    uint80 _roundId
  ) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);

  function latestRoundData()
    external
    view
    returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}

上述变量的含义

这个函数签名的返回类型是 (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound),每个变量有特定的意义。让我们逐个分析这些变量的含义:

  1. roundId (uint80)
  • 含义:这是当前价格更新的“轮次ID”(Round ID)。
  • 解释:Chainlink 预言机是通过多轮次的方式来聚合数据的,每一轮都会有一个唯一的 roundId。这个 roundId 用于标识这是第几轮价格更新或报告。
  • 用途:通过 roundId,你可以知道当前的价格数据是哪一轮生成的。
  1. answer (int256)
  • 含义:这是预言机返回的实际答案,即你请求的数据结果。
  • 解释:对于价格预言机来说,answer 通常是某种资产的价格,例如 ETH/USD 或 BTC/USD 的价格。
  • 类型为 int256 是因为价格可能为负数(尽管在实际使用中很少见)。例如,它可以用于某些负值的经济数据。
  1. startedAt (uint256)
  • 含义:这是当前这一轮价格更新的启动时间。
  • 解释startedAt 代表这一轮价格数据采集的开始时间,通常是 UNIX 时间戳(即从1970年1月1日以来的秒数)。
  • 用途:通过这个时间戳,你可以知道这一轮价格数据什么时候开始聚合的。
  1. updatedAt (uint256)
  • 含义:这是当前价格更新的时间戳。
  • 解释updatedAt 代表预言机在这一轮价格更新的确切时间,也是 UNIX 时间戳格式。
  • 用途:可以用于追踪价格数据的最新更新时间,判断数据是否及时。
  1. answeredInRound (uint80)
  • 含义:这是价格数据成功报告的轮次ID。
  • 解释:这表示在哪一轮数据收集的最终答案是有效的。如果 answeredInRound 小于 roundId,则表明当前轮次的结果还没有最终确定或回答可能是来自于前几轮。
  • 用途:用来判断当前轮次的 answer 是在哪一轮被有效报告的,这可以帮助你验证数据的准确性。

查询数据

// SPDX-License-Identifier: MIT 
import "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
pragma solidity ^0.8.7;

contract FeedData{  
  AggregatorV3Interface private priceFeed;
  constructor(){
    priceFeed = AggregatorV3Interface(0x5fb1616F78dA7aFC9FF79e0371741a747D2a7F22);
  }

  function getLatestPrice() public view returns (int256) {
        (, int256 answer, , , ) = priceFeed.latestRoundData(); //该地址支持这个方法
        return answer;
    }
}
  • 根据接口合约可以知道,会返回五个数据,不需要的数据我们可以直接置空,但是数量要一致

实现 ETH/USTD的转换

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import {AggregatorV3Interface} from "@chainlink/contracts@1.2.0/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";

library PriceConverter{

    function getVersion() internal view returns (uint256){
        AggregatorV3Interface priceFeed = AggregatorV3Interface(0x694AA1769357215DE4FAC081bf1f309aDC325306);
        return priceFeed.version();

    }
    function getPrice() internal view returns (uint256) {
        AggregatorV3Interface priceFeed = AggregatorV3Interface(0x694AA1769357215DE4FAC081bf1f309aDC325306);//实例化一个对象,通过接口,将有对应功能的节点地址导入
        (, int256 price, , ,) = priceFeed.latestRoundData();//选择性返回 price
        uint8 decimals = getDecimals();
        uint256 adjustedPrice = uint256(price) * 10**(18 - uint256(decimals));//都可以以最小单位 wei来计算。
        return adjustedPrice;
    }
    function getDecimals() internal view returns (uint8){
        AggregatorV3Interface priceFeed = AggregatorV3Interface(0x694AA1769357215DE4FAC081bf1f309aDC325306);
        return priceFeed.decimals();
    }

    function getConversionRate(uint ethAmount) internal view returns (uint256)  {
        uint256 ethprice = getPrice();
        uint256 ethAmountInUsd = (ethprice * ethAmount) / 1e18;  //ethAmount 是以 wei 为单位的 ETH 数量,所以除以 1e18
        return ethAmountInUsd;

    }

}

上面的代码使用 library库 封装的函数功能

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import "./priceConverter.sol";

contract FundMe {
    using PriceConverter for uint256;

    event Funded(address indexed from,uint256 amount);

    mapping (address => uint256) public addressToAmountFunded;
    address[] public funders;

    address public owner;

    modifier onlyOwner(){
        require(msg.sender == owner);
        _;
    }

    constructor(){
        owner = msg.sender;
    }

    uint256 public minimumUsd = 50 * 1e18;

    function fund() public payable{
        require(msg.value.getConversionRate() > minimumUsd,"didn't send enough"); //msg.sender会被当作第一个参数传入函数中,如果要传入第二个参数,现在库合约中定义,再从括号内传入即可
        funders.push(msg.sender);
        addressToAmountFunded[msg.sender] = msg.value;

    }

    function withdraw() public onlyOwner{
        for (uint i; i < funders.length; ++i){
            address funder = funders[i];
            addressToAmountFunded[funder] = 0;
        }   

        funders = new address[](0); //重置数组

        payable(msg.sender).transfer(address(this).balance); //将资金转给msg.sender,注意:如果有多个收款人,这个函数只能转给第一个收款人

        //bool sendSuccess = payable(msg.sender).send(address(this).balance);
        //require(sendSuccess,"Send Failed");

        //(bool callSuccess,bytes memory returnData) = payable(msg.sender).call{value: address(this).balance}("");
        //require(callSuccess,"call failed");
    }
}

具体操作

image-20241101200631920.png

在这个页面可以获得提供喂价服务的地址,就是我在代码中填入的地址

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

1 条评论

请先 登录 后评论
浪迹陨灭
浪迹陨灭
0x0c37...a92b
专注于solidity智能合约的开发