chainlink喂价服务讲解
浪迹陨灭nd
- 关注
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)
,每个变量有特定的意义。让我们逐个分析这些变量的含义:
roundId
(uint80
)
- 含义:这是当前价格更新的“轮次ID”(Round ID)。
- 解释:Chainlink 预言机是通过多轮次的方式来聚合数据的,每一轮都会有一个唯一的
roundId
。这个roundId
用于标识这是第几轮价格更新或报告。 - 用途:通过
roundId
,你可以知道当前的价格数据是哪一轮生成的。
answer
(int256
)
- 含义:这是预言机返回的实际答案,即你请求的数据结果。
- 解释:对于价格预言机来说,
answer
通常是某种资产的价格,例如 ETH/USD 或 BTC/USD 的价格。 - 类型为
int256
是因为价格可能为负数(尽管在实际使用中很少见)。例如,它可以用于某些负值的经济数据。
startedAt
(uint256
)
- 含义:这是当前这一轮价格更新的启动时间。
- 解释:
startedAt
代表这一轮价格数据采集的开始时间,通常是 UNIX 时间戳(即从1970年1月1日以来的秒数)。 - 用途:通过这个时间戳,你可以知道这一轮价格数据什么时候开始聚合的。
updatedAt
(uint256
)
- 含义:这是当前价格更新的时间戳。
- 解释:
updatedAt
代表预言机在这一轮价格更新的确切时间,也是 UNIX 时间戳格式。 - 用途:可以用于追踪价格数据的最新更新时间,判断数据是否及时。
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"); } }
具体操作
在这个页面可以获得提供喂价服务的地址,就是我在代码中填入的地址
本文为 浪迹陨灭nd 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
稳定币项目构建 (二)
2025-03-06
Chainlink--CCIP--NFT 讲解
2025-03-06
稳定币项目构建 (一)
2025-03-05
文章目录