Operations

The web app


Next.js 16 (App Router), bun, dev server on port 3000 (the Privy app allows only localhost:3000 and the production domain). The app runs on Solana mainnet only; the RPC URL is MAINNET_RPC_URL in .env.local (or the host's environment).

Transaction flow

  1. The client asks a server route to build a transaction for the connected wallet.
  2. The server builds it with the vendored tender SDK (app/lib/tender, synced from ~/tender/sdk/solana by scripts/sync-tender-sdk.sh), simulates it, and returns base64. Where a fresh keypair must sign (a new NFT asset, a new mint), the server pre-signs.
  3. The wallet signs (Privy useSignTransaction, chain solana:mainnet).
  4. The client posts the signed transaction to a send route; the server relays and polls to confirmation.

Routes

RoutePurpose
GET /api/options/[mint]options view: call ladder quotes per tenor, puts, balances, positions, listings
POST /api/options/[mint]/txbuild: buyCall (tenor, amount, strikeMcapUsd), buyPut, exercise, cashOut, claim, deposit, withdraw, collect, listCall, updateListing, cancelListing, buyListing
POST /api/options/sendrelay
GET /api/launch/buildstake options table (5% to 10% in 0.5% steps) from the pump.fun curve
POST /api/launch/buildsetup: backer pool and lookup table transactions for the mint (fresh from the browser, or "reserved" for the owner's server-held mint, owner wallet only), stake and dev-buy caps
POST /api/launch/sendrelay one setup transaction (waits a slot after the last so the table is live)
POST /api/launch/finalthe launch, open calls and the dev buy on a fresh blockhash (Jito tip included)
POST /api/launch/bundlesend the three wallet-signed transactions: the launch first with preflight, then open calls and the dev buy (a Jito bundle only with POC_USE_JITO=1); waits for the launch
POST /api/launch/metadataupload image + metadata to pump.fun IPFS; the launch is refused if it fails
GET /api/portfolio/[owner]every position across all vaults with value, paid, P/L
GET /api/marketsEstablished Tokens and every launch vault
GET /api/vault/[mint]put and launch vault state
GET /api/swap/[mint], POST /api/swap/[mint], POST /api/swap/sendspot quotes and swaps: Jupiter; a coin Jupiter has not indexed yet trades on its pump.fun curve or PumpSwap pool
GET /api/token/[mint]/activity, /candlestrades, holders, chart candles

Metadata on IPFS

/api/launch/metadata forwards the image, name, symbol, description and links to https://pump.fun/api/ipfs and puts the returned metadataUri on chain. The launch is refused if the upload fails. Because ipfs.io no longer serves files to applications, the app reads any /ipfs/<cid> link through pump.mypinata.cloud (ipfsGateway in app/lib/options/server.ts).

Pages

/markets (Explore), /t/[mint] (token page with chart and options terminal), /launch, /portfolio, /vault/[mint], /vaults, /marketplace, /watchlist. Shared header (AppHeader, links from app/lib/site-nav.json): Docs, Twitter, Explore, Launch, Vaults, Marketplace, Portfolio.

Data sources

Token data: POC API, then Dexscreener, then chain reads. GeckoTerminal serves candles for tokens not launched on POC (throttled).

Trade indexer (coins launched on POC)

Every coin launched on POC has its chart, trades tab and 24h figures from POC's own indexer (app/lib/indexer/), not from any third party:

  • What it reads: each swap on the coin's pump.fun bonding curve (the curve's token balance and its SOL) and, after graduation, on its PumpSwap pool (the pool's token and wSOL balances), straight from Solana transactions. Creation, migration and fee moves are not swaps and are skipped.
  • Which coins: every launch vault of the launch program, found automatically every minute, with its whole history from the launch transaction on.
  • Live: a background loop in the web server (instrumentation.ts) reads new transactions every 3 seconds.
  • Storage: SQLite on the server at .data/indexer.sqlite (one row per swap).
  • Dollars: each trade is priced with SOL/USD at its own minute (Coinbase SOL-USD 1-minute closes, Binance SOLUSDC as a fallback), stored alongside.
  • Hosting: its own service at https://indexer.poc.money (a small Ubuntu server; systemd restarts it on crash and reboot, Caddy serves HTTPS). The site on Vercel reads it through INDEXER_URL. Deploy or update: SERVER=root@<ip> SSH_KEY=~/.ssh/poc_indexer DOMAIN=indexer.poc.money bash indexer/deploy/deploy.sh. Caches with last-good fallback protect against RPC rate limits.