All articles
MEV·December 25, 2025·5 min read

Atomic Arbitrage Across Raydium and Orca: A Searcher's Playbook

Step-by-step guide to building and executing atomic arbitrage between Raydium and Orca pools in a single Solana transaction. Covers account locking, route discovery, and how to avoid failed transaction fees eating profit.

Raydium and Orca together account for the majority of Solana DEX liquidity, and the price discrepancies between their pools are real, frequent, and short-lived. Capturing them requires more than watching spreads — it requires building a transaction that locks both sides atomically, survives high-contention slots, and clears fees that would otherwise devour any edge you think you have. Here is what that actually looks like in practice.

Why Atomicity Is Non-Negotiable

On Ethereum you can simulate with eth_call and reason about state at a block boundary. Solana's execution model is different: accounts are locked at the transaction level, not the block level, so your two swap instructions must land in the same transaction or you are exposed to leg risk. If leg one settles and leg two fails, you hold an unwanted position with no recourse.

The mechanism that saves you is Solana's account locking semantics. Every transaction declares a static set of accounts it will read or write. The runtime rejects any other transaction touching those same writable accounts until yours resolves. Pack both your Raydium CLMM instruction and your Orca Whirlpool instruction into one transaction and the runtime treats them as a unit — both succeed or both fail, with no intermediate state written.

Route Discovery in Practice

Before you can build the transaction you need to know which pool pair is mispriced. The naive approach is polling both pool states on-chain, but at slot times of roughly 400 ms you will be stale by the time you react. A tighter loop subscribes to account change notifications via the accountSubscribe WebSocket feed, maintaining an in-process cache of the relevant pool states.

The accounts you need to watch per pool:

  • Raydium CLMM: the pool state account, the current tick array (determined by current sqrt price), and both vault accounts
  • Orca Whirlpool: the whirlpool account itself plus the tick array accounts indexed by the current tick index

When either side updates, recompute your expected output using the AMM math locally — no RPC call. For CLMM and Whirlpool pools this means implementing the sqrt-price based swap simulation, but the arithmetic is deterministic and fast. You are looking for: amountOut(leg1) > amountIn(leg1) with amountIn(leg2) = amountOut(leg1) and amountOut(leg2) > amountIn(leg1). The excess is gross profit before fees.

Instruction Layout and CU Budgeting

Solana transactions have a 1232-byte size limit and a per-transaction compute unit cap (currently 1.4 million CUs, though the practical soft limit is lower for priority landing). A two-leg arb across CLMM and Whirlpool with a single hop each will consume roughly 120k–180k CUs depending on tick crossings. Tick crossings are the variable you cannot fully control — a large swap moving price through multiple ticks inflates CU usage unpredictably.

Your instruction order matters:

  1. ComputeBudgetProgram.setComputeUnitLimit — set to your simulated estimate plus a 20% buffer
  2. ComputeBudgetProgram.setComputeUnitPrice — your priority fee in micro-lamports
  3. Leg one swap instruction (input token → intermediate)
  4. Leg two swap instruction (intermediate → input token)

Always specify slippage = 0 on both legs if your simulation is accurate. Any tolerance you introduce is profit you leave on the table — and more importantly, it allows the transaction to land in a marginal state where the arb barely covers fees.

The Fee Trap and How to Avoid It

This is where most searchers bleed out. On Solana, failed transactions still cost priority fees. Unlike Ethereum where failed transactions burn gas but the searcher chose to broadcast, on Solana the fee is taken the moment the transaction is processed regardless of outcome. If your simulation is stale or your slippage math is wrong, you pay the priority fee for a transaction that reverts.

The mitigation is a simulation gate. Before broadcasting, call simulateTransaction with replaceRecentBlockhash: true and commitment: processed. If simulation fails, do not send. Yes, this adds latency — roughly 10–30 ms round-trip to a colocated RPC — but it eliminates a class of losses that compound badly when markets are choppy. You should also track your simulation hit rate over time. A hit rate below 85% suggests your in-process price model is drifting and needs recalibration.

Additionally, build a hard floor into your profit calculation. At a priority fee of 100k micro-lamports per CU and 150k CUs of consumption, you are paying ~0.015 SOL per attempt. If expected profit does not clear that threshold by at least 2x, the transaction should not be queued. Thin arbs are fee traps with extra steps.

Handling Slot Contention

Popular pools attract multiple searchers. You will lose transactions to account conflicts — another transaction touched one of your locked accounts first, and yours was discarded. This is not failure in the traditional sense; the transaction never reached execution. The observable symptom is a high rate of AlreadyProcessed or blockhash expiry errors without simulation failures.

Your response here is twofold. First, minimize the number of accounts your transaction touches — use token accounts you pre-initialize rather than creating them inline, and avoid redundant reads. Second, subscribe to the Jito block engine and submit through their bundle endpoint. Bundles give you atomic execution guarantees at the leader level and reduce the probability of account conflicts with competing searchers by letting you outbid for slot inclusion directly.

The combination of fast local simulation, precise CU budgeting, and Jito bundle submission is what separates production Solana trading bots from backtesting experiments. Each layer reduces a different category of loss: simulation gates kill fee bleed, CU precision avoids compute cap rejections, and Jito reduces ordering conflicts.


If you want to move from theory to a live searcher on Solana, our team builds and operates these systems end to end. Get in touch to discuss what a production deployment looks like for your strategy.

Need a bot like this built?

We design, build and run trading bots on Solana, Hyperliquid and Polymarket.

Start a project
#MEV#Solana#arbitrage#Raydium#Orca#DeFi#trading-bots