Architecture
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
humans ─► │ Web app │ │ SDK (TS) │ │ MCP server │ ◄─ agents
│ Next.js │ │ packages/sdk │ │ packages/mcp │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ fetch /api/v1 │ fetch /api/v1 │ fetch /api/v1
▼ ▼ ▼
┌─────────────────────────────────────────────────────┐
│ REST API (src/app/api/v1/*) — JSON envelope, │
│ validation, rate limit, consistent errors │
└──────────────────────┬──────────────────────────────┘
▼
┌─────────────────────────────────────────────────────┐
│ Pons data layer (src/lib/pons) │
│ reads.ts launch index, provenance, token/curve │
│ reads, trades, portfolio, launches │
│ prepare.ts quotes, prepare buy/sell/launch/ │
│ claim/sweep, simulate, integrity │
│ quote.ts pure curve math (shared w/ browser) │
│ addresses/abis verified contracts + ABIs │
└──────────────────────┬──────────────────────────────┘
▼
viem public client (official RPC → optional fallbacks,
retry, 4-way concurrency gate, Multicall3 batching)
▼
Robinhood Chain (4663) · Pons V2
Browser signing path (never server-side):
TxFlow → POST /prepare/* → preview + allow-list check
→ WalletProvider.sendPrepared → selected EIP-6963 provider
→ receipt via OpenPons RPC → verify
Key decisions
- No indexer, no database. Everything is derived from chain state and logs at request
time, with small in-process caches (
globalThis.__openpons):- A rolling launch index of the last 150k blocks (about 4 h), refreshed incrementally.
- A background backwards scan of
LaunchSweptlogs for graduated tokens. - Immutable token metadata is cached forever; curve state for 10 s.
- Provenance by registry. A token counts as a Pons token only if
factory.getLaunchedToken(token).existsholds and the token matches. Lists built from factory events are provenance by construction. - Quotes use the verified curve formula (buy: fee/tax/snipe then constant product with a
virtual reserve; sell: constant product then fee/tax). They are checked wei-exact against
eth_call. - Prepare = simulate.
simulateContractfrom the user's address; custom errors are decoded from the verified ABIs. A sell without allowance is simulated with aneth_callstate override of the OZ_allowancesslot, and flagged as such. - Integrity pin. Factory and router runtime codehashes must match the pinned values before any write is prepared.
- The server never signs. There is no key material anywhere in the codebase.
Rate-limit strategy
The public RPC returns 429 under bursts and caps eth_getLogs at 10k results. OpenPons:
- gates concurrency (4 server-side),
- batches reads via Multicall3,
- chunks log scans (50k blocks for launches, adaptive halving for Transfer scans),
- caches aggressively, and polls UI data at 12–20 s, only while the tab is visible.