The structural core: payout ≤ collateral == MaxIL
Everything rests on a single arithmetic fact. At creation, the underwriter locks
exactly MaxIL of collateral. At settlement, the protocol pays the LP
Because collateral == MaxIL in FULL mode and the payout is capped at MaxIL,
for any price path — in-range, below Pa, above Pb, and the no-IL region.
This is invariant I1, and it is a construction, not a
hope: there is no sequence of prices, no settlement timing, and no σ value that can
make a capped payout exceed the collateral that equals the cap.
MaxIL is the maximum in-range impermanent loss of the specific
position — pure geometry, frozen at creation. It is convex on
[Pa, Pb], so its
maximum while price stays in range is attained at a boundary,
MaxIL = max(IL(Pa), IL(Pb)). That is exactly why the
cap is the right collateral amount: it is the worst case the product covers. See
the MaxIL derivation and the no-bad-debt math
for the full proof.
realized_IL is recomputed on-chain at settle, never caller-supplied. The
settlement price sqrtPTX96 is derived on-chain from the Chainlink round pinned at
expiry T via _oracleSqrtPriceX96, then fed to
computeIL together with the stored liquidity L (invariant
I6). A permissionless settler cannot set the payout anywhere
in [0, MaxIL] — the inputs are not theirs to choose. This is what makes I1, I2, and
I4 hold against an adversarial settler.The full clause — and why every word is load-bearing
The guarantee is exact only under four conditions. Each one, if removed, breaks a different link in the chainpayout ≤ collateral. A caveat is only honest when it
comes with its why and its mitigation, so here is each clause with both.
(a) Capped payoff — payout = min(realized_IL, MaxIL)
(a) Capped payoff — payout = min(realized_IL, MaxIL)
Why it is load-bearing. Remove the cap and beyond-range IL is unbounded.
Above
Pb the LP is fully rotated into one asset at constant value while a hold
position keeps growing linearly with price, so absolute IL has no ceiling.
No fixed amount of collateral can back an unbounded liability —
the product could not be fully collateralized, so it could not be trustless.Why the cap is the right product, not a defect. At the range boundary the LP
has already fully rotated; loss beyond that point is directional (foregone spot
upside), not the impermanent loss the LP set out to hedge. Capping at MaxIL is
what keeps the hedge fully collateralized and trustless. This is an
in-range convexity hedge, not unbounded
“IL insurance,” and the cap is the line between the two.Mitigation / path-forward. LPs who want protection beyond the range simply
re-cover after re-ranging — a new in-range position, a new MaxIL, fresh collateral.(b) Solvent collateral asset (USDC)
(b) Solvent collateral asset (USDC)
Why it is load-bearing. Collateral, premium, and payout are all denominated in
USDC (
dUSDC, 6 decimals, the numéraire). The
non-oracle token in every pair is assumed to be a USD-stable numéraire.
If that asset loses its peg or its redeemability,
payout ≤ collateral can still hold in token units while failing in real value.Why this is a disclosed shared risk, not a protocol bug. A USDC depeg is a
systemic event that hits every party denominated in USDC equally — it is not
something the protocol’s settlement logic can or should try to absorb. We disclose
it rather than pretend it away.Mitigation / path-forward. Use a collateral asset with a credible peg and
instant redeemability; the design is asset-agnostic at the numéraire layer, so a
different solvent stable can be configured per market.(c) Oracle / settlement liveness
(c) Oracle / settlement liveness
Why it is load-bearing.
settle() pins the price to the Chainlink round at
expiry T. If the oracle never produces a usable round, funds cannot settle —
not because the math fails, but because settlement cannot run. Note the subtlety:
the amount I1 caps is oracle-independent; the act of settling needs the
oracle live. A wrong σ cannot violate I1, but a permanently dead oracle could
strand funds.Why it does not become a permanent lockup. This was an audited risk
(Fork 1). The fix is invariant I8: the
price stays pinned to the round-at-T for fairness, a glitched “lone spike” (a print
differing from both neighbours by ≥ LONE_SPIKE_BPS = 500 / 5%) is deferred,
and a LIVENESS_WINDOW = 86,400s (24h) backstop unconditionally accepts the
round after the window. A missing neighbour round across a Chainlink phaseId
boundary is read tolerantly via _tryRound (try/catch, not revert), so it degrades
to the backstop rather than locking. Implemented in
OracleManager.getSettlementPrice.(d) No rehypothecation breach
(d) No rehypothecation breach
Why it is load-bearing.
payout ≤ collateral is only meaningful if the
collateral is actually there when settle runs. Route locked collateral to a
utilization-gated venue (Aave / Compound) and a withdrawal could revert in a
crash — exactly when payouts are due — turning a solvent-on-paper position into a
failed settlement.Why this is a hard rule, not a preference. Locked collateral must stay
instantly liquid. This is a hard rule and audit fix #3:
only idle capital may earn yield, and only to
instantly-redeemable wrappers (sDAI / tokenized T-bills) — never to anything
whose redemption depends on pool utilization.Mitigation / path-forward. The yield adapter interface requires
isInstantlyRedeemable(); locked collateral is never routed to a gated venue by
construction. Idle-only, instant-only.Stated without these qualifiers, the guarantee is not correct. “Bad debt impossible” — full stop — is incorrect. The exact claim is always: no bad debt in FULL mode under capped payoff + solvent USDC + oracle/settlement liveness + no rehypothecation breach.
I1 is structurally oracle-independent
This is the most important nuance on the page, and the one that makes the guarantee robust. The no-bad-debt invariant (I1) does not depend on any pricing oracle being right. In FULL mode,collateral == MaxIL and payout = min(realized_IL, MaxIL) ≤ MaxIL
regardless of what σ was, regardless of what the FairValueOracle
priced, regardless of what the VolOracle estimated. A wrong σ_ref cannot violate
I1, because I1 is about the cap and the collateral, both of which are fixed pure
geometry — they were never functions of σ.
What the pricing oracles are load-bearing for:
The Slither cvAMM review confirmed this independence directly: manual review
verified that the FULL no-bad-debt guarantee (I1) is structural and independent of
the FairValue / Vol oracles —
settle caps payout at MaxIL == collateral
regardless of any pricing input.
Two separate guarantees — never merged
Claim A (LP no-bad-debt) and Claim B (depositor/MM capital) are two different promises to two different parties. Both are true; neither implies the other; merging them is a category error.Claim A — LPs are always paid
No bad debt in FULL, code-enforced (I1). Structural and oracle-independent:
settle caps payout at MaxIL == collateral regardless of any pricing oracle.
Qualified by the full clause above.Claim B — capital is NOT guaranteed
The underwriter is a volatility seller. Junior is first-loss; senior is
structurally protected from underwriting loss only, never from the systemic
tail. Applies to both the cvAMM pool and any MM.
- A bad price path moves money from the underwriter to the LP — the LP is paid
min(IL, MaxIL)out of locked collateral. Claim A holds (LP paid); Claim B is realized (the underwriter took the loss it was paid a premium to take). Nothing is broken; this is the product working. - A wrong σ / mispricing can make underwriting systematically unprofitable over time — premiums too low for the risk. Claim B bites (depositors can lose principal); Claim A is untouched (every individual LP is still paid up to MaxIL from collateral that equals MaxIL).
- A USDC depeg or dead oracle is a shared systemic failure outside both the capped-payoff and the FULL-collateral mechanisms — it sits in the qualifying clause of Claim A, and it is part of the “systemic tail” that even the senior tranche bears in Claim B.
Inflexion is not Bancor. The cvAMM pays claims in pre-locked USDC and mints nothing — no token-inflation reinsurance, no death spiral. In FULL the pool cannot become insolvent against its LPs (collateral = MaxIL ≥ payout) and cannot be run (withdrawal cooldown + locked/free accounting). See what this is not.
Senior protection is a calibration result, not a third guarantee
It is tempting to read the senior tranche as “safe.” It is not — and conflating structural senior protection with a guarantee would be a third claim we do not make. The pool enforcestotalLocked ≤ juniorAssets at every lockCollateral
(the SeniorProtectionBreached revert). Since every
payout ≤ its MaxIL = its locked amount, total payouts ≤ totalLocked ≤ juniorAssets, so the junior-first-loss waterfall absorbs all underwriting loss
before senior is ever touched (in releaseAndDistribute).
How the guarantee is verified, not just asserted
I1 is not a comment in the code — it is fuzzed over the whole price domain.
The supporting invariants close the vectors that could otherwise break the core
inequality from the side: I3 (no underflow when
V_lp > V_hold), I4 (the LP never profits from the swap — payout is
0 whenever IL is 0), I5 (locked ≤ deposited, so the
collateral is genuinely there), and I6 (settle uses the L
stored at creation, so an external increaseLiquidity on the custodied NFT cannot
inflate the payout above MaxIL).
The guarantee, proven live
The 2026-06-05 redeploy ran real create→settle lifecycles on both rails, and in both cases the payout came from the counterparty’s own collateral, never protocol funds:- Path A (cvAMM): swap #1 — premium $9.70 on MaxIL $1,669.24 (0.58% of MaxIL),
realized IL $148.64, payout $148.64, paid from the
ConvexityVault. - Path B (routed → MM): swap #2 —
createSwapRoutedpicked the MM ($8.93 vs the cvAMM’s $13.80); MaxIL $3,215.65 was locked from the MM’s ownUnderwriterVault, realized IL $245.66, payout $245.66 settled from that collateral.
payout ≤ collateral == MaxIL held, and the LP was paid from collateral
locked at creation — the guarantee, end to end. See the two rails
and the full lifecycle.
Where to go next
The invariants (I1–I10)
Every invariant precisely stated, with why it holds and where it is enforced.
The no-bad-debt math
The formal
payout ≤ collateral argument and the convexity of MaxIL.Tranches & capital risk
Junior first-loss, senior protection, and why capital is not guaranteed.
MaxIL — cap and unit
Why the cap is load-bearing and how it doubles as the unit of risk.