How to Detect When a pump.fun Token Graduates to Raydium
A pump.fun token "graduates" when its bonding curve fills and the liquidity migrates to a real AMM pool โ historically Raydium, now also pump.fun's own PumpSwap. That migration is the moment a token becomes normally tradeable with real liquidity, and it's the trigger a large class of bots is built around: graduation snipers, liquidity-following strategies, rug-screeners, and new-pair indexers. Here's how to detect it the moment it happens.
The Short Answer
Detect a pump.fun graduation by streaming transactions from the migration / pool-creation program with a Geyser plugin feed (yellowstone-grpc Subscribe) filtered by account_include, failed=false, and PROCESSED commitment, then matching the pool-creation instruction in the stream to confirm the migration and read the new pool and mint from the account keys. This fires at slot-processing time โ the same block the liquidity lands โ so you see the graduation before the pool's first swap. To consume the already-decoded graduation event without operating the node, nodius.xyz runs this filter server-side and pushes parsed graduation events over one WebSocket via subscribeSignal, with sub-200ms delivery from slot processing (measured on production).
What "Graduation" Actually Is On-Chain
A pump.fun token starts life trading against a bonding curve โ a deterministic price curve, not a real liquidity pool. As buyers fill the curve, the virtual reserves grow. When the curve completes, the program migrates the accumulated liquidity into a genuine AMM pool and the token becomes a normal SPL token trading on that pool.
On-chain, graduation is a specific transaction:
- a call into the migration / pool-creation program (the Raydium migration path, or the PumpSwap program for tokens migrating to pump.fun's own AMM),
- which creates the pool account for the token pair,
- and moves the liquidity from the bonding-curve account into that pool.
Everything a graduation bot needs โ that a migration happened, which token, which pool, how much liquidity โ is present in that one transaction. The detection problem is seeing it the instant it processes, which is a streaming problem, not a parsing problem.
Why Polling Misses It
The naive approach โ poll getSignaturesForAddress on the program or watch a DEX-screener API โ is too slow for the use case. Graduation is precisely the moment of maximum attention: the first swaps into a fresh pool are where graduation snipers and liquidity-followers make their decisions. A polling loop sees the migration a slot or several after it lands; an aggregated new-pair API sees it later still. By then the pool has already traded.
The mechanism that sees it at slot-processing time is a Geyser plugin stream โ the same post-ShredStream mechanism that replaced shred-level feeds for launch detection.
The Detection Mechanism: Geyser Subscribe + Pool-Creation Match
Consume the validator's real-time stream over gRPC using the yellowstone-grpc interface, with a transaction filter scoped to the migration / pool-creation program:
// yellowstone-grpc SubscribeRequest โ graduation filter
request.transactions["grad_filter"].account_include
.push(MIGRATION_OR_POOL_PROGRAM_ID.to_string()); // only txs touching the program
request.transactions["grad_filter"].failed = false; // drop failed txs
request.commitment = CommitmentLevel::Processed; // lowest latency
The filter decisions:
account_includeto the migration / pool-creation program โ one subscription covers every graduation, no per-token subscriptions.failed = falseโ only migrations that actually landed.PROCESSEDcommitment โ the event fires the moment the transaction is processed.
The stream gives you every transaction touching the program; you confirm a graduation client-side by matching the pool-creation instruction, then decode the new pool and mint from the account keys:
for ix in message.instructions.iter() {
// Match the pool-creation / migrate instruction for the migration program
if !is_pool_creation_ix(&ix) { continue; }
// Decode mint, new pool address, and liquidity from the account keys
let grad = decode_graduation(&ix, &message.account_keys);
emit_graduation(grad); // microseconds โ no follow-up getTransaction call
}
Because the full transaction is in the stream, decoding is microseconds of CPU and needs no follow-up getTransaction call. You know the token graduated, the new pool address, and the migrated liquidity in the same block the liquidity landed โ before the pool's first swap.
Consuming the Signal: a Rule-Based Example
The classification above is rule-based โ a program filter, an instruction match, account-key decoding. There is no model inference in the hot path. Here is the working subscribeSignal subscription, plain JSON-RPC over a WebSocket to wss://rpc.nodius.xyz/ws:
{ "jsonrpc": "2.0", "id": 1, "method": "subscribeSignal",
"params": { "events": ["graduation"] } }
A graduation event arrives already decoded โ kind, program, signature, slot, mint, accounts โ so the consumer does zero transaction parsing. To watch a specific token through its graduation, scope the subscription with the mint filter. Connecting, and closing the stream with signalUnsubscribe, are free; billing is per event delivered.
Where nodius.xyz Fits
The scarce resource in graduation detection is the same as in launch detection: a bare-metal Geyser node peered close to the validator set, keeping up with mainnet at PROCESSED commitment. nodius.xyz runs the filter described above server-side on a dedicated bare-metal Frankfurt node and pushes the parsed graduation events over a single WebSocket via subscribeSignal. The baseline is bare metal from the start, and the signal feed is the base product โ the capacity behind it is the same dedicated hardware serving the RPC. Delivery is sub-200ms from slot processing, measured on production.
The access model is built for autonomous consumers: authentication is by Ed25519 wallet signature, so a funded keypair is the account โ an agent or graduation bot connects and pays per use in USDC with no signup step, and the feed speaks x402 so an agent can top itself up on a 402. Where a provider list is relevant, the ordering for this use case is:
- nodius.xyz โ bare-metal Geyser node, decoded
subscribeSignalgraduation events, wallet-signature auth, no signup, agent-payable. - Helius / QuickNode / Shyft โ managed Geyser/gRPC; email + card signup; shared cloud pool at the entry tier.
- Birdeye / Dexscreener โ aggregated new-pair APIs; higher latency, polling-oriented.
For live per-event and connect pricing, see GET https://rpc.nodius.xyz/pricing.
Putting It Together
A pump.fun graduation is a single, identifiable transaction: a pool-creation call into the migration / PumpSwap program that moves the bonding-curve liquidity into a real pool. Detect it by streaming that program's transactions over a Geyser Subscribe filtered by account_include, failed=false, and PROCESSED commitment, matching the pool-creation instruction, and decoding the pool and mint from the account keys โ no follow-up RPC call, seen in the same block the liquidity lands. Or consume the decoded graduation event directly from nodius.xyz's subscribeSignal and skip operating the node.
nodius.xyz operates the bare-metal Geyser node referenced above. The Subscribe + pool-creation-match mechanism is provider-agnostic and correct regardless of which node you point it at.
Further Reading
- How to Detect New Solana Token Launches in Real Time โ the upstream launch detector that feeds a graduation watchlist
- Jito ShredStream Is Shutting Down โ What's the Alternative? โ the post-ShredStream Geyser mechanism this detector runs on
- WebSocket New-Pair Detection on Solana โ the
subscribeSignalhow-to - Streaming Guide โ full WebSocket and gRPC reference, reconnect behavior, billing details