createSwapRouted is the entry point an LP should
almost always use. In a single transaction it prices both underwriting rails off
the same on-chain fair value, gives the LP the cheaper of the two, and — this
is the load-bearing property — falls back to the always-on pool whenever the MM quote
is not strictly better or not usable, without ever reverting on the MM’s account.
It is the concrete expression of the floor/ceiling framing: the
cvAMM pool (Path A) is the floor of liquidity — always a
code-capped price — and the MM rail (Path B) is the ceiling of
price — a pure price-improvement layer that can only ever undercut the floor, never
degrade it. The router is what wires those two facts together for the LP.
One FairPremium
Both rails priced off the same
FairPremium, single VolOracle poke.Strict-beat, ties to A
The MM wins only if
premiumB < premiumA. A tie resolves to the pool.Never reverts on the MM
A bad / stale / absent MM quote silently falls back to the pool — zero trace (I7).
The one-line decision
The entire routing rule is one boolean:usableB, premiumB, and premiumA — honest, comparable, and side-effect-free
until exactly one rail is executed.
The router emits
SwapRouted(swapId, pathB, premiumA, premiumB)
on every fill. The chosen rail, and both candidate
prices it was choosing between, are written to the chain — the cheapest-wins decision
is fully auditable after the fact, and feeds the pool-vs-MM spread signal
of the data moat.Step 1 — both rails priced off the same FairPremium
A fair comparison requires a common baseline. The router computes oneFairPremium for the position and prices both rails on top of
it, so the only thing that differs between premiumA and premiumB is the load,
never the fair value underneath.
The shared read prologue (_prepareSwap) and the
fair-value read (_fairPremium) run once; the
VolOracle is poked exactly once to refresh σ_ref, and both rails
read the result. The two candidate premiums are then the
same FairPremium with two different loads layered on:
Both are additionally capped at MaxIL (never charge more than the maximum possible
payout), and the Path-A load sum is hard-clamped
by invariant I10, min(..., maxLoad), by construction in
code. Path A is computed by _pricePathAFromFair; Path B’s price comes back from the
usability mirror described next. See the pricing stack and
the load stack for how each load is built.
Step 2 — usableB: the non-reverting mirror of Path B
This is the heart of the routing safety story. The router does not call the
reverting Path-B gate. It calls _quoteUsableAndPremiumB,
a view function that mirrors every Path-B check and returns (usableB, premiumB)
— (false, 0) instead of reverting whenever any check fails.
It returns (false, 0) if the MM quote is any of:
Absent, wrong-model, or dust
Absent, wrong-model, or dust
No quote supplied,
model != FULL, or the position/premium fails the
MIN_POSITION_V0 = $100 / MIN_PREMIUM = $1 dust floors.Over-load (I10)
Over-load (I10)
loadBps > maxLoadBps — the same I10 ceiling the reverting path enforces, evaluated
as a boolean here instead of a revert.Expired or out-of-validity-band
Expired or out-of-validity-band
validUntil <= now, or secondsAhead outside the [5s, 15s] window.Bad price band or out-of-oracle-band (I9)
Bad price band or out-of-oracle-band (I9)
priceBandBps outside [25, 500], or the live oracle has drifted beyond the band:
absBps(P_live, quotePrice) > priceBandBps — see price pinning.Out-of-ratio, over-capacity, or nonce-used (I7)
Out-of-ratio, over-capacity, or nonce-used (I7)
The LP’s
ratioBps = maxIL·1e4/V0 outside the quote’s MaxIL-ratio band;
consumedNotional[quoteId] + V0 > maxNotionalV0; or the bitmap nonce already used.Undercollateralized, zero-price, or bad signature
Undercollateralized, zero-price, or bad signature
availableBalance(mm) < maxIL; a zero quotePrice; or the EIP-712 / EIP-1271
signature failing verification (checked via STATICCALL)._quoteUsableAndPremiumB is view. It reads
isNonceUsed, consumedNotional, availableBalance, and the signature (via
STATICCALL), but it never calls _useNonce, never increments consumedNotional, and
never locks collateral. A quote that is evaluated but not chosen mutates no
state whatsoever — it leaves zero trace.
Step 3 — the route: strict-beat, ties to Path A
1
Strict-beat (< not ≤)
The MM wins only if it strictly undercuts the pool. This is what makes the MM a
genuine price-improvement layer: it captures flow only when it offers the LP a real
saving, not when it merely matches.
2
Ties resolve to Path A
When
premiumB == premiumA, useB is false and the swap goes to the pool —
the dependency-free, always-on rail. An MM cannot divert flow by matching the
pool’s price; it must beat it. This protects the floor: the rail with no relayer,
no validity clock, and no off-chain dependency is the default.min(premiumA, premiumB_if_usable) and is always
served — the pool floor guarantees a fillable price exists, and the MM ceiling can only
push the LP’s cost down.
Step 4 — only the executed rail mutates state (I7 preserved)
After the boolean resolves, exactly one rail executes, and only that rail mutates nonce, capacity, or lock:
consumedNotional[quoteId] ≤ maxNotionalV0, and a cancelled bitmap-nonce bit can
never fill.
Because the losing rail’s usability is evaluated through a view mirror, a Path-B quote
that loses the route consumes no capacity, burns no nonce, and locks no
collateral. An MM’s quote cannot be silently drained by an LP who ends up routing to
the pool — the on-chain ledger only ever moves for the rail that actually filled.
On Path A, the lock additionally passes the pool’s structural checks —
free ≥ amount
and the senior-protection invariant totalLocked ≤ juniorAssets. So even the fallback rail enforces
depositor-protection at lock time; the router never bypasses it.What does revert — and why those are correct
The router does not revert on the MM. It does revert on protocol-level failures, because those are not “the MM quote was bad” — they are “this swap cannot exist at all”:
In every one of these cases, the swap is invalid for both rails — so reverting is the
correct, honest outcome. The router’s promise is narrow and precise: a bad MM quote
never reverts; an invalid swap always does.
The LP-always-served guarantee, stated precisely
Putting the pieces together,createSwapRouted gives the LP a guarantee that no
single-counterparty design can:
1
A fillable price always exists
The pool is the always-on floor. Whenever the swap is valid at all (owner, in-range,
market wired, above dust), the pool can fill it at a code-capped (I10) price.
2
The MM can only improve it
The MM rail is a read-only price-improvement layer. It wins only by strictly beating
the floor; it can never make the LP pay more, and a tie keeps the LP on the pool.
3
A misbehaving MM is invisible to the LP
Stale, leaked, undercollateralized, or absent MM quotes degrade to the pool with no
revert and no state change. The LP’s experience is identical to the MM not existing.
4
The settlement core is the same either way
Whichever rail filled,
settle is the single untouched core:
pin the Chainlink round-at-T, compute IL with the stored L (I6), pay
min(realized_IL, MaxIL) (I1 + I2) from the rail’s own vault, return the NFT.Worked example — live on Arbitrum Sepolia
The 2026-06-05 redeploy ran a real routed create→settle against one 300s market:- Routed swap #2 — MM won
- Path A swap #1 — pool baseline
createSwapRouted priced both rails off one FairPremium:premiumA_cvamm= $13.80 (pool, with its on-chain load stack)premiumB_mm= $8.93 (MM,loadBps1000)
usableB == true and 8.93 < 13.80, useB was true → the MM won.
MaxIL $3,215.65 was locked from the MM’s own UnderwriterVault collateral,
realized IL came to $245.66, payout $245.66, settled from the MM’s
collateral. The pool’s nonce/capacity were untouched — only the executed rail moved.SwapRouted event on swap #2 carries (premiumA = 13.80, premiumB = 8.93, pathB = true) — the entire routing decision, both candidate prices included, is on-chain and
auditable.
The two separate claims
Routing changes who underwrites and what the LP pays — it does not change which guarantees apply. The LP-facing guarantee is enforced identically at settlement for both rails: And the capital-at-risk disclosure applies to whoever the router put on the other side — the pool’s depositors on Path A, the market maker on Path B:Where to go next
The two rails
The floor/ceiling framing and the one-settlement-core architecture in full.
Path A — the cvAMM
The always-on pool: pricing, dual-tranche collateral, run defense.
Path B — the MM rail
Firm EIP-712 quotes, no last-look, and the three on-chain protections.
The pricing stack
How FairPremium, the load stack, and the I10 cap compose into a premium.
Capacity authority (I7)
Why only the executed rail mutates nonce/capacity/lock.
The full lifecycle
Create → active → settle, identical regardless of which rail filled.