Skip to main content
DataClient is the typed access layer over the data moat — the first structured view into the microstructure of the DeFi LP volatility-risk premium. It is read-only: it holds no signer, sends no transaction, and carries no claim. Its job is to expose the five non-circular behavioral signals through one consistent rule: if a backing (subgraph URL, RPC, or telemetry sink) is absent, the surface degrades to a typed pending state — never an error. The surface splits cleanly into two classes:

LIVE — live RPC

getCurrentLoadSurface and getSurfaceSigmaRef hit the chain directly and return real numbers today. The current load surface is the one live half of Signal 1 — the “price-to-beat”.

LIVE — subgraph/API-backed

The five history/aggregate methods resolve from the deployed subgraph via the hosted API. If a history source is absent the SDK returns a typed ApiPending envelope naming the API route and the query — so the UI degrades gracefully rather than throws.
Why this split exists. The on-chain moat events (SwapPriced, QuoteFilled) and the off-chain telemetry sinks are live now, and the subgraph that indexes them into bucketed history is deployed and indexing (served via the hosted API). So both the current surface and history / aggregates are queryable today; if a backing is absent a surface degrades gracefully rather than throws. See State of the dataset.

Method reference

Construct via the one-call factory; sdk.data needs only a read client.
The data moat is free public infrastructure, not a paywall. Revenue is protocol fees; the data is the competitive moat. DataClient is the SDK rung of the three-layer access rule — needs the exact surface right now → SDK; needs history or an aggregate → subgraph (consumed via the API); needs frictionless public access with no wallet → API.

The one live surface — getCurrentLoadSurface

getCurrentLoadSurface is the only DataClient method that hits live RPC instead of the API. It answers the question an MM or an LP needs right now: what mechanical load is the cvAMM pool charging — the “price-to-beat”? It fans the exact read set that MM getMarketPricing runs, across a set of markets at once.

What it reads (per market, one multicall)

1

Read loadParams + inventory once (pool-wide)

InflexionCore.loadParams() (the load-stack curve params) and ConvexityVault.inventory() → (total, locked, free, util, conc) are pool-wide, so they are read a single time and shared across all markets.
2

Per-market markets() multicall

InflexionCore.markets(marketId) → the market config (token0/token1/fee/duration). An unknown or inactive market yields an inlined degraded row, never a thrown call.
3

Per-market fairPremium() multicall

FairValueOracle.fairPremium(token, aWad, bWad, durationSeconds, maxIL) → (premium, fairRateWad, sigmaRefWad). This is the on-chain Phi-sum — never reimplemented off-chain.
4

Finish the load stack client-side (parity-locked TS port)

The deterministic, pure load stack is evaluated in TypeScript via the parity-locked cvamm port, then poolPremium = ceil(fairPremium·(1+totalLoad)) capped at MaxIL — exactly _pricePathAFromFair on-chain.
Why the load is finished client-side — the deployed CvammPricing library is delegatecall-only.
  • Limit: a direct eth_call to libs.cvammPricing reverts, so the SDK cannot read the on-chain loadComponents decomposition directly.
  • Why: Solidity guards deployed public-library functions; the lib runs on-chain only via the core’s delegatecall during pricing (confirmed on the 2026-06-05 deploy).
  • Mitigation: the SDK permanently mirrors only the deterministic load stack in a parity-locked TypeScript port, asserted byte-equal to the deployed Solidity by a dedicated parity test. This is the only permitted duplication — the SDK never reimplements the fairRate Φ-sum, which is always read on-chain (see the cvAMM port).

Geometry is optional — the load % is geometry-independent

If a market entry supplies no geometry, the SDK substitutes a neutral reference geometry. This is sound because the load percentage is geometry-independent — only the dollar fairPremium / poolPremium scale with the position’s aWad/bWad/maxIL. So you can read the per-market load surface without bringing any LP position. This is the same property that makes MaxIL the unit of risk and an MM quote per-market, never per-NFT.

Per-market graceful degradation

Each SurfaceRow is independently a discriminated union. A degraded market never breaks the others:

Worked example — read the live load surface

data-client-surface.ts
This row is the live half of Signal 1 — the realized clearing-load baseline. It is the mechanical leg (the protocol’s transparent yardstick), never sold as a behavioral signal; the behavioral leg (an MM’s freely chosen loadBps) is the QuoteFilled event, which arrives through the subgraph-backed history methods below.

getSurfaceSigmaRef — the transparent vol reference

The second live method reads the realized-vol oracle the entire load stack is measured against:
σ_ref is a poke-based, time-aware EWMA of Chainlink-tick log-returns — never raw realized σ (σ_ref derivation). Because it is transparent and on-chain, the load charged above it is a well-defined, identifiable quantity — which is precisely the property that converts the moat from circular to legible. It degrades to { available: false, reason: 'vol-uninitialized' } if the oracle has not yet been poked for that token.

The history methods + the ApiPending envelope

The remaining five methods need history or aggregates, which come from the subgraph (consumed via the hosted API at https://inflexion-backend.onrender.com). They resolve live today; if a history source is absent the method returns a typed ApiPending body instead of throwing:
ApiPending names the route and the would-be query. This is the graceful-degradation contract: if a backing is absent the UI can show “coming from <route>” rather than erroring, and the SDK swaps a one-line body to resolve from data — zero re-derivation. The SDK never fabricates history.
Handling it is uniform — discriminate on available and render the pending state:
pending-history.ts
The subgraph is deployed and indexing — so every history/aggregate method resolves live, with graceful degradation if a backing is absent.The contracts emit every event the moat needs (SwapPriced, QuoteFilled), the subgraph indexes them (slug inflexion-arb-sepolia on The Graph Studio, indexing from the redeploy startBlock), and the hosted API at https://inflexion-backend.onrender.com serves getLoadSurfaceHistory, getQuoteCompetition, getDemandRequests, getNavHistory, and getNetGamma over that subgraph plus the telemetry sinks. The off-chain telemetry halves (DEMAND_LOG, COMPETITION_LOG) are capturing now. If a backing (subgraph URL, RPC, or telemetry sink) is absent, the method returns ApiPending rather than throwing — so the degraded path remains a one-line body swap to data. See SDK degradation.
The free hosting tier sleeps after ~15 min idle, so the first request after a quiet period may incur a brief cold start.

One method’s latent half is off-chain by design — getDemandRequests

getDemandRequests resolves live, but its latent half is off-chain by design and can never be on-chain. It surfaces Signal 4’s demand that includes unfilled interest — an LP who priced but did not buy, and an MM quote that lost or was withdrawn, leave no on-chain trace because invariant I7 guarantees an unchosen quote touches no nonce and no capacity. Putting unfilled interest on-chain would both cost gas and break I7. So the latent half lives in the engine’s DEMAND_LOG telemetry sink — which is capturing now and is unreconstructable retroactively. getDemandRequests resolves from that accumulating log via the hosted engine (/engine), not from a backfill.

The five-signals access map

DataClient is the SDK rung of the per-signal access map. Each signal carries an explicit non-circularity verdict — the moat’s credibility rests on not being circular: a signal is non-circular iff its informative degrees of freedom come from the MM’s loadBps or the LP’s geometry/duration choice, measured against the transparent mechanical baseline, not derived from it. The deliberately-dropped circular idea (“invert fairRate to read implied vol”) is not a signal — see circular vs behavioral for why.
The behavioral − mechanical shape. Four of the five signals separate a behavioral leg (an actor’s free choice) from a mechanical baseline (the protocol’s transparent price-to-beat); the subtraction is what isolates the actor’s view and removes the circular component:
getCurrentLoadSurface serves the mechanical leg live (Path-A totalLoadWad, sigmaRefWad); the behavioral legs arrive through the history methods, served live from the deployed subgraph’s indexed QuoteFilled events via the API.
For exhaustive per-signal definitions, sourcing, and maturity, read the five signals; for the access routing in full, see the access map and the subgraph integration.

State of the dataset

This is the honest framing, and it is mandatory on every data-product surface.
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 pending state — never an error.
So the leading-indicator and forward-vol dynamics (the dispersion of Signal 1, the competitive distribution of Signal 2) need ≥3 competing MMs and ~30–50 fills per bucket — weeks-to-months at launch flow. The structures — the current load surface, the term-structure shape, the demand skew by geometry, the net-gamma surface — are queryable from launch. We ship the architecture and the first view, not a mature dataset.

Degradation cheat-sheet

The envelopes DataClient returns: The contract everywhere: reads are graceful — DataClient never throws on a reverting oracle, an absent rich event, or an absent history backing; it returns a typed degraded envelope. See SDK degradation for the full taxonomy.

The data moat (concept)

Why the flow is the product, and the circular idea we deliberately dropped.

The five signals

Exhaustive per-signal definitions, sourcing, non-circularity verdicts, and maturity.

On-chain primitives

The two moat events (SwapPriced, QuoteFilled) and the load-breakdown library.

The access map

The three-layer SDK / subgraph / API routing rule, per signal.

The cvAMM port

The parity-locked TS load stack — the only permitted off-chain duplication.

SDK degradation

Every typed degraded envelope the SDK returns, and how to render each.