> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tayho.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Indexer architecture

> Ponder ingestion, reorg-safe projections, private queries, and canonical realtime event publication.

# On-chain indexer

The `tayho-indexer` service is a Ponder 0.16 projection of canonical HyperEVM data. Its trust
boundary stops at the chain: it consumes contract logs and block-pinned `eth_call` results, and it
never reads the engine database, Redis, BullMQ, signer secrets, or live order-book sources.

```mermaid theme={null}
flowchart LR
  RPC1[HyperEVM RPC A] --> P[Ponder writer x1]
  RPC2[HyperEVM RPC B] --> P
  WS[Optional chain WebSocket] -. ingestion acceleration .-> P
  P --> DB[(Dedicated indexer Postgres)]
  DB --> V[Stable tayho_indexer views]
  P --> API[Private REST + GraphQL]
  API --> Q[Elysia public query API]
  P -->|cursor feed| R[(Redis Streams)]
  R -->|replay + fan-out| Q
  E[Engine / automatic orders] --> Q
  L[Live market-data service] --> Q

  P -. /metrics .-> M[Prometheus]
  P -. /ready /status .-> O[Railway + operators]
```

The writer and its HTTP server run together initially. Ponder assigns each Railway deployment its
own database schema and switches the stable views only after the replacement has fully backfilled
and reached realtime. Railway keeps the prior deployment serving during that backfill. This gives
zero-downtime schema changes without two writers mutating one projection.

If read traffic later contends with indexing, add `ponder serve` replicas behind a private proxy and
attach them to the active deployment schema. Writer scaling is deliberately not used as a read
scaling mechanism.

## Ownership and consistency

* Ponder is the sole historical log-ingestion owner and the only Tayho service permitted to call
  `eth_getLogs`. The auditor, API, engine, relayer, SDK, and other workers consume this projection
  or bounded state reads; they never run independent range scanners.
* Ponder is responsible for EVM ordering, finality checkpoints, reorg rollback, RPC caching, and
  crash recovery.
* Every history row uses `chainId:transactionHash:logIndex` as its stable identity.
* Current-state tables are keyed by their protocol identity and updated in log order.
* Position settlement handlers insert the full-close outcome emitted by `PositionSettled`, then
  reconcile the same history row from the immediately following `PositionReduced` event when the
  close is partial. This preserves exact per-log quantities even when a batch reduces one position
  several times in one block.
* Funding snapshots are derived from already ordered funding-update events. Vault reserve-release
  logs are attributed to the immediately following position settlement in the same transaction,
  so market reserves remain log-ordered even when many positions settle in one block.
* The independent auditor remains separate. It consumes the indexer's private projection for
  ordered event evidence and uses independent RPC quorum calls for bounded current-state
  verification. It does not recreate the log stream.

## Query composition

Ponder answers chain facts: listed markets, positions, settlements, funding, session limits and
spend, final order execution/cancellation, vault flows, oracle attestations, staking, and token
balances. The engine remains authoritative for automatic orders before settlement. The Elysia API
composes both domains at response time, preserves source labels, and never writes off-chain state
into Ponder tables. Its private cursor feed emits canonical event projections to a renewable,
single-leader API pump. Redis Streams is a derived replay/backplane layer; Ponder remains the source
for every reconnect snapshot and can repopulate the stream after loss.

## Inputs, outputs, and readiness

The indexer accepts the deployment identity, earliest deployment block, independent HTTP RPC
origins, optional WebSocket acceleration, and its isolated database. It outputs bounded private
REST/GraphQL projections, checkpoint/status/metrics endpoints, stable views, and the canonical event
cursor consumed by the API pump.

`/ready` proves Ponder and query readiness; `/status` reports projection progress. A wrong or too-late
start block is an incomplete database, not a recoverable query warning. RPC failure pauses
ingestion. Query replicas may scale later, but there must remain exactly one Ponder writer for a
deployment schema.

Sources:
[`ponder.config.ts`](https://github.com/Tay-Ho/app/blob/develop/apps/indexer/ponder.config.ts),
[`ponder.schema.ts`](https://github.com/Tay-Ho/app/blob/develop/apps/indexer/ponder.schema.ts),
and [`src`](https://github.com/Tay-Ho/app/tree/develop/apps/indexer/src).
