Skip to main content
The indexer is one of three @darkpool/server processes. It polls Sui events on a configurable interval (INDEXER_POLL_MS, default 4000ms) and writes them to Postgres via Drizzle. Cursor state is persisted in the indexer_cursors table so restarts resume cleanly.

Streams

Indexer streams diagram. Sui RPC queryEvents feeds the indexer process. The indexer process owns seven event streams: predict::PositionMinted to the fills table, predict::PositionRedeemed to the redemptions table, predict::oracle::* to the oracles + strikes tables, darkpool::oo_resolution::* to the oo_proposals + votes tables, darkpool::agent::* to the agents table, darkpool::dark_pool::* to the dark_pool_vaults + deposits + settlements tables, binary by slug settlement Redeemed to the redemptions table. The indexer process persists per-stream cursor state in the indexer_cursors table.

One indexer process owns several event streams, each scoped to a different package. Cursor state is persisted per stream so restarts resume cleanly.

All active streams: One binary::<slug> stream is created per .binary-markets/registry.json entry at startup. New markets need an indexer restart before their event stream exists.

Cursors

Each poll uses sui.queryEvents({ MoveEventType: … }) with the stored cursor; on success the new tail cursor is upserted in the same transaction.

Logs

Database schema

Drizzle schema lives in packages/server/src/db/schema.ts. Migrations under packages/server/src/db/migrations/. Run:
The migrate Docker service runs this as a one-shot at compose-up.

Inspection

What’s not indexed yet (v0.4 follow-ups)

  • binary::<slug>::settlement::MarketCreated / PairMinted / MarketResolved are not indexed. /v1/binary-markets reads chain state directly, which is fine at this scale.
  • predict_facade::* attribution events are not indexed. The router relies on the underlying predict::* events instead.
  • Pause / resume of agents is not indexed (no events emitted by Move). The UI reads is_active live via sui.getObject.