Ring feasibility, zombie orders, and why 23/23 profitable rings turned out to be 0/14

Measuring the unexploited CoW/ring surface: a negative result (and two bugs I found in my own analysis)

I’m an independent developer building toward the solver competition. Before writing a search algorithm, I wanted to measure whether an unexploited direct-matching surface actually exists — order pairs that cross directly, and 3–4 token rings — rather than assume it. The answer, in my corpus, was mostly no. Posting the method and numbers because negative results rarely get written up, and because I’d like the people who actually run solvers to tell me where I’m wrong.


TL;DR

  • Direct crossings and rings are detectable in essentially every auction, but the overwhelming majority are dead orders — cancelled, expired, or with drained balances/revoked allowances (60–94% zombie rate depending on network and structure).
  • Of the fillable ones, 56% of rings fail the basic feasibility condition — no uniform clearing price exists that satisfies every leg’s limit simultaneously.
  • The genuinely feasible remainder carries surplus two to eight orders of magnitude below settlement gas cost on mainnet.
  • Mainnet vs L2 differs sharply: mainnet crossings cleared estimated gas 0/15; Arbitrum crossings cleared 6/6 (4/6 at 5x). Small sample, but the direction is what cheap L2 gas would predict.
  • I found two bugs in my own analysis along the way, one of which had produced a spectacular false positive (23/23 rings “profitable”). Both are documented below, because the corrected numbers are only meaningful if you can see how the wrong ones happened.

Why I looked

The intuition that draws people to this protocol is that a batch auction should contain matchable structure — coincidences of wants, and longer cycles — that a naive router misses. If that structure exists in quantity and is being left uncaptured, it’s an obvious entry point for a new solver.

That’s a testable claim, so I tested it before building anything.

Method

Corpus. Polling the public solver_competition/latest endpoint for mainnet and Arbitrum, archiving each new auction (gzipped, deduplicated by auctionId). The auction payload lists orders by UID only, so I built a persistent UID-keyed cache of order details fetched from /api/v1/orders/{uid} (rate-limited, ~2.2 req/s effective, capped per poll).

Detection. For each auction: find order pairs that directly cross (A sells X for Y, B sells Y for X, limits overlapping), and build the directed token graph from resting orders to find simple cycles of length 3–4 with overlapping limits.

Validation against reality. Detection alone proves nothing. For a sample of detected opportunities I checked, against current chain state:

  • balanceOf and vault-relayer allowance for each order’s owner
  • authoritative order status from the API (invalidated, expiry, fill-or-kill flags)

Exact settlement math. For the survivors, an exact max-surplus solver — rational arithmetic throughout (Fraction, no floating point until the final ETH conversion), vertex enumeration over the LP, since k ≤ 4 makes the problem tiny.

Gas model. The per-trade gas model from crates/price-estimation/src/gas.rs (verified to reproduce the driver’s solution-gas-offset default of 106,391 exactly), cross-checked against 15 recent real settlement receipts per network: mainnet mean 440,591 gasUsed at 0.31 gwei; Arbitrum mean 600,467 at 0.02 gwei.

The feasibility condition

For a ring of orders o₁: T₁→T₂, o₂: T₂→T₃, …, o_k: T_k→T₁, let r_i be order i’s limit rate (minimum units of T_{i+1} required per unit of T_i sold).

Under uniform clearing prices p, order i receives at rate p_{T_i}/p_{T_{i+1}}, so its limit requires:

p_{T_i} / p_{T_{i+1}} ≥ r_i    for every i

Multiplying around the cycle, the left side telescopes to 1:

∏ r_i ≤ 1

This is necessary, and sufficient for a satisfying price vector to exist (the slack can be distributed across the cycle). Usefully, 1 − ∏ r_i is the ring’s entire surplus budget — everything the solver could possibly extract or return to users. In my sample, for feasible rings, that slack was consistently minuscule: limits overlapped by a hair, not by enough to pay for a settlement.

Results

Sample: 100 crossings + 50 rings per network, drawn most-recent-first from a ~56-auction corpus, plus a re-check of previously flagged rings (53 rings total after correction).

Mainnet crossings

Stage Count
Detected (deduplicated) 100
Fillable now 15 (14 full, 1 partial)
Zombie 85
Clears 1x estimated gas 0 / 15

Zombie causes (leg-level, an opportunity can have multiple dead legs): no balance/allowance 56, fill-or-kill with insufficient funds 26, cancelled 24, expired 12.

Size compatibility was also poor: of 15 with computable overlap, 0 would fill ~100% of both sides. Mean fill of side A: 13.4%; side B: 86.7%.

Rings (mainnet, corrected)

Stage Count
Detected (deduplicated) 53
Fillable now 32
Limit-compatible (∏ r_i ≤ 1) 14
Clears 1x estimated gas 0 / 14

Exact surplus on the 14 feasible rings ranged from ~1e-6 down to ~1e-12 ETH, against a settlement cost around 1.4e-4 ETH — short by roughly 2 to 8 orders of magnitude.

Arbitrum — the one asymmetry worth flagging

Stage Crossings Rings
Detected 100 50
Fillable now 6 (all partial) 0
Clears 1x gas 6 / 6
Clears 5x gas 4 / 6

Very small sample (one auction scanned), but with gas roughly an order of magnitude cheaper and settlements priced at 0.02 gwei, thin surfaces that die on mainnet economics plausibly survive on L2. This is the result I’d most like informed pushback on.

Two bugs I found in my own analysis

Publishing these because the corrected numbers are only credible if the errors are visible.

1. Rotational duplicates inflated ring counts 2.5–3x. The cycle search tries every token as a DFS root, so one physical ring A→B→C→A was rediscovered once per starting node. Fixed by deduplicating on the frozenset of order UIDs. On a test auction: 279 found / 77 unique before, 79 / 79 after.

2. The feasibility inequality was backwards — and this one produced the headline false positive. My first pass checked ∏ r_i ≥ 1 instead of ≤ 1. Combined with an approximate volume calculation that treated each leg’s size independently rather than propagating flow around the cycle, this yielded “23 of 23 fillable rings clear gas, several by large margins.”

That result should have been suspicious on structural grounds and was: rings are strictly harder than crossings — more legs, more gas, and surplus must survive the full cycle of limits. If 2-leg opportunities never clear gas, 3–4-leg opportunities always clearing it is not a plausible market state. Re-deriving the condition three independent ways (clearing-price telescoping, direct multiplication of each order’s own constraint, and consistency with the already-validated 2-order case) surfaced the sign error.

A detail I found telling: the old approximate formula was structurally incapable of valuing a real ring, because it refused to return a number whenever the loop product was below 1 — precisely the condition that defines a feasible ring. It could only produce values for infeasible ones.

The exact solver was also cross-checked against an independent brute-force grid, which found a case where the LP located a strictly better point than the naive approach — verified by hand before I trusted either.

Limitations (please weight these)

  • Small, correlated sample. Tens of auctions, drawn from a short window; the same resting orders persist across consecutive auctions, so these are not independent observations.
  • Current-state checking, historical detection. I check balances/allowances now against opportunities detected earlier. This can only make old auctions look more zombie-heavy than they were (orders go alive→dead, not the reverse). Sampling most-recent-first minimizes but doesn’t eliminate the bias.
  • Survivorship. Opportunities profitable enough to capture may have been captured before my snapshot. My corpus sees the residue.
  • Low-gas regime. Mainnet at 0.31 gwei is not a stressed market. Conclusions about gas thresholds are regime-dependent — though the surplus shortfall here is so large that gas would have to move by orders of magnitude to matter.
  • Order-detail coverage was incomplete during the first pass (13.5% mainnet / 65.7% Arbitrum, climbing from a cold cache), so detection counts are floors.
  • No interaction-level detail in the public schema, so “did the winner match these orders directly vs route through an AMM” is inferred, not proven.

What I take from it

Both surfaces read as real but thin in this corpus. The professionals capturing approximately none of them looks like correct behavior rather than oversight — there’s very little there to capture. That’s a useful thing to learn in a day rather than after months of building a combination-search engine on the assumption.

Questions for people who actually run solvers

  1. Does this match your experience? Is direct CoW/ring matching a meaningful revenue component for anyone, or is essentially all value in execution quality against external liquidity?
  2. Is the L2 asymmetry real? Do thin crossings become economic on Arbitrum/Base in a way they aren’t on mainnet, and is anyone systematically working that?
  3. Historical auction data. The prod /api/v1/auction route returns 403 publicly (marked in-code as liveness-checking only as of late 2025), so I’m reconstructing from solver_competition snapshots and building my own corpus forward in time. Is there a sanctioned path to historical auction data for solver R&D? A larger and older sample would address my biggest limitation directly.
  4. Am I wrong about the feasibility condition or the surplus budget framing? I’d rather be corrected publicly than build on it.

Happy to share the analysis scripts — the exact ring-settlement solver in particular is dependency-free and might be useful to others regardless of what it concluded.

1 Like

Nice write-up @Mr_Robot!
I will check if it’s possible to make the auction/competition data available. It was/is an interest of mine to build a dashboard in the explorer for coincidence of wants.

1 Like