> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chaintable.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Track liquidity pool reserves

> Read end-of-block reserves when the Uniswap V2 USDC–ETH pool emits a Sync event, then store and inspect current and historical state.

This tutorial uses the Uniswap V2 USDC–ETH pool at `0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc` on Ethereum mainnet. Its contract holds USDC and WETH.

<div className="doc-flow">
  `chain.event.eth` → Filter the pool's Sync events → Read end-of-block reserves → Reserve state table
</div>

Sign in to the [Chaintable console](https://chaintable.com/spaces) and open your 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`.

<Frame>
  <img src="https://mintcdn.com/opcodelabspteltd/TOA0bb8_WqdBuVVN/images/quickstart/track-pool-reserves/create-table.png?fit=max&auto=format&n=TOA0bb8_WqdBuVVN&q=85&s=db0e6b765f548445a3cb50170978b35b" alt="Create the pool_reserves Block State Table on Ethereum" width="1920" height="1080" data-path="images/quickstart/track-pool-reserves/create-table.png" />
</Frame>

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:

| Field          | Type      | Content          |
| -------------- | --------- | ---------------- |
| `reserve_usdc` | `UINT256` | Raw USDC reserve |
| `reserve_weth` | `UINT256` | Raw WETH reserve |

<Frame>
  <img src="https://mintcdn.com/opcodelabspteltd/TOA0bb8_WqdBuVVN/images/quickstart/track-pool-reserves/schema.png?fit=max&auto=format&n=TOA0bb8_WqdBuVVN&q=85&s=74bf2e7288bc5a4ee55df70832cad515" alt="Reserve fields added as UINT256 alongside the block fields" width="1920" height="1080" data-path="images/quickstart/track-pool-reserves/schema.png" />
</Frame>

## 2. Run the Pipeline

### Configure the Pipeline

In **Notebooks**, create `backfill_pool_reserves` and enter the code below. Set `SPACE` to your Space ID:

```python theme={null}
from blockdb import Column, filter
from blockx import Pipeline, Trigger, SOURCE_ROW

SPACE = 'demo'


def read_reserves(event):
    from leafage import ChainState

    pool = '0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc'
    chain = ChainState('eth', event['block_id'])
    reserve_usdc, reserve_weth, _ = chain.call(
        pool, 'getReserves()(uint112,uint112,uint32)', []
    )
    return {
        'id': pool,
        'reserve_usdc': reserve_usdc,
        'reserve_weth': reserve_weth,
    }


pipeline = Pipeline(
    triggers=[
        Trigger(
            table='chain.event.eth',
            func=read_reserves,
            params=[SOURCE_ROW],
            operator=filter(
                (Column('contract_id') == '0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc')
                & (Column('name') == 'Sync')
            ),
        ),
    ],
    target_table=f'{SPACE}.pool_reserves.eth',
)

pipeline.backfill(block_start=25939925, block_end=25939934)
```

The code follows this flow:

* `Trigger` filters the pool's Sync events.
* `SOURCE_ROW` passes each matching event to the function.
* `read_reserves` calls `getReserves()` at the event's `block_id` to read USDC and WETH reserves.
* The Pipeline writes the returned record to the reserve table specified by `target_table`.

The function is defined directly in the Notebook. You can also set `func` to an existing Function ID.

`getReserves()` reads reserves after the block has finished executing. Multiple Sync events in one block therefore return the same end-of-block state.

### 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.

<Frame>
  <img src="https://mintcdn.com/opcodelabspteltd/TOA0bb8_WqdBuVVN/images/quickstart/track-pool-reserves/backfill.png?fit=max&auto=format&n=TOA0bb8_WqdBuVVN&q=85&s=09bf3f82a1fe81012c0af654cad88991" alt="Notebook backfill processes 10 blocks and two reserve updates" width="1920" height="1080" data-path="images/quickstart/track-pool-reserves/backfill.png" />
</Frame>

## 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.

<Frame>
  <img src="https://mintcdn.com/opcodelabspteltd/TOA0bb8_WqdBuVVN/images/quickstart/track-pool-reserves/overview.png?fit=max&auto=format&n=TOA0bb8_WqdBuVVN&q=85&s=6f4d0de84be5debb0e2a690e7a1a9b72" alt="Reserve table progress with default settings and links to latest and archive" width="1920" height="1080" data-path="images/quickstart/track-pool-reserves/overview.png" />
</Frame>

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.

<Frame>
  <img src="https://mintcdn.com/opcodelabspteltd/TOA0bb8_WqdBuVVN/images/quickstart/track-pool-reserves/latest.png?fit=max&auto=format&n=TOA0bb8_WqdBuVVN&q=85&s=fdc543458ccb27ab1a57f673dc67d7a6" alt="The latest subtable retains one current reserve record per pool address" width="1920" height="1080" data-path="images/quickstart/track-pool-reserves/latest.png" />
</Frame>

Open **archive** to inspect historical state by block. `original_id` is the pool address; `id` identifies the historical record.

<Frame>
  <img src="https://mintcdn.com/opcodelabspteltd/TOA0bb8_WqdBuVVN/images/quickstart/track-pool-reserves/archive.png?fit=max&auto=format&n=TOA0bb8_WqdBuVVN&q=85&s=a84dcde0cfce67667b1f7b9564d0f8a1" alt="The archive contains reserve updates at blocks 25939928 and 25939930" width="1920" height="1080" data-path="images/quickstart/track-pool-reserves/archive.png" />
</Frame>

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:

```python theme={null}
pipeline.update()
```

By default, `update()` fills history from the earliest unfinished block, then continues processing new blocks after catching up.

For large historical ranges, you can run `backfill()` in another Notebook at the same time to speed up the backfill.

<Frame>
  <img src="https://mintcdn.com/opcodelabspteltd/TOA0bb8_WqdBuVVN/images/quickstart/track-pool-reserves/update.png?fit=max&auto=format&n=TOA0bb8_WqdBuVVN&q=85&s=977c8591363a7fa87b2dd488a258853d" alt="Continuous update call and historical processing logs in update_pool_reserves" width="1920" height="1080" data-path="images/quickstart/track-pool-reserves/update.png" />
</Frame>

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.
