The Moment You Realize You Need a Crystal Ball
I am staring at a pending swap inside the Jito tip-priority competition window. A user is about to send a few hundred dollars of SOL into a Raydium pool. The transaction has not landed yet — it is sitting in a holding pen for roughly 200 milliseconds before being forwarded to the leader, per a writeup on Solana sandwich attacks. My bot has that window to decide: is there a backrun worth doing here, and at what size?
The answer hinges on a question that sounds almost philosophical: what will the pool look like after this swap executes, even though the swap has not executed yet?
That question is what people in this corner of Solana call the predicted state problem. It is one of those things that sounds trivial when you describe it at a whiteboard — "just apply the constant product formula, dude" — and turns into a wormhole the moment you try to ship it. This week I am living inside that wormhole, so let me write down what I am learning while it is still fresh.
What "Predicted State" Actually Means
A predicted state engine is a piece of bot infrastructure that, given the current snapshot of an AMM pool and a pending swap, computes the pool's post-swap state — reserves, price, accumulated fees, tick or bin position, the works — before the chain itself does.
It is a purely deterministic computation. The on-chain program follows fixed math. If I have the same inputs the validator will have, and I run the same math, I get the same answer the validator will get. No oracle. No off-chain heuristic. No machine learning. Just arithmetic.
The reason this matters: every meaningful MEV decision on Solana depends on it.
- Backrun arbitrage: I need to know where the pool will sit after the victim's swap so I can size a trade that closes the price gap against another venue.
- Sandwich attempts (which I am not building, but the mechanics are instructive): the attacker must front-run with exactly enough size that the victim's slippage tolerance is still satisfied, then back-run on the rebound.
- Failure avoidance: if my predicted state shows the swap would leave the pool in a way that makes my own trade unprofitable, I should not submit. Failed bundles still cost tips.
An MEV report puts it bluntly: "Atomic arbitrage is the dominant form of MEV on Solana, typically arising when two DEXs list different prices for the same trading pair, often exploiting stale quotes on a constant product automated market maker." Stale quotes. That phrase is doing a lot of work — the entire business is built on the fact that some participant is computing the post-trade state and another is not.
My job is to be the participant that is computing it.
The Easy Case: Constant Product Pools
For a constant product (CPMM) pool — Raydium V4, the original Uniswap V2 design, PumpSwap's AMM — the math is so simple it is almost embarrassing.
The invariant is the famous x * y = k, where x and y are the reserves of the two tokens. As a guide walks through, given an input amount dx (fee-free) the output is:
dy = (y * dx) / (x + dx)
Throw in a fee f, and you scale the input first:
dx_effective = dx * (1 - f)
dy = (y * dx_effective) / (x + dx_effective)
The post-swap reserves are trivial:
x_new = x + dx
y_new = y - dy
That's it. Three lines. A high school algebra student could derive it.
The fees are well-documented per protocol. Raydium's CPMM splits 0.25% total — 0.22% to LPs and 0.03% to RAY buyback. PumpSwap charges 20 bps to LPs, 5 bps to protocol, plus a dynamic coin creator fee. So my CPMM predicted state function is a switch statement on pool type, a fee lookup, and the formula above.
If the entire DEX landscape were CPMM, this article would end here. The pool tells me exactly where it is going. I just multiply and divide.
But a strong majority of bot-relevant volume is not on CPMMs anymore. The center of gravity has shifted to concentrated liquidity — Orca Whirlpool, Raydium CLMM — and to Meteora's discrete-bin DLMM, and to oracle-anchored proprietary AMMs. Each one breaks the simple formula in its own way.
When the Math Gets Mean: Concentrated Liquidity
Concentrated liquidity (CLMM) is what happens when LPs got tired of having their capital uselessly stretched across a 0-to-infinity price range. Instead, each LP chooses a price band — say, SOL between $140 and $160 — and concentrates capital there. The protocol implements this by dividing the price axis into discrete ticks, each representing a small geometric step in price.
The state of a CLMM pool is no longer just (x, y). It is, at minimum:
sqrt_price— current price stored as a square root in Q64.64 fixed-point, per a CLMM walkthrough.tick_current_index— which tick the price is sitting in.liquidity— active liquidity at the current price (not total).- Tick arrays — sparse data structures recording, for each initialized tick, how much liquidity activates or deactivates when the price crosses it.
- Fee growth accumulators per token.
A swap through a CLMM is not a single formula. It is a loop. The protocol consumes input in segments: it figures out how much input it would take to push the price to the next initialized tick, applies that segment's math, decrements remaining input, and if there is anything left, crosses the tick — adjusting active liquidity by the liquidity_net value baked into the tick — and continues to the next segment. The loop terminates when input is exhausted.
Which means my predicted state engine for CLMM is not a formula. It is a faithful re-implementation of the swap loop. To get it right I need:
- The current pool state (sqrt_price, tick_current, active liquidity).
- The tick array accounts that cover the price range the swap might traverse.
- The exact fee math the protocol applies per segment.
- The exact tick-crossing semantics (lower tick crossed: liquidity goes up; upper tick crossed: liquidity goes down — or the reverse depending on swap direction).
Get any one of those wrong and the predicted output drifts. The drift is silent — the loop still terminates, the math is still internally consistent, the bot still produces a number. The number is just wrong. That kind of bug is the worst kind, because the bot will happily lose money for hours before you realize the prediction itself is the leak.
This is the moment in the project where I started understanding why MEV teams talk about "the math layer" as if it were a load-bearing wall. Because it is.
The Other Mean Case: Discrete Bins
Meteora's DLMM takes a different approach: it discretizes liquidity into bins rather than continuous tick ranges. Each bin holds liquidity at a specific price. When you swap through a DLMM, you consume the active bin until either the input is exhausted or the bin is drained, at which point execution moves to the adjacent bin.
From a prediction standpoint, Vadim's blog lays out the trade-off well: DLMMs offer dynamic fees that respond to volatility, and bin distributions (uniform, curve, bid-ask) let LPs encode market-maker-like strategies. For my bot, that means the predicted state computation has to walk the bins in swap direction, draining each in turn, summing output, and stopping at the right place. Plus the fee at each bin can vary based on the dynamic-fee schedule.
It is not as gnarly as CLMM tick loops in practice, but it is its own little universe of edge cases.
The Comparison Table That Lives in My Head
Vadim's blog has a table comparing AMM types that I keep mentally reaching for. Paraphrasing the structure: CPMMs write a single pool account plus both vaults per swap, are easy to predict (one formula), and are the highest-risk targets for sandwiches. CLMMs write vaults plus tick arrays plus position state, are medium-risk for sandwiches, and are hard to predict because of the tick loop. DLMMs write vaults plus active bins plus parameters, sit somewhere in the middle on both axes. Proprietary AMMs — the oracle-anchored, off-chain-priced kind that Jump Crypto wrote about in their paper on PropAMMs — are essentially un-predictable from on-chain data alone, because the price for a given swap is signed off-chain by a pricing engine.
The practical implication is that the value of my predicted state engine varies enormously by venue. On the constant-product pools that an open-source MEV dashboard reports account for roughly 72% of sandwich activity (Raydium), the engine is straightforward. On Orca CLMM pools, it is an order of magnitude more code. On a PropAMM, it is essentially impossible — and Jump argues that is the entire design point: "Intra-block oracle updates and tightness of spreads compress the potential margin of sandwich attacks, often below the cost of executing them."
That is a fancy way of saying: if you cannot predict the state, you cannot sandwich it. The defense is mathematical, not procedural.
The Slippage Window — Where the Prediction Becomes a Lever
The practical use case I keep returning to: every swap on Solana carries a minimum_amount_out (or max_amount_in for an exact-output swap). This is the user's slippage tolerance encoded as a hard floor.
The same MEV report describes the canonical sandwich: "Three transactions atomically bundled together. First, the attacker executes an unprofitable front-run transaction, buying the asset to drive its price to the worst execution level allowed by the victim's slippage settings." The phrase "worst execution level allowed" is the whole game. The sandwich bot's job, in pure math terms, is to solve for the front-run size that takes the pool from its current state to exactly the point where the victim's transaction still barely passes the slippage check.
This is where Chorus.One's research becomes uncomfortable to read. They report that on Raydium "on average, 40% of transactions fail" — "mostly because of tight slippage allowed by user settings" — and that "at least 28% of transactions assumed to use the default value" of 1% slippage. One percent is a generous extractable window when stretched across a high-volume pool. The math falls out cleanly: the closer a user's slippage tolerance is to the actual realizable output, the smaller the sandwich window; the looser, the larger.
From the bot's side, this is purely a predicted-state computation. From the user's side, it is the difference between getting fairly executed and unknowingly tipping into a three-transaction bundle. I want to say this plainly: I am not building a sandwich bot. I am building a backrun arbitrage system. But the math underneath is essentially the same engine pointed at a different target, and pretending otherwise would be dishonest. If you are reading this and trading on a Solana DEX, your slippage tolerance is the most consequential number on your screen.
Where Prediction Fails — Five Ways To Lose Money
Writing the math down is the easy half. The hard half is the dozen ways the prediction silently goes wrong in production. Here are the ones I am currently designing around.
1. Stale reserves between read and execution
Between the moment I read pool state and the moment my bundle lands, the pool can move. Another bot, an unrelated user, a CEX-driven arb — anyone can land a transaction that changes x and y. My predicted state was correct for the state I read. It is no longer correct for the state the validator sees when my bundle lands. The result is usually a smaller-than-predicted profit, sometimes a loss after tips.
The defense is layered. First, minimize the gap between read and submit. Second, encode an on-chain profit assertion inside a custom program — an instruction that, before the bundle commits, checks that realized output is at least some threshold and reverts the entire bundle if not. The realized-output check is the only honest answer to race conditions: predict, but verify on-chain.
2. CLMM tick-array staleness
For CLMM pools, the post-swap state depends on which ticks are initialized and what liquidity_net they carry. A large unrelated swap that crosses a tick I did not load means my next prediction is using the wrong active-liquidity figure. Tick arrays can hold up to 88 ticks each. Tracking which ones are relevant and refreshing them when needed is non-trivial.
3. Token-2022 transfer fees
This is the one that took me longest to internalize. For tokens that use the Token-2022 transfer-fee extension, the amount that actually arrives in the pool's vault is less than the amount_in specified in the instruction — the difference is consumed as a transfer fee.
If my predicted state engine plugs the instruction's amount_in directly into the swap formula, it overestimates the input that reaches the pool, which means it overestimates dy, which means it predicts a profit that does not actually exist. Vadim's blog put this succinctly: "The only safe dx is vault_after - vault_before." In other words, do not trust the instruction; trust the observed vault balances.
The failure mode here is the platonic ideal of a silent bug: the prediction looks internally consistent, the bundle compiles, the simulation passes — and a slice of trades quietly bleeds because the input arriving at the math is wrong.
4. Interest-bearing and rebasing tokens
Same family of problem. Balances drift over time. Cached reserves go stale. The rule is the same: use observed vault balances from real-time account streams, not cached values.
5. Compute unit budget
Simulating a CLMM swap that crosses many ticks burns compute units. Solana caps transactions at 1.4M CUs. A complex bundle that includes a multi-tick swap plus your own backrun plus profit-assertion logic can edge close to the limit. Run out of budget and the whole thing fails. The prediction engine has to be aware of CU cost, not just numerical correctness.
None of these are exotic. They are the table stakes of the problem.
Simulation Is Not Optional
The pattern that keeps reasserting itself: predict in pure math, then simulate against the real RPC before committing. Solana's simulateTransaction runs the transaction against the validator's current state without committing it. A failed simulation costs nothing. A failed bundle with a real Jito tip costs the tip.
This is also the only honest way to validate that the predicted state engine is correct in the first place. If my predicted post-swap reserves and the simulation's reported post-swap reserves disagree, the engine has a bug. The simulation is the ground truth. The math is the speed.
An MEV report notes that in 2024 Jito processed over 3 billion bundles and generated 3.75 million SOL in tips. Even at the minimum tip of 10,000 lamports (one hundred-thousandth of a SOL), the cost of being wrong in volume is real money. Bundles that fail because the prediction was off do not get refunded.
Why CPMMs Become Hotspots
One more design note that I have been chewing on. Vadim's analysis points out that on Solana, CPMM pools become write-lock hotspots under high volume. Because every swap on a given CPMM updates the same pool account, all swaps on that pool serialize. Two parallel transactions touching the same Raydium pool can't both land in the same slot — they queue.
CLMM and DLMM avoid this in part because writes are distributed across tick arrays or bin accounts, so two swaps that touch different tick ranges can proceed in parallel. This is one of those rare cases where a Solana design choice (parallelism via account-locking) interacts with AMM math in a way that pushes liquidity providers toward concentrated designs almost as a side effect.
For my predicted state engine, this means CPMM contention is itself a source of uncertainty. Even if the prediction is mathematically perfect, if my bundle is fighting other bundles for the same pool account in the same slot, the order I land in determines the state I act on. I do not get to choose the order. The validator does.
What I Am Actually Building This Week
If you sliced open my project right now, the predicted state engine is the load-bearing math layer underneath everything else. It has three responsibilities:
- Given a snapshot of pool state and a pending swap, return predicted post-swap state. Per AMM type. With correct fee math. Using observed vault deltas, not instruction inputs.
- Be fast enough to run inside the detection window. Roughly 200 milliseconds is the holding window per the Coinmonks writeup; my computation has to be a small fraction of that, because I also need bundle construction time.
- Be honest about uncertainty. A predicted state that the engine knows is unreliable (Token-2022 token I don't recognize, PropAMM that I can't see the pricing model for, CLMM with tick arrays I don't have loaded) should return no quote, not a wrong one.
The third one is the discipline I keep failing at and re-learning. The easiest way to lose money in this game is to have the engine produce a number when it should produce a refusal. "I don't know" is a perfectly valid output. It is the output that protects capital.
What This Implies Going Forward
A few things are clicking into focus as I sit with this.
First, the AMM design choices on Solana are not neutral with respect to MEV. CPMMs are simple, hot, and easy to prey on. CLMMs and DLMMs are more parallel, harder to predict, and shift the extractable-window economics. PropAMMs and slot-aware AMM designs like the sr-AMM concept Umbra Research describes — which enforce that "no swaps get filled at a price better than the price at the beginning of the slot window" — are explicit attempts to engineer the predicted-state advantage away. Whether they win depends on whether LPs and users actually migrate to them, which depends on whether the fees and execution quality are competitive. Open question.
Second, the user-facing slippage problem is the elephant in the room. Twenty-eight percent of trades on Raydium running with the default 1% slippage is not a quirk — it is the entire economic substrate the sandwich industry feeds on. Wallets and frontends that surface and tighten slippage defaults probably do more for retail than any protocol-level fix.
Third, the gap between "I wrote the math" and "the bot is profitable" is not closed by the math. It is closed by the verification layer — simulation, on-chain assertions, vault-delta reads — that catches everything the math gets wrong because the math operates on assumptions about a world that has already moved on.
And that is the part I keep underestimating. The predicted state engine is not what makes a bot work. It is the floor on which everything else stands. Without it, nothing else has anywhere to be built. With it — and only with it — does it start to make sense to think about the rest of the stack.
Key Takeaways
- A predicted state engine is the deterministic computation of an AMM pool's post-swap reserves, prices, and accumulated fees from current state and pending-swap inputs. Every MEV decision on Solana depends on it.
- CPMM math (
x * y = k) is essentially a single formula plus a fee constant. CLMM is a tick-segment loop with sparse data structures. DLMM is bin traversal. Proprietary AMMs with off-chain pricing are essentially un-predictable from on-chain state alone, which is by design. - The largest hidden failure modes are silent: stale reserves between read and execution, Token-2022 transfer fees that shrink the actual input reaching the pool, and CLMM tick-array staleness. Each one produces a confident, internally consistent, wrong prediction.
- Simulation against the live RPC is the ground truth that validates the math, and an on-chain profit assertion in a custom program is the last-resort defense against race conditions. Predict in math, verify on-chain.
- Per Chorus.One, roughly 40% of Raydium transactions fail mostly due to tight slippage, while at least 28% use the default 1% setting. The extractable window for sandwich attacks is, mathematically, the slack a user gives up at slippage configuration — which means user-facing slippage UX matters more for protection than most retail traders realize.
Disclaimer
This article is for informational and educational purposes only and does not constitute financial, investment, legal, or professional advice. Content is produced independently and supported by advertising revenue. While we strive for accuracy, this article may contain unintentional errors or outdated information. Readers should independently verify all facts and data before making decisions. Company names and trademarks are referenced for analysis purposes under fair use principles. Always consult qualified professionals before making financial or legal decisions.