Skip to main content
Solana MEV Protection: 5 Ways to Stop Sandwiches - Featured image

Solana MEV Protection: 5 Ways to Stop Sandwiches

BUILDERZ

BUILDERZ

Share

In this guide

The decisions and working steps ahead.

How a sandwich lands on Solana

1. Tight slippage and simulation

2. Bundles with the jitodontfront marker

Your users say the quote was one number and the fill was another.

Support blames slippage. Your logs show a buy right before their trade and a sell right after.

That's a sandwich. On Solana it lands inside the leader's block, not in a public queue.

A 5% slippage setting on a thin pool is the attacker's budget.

Below are the 5 layers we recommend for production DeFi builds, cheapest first.

Keep this checklist for your next launch review.

How a sandwich lands on Solana

Nothing waits in a public pool of pending transactions. Yours goes to the current leader, who orders its slot.

A slot is 200 ms since 9 October 2026, per the reduced slot times upgrade page. That's the whole attack window.

A sandwich needs two things. The attacker needs sight of your order, and it needs control of ordering. Sight comes from a leaking RPC or a leader; ordering comes from bundling, from running the leader, or from paying it.

Your slippage tolerance tells the bot how far it can push the price before your transaction reverts. Wide tolerance, wide profit.

Each layer below removes sight, removes ordering, or caps the budget. The first two are cheap and partial. The last two cost engineering time and cover more.

1. Tight slippage and simulation

This is the floor, and it costs a code review. Set the smallest slippage that still fills, then simulate before you send.

Solana's simulation RPC method returns an error field, the program logs, and the compute units used.

Turn on the replace-block-hash option so the node simulates against a live block hash. The docs note it conflicts with signature verification, so pick one.

On the Jupiter side, the Swap V2 build endpoint defaults slippage to 50 bps. You can pass a fixed integer, or ask Jupiter's estimator to set it per trade.

The samples target @solana/web3.js 3.1.1, the current latest on the registry. Its README says the 1.x line now gets critical fixes only.

Code exampletypescript
// Targets @solana/web3.js 3.1.1
import { Connection, VersionedTransaction } from "@solana/web3.js";

// quotedOut and minOut both come from the quote you already hold:
// the quoted output amount and the minimum the swap instruction enforces.
export async function preflightOrAbort(
  connection: Connection,
  tx: VersionedTransaction,
  quotedOut: bigint,
  minOut: bigint,
  maxSlippageBps = 50n,
): Promise<number | null | undefined> {
  // 1. Guard the quote: minOut is what the program will enforce on-chain.
  const floor = quotedOut - (quotedOut * maxSlippageBps) / 10_000n;
  if (minOut < floor) {
    throw new Error("quote allows more slippage than the floor, not sending");
  }

  // 2. Simulate the signed transaction against current state.
  const sim = await connection.simulateTransaction(tx, {
    replaceRecentBlockhash: true, // simulate against a fresh blockhash
    sigVerify: false, // conflicts with replaceRecentBlockhash, so keep it off
    commitment: "confirmed",
  });

  if (sim.value.err) {
    throw new Error(`simulation failed: ${JSON.stringify(sim.value.err)}`);
  }
  return sim.value.unitsConsumed;
}

Coverage is partial. Simulation shows the state now, and the attacker moves it after you sign.

Tight slippage caps the loss per trade. It also raises your revert rate on volatile pairs, so watch both numbers.

2. Bundles with the jitodontfront marker

The block engine accepts bundles of up to five transactions, per the block engine docs. They execute in order and atomically.

A bundle needs a tip of at least 1000 lamports, sent to one of eight tip accounts.

The anti-sandwich mechanism is one extra account. Include a read-only account whose address starts with the marker prefix shown in the sample below. It doesn't need to exist on-chain.

The block engine then rejects any bundle that carries that account unless your transaction sits at index 0. Nobody can put a buy in front of you inside a bundle. The same marker works on the block engine's single-transaction send endpoint.

Code exampletypescript
// Targets @solana/web3.js 3.1.1
import { PublicKey, SystemProgram, TransactionInstruction } from "@solana/web3.js";

// Any valid pubkey starting with "jitodontfront" works; it need not exist.
// The docs use this exact example address.
const DONT_FRONT = new PublicKey("jitodontfront111111111111111111111111111111");

export function protectSwap(
  swapIx: TransactionInstruction,
  payer: PublicKey,
  tipAccount: PublicKey, // one of the 8 accounts from getTipAccounts
  tipLamports = 1_000, // documented minimum for bundles
): TransactionInstruction[] {
  // 1. Append the marker as a read-only key. Anchor programs ignore extra
  //    accounts; a program that checks account count will reject it, so test.
  swapIx.keys.push({ pubkey: DONT_FRONT, isSigner: false, isWritable: false });

  // 2. Tip in the same transaction. Do not load the tip account via a lookup table.
  const tipIx = SystemProgram.transfer({
    fromPubkey: payer,
    toPubkey: tipAccount,
    lamports: tipLamports,
  });

  return [swapIx, tipIx];
}

Read the limits before you rely on it. The same docs say the marker "may help reduce sandwich attacks but is not guaranteed to do so" and does not cover ordering by third parties.

It protects you inside one block engine. A leader that orders its own block is out of reach.

Cost is the tip plus a default rate limit of one request per second per IP per region. Coverage is good against bundle-based sandwiches and nothing else.

3. Protected send endpoints

The next layer is to stop sending through a plain RPC. Several providers route around validators they link to sandwiching, and the switch is one query parameter.

Helius MEV Protect is enabled by adding mev-protect=true to the endpoint URL. The docs say it excludes validators whose link to sandwich activity is statistically significant, and that roughly 3 to 4 million SOL of stake is excluded at any time.

The documented tradeoff is slightly fewer leaders to land with. The same page suggests measuring your landing rate with and without the flag before you turn it on in production.

The flag also works on Sender, which submits across several pathways at once. Sender is paid per transaction with a minimum tip of 0.001 SOL for the full tier, or 0.000005 SOL for the single-path tier, plus a priority fee.

Jupiter's Swap V2 build endpoint takes a tip field and lands through Jupiter's own submit route. Its Ultra docs describe keeping transactions private until execution.

The block engine's own send endpoint has protection on by default, per the same docs. It skips preflight, so pair it with your own simulation from layer 1.

This layer costs a tip per trade and a vendor dependency. Coverage is broad for ordinary swaps, because the leaders most likely to sandwich you never see the transaction.

4. Leader-aware and allow list routing

If you want control instead of a vendor's judgment, route by leader yourself. Solana's RPC method for slot leaders returns the validator identity for each slot in a range of 1 to 5,000 slots.

The pattern is a small loop. Fetch the next few leaders, check them against your own block list, and hold the transaction until a trusted leader is up.

Keep the wait short. A block hash stays valid for 150 blocks, which is about 30 seconds at the 200 ms slot time on the reduced slot times page. The Solana confirmation guide explains the expiry mechanism.

Triton's Yellowstone Shield moves that list on-chain. You create an allow list or block list policy, then pass its address in the forwarding policies field on the send call.

A Shield-enabled RPC checks the current leader against every policy you name. Standard RPCs ignore the field.

The documented failure mode matters. If the leader fails the policy, the transaction is dropped, not queued, and Triton warns against strict policies for time-sensitive operations.

Cost is engineering time and a curated validator list you must maintain. Coverage is as good as your list, which is both the strength and the weakness.

5. Contract-level rules

The strongest layer lives in the program, because it holds no matter how the transaction was routed. Three rules do most of the work.

A commit-reveal flow splits a trade into a hash commitment and a later reveal. The bot sees a hash, not an amount, so it has nothing to front-run.

An average-price check rejects fills when spot deviates too far from a recent time-weighted average. The sandwich's first leg moves spot away from that average, so it fails.

Code examplerust
// Illustrative Anchor-style check, written for this article.
pub fn check_twap_deviation(spot: u64, twap: u64, max_bps: u64) -> Result<()> {
    let diff = spot.abs_diff(twap) as u128;
    let deviation_bps = diff * 10_000 / twap as u128;
    require!(deviation_bps <= max_bps as u128, SwapError::PriceDeviationTooHigh);
    Ok(())
}

Per-transaction and per-slot limits are the third rule. Cap how much of a pool one trade can take, and cap how many fills one wallet gets per slot.

Our pump.science case study, one of 22 published and labelled historical, gives one example of a contract-level defense. Each compound got its own token on a bonding curve, and the contracts carried a dynamic fee model to deter bot manipulation.

A fee that rises against bot-like behaviour attacks the budget, the same lever as the limits above.

Cost is highest here: program changes, tests, and an independent review before you ship. Coverage is also highest, and it compounds with every layer above it.

Our recommendation for a first release is layers 1 through 3, with layer 5 added once token economics settle. Layer 4 is for teams that run their own routing. Our Solana DeFi development page covers how we scope that work.

Before launch, walk the Solana launch checklist. It covers the fee, RPC, and monitoring decisions that decide whether a fix like this is measurable.

FAQ

Does the jitodontfront marker stop every sandwich on Solana?

No. The marker tells the block engine to reject any bundle where your transaction isn't at index 0, so searchers can't front-run you inside a bundle. The docs say it may reduce sandwiches and doesn't cover ordering done by third parties. A leader that orders its own block is outside its reach.

How much slippage should a Solana swap allow?

As little as still fills. Jupiter's Swap V2 build endpoint defaults to 50 bps, and you can ask its estimator to set the value per trade. Treat your tolerance as the attacker's maximum profit, then simulate and reject fills below your floor.

What does the Helius protect flag cost?

The routing flag adds nothing to your bill. The docs say it only changes where the transaction is routed, so tips and fees stay the same. On Sender that means a minimum tip of 0.001 SOL for the full tier or 0.000005 SOL for the single-path tier, plus a priority fee.

Should I build commit-reveal into my swap program?

Build it when your users trade sizes that move the pool and you control the program. It costs an extra transaction per trade and a review of the hashing scheme. For thin-pool token launches it removes the information a bot needs, which no routing layer can do.

Pick your layers, then fix the fills

You don't need all five on day one. Stack them in this order and stop when fills stop being a support ticket.

  • Layer 1, slippage and simulation. Free. Caps the loss, doesn't prevent it.
  • Layer 2, bundles with the marker. A small tip. Stops bundle-based sandwiches only.
  • Layer 3, protected send endpoints. A tip per trade. Routes around leaders linked to sandwiching.
  • Layer 4, leader-aware routing. Engineering time. Coverage equals your list.
  • Layer 5, contract rules. Program changes plus review. Holds regardless of routing.

Try layer 1 this week. Then send us the swap signatures and the pool, and we'll tell you which layers you're missing and what each one costs to add.

Our first published Solana build shipped in 2021, and our Solana development service covers work like this today. Our process is public on /process, and Mission Control is open source.

Talk to us about your fills and bring one bad trade with you.

Continue reading

Building on Solana?

Book a 20-minute intro call, or send a short brief. We reply within one business day.

Solana development service