One-Step Closer to Decentralized MEV: Unlocking Circular Swaps

Why Carbium supports circular arbitrage swaps ((TokenA) -> (TokenB) -> (TokenA)) and why other providers gatekeep them to protect their own MEV revenue.

Share
One-Step Closer to Decentralized MEV: Unlocking Circular Swaps Carbium Blog post banner
Carbium Blog Banner: One-Step Closer to Decentralized MEV

In the high-stakes world of Solana MEV (Maximal Extractable Value), knowledge is profit. Yet, as the percentage of SOL held by MEV bots and their equivalents rises toward increasingly risky levels, the ecosystem faces a growing centralization threat. For years, the most lucrative strategies, specifically Circular Arbitrage (Full-circle swaps), have been the exclusive domain of elite searchers and validator-aligned trading firms.

Today, Carbium is changing the game. By natively supporting circular swaps via our DEX API, we are taking a massive step toward democratizing MEV.


The Forbidden Trade: What is Circular Arbitrage?

A circular swap is the purest form of market inefficiency. It involves routing a token through one or more intermediate assets and returning to the starting token, profiting from price discrepancies across pools.

The Loop: SOL → USDC → SOL

If you start with 10 SOL and finish the loop with 10.05 SOL, you have extracted value from the network risk-free (atomic execution). This is the most ethical form of MEV. It supports market efficiency.

Mermaid chart for Circular Swap (Arbitrage) handled by Carbium API. graph LR      START((Token A)):::start      subgraph LEG1["Leg 1"]         Q1[getQuote<br/>A → B]:::quote         AMM1[AMM1]:::amm     end      MID[(Token B)]:::token      subgraph LEG2["Leg 2"]         Q2[getQuote<br/>B → A]:::quote         AMM2[AMM2]:::amm     end      FINAL[(Token A')]:::token      CHECK{A' > A?}:::check     YES[Execute]:::execute     NO[Skip]:::skip      %% Connections     START --> Q1     Q1 --> AMM1     AMM1 --> MID     MID --> Q2     Q2 --> AMM2     AMM2 --> FINAL     FINAL --> CHECK     CHECK -->|Profit| YES     CHECK -->|No Profit| NO     YES -.-> START
Circular Swap Mermaid provided by Carbium API

Why Don't Other APIs Support This?

If you look at the documentation of major DEX aggregators or RPC providers, you will rarely find native support for circular routing. Why?

It eats their bread.

Many infrastructure providers operate in a conflict of interest. They have internal trading teams or exclusive deals with top searchers. If an API provider spots an arbitrage opportunity:

  1. They capture it themselves (internal MEV).
  2. They sell the signal to a preferred partner (often users with exclusive "all-access" API tiers).
  3. They arbitrage their own users' trades, effectively trading against the clients who trust them.
  4. Last priority: They let you, the public API user, see it.

Building an API that makes circular arbitrage easy for the public effectively destroys their own alpha. They are incentivized to keep the barrier to entry high.


The Proof is in the Profits

To understand why this access is gated, one only needs to look at the revenue generated by the top arbitrage programs. These exclusive bots extract millions of dollars in value from the network monthly.

Data via Sandwiched.me (Last 30 Days)

Rank Arbitrage Program Profit (SOL)
#1 JUP6L...TaV4 3,196 SOL
#2 King7...cb7T 2,584 SOL
#3 NA247...TUV 1,589 SOL
#4 CroWg...7aK 1,257 SOL
#5 9GCBb...vQQ 1,236 SOL

These 5 programs alone captured over 9,800 SOL in pure profit in just one month. This is the "bread" that legacy providers are reluctant to share. In the worst case, the bad performance you experience with different protocols is because you're being harvested.

Arbitrages | Solana MEV | Sandwiched.me
Explore real-time arbitrage opportunities and historical data across Solana DEXs and liquidity pools

The "Solana Centralization" Problem

The massive accumulation of wealth shown above isn't just a matter of fairness; it represents a structural risk to the Solana network. When MEV extraction is restricted to a small circle of elite players, SOL accumulates in fewer and fewer hands.

This concentration creates two critical threats:

  1. Validator Leverage: Large MEV entities often stake their accumulated SOL with specific validators to gain favorable treatment or faster inclusion. This creates a "pay-to-play" dynamic where independent validators struggle to compete against those backed by MEV cartels.
  2. Censorship Risks: As fewer entities control the transaction supply chain, the network becomes more susceptible to censorship. If a dominant searcher or block builder decides to exclude certain transactions to protect their own strategies, the fundamental promise of a permissionless blockchain is compromised.

By keeping circular arbitrage tools exclusive, legacy providers are inadvertently accelerating this centralization.


The Technical Unlock

Historically, participating in this level of arbitrage required writing complex Rust programs, deploying them on-chain, and managing your own Geyser plugins to index state. You needed geographically placed high-performance servers starting from $200 a month just to compete. It was an engineering barrier that kept 99% of developers out.

With Carbium, the complexity moves from your infrastructure to our API. You can now detect and execute circular swaps using simple, off-chain logic in JavaScript or Python.

Here is what the logic looks like:

// A simple "Circular Loop" check using Carbium API
async function checkArbitrage(amountIn) {
  // Leg 1: Quote SOL -> USDC
  const leg1 = await getQuote(SOL_MINT, USDC_MINT, amountIn);
  if (!leg1) return;
  const usdcAmount = leg1.outAmount;

  // Leg 2: Quote USDC -> SOL
  const leg2 = await getQuote(USDC_MINT, SOL_MINT, usdcAmount);
  if (!leg2) return;
  const finalSolAmount = leg2.outAmount;

  // Did we make money?
  if (finalSolAmount > amountIn) {
     const profit = finalSolAmount - amountIn;
     console.log(`Arbitrage Opportunity! Profit: ${profit} lamports`);
     // Execute atomic transaction...
  }
}

Our API handles the heavy lifting, validating the routes, checking liquidity depth, and bundling the instructions into a Versioned Transaction that you simply sign and submit. If the opportunity disappears between the quote and execution, the transaction reverts, saving you from bad trades.


The Catch: A Positive Quote Is Not Profit Quarantee

Here is where most circular-arb tutorials stop, and where most circular-arb bots lose money. The check above will fire. It will fire often. But a positive quote is not yet a profit guarantee, it is a signal that deserves a proper net check.

Two things decide whether a positive cycle is real, and the first one catches almost
everyone.

Size

Quotes are sized in token units, not dollars. So a cycle that looks profitable can be
nothing more than a rounding artifact on a dust trade. We measured the same BONK cycle, in the same minute, at two different sizes:

Notional Cycle Δ
~$0.02 (1,000 BONK) +17 bps
$1,000 −1,076 bps

Nothing changed but the size, and a 17 bps "opportunity" inverted into a 10% loss. If you scan at whatever amount happens to be in your wallet, you are not finding arbitrage, you are finding rounding.

The fix is to price every cycle to a fixed USD notional before comparing anything. And once you are sizing properly, you can drop the two-leg chain entirely: our router accepts the same mint as both src_mint and dst_mint, searches for a cycle, and returns what one round trip yields in a single call, with no risk that your two legs stop agreeing with each other between requests.

const BASE = "https://api.carbium.io/api/v2";
const get = (path) =>
  fetch(`${BASE}${path}`, { headers: { "X-API-KEY": process.env.CARBIUM_API_KEY } })
    .then((r) => r.json());

// 1. Price the token, so the cycle is sized in dollars and not in wallet dust.
const { srcAmountUsd } = await get(
  `/quote-usd?src_mint=${mint}&dst_mint=${USDC}&amount_in=${oneToken}&slippage_bps=50`,
);
const amount = BigInt(Math.round((NOTIONAL_USD / srcAmountUsd) * 10 ** decimals));

// 2. Same mint in, same mint out. One call. The router finds the cycle.
const q = await get(
  `/quote?src_mint=${mint}&dst_mint=${mint}&amount_in=${amount}&slippage_bps=50`,
);

const inAmt = BigInt(q.srcAmountIn);
const outAmt = BigInt(q.destAmountOut);
const bps = Number(((outAmt - inAmt) * 10_000_000n) / inAmt) / 1000;

Cost

A round trip has to clear the cost of landing the transaction before it is worth
anything, base fee plus whatever priority fee the current market demands. Then it has to survive slippage, other searchers watching the same route, and the chance the route changes before execution lands.

Subtract the fee first. A cycle that shows +8 bps on $1,000 is $0.80 of gross edge, and that is not a trade, it is a rounding error with extra steps.

What clearing the bar actually means

A cycle that survives both filters is a real candidate, not a promise. It is the point
where execution work becomes worth considering: construct the atomic transaction, model the current fee and slippage budget, then measure what actually lands. Quoting is free and reversible: /quote and /quote-usd are read-only GETs that sign nothing and broadcast nothing. Execution is the separate step that turns a route into a result.

You do not need a colocated server just to investigate, quote, or execute circular routes. Colocation is an advantage on the shortest-lived, most crowded edges to MEV. A well-engineered remote searcher can still pursue wider or more durable edges; it just should not pretend to have the same execution odds as a specialist operating beside the fastest path to the leader.

The point of the scanner is not to print Arbitrage Opportunity! at every dust-sized rounding artifact. It is to give more builders a credible starting signal, then let real execution results decide whether a route is worth pursuing.

The full scanner sized in USD, net of transaction cost, across SOL, USDT, JUP and
BONK is swap-cycle-scanner.mjs in the Carbium Cookbook. It runs against
the live API and is re-verified in CI every Monday. For the longer walkthrough, see
Build a Solana Arbitrage Quote Engine.

npm run swap:cycles          # defaults to $1,000 notional
node --env-file=.env examples/swap-cycle-scanner.mjs 5000

What Actually Decides Who Captures It

The edge is real. Cycles do clear, and they clear more often than the sceptics claim.
What separates the searchers who capture them from the ones who watch them evaporate is almost never the thing people optimise first.

Here is the order that actually matters, measured rather than assumed.

1. You are always trading on stale state, so price that first

Solana targets a ~400 ms slot, and each leader holds four consecutive slots. Our own swap quote for 1 SOL to USDC returned in 395 ms. Read those two numbers together: by the time a quote reaches your process, roughly a slot has passed and the pool state it described may already be gone.

This is not a flaw to engineer away. It is the actual shape of the problem. Every
downstream decision follows from accepting that you are reacting to a photograph and not a live feed: how much margin you demand over cost, how wide your slippage tolerance runs, whether you re-quote before signing.

Searchers who lose money on paper-profitable cycles have usually not made this
assumption explicit anywhere in their code.

2. Reuse the connection, the largest free win in the stack

Measured against our own endpoint: a cold first call took 151-254 ms. The warm median over eight calls was 73 ms.

That gap of roughly 80 to 180 ms is pure TLS handshake, and you pay it on every single request if your client opens a new connection each time. It is larger than any gain you will get from rewriting your bot in a faster language, and it costs nothing but a persistent client held across calls.

If you benchmark without warming the connection first, you are not measuring the API. You are measuring your own handshake.

3. Subscribe instead of polling

A polling loop learns about the market on your schedule. A subscription learns on the market's.

Our transactionSubscribe stream measured ~117 notifications per second on a busy account. No polling cadence you can afford gets close to that, and the gap is not incremental: polling structurally cannot see a state change that opens and closes between two of your requests.

If your strategy depends on reacting to pool state, streaming is not an optimisation. It is the difference between reacting and guessing.

4. Then, and only then, geography

Colocation compresses the network term. It is genuinely decisive on the shortest,
most-contested routes in the majors, where the winner is separated from the loser by single-digit milliseconds and the participants are specialists.

But it is fourth on this list for a reason. Colocating a bot that opens a fresh TLS
connection per quote and polls on a timer is a race car with the handbrake engaged. Fix the order above first, because those wins are free and they are larger.

And be clear about what colocation buys: better odds on a specific kind of edge. It is not an entry ticket to MEV, and its absence is not a reason to stay out.

5. Language matters less than you think, until suddenly it does

For quoting, sizing, and signal generation, the bottleneck is network I/O, not CPU. Node is entirely adequate. Every recipe in our cookbook is plain Node, and the streaming and Swap examples carry no dependencies at all.

The honest test: if your p99 is 400 ms and your language change saves you 2 ms, you do not have a language problem. You have a network problem.

Rust earns its keep at a specific threshold, which is when you stop asking an API for quotes and start reconstructing pool state locally from a Geyser firehose. At thousands of account updates per second, garbage-collection pauses stop being an abstraction and become your tail latency directly. That is a real reason to reach for Rust. "It is faster" is not.

Rewrite when you have measured the pause, not before.

6. Atomicity is not optional

A circular arb must be one transaction. If leg one lands and leg two does not, you are no longer arbitraging. You are holding unpriced directional risk you never agreed to take.

Two constraints bite here, and long routes hit both:

  • 1232 bytes per transaction packet
  • 1.4M compute units per transaction

Address lookup tables compress account references and buy you room. Past that, the routemis simply too long to land, and the correct move is to take the shorter, less profitable path that actually executes.

7. Bid the percentile, not the maximum

A static priority fee is always wrong: either you are overpaying on quiet blocks or you are not landing on busy ones.

Sample what recent blocks actually paid for transactions touching your accounts, and bid a percentile of it. The p75 we measured on SOL was 6 microlamports per compute unit.
The maximum in any sample is usually a single outlier bidding against itself, and pricing off it is how a thin edge becomes a loss at the fee line.

8. Where the edge actually lives for everyone else

This is the part the speed narrative obscures.

On the shortest routes between the largest pairs, you are competing against colocated specialists, and you will lose. That contest is decided in milliseconds you do not have.

But that is one arena, not the whole market. The durable edge for a well-engineered remote searcher is selection, not speed:

  • long-tail mints that nobody is quoting continuously
  • pools that are new enough that coverage is thin
  • venues outside whatever the current bot consensus watches
  • hours when competition genuinely thins out

Being 50 ms slower is irrelevant on a route no one else is quoting at all. The searchers who survive without a rack in Frankfurt are, almost without exception, the ones who stopped racing and started looking somewhere else.

9. Score yourself on what lands

Quoted basis points are a hypothesis. Realised basis points are the result.

Log both, on every attempt, and watch the spread between them. That spread is your actual edge, not your quote count, not your latency graph, not your scanner's candidate rate. It is the only number that tells you whether any of the work above paid for itself.

Most searchers never measure it, which is precisely why most searchers cannot tell you whether they are profitable.


The Carbium Philosophy: MEV is for Everyone

At Carbium, we believe that a decentralized blockchain deserves decentralized MEV. We don't run internal bots to frontrun our users. We build the highway, we don't block the traffic.

Our Quote API is designed to be agnostic. If there is a profitable route from Token A back to Token A, our engine will find it and serve it to you with the same speed and reliability as a standard swap.

How We Enable It

  1. Atomic Execution: Our API constructs the full transaction (all legs of the swap) into a single, atomic Versioned Transaction. If one leg fails, the whole trade fails, protecting you from holding "bags" of intermediate tokens.
  2. Zero-Conflict Execution: We forward your transaction directly to the leader. We don't inspect it for our own profit.
  3. Binary-State Management: With sub-100ms latencies on our data streams, you see the opportunity at the same time as the "pros."

The Inevitable Shift

The amount of Solana held by MEV extractors is becoming a growing problem on Solana. As capital concentrates in the hands of a few gatekeepers, the risk of centralization increases. By opening these strategies to everyone, we dilute this concentration and distribute value back to the broader developer community.

Business-Scale MEV extraction is a long-term risk for Solana in the same way concentrated mining is for Bitcoin.

The days of gatekept markets are numbered. It was always just a matter of time before institutional-grade tools became the standard for everyone. Carbium is accelerating the inevitable shift in the paradigm.

If you are coding your first bot or optimizing a complex engine, the playing field is finally level. Dive into our documentation, now fully optimized for AI-assisted development, to start building today.

Build a Solana Arbitrage Quote Engine | Carbium DEX API
Tutorial: Build a circular arbitrage bot on Solana using the Carbium DEX API. Detect profitable token routes (SOL-USDC-SOL) and automate quotes programmatically.

If you are building a swap flow or interested in atomic arbitrage, explore Carbium Swap API:

Carbium API | Full-Stack Solana Swap, Trading & RPC Infrastructure
Carbium is a Swiss-hosted, full-stack Solana API: multi-DEX swap routing, RPC, and trading infrastructure behind one key. 0.08% per swap, MEV Protection V2, and a public REST API for wallets, bots, and trading teams.
Carbium Services
Reliable Solana swap, quote and swap APIs, validator staking, and RPC services for developers and businesses.

Explore Carbium Solana Infrastructure, DEX, RPC and APIs at https://www.carbium.io


Technical Reference & Resources

State of Solana MEV May 2025
Summary of our Solana Accelerate talk (The State of Solana MEV), with all the charts and data.
GitHub - Ukkometa/carbium-cookbook: Runnable, continuously tested recipes for the Carbium Solana RPC and Swap API.
Runnable, continuously tested recipes for the Carbium Solana RPC and Swap API. - Ukkometa/carbium-cookbook