# Trading the curve

Before graduation the only venue is the launch's own bonding curve. It has no fixed address —
read it from `factory.getLaunchedToken(token).curve`.

Approve **the curve** for both legs: the quote asset to buy, the memecoin to sell.

## The two slippage bounds are not the same kind of bound

This surprises people, and it is deliberate.

**On a buy, `minTokensOut` is a price bound.** A buy that would take more than the remaining
allocation is *clamped* rather than reverted — you get the remaining tokens and the unspent
quote is refunded to `msg.sender` in the same transaction. The bound is then enforced as an
implied price rather than a quantity, so a partial fill at an acceptable price succeeds.

That means **you can safely overshoot the graduation threshold**. Sending more than the curve
can absorb is normal and costs nothing.

**On a sell, `minQuoteOut` is a strict quantity bound.** You get at least that much or the
call reverts.

## The sell side closes early

A sell reverts with `CurveGraduated` as soon as `readyToGraduate()` becomes true — which is
*before* the `graduated` flag is set and before anyone has called `graduate`.

So there is a window where the curve looks live, `graduated` is still false, and every sell
reverts. If your UI reads `graduated` to decide whether selling is possible, it will offer a
button that cannot work. Read `readyToGraduate()` too.

## Referrals

The four-argument `buy` overload takes a referrer:

```solidity
function buy(uint256 quoteIn, uint256 minTokensOut, address recipient, address referrer)
```

Three things to know:

- The binding is written for **`recipient`**, not `msg.sender`.
- It is consulted only on that address's **first** referred trade, and is permanent after
  that. Passing a fresh referrer later cannot poach an existing relationship.
- **A bad referrer reverts the whole buy.** `SelfReferral` and `ReciprocalReferral` are not
  swallowed. Validate before you put an address in the call — particularly if it came from a
  URL parameter.

`sell` has no referrer argument; only an existing binding applies.

Users can also bind themselves ahead of any trade with
`referralRegistry.setReferrer(address)`.

## Quoting

Off-chain, the curve is constant product against a virtual reserve:

```
netIn     = quoteIn - fee - creatorTax          // fees come off the QUOTE leg
tokensOut = netIn * tokenReserve / (quoteReserve + netIn)
```

where `quoteReserve = phantomQuote + trackedQuote - quoteFeeBalance - creatorTaxBalance`,
available together from `getReserves()`.

Note `getReserves()` returns the **virtual** quote reserve, which includes the phantom
reserve. For the amount actually raised — what a progress bar should show against the
threshold — use `realQuoteReserve()`.

Once a launch graduates the curve is closed and estimates must come from the Uniswap V4
Quoter instead. See [Trading the pool](/documentation/pool).