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 adeadline and a mandatory recipient.
Quote-token (ERC-20) entries — approve the launch first:
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:
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.recipientredirects only the proceeds.
Quoting
On-chain views on each launch:quoteBuy/quoteSellreturn zeros instead of reverting outside theTradingphase — treat(0,0)as “not tradable”, not as a price.quoteBuyWithNativeis notquoteBuy(nativeIn / divisor): native→quote truncation is returned as dust in native units. Use the native quoter for native trades.
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.