There was a moment when I needed to answer a deceptively simple question:
“What was the price of this asset then, not now?”
Not five minutes ago.
Not the current block.
But at a very specific point in the past.
I was working on a feature that needed historical pricing for an asset. Not off-chain charts, not an indexer snapshot, but the actual on-chain value that existed at a given time. Since the asset used Chainlink price feeds, I assumed this would be straightforward.
It wasn’t.
At first, I kept getting the current price no matter what I tried. That’s when I realized something important: most examples show you how to read contract state, but very few show you how to read contract state at a specific block.
That’s where Wagmi quietly shines.
The Core Idea
Ethereum (and EVM chains in general) allow you to query contract state as it existed at any historical block. If a contract method is view or pure, you can read it at a past block without any special indexing infrastructure.
Wagmi exposes this directly through blockNumber.
So instead of asking:
“What does the contract return now?”
You ask:
“What did the contract return at block X?”
For price feeds, this is gold.
The Scenario: Chainlink Price at a Past Time
Chainlink price feeds expose methods like:
latestRoundData()
getRoundData(roundId)
If you already know the round ID, you can query it directly. But sometimes you don’t. Sometimes all you know is the time.
A reliable approach is:
Convert the timestamp you care about into a block number
Read the price feed contract at that block
Let’s focus on step 2 using Wagmi.
Reading a Contract Method at a Specific Block
Wagmi’s readContract (or useReadContract) accepts a blockNumber parameter.
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,
})
What happens here is subtle but powerful.
Wagmi asks the RPC node:
“Pretend the chain is at block 18,500,000. What does this function return?”
The result is exactly what the Chainlink contract would have returned at that block, not today.
Why This Works
Ethereum nodes store historical state. When you specify a blockNumber, the node executes the call against that historical snapshot.
No subgraph.
No off-chain cache.
No guesswork.
Just deterministic blockchain state.
Mapping Time to Block
You usually don’t know the block number upfront. You know a timestamp.
Typical approaches:
Binary search blocks by timestamp using eth_getBlockByNumber
Use a helper API once, then cache the mapping
Use an archive node for accuracy
Once you have the block number, Wagmi does the rest.
Frontend Example with React
If you’re using Wagmi hooks in a React app:
import { useReadContract } from 'wagmi'
const { data } = useReadContract({
address: priceFeedAddress,
abi: aggregatorAbi,
functionName: 'latestRoundData',
blockNumber: 18_500_000n,
})
This is especially useful for:
Historical charts
Auditing old positions
Liquidation simulations
“What-if” analytics
Dispute resolution in DeFi
Important Caveats
RPC support matters
You need an RPC that supports historical reads. Some free providers prune old state.
Performance
Historical reads are slightly heavier. Cache results when possible.
Final Thoughts
Wagmi doesn’t make a big deal out of this feature, but once you realize you can read contract state at any point in time, a lot of problems suddenly become simpler.
Top comments (0)