Detecting a token launch in shreds, before the block exists
Launch detection on a deshredded transaction is a byte comparison, not a query. Resolve the program id, then read the leading bytes of the instruction data: PumpFun create carries an 8-byte Anchor discriminator, Raydium AMM v4 initialize2 carries a single tag byte that needs an account-count check beside it. Execution outcomes are not available at that point.
protocol desk · updated 2026-09-15
Everything else in this section explains how to turn UDP packets into transactions. This page is about the next problem: you have a VersionedTransaction in memory, the block it belongs to does not exist yet anywhere else, and you have perhaps two hundred milliseconds of advantage. What are you actually looking for?
We will use the two launches people care about most, a PumpFun token creation and a Raydium AMM v4 pool initialization, because between them they cover the two decoding situations you will meet everywhere else.
You are pattern-matching bytes, not calling an API
A deshredded transaction gives you the message: account keys, one instruction list, and raw instruction data. No logs. No inner instructions. No token metadata, no "parsed" view. Execution has not happened, so nothing execution produces is available. If your mental model of Solana data comes from getTransaction with jsonParsed, throw it away for this work.
What you have is enough, though. An instruction is three things: an index naming the program, account indexes, and a data buffer. Detection means checking the program id and then checking the first bytes of the data buffer.
PumpFun: an Anchor program, so the discriminator does the work
PumpFun's bonding curve program is 6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P. It is Anchor-based, which means every instruction's data buffer starts with an 8-byte discriminator derived from the instruction name. The create discriminator is a constant. Compute it once, hard-code it, and your detector is:
- Does any instruction's program id resolve to the PumpFun program?
- Do the first 8 bytes of that instruction's data match the create discriminator?
That is the whole test. Two comparisons per instruction. After the discriminator, the data buffer carries the name, symbol, and URI as Borsh-encoded strings, and the account list carries the mint and bonding curve at fixed positions. You can have the mint address of a brand-new token parsed and sized before any RPC in the world can return it, because the block it lives in has not been assembled anywhere but your process.
One caution: check the program id from the resolved key list, not by assuming a fixed account index. Transaction builders order accounts however they like.
Raydium AMM v4: no Anchor, so you match the instruction tag
Raydium AMM v4 (675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8) predates the everyone-uses-Anchor era. Its instructions are tagged with a single leading byte. Pool creation is initialize2, tag 1. So the test is the same shape but cruder: program id match, then data[0] == 1.
A one-byte tag will false-positive on garbage data if you only check the byte, so validate the account count too. initialize2 carries a long, fixed account list, and the AMM id, the two vaults, and the two mints sit at documented positions in it. If the instruction has the wrong number of accounts, discard it and move on.
This two-program pair is the general lesson. Anchor program: 8-byte discriminator, high confidence. Pre-Anchor program: short tag plus structural validation. Every other program you will ever want to detect falls into one of the two.
The lookup-table catch
Here is the part that surprises people. Version 0 transactions can load accounts through address lookup tables. The transaction carries the table's address and a list of indexes into it, not the addresses themselves. Resolving an index to a real address requires the table's on-chain state, and you are working pre-execution, without state.
For launch detection this matters less than you would fear. A create or initialize2 nearly always carries its important accounts statically, because the accounts are new and cannot already sit in a lookup table. But if you extend the same detector to swaps, Jupiter routes especially, you will hit transactions where the account you care about hides behind a table index. Your options are to maintain a warm cache of popular lookup tables from a normal RPC connection, or to accept that some fraction of matches resolve only after the fact. Most trading receivers do the cache.
What you still do not know
Seen-in-shreds is not landed. The transaction can fail at execution. The slot can be skipped. The same transaction can arrive again in the next leader's slot after a fork. A detector that fires a buy on every match, with no reconciliation, will eventually buy into a launch that never happened.
The practical pattern is act-then-confirm: act on the shred-level signal, then reconcile against slot completion and a confirmed-commitment source, and unwind or retry when they disagree. How often that happens, and what it costs when it does, is its own topic, and it gets its own page.
In practice
A transaction arrives in the deshredded stream for a slot that no RPC has yet returned. It carries four instructions. The detector walks the resolved key list and finds instruction two belongs to the PumpFun bonding curve program.
It reads the first 8 bytes of that instruction's data buffer and they equal the hard-coded create discriminator. The Borsh strings that follow yield a name, a symbol and a metadata URI, and the account list yields the mint at its fixed position. Total work: one program id comparison, one 8-byte comparison, one Borsh read.
The same pass sees a second transaction whose first data byte is 1 under the Raydium AMM v4 program. The account count is 14 rather than the initialize2 layout's full list, so it is discarded as a tag collision rather than treated as a pool creation.
Scope of this page
This page covers identifying launch instructions inside a transaction you have already deshredded. It does not cover receiving packets, reassembling a slot, or submitting the trade that follows, and it does not enumerate program layouts beyond the two used as examples.
Discriminators and tag values belong to deployed programs, so treat the specific constants here as illustrations to verify against the program you actually target rather than as permanent facts. Nothing on this page tells you whether a detected instruction executed, succeeded, or survived fork choice.
Related questions
Yes. A deshredded transaction exposes the instruction data during production, before the leader has closed the slot, so a PumpFun create can be identified from its Anchor discriminator well before any RPC returns the block. What you gain is early sight of a proposal. Whether that proposal executes, succeeds, and survives fork choice is decided later, so the detection has to be treated as provisional.
Anchor prefixes every instruction data buffer with 8 bytes derived from the instruction name. Because the value is a constant for a given program and instruction, a receiver can hard-code it and identify the call with a single fixed-length comparison. That is what makes pre-execution detection cheap: no parsing, no state lookup, and no round trip to an external service in the hot path.
Match the program id, then read the leading tag byte that the program uses to select an instruction. A single byte collides easily with unrelated data, so pair it with a structural check such as the expected account count for that instruction. Raydium AMM v4 pool creation uses tag 1 and a long fixed account list, and the count is what separates a real match from noise.
They limit it. A version 0 transaction can reference accounts by index into a table whose contents live on chain, and resolving those indexes needs state a pre-execution receiver does not hold. Creation instructions usually carry their new accounts statically, so launches are mostly unaffected. Swap routing is where it bites, and the usual answer is a warm cache of popular tables kept beside the receiver.
No. Observation proves the leader put those bytes in a proposed slot. The transaction can still revert at execution, the slot can be skipped, or the fork it rode in can lose. A detector that acts on every match without checking it later against a truthful confirmation feed will eventually take a position on an event that never became part of the chain.
Read next
Ready to build against this? The documentation covers the implementation.