Chainlink 价格预言机(price oracles)是带有 public view 函数的智能合约,这些函数返回特定资产以美元计价的价格。
链下节点从交易所等各种来源收集价格,并将价格数据写入智能合约。
以下是获取 ETH / USD 价格的智能合约:https://etherscan.io/address/0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419/advanced#readContract
当我们调用 latestAnswer() 函数时,我们会得到以太坊(Ether)的价格。当我们查询 decimals() 时,我们会得到用于解析该结果的小数位数。

因此,根据预言机,以太坊当前的价格为 2053.05552675 美元(在撰写本文时为真实数据)。
如果你只想大概了解 Chainlink 预言机的工作原理,你可以就此打住——这就是价格预言机的全部内容!
如果你打算在项目中使用它们,接下来的内容将是重要的实现细节。
我们将使用 ETH / USD 作为贯穿全文的示例,但 Chainlink 支持更多其他资产的价格。
不推荐使用 latestAnswer() —— 请改用 latestRoundData()
这个 latestAnswer() 函数并没有告诉我们价格最后一次更新的时间。如果价格更新出现延迟,智能合约可能会基于过时的价格做出决策。
在下方的绿框中,我们看到了与 latestAnswer() 相同的价格,而在蓝框中,我们看到了它最后一次更新时的 Unix 时间戳。

智能合约可能需要设置一个阈值,以便使用备用预言机或暂停关键决策,直到 updatedAt 字段足够新。
价格聚合
依赖单个节点或数据源来获取价格是不安全的,因此 Chainlink Price Feeds 拥有多个提供价格的白名单节点。
ETH / USD Price Feed 的提供者截图如下。
从报告价格的微小差异中可以看出它们在特定时间提供的价格范围。请注意,价格中“美分”部分的变化范围从 26 美分(顶行)到 73 美分(底行)不等。

transmit()
链下价格通过 transmit 函数进入智能合约生态系统。该函数接收一个(已排序的)价格列表以及来自节点的签名列表。预言机上报告的价格是这些价格的中位数。下面我们展示来自 Etherscan 的相关代码行。

智能合约架构
读者可能已经注意到,latestRoundData() 函数与 transmit() 并不在同一个合约中。这里有三个智能合约在发挥作用:
价格更新交易
在价格更新期间,节点的签名和价格被打包在一起,并发送到 aggregator 合约中的 transmit()。aggregator 合约随后调用 validator 合约中的 validate 函数。受该合约规则的限制,价格更新可能会被拒绝。此类交易的 Tenderly 追踪截图如下。紫色的调用代码显示了跨合约调用。

查看价格

提高读取价格预言机的 Gas 效率
由于查看价格涉及跨合约调用,建议使用访问列表交易(access list transaction)对 aggregator 调用进行“预热”,从而节省 200 Gas。在此仓库中查看将 access list 与 Chainlink 价格预言机结合使用的示例。
价格更新频率
每分钟向区块链发送更新状态的交易是不切实际的。因此,Chainlink 在以下两种情况下更新价格:
- 当超过“心跳(heartbeat)”时间时(对于 ETH / USD 来说是一小时)
- 如果价格变动幅度超过 0.5%
这些参数在下方 Chainlink ETH / USD 面板的截图中被高亮显示

安全注意事项
关于因错误使用 Chainlink 预言机而引发的智能合约安全问题已经有大量的探讨,因此我们在此不再赘述。我们建议读者阅读 Dacian 撰写的一篇文章,其中列出了这些潜在的问题。
在 RareSkills 了解更多
请参阅我们的 Solidity 训练营,深入学习智能合约开发。
最初发布于 2024 年 1 月 11 日