The app
What lives where
Everything that decides who owns what lives on the chain and is read from there on every view: the price, the raise, the fees, whether a token graduated, what a wallet holds, what it is owed. The app never caches any of it in a column somebody could edit.
The app keeps what a chain is a bad place for: a token's description, its picture, its links, which Creora project it was launched for, and who launched it. It also keeps a copy of each launch's trade events, so a tape is read forward from the last block it saw rather than from block zero every time. That copy is a cache of the chain's own events; nothing in it is ever edited, and a row the chain did not emit cannot exist.
A launch's identity is its gauge address on its chain. A row is written only after the creation transaction confirms, and only after the server has asked the Launchpad who created the token and compared that to the wallet on the session. No field in the request can name the creator.
Configuration
Two addresses, both public facts the moment the first launch happens.
LAUNCHPAD_ADDRESSandNEXT_PUBLIC_LAUNCHPAD_ADDRESS: the Launchpad. Without it the launchpad is off everywhere and every surface says so.SWAP_ROUTER_ADDRESSandNEXT_PUBLIC_SWAP_ROUTER_ADDRESS: the swap router. Without it the token page sends people to Uniswap's site after graduation.LAUNCH_CHAIN_IDandNEXT_PUBLIC_LAUNCH_CHAIN_ID: 46630 for the testnet, 4663 for mainnet. One chain at a time.LAUNCH_RPC_URL: the endpoint the server reads through. The public endpoints are rate limited.
The gauges, the curve, the registry, the referral contracts, Uniswap's PoolManager and PositionManager are all read off the contracts themselves.
Pages
/tokens. Every launch, newest first, with sort tabs and, for a signed in visitor, a Mine tab. Public./tokens/<id>. One token: the chart, the tape, the holders, the facts, and, for a signed in visitor, the trade box and the reward card. Public. Live: the page opens a server sent event stream and receives every new block's figures; where that cannot be opened it polls./tokens/new. The launch form. Needs a signed in wallet./tokens/referrals. Register a referral code, see what it has earned, withdraw. Needs a signed in wallet./tokens/admin. The launchpad's settings. Anybody signed in can look; only the owner's wallet gets buttons.
Endpoints
GET /api/launches. The list.?mine=1narrows to the caller's own;?state=0skips the chain reads.POST /api/launches. Records a launch that already exists on the chain. Checked against the session.GET /api/launches/launchpad. The launchpad's own figures and addresses.?fresh=1skips the short cache.GET /api/launches/referrals?address=. One address's referral code and earnings.PUT /api/launches/image. Stores a token's picture ahead of the launch, unclaimed. Recording the launch claims it; an unclaimed picture is swept after a day.GET /api/launches/<id>. One launch with its live state.GET /api/launches/<id>/trades. Every trade, priced.GET /api/launches/<id>/holders. The largest holders and how many there are, from the token's own transfers.GET /api/launches/<id>/holdings?address=. What one address holds and is owed.GET /api/launches/<id>/stream. Server sent events: one per new block, carrying the launch and its trades.
Everything under /api/launches that only reads is public, because everything it answers is on the chain for anyone to read.
How trades are priced
The curve's events carry the price the curve stood at before each trade. A trade's closing price is therefore the next trade's starting price, exactly, because the curve moves only when somebody trades. The last trade closes at the curve's price now, or, once the curve has closed, at the price the pool opened at. Pool swaps carry their own closing price in the event. The chart draws candles from those closing prices; the facts card and the pool agree with it.
What the browser signs
Every transaction is built in the browser from a short, hand written slice of each contract's interface, in src/lib/launch/abi.ts, and signed by the person's own wallet. Creation, buys and sells go to the Launchpad; a trade by somebody who arrived through a referral link goes to the referral router once, with the code, and the chain remembers the referral from then on. Pool swaps go to the swap router. The creator's reward is claimed from the gauge. The LP receiver collects the pool's fees through Uniswap's PositionManager. The owner's settings go to the Launchpad and the registry.
Every trade carries a floor two percent under a live quote, so a transaction that lands after somebody else's cannot fill at a worse price than the one shown. Pool swaps carry a ten minute deadline as well.
One rule about numbers
A promise a server component awaits must never resolve to a BigInt. React's development build records every awaited value with JSON, which throws on a BigInt and takes the page's hydration with it. So every chain read turns its numbers into strings at the call, and the arithmetic is done on strings turned back into BigInts afterwards. Production carries no such instrumentation, which is why this only ever bit in development.