Skip to main content

Indexer API

A read-only REST API (Ponder + Postgres, hosted on Railway) that indexes every IndexPad contract — including tokens launched after deployment, via the factory pattern. CORS is open; all bigint values are serialized as strings.

Base URL (testnet): https://indexpad-indexer-production.up.railway.app

info

The indexer is a convenience for UIs. Nothing in the protocol depends on it — every value can be read directly from the contracts. Backing / NAV and bond-market state are read on-chain by the app (oracle-priced, per-clone); the indexer tracks launches, holders, the inline fee-split flow, and redemptions.

Event sources

The indexer's per-index accumulation source is the hook's FeeSplit event (one per swap), not a keeper — there is no Converted/dividend feed anymore. It also tracks IndexCreated (launches), Transfer (holders, excluding the PoolManager), Redeemed (multi-asset redemptions), and AssetConfigured (the allow-list).

GET /stats

Global protocol totals.

{
"id": "global",
"indexCount": 1,
"reserveInTotal": "4000000000000000000000",
"protocolCutTotal": "400000000000000000000"
}

GET /indexes?limit=50

All index tokens, newest first (limit ≤ 100). Each row includes the launch config (name, symbol, totalSupply, stocks[], rfvShareBps, buybackShareBps, treasury, bond, creator, createdAt, txHash), cumulative flow totals (reserveInTotal, protocolCutTotal, buybackTotal, accumulateCount), and a live holders count.

GET /index/:address

One index with its recent history:

{
"address": "0x…",
"symbol": "MAG7",
"rfvShareBps": 3000,
"buybackShareBps": 3000,
"pair": "0x…", // the pool id (bytes32) as hex, or null
"holders": 3,
"accumulations": [
{ "reserveIn": "…", "protocolCut": "…", "buybackIndex": "…", "stockCount": 7, "timestamp": 1752, "txHash": "0x…" }
],
"redemptions": [
{ "user": "0x…", "burned": "…", "reserveOut": "…", "stockOuts": ["…","…"], "timestamp": 1752, "txHash": "0x…" }
]
}

Returns 404 {"error": "not found"} for unknown addresses. Limits: 25 accumulations, 25 redemptions.

GET /activity?limit=8

A merged, time-sorted feed across all indexes (limit ≤ 30) — powers the app's live activity panel. Event shapes by type:

typeExtra fields
launchsymbol, stockCount
accumulatereserveIn, stockCount
redemptionburned, reserveOut

All events carry index, symbol, timestamp, txHash.

GET /token-holders/:address

Every non-zero holder of an index (the Uniswap V4 PoolManager is excluded — the pool isn't a real holder):

[ { "account": "0x…", "balance": "989999999999999999999900" } ]

GET /assets

Every currently-allow-listed basket asset, enriched with on-chain metadata (address, symbol, name, decimals) — the create and bond-quote pickers read this so RWAs the protocol admin whitelists later appear automatically.

GET|POST /image/:token

Per-index token images (creator-signed uploads, stored outside the reindexable schema). POST requires a signature the recovered address must match the index's on-chain creator.

Running your own

The indexer lives in indexer/. Configuration:

CHAIN_ID=46630
PONDER_RPC_URL=https://rpc.testnet.chain.robinhood.com
INDEX_FACTORY_ADDRESS=<indexFactory>
FEE_REGISTRY_ADDRESS=<feeRegistry>
FEE_HOOK_ADDRESS=<feeHook> # emits FeeSplit per swap
START_BLOCK=<deploy block>
# DATABASE_URL — Railway provides it; omit for local PGlite

See the deployment runbook.