StrimzStrimz
Self-hosting

Self-hosting the indexer

Configure the Go indexer against your own RPC + Postgres.

The indexer is a single Go binary. It polls an Arc RPC for new blocks, decodes contract events, and projects them into Postgres.

Build

cd apps/indexer
make build
./bin/indexer run

Or run the prebuilt distroless image:

docker pull ghcr.io/strimzlab/indexer:latest
docker run --env-file=.env ghcr.io/strimzlab/indexer:latest

Configuration

Required env vars (see .env.example):

ARC_ENVIRONMENT=mainnet            # or testnet
ARC_CHAIN_ID=5042
ARC_RPC_URL=https://your-arc-rpc.com
DATABASE_URL=postgresql://...

REGISTRY_ADDRESS=0x...
PAYMENTS_ADDRESS=0x...
SUBSCRIPTIONS_ADDRESS=0x...
AGENT_ESCROW_ADDRESS=0x...
FEE_COLLECTOR_ADDRESS=0x...
TOKEN_WHITELIST_ADDRESS=0x...
AGENT_REGISTRY_ADDRESS=0x...
TIMELOCK_ADDRESS=0x...            # the TimelockController from the admin handoff
STABLECOIN_ADDRESSES=USDC:0x...,EURC:0x...

START_BLOCK=12345678
CONFIRMATIONS=1                     # blocks to wait before projecting
POLL_INTERVAL_MS=5000               # how often to check for new blocks
BLOCK_BATCH_SIZE=500                # max blocks per RPC call

STABLECOIN_ADDRESSES is a comma-separated list of SYMBOL:address pairs (USDC and EURC) for the stablecoins Strimz accepts. The indexer resolves payment tokens through it and scans those contracts for refund-completion Transfer events. At least one entry is required.

ARC_CHAIN_ID, START_BLOCK, CONFIRMATIONS and TOKEN_WHITELIST_ADDRESS have no default. A missing or malformed value stops the indexer at boot with the variable named.

  • ARC_CHAIN_ID is 5042002 on Arc testnet and 5042 on Arc mainnet. At boot the indexer asks every RPC endpoint (ARC_RPC_URL and each ARC_FALLBACK_RPC_URLS entry) for its chain id. An endpoint on another chain stops the boot; an endpoint that does not answer is dropped with a warning.
  • START_BLOCK is the block your core contracts were deployed at. A fresh database starts indexing there.
  • TOKEN_WHITELIST_ADDRESS is the TokenWhitelist contract. The indexer records its token changes and logs an error when a newly whitelisted token is missing from STABLECOIN_ADDRESSES.

Run one indexer and one database per network. The indexer's bookmarks are keyed by chain id, but the tables it projects into are not, so testnet and mainnet must not share a database.

Migrations

The indexer expects the Prisma schema from packages/db to be applied. From the repo root:

pnpm --filter @strimz/db db:migrate:deploy

Confirmations

CONFIRMATIONS=1 keeps the indexer one block behind head. Arc has deterministic BFT finality — a committed block never reorgs — so one confirmation is plenty; the extra block only shields against an RPC replica that hasn't yet caught up to head.

Idempotency

The indexer's checkpoint is IndexerCursor. Truncate it and restart, and the indexer re-processes from the configured START_BLOCK. Every projection is idempotent (INSERT … ON CONFLICT DO NOTHING keyed on natural identifiers), so re-running is safe.

Observability

  • /healthz. Always 200 once the process is alive.
  • /readyz. 200 once the first batch has been processed.
  • /metrics. Prometheus endpoint with per-contract block lag, RPC latency, projection counts.

Failure recovery

If the indexer crashes mid-batch, the IndexerCursor does not advance until the batch completes. On restart it picks up at the last successful batch's end block. No event gets projected twice.

If the RPC returns malformed data (rare), the indexer logs the error and skips the bad log. The rest of the batch processes normally. Failed projections write to the AgentActivityLog, or to stderr for a structural error like a schema mismatch.

Source

github.com/StrimzLab/strimz/tree/main/apps/indexer

On this page