Small TypeScript service that ingests SRG20 events from BSC (or any EVM chain) and exposes REST endpoints with historical price, rolling volume, and liquidity data. Ponder keeps PostgreSQL in sync with on-chain events, while a lightweight Hono API serves aggregated, gap-free time series for charts or monitoring.
- Event indexing with Ponder.
ponder.config.tswires SRG20 contracts (addresses come fromTOKENS_CONFIG_JSON) to a Postgres store. The handlers insrc/handlers/handlers.tslisten toBought,Sold,Transfer, andOwnershipTransferredevents, maintain per-token supply/liquidity state, and persist every trade in thetransactionstable defined inponder.schema.ts. - Derived liquidity tracking. Because SRG20 contracts do not emit
AddLiquidityevents, owner-to-contract transfers are detected and replay the same math as the contract so that liquidity and price stay in sync without querying the chain. - REST API on top of Postgres.
src/api/index.tsis a Hono app mounted inside Ponder. It validates requests with Zod, buckets trades into hourly/daily/weekly intervals using SQL expressions, and fills missing buckets after retrieving datapoints from the db. - Config-driven deployment. All runtime specifics (RPC URLs, DB connection string, tracked tokens, chain ID/start block) sit in
.envJSON strings, which keeps the codebase stateless and ready for multiple environments. - Tooling/observability. Viem handles EVM utilities, Pino logs structured messages, Biome enforces formatting/linting, and Docker Compose supplies a local Postgres instance.
- Runtime: Node.js 20+, pnpm, TypeScript
- Indexer: Ponder with Postgres target
- API: Hono + Zod validators
- EVM utilities: Viem, SRG20 ABI (in
abis/) - Tooling: Docker Compose (Postgres), Biome, dotenv-cli, Pino
- Install dependencies
corepack enable pnpm pnpm install - Provision Postgres (recommended via Docker)
docker-compose up -d db
- Configure environment
Fill in/separate secrets as needed. Key variables:
cp .env.example .env
PONDER_RPC_HTTP_URLandPONDER_WS_HTTP_URL– RPC endpoints with archive access to your target chain.DATABASE_URL– connection string for the Postgres instance Ponder will manage.PONDER_CONFIG_JSON–{ chainKey, chainId, startBlock }. ThetokenAddressesarray is auto-overridden with the values fromTOKENS_CONFIG_JSON.TOKENS_CONFIG_JSON– array of tracked tokens, includingaddress,decimals,initialLiquidity, andtotalSupply. These seed the liquidity cache before events are replayed.
- Run the dev server
This runs
pnpm dev
dotenv -e .env -- ponder dev, which resets (drops + recreates) the tracked tables on every start so you always replay from scratch. Ponder will then sync the chain, apply handlers, and start the REST API onhttp://localhost:42069(default).
pnpm buildThis emits the compiled files to dist/; run the resulting JS with node or bundle into your deployment container alongside the same environment variables.
To run the indexer/API in production mode without dropping tables, use the dedicated script:
pnpm startThis executes dotenv -e .env -- ponder start with DATABASE_SCHEMA=prod, which keeps existing database state intact and simply continues syncing.
- Health check:
GET /→{ "status": "ok" } - Market history:
GET /market/:chainId/:address?interval=hourly|daily|weekly- Returns
{ priceHistory, volumeHistory, liquidityHistory }. Each array contains{ timestamp, value }pairs aligned to the requested interval. Volume is a rolling 24h window when the interval is set to hourly. Otherwise, it's the volume per interval. - Invalid chain IDs or addresses return
400thanks to Zod + viem checksum validation.
- Returns
Example request:
curl "http://localhost:42069/market/56/0x43C3EBaFdF32909aC60E80ee34aE46637E743d65?interval=daily"- Schema changes: When you alter
ponder.schema.ts, restartpnpm dev; Ponder handles migrations automatically. - RPC throttling: Use a dedicated archive node URL; public endpoints often fail to serve the deep history required by SRG20 tokens.
- Auto-discover token metadata (name, symbol, decimals) directly from contracts instead of relying on
.envJSON. - Add caching (e.g., Redis) to reduce load for repeated market queries.
- Provide pagination/filtering endpoints for raw trades to complement the aggregated history.
- Implement integration tests that spin up a Postgres container and replay a small SRG20 fixture to guard against handler regressions.
- Ship a Dockerfile so the full stack can be built and deployed without relying on global pnpm/Node installations.
- Store supported tokens in the db and add an admin API to administer them.
- Add a /tokens endpoint in the API.
- Restrict time window on the API to avoid clients fetching the whole history which can leave to heavy resources usage on the API.
- Add an endpoint to return latest values instead of historical ones.