Factory Contracts
Dynamically discover and index child contracts as they're deployed.
Configuration
Instead of a static address, define a [contracts.factory] block that tells Sieve how to find child contracts.
[[contracts]] name = "UniswapV3Pool" abi = "abis/uniswap_v3_pool.json" # start_block belongs here, children inherit it [contracts.factory] address = "0x1F98431c8aD98523631AE4a59f267346ea31F984" event = "PoolCreated" param = "pool" start_block = 12_369_621 [[contracts.events]] name = "Swap" table = "uniswap_v3_swaps"
[[contracts]]How it works
Sieve scans the factory contract for creation events starting from start_block. Each time a new child address is found, it's registered dynamically. All events and calls defined on the parent contract are then indexed for every discovered child.
A contract_address column is automatically added to every table so you can distinguish which child contract emitted each event.
Discovery is sequenced ahead of the parallel block workers, so events a child emits in or shortly after its own creation block are never missed.
Coverage tracking
Sieve records which block ranges each factory was active for. A factory that was not watched over some range would silently miss the children created in it, and every event those children emitted, so Sieve refuses to start instead of indexing a partial table.
The refusals cover adding a factory to a database already indexed past its start_block, lowering an existing start_block, changing a factory's creation event or param, starting a sync past the uncovered range, and re-adding a factory that was removed while indexing continued. The fix is a fresh database or sieve reset.
Upgrading a database created before coverage tracking is the one exception. Run once with --assume-factory-coverage to record the current state as covered. It applies only to factories with no coverage record at all, asserting they were configured continuously. Every other refusal still stands.
sieve --assume-factory-coverage
Key rules
address field. A contract is either static (has address) or factory-based (has factory block), never both.event must exist in the factory ABI, and param must be a parameter in that event.