> For the complete documentation index, see [llms.txt](https://docs.surged.fun/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.surged.fun/integration/graduation.md).

# Handling graduation

A curve is not forever. Once it has collected enough real USDC, the token leaves the curve and moves into a Uniswap pool. On Surged today the threshold is **12,000 USDC**, and `launch.progressBps` tells you how close a token is: 10,000 means it is there.

## What happens

1. **The last buy crosses.** When a buy would take more tokens than are left, the curve sells exactly what remains, charges only what those cost and refunds the difference. `previewBuy` tells you this is about to happen through `quote.crossing` and `quote.refund`, so you never send more than the curve can fill.
2. **The curve closes.** No more buys, no more sells. `phase` moves off `curve`.
3. **The pool opens.** The collected USDC and the reserved tokens go into a Uniswap v3 pool, and the liquidity position is locked forever. Nobody can pull it, not the creator and not us.
4. **`phase` becomes `pool`.** `launch.graduation.pool` is the pool address from then on.

Step 3 runs by itself when the crossing buy has enough gas left. If it does not, a keeper picks it up within seconds; `graduationPending` is `true` in that gap.

## What an integration must do

**Stop quoting against the curve.** `previewBuy` and `previewSell` throw `CurveGraduated` once the state says so, but a client that caches the launch for a minute can try to trade a curve that closed. Check `phase` before trading, and treat a `CurveGraduated` revert as "refresh and go to Uniswap", not as an error to retry.

**Follow the pool.** Once `phase` is `pool`, the price no longer comes from the formula in this package; it comes from the Uniswap pool at `graduation.pool`. The api keeps serving the token's history, but new trades happen on Uniswap and are not ours to report.

## Watching for it

The realtime feed pushes a `phase` message the moment a launch moves, so you do not have to poll:

```ts
const ws = new WebSocket(`${WS}/ws`)
ws.onopen = () => ws.send(JSON.stringify({ subscribe: [`token:${token}`] }))
ws.onmessage = (e) => {
  const m = JSON.parse(e.data)
  if (m.type === 'phase' && m.phase === 'pool') stopTradingTheCurve()
}
```

See [Realtime feed](/integration/api/realtime.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.surged.fun/integration/graduation.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
