From contract to nest: indexing USDC

This is the current, executable path on v5.3.0. It creates a nest from a verified contract, backfills its recent history, follows the chain, and serves decoded event data locally. The data surface is read-only SQL over HTTP and MCP. GraphQL is a partial read surface, exact for a subgraph's event-shaped fields and a named refusal for the rest, it is parked, and the default binary has no GraphQL route: it is served only by the nuthatch-graph download attached to every release since 4.11.0. See the roadmap.

Nuthatch begins with a contract, not a hosted indexing service. This example indexes USDC on Ethereum mainnet. The same shape works for a contract of your own, or for a published nest checked out with nuthatch init --from <git-url>.

One command, one nest

shell
nuthatch init 0xA0b86991c6218b36c1D19D4a2e9Eb0cE3606eB48 \
  --alias usdc --chain mainnet

init vendors the ABI, records the chain and contract in nuthatch.toml, and writes the schema and authoring files. The explicit --alias usdc gives the event tables stable, readable names.

USDC is a proxy, so init also warns that events before block 18,921,498, when the current implementation was deployed, will not decode under this scaffold. Add the earlier ABI as a second contract entry before trusting historical totals.

nuthatch dev --backfill 300

The process backfills the last 300 blocks, so there are rows within seconds, follows the tip, and serves a local API at http://127.0.0.1:8288. Without --backfill, dev backfills from the contract's deployment block, which for USDC is 20 million blocks and wants your own archive-capable RPC rather than the free public defaults.

Queryable before you model anything

Every declared event becomes a table named {alias}__{event}. For this nest, Transfers are usdc__transfer. The raw layer includes provenance such as block number, transaction hash, and log index alongside the decoded event fields.

the ten latest USDC transfers
SELECT block_number, tx_hash, log_index, "from", "to", value
FROM usdc__transfer
ORDER BY block_number DESC, log_index DESC
LIMIT 10;

Start with GET /schema or GET /tables when you do not know a nest’s shape. Solidity’s from and to are SQL reserved words, so they need double quotes in a query.

Serve the data

The SQL endpoint is deliberately small: it accepts read-only SELECT or WITH queries as the q query parameter. It is a GET endpoint, not a Postgres wire protocol and not GraphQL.

query over HTTP
curl -G 'http://127.0.0.1:8288/sql' \
  --data-urlencode 'q=SELECT count(*) AS transfers FROM usdc__transfer'

The response covers both sealed historical segments and the live hot tip. Query limits, timeouts, and read-only enforcement are part of the endpoint, not an optional client habit. A reverse proxy should still provide authentication and per-client rate limits before exposing it publicly.

Turn facts into your application model

Raw events are available immediately. Add an authored view when your application needs a stable derived shape, and commit checks with recorded fixtures when the result matters. A view is evaluated at query time, so it is broad and inexpensive until someone asks for it.

When a view becomes a hot read

If one grouped answer is asked often enough that rescanning history is the expensive part, make the distinction explicit: put its one SELECT in entities/holders.sql and declare its key and bound in entities.toml. Nuthatch then maintains the relation for each arriving block, exposes it to /sql by name, and retracts it on a reorganisation.

entities.toml
[[entities]]
name = "holders"
sql = "entities/holders.sql"
key = ["holder"]
max_rows = 100000

This is not a faster spelling of a view. An entity reserves memory and accepts a deliberately small SQL subset, but makes a repeated aggregate an indexing-time cost instead of a query-time one. Keep general SQL in views/. The full authoring contract, including restart seeding and the admissible SQL, is in the entities guide.


The result is a self-hosted, replayable event index you can query without a deploy key or a gateway. For the full command and HTTP reference, continue to the quickstart or the HTTP API.