Skip to content

Migration to PumpSwap

A pump.fun-launched token spends the first part of its life trading on a bonding curve — a price-discovery automaton owned by the pump.fun program. Once enough SOL has flowed in to fill the curve, the curve graduates: liquidity moves to a permanent PumpSwap pool (an AMM), and trading continues there forever after.

Moono Protocol treats this transition as a first-class concept. Every Moono operation — loan buys/sells, MTrade buys/sells, liquidation — works identically before and after graduation, because the universal instructions detect curve state on-chain and route to the right backend.

When the bonding curve’s real_sol_reserves field reaches pump.fun’s Global.threshold constant:

  1. The curve account flips its complete flag to true. No more buys can hit the curve.
  2. Pump.fun’s migrate instruction can be called to:
    • Create a PumpSwap pool for the token
    • Mint LP tokens to the pool authority
    • Transfer the curve’s accumulated SOL and base tokens into the pool’s vaults
  3. After migration, all trading goes through PumpSwap’s AMM (pumpswap.buy, pumpswap.sell).

The migration is one-shot per token. After it happens, the curve is sealed and the pool is live.

Moono allows curve graduation in exactly one place in the loan flow — the cap-aware initial buy inside launch_0. Outside of that, all other Moono buy ix’s reject mid-flow graduation with BuyWouldGraduateCurve.

This gives the frontend a single, deterministic graduation point. The cost: pre-flight has to plan every bundle so no bundle buy or user buy would accidentally cap the curve.

Scenario A — All-pre-grad (no migration during your loan flow)

Your launch’s total demand fits comfortably below the graduation threshold. launch_0 doesn’t cap the curve. launch_migrate_0 and launch_complete_0 are submitted as part of the entry bundle but execute as cheap no-ops. All subsequent loan-flow buys and user buys stay on the bonding curve.

Scenario B — Cap-path (migration as part of your launch)

Your Initial Buy Amount is large enough to cap the curve. The entry bundle:

  1. launch_0 — graduates the curve (pump.fun automatically caps the buy at the threshold; the leftover SOL stays on the loan as initial_quote_buy_remaining)
  2. launch_migrate_0 — calls pump.fun.migrate to create the PumpSwap pool and pumpswap.extend_account to upgrade the pool to the latest layout
  3. launch_complete_0 — spends initial_quote_buy_remaining on PumpSwap via pumpswap.buy_exact_quote_in
  4. bundle_buy_universal_0 × N — bundle buys, now routed to PumpSwap
  5. buy_exact_quote_in_market_universal_0 — your user buy, also on PumpSwap

The whole sequence is atomic (one Jito bundle if enabled). For details on the pre-flight check and gray-zone rejection, see the Borrower Guide → Step 5.

Scenario C — External graduation during your loan

You launched in all-pre-grad mode, but other traders pumped the curve over the threshold while your loan was open. The next time you (or anyone) operates on this token through Moono, the universal ix detects BondingCurve.complete == true and routes to PumpSwap.

If pump.fun’s migrate hasn’t been cranked yet — pool doesn’t exist on PumpSwap — the buy or sell would fail. To cover this, Moono’s exit bundle (repay or liquidate) starts with a defensive launch_migrate_0. It’s idempotent: a no-op when the curve isn’t complete, a no-op when the pool already exists, and a crank when both conditions trigger.

You don’t need to do anything manually. The app inserts this defensive migrate automatically on every exit.

In MTrade (the standalone trading terminal), graduation is not bound to any specific user action. If you open a token whose curve has completed but no PumpSwap pool exists yet, the page shows a Migrate banner:

Bonding curve is ready to be migrated to PumpSwap. Anyone can trigger it now.
[Migrate]

Anyone can click it. The caller pays for the migration — roughly ~0.05 SOL in rent for the new accounts (pool, lp_mint, pool ATAs) plus compute fees — and after the tx lands, MTrade trades on that token start routing to PumpSwap.

The on-chain handler (mtrade_migrate_0) is the same one the loan flow uses (launch_migrate_0). Same instruction, same idempotent behaviour — calling it twice or unnecessarily is safe.

For a single token, post-graduation:

AspectPre-gradPost-grad
Buy/sell venuepump.fun bonding curvePumpSwap AMM pool
Price discoveryCurve formulaConstant-product AMM
Moono instructionSame universal ix, pump branchSame universal ix, PumpSwap branch
ALTSame per-token ALTSame per-token ALT (already includes PumpSwap addresses)
Slippage behaviourCurve curvature dominatesPool depth dominates
FeesPump.fun fee recipientsPumpSwap protocol/buyback fee recipients

The ALT is the key UX point: derive both branches once when you first interact with the token, and you’re set for life. Moono’s bundle ALTs and MTrade per-token ALTs both follow this rule.

ActionWho paysApprox cost
Cap-path migrate during launch_0Borrower (paid from the launch overhead and bundled into the entry tx)~0.05 SOL for pool/lp_mint/ATA rent + CU
Defensive migrate in exit bundleCaller of repay/liquidate (you) — but it’s a no-op unless an external graduation happened~0 SOL on the no-op path
Crank an external token’s migration via MTrade mtrade_migrate_0Caller (anyone)~0.05 SOL + ~1M CU

Rent is recoverable indirectly (it lands on pool accounts) — the practical cost is mostly the upfront capital that gets locked into the pool’s accounts. Moono itself takes no fee for migration.

Both launch_migrate_0 and mtrade_migrate_0 are idempotent:

  • If the curve hasn’t graduated: fast no-op return
  • If the curve has graduated but no pool exists: full migrate CPI
  • If the curve has graduated and a pool exists: skip migrate, run extend_account (also idempotent)

You can call them anywhere it’s convenient — at worst it costs a few thousand CU.

Frontend doesn’t need to detect graduation

Section titled “Frontend doesn’t need to detect graduation”

For developers building on Moono: you don’t need to read BondingCurve.complete off-chain to decide which ix to send. The universal ix’s read it on-chain. Build the tx with both branches in remaining_accounts, pass the same shape every time, and the handler picks the live branch at execution. This eliminates a race window between off-chain read and on-chain landing.

See the IX reference in the moono-solana repo for the full account layout.

The Migrate button on MTrade is most useful when:

  • You want to trade a token whose curve completed but nobody migrated yet — you can’t buy/sell until the pool exists
  • You’re a bot operator who wants to crank migrations as a public service (no protocol reward, but it unlocks trading for that token)

If a token doesn’t have a Migrate banner on MTrade, the migration is either not needed (curve still active) or already done (you’re already trading on PumpSwap).