Understanding what happens when a token graduates from the bonding curve to the PumpAMM pool.
When enough SOL has been deposited into a bonding curve, the token "graduates" — it migrates from the bonding curve to a constant-product AMM pool (PumpAMM). This happens automatically when the bonding curve fills up.
After migration:
bondingCurve.complete === true- Trading happens on the PumpAMM pool instead of the bonding curve
- The token becomes tradeable on standard DEX interfaces
import { Connection, PublicKey } from "@solana/web3.js";
import { OnlinePumpSdk } from "@pump-fun/pump-sdk";
const connection = new Connection("https://api.devnet.solana.com", "confirmed");
const onlineSdk = new OnlinePumpSdk(connection);
const mint = new PublicKey("YOUR_TOKEN_MINT_ADDRESS");
const bondingCurve = await onlineSdk.fetchBondingCurve(mint);
if (bondingCurve.complete) {
console.log("Token has graduated to PumpAMM!");
console.log("Bonding curve is now closed.");
} else {
console.log("Token is still on the bonding curve.");
console.log("Real SOL collected:", bondingCurve.realSolReserves.toString());
}Migration is triggered by a permissioned authority. The SDK provides migrateInstruction:
import { PUMP_SDK } from "@pump-fun/pump-sdk";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
// Only the withdraw authority can call this
const migrateIx = await PUMP_SDK.migrateInstruction({
withdrawAuthority: withdrawAuthorityPubkey,
mint: mintPubkey,
user: userPubkey,
tokenProgram: TOKEN_PROGRAM_ID,
});- Remaining tokens from the bonding curve are moved to a PumpAMM pool
- Collected SOL is deposited as the other side of the AMM pair
bondingCurve.completeis set totrue- A new pool account is created at the canonical PDA
import { canonicalPumpPoolPda, pumpPoolAuthorityPda, bondingCurvePda } from "@pump-fun/pump-sdk";
const mint = new PublicKey("YOUR_MINT");
// The bonding curve (still exists, but complete = true)
const bc = bondingCurvePda(mint);
// The AMM pool address
const pool = canonicalPumpPoolPda(mint);
// The pool authority (owns the pool's token accounts)
const poolAuth = pumpPoolAuthorityPda(mint);
console.log("Bonding curve:", bc.toBase58());
console.log("AMM pool:", pool.toBase58());
console.log("Pool authority:", poolAuth.toBase58());After migration, use the PumpAMM SDK (@pump-fun/pump-swap-sdk) for trading:
import { OnlinePumpAmmSdk } from "@pump-fun/pump-swap-sdk";
const ammSdk = new OnlinePumpAmmSdk(connection);
// Use the AMM SDK for buy/sell operations on graduated tokensimport { OnlinePumpSdk, bondingCurvePda } from "@pump-fun/pump-sdk";
import { Connection, PublicKey } from "@solana/web3.js";
async function getTokenState(mint: PublicKey) {
const connection = new Connection("https://api.devnet.solana.com", "confirmed");
const onlineSdk = new OnlinePumpSdk(connection);
try {
const bc = await onlineSdk.fetchBondingCurve(mint);
if (bc.complete) {
return {
state: "graduated",
message: "Trading on PumpAMM pool",
creator: bc.creator.toBase58(),
};
}
if (bc.virtualTokenReserves.isZero()) {
return {
state: "migrated",
message: "Fully migrated, bonding curve empty",
};
}
return {
state: "active",
message: "Trading on bonding curve",
realSolReserves: bc.realSolReserves.toString(),
realTokenReserves: bc.realTokenReserves.toString(),
creator: bc.creator.toBase58(),
};
} catch {
return { state: "not_found", message: "Token not found on Pump" };
}
}
const state = await getTokenState(new PublicKey("YOUR_MINT"));
console.log(state);