pump.fun Sniper Bot: Why Detecting First Still Loses

Most sniper bots optimise detection and lose on submission. Where the slots actually go between a launch appearing and your buy landing, and what to fix first.

BoltTx Team··10 min read
solanasniper-botpump-funtransaction-landingpriority-feetrading-bot

Every sniper bot guide is about detection. WebSocket versus polling, Geyser streams, how to parse creation events three milliseconds sooner.

Then people build one, watch it detect launches beautifully, and get filled after the price has already tripled.

Detection was never the bottleneck.

Where the Slots Actually Go

A snipe has five stages. Only one of them gets written about:

① launch appears on chain
② your bot detects it          ← everyone optimises this
③ your bot decides to buy
④ you build and sign
⑤ your transaction lands       ← this is where you lose

Stages 2 through 4 are your own code, and they are fast — parsing a log line and building an instruction is sub-millisecond work. Stage 5 is a network problem, and during a launch it is the slowest part by a wide margin.

★If you shave a few milliseconds off detection and still land three slots late, you saved nothing.★ A slot is far longer than that gap. You were optimising a rounding error.

Already have detection working and want to fix the last stage? A free BoltTx key is one line of config. The rest of this explains why that stage dominates.

Why Launches Are the Hardest Case

Congestion is not random. It clusters around exactly the events you are trying to trade.

A launch means every sniper watching that program submits within the same second. Block space is contested, priority fees spike across the accounts everyone is writing to, and the window to land narrows.

This creates a specific trap: ★your bot works perfectly in testing and fails in production★, because testing happens when the network is quiet and every submission path performs identically. The differences only appear under load.

The Four Things That Decide Your Fill

1. Priority fee, derived not hardcoded

A constant you set last month is either wasteful most of the time or useless during launches. Usually both.

import { ComputeBudgetProgram } from "@solana/web3.js";

// Fees are contested per account, not globally. Query with the
// accounts your transaction writes to — during a launch, everyone
// is writing to the same bonding curve account.
const recent = await connection.getRecentPrioritizationFees({
  lockedWritableAccounts: [bondingCurve, yourTokenAccount],
});
const fees = recent.map((r) => r.prioritizationFee).sort((a, b) => a - b);
const median = fees[Math.floor(fees.length / 2)] ?? 0;

instructions.unshift(
  ComputeBudgetProgram.setComputeUnitPrice({
    // Launches are the contested case. Median is a floor.
    microLamports: Math.max(median * 3, 10_000),
  }),
  ComputeBudgetProgram.setComputeUnitLimit({ units: 120_000 }),
);

★Set the compute unit limit too.★ Without one you are charged against a default well above your actual usage, which wastes fee budget during precisely the moments fees are expensive.

2. Blockhash fetched at signing time

A blockhash is valid for roughly 150 blocks, about 60 seconds. That sounds generous until you fetch one at startup and reuse it.

// Wrong: the blockhash is already old when the launch fires.
const { blockhash } = await connection.getLatestBlockhash();
watchForLaunches((mint) => buildAndSend(mint, blockhash));

// Right: keep a fresh one, refreshed on a timer.
let cached = await connection.getLatestBlockhash("confirmed");
setInterval(async () => {
  cached = await connection.getLatestBlockhash("confirmed");
}, 5_000);

Refreshing on a timer rather than fetching on demand also removes a round trip from the hot path. ★You cannot afford a network call between detecting and submitting.★

3. Retry until expiry, not once

A single submission during a launch is a coin flip.

const raw = tx.serialize();
const sig = await connection.sendRawTransaction(raw, {
  skipPreflight: true,
  maxRetries: 0, // we drive retries ourselves
});

while (await connection.getBlockHeight("confirmed") <= lastValidBlockHeight) {
  const { value } = await connection.getSignatureStatuses([sig]);
  if (value[0]) break; // landed, check .err for the outcome

  await connection.sendRawTransaction(raw, {
    skipPreflight: true,
    maxRetries: 0,
  });
  await new Promise((r) => setTimeout(r, 400));
}

Resending identical bytes is safe — same signature, included at most once. skipPreflight matters here because preflight costs a round trip and simulates against a slot you will not land in.

4. A submission path that holds up under load

This is the one you cannot fix in application code, which is why it should be checked last — after the three cheap fixes are ruled out.

Validators accept forwarded transactions in proportion to the forwarding node's stake weight. When block space is plentiful this is invisible. When it is contested, a low-stake path gets deprioritised exactly when you need it not to be.

What Landing Looks Like

Real transactions through our delivery nodes: median confirmation 336ms — under one slot.

Two slots is under a second. On a launch, the price at slot 2 and the price at slot 6 are different enough to be the whole trade.

★During congestion that number stretches★ — most transactions are unaffected while a minority take noticeably longer. Snipes live in that minority, because launches are congestion.

Measuring the Right Thing

Fill rate alone is misleading. A bot that fills every snipe at a terrible price looks healthy.

log({
  mint,
  detectSlot,        // slot where you saw the launch
  landSlot,          // slot where your buy landed
  slotGap: landSlot - detectSlot,
  entryPrice,
  curvePriceAtDetect,
  gapBps: Math.round(((entryPrice - curvePriceAtDetect) / curvePriceAtDetect) * 10_000),
});

slotGap tells you whether execution is the problem. gapBps tells you whether it costs enough to matter.★ Track them separately, because optimising detection when slotGap is large is effort spent on the wrong stage.

The Honest Part

Sniping is competitive. Everyone reading this has the same public information about the same launches, and the edge from any single optimisation is small.

What is true is that ★most bots are badly tuned on submission★ — hardcoded fees, one submission attempt, a stale blockhash, a general-purpose endpoint. Fixing those puts you ahead of the majority, which is a different claim from putting you first.

If your current bot lands consistently within two slots of detection and still loses money, the problem is strategy or token selection, not infrastructure. Measure before assuming.

Where BoltTx Fits

We do stage 5. Not detection, not launch feeds, not indexing.

Submissions route through our own delivery nodes in four regions with stake-weighted routing and no public mempool exposure, so a transaction is not observable in transit before it lands. You sign locally — we never hold funds, never sign, and never modify transaction contents.

The tip travels inside the transaction, paid on chain from your own wallet. If the transaction reverts, the tip reverts with it, because that is how Solana handles atomic transactions. You pay only on transactions that reach the chain.

Get a free API key. No monthly fee:

// Pick the region closest to where your bot runs
const connection = new Connection("https://la.bolttx.io/?api-key=YOUR_KEY");

Then log slotGap across a few real launches and compare.

FAQ

Why does my pump.fun sniper bot detect launches but never fill? Detection and execution are separate stages. If you see launches instantly but land three or more slots later, the loss is in submission: priority fee, blockhash freshness, retry behaviour, or routing under congestion.

How fast does a Solana sniper bot need to be? Fast enough to land within a slot or two of detection. Detection speed matters less than most guides suggest, because a millisecond saved parsing a log means nothing if your transaction takes an extra slot to land.

What priority fee should a sniper bot use? Derive it from getRecentPrioritizationFees on the accounts your transaction writes to, then multiply for the contested case. Launches are the most contested moment on the network, so the median recent fee is a floor rather than a target.

Why does my bot work in testing but fail during real launches? Testing happens when the network is quiet and every submission path performs the same. Launches create congestion, and congestion is when fee, retry behaviour, and routing all start mattering at once.

Should I use skipPreflight for sniping? Yes. Preflight costs a network round trip and simulates against the current slot, which is not the slot you will land in. Simulate during development instead, and use getSignatureStatuses to learn the outcome.

How do I keep a fresh blockhash without adding latency? Refresh one on a timer in the background rather than fetching on demand. Fetching at snipe time adds a round trip to the hot path, and a blockhash cached at startup will be near expiry when you need it.

What compute unit limit should a pump.fun buy use? Simulate during development to find your real consumption, then set slightly above it. Leaving the default means being charged against a much higher figure, which wastes budget exactly when fees spike.

Is it safe to resubmit the same snipe transaction repeatedly? Yes. Identical signed bytes produce an identical signature, and Solana includes any signature at most once. Continuous resubmission until the blockhash expires is the standard production pattern.

How many slots behind is too far for a snipe? It depends on how fast the curve moves, but beyond three or four slots on an active launch you are usually buying at a price that removes the edge. Log the price at detection and at fill to see where your threshold is.

Do I need Geyser or a dedicated stream to snipe? It helps detection, but only if submission is already tight. Paying for the fastest possible detection while submitting through a general-purpose endpoint is spending on the wrong stage.

Why do my snipe transactions fail with slippage errors? The curve moved between your quote and your inclusion. Widening tolerance makes you fill worse rather than fixing the cause. If it happens consistently, the slot gap is the real variable.

Can I run a sniper bot without a paid RPC? For detection on a small scale, sometimes. For submitting during launches, shared public endpoints are the worst possible case, since they are congested by everyone else at exactly the same moment.

What is the difference between sniping and front running? Sniping acts on a launch that has already happened on chain — public information. Front running acts on knowledge of a pending transaction before inclusion. On Solana there is no public mempool, so the second is not available in the way it is elsewhere.

Should my sniper bot check whether the curve has graduated? Yes, before every buy. Once a curve completes, trading moves to an AMM pool and bonding curve instructions fail. A bot that checks only at startup will send failing instructions repeatedly.

How do I know if my bot's problem is infrastructure or strategy? Log slot gap and entry price gap separately. Consistently landing within two slots and still losing money points at token selection or strategy. A large slot gap points at execution.

Back to all posts