Inventory management

AIMM books every asset separately: each leg carries its own reserves, its own LP liabilities and its own risk parameters, with no pool-wide invariant tying them together. The ratio of the two, coverage, is the single state variable the rest of the pricing stack reads. This page derives it and the three mechanisms it drives, each stated exactly as the contracts compute it.


0. Units and notation

Every quantity below is an on-chain integer. Fixed-point bases (Constants.sol):

SymbolBaseValueUsed for
WAD1e181018coverage, haircut ratio, prices
BPS1e41040.01% units: kappa, spline x-domain
PBPS1e61060.0001% units: dispersion, spread

All division is Solidity integer division, truncating toward zero. Truncation is called out where it changes an economic outcome. Symbol collision: κ denotes dispersion in Liquidity Shaping and Spread & Fees; this document writes the convex coverage-wall strength as κcov (kappaCovBps) to keep the two apart.

Live figures come from a shipped stable pool (addresses: 2. Deployments) and from the shipped reference-roster parameters (per-parameter tables in Parametrization). Reserves move: treat reserve-derived numbers as a dated snapshot. The parameters are stable.


1. Overview

AIMM uses Asset-Liability Management (ALM) in the lineage of Wombat and Platypus:

  • Reserves R (Asset.reserves, uint128, token units): tokens the pool holds.
  • Liabilities L (Asset.liabilities, uint128, token units): LP claims on that asset.
  • Coverage c=R/L.

There is no pool-wide invariant. Each asset carries its own (R,L) and its own risk parameters, and the price is anchored to an external oracle mark rather than to a reserve ratio. Coverage enters pricing at exactly three points:

MechanismFunctionEffect
Inventory skew ψPricing.computeInventorySkewShifts the quote center along the spline
Coverage toll tPricing._covTollConvex charge on draining an under-covered leg
Withdrawal haircut hPoolLiquidity.applyHaircutPrices an LP exit out of a deficit

It does not enter the depth axis: the denominator converting trade size into spline domain is the leg’s raw reserves (§4). Coverage moves the quote center and charges the drain; it never manufactures depth the leg does not hold.

1.1. Beyond pool-wise invariants

Traditional AMMs enforce a pool-wise invariant: x·y=k; Curve StableSwap’s Annixi+D=ADnn+Dn+1/(nnixi); Balancer’s ixiwi=k; Orbital/CCMM’s spherical i(r-xi)2=r2. Each of those is simultaneously the pricing rule and the solvency rule, so N-asset generalization requires new geometry. AIMM separates them:

  • Pricing comes from the oracle mark, the inventory skew, and a chosen density profile.
  • Solvency is per-asset (R,L) bookkeeping.

Adding an asset therefore adds a row, not a dimension to an invariant.


2. Coverage ratio

2.1. Definition

c=R·WADL

Pricing.calculateCoverage returns exactly this, in WAD, so c=1018 is 100% coverage. Two edge behaviors:

  • L=0 returns type(uint256).max, not a revert. Every consumer treats that as “infinitely covered”.
  • The division truncates, so the stored c is a floor. A leg is never reported as better covered than it is.

R is the economic reserve, the full dual-ledger book R=Rliq+Rinv when a yield hook is invested. Pricing and coverage always use full R; executable cash for swap/flash/push is Rliq only, checked separately at settlement (PoolIOLib.settle, PoolIOLib.sol). See Pool Hooks.

2.2. Key thresholds

The saturation points are protocol constants, not configuration: the skew law hard-codes c=1/2 and c=2 (§3), identically on every leg of every pool.

CoverageStateSkewBehavior
c2Overcollateralized-100Max discount, pool wants to sell the asset
c=1Equilibrium0Quote centered on the mark
c1/2Undercollateralized+100Max premium, pool wants to buy the asset

Both are constants, so no write can move the slope or reprice an open book by shifting where the arms saturate. Why those two points are the only admissible ones: §3.2.1.


3. Inventory skew (coverage → skew)

ψ maps to a position on the spline in Liquidity Shaping §5.

3.1. Exact formula

Pricing.computeInventorySkew, in order:

ψ=-100L=0+100c1/2-100c2+200(1-c)1/2<c<1(drainingarm)-100(c-1)1c<2(fillingarm)

with c=R·WAD/L from §2.1. Four properties of that law:

  • No inputs beyond coverage: no per-asset parameter, no oracle read.
  • Return type is int8, so ψ[-100,+100] by both clamp and type.
  • The magnitude truncates toward zero: a computed 14.62 becomes 14, never 15.
  • Positive ψ means undercovered, and the pool quotes the asset at a premium so it is bought back.

The empty-liability sentinel is not a rounding case. L=0 returns -100, the maximum discount, not 0: a leg with reserves and no LP claims is pure surplus and the pool should give it away.

What makes the skew earn rather than merely protect is the roster, not the formula. The law only prices imbalance: a premium on the side that drains, a discount on the side that refills. If the discount is never taken, the leg sits at its clamp holding whatever the market wanted to sell. Inside a core of correlated legs the two sides usually meet, because the flow that refills one leg is flow that drains another: a single trade pays skew on the leg it takes while restoring coverage on the leg it delivers, so inventory mean-reverts instead of accumulating. Correlation makes that likely, not certain: legs that move together can leave the whole core displaced the same way at once. Why cores are cut by asset class: Pool Composition.

3.2. The two arms are not symmetric

The draining arm has slope 200, the filling arm slope 100. That is a conservation bound, not an oversight: the two must not be tidied into one 200(1-c).

Both slopes come from the same requirement: a closed round trip must not refund more impact than the outbound leg charged. The skew step and the volume traverse advance the same spline x-coordinate, so the skew slope is pinned against the traverse’s step. On the draining side the traverse already out-steps and 200 is admissible. On the filling side it under-steps, and a 200 slope there would put the return leg of a ping-pong ahead of the outbound one by exactly the gap, which a trader extracts from LPs. Pinned by ImpactConservation.t.sol, not by a comment.

CoverageψNote
50%+100saturated
75%+50draining arm
90%+20draining arm
100%0centered on the mark
120%-20filling arm
150%-50filling arm
200%-100saturated

The arms meet their clamps exactly, so the whole [0.5,2.0] range carries information and neither arm has a dead zone.

3.2.1. Why saturation sits at 1/2 and 2

Write the saturation points as [1/k,k]. Two independent studies asked whether k should be a per-asset dial; both closed the question the same way.

k cannot reach the draining arm at all. The round-trip conservation bound of §3.2 pins the draining slope at 200 for every k. All k could ever do is soften the filling arm, whose slope would be 100/(k-1).

k=2 is the unique admissible value, pinned from both sides:

  • Continuity. The draining arm reaches ψ=+100 at c=1/2. Saturating at 1/k>1/2 (that is, k<2) clamps the arm early, at 200(1-1/k)<100, so ψ jumps at the saturation point. Measured leak across such a discontinuity: up to +583 pbps.
  • Conservation. A filling slope 100/(k-1) above 100 lets a ping-pong round trip refund more impact than it charged (§3.2), which requires k2.

k<2 is discontinuous and k>2 only weakens inventory control. k=2 is the single point satisfying both, which is why 200, 100 and the clamps at c1/2 and c2 are constants rather than writable fields.

The empirics agree. k=2 is also the LVR minimum on all three real tapes (ETH, BTC, SOL). More importantly, the coverage floor is fee-determined: a drain stops where the skew’s mid displacement equals the spread, which puts cfloor0.85 on a volatile leg and 0.82 on a stable one independently of shock size. The [0.5,2] clamp region is therefore unreachable in practice. Real-tape dwell below c=0.5: 0.14% to 0.70% of the time for an unwalled volatile leg, and 0.000% of 3.5 years for a walled stable. A per-asset saturation point would be a dial on a region the pool does not visit.

3.3. Measured skew, stable pool

R and L are a dated on-chain snapshot of a pre-Arc reference roster; ψ is recomputed from §3.1 against that snapshot rather than read back from chain, so the rows are worked examples of the two arms, not verification. DAI, RLUSD and USDG are not listed on the Arc fleet - its stable core is USDC, USDT, USDS, USD1 and PYUSD (deployments/arc-risk-params.json). Other pages quote coverages captured at other times. The toll example in Spread & Fees §6.3 reads RLUSD at c=0.9575, from an earlier snapshot than this table. Reserves move; only the parameters are stable.

AssetRLcArmψ
USDC (base)66,369.8450,154.231.32332filling-32
USDT60,035.6550,130.651.19758filling-19
DAI52,714.5750,104.151.05210filling-5
RLUSD48,212.3150,041.020.96346draining+7
USDG47,805.8950,081.420.95456draining+9

The book is asymmetric in normal operation. No leg sits at ψ=0, so the tradeable spline domain is split unevenly about the center before any other mechanism acts (see Liquidity Shaping §5). Each filling-arm row displaces half as far as the same distance from par displaces on the draining arm: the conservation bound of §3.2 doing its work.

3.4. Relation to Avellaneda-Stoikov

Avellaneda-Stoikov displace the quote by δAS=γqσ2, linear in inventory q and scaled by their risk-aversion coefficient γ and variance σ2. AIMM keeps the linearity, replaces q with the coverage ratio c (the Platypus/Wombat imbalance metric), and moves both the risk-aversion multiplier and σ out of the skew entirely. What remains is an inventory-driven mid shift, first instantiated on-chain by DODO PMM’s oracle-anchored proactive maker, driven by a coverage metric rather than by a slippage-on-invariant.

Risk aversion is not a dial on the skew: the round-trip conservation bound of §3.2 determines both slopes uniquely. AIMM expresses it instead through vegaBps, which widens the quoting band against σ, and through minFeePbps, which floors the spread.

σ enters two other places: the dispersion that scales the density curve (Liquidity Shaping §6) and the volatility term of the spread (Spread & Fees). The separation lets the level shift and the width be tuned independently, and keeps computeInventorySkew free of any oracle read.

See Foundations §2.4 for the AS reference.


4. The depth denominator

Canonical. Liquidity Shaping §7, Spread & Fees §6.5 and Slippage & Price Impact §2.1 restate the result only.

4.1. What it is

The denominator converting a trade size into a fraction of the spline domain is the leg’s raw reserves, with a zero-guard and nothing else:

uint256 depth = reserves == 0 ? 1 : uint256(reserves); // Pricing.quoteSwap, Pricing._priceEdgeHop volumeFraction = amountIn * BPS / depth;

It is expressed in the profile asset’s own token units, so the x-axis is anchor-free: it depends neither on which asset the leg is anchored to nor on any price. The guard exists because _traverseCurve divides by it; 1 wei is not a liquidity claim, it is a division floor.

4.2. Properties

PointValue
R=0D=1 wei (division guard)
R>0, any coverageD=R

Monotone in reserves, independent of L, independent of c, and constant per swap. The real depth lever is the reserve balance itself.

Coverage does not reach this axis: an under-covered leg gets no virtual depth. Subsidizing the denominator on a leg an informed flow is draining would shrink the traversed spline interval and so reduce the impact charged on the drain, paying a trader to cycle exactly the leg that needs reserves. Coverage is priced by the two mechanisms that charge instead: the skew shifts the mid against the deficit (§3) and the convex wall tolls the drain (§6).


5. Withdrawal haircut

The haircut stops an LP exiting an under-covered leg at face value and leaving the deficit to whoever stays.

5.1. Flow

R >= L or L == 0

R < L

User requests withdrawal

Read R, L

haircut = 0, pay face

deficit = R minus L over L

factor from suppressor

haircut = ceil of amount times ratio

Update reserves

Burn LP for FULL face

User receives amount minus haircut

5.2. Exact formula

PoolLiquidity.applyHaircut:

d=(L-R)·WADLϕ=WAD-η·WADηmaxρ=min(WAD,dϕWAD)

h=xρWADy=x-h

with d the coverage deficit, ϕ the suppressor factor, ρ the haircut ratio, h the haircut and y the payout; x is the face amount, η = Asset.haircutSuppressorBps (uint16) and ηmax=20000 is PoolConstantsLib.HAIRCUT_SUPPRESSOR_FULL_BPS.

The haircut is linear in the coverage deficit: no power-law exponent, no separate severity curve.

Four implementation facts:

  • Early exit at RL or L=0 returns (x,0): full face, no haircut, no reads.
  • There is no ηηmaxϕ=0 branch. setAssetParams rejects that range outright and initAsset seeds BPS, so no writer can reach it. Out-of-range stored state underflows here rather than silently zeroing the haircut: fail closed, not open.
  • The haircut rounds up (ceil-div) so the payout rounds down. Without it a withdrawer could over-draw an under-covered reserve by up to 1 wei per call.
  • Liabilities burn at full face x, not at y. The retained x-y is exactly the exiting LP’s pro-rata share of the deficit at η=0, so a same-asset exit leaves c where it found it rather than raising it; §5.5 does that arithmetic.

5.3. Suppressor

ηfactorEffect
01.00Full linear haircut
100000.50Half haircut
150000.25Quarter haircut
20000-No haircut is possible: the writer reverts - setAssetParams rejects this range outright (PoolConfig), so no zeroing branch exists

Worked, at c=0.8: d=0.2. With η=0, h=20%. With η=10000, h=10%. A 1000-unit exit therefore returns 800 or 900 units respectively, and burns LP for 1000 in both cases.

Only the η=0 row is reachable on a listed asset. Two predicates compose to pin it: PoolConfig.requireNeverDepletable rejects κcov=0 at every writer, and PoolConfig.requireWallOk rejects κcov0 paired with η0 at the same writers. initAsset seeds η=10000 and setupOracleAndConfig zeroes it the moment a walled asset is listed. Every leg of the Arc fleet carries η=0 (deployments/arc-risk-params.json); η>0 is a dead field, and the non-zero rows above are the arithmetic of a value the write path will not admit.

5.4. Cross-asset exit

PoolLiquidity._quoteWithdrawCross applies the haircut twice; the order is a security property:

  1. Haircut on the source asset first, before the mark conversion. Skipping this would let an LP in an under-covered leg exit at full face out of a healthy leg, dumping the deficit on that leg’s LPs.
  2. Route the haircut face through Pricing.anchorPathQuoteLp (the normal swap path, including spread and coverage toll).
  3. Mark cap: the payout is capped at the haircut face converted through the path’s oracle mark, min(amountOut, fair · markPrice · 10^(d_to - d_from)) (PoolLiquidity._markCap). The inventory skew is a level, and it is one-sided on an under-covered child (draining slope 200 against filling 100), so a one-way LP conversion would monetize it out of the healthy destination leg. Trader swaps are immune - the level cancels on paired crossings - so only this path needs the cap. The decimal factor is carried explicitly because markPrice is a whole-unit WAD ratio while the amount walk is rescaled per leg; without it the cap misses by 10dto-dfrom on a mixed-decimal pool, binding to dust one way and never binding the other.
  4. Haircut again on the destination asset, because that leg’s own coverage now applies.

Both depeg breakers run after the quote, which is state-identical to running them before in an all-or-nothing transaction, and lets them hit the primed transient feed cache.

5.5. How coverage restores

Restoration is priced, never scheduled. The haircut acts on the event that matters, an LP leaving an under-covered leg; what it does to coverage depends on which exit is taken.

A same-asset withdrawal at η=0 leaves c exactly unchanged. With ϕ=WAD the haircut ratio is the deficit itself, ρ=d=(L-R)/L, so the payout is the withdrawer’s own pro-rata share of the reserve, y=x(1-d)=xR/L. Settlement burns ΔR=-y and ΔL=-x (PoolLiquidity._applyWithdraw, same-asset branch), giving

c=R-xR/LL-x=R(L-x)L(L-x)=RL=c

The exiting LP takes its share of the deficit with it and leaves the ratio where it found it. Only the ceil-div dust the haircut keeps with the pool moves c, by at most 1 wei of reserve per call. Pinned by test_withdraw_coverage_neutral_when_suppressor_zero. A suppressed haircut (η>0) would make this exit coverage-raising, at the LP’s expense; η=0 is the only value a listed asset can hold (§5.3), so the coverage-neutral case is the only one on the fleet.

Two exits do raise the source leg’s c, and both are cross-asset: withdrawTo into a different token (§5.4) and swapLiability. Each burns the full face x from the source leg’s liabilities and leaves the source leg’s reserves untouched - the payout is debited from the destination leg instead (PoolLiquidity._applyWithdraw cross branch; PoolLiquidity.swapLiability). The source leg therefore moves to c=R/(L-x)>c. The source-side haircut on those paths is not what restores coverage: it exists so the exiting LP converts only xR/L of face and cannot dump its deficit on the destination leg’s LPs.

The convex wall (§6) is the other priced restorer, tolling any swap that drains a walled leg further: the toll is withheld from the gross output with no matching liability credit, so it raises R against unchanged L. Deposits move c toward 1 from below (§8.1). Neither the haircut nor the wall reduces liabilities on its own, and no background process rewrites coverage.

The one path that can lower liquidityIndexWad is Pool.hookWriteDown, which realizes an actual loss on invested reserves.


6. Convex coverage wall

Canonical derivation. Spread & Fees §6 owns the settlement order and the charge semantics; this section owns the potential and the clamps.

Pricing._covToll is the second coverage mechanism. Unlike the skew it is a charge, not a level shift. It mirrors the reference simulator’s cov_q.

6.1. Potential and toll

Q(c)=lnc-c+1(0,max0atc=1,concave,-asc0)

c0=min(1,R·WADL),c1=min(1,(R-g)·WADL),t=min(g,(Q(c0)-Q(c1))·κcov·LBPS·WAD)

where g is the gross output before fees, in output-token units, and κcov = RiskConfig.kappaCovBps. Charged only when Q(c0)-Q(c1)>0; the toll is withheld from the gross output and retained in the output reserve, so it accrues to LPs and is never a mark shift.

6.2. Why the clamps are there

  • min(c,1) on both endpoints. Q is non-monotonic: it decreases on both sides of c=1. A raw endpoint difference lets a drain that starts over-covered cross the peg and land below it with ΔQ0, paying zero toll. Clamping restricts Q to its increasing branch so the toll prices exactly the below-peg deficit and the over-peg portion stays free.
  • gR short-circuits to t=g: a fill that fully drains the leg is tolled to zero output. Pricing.swap then reverts rather than settling a zero-delivery swap.
  • Charge-only, no rebate ledger. A coverage-restoring trade drains the healthy leg, where c1 and Q0, so it pays approximately nothing. A round trip therefore strictly loses, which is the LP-safety property.

6.3. Round-trip behavior

Finite differences of Q telescope to zero over any closed reserve loop at constant L. Since LP fees accrue into liabilities mid-loop (§7), the telescoping is only approximate. The residual is pool-favorable: higher L gives lower c gives more toll.

The wall is output-only: a same-pool spoke→spoke swap never outputs the hub, while a cross-pool hop that takes the hub out pays hub κcov.

The protocol rule is that every listed asset, the hub included, carries κcov>0; PoolConfig.requireNeverDepletable rejects a zero at every writer. The Arc fleet carries κcov = 300 on stables, crypto and metals, 400 on FX and 600 on equities, sized so the resting coverage ceq=κ/(κ+e) holds against each class’s on-chain maxDeviationBps as the worst-case single-push mark error e. Per-chain values live in 2. Deployments; they differ by deployment and nothing on this page should be read as a fleet-wide statement. Read the live value with getAsset, never off a params file.


7. Settlement: what actually moves

PoolIOLib.settle is the only place reserves and liabilities change on a swap (there is no separate exec: the split was considered and deliberately not made, since it would only thread need across the boundary as an argument):

aIn.reserves += amountIn aOut.reserves -= amountOut + protoFee protocolFees[tokenOut] += protoFee accrueLpFee(aOut, lpFee) // aOut.liabilities += lpFee, index raised

Two consequences that are commonly stated wrong:

  • Settlement is endpoint-only. Interior hops of a multi-leg path do not move any reserve. Only the two endpoint legs settle. This is what makes per-leg impact charging on interior hops incorrect (see Anchor Path Pricing).
  • Liabilities are NOT unchanged on a swap. PoolLiquidity.accrueLpFee raises aOut.liabilities by the LP fee and raises the liquidity index to match. The LP fee is the output the reserve debit deliberately did not pay out, so Rout and Lout both rise by lpFee relative to a fee-free settlement, and cout moves accordingly.

The executable-liquidity check reads Rliq=R-invested fresh at settlement and reverts InsufficientAmount if it cannot cover amountOut + protoFee + minLiquidity.


8. ALM flows

8.1. Deposit

  1. Pull x, compute lpAmt = x * WAD / mintIndex(asset).
  2. Reject if lpAmt rounds to fewer shares than the dead-share seed requires: a deposit too small to mint a share would otherwise donate reserves to existing LPs for free.
  3. R+=x, L+=x. Coverage unchanged when the index is at parity.

Deposits are single-sided by construction: each asset’s (R,L) is independent, so there is no pairing requirement and no forced ratio.

8.2. Withdrawal

  1. Compute face x from LP shares and the liquidity index.
  2. h per §5, y=x-h.
  3. R-=y, L-=x (full face). At η=0 the gap is the withdrawer’s own share of the deficit and c is unchanged (§5.5). A cross exit debits y from the destination leg instead, so the source leg’s c rises.

8.3. Swap

  1. Skews ψin,ψout per §3, depth denominators per §4.
  2. Spline traversal per Liquidity Shaping §8.
  3. Coverage toll on the output leg per §6, then the spread fee.
  4. Settlement per §7.
  5. cin, cout (net of the LP-fee accrual on the output leg).

Pool State

User Actions

+x, +x

+x, +x

-y

-x face

+in, -out-protoFee

+lpFee on out

Deposit

Withdraw

Swap

Reserves

Liabilities


9. Coverage classification

9.1. Per asset

CoverageState
c> 200%OVER
200% c> 100%ADEQUATE
100% c> 50%UNDER
c 50%CRITICAL

Only deposits, withdrawals and swaps move a leg between these states; nothing runs on a clock (§5.5).

withdrawals

deposits

withdrawals

deposits

coverage drops

deposit, cross exit, or coverage toll

OVER

ADEQUATE

UNDER

CRITICAL

9.2. Pool level

C=jRjpjjLjpj

with pj the mark of asset j in the pool’s unit of account. This is an off-chain reporting aggregate. No on-chain code path consumes C: every gate in the contract is per-asset.


10. Parameter reference

10.1. Per-asset RiskConfig (IPool.sol)

Two fields, and that is the whole struct. It is an ABI and memory type only: both fields are stored in Asset slot 2, not in a mapping of their own, which is why a risk write and an asset write touch the same word.

FieldTypeUnitDeployed (Arc)Purpose
flagsuint16bitfield0x06 (SWAP_ENABLED_BIT | LIABILITY_SWAP_ENABLED_BIT; FLASH_ENABLED_BIT is set on no leg)SWAP_ENABLED_BIT, LIABILITY_SWAP_ENABLED_BIT, FLASH_ENABLED_BIT, the two halt bits
kappaCovBpsuint16bps600 stables, 1,500 FX, 2,000 crypto majors, 1,800 metals, 2,500 equities; each pool’s hub leg at the maximum of its own spokes (κ=0 is rejected by requireNeverDepletable at every writer)Convex coverage wall (§6). Ladder and its derivation: Parametrization §6.2

10.2. Per-asset coverage sensitivity (IPool.Asset)

FieldTypeUnitDeployed (Arc)Purpose
haircutSuppressorBpsuint16basis 200000 on every legWithdrawal haircut gentleness (§5.3); forced to 0 on a κ-walled leg, and every listed leg is walled

The inventory skew carries no per-asset field: it is the fixed law of §3, identical on every leg. Neither does the depth denominator, which is the leg’s own reserves (§4).


11. Traditional AMM vs AIMM ALM

AspectTraditional AMMAIMM ALM
Price sourceReserve ratio via invariantOracle mark, shifted by inventory skew
LP accountingShare of the whole poolPer-asset liability + liquidity index
DepositBoth sides requiredSingle-sided
WithdrawalPro-rata across assetsNamed asset, haircut on deficit
Rebalancing incentiveArbitrage on the invariantSkew (level) plus coverage toll (charge)
UndercollateralizationImplicit as impermanent lossExplicit as c<1, priced by skew, toll and exit haircut

12. Security considerations

12.1. Bank-run resistance

  1. Withdrawal haircuts make an exit from a deficit cost the exiting LP the deficit share (§5), removing the first-mover advantage that drives a run.
  2. Mid skew gives a coverage-restoring trade the favorable side of the same shift a coverage-worsening trade pays (§3), so flow is priced toward equilibrium continuously.
  3. The convex wall (§6) makes the marginal cost of draining an under-covered leg diverge, so the last of the reserve is never cheap.
  4. minLiquidity floors the executable reserve, so a leg cannot be drained to zero even where κcov=0 leaves no wall (§6). It is the last outflow backstop, but it is inert unless a deploy config raises it: initAsset writes 0.

12.2. Manipulation resistance

  1. External-mark pricing. Quotes center on the keeper-pushed mark (FeedMathLib.mark). No quote input is derived from the pool’s own reserves or its own trade history, so a flash-loan-and-swap cannot move the quote center within a block. Only realized inventory skew moves, and skew is a level: it cancels exactly on a round trip.
  2. The skew law takes no configuration. A sign-inverted or over-steep skew is not a rejected write, it is an unrepresentable state: both slopes and both saturation points are constants (§3.2.1).
  3. Skew bounds ±100 hard-cap the inventory-driven price displacement at one wall of the spline.
  4. Flow Guard locks freshly minted LP receipt shares for flowCooldownSecs, against transfer and against burn alike (LPToken._beforeTokenTransfer), so JIT liquidity around a single block is impractical. There is no staking surface. See Flow Guards.

12.3. Circuit breakers

  • HALT_MASK (HALT_RISK_BIT | HALT_GUARDIAN_BIT = 0x0041) halts the asset, checked on every hop of every path.
  • FeedMathLib.gate fails closed on stale, dead, or over-confident feeds.
  • BASE_DEPEG_HALT_BPS = 500 reverts the whole pool if the base mark leaves ±5% of parity.
  • The per-asset depeg band is feed-relative: OracleConfig.refFeedId + refBandBps, armed at settlement by PoolIOLib.priceBandGuardPath, halting the leg when its mark leaves refBandBps of an independent reference feed’s price. A discretionary “stop quoting this leg” call is the guardian halt, not a stored bound.