Skip to content
Indexer Access

What it stores

How a number was derived, and the rules that decide what a value means. Absence, quote units, transfer-derived balances, labelled approximations, and trace coverage.

These rules apply to every route. They are the difference between reading a number correctly and reading it confidently but wrong.

Absent is not zero

A value that could not be derived is null and carries a reason. It is never zero, and it is never dropped from the response.

This matters most where zero is a plausible answer:

ValueMeans
volume: 0The window was computed, and no trades were observed
volume: nullThe window could not be computed

The same distinction holds for decoding. A contract that could not be decoded is reported as undecoded, not as a contract with nothing to report.

Quote units are never merged

A token trading against wrapped native and against a stablecoin has two separate series. No route sums them. That includes market cap, liquidity, and portfolio totals.

If you want one blended number you have to make that choice yourself, with the quote basis visible. The Indexer will not make it silently, because the blend is an editorial judgment and the inputs are not interchangeable.

Balances are transfer-derived

Balances are the running signed sum of decoded transfers. They are not balanceOf calls against the node.

One consequence is worth stating plainly: a negative balance means inbound history is incomplete, and it is served as-is rather than clamped to zero. Clamping would hide the gap and present a wrong number as a clean one.

A wallet holdings row exists only while the balance is non-zero, so holdings routes are what a wallet holds now, not what it has ever held.

Approximations say so

Where a value is a bounded estimate rather than an exact count, it is labelled and published with its bounds.

  • Distinct-trader counts are a bounded sketch, published with exact lower and upper bounds.
  • Top-holder lists are exact. /top-holders pages a balance-ordered index that is updated in the same write as every balance, with no cap and a cursor. The one remaining capped, approximate holder list is internal: it only picks the candidate wallets for /traders, and that route says so.
  • Compact amounts carry a precision witness so you can tell what was preserved.

Internal transfers are the one unverifiable class

Internal value transfers come from node re-execution, not from a consensus commitment. They are the only data class in the store that cannot be checked against a block root.

Routes that use them publish their own coverage and gap counts rather than presenting them at the same confidence as receipt-backed data. Treat them accordingly.

Coverage is stated per route

Routes whose underlying data is known to be partial carry that fact on every response, as a fixed field describing the route's limits rather than that particular answer.

Route familyCarries
Wallet transactionsTop-level transactions only, internal calls not retained
TransfersTransfer activity only, not complete EVM history
Trace-derivedPending and gapped block counts

Empty is a real answer

A 200 with empty collections usually means the subject genuinely has no matching rows. Discovery feeds in particular, such as new tokens and new pools, are unfiltered lifecycle feeds and promise no activity.

Before treating an empty result as a coverage bug, check it against a subject you know is populated. The two look identical from a single call.

Coverage while projections backfill

Some projections can still be backfilling while the canonical head advances. During that window, wallet activity may describe a recent interval rather than full history, and portfolio responses may publish a typed absence for totalUsd while still returning the coordinate split. Always honor each route's coverage, status, and reason fields; do not interpret a missing historical row as proof that the wallet never held the asset.

View this page as Markdown