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

# Factory contracts

> Index contracts a factory creates over time, such as every pool of a DEX, with growing sets.

Many protocols deploy one contract per market: a DEX factory creates a pool per token pair, a
lending protocol a vault per asset. To index their events you need the list of child contracts,
and the list keeps growing.

The pattern:

1. Read the factory's creation events to learn the child addresses.
2. Put the children in a [set](https://docs.bloklake.com/querying/sets.md).
3. Read the children's events with that set.
4. As new children appear, create a bigger set with `basedOn` pointing at the previous one.

## Example: Uniswap V3 pools

The factory emits `PoolCreated(address indexed token0, address indexed token1, uint24 indexed fee, int24 tickSpacing, address pool)`.
The pool's address is the last 32-byte word of `data`. With the [Python client](https://docs.bloklake.com/clients.md):

```python theme={null}
from bloklake import Bloklake

bl = Bloklake(chain="eth")
FACTORY = "0x1f98431c8ad98523631ae4a59f267346ea31f984"  # Uniswap V3
POOL_CREATED = "0x783cca1c0412dd0d695e784568c96da2e9c22ff989357a2e8b1d9b2b4e6b7118"
SWAP = "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67"


def new_pools(frm: int, to: int) -> list[str]:
    page = bl.collect({"from_block": frm, "to_block": to,
                       "logs": [{"address": [FACTORY], "topic0": [POOL_CREATED]}],
                       "fields": {"log": ["data"]}})
    return ["0x" + log["data"][-40:] for log in page.logs]  # the pool: last 20 bytes of data

```

### Backfill

Walk the chain in chunks. In each chunk, first learn the pools created in it, then read swaps
of every pool known so far:

```python theme={null}
START, END, CHUNK = 12369621, 21000000, 200_000  # factory deployment … head
pools: list[str] = []
set_id = None
frm = START
while frm <= END:
    to = min(frm + CHUNK - 1, END)
    created = new_pools(frm, to)
    if created:
        pools += created
        set_id = bl.create_set("address", pools, based_on=set_id).set_id  # grow the set
    if set_id:
        for page in bl.paginate({"from_block": frm, "to_block": to,
                                 "logs": [{"address_set": set_id, "topic0": [SWAP]}],
                                 "fields": {"log": ["block_number", "address", "data"]}}):
            store(page.logs)
    frm = to + 1
```

Reading the pools created in a chunk **before** that chunk's swaps matters: a pool can be
created and swapped in within the same chunk.

## Why sets and `basedOn`

* The pool list grows to tens of thousands of addresses. As a set, it's uploaded once per growth
  step instead of on every request.
* With `basedOn`, the server works out where the new set's addresses appear incrementally
  instead of from scratch, so growing a large set stays fast.
* A set's id is a hash of its values. Re-creating the same set after a restart returns the same
  id, so restarts need no bookkeeping.

## Restarting

Persist `pools` (or rebuild it by re-reading `PoolCreated` from the start; it's a small query)
and the block you reached. Then create the set again (same values, same id) and continue.

> [!TIP]
>
> If you only need recent history, filtering on the event alone can be simpler: `topic0 = Swap`
> without an address matches the swaps of every Uniswap V3 pool, plus any other contract that
> emits an identical event. Keep `address` in the output and drop unknown ones client-side.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.