Skip to main content
This walkthrough takes a launch from creation to its locked Uniswap v4 pool using @launchpad/abis and viem, with cast equivalents where they are short. Addresses are Robinhood Chain (4663); swap in another chain’s addresses for the testnets. Every amount convention used here is defined in Units.

Setup

packages/abis/deployments/<chainId>.json is written by the deploy script; the same data is served at https://windrose.market/api/deployment?chainId=4663. Gas: the registry’s gas field gives maxFeeGwei / priorityGwei to spread into writes (Arc needs at least 20 gwei; Robinhood Chain is happy with the defaults).

1. Read the currency

keeperFxOracleAbi from @launchpad/abis has peekRate and rate too; the inline ABI above works against any IFxOracle.

2. Create a launch

A launch needs a name, a symbol, a metadata URI, the currency code and, optionally, the creator’s first buy (initialIn). With payInUsdc = true on a synthetic currency the factory mints the synthetic from dollars inside the call; otherwise initialIn is in the quote asset. To set minTokensOut for that first buy, reproduce the curve maths off-chain from the factory config and the oracle rate (the curve does not exist yet):
Skip the first buy with initialIn = 0 and minTokensOut = 0 (no approval needed). A EUR launch on Arc pays its first buy in EURC with payInUsdc = false.

3. Quote and trade on the curve

Read the curve state once and keep it fresh from events or polling:

Buy with dollars (any synthetic launch, or a USD launch)

Buy with the quote asset (wINR held in the wallet, or EURC)

Sell

The last buy before graduation is capped: the router returns the untaken part in the asset you paid with. Quotes revert with StalePrice on the dollar paths when the oracle rate is older than 5 days; the quote-asset paths never touch the oracle. Full semantics: Router.

4. Detect readiness and graduate

ready() flips inside the buy that reaches graduationQuote (or sells out the curve) and ReadyToGraduate is emitted. The router immediately tries graduate(); if that inner call failed (graduated() still false while ready() is true), anyone can call it:
Graduated(poolId, positionTokenId, lpQuote, lpTokens, burned) records the pool id and the locked position. From then on buy, sell and the quote functions are closed; the creator can still claimCreatorFees and anyone can sweepProtocolFees.

5. Read the pool after graduation

The pool key is { currency0: min(token, quoteAsset), currency1: max(token, quoteAsset), fee: 3000, tickSpacing: 60, hooks: 0x0 }. poolId() on the curve is its id. StateView.getSlot0(poolId) returns sqrtPriceX96, which encodes sqrt(rawAmount1 / rawAmount0):
Swaps after graduation go through Uniswap v4 (the UniversalRouter or a direct PoolManager unlock); Windrose’s router only serves the curve phase. The locked position and fee collection are described in LiquidityLocker.

6. Follow events

For history (trades, candles, holders, rates) query the indexer instead of replaying logs: see the API and the Launches query. Chain reads are the source of truth for the current state; the app falls back to them whenever the indexer is unreachable.

Checklist for a correct integration

  • Never assume quote decimals: read quoteDecimals from the registry (6 for the dollar and EURC, 18 for synthetics).
  • Apply your own slippage to a fresh quote; the dollar paths have no oracle-side floor.
  • Pass [] and value: 0n for priceUpdate while the registry oracle is the keeper oracle.
  • Use timestamp deadlines, and on Arc bid at least 20 gwei.
  • Treat ready && !graduated as a state you may have to resolve yourself with graduate().
  • Fees accrue in the quote asset (wINR for an INR launch); claiming them does not convert to dollars.