Skip to main content
@inflexion/sdk exports the deterministic cvAMM load math as a namespaced port, cvamm. It is the single duplication the architecture permits, and it exists because the deployed CvammPricing library is delegatecall-only — a direct eth_call reverts. The port is kept byte-equal to the deployed Solidity by a parity-locked test. The fairRate Φ-sum is NEVER duplicated — it is always read from the on-chain FairValueOracle.
The SDK’s prime directive is one pricing implementation. The expensive, load-bearing part of a premium — the closed-form Φ-sum fair value — lives on-chain in the Stylus FairValueOracle and is only ever read, never re-derived. So why does the SDK carry an off-chain copy of any pricing math at all? Because the cheap, deterministic part — the dealer load stack that marks the fair value up to a charged premium — physically cannot be read on-chain. The contract that computes it is a Solidity library, and deployed libraries refuse direct calls. This page is the full account of that one exception: what it is, why it is forced, and how it is prevented from ever drifting.

The load stack vs the Φ-sum — what gets duplicated and what never does

Every premium in the protocol factors cleanly into two parts: premium  =  FairPremium(a,b,σref,T,MaxIL)⏟Pillar 1 — on-chain, READ only  ×  (1+totalLoad(σref,u,h))⏟the load — deterministic, may be re-evaluated\text{premium} \;=\; \underbrace{\text{FairPremium}(a, b, \sigma_{\text{ref}}, T, \text{MaxIL})}_{\text{Pillar 1 — on-chain, READ only}} \;\times\; \underbrace{\bigl(1 + \text{totalLoad}(\sigma_{\text{ref}}, u, h)\bigr)}_{\text{the load — deterministic, may be re-evaluated}} The two factors have opposite duplication policies, and the distinction is the whole point of this page.

FairPremium — the Φ-sum

A closed-form sum of Φ\Phi terms, computed by the Stylus FairValueOracle (fairPremium / fairRate). It is never reimplemented off-chain — there is exactly one implementation, and it lives on-chain. The SDK reads it via eth_call. See the Φ-sum.

totalLoad — the load stack

A deterministic pure transform of three public scalars (σref\sigma_{\text{ref}}, utilisation uu, concentration hh) plus the public loadParams. It is computed on-chain by CvammPricing — but that library cannot be eth_call’d, so the SDK mirrors it in the cvamm TS port, kept byte-equal by a parity test.
The asymmetry is principled, not arbitrary: the Φ-sum is a genuinely hard computation with a single canonical answer (so one implementation, on-chain), while the load stack is an explicitly deterministic pure transform of public inputs — the kind of thing a client may legitimately re-evaluate, provided it provably agrees with the chain. The access-layer architecture sanctions exactly this and nothing more.

Limit → Why → Mitigation — the one permitted duplication

A naked “we duplicated some pricing math off-chain” would be a defect. It is not — because the duplication is forced by the EVM and bounded by a parity lock. Here is the full chain.
Limit — the SDK carries an off-chain copy of the cvAMM load stack.Why — the deployed CvammPricing library is DELEGATECALL-ONLY. It is deployed (with totalLoadWad / loadComponents), but Solidity guards deployed library functions: a direct eth_call to libs.cvammPricing reverts (confirmed on the 2026-06-05 deploy). The library runs on-chain only via InflexionCore’s delegatecall during pricing — there is no callable surface for a client to read the load from. The SDK therefore cannot read it the way it reads the Φ-sum.Mitigation — the port is PARITY-LOCKED byte-equal to the deployed Solidity. cvamm is asserted equal to the deployed CvammPricing in math.parity.test.ts. It is a permanent mirror — not a temporary stopgap — precisely because the delegatecall-only property is permanent. Any divergence fails CI before it ships. This is the only duplication the architecture permits; the fairRate Φ-sum is never duplicated.
The reason this is safe to duplicate where the Φ-sum is not: the load stack is a deterministic, pure function of public inputs (σ_ref, util, conc, loadParams) — every one of which is readable from a public getter. A client re-evaluating it reaches the same answer the chain would, and the parity test proves it. The Φ-sum, by contrast, has exactly one canonical implementation and is left there. See the access-layer architecture.

Why delegatecall-only forces a port — and where the on-chain copy still runs

On-chain, the load decomposition that backs the live SwapPriced event is computed by CvammPricing.loadComponents(σ_ref, util, conc, loadParams), called from InflexionCore._pricePathAFromFair during a create — purely through delegatecall. There is no path for an external reader to invoke it. The SDK’s job is to reproduce that same pure transform from the same public inputs, so a client preview matches what the create call will charge to within a few wei.
1

On-chain: the contract delegatecalls the library

InflexionCore._pricePathAFromFair delegatecalls CvammPricing.loadComponents(...) and premiumFromLoad(...) to mark the read Φ-sum up to the Path-A pool premium. This is the canonical implementation — the one the create actually uses.
2

The library refuses a direct read

A standalone eth_call to libs.cvammPricing reverts. Deployed Solidity libraries are guarded against being called as ordinary contracts; they only execute in a caller’s storage context via delegatecall. So the SDK has no readContract it can point at the load math.
3

Off-chain: the cvamm port reproduces the same pure transform

cvamm.loadComponents(...) / cvamm.totalLoadWad(...) compute the identical result from the public σ_ref, util, conc, and loadParams. The SDK then applies cvamm.premiumFromLoad(fairPremium, totalLoad) to the read fair value.
4

The parity test pins them together forever

math.parity.test.ts asserts the port agrees with the deployed Solidity byte-for-byte (within a small absolute tolerance on the WAD pow/exp helpers). Drift is a CI failure, so the two can never silently diverge.

What the cvamm namespace contains

The port is exported namespaced as cvamm — not flat — specifically to avoid clobbering type names like WAD, LoadParams, and Regime. Import it from the package root:
All arithmetic is bigint at WAD = 1e18 precision. The helpers mirror solady’s FixedPointMathLib closely enough that totalLoadWad agrees with the on-chain library to within a few wei.

The load stack

The load is a clamped sum of three components, exactly as deployed in CvammPricing.sol: totalLoad  =  min⁡ ⁣( baseLoad(σref)+utilSkew(u)+dispSkew(h),    maxLoadBps⋅1014)\text{totalLoad} \;=\; \min\!\Bigl(\,\text{baseLoad}(\sigma_{\text{ref}}) + \text{utilSkew}(u) + \text{dispSkew}(h),\;\; \text{maxLoadBps}\cdot 10^{14}\Bigr) The outer min is invariant I10 by construction — the load sum is clamped so that premium ≤ FairPremium·(1 + maxLoad) holds for any inputs, on both rails, upstream of settle. It never touches settle / MaxIL / I1–I9.
cvamm.baseLoadWad(σ_ref, params) returns one of three flat values selected by which regime band σref\sigma_{\text{ref}} falls into — it is not a continuous function of σref\sigma_{\text{ref}}:baseLoad={baseLoadCalmBpsσref<regimeCalmBelowWadbaseLoadStressedBpsσref≥regimeStressedAtWadbaseLoadNormalBpsotherwise\text{baseLoad} = \begin{cases} \text{baseLoadCalmBps} & \sigma_{\text{ref}} < \text{regimeCalmBelowWad} \\ \text{baseLoadStressedBps} & \sigma_{\text{ref}} \ge \text{regimeStressedAtWad} \\ \text{baseLoadNormalBps} & \text{otherwise} \end{cases}This is why a Path-A “term structure of load” is a flat line: baseLoad is duration-independent. See the load stack.
cvamm.utilSkewWad(u, params), where u=locked/totalu = \text{locked}/\text{total}:utilSkew(u)={0u≤utilKneemin⁡ ⁣(utilCap,  utilSlope⋅(u−knee1−knee)utilPower)u>utilKnee\text{utilSkew}(u) = \begin{cases} 0 & u \le \text{utilKnee} \\ \min\!\Bigl(\text{utilCap},\; \text{utilSlope}\cdot\bigl(\tfrac{u-\text{knee}}{1-\text{knee}}\bigr)^{\text{utilPower}}\Bigr) & u > \text{utilKnee} \end{cases}The convex term uses the WAD powWad helper.
cvamm.dispSkewWad(h, params), where hh is the normalised coverage HHI (concentration):dispSkew(h)=min⁡ ⁣(dispCap,  dispSlope⋅hdispPower)\text{dispSkew}(h) = \min\!\bigl(\text{dispCap},\; \text{dispSlope}\cdot h^{\text{dispPower}}\bigr)
No load primitive is hardcoded. Every curve parameter (baseLoad*Bps, utilKnee/Slope/Power/Cap, dispSlope/Power/Cap, maxLoadBps, the regime bands) comes from the calibrated risk-parameter set and is mirrored on-chain by InflexionCore.loadParams() — which the SDK reads and passes into the port. Hardcoding any of these is the exact failure the audit flagged. See PARTIAL parameters.

Key functions

regimeOf returns the load regime (calm / normal / stressed — the σ_ref band that selects baseLoad). This is not the σ_ref binding (which-EWMA-window) reported by VolOracle.sigmaComponents. Do not conflate the two.

How the port is used — finishing the premium client-side

The port never prices a premium on its own — it finishes a premium whose fair-value half was read on-chain. Both rails follow the same shape, and this is precisely _pricePathAFromFair / the Path-B markup reproduced off-chain.
This is the engine behind lp.previewPremium, mm.getMarketPricing, mm.getPoolLoadToBeat, and data.getCurrentLoadSurface — every one of them reads the Φ-sum on-chain and finishes the load via the port. The pool’s geometry-independent “load to beat” — the floor an MM must undercut — is the same totalLoadWad evaluated geometry-free.
The load percentage is geometry-independent — totalLoadWad takes only σ_ref, util, conc. Only the dollar premium scales with the position’s a/b/maxIL (through fairPremium). This is why getCurrentLoadSurface can return a meaningful load for a market even with no specific position geometry — it falls back to a neutral reference geometry for the dollar figure while the load % is exact.

resolveMarket / computeMarketId — recovering the market off-chain

The foundation re-exports two more helpers in the same spirit as the load port: deterministic functions that reproduce an exact on-chain derivation a client can’t otherwise read. A SwapRecord carries no marketId — it is kept compact on-chain — so the SDK recovers it by reproducing the contract’s _marketIdForSwap.
Hex
The standalone, pure derivation — the exact keccak256(abi.encodePacked(...)) the contract uses at registration:marketId=keccak256(abi.encodePacked(token0,token1,fee,uint32(durationSeconds)))\text{marketId} = \text{keccak256}\bigl(\text{abi.encodePacked}(\text{token0}, \text{token1}, \text{fee}, \text{uint32}(\text{durationSeconds}))\bigr)
Promise<ResolvedMarket>
The async recovery from a decoded swap record. It reads NPM.positions(swap.tokenId) for (token0, token1, fee), derives durationSeconds = expiry − createdAt, computes the marketId, and reads back InflexionCore.markets(marketId) for the config.
computeMarketId is itself parity-locked against the contract derivation in marketid.parity.test.ts — the same discipline as the load port. Reproducing an on-chain keccak256 off-chain is safe only because it is pinned to the chain by a test, never guessed. Every LP/MM surface row that starts from a swapId uses resolveMarket to recover its market.

The foundation re-exports, in one glance

@inflexion/sdk re-exports the whole foundation flat — addresses, abis, client, types, decode, resolveMarket, the quote helpers from ./quote.js — plus the load math namespaced as cvamm:

Summary

  • One pricing implementation. The Φ-sum is read on-chain and never reimplemented; only the deterministic load stack is mirrored off-chain.
  • The duplication is forced, not a shortcut. CvammPricing is delegatecall-only — there is no callable surface to read the load from, so a parity-locked port is the only way to preview a premium client-side.
  • It cannot drift. math.parity.test.ts asserts byte-equality with the deployed Solidity; divergence fails CI.
  • It is permanent, not temporary. The delegatecall-only property is permanent, so the mirror is too — and it is the only permitted duplication.
  • I10 is structural. The load clamp lives entirely upstream of settle and never touches MaxIL or I1–I9 — the no-bad-debt guarantee is independent of the load math.
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 Φ-sum fair value

The on-chain closed form the port multiplies — read, never reimplemented.

The load stack

The full derivation of baseLoad / utilSkew / dispSkew and the I10 clamp.

The pricing stack

How fair value + load combine across the two rails.

marketId parity

The off-chain marketId derivation and its parity lock.