使用 Wagmi 读取过去区块的合约状态

发布: (2026年1月9日 GMT+8 00:56)
4 min read
原文: Dev.to

Source: Dev.to

核心思路

以太坊(以及一般的 EVM 链)允许你查询任意历史区块时的合约状态。如果合约方法是 viewpure,就可以在过去的区块上读取,而无需任何特殊的索引基础设施。Wagmi 通过 blockNumber 参数直接提供了这种能力。

Chainlink 价格喂价合约提供 latestRoundData() 等方法。如果你已经知道轮次 ID,可以直接查询,但有时你只知道时间戳。一个可靠的做法是把感兴趣的时间戳转换为区块号,然后在该区块上读取合约。

import { readContract } from '@wagmi/core';
import { parseAbi } from 'viem';

const aggregatorAbi = parseAbi([
  'function latestRoundData() view returns (uint80,int256,uint256,uint256,uint80)'
]);

const priceFeedAddress = '0x...';
const blockNumber = 18_500_000n; // 对应目标时间戳的区块

const data = await readContract({
  address: priceFeedAddress,
  abi: aggregatorAbi,
  functionName: 'latestRoundData',
  blockNumber,
});

Wagmi 向 RPC 节点询问:“假装链在区块 18,500,000 时的状态。这个函数会返回什么?”返回的结果正是 Chainlink 合约在该区块时会返回的值,而不是当前值。

为什么可行

以太坊节点会保存历史状态。当你指定 blockNumber 时,节点会在那个历史快照上执行调用——不需要子图或外部索引器,只依赖确定性的区块链状态。

将时间映射到区块

通常你知道的是时间戳而不是区块号。获取对应区块的常见方法:

  • 二分搜索:使用 eth_getBlockByNumber 按时间戳搜索区块。
  • 辅助 API(例如区块浏览器服务),一次获取后缓存映射关系。
  • 归档节点:获取最精确的结果。

得到区块号后,Wagmi 会处理剩下的工作。

使用 React 的前端示例

如果在 React 应用中使用 Wagmi Hook:

import { useReadContract } from 'wagmi';

const { data } = useReadContract({
  address: priceFeedAddress,
  abi: aggregatorAbi,
  functionName: 'latestRoundData',
  blockNumber: 18_500_000n,
});

用例

  • 历史价格图表
  • 审计过去的合约状态
  • 任何需要特定时间点链上数据的功能

重要注意事项

  • RPC 支持:并非所有 RPC 提供商都暴露历史状态;通常需要归档节点。
  • 性能:查询旧区块的速度可能慢于当前状态的调用。

最后思考

Wagmi 并未大量宣传这个特性,但一旦意识到可以在任意时间点读取合约状态,许多问题就会变得更简单。利用 blockNumber 可以从过去检索准确的链上数据,而无需依赖链下快照或索引器。

Back to Blog

相关文章

阅读更多 »