Skip to main content
All trading happens on the launch clone — resolve it once via factory.launchOf(token). There is no router: approvals go to the launch itself, and no function takes a token argument.

The four entry points

Two payment shapes, four distinct selectors — not overloads. All take a deadline and a mandatory recipient. Quote-token (ERC-20) entries — approve the launch first:
Native entries — only where the launch accepts native (acceptsNative()):
buyWithNative has no amountIn — the amount is msg.value.

Units — read this twice

Everything is denominated in the quote token’s own decimals: amountIn, minAmountOut on sell, quotes, reserves, event amounts. One exception, deliberate:
sellForNative’s minAmountOut is denominated in the NATIVE coin, because that is the unit the caller receives. On a chain whose quote has 6 decimals and whose native view has 18, mixing the two is a silent 10¹² error, not a revert.
minTokensOut is always in launch-token units (18 decimals).

Recipient and refund semantics

  • Buys: tokens go to recipient; any refund goes to the payer (msg.sender). Only the curve-completing buy refunds — it takes exactly what is left on the curve and returns the overshoot (native refunds come back unwrapped, plus any sub-unit dust).
  • Sells: tokens always come from msg.sender — the transfer gate means nobody can hold pre-graduation tokens on another’s behalf. recipient redirects only the proceeds.

Quoting

On-chain views on each launch:
  • quoteBuy/quoteSell return zeros instead of reverting outside the Trading phase — treat (0,0) as “not tradable”, not as a price.
  • quoteBuyWithNative is not quoteBuy(nativeIn / divisor): native→quote truncation is returned as dust in native units. Use the native quoter for native trades.
Reproducing the curve off-chain costs no RPC per quote once you hold the state. The curve is constant-product over virtual reserves:
The buy that would exceed the remaining curve supply takes exactly what is left and refunds the overshoot (fees recomputed on the gross actually needed, rounding up). Read reserve() and sold() from storage and the constants (virtualQuote, virtualToken, curveSupply, tradeFeeBps, nativeDivisor) from config() — the interface deliberately omits them, so bind the concrete ABI.

Errors you will hit

The frozen window is a real state: between the curve filling (CurveCompleted) and someone calling graduate(), all four entries revert WrongPhase(). Surface it distinctly — the token is neither tradable on the curve nor on the exchange yet. Factory creationPaused never affects trading on existing curves.