MmClient — the
SDK surface for the Path-B market-maker rail. Every method
is listed with its exact TypeScript signature, the contract function(s) it reads
or writes, and its degradation envelope. For the narrative — why an MM quote is
per-market, the firm-quote / short-TTL economics, the end-to-end loop — see the
MmClient guide. For the canonical wire format, see
quote signing and the
quote-helpers reference.
The whole MM workflow is sign + read + cancel.
MmClient never sends a fill
(an LP does that on-chain via createSwapRouted) and never holds collateral (a
separate UnderwriterVault flow does). The one write it owns
is cancelNonces.Construction
MmClient is wired by the one-call factory; you never
instantiate it directly. It is the only surface that receives the EIP-712
chainId. Defaults: coreAddress = core.inflexionCore, npmAddress = npm,
chainId = 421614. It caches loadParams and per-market
configs — both immutable after market freeze.
MmClientOptions:
PublicClient
required
viem read client. Required for any on-chain read.
WalletClient (optional)
Write client for
cancelNonces. Absent ⇒ cancelNonces
throws MmQuoteError('no-signer').Address (optional)
Override the
InflexionCore address (defaults to the registry).Address (optional)
Override the Uniswap NPM address (defaults to the registry).
number (optional)
EIP-712 domain
chainId for quote signing. Defaults to 421614.Method reference — at a glance
R = read, W = write (tx), sign = signs but sends no tx, build = returns unsent calldata, poll = returns aStreamHandle.
Exported standalone utils:
Cached config reads
getLoadParams
InflexionCore.loadParams() and caches the result (immutable after
freeze — read once, reused thereafter). Used by every guard and
every load computation.
LoadParams — all *Bps are integer bigint, all *Wad are
1e18-scaled:
getMarketConfig
InflexionCore.markets(marketId); returns undefined when the market is
unregistered (token0 == address(0)). Cached per marketId (immutable).
MarketConfig:
Pricing
getMarketPricing
FairValueOracle.fairPremium + ConvexityVault.inventory +
VolOracle.sigmaRef, finished with the parity-locked TS port
of the load stack. The Φ-sum fairPremium is
read on-chain, never reimplemented; only the
deterministic load stack is mirrored off-chain (the deployed CvammPricing lib
is delegatecall-only). Returns a typed degraded result on any revert — never throws.
PricingGeometry input:
bigint
required
in WAD — lower range bound as a squared price ratio.
bigint
required
in WAD — upper range bound as a squared price ratio.
bigint
required
Protection tenor; selects the duration the FairValueOracle prices.
bigint
required
Position MaxIL in numéraire raw (dUSDC, 6 decimals) — scales the dollar premium.
Address (optional)
σ_ref token; defaults to the resolved
market.oracleToken.MarketPricingResult is a discriminated union:
MmMarketPricing:
_pricePathA expression:
LoadBreakdown and Regime:
PricingDegradeReason:
'no-rpc' | 'market-unknown' | 'vol-uninitialized' | 'fair-premium-revert' | 'inventory-revert'.
getPoolLoadToBeat
ConvexityVault.inventory() + VolOracle.sigmaRef,
finished by the TS-port load stack — no position geometry needed, because the
load (a percentage spread over FairPremium) is geometry-independent.
This is the mechanical face of MaxIL fungibility:
appetite, not position, is what an MM expresses.
PoolLoadTick — the optional fields are present only when
available: true:
streamPoolLoadToBeat
getPoolLoadToBeat on a loop (4 s default). The callback
fires once per market per tick with a single PoolLoadTick argument (the tick
carries its own marketId) — available or typed-degraded. Never throws inside
the loop.
StreamHandle: { stop: () => void } — every streaming method
returns this.
Vol oracle reads
getSigmaRef
VolOracle.sigmaRef(token) (WAD). Degrades to undefined if the token is
uninitialized (the getter reverts).
getSigmaComponents
VolOracle.sigmaComponents(token) — the EWMA inputs and which one binds.
Degrades to undefined on revert.
SigmaComponents:
binding (which σ source binds) is distinct from the load regime
(calm/normal/stressed). regime is derived from σ_ref vs the loadParams regime
bands, not from sigmaComponents.binding. See
σ_ref.Position geometry (for $ display)
getPositionGeometry
NPM.positions
for ticks + liquidity, derives marketId from (token0, token1, fee, durationSeconds),
pins P0 from InflexionCore.oracleDerivedSqrtPriceX96, and computes a/b + entry
amounts + MaxIL on-chain via ILMath. durationSeconds is required — a position
alone has no expiry, so the duration is what lines up the marketId and the FVO
duration. Returns a typed degrade on an oracle revert or unrecognized position; never
throws.
PositionGeometry:
Geometry is for display, not for signing. You sign a per-market quote — the
SignedQuote carries no tokenId. Geometry only lets you show a
$ pool premium next to your $ quote (feed it to getMarketPricing).
That is MaxIL fungibility in code: appetite is per-market, position is per-NFT.The book and greeks
getBook
mm plus aggregate exposure. The live deploy
has no on-chain quoteId/nonce → swap index and MmClient takes no subgraph
dependency, so the swap-id set is discovered by scanning swaps(id) over [fromSwapId, nextSwapId) (bounded; narrow with fromSwapId, or inject a known swapIds set).
Each swap’s path is inferred via mm == convexityVault (Path A) else Path B. With
withGreeks: true, per-position δ/γ are finite-differenced off the on-chain ILMath.
A direct on-chain scan — independent of the subgraph.
BookResult:
BookPosition:
greeksForSwap
ILMath.computeIL over ±1%
of the live oracle P0, each leg capped at MaxIL (the MM is short the capped
claim). Returns undefined if the swap cannot be priced (oracle
degraded / not active). This is the MM-book fast path: vega and theta are left
at 0 — full vol-greeks live in the GreeksEngine,
which finite-differences FairValueOracle.fairRate.
Greeks:
Quote signing
signQuote
SignedQuote and enforces two guards before returning the
envelope. The actual EIP-712 signing delegates to the engine
signer (@inflexion/engine/quote.signQuote, never reimplemented) — it builds a
viem account from the raw key, so this path is server-side only. For the
browser, sign with the connected wallet and replicate these guards yourself (see
the guide and
quote signing).
1
I10 — the price cap (hard)
loadBps ≤ loadParams.maxLoadBps, else throws MmQuoteError('i10-exceeded')
(invariant I10). The MM can never out-load the protocol cap.2
Below-pool — strict beat (soft unless required)
loadBps < live pool-load-bps (read via getPoolLoadToBeat),
else MmQuoteError('not-below-pool'). If the pool load is unreadable the check is
skipped and reported as belowPoolChecked: false — unless requirePoolCheck: true,
which makes it throw MmQuoteError('pool-load-unreadable').SignedQuote input — the 13 fields in struct/signing order;
quotePrice, maxNotionalV0, validUntil, nonce
are bigint, the *Bps and model are plain number:
opts:
boolean (default false)
Make an unreadable pool load a hard error (
pool-load-unreadable) instead of skipping the below-pool guard.Address (optional)
Override the EIP-712
verifyingContract (defaults to coreAddress).number (optional)
Override the EIP-712
chainId (defaults to the client’s chainId).SignQuoteResult:
QuoteEnvelope: { quote: SignedQuote; signature: Hex }.
quoteStream
getPoolLoadToBeat,
calls build(poolLoad) (return undefined to skip a tick), signs via
signQuote (re-enforcing I10 + below-pool), then hands the envelope
to your injected publish transport. MmClient deliberately does not
depend on ws — you own the socket. Degrades silently per tick (a tick whose pool
load is unreadable, or whose build/sign throws, is skipped and reported via
onError).
QuoteStreamOptions:
Fills, capacity, and cancel
isQuoteFilled
InflexionCore.isNonceUsed(mm, nonce). Degrades to
spent: false with a detail on a read failure — never throws.
NonceStatus:
watchFills
SwapCreated logs filtered by the indexed mm topic and fires onFill per
new matching log. The event carries mm but not
quoteId/nonce, so the match to a specific quote is coarse (attribution: 'coarse'). Works now; the precise path is the QuoteFilled event, indexed by
the subgraph and served live via the hosted API.
Degrades silently on a failed poll (reports via onError).
FillLog:
Structures ship from day one; the full DYNAMICS (pool-vs-MM spread as a forward-vol signal) mature with multiple competing MMs and volume. The dataset begins at the single redeploy; the off-chain telemetry halves begin at the first interaction logged.What Inflexion offers today is the architecture and the first public view into the microstructure of the DeFi LP volatility-risk premium — not yet a mature dataset:
- Structures are present day-one. All five non-circular behavioral signals are defined and queryable from launch.
- Dynamics mature with volume. The richer signal — the pool-vs-MM spread read as a forward-vol indicator — only sharpens once multiple market makers compete and real flow accumulates.
- The dataset begins at the single redeploy, and the off-chain telemetry halves begin at the first interaction logged. History is served live from the subgraph via the API; if a backing (subgraph URL / RPC / telemetry) is absent, surfaces degrade to a typed
pendingstate — never an error.
capacityRemaining
consumedNotional[quoteId] is the
on-chain authority, incremented atomically in the effects phase before any external
call, so concurrent fills cannot over-consume a quote. Degrades to
{ available: false } on a read failure — never throws.
cancelNonces
MmClient owns. Sends InflexionCore.cancelNonces from the
wallet client, flipping exactly the bitmap bits you pass (never cancel-all), so
you revoke precisely the quotes you want. Returns the tx hash.
Throws MmQuoteError('no-signer') if no wallet (or no account) is wired. A
cancelled bit can never fill — it satisfies the second clause of
I7.
buildCancelNoncesTx
cancelNonces calldata, for an external signer or a tx preview — no
wallet required.
MM collateral — the UnderwriterVault flow
getMmCollateral
UnderwriterVault balances in one
multicall (deposited / locked / availableBalance). All figures are dUSDC
6-dec raw. Degrades to undefined on a failed read.
Collateral is not part of signQuote. Before any of an MM’s quotes can be
filled, the MM posts collateral via a separate ERC-20 approve + deposit to the
UnderwriterVault — MmClient only reads the state, it never writes the deposit.
On a Path-B fill the contract requires availableBalance(mm) ≥ maxIL and locks
maxIL of the MM’s own collateral; at settlement the LP is paid
from that locked collateral — never
protocol funds. The standing invariant is I5:
locked[mm] ≤ deposited[mm] by construction.
Errors
MmQuoteError — the typed error every guard and write throws:
Degradation envelope cheat-sheet
Reads degrade; writes throw. Every MM read returns a typed envelope
(
available/priceable/undefined) and never throws on a missing oracle or RPC.
The two non-read paths — signQuote (a guard failure) and cancelNonces (a missing
signer) — throw MmQuoteError with a .code, because a violated guard or absent
wallet is a hard programmer error, not a degraded data state. See
degradation.The two separate claims
The MM rail changes neither guarantee. The settlement core enforces the LP-facing guarantee identically for both rails: And the capital-at-risk disclosure applies to the underwriter — on Path B, the market maker posting collateral in its ownUnderwriterVault:
Network: Arbitrum Sepolia · chainId 421614 · deploy block 274081134 (subgraph startBlock) · deployed 2026-06-05
Core protocol
Stylus & libraries
Oracles
Uniswap
Chainlink feeds
Demo tokens / pool / LP
Lifecycle swaps
Live create→settle lifecycle (2026-06-05, short 300s fee-500 market
0xb8bbd684f213d5833886ade7b531a6949d85522249881a2b5d46a5cc76e439c2):
- Path A (cvAMM convexity) — swapId 1, LP tokenId 3220 · V0 $270,531.28 · MaxIL $1,669.24 · premium $9.70 (0.58% of MaxIL) · settled payout $148.64 from ConvexityVault.
- Path B (MM routing) — swapId 2, LP tokenId 3221 · MM beat cvAMM ($8.93 vs $13.80) · MaxIL $3,215.65 · MM collateral locked $3,215.65 · settled payout $245.66 from MM collateral.
Where to go next
MmClient guide
The narrative: per-market quoting economics, the end-to-end loop, browser signing.
Quote signing reference
The canonical EIP-712 domain, type-string, and verify/recover helpers.
Quote helpers
encodeQuote / decodeQuote / quoteDigest / verifyQuote signatures.
Greeks + hedge types
Full vol-greeks (vega/theta) and the three-leg hedge suggestion types.
Path B in the protocol
The on-chain createSwap gate, capacity (I7), the no-last-look protections.
The engine
The Path-B relayer: WS protocol, GET/POST /quote, the freshness gate.