MEV FORENSICS — Solana × Address History

Solana Sandwich Attacks: How to Detect Them From Public Data

7 min read
SolanaMEVSandwichForensics

You bought a token at a quoted price and got filled worse. Not slippage-worse — the pool moved against you in the same block, then moved back. You suspect a bot ate the difference. Until this year, proving it from your own wallet was expensive: the evidence sits in other people's transactions, and address history gave you signatures without saying where in the block each one landed.

That changed in January. The address history that every RPC serves now carries each transaction's position inside its block. With that one integer, a sandwich becomes a pattern you can test for from a wallet address, no firehose required. This post is the pattern, the data that supports it, and the honest limits of what it proves.


What a Sandwich Is, Mechanically

A sandwich is three transactions on one pool in a fixed order:

  • The attacker buys the token you are about to buy, pushing the price up.
  • Your buy executes at the worse price.
  • The attacker sells, capturing the difference you paid.

The first and third legs are the same fee payer. The attacker's profit is your worse fill, minus their fees and tips. On Solana the legs usually sit in the same block as bundled transactions with consecutive positions, but they can straddle two adjacent slots, which is why any check has to look at the neighbours.

The scale is not small. A live counter that tracks these patterns measured roughly 8,700 SOL a day extracted in mid-September 2026, across some 74,000 distinct victim wallets in a single 24-hour window; the blended cost per victim swap was about $12, with a lower median. Those are someone else's measurements and they move; the method below is how to make your own.


The Field That Makes It Checkable: transactionIndex

getSignaturesForAddress has always returned your transactions in reverse order with their slot. Since 23 January 2026 each entry also carries transactionIndex — the transaction's position within its block. The validator stores it in the address index itself: the key of that index is address, slot, index, signature, and the stored value even records whether your address was writable in that transaction.

For the victim's side of a sandwich, that is enough to place every one of your swaps at an exact coordinate: slot s, position i.

The attacker's side lives in the same blocks. Fetch block s with transaction details and you get every transaction with its pre- and post-balances — SOL and token — per account. The validator records those balances for every transaction as part of its status service, which is why an explorer can show them at all.


The Signature, Stated So It Returns Zero on a Clean Block

Naive detectors match on shared accounts: any transaction touching the same pool before and after yours. That produces thousands of false positives, because a hot pool is touched by dozens of unrelated transactions per block. The test that holds up is on balance deltas, not accounts.

For your swap at (s, i), which bought mint M with SOL:

Front lega tx at (s, j) with j < i, or in slot s − 1, whose fee payer's balance of M increased and SOL decreased
Back lega tx at (s, k) with k > i, or in slot s + 1, same fee payer, M decreased by ≥ half that increase, SOL increased
Confirmationthe fee payer's net SOL across the two legs is positive

All three, together, on one fee payer, around your position: that is a sandwich. Any one alone is a market maker, an arbitrageur, or a coincidence. The check returns nothing on a block where nobody wrapped you, which is the property that matters.

Worth knowing: the attacker's sell often lands in the next slot, not the same one. Bundles are usually intra-block, but a bot that misses the tail of a block finishes in the next leader's first block. Scan s − 1 through s + 1.


What the Number Is, and What It Is Not

The three transactions are a measurement: they exist, at those positions, with those balance changes, signed by that fee payer. Show them and anyone can verify them.

The amount you "lost" is an estimate. To say what your fill would have been without the front-run, you have to reconstruct the pool's reserves before it, which means reading the pool state at the previous slot and re-running the curve. That is doable for constant-product pools and approximate for concentrated liquidity. Publish it with error bars, or publish the transactions and let the reader see the price impact for themselves.

What the check cannot tell you is who the attacker is beyond a fee-payer address, or which validator included the bundle. Both are inferable and both are accusations. The transactions are evidence; names are a legal surface.


The Cost of Running This

Per wallet, on demand, it is cheap: one address-history call, then one block fetch for each swap and its two neighbours. A few hundred RPC calls for an active trader's month.

As a standing index — every block, every swap, every wallet — it is a different product. Full blocks with balance data run to several hundred gigabytes a day, and the archive's address index stores no amounts, so there is no shortcut through the archive. Anyone offering a live sandwich feed for the whole chain is running that pipeline, and the price of the feed is the price of the pipeline.


What Protects You, and What Does Not

  • A tighter slippage limit caps what a sandwich can take, at the cost of more failed swaps. It is the one lever entirely in your hands.
  • Private submission — sending through a relay that does not expose your transaction to searchers before it lands — removes the attacker's view of your pending trade. It also concentrates your order flow with one party, which is a trust decision.
  • A higher priority fee does not help. The attacker is not racing you for inclusion; they are bracketing you inside a bundle that includes your transaction. Paying more to land faster lands you faster inside the same sandwich.

Sandwich Attacks: Questions People Actually Ask

How can I tell if my Solana swap was sandwiched?

Fetch your swap’s slot and block position from address history, then look in the same and adjacent slots for one fee payer that bought the same token before you and sold at least half of it after you with a positive net in SOL. All three together are a sandwich.

What is transactionIndex in getSignaturesForAddress?

The transaction’s position inside its block, returned since January 2026. It lets you order your transaction against others in the same slot without downloading every block.

Does a higher priority fee prevent sandwich attacks on Solana?

No. A sandwich brackets your transaction inside a bundle that includes it, so landing faster lands you faster in the same bundle. Slippage limits and private submission are the levers that help.

How much do sandwich bots take on Solana?

A live tracker measured roughly 8,700 SOL per day in mid-September 2026 across about 74,000 victim wallets in one day. The per-swap cost is usually a few dollars; the figures move and should be re-checked at the source.


Check Your Own Swaps

Pull your swaps with getSignaturesForAddress, keep the slot and the index, fetch each block with balances, and run the three-part test on the neighbours. If it returns nothing, nobody wrapped you in that window. If it returns a fee payer twice with a positive net, you have the two transactions that did it, and the block positions that prove the order.

That is the whole receipt. It fits in a script, it runs on any RPC, and it needed one integer that the network only started giving out this year.

— Before the Swap, Not After —

A sandwich is one way a trade goes wrong. The token itself is another.

The detection above is forensics: it tells you what already happened. The token audit runs the other direction — it reads a mint's authorities, supply and holder concentration from the chain before you commit SOL to it.

Audit a Token ↗

Field and storage details read from the Agave validator source at commit beee69b958: rpc-client-types/src/response.rs, ledger/src/blockstore/column.rs and rpc/src/transaction_status_service.rs. The market figures are third-party measurements from mid-September 2026 and move daily — re-check them at the source before quoting them.

xroot.devOn-chain research, published in full
𝕏 @xrootdev
← Back to all notes