Indexing and data freshness
Canonical event replay, reorganization recovery, discovery pagination, quote snapshots, and cache lifetimes.
The backend index stores canonical basket creation events so clients can discover and paginate baskets. It does not replace contract reads for live reserves, share supply, user balances, fees, or claims.
What is indexed
The indexer watches the configured community factory, optional managed factory, and optional native factory for:
event BasketCreated(
address indexed creator,
address indexed vault,
address indexed receiver,
string metadataURI
);
Records include the vault/share address, creator, receiver, metadata URI, creation transaction, block number, and block timestamp. The public createdAt value is in milliseconds. The API does not expose an indexed holder ledger or a complete transaction history.
Replay and checkpoints
The initial cursor is DEPLOYMENT_BLOCK - 1. Each tick verifies the RPC chain, reconciles stored checkpoints, reads the current head, and targets head - INDEX_CONFIRMATIONS. It processes at most INDEX_BATCH_BLOCKS in one batch.
For each returned event, the indexer checks the emitting factory, block range, event encoding, transaction/block hash format, and canonical block hash. It reads the ending block again and rechecks the chain before committing. A changed block prevents committing a mixed-chain batch.
SQLite commits records and the ending checkpoint together in a transaction. The database uses WAL mode, synchronous=FULL, and a five-second busy timeout. It retains the latest 128 batch checkpoints. Those are batch boundaries, not necessarily 128 consecutive blocks.
Reorganization recovery
On each tick, reconciliation compares checkpoints from newest to oldest against canonical block headers. At the newest matching checkpoint, it rolls back later baskets/checkpoints and replays forward. If none match, it resets the index to the original starting block and replays the configured factories.
This changes discovery records only. It does not move vault assets or rewrite chain history. Clients should key baskets by chain and address, deduplicate paginated results, and refresh the first page after a reorganization or long pause.
The data directory is bound to the chain ID, community factory, managed factory, native factory, and deployment block. A changed binding is rejected at startup. Use a deliberately separate directory for a different deployment.
Readiness signals
| Signal | Meaning |
|---|---|
ready in /v1/config or standard /health |
Most recent RPC chain validation succeeded |
status: "syncing" / indexer: "syncing" |
More eligible blocks remain to index |
ready index status |
Cursor reached the confirmation-adjusted target on the last tick |
degraded index status |
A tick or periodic RPC validation failed |
indexedBlock |
Last committed block, expressed as a decimal string |
lastIndexedAt |
Last successful tick time in milliseconds; null before one succeeds |
The default cadence is five seconds, with 250 blocks per batch and two confirmations. A successful no-new-block tick updates lastIndexedAt; it is a service activity timestamp, not the timestamp of the most recently created basket. A syncing service can return HTTP 200 from /health.
A missing indexed basket returns { "basket": null } with HTTP 200. This can mean it is too recent, outside the configured registries, not indexed during an outage, or absent from the canonical chain. Verify membership, receipt, and bytecode before drawing a conclusion.
Separate freshness domains
| Data | Freshness behavior |
|---|---|
| Basket discovery | Confirmation-adjusted event cursor; no API response cache |
| Launch/proportional-trade quote | New explicit snapshot at head minus 20 on Robinhood chains; expires after two minutes |
| Liquidity discovery/quote | Prefers head; fallback to head minus 5 or 20 only for a state-height RPC error |
| Immutable venue/pool identity cache | Ten seconds, at most 1,024 entries; mutable prices/liquidity are not cached as quotes |
| Blockscout token directory | 15-second cache |
| Codex mainnet token directory | 60-second cache |
| Robinhood stock identity registry | Five-minute cache |
| Stored JSON/WebP | Content-addressed, one-year immutable HTTP caching |
The local quote test chain 31337 uses its current block. Standard service configuration still accepts only Robinhood mainnet/testnet IDs; local fixture scripts manage their own test setup.
Token-directory cursors are authenticated by a random process key, scoped to their chain/query or wallet, and expire after 15 minutes. Restarting the service invalidates them. Refresh the list instead of persisting a token cursor as durable application state. Basket cursors use keyset markers and have a different format and lifecycle.
Client behavior during partial failure
Display discovery lag and unavailable data separately from an empty collection. Refresh balances from RPC after account changes and after confirmed transactions. A confirmed launch can be opened directly by its address while the creation index catches up.
Do not reuse an old quote after approvals, wallet changes, edits, or expiry. A pool that appears in discovery may fail for a larger requested amount. Provider market metrics and structural route availability are not substitutes for a fresh amount-specific quote.
For monitoring and recovery practices, see configuration and operations.