Compressed NFT Sniping on Solana: Bots and the Bubblegum Program
A compressed NFT sniper bot on Solana must fetch Merkle proofs and race Bubblegum mints. Here's how state compression works and where cNFT snipers actually win.
A compressed NFT lives as a leaf in a Merkle tree, not as a token account. That single fact rewrites everything a sniper bot has to do on Solana. There is no mint account to watch, no associated token account to poll, no getTokenAccountsByOwner call that surfaces the asset. The NFT exists only as a 32-byte hash inside a concurrent Merkle tree, and the only durable state on-chain is the tree's root. If your bot is built around the classic SPL-token mint flow, it is blind to the entire cNFT asset class.
Compressed NFTs matter because they are cheap enough to mint in the millions. A Bubblegum tree sized to a depth of 20 holds ~1 million leaves and costs on the order of a few SOL to create, versus the ~0.012 SOL per NFT you'd burn on rent for uncompressed mints. Projects that airdrop or sell 100k-supply collections now do it almost exclusively with cNFTs. If there is edge to be had at those mints, it is a cNFT problem.
How state compression actually stores an NFT
The Bubblegum program (Metaplex) writes NFT metadata into a leaf, hashes it, and appends that hash to a concurrent Merkle tree managed by the SPL Account Compression program. What lands on-chain is:
- The tree's current root (32 bytes) plus a small changelog buffer of recent roots.
- A canopy — a cached top slice of the tree — sized when the tree is created.
- Nothing about the leaf's contents. The actual metadata (name, URI, owner, creators) is emitted only in the transaction's
mpl_bubbleguminstruction data and reconstructed off-chain by an indexer.
That last point is the whole game. To do anything with a cNFT — read it, transfer it, verify ownership — you need a Merkle proof: the sibling hashes along the path from the leaf to the root. On-chain programs verify the proof against the stored root. Nobody stores proofs; they're recomputed from the tree's full leaf set, which is why you can't operate on cNFTs without an indexer running the Digital Asset Standard (DAS) API.
Why proofs are the bottleneck
For an uncompressed NFT, a snipe is a transfer or a bonding-curve buy — a couple of accounts, self-contained. For a cNFT, every operation that touches a leaf must pass the proof as remaining accounts. A depth-20 tree implies a 20-node proof path, and each node is a 32-byte pubkey passed as an account in the transaction.
Two problems fall out of this immediately.
First, transaction account limits. A legacy Solana transaction fits 32 accounts; a full 20-deep proof plus your program accounts blows past that. This is where the canopy earns its keep. If the tree was created with a canopy depth of, say, 14, the top 14 levels are cached on-chain and you only supply the remaining 6 proof nodes. Snipers care intensely about canopy depth because a shallow canopy means fat transactions, and fat transactions mean you need Address Lookup Tables and you eat more compute. Check the tree's canopy before you decide a collection is even worth targeting.
Second, proof freshness. The proof is valid against a specific root. Every mint or transfer into the same tree changes the root and can invalidate a proof that was fetched a few slots ago. The concurrent Merkle tree's changelog buffer (the maxBufferSize set at creation, commonly 64–256) is what lets multiple writes in flight still verify — it stores recent roots so a proof computed against a slightly stale root still passes as long as it's within the buffer window. If you fetch a proof, sit on it for 40 slots during a hot mint, and the buffer has rolled past your root, your transaction reverts with a proof-mismatch error. You refetch and you've lost the race.
Sniping a Bubblegum mint
The realistic snipe targets are cNFT primary sales: a candy-machine-style program or a Bubblegum-backed launchpad minting sequentially into one tree. Your bot has to detect the mint going live, land a mint_to_collection_v1 (or the launchpad's buy instruction) before supply exhausts, and do it without a proof for its own not-yet-existent leaf — minting appends a fresh leaf, so you only need proofs for existing-leaf operations like transfer or redeem.
The pipeline looks like this:
- Watch tree creation and config. Subscribe to the tree authority PDA and the launchpad's mint-config account. Log
maxDepth,maxBufferSize, and canopy depth the moment the tree is initialized — these decide your transaction shape. - Detect the go-live edge. Poll or geyser-subscribe the config account for the
goLiveDate/isActiveflip, exactly like an SPL launch. The mechanics of racing that flip — clock skew, targeting the right slot, submitting to multiple validators — are the same ones covered in the piece on stake-weighted QoS and transaction priority, and they apply here unchanged. - Pre-build and pre-sign. Have the mint instruction assembled with your fee payer, priority fee, and the correct tree accounts before go-live. cNFT mint instructions are heavier on compute than an SPL swap; budget 400k–800k CU and set the compute-unit price accordingly.
- Submit aggressively. Skip preflight on competitive mints, fan out to several leaders, and accept revert costs on the tail.
For anything that touches an existing leaf — say you're sniping a secondary listing or redeeming a cNFT the instant it becomes transferable — you fetch the proof from a DAS provider right before submission:
// Fetch proof + asset just-in-time, then build the transfer.
const { result: proof } = await das("getAssetProof", { id: assetId });
const { result: asset } = await das("getAsset", { id: assetId });
// proof.proof is the sibling-hash array; slice off what the canopy covers.
const proofPath = proof.proof
.slice(0, proof.proof.length - CANOPY_DEPTH)
.map(pk => ({ pubkey: new PublicKey(pk), isSigner: false, isWritable: false }));
// root, dataHash, creatorHash, nonce, index all come from `asset` + `proof`
// and go into the mpl-bubblegum transfer ix as instruction args.
The das() call is your latency floor. A public Helius/Triton DAS endpoint answers getAssetProof in 80–200 ms; that round trip is dead time during which the root can move. Running your own DAS indexer next to your submission box — the kind of colocated data and indexing infrastructure we build — cuts it to single-digit milliseconds and, more importantly, lets you re-derive a fresh proof locally the instant the root changes instead of round-tripping to a third party.
Where cNFT snipers actually win and lose
The wins are structural. Because most operators still treat cNFTs as an afterthought, competition at compressed mints is thinner than at SPL token launches. The tooling gap is real: many off-the-shelf Solana sniper stacks don't handle proofs at all, so a bot that does is competing against a smaller field.
The losses are almost always proof-related:
- Stale-root reverts during high-throughput mints, when the buffer rolls past your fetched root. Mitigation: fetch proof as late as possible, or re-derive locally.
- Fat transactions on shallow-canopy trees that don't fit without Lookup Tables, forcing an extra ALT-creation step that costs you slots.
- Indexer lag, where the DAS provider hasn't ingested a leaf that was minted two slots ago, so
getAssetProofreturns not-found on an asset that demonstrably exists. This is the single most frustrating failure mode, and it's why serious operators run their own indexer rather than trusting a shared one.
There's a further edge in reading the tree directly. Because leaves are appended sequentially, watching mint order tells you supply remaining in real time — useful for the same reasons a Solana wallet tracker is useful on SPL flow, except here you're tracking leaf indices instead of token balances. Pair that with a low-latency shred feed and you see mints land before they're confirmed, which is the difference between reacting to a sellout and being part of one.
cNFT sniping is less about raw speed than uncompressed token sniping and more about owning the data path — the proof, the root, the indexer. Get colocated proof derivation right and the compressed asset class is one of the few places on Solana where the field is still soft. If you want that path built end to end, our team can build a compressed-NFT sniper around your target launchpads.
Need a bot like this built?
We design, build and run trading bots on Solana, Hyperliquid and Polymarket.
Start a projectMore from the blog
Public vs Paid RPC: How to Run a Fair Benchmark
A fair comparison of public and paid RPC endpoints must account for quotas, workload, freshness and support guarantees.
Read articleRPC Benchmark Percentiles Explained: p50, p95 and p99
Why averages hide the latency spikes that break trading bots, wallets and production blockchain applications.
Read articleHyperliquid REST vs WebSocket Benchmark: What to Measure
A benchmark plan for Hyperliquid market data that separates request latency from streaming freshness and recovery.
Read article