@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.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: 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 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 (, utilisation , concentration ) 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.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.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 liveSwapPriced 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:
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 inCvammPricing.sol:
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.
baseLoad(σ_ref) — a regime BAND, not a continuous curve
baseLoad(σ_ref) — a regime BAND, not a continuous curve
cvamm.baseLoadWad(σ_ref, params) returns one of three flat values selected by which regime band falls into — it is not a continuous function of :This is why a Path-A “term structure of load” is a flat line: baseLoad is duration-independent. See the load stack.utilSkew(u) — flat below a knee, convex above, capped
utilSkew(u) — flat below a knee, convex above, capped
cvamm.utilSkewWad(u, params), where :The convex term uses the WAD powWad helper.dispSkew(h) — HHI dispersion, capped
dispSkew(h) — HHI dispersion, capped
cvamm.dispSkewWad(h, params), where is the normalised coverage HHI (concentration):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
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.
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.
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: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.
CvammPricingis 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.tsasserts 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
settleand never touchesMaxILor I1–I9 — the no-bad-debt guarantee is independent of the load math.
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.