Create a subgrove
This guide walks through creating a BlockchainIndexing subgrove: pointing
Willow at a contract so its events become a live, queryable, verifiable dataset.
By the end you’ll understand the manifest (which contracts and events to index), the schema (the shape of the rows), and every field you can set.
Before you start
Section titled “Before you start”- A Willow account (free tier, no card) — sign up at dashboard.willow.tech.
- The contract address, the events you want, and the block to start from.
- A small amount of WILL to fund the indexers (set at registration).
How indexing works
Section titled “How indexing works”Willow indexes events declaratively — you don’t write handler code for standard contracts. Two pieces work together:
- The manifest lists each contract and the event signatures to watch.
- The schema declares a GraphQL entity per event.
The rule that connects them: an entity’s type name must match the event
name, and its fields map positionally to the event’s parameters. Willow
decodes each matching log and writes one row, auto-filling metadata fields
(id, blockNumber, timestamp, transactionHash). No handler function is
involved.
The manifest
Section titled “The manifest”The manifest is JSON. Here is a complete, valid example — USDC Transfer
events on Ethereum mainnet:
{ "spec_version": "1.0.0", "description": "USDC transfers on Ethereum mainnet", "data_sources": [ { "name": "USDC", "network": "mainnet", "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "abi": "ERC20", "start_block": 6082465, "events": [ "Transfer(address indexed,address indexed,uint256)" ] } ]}The schema
Section titled “The schema”The schema is a separate field you provide at registration (it is not
inside the manifest). Declare one @entity type per event, named after the
event:
type Transfer @entity { id: ID! from: String! to: String! value: BigInt! blockNumber: BigInt! timestamp: BigInt! transactionHash: String!}How the fields map:
type Transfermatches theTransfer(...)event.from,to,valueare your data fields — they map, in order, to the event’s three parameters (address,address,uint256).id,blockNumber,timestamp,transactionHashare metadata — Willow fills these automatically. (idis{txHash}-{logIndex}.)
So the order of your non-metadata fields must match the order of the event parameters.
Scalar types
Section titled “Scalar types”| Type | Use for |
|---|---|
String | text, addresses as hex, anything textual |
BigInt | 256-bit integers (token amounts, prices) — stored exactly |
Int | 32-bit signed integers |
Boolean | true/false |
Bytes | hex byte strings |
Address | 20-byte addresses |
BigDecimal | arbitrary-precision decimals |
Timestamp | block timestamps |
Event signatures
Section titled “Event signatures”Each entry in events is a Solidity event signature, types only (no
parameter names), with an optional indexed keyword per parameter:
Transfer(address indexed,address indexed,uint256)Supply(address indexed,address,address indexed,uint256,uint16 indexed)- Use
indexedto mark parameters declaredindexedin the contract (they’re read from log topics; non-indexed come from the data blob). Solidity allows at most 3 indexed parameters. - Up to 32 events per data source.
Field reference
Section titled “Field reference”Manifest (top level)
Section titled “Manifest (top level)”| Field | Type | Required | Notes |
|---|---|---|---|
spec_version | string | yes | Must equal "1.0.0". |
description | string | no | ≤ 1024 chars. |
data_sources | array | yes | 1–64 data sources. |
deferred_completeness | bool | no | Defaults to false. |
EVM data source
Section titled “EVM data source”| Field | Type | Notes |
|---|---|---|
name | string | Label; alphanumeric / - / _, ≤ 64 chars. |
network | string | Canonical chain id (see below). |
address | string | 0x + 40 hex. |
abi | string | A label only (e.g. ERC20) — the real decode info is the event signatures. ≤ 64 chars. |
start_block | number | Block to begin indexing from. |
events | array | 1–32 event signatures. |
indexer_config
Section titled “indexer_config”| Field | Type | Default | Notes |
|---|---|---|---|
min_indexers | number | 1 | 1–10. |
max_indexers | number | 3 | 1–10, ≥ min_indexers. |
reward_per_epoch | string | 0.1 WILL | Per indexer, per epoch, in the smallest WILL unit (1 WILL = 10¹⁸). Max 1000 WILL. |
epoch_length | number | 100 | Epoch length in blocks. |
min_indexer_stake | string | 100,000 WILL | Per-indexer stake, smallest WILL unit. |
Execution mode
Section titled “Execution mode”execution_mode chooses how the indexing is verified. Defaults to
ConsensusExecution. See Execution modes for all
variants and their sub-config.
Supported networks
Section titled “Supported networks”network must be one of these exact canonical ids (no aliases):
mainnet, sepolia, holesky, bsc, optimism, arbitrum-one, base,
polygon, solana-mainnet.
Register
Section titled “Register”You register by submitting a RegisterSubgrove transaction. It carries:
subgrove_id— your unique id.schema— the GraphQL schema string above.- the
BlockchainIndexingmode —manifest_content(the manifest JSON),execution_mode,indexer_config(and optionalwasm_modules). - initial funding (WILL).
From the dashboard
Section titled “From the dashboard”Go to Subgroves → Register a subgrove, keep Mode on
BlockchainIndexing, fill in the Subgrove ID, funding, and the
Config, then Register.
Programmatically
Section titled “Programmatically”Any of the SDKs can sign and submit the transaction — useful
for scripting or CI. See the SDK reference for the exact register call.
After registering
Section titled “After registering”- Watch indexing progress and validators in the dashboard.
- Query the dataset — see Query indexed data.
- Every row you read back is Willow verified.