2

我需要获取从特定时间到最近一轮的代币的 Chainlink 价格。此时间根据用户输入而有所不同,但根据令牌的心跳,将是相对较短的窗口(最多 1 天到 2 周)。这用于计算智能合约和应用程序主页上的支付价格。

要获取历史价格数据,Chainlink 需要一个“roundId”,它是一个非增量值。

从 Chainlink 获取给定时间窗口的所有 roundId 或以开放、去中心化且可以在 Solidity 智能合约中访问的方式记录它们的最佳方法是什么?

4

1 回答 1

2

Chainlink Price Feed 的每个代理合约都可以有多个底层聚合器合约,其中一个在任何给定实例中都被设置为“活动”。也就是说,每当 Chainlink Labs 团队部署新版本的聚合器时,他们都会更新代理合约以将当前的聚合器版本设置为新版本,并且所有新的价格数据都开始写入新的聚合器。

基于此,如果您想要过去几周左右的代理合约/价格对的历史价格数据,您需要转到代理合约的当前聚合器,然后获取当前轮次信息(包括时间戳) ,然后在循环中返回聚合器轮次,直到到达小于搜索参数时间戳的轮次。

要查找代理合约的当前聚合器合约地址,您可以调用代理合约中的aggregatorgetter 函数。

阶段 ID 可以被认为是代理合约在添加到代理时用来识别每个聚合器的递增 ID 号,因此第一个是 1,第二个是 2,依此类推。找出当前阶段 ID 是什么对于当前聚合器,您可以使用代理合约中的phaseId getter 函数。

聚合器轮次 ID 从 1 开始,每次增加 1。例如,您可以使用聚合器latestRoundgetter 函数查找它存储的最后一轮,然后从该数字作为输入参数开始getRoundData,然后将数字减一并循环直到到达您的时间点。

与聚合器轮 ID 不同,代理轮 ID 是那些非常长的数字,例如36893488147419113293,实际上只是基于聚合器阶段 ID 和聚合器轮 ID 的派生值。这样做是为了确保代理轮次 ID 的值始终在增加,并且不同聚合器之间的相同轮次之间永远不会有任何重叠,例如,来自具有阶段 ID 1 的聚合器的第 5000 轮应该具有比第 5000 轮更低的代理轮次 ID来自阶段 ID 为 2 的聚合器

在 Solidity 中,您可以使用以下公式轻松复制代理轮 ID 派生值,传入聚合器的阶段 ID 和聚合器轮 ID

return uint80(uint256(_phaseId) << 64 | _aggregatorRoundId);

您甚至可以获取该派生值并将其传递给代理合约函数,并获得与在给定聚合器轮 ID 的聚合器合约中getRoundData调用相同的数据结果。getRoundData

我发现解决这些问题的一个好方法是直接在 etherescan 上与函数交互,并查看返回的数据。即这里是 Kovan ETH/USD 代理及其最新的聚合器

关于第二个问题的答案,最好的方法是从“现在”开始,即获取最新的聚合器,在聚合器中抓取最新的轮次,然后通过将聚合器轮次ID减1来及时返回,并继续获取直到回合时间戳<您的搜索时间戳的定价信息。

最后,Solidity 中的循环并不是很省气。您可以采取的另一种方法是将外部计算卸载到预言机,预言机可以为您提供正确的轮 ID,然后您可以使用它并在链上验证结果。这是该设计模式的一个示例,采用外部适配器的形式,它根据时间戳检索历史价格数据。Kovan 上也有此运行的实时版本,请查看自述文件以获取更多信息

于 2021-12-17T06:04:19.407 回答