Sandwich Protection in Practice: Layers, Costs and Limits
There is no switch that turns sandwiching off. There are four layers, each of which closes part of the exposure, each of which costs something, and none of which composes cleanly with the others. This page treats protection as an engineering problem rather than a product category.
Sandwich protection on Solana is a stack of four partial measures: narrowing who sees the transaction before inclusion, constraining what a profitable attack would need in order to work, shaping the order so it is not worth targeting, and choosing a fill type where the attack has no place to sit. No single layer closes the exposure. Composed carelessly, they can also cancel each other out.
This page assumes you know what the pattern is and why tolerance settings matter. The question here is narrower and more useful: given the layers available, which combination is worth running, what does the combination cost, and how would you know whether the change you made helped.
Four layers and what each one closes
| Layer | Closes | Leaves open | Cost to you |
|---|---|---|---|
| Path narrowing | Observation by parties not on your chosen path | Observation by the party you chose | Tips or subscription, plus dependence |
| Constraint tightening | The room an attacker needs between your quote and your floor | Nothing, if the pair is moving on its own | Higher revert rate and repeated fee spend |
| Order shaping | The economic attractiveness of the order itself | Exposure of the shape you chose, once repeated | More attempts, more fees, longer exposure window |
| Fill-type choice | The pool position an attack needs to occupy | Counterparty discretion and quote-time leakage | An embedded spread you cannot decompose |
Read the third row carefully. Splitting a large order into smaller pieces reduces the prize on any individual piece, which is genuinely useful. But a sequence of identical small orders at regular intervals is itself a pattern, and a pattern is information. Shaping trades one kind of visibility for another rather than removing visibility, and the trade is only favourable if the sequence is irregular enough not to be predictable.
Why stacking is not additive
The intuitive model is that each layer removes some percentage of the risk and the remainder multiplies down. That model is wrong in three specific ways, and each of them shows up in practice.
Three interactions that break the additive model
- Tight constraints plus a slow path
- A narrowed path can add latency. A tighter floor is more likely to be breached when more time passes. Applied together, the second layer makes the first layer's cost worse, and the visible symptom is a rising revert rate that looks like a tolerance problem.
- Shaping plus a fixed-cost path
- Splitting one order into six multiplies the per-attempt costs by six. If your path charges a tip per attempt, shaping just made protection roughly six times more expensive while reducing the prize on each piece.
- Fill-type choice plus path narrowing
- Choosing a quoted counterparty already moves the trade off the pool where a sandwich would sit. Adding a narrowed submission path on top mostly protects a leg that no longer has the exposure, while still charging you for it.
The practical implication is that a stack should be assembled in a deliberate order rather than accumulated. Start with the layer that closes the largest part of your specific exposure, measure, and only add a second layer if the first left something identifiable open. Most desks do the reverse: they turn on everything at once, cannot attribute the result, and keep paying for all of it forever.
The cost of running the whole stack
Illustrative arithmetic with stated assumptions. Take a desk sending one hundred orders in a session. Assume protection layers as follows: a tip of 0.001 SOL per submission attempt, a constraint tightening that raises the revert rate from 3% to 9%, and shaping that turns each order into three pieces.
| Line | No layers | Path only | All three layers |
|---|---|---|---|
| Submission attempts | 103 | 103 | 330 |
| Tips paid | 0.000 SOL | 0.103 SOL | 0.330 SOL |
| Base fees | 0.000515 SOL | 0.000515 SOL | 0.00165 SOL |
| Attempts wasted on reverts | 3 | 3 | 30 |
| Total direct cost | 0.000515 SOL | 0.1035 SOL | 0.3317 SOL |
The full stack costs roughly three times the single-layer configuration in this illustration, and the additional protection it buys is not three times greater; it is whatever residual exposure the first layer left, which may be small. That is the whole argument for deliberate composition. Protection spending has diminishing returns in a way that is easy to demonstrate arithmetically and very easy to ignore in practice.
There is a second cost that does not appear in the table: thirty reverted attempts is thirty moments when you did not have the position you wanted. On a moving pair, the opportunity cost of not being filled can exceed every fee line above it. Any honest cost model has to carry that term even when it cannot be measured precisely.
What no layer closes
- State inference. Your trade changes pool reserves, and that change is public the instant it lands. Anyone reacting to the new state is not front-running you; they are trading after you.
- Wallet-level patterns. If the same address behaves the same way at the same times, the behaviour is legible from history alone, with no pre-inclusion observation required.
- Your chosen counterparty. Every layer narrows the set of observers to include at least one party you selected. That party's conduct is a trust assumption, not a protected variable.
- Ordinary competing flow. Someone else trading the same pair in the same slot for their own reasons will move your fill and is unaffected by anything you configure.
- Correlated events. Listings, unlocks and announcements move prices in the window you are trading. No submission path changes that.
The distinction between the last two and adversarial behaviour is worth holding firmly, because conflating them produces bad decisions. A desk that attributes every disappointing fill to an attacker will keep buying protection that cannot help, and will not investigate the causes that could actually be addressed, such as size relative to depth or the time of day it chooses to trade.
Attributing a bad fill before buying anything
Before any layer is worth paying for, you need a rough sense of how much of your shortfall is adversarial at all. Attribution here does not require sophisticated analysis; it requires three questions asked in order, each of which eliminates a large share of cases.
- Was the order large relative to available depth? If so, the majority of the gap is the curve doing what the curve does, and no protection layer touches it. The remedy is sizing, not submission.
- Did the pair move in the same direction for everyone during that window? Broad movement affects every participant and is not directed at you. Compare the pair's behaviour either side of your slot before concluding anything.
- Is the pattern repeatable? A single bad outcome is not interpretable. If the same shape appears across many attempts under similar conditions, you have something worth investigating; if it appears once, you have variance.
Only the residue that survives all three questions is a candidate for the layers described above. In practice that residue is smaller than most traders assume, and it concentrates in a recognisable place: larger orders, thinner pairs, wider constraints, busier moments. Knowing where your own residue sits tells you which layer to buy and, just as importantly, when to buy nothing at all.
Designing a controlled test on your own flow
Protection changes are testable, and almost nobody tests them. The obstacle is not sophistication; it is that a proper test requires you to keep sending some orders the old way, which feels wrong. Here is a design that is realistic to run at a desk.
- Fix everything except the layer under test. Same pair, same size distribution, same time window, same interface. One variable.
- Alternate rather than switch. Send alternate orders through configuration A and configuration B in the same session. Comparing this week to last week compares market conditions, not configurations.
- Record attempts, not fills. Log every submission, its outcome, its fee lines, its timestamp and its signature. A log of successes is a biased sample.
- Define the metric before you look. Realised cost against a fixed benchmark, computed per attempt, is a defensible choice. Choose it in advance so the data cannot choose it for you.
- Collect enough attempts to see a distribution. Twenty attempts tells you almost nothing when the effect you are looking for is a few basis points inside ordinary variance.
- Compare distributions, not averages. A configuration with a slightly worse mean and a much thinner tail is often the better one, and an average hides exactly that.
- Write down the conclusion and the date. Market structure changes by announcement. A conclusion without a date will be applied long after it stopped being true.
The reference material you need for step three is on chain. Transaction fee composition and the account changes that let you reconstruct a fill are documented at solana.com/docs, and any routing service you use will expose its own quote parameters, in the way the developer documentation at docs.jup.ag does, so you can hold the routing variable constant while you change the protection variable.
If a test is too much work for the size you trade, that is a finding. It means the effect you are trying to detect is smaller than the effort required to detect it, which is a good reason to choose a simple configuration and stop optimising it.
Reading a protected claim
Products describe themselves as MEV-protected with very little consistency about what the phrase covers. Four questions convert the claim into something assessable.
- Which layer is this? Path narrowing, constraint enforcement, shaping, or fill-type selection. If the answer is all of them, ask again more specifically.
- Who is the residual observer? Every design leaves someone. Name them.
- What happens on failure? If the protected path cannot deliver, does the order fall back to an ordinary path, silently.
- What is measured, and against what benchmark? A claim of improvement requires a stated comparison; without one it is a description of a feeling.
A product that answers all four clearly is not necessarily better than one that does not, but it is assessable, and assessable is the precondition for everything else. Note also that the honest answer to question three is frequently the most expensive detail in the whole arrangement, because a silent fallback means your protection has a hole exactly at peak load.
Composition by trader profile
| Profile | Start with | Add only if measured | Usually not worth it |
|---|---|---|---|
| Occasional trader, small size | Sensible constraints and nothing else | Path narrowing above a size threshold | Tips per attempt, shaping |
| Active trader, moderate size | Path narrowing | Constraint tightening on thin pairs | Full stack on every order |
| Desk running schedules | Path narrowing plus consistent shaping | Fill-type choice for the largest clips | Ad hoc per-order changes |
| Large single orders | Fill-type choice | Path narrowing for the settlement leg | Aggressive splitting into a moving market |
The row for desks running schedules is the one where consistency does the heavy lifting. When the same policy applies to every order in a sequence, the resulting data is comparable and the test described above becomes possible. This is the unglamorous case for multi-venue volume automation in a protection context: not that software trades better than a person, but that it applies the same settings the four-hundredth time as the first, which is the only condition under which measurement means anything.
The operating discipline
Three habits separate desks that manage this well from desks that spend money on it indefinitely without learning anything.
First, attribute before you spend. Establish which part of your gap between expectation and outcome is adversarial at all. On most pairs, for most sizes, the majority of it is ordinary movement and competing flow, and no protection layer addresses either.
Second, add layers one at a time, with a measurement between each. The stack you end up with should be the smallest one that closes the exposure you actually identified, not the largest one your tooling supports.
Third, review on a calendar rather than after a bad trade. This landscape changes through business announcements rather than protocol upgrades, and a configuration that was correct six months ago may now be protecting against something that no longer exists while ignoring something that does.
None of this promises a clean outcome. Protection on a public chain is a matter of degree, and the residual is permanent. What the discipline buys is not safety but knowledge of your own position: which exposures you have closed, what you paid to close them, and which ones you have consciously decided to live with.
Filed under Protection by The Order Flow Desk. Any figure used here is either a protocol constant or arithmetic labelled as illustrative; the desk publishes no measured fill data of its own. Scope and method are set out on the desk page.