DataClient is the SDK surface over the data moat — the first public view into the microstructure of the DeFi LP volatility-risk premium. It carries no claim and holds no signer: every method is read-only and none of them ever mutate state.
The surface splits cleanly into two classes, and the split is the whole design:
One LIVE method
getCurrentLoadSurface (+ the getSurfaceSigmaRef annotation) reads live RPC: the same multicall MM getMarketPricing does, fanned across a set of markets. The current “price-to-beat” snapshot, uncached.Five history methods
getLoadSurfaceHistory, getQuoteCompetition, getDemandRequests, getNavHistory, getNetGamma — every history/aggregate surface. Each names its API route and is served live from the subgraph via the hosted API; if no source is configured it degrades to a typed ApiPending rather than throwing.The SDK never fabricates history. The history/aggregate surfaces are served live from the deployed subgraph via the hosted API (REST at
/, engine at /engine). If a backing source is not configured the method returns a typed degraded envelope ({ available:false, reason:'no-history-source', endpoint, query, detail }) — never a throw, never a guessed number. The on-chain moat events (SwapPriced, QuoteFilled) are LIVE since the 2026-06-05 redeploy and the subgraph has indexed them from block 274081134.The method table
Construct it from the SDK factory (sdk.data) or directly via makeDataClient(publicClient). The constructor takes optional address overrides; by default it resolves InflexionCore, ConvexityVault, the Stylus FairValueOracle, and VolOracle from the deployment registry.
Each history method maps 1:1 onto one of the five behavioral signals. The route strings are not free text — they are the SDK ↔ API contract, exported verbatim as
DATA_API_ROUTES so the integration layer wires exactly the same paths the SDK already names.
The live half — getCurrentLoadSurface
This is the only DataClient method that hits live RPC directly instead of the hosted API. It is the live half of Signal 1 — the current clearing-load “price-to-beat” — while its historical evolution is getLoadSurfaceHistory.
Read set
Per call: one sharedloadParams() + inventory(), then a per-market markets() multicall, then a per-market fairPremium() multicall — exactly the read set MM getMarketPricing does, fanned out:
CvammPricing TS port: load = loadComponents(σ_ref, util, conc, params) and
The Φ-sum is read on-chain and never reimplemented; only the deterministic pure load stack is mirrored off-chain — the single permitted duplication, because the deployed CvammPricing library is delegatecall-only and reverts on a direct eth_call. See the cvAMM port.
Return shape — LoadSurface
MarketPricing row carries the full price-to-beat decomposition:
Hex
FairPremium for the supplied geometry, USDC raw (6-dec) — from the Stylus FVO.
bigint
FairPremium / MaxIL as a WAD ratio (1e18-scaled).bigint
The σ_ref (WAD) the fair value was computed against.
Path-A pool premium =
ceil(FairPremium·(1+totalLoad)), capped at MaxIL, USDC raw.bigint
MaxIL for the geometry, USDC raw — the cap
poolPremium is clamped to.LoadBreakdown
The pool load stack — the price-to-beat decomposition.
bigint
Pool utilization (locked / total), WAD.
bigint
Pool coverage concentration (HHI), WAD.
'calm' | 'normal' | 'stressed'
Vol regime from σ_ref vs the
loadParams bands.Per-market degradation
A single bad market never throws the whole surface — the degraded row is inlined so the caller sees exactly which markets have gaps:Worked example
data-surface.ts
getSurfaceSigmaRef returns a Degraded<{ sigmaRefWad, regime }>: { available:false, reason } if the VolOracle is uninitialised for the token (poke it first), never a throw. See σ_ref and the load stack.
The degradation contract — the ApiPending envelope
The history/aggregate methods are served live from the subgraph via the hosted API. The full type is ApiBacked<T> = ({ available:true } & T) | ApiPending — the rich T from the API, else, if no backing source is configured, the same typed pending envelope:
<route>” regardless of backing state, and the degraded path is a typed body — not a throw — so graceful degradation is a design property: if a backing (subgraph URL / RPC / telemetry) is absent, the surface returns this pending body instead of erroring.
When degraded, the detail string carries the disclaimer verbatim, with any method-specific prefix folded in front:
DATA_API_ROUTES — the route contract
The five routes are exported as a const so callers can read them and the hosted API serves the same strings:
The route + query, per method
Each method assembles itsendpoint + query deterministically from its args (optional args are omitted from query when absent; bucketed methods default the bucket). Live, the API returns the rich body for that route; the snippets below show the typed degraded fallback the SDK returns when no source is configured, which is exact to source.
getLoadSurfaceHistory — Signal 1 (history)
getLoadSurfaceHistory — Signal 1 (history)
Args:
{ marketId: Hex; from?: number; to?: number; bucket?: '1h' | '1d' }bucket defaults to '1d'; from/to are stringified when present, omitted when absent. Source for the historical evolution of getCurrentLoadSurface — the subgraph indexes MarketStateSnapshot and joins the now-live SwapPriced/QuoteFilled per-fill load events, served live via /data/load-surface. For the CURRENT surface, use getCurrentLoadSurface (live RPC). See Signal 1.getQuoteCompetition — Signal 2 (spread + win-rate)
getQuoteCompetition — Signal 2 (spread + win-rate)
Args: Joins the now-live
{ marketId?: Hex; from?: number; to?: number } (all optional)SwapPriced (mechanical pool baseline = the price-to-beat) with QuoteFilled.loadBps (the behavioral MM load) per swap from the subgraph, plus the off-chain engine COMPETITION_LOG telemetry for the dynamic half. The spread poolLoad − mmLoad is non-circular as a spread — the subtraction removes the circular component (see circular vs behavioral). Both halves are live: the dynamic half is captured in engine telemetry, the structural half is indexed by the subgraph.getDemandRequests — Signal 4 latent half (off-chain BY DESIGN)
getDemandRequests — Signal 4 latent half (off-chain BY DESIGN)
Args:
{ marketId?: Hex; from?: number; to?: number } (all optional)getNetGamma — Signal 5 (net convexity supply)
getNetGamma — Signal 5 (net convexity supply)
Args: Off-chain compute over the subgraph-tracked open swap set (
{ marketId?: Hex } (optional; defaults to {})SwapCreated opens, SwapSettled closes), summing per-swap Greeks finite-differenced from the deployed ILMath.computeIL / FairValueOracle.fairRate — no parallel pricing model. NOT a contract event; the live SDK has no aggregator because it needs the open set. This is the most launch-robust signal — a sum, not a distribution, so it is meaningful from a handful of swaps. See Signal 5 and the Greeks engine.The five signals this surface maps to
EachDataClient method maps onto one behavioral signal. All five are non-circular — their informative degrees of freedom come from the MM’s loadBps or the LP’s geometry/duration choice, measured against the transparent mechanical baseline, never derived from it.
Exclude cap-bound fills from the load surfaces (Signals 1/2/3): when
premium == MaxIL the load was truncated by the cap and the number carries zero load information. The on-chain SwapPriced.cappedAtMaxIL boolean makes this filter cheap and unambiguous. See the five signals.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.
Live vs live — the one-glance summary
- Live via RPC (no API needed)
- Live via the hosted API + subgraph
getCurrentLoadSurface— current pool load surface across markets (live RPC multicall).getSurfaceSigmaRef— the σ_ref + regime a surface is priced against.- The on-chain moat events (
SwapPriced,QuoteFilled) are emitting now (since 2026-06-05). - The off-chain telemetry sinks (
DEMAND_LOG,COMPETITION_LOG) are capturing now — the dynamic/latent halves of Signals 2 & 4.
Related
The data moat (concept)
The thesis, the five signals, and why the dataset cannot exist anywhere else.
Circular vs behavioral
Why inverting
fairRate is circular, and what makes each signal legible.DataClient (guide)
The narrative walkthrough of the load surface and the degradation contract.
MmClient reference
The same multicall read set, per-market, plus quote signing.