MaxIL = max(IL(Pa), IL(Pb)): the convexity proof that interior IL never exceeds the boundary, the upper-boundary asymmetry, and why the cap is load-bearing for no-bad-debt — with the verified [80,100,125] fixture.
MaxIL is the single quantity that does double duty in Inflexion: it is both the load-bearing payout cap that makes no bad debt possible, and the unit of risk that makes positions fungible to an underwriter. This page proves where it comes from. The headline definition is one line:MaxIL=max(IL(Pa),IL(Pb))The maximum in-range impermanent loss is attained at a range boundary, never in the interior. That fact is not an approximation or a calibration — it follows from a short convexity argument, and it is what lets the protocol lock exactly MaxIL of collateral at creation and guarantee the LP is always made whole, capped, from it.
This page is the rigorous companion to the IL formula (where Vhold and Vlp come from) and to FairValue (which prices the capped claim min(IL,MaxIL)). Read those for the surrounding stack; this page is about the geometry of the cap itself.
Let P be the price of token0 in token1 (e.g. ETH in USDC). A position is liquidity L over a tick range [Pa,Pb], opened at P0 with the in-range requirementPa≤P0≤Pb enforced at creation; on-chain the gate a >= 1e18 || b <= 1e18 reverts OutOfRange. Out-of-range entries are rejected — there is nothing to hedge if the position is already one-sided.Impermanent loss is the gap between holding the entry basket and being the LP:IL(P)=max(0,Vhold(P)−Vlp(P))with the two value functions taken directly from the settle-path math:Vhold(P)=a0P+a1(affine in P)Vlp(P)=⎩⎨⎧L(Pa1−Pb1)PL(2P−PbP−Pa)L(Pb−Pa)P<Pa(linear, all token0)Pa≤P≤Pb(strictly concave)P>Pb(constant, all token1)where a0=amount0_entry=L(1/P0−1/Pb) and a1=amount1_entry=L(P0−Pa) are the entry token amounts snapshotted at creation. The three regimes of Vlp are the whole story: inside the range the LP holds a price-dependent mix of both tokens, belowPa it has rotated fully into token0, abovePb it has rotated fully into token1.
The single most important shape fact: Vlp is strictly concave inside the range and flat above Pb. The concavity is why interior IL is bounded by the endpoints; the flatness is why IL beyond the range is unbounded. Both follow below.
We want the maximum of IL(P)while the price stays in range, i.e. over the compact interval [Pa,Pb]. The claim is that this maximum is attained at an endpoint. Three lines:
1
V_hold is affine
Vhold(P)=a0P+a1 is a straight line in P. Its second derivative is identically zero:dP2d2Vhold=0.
2
V_lp is strictly concave in range
On [Pa,Pb], Vlp(P)=L(2P−Pa−P/Pb), sodPdVlp=L(P−1/2−Pb1),dP2d2Vlp=−41LP−3/2<0for all P>0. So Vlp is strictly concave — the LP is short gamma.
3
IL = affine − concave = convex
IL(P)=Vhold(P)−Vlp(P)=convexaffine−−(⋅)convexconcave=convex.Concretely dP2d2IL=0−(−41LP−3/2)=+41LP−3/2>0. And max(0,IL) — the pointwise max of two convex functions — is convex too.
4
A convex function on a compact interval maxes at an endpoint
A convex function on [Pa,Pb] attains its maximum at Pa or Pb. ThereforeP∈[Pa,Pb]maxIL(P)=max(IL(Pa),IL(Pb))=MaxIL.■
This holds for any entry P0∈[Pa,Pb] — centered or arbitrarily skewed toward one edge. The proof never used the location of P0; it only used the affine/concave shapes, which hold for every in-range entry.
Why the asymmetric-entry case was double-checked (and confirmed)
Two external auditors flagged the asymmetric case — a position opened far from the center of its range — worried the maximum might wander into the interior. One re-derived the algebra and confirmed the boundary result holds. To be sure, a property test fuzz_asymmetric_entry_maxil samples highly asymmetric P0 near Pa / Pb, 2,000 times, and checks MaxIL == max(IL(Pa), IL(Pb)) every time. The convexity argument above is exactly why the test passes: convexity of IL does not depend on where the entry sits.
The boundaries are not symmetric, even for a ratio-symmetric range. The convex IL curve rises more steeply toward the upper boundary, soMaxIL=IL(Pb)>IL(Pa)for a geometric-symmetric range. Intuitively: Vhold grows linearly without bound as price rises (you keep holding token0, which keeps appreciating), while Vlp flattens as the position rotates into token1 — so the gap at Pb exceeds the gap at Pa, where instead the LP is rotating into the appreciating token0 and partially keeps pace. The canonical fixture makes this concrete: a [80,100,125] range (−20% / +25% around 100) is ratio-symmetric, and IL(125)>IL(80).
Limit → Why → Mitigation. Because the upper boundary is the larger one, you cannot approximate MaxIL by the lower-edge IL or by a centered average — that would under-collateralize the worst in-range case and break the cap. Why: the asymmetry is structural (affine Vhold vs. flattening Vlp), not a rounding artifact. Mitigation: the protocol always computes both endpoints and takes the literal max (on-chain ILMath.sol), and the asymmetric-entry fuzz test guards it. MaxIL is never inferred — it is computed from the full geometry.
MaxIL is the maximum in-range IL — it is not the global worst case. Above Pb the LP is fully in token1, so Vlp is constant while Vhold keeps growing linearly with price. Absolute IL is therefore unbounded beyond the range:P→∞limIL(P)=P→∞lim(a0P+a1−L(Pb−Pa))=+∞.The protocol does not insure that tail. It covers the capped payoff:covered_payoff=min(realized_IL,MaxIL)via compute_payout. And because FULL collateral is set to exactly the cap,collateralFULL=MaxIL,covered_payoff≤MaxILby construction∴payout≤collateral=MaxILso FULL mode cannot produce bad debt under any price path — this is invariantsI1 (no bad debt) and I2 (cap correctness). The guarantee is structural and oracle-independent: it holds for any price path and any (even wrong) σ.
LPs are always paid with no bad debt in FULL mode — qualified: capped payoff + solvent USDC + oracle/settlement liveness.The no-bad-debt guarantee is exact only under the full clause:
FULL collateralization — the underwriter has posted exactly MaxIL per swap, locked for the life of the position.
Capped payoff — the payout is min(realized_IL, MaxIL). The cap is load-bearing: it is what makes payout ≤ collateral hold by construction.
Solvent USDC — the collateral numeraire (dUSDC) holds its peg and remains redeemable.
Oracle / settlement liveness — the price oracle stays live and settle() runs within the protocol’s settlement window.
No rehypothecation breach — locked collateral stays instantly liquid; it is never routed to utilization-gated venues.
Stated without these qualifiers, the guarantee is not correct.
The product framing is the honest version of the cap. At the range boundary the LP has fully rotated into one asset. IL beyond that point is directional loss — foregone spot upside — not the impermanent loss the LP set out to hedge. Capping at MaxIL keeps the product fully collateralized and trustless, and is exactly why Inflexion is an in-range convexity hedge, not “IL insurance.” Mislabeling it “IL insurance” is both a demand risk (sophisticated LPs would discount the truncated tail) and a reputational/regulatory one — so every LP surface shows the payoff diagram and the cap, and the cap never surprises an LP. See what this is not.
The cap is the opposite of a weakness. An uncapped IL claim would be an unbounded short-volatility liability with no finite collateral that makes it safe. The cap is precisely what turns an unhedgeable tail into a bounded, fully-collateralizable, fungible unit of risk — see MaxIL as the unit of risk and tranches.
These are pure geometry — no volatility, no time enters MaxIL at all. For a geometric-symmetric range [P0/(1+w),P0(1+w)], computed by compute_max_il / cvamm.maxil_over_v0 (maxil_over_v0_geometric):
range width
MaxIL / V0 (geometric centering)
±5%
1.27%
±10%
2.56%
±20%
5.23%
±50%
13.76% (arithmetic centering ±50% → ~18.0%)
Tighter ranges produce smaller MaxIL: the position has less room to drift before rotating fully into one asset, so the worst in-range gap is smaller. Wider ranges produce larger MaxIL — more interior price travel, a bigger boundary gap.
Doc-correction flag. The table above is the corrected set from compute_max_il. Older documentation carried an older, ~4.2× too-low set (±5% → 0.3%, ±10% → 1.2%, ±20% → 4.8%, ±50% → 25%). Why: that was a documentation bug — the contract ILMath.sol always computed the correct (higher) values, so this was never a code change. Mitigation: use the “Reference magnitudes” table here. The earlier fixture table for [80,100,125] (MaxIL ≈ 6.6% of V0) is correct and verified — only the centered-range ballpark there is stale.
This is the canonical asymmetric-but-ratio-symmetric fixture, with every number verified by amounts_fixture_matches_python / maxil_fixture_matches_python and mirrored in ILMath.t.sol. Range [Pa,Pb]=[80,125], entry P0=100, L=1018.
The asymmetry is real.IL(125)=0.1393>IL(80)=0.1115. The upper boundary is ~25% larger than the lower, on a ratio-symmetric range. MaxIL = IL(Pb) exactly as the proof predicts.
MaxIL / V0 ≈ 6.6%. With Vhold(P0)≈2.1115 and MaxIL≈0.1393, the cap is about 6.6% of the position’s entry value — consistent with the ±20%-ish width of this range.
Integer vs. float reproducibility. On-chain everything is integer math in Uniswap Q64.96 with floor rounding everywhere (see the IL formula). The on-node integer-floor MaxIL is 139_320_225_002_103_011, which sits 1,691 wei from the Python float anchor 139_320_225_002_101_320 — well inside the 10,000-wei float-vs-integer tolerance. The Stylus and Solidity implementations agree to the wei by construction because they share the same mulDiv chain.
MaxIL being frozen at creation, identical across all three durations (7/30/90d) for a given position, and L-independent in the fair-rate sense is exactly what makes positions fungible to an underwriter. An MM quote is therefore per-market — a load, an optional MaxIL-ratio band, and capacity — never per-NFT (the SignedQuote carries no tokenId). See the two rails and quote signing.
Important nuance — MaxIL is a normalization unit, not a risk metric. Two positions with identical MaxIL can carry very different risk (distance from current price, delta). Why: MaxIL is pure geometry; it knows nothing about how close the price currently sits to an edge or how volatile the pair is. Mitigation: both the pool and MMs price EQ[min(IL,MaxIL)]/MaxIL — the fairRate — for the specific public geometry (positions(tokenId)). MaxIL/V0 is a fine monotone proxy for width when displaying or filtering, but is never the pricing input. This is what dissolves the old adverse-selection story: the pricing input is fully public.
MaxIL is the geometry layer — the “how much capital.” It multiplies cleanly with the stochastics and the inventory state:premium=stochastics: how riskyfairRate⋅geometry: how much capitalMaxIL⋅inventory: how scarce(1+load)
Layer
Formula
Depends on
Where it lives
IL
max(0,Vhold−Vlp)
Pa,Pb,L,P0,PT
ILMath.sol / il.py
MaxIL
max(IL(Pa),IL(Pb))
geometry only (Pa,Pb,L,P0)
ILMath.sol / il.compute_max_il
fairRate
EQ[min(IL,MaxIL)]/MaxIL
a,b,σref,T
Stylus FairValueOracle
The IL formula
Where Vhold and Vlp come from, the three regimes, and the Q64.96 fixed-point implementation.
FairValue — the Φ-sum
Pricing the capped claim min(IL,MaxIL) as an exact closed-form lognormal moment sum.
No-bad-debt math
The three-line proof that payout ≤ collateral = MaxIL, with its full qualifying clause.
Worked example
One position, three durations, three prices — MaxIL constant, only fairRate moving.