Skip to content
Back to Projects
Supra Indexer SDK (Rust) logo

Supra Indexer SDK (Rust)

Open-source Rust crate for building Supra blockchain indexers: typed event collectors, cursor pagination, and resumable PostgreSQL checkpoints.

RustBlockchainSDKIndexerSupraWeb3AsyncPostgreSQLDatabaseInfrastructureDiesel

Problem

Every Supra dApp that needs on-chain events in a database ends up rewriting the same loop: poll the RPC, page through results, store rows, remember where it stopped. The SDK turns that loop into a reusable, typed library so a team only writes the event types and the storage logic.

My role: Personal open-source project. Designed the API, implemented the crate and published it to crates.io.

Constraints

  • Supra exposes events over an HTTP RPC (/rpc/v3/events/{address}::{event}) with header-based pagination, so indexing is poll-based.
  • An indexer must resume where it left off after a restart without re-indexing from genesis.
  • Each consumer has its own event schema and tables, so storage cannot be hard-coded.

Architecture

  1. IndexerConfig

    node_url, contract_address, events, starting block height, fetch interval

  2. SupraIndexer::start_all

    Spawns one tokio task per registered event collector

  3. Supra RPC (HTTP)

    GET events from the saved block height, up to 100 per page, following the x-supra-cursor header

  4. EventStore<E> (user code)

    Typed events handed to the consumer's own storage logic

  5. PostgreSQL block_heights

    Per-event checkpoint upserted after each batch

What I Built

  • SupraIndexer with register_collector::<E, R, S>() and start_all(): one concurrent collector per event type.
  • Trait-based extension points: EventStore<E> for persistence, ExtractEventData<E> for unwrapping RPC responses, HasBlockHeight for checkpointing.
  • GenericEventCollector<E, R, S>, so the event type, response wrapper and store are all chosen by the consumer at compile time.
  • Checkpoint table (block_heights) created and seeded on startup with ON CONFLICT DO NOTHING, so restarts keep existing progress.
  • Diesel 2 + r2d2 connection pool for PostgreSQL, reqwest for RPC calls, tokio for scheduling.
  • Published as supra_indexer_sdk on crates.io.

Technical Challenges

Generic but type-safe collectors
Each collector is generic over the event type, the RPC response shape and the store, so consumers get compile-time checked events without the SDK knowing their schema.
Resumable indexing
Progress is stored per event name and upserted as last_block + 1 after every batch. The startup seed never overwrites an existing checkpoint.
Cursor pagination
The collector follows the x-supra-cursor response header page by page until the RPC stops returning one, then sleeps for the configured interval.
Isolated failures
Each event type runs in its own task. An RPC or storage error pauses that collector and retries after 5 seconds without stopping the others.

Trade-offs & Limitations

  • HTTP polling rather than streaming: simple and matches the RPC, at the cost of latency equal to the fetch interval.
  • Events are stored before the checkpoint moves, in separate steps. Delivery is at-least-once, so EventStore implementations should write idempotently.
  • Fixed 5-second retry with no backoff; Diesel calls are blocking inside async tasks.
  • Early version (0.1.x) with no automated tests yet.