This tutorial uses the Uniswap V2 USDC–ETH pool at 0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc on Ethereum mainnet. Its contract holds USDC and WETH.
chain.event.eth → Filter the pool’s Sync events → Read end-of-block reserves → Reserve state table
Before you begin
Sign in to the Chaintable console. If you don’t have a Space yet, click New Space on the Spaces page, enter an Id, and click Create space.
Open your new or existing Space. This tutorial uses demo; replace it with your Space ID.
1. Create the reserve state table
In Tables, create a table named pool_reserves, select Block State, and choose Ethereum. Its table ID is demo.pool_reserves.eth.
In the table’s Schema, change id to ADDRESS to store the pool address, then add the fields below. Keep the built-in block fields and other default settings:
2. Create a Function
In Functions, create read_pool_reserves and enter the following code:
Add an event parameter below the editor, select JSON as its type, and save the Function. For the steps, see Create a Function.
The Function uses the event’s block_id to read reserves at the end of that block. Multiple Sync events in the same block return the same end-of-block state. The record also carries the event’s block fields, which larger backfills require; see Result handlers.
3. Run the Pipeline
In Notebooks, create backfill_pool_reserves and enter the following code. Replace SPACE with your Space ID:
sources specifies the source table and saved Function. operator filters events, and ROW passes each source record as an argument. The Pipeline writes the Function’s returned records to target.
Run the backfill
Save and click Run, then check Output for progress and results.
backfill() processes the specified 10 blocks, including both boundary heights, and exits when finished.
3. Inspect current and historical state
Return to pool_reserves.eth and check processed blocks in Overview. This backfill covers a limited range; earlier history is still incomplete.
Open latest under Subtables to view current reserves. Records use the pool address as their ID, so the two state updates leave one current record.
Open archive to inspect historical state by block. original_id is the pool address; id identifies the historical record.
The result contains one state record at each of blocks 25939928 and 25939930. Reserve fields retain raw integers:
- Divide the USDC value by
10^6 to get USDC units.
- Divide the WETH value by
10^18 to get WETH units.
Optional: keep the table updated
Create a Notebook named update_pool_reserves, copy the code above, and replace the final pipeline.backfill(...) line with the call below. Save and run it:
By default, update() fills history from the earliest unfinished block, then continues processing new blocks after catching up. If you only need data from a specific height onward, set the start height first.
For large historical ranges, you can run backfill() in another Notebook at the same time to speed up the backfill.
Choose Switch to Background to keep the instance running in the background. Cancel it under the account’s Instances page to stop it. Data already written remains in the table.