Indexer

How the Adrift indexer works, how the Adrift app uses it, and how it leverages Syndicate's sequencer design.

The Adrift indexer is a specialized service that:

  • Indexes onchain events from the Adrift appchain and underlying chains.
  • Aggregates and exposes game state (players, check-ins, winners, etc.) via a developer-friendly API.
  • Reads from Syndicate's sequencer chain contracts and events to power fair, verifiable, and tamper-resistant game mechanics.

Architecture

+-------------------------------------------------------------------------------------+
|                                    Adrift Frontend                                  |
+-------------------------------------------------------------------------------------+
+-------------------------------------------------------------------------------------+
|                                      Indexer/API                                    |
+-------------------------------------------------------------------------------------+
+-------------------------------------------------------------------------------------+
|                                  Adrift Smart Contracts                             |
|                                     (Pacifica chain)                                |
+-------------------------------------------------------------------------------------+
+-----------------------------------------+ +-----------------------------------------+
|       Syndicate Sequencing Chain        | |          Randomness Providers           |
|             (Risa Testnet)              | |          (Lit, drand, local)            |
+-----------------------------------------+ +-----------------------------------------+
  • Event Indexing: Uses Ponder to listen to smart contract events on the Adrift appchain (Pacifica) and the underlying sequencer chain (Risa Testnet).
  • Database: Stores indexed data in a Postgres database.
  • API Layer: Exposes REST endpoints (using Hono) for the Adrift app and other clients to query game state and trigger actions.
  • Randomness Integration: Leverages Lit Protocol and drand to inject verifiable randomness into the sequencer, powering game events.

Key Contracts Indexed

  • AdriftFactory

    // ponder.config.ts
    contracts: {
      AdriftFactory: {
        chain: "pacifica",
        abi: AdriftFactoryAbi,
        address: env.FACTORY_ADDRESS,
        startBlock: env.START_BLOCK
      },
      // ...
    }
     
    // src/index.ts
    ponder.on("AdriftFactory:AdriftCreated", async ({ event, context }) => {
      // Handles new game creation
    })

    Indexes the factory to detect and start tracking new games as they are created.

  • Adrift

    // ponder.config.ts
    Adrift: {
      chain: "pacifica",
      abi: AdriftAbi,
      address: factory({
        address: env.FACTORY_ADDRESS,
        event: parseAbiItem("event AdriftCreated(address indexed gameAddress, ...)") ,
        parameter: "gameAddress"
      }),
      startBlock: env.START_BLOCK
    }
     
    // src/index.ts
    ponder.on("Adrift:PlayerRegistered", ...)
    ponder.on("Adrift:PlayerCheckedIn", ...)
    ponder.on("Adrift:GameStartTimeSet", ...)
    ponder.on("Adrift:GameEnded", ...)

    Indexes all game events for each deployed Adrift contract.

  • AdriftBundler

    // ponder.config.ts
    AdriftBundler: {
      chain: "risa",
      abi: AdriftBundlerAbi,
      address: env.BUNDLER_ADDRESS,
      startBlock: "latest"
    }
    // src/index.ts

    Indexes sequencer mempool and randomness events on the Risa chain.

Data Model

  • Game: Tracks game state, start/end times, winner, etc.
  • Player: Registered player addresses.
  • GamePlayer: Player-game relationships, check-in status, disqualification, etc.
  • Checkins: Individual check-in events, buffs/debuffs, timestamps.

How the Adrift App Uses the Indexer

The Adrift frontend interacts with the indexer API to:

  • Join the game: Calls /join to register a player onchain.
  • Fetch player state: Calls /player/:address to get check-in status, next check-in time, disqualification, etc.
  • Leaderboard: Calls /leaderboard to get top players and game status.
  • Heartbeat: Calls /heartbeat to automate disqualification and winner detection.

All game state shown in the UI is powered by the indexer's API, which is kept in sync with the chain by Ponder.

API Reference

POST /join

  • Registers a player for the current game.
  • Body: { playerAddress: string }
  • Returns: { success: boolean, hash: string }

GET /player/:address

  • Fetches player state, check-ins, and status.
  • Returns: { data: { ...playerState } }

GET /leaderboard

  • Fetches top players and game status.
  • Returns: { data: { topPlayers: [...], ...gameState } }

GET /heartbeat

  • Triggers disqualification of inactive players and winner detection.
  • Returns: { data: { action: string, ... } }

Learn More

This guide should help you understand, run, and extend the Adrift indexer, and leverage Syndicate's sequencer design for your own projects.

On this page