Skip to main content
@inflexion/sdk is the typed access layer over the live deployment. It is the only layer that holds a signer and the only one that can answer the load-bearing question — “what dollar premium will I be charged on this position if I sign in the next block?” — by combining a fresh on-chain FairValueOracle read with the position’s geometry. One call wires everything: createInflexionSdk(config) builds one public (read) client plus one optional wallet (write) client, then injects them into all five stakeholder surfaces — lp, depositor, mm, data, and the read-only greeks/hedge.
No address is ever passed in. Every contract address loads from the on-chain address registry — a hard rule, not a convenience. See addresses & units and the deployments registry.

Install

The SDK is a workspace package in the Inflexion monorepo. It ships ESM with viem as the only hard runtime dependency on the read/write side; the EIP-712 quote helpers are re-exported from the engine.
Quote helpers are also exposed at a subpath. The EIP-712 SignedQuote helpers re-export from both @inflexion/sdk and @inflexion/sdk/quote. Import from the subpath when you only need signing/verification and want to keep your bundle tight.

The one-call factory

The whole config is optional. With no args at all the SDK still constructs — it resolves the RPC and signer from the environment and degrades gracefully if either is absent. The design has two properties you can rely on everywhere:

Reads are graceful

Anything that needs a reverting oracle, an absent rich event, or an unreachable subgraph returns a typed degraded envelope ({ available: false, reason } / { priceable: false, reason } / precision: 'coarse') — it never throws. See degradation.

Writes degrade, never crash at construction

Construction never throws on a missing signer. With no walletClient, LP/MM writes throw a clear error on call (the one place a missing signer is a hard error); DepositorClient instead returns WriteResult { status: 'deferred-no-wallet' } carrying the unsigned tx for an external signer.

Every config field

InflexionSdkConfig. Every field is optional; precedence rules are in Resolution order.
string
Explicit RPC URL for the read client. Falls back to env, then to the chain’s default public RPC.
Transport
A custom viem Transport (for example a test mock). Overrides rpcUrl.
PublicClient
A pre-built viem read client. Overrides rpcUrl and transport — this is the recommended browser path, since it reuses the client wagmi already holds and avoids a second RPC connection.
WalletClient
A pre-built viem write client. Overrides privateKey and account. This is how the browser injects the connected wallet.
Hex
A raw signer key for writes (server/key-based mode). Falls back to env. Absent ⇒ writes are deferred, not crashed.
Account
A pre-built viem Account for writes. Overrides privateKey.
string
Base URL of the off-chain matching engine. Used for Path-B MM quotes and the previewPremium latent-demand telemetry ping. Only the lp surface receives it.
string
Base URL of the public REST API (the hosted backend). Passed to the data surface so the history/aggregate methods (getNavHistory, getLoadSurfaceHistory, getQuoteCompetition, getDemandRequests, getNetGamma) fetch live from the subgraph; absent ⇒ those surfaces degrade to a typed ApiPending (the live RPC surfaces are unaffected). The app reads it from NEXT_PUBLIC_API_URL.
string
Override for the telemetry endpoint. Defaults to ${engineBaseUrl}/telemetry/preview.
typeof fetch
An injected fetch implementation (tests / non-browser runtimes). Defaults to the global fetch when present.
number
default:"421614"
The EIP-712 chain id used for quote signing. Defaults to the live chain, 421614. Only the mm surface receives it.

Resolution order

This is the graceful-degradation contract. It is fully deterministic — higher-precedence fields win, and missing fields fall back to env, then to a safe default.

Read client

If you pass publicClient, it is used verbatim. Otherwise the SDK builds one. The effective rpcUrl is resolved in this order:
1

config.rpcUrl

The explicit URL you passed.
2

process.env.ARBITRUM_SEPOLIA_RPC

The canonical env var for this network.
3

process.env.SEPOLIA_RPC

A secondary env fallback.
4

the chain's default public RPC

A safe last resort so reads always have a transport.
A transport you pass overrides rpcUrl (it is injected directly into the viem client).

Write client

makeWalletClient returns undefined when no signer is available — no account, no privateKey arg, and no env key. When that happens the SDK degrades every write rather than crashing at construction. The signer key is resolved in this order:
1

config.account

A pre-built viem account wins outright.
2

config.privateKey

A raw key arg, from which an account is derived.
3

process.env.DEPLOYER_PRIVATE_KEY

The canonical deployer/server key.
4

process.env.PRIVATE_KEY

A secondary env fallback. If none of these is present, the write client is undefined.

Chain id

Never put a raw private key in the browser. The key-based path (and the engine’s positional signQuote(privateKey, ...) helper) is server-only. In the browser, inject a walletClient and sign with the connected wallet — see mode (a) below and quote signing.

What the factory returns

InflexionSdk:
Only the surfaces that need an extra config field receive one: lp gets engineBaseUrl / telemetryUrl / fetchImpl; mm gets chainId; depositor / data / greeks / hedge get just the clients. The five surfaces are documented in the LP, depositor, MM, data, and greeks/hedge clients.

The two instantiation modes

The recommended path. Inject the pre-built viem clients wagmi already holds; passing publicClient overrides rpcUrl/transport so you avoid opening a second RPC connection. The wallet client appears only once connected — omit it until then and writes throw a clear error on call.
apps/web/lib/use-sdk.ts
Do not pass account explicitly. wagmi’s useWalletClient() already carries .account and .chain; walletClient.account is used directly. Spreading walletClient only when truthy keeps the SDK in graceful-write mode while the wallet is disconnected.

Environment variables

The factory resolves these when the corresponding config field is absent. Set them in your shell, .env, or deployment platform — see env vars for the full app-side list.
In the browser, only NEXT_PUBLIC_-prefixed env vars are visible. The app reads the engine URL from NEXT_PUBLIC_ENGINE_URL and passes it as engineBaseUrl (see mode (a)). The bare ARBITRUM_SEPOLIA_RPC / *_PRIVATE_KEY fallbacks are server-side conveniences — they never apply when you inject a publicClient/walletClient from wagmi.

A first call — confirm it’s wired

A construction-only smoke test. Reads are graceful, so this never throws even if the oracle is degraded — it returns a typed envelope you can branch on.
smoke-test.ts
What needs which backend — read this once.Path-B previews need the engine; all history/aggregate surfaces are served live from the subgraph via the hosted API. Both backends are hosted as one combined service at https://inflexion-backend.onrender.com (REST API at /, engine at /engine).The engine relays firm MM quotes off-chain (no last look); the rich on-chain events (SwapPriced, QuoteFilled) are indexed from deploy block 274081134 and queryable now via the subgraph.Graceful degradation still holds: if engineBaseUrl is unset, previewPremium silently routes Path A only — never an error. If a subgraph URL is unset, every DataClient history method returns a typed ApiPending envelope naming the route — never a fabricated number. Live today over RPC alone (no subgraph needed): premium preview, current load surface, σ_ref, market pricing, vault state, protection status, position geometry, the book, and coarse fills. See status & caveats and degradation.
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.

Where to go next

Addresses & units

The registry imports, dUSDC = 6-dec numéraire, WAD = 1e18, and the sqrtPriceX96 conversions.

LP client

previewPremium, buyProtection, settle — buying in-range IL protection (claim A).

Depositor client

Deposit/withdraw the cvAMM tranches; every result carries the capital-not-guaranteed claim (claim B).

MM client

Per-market signed quotes, the pool-load-to-beat, and the I10 / below-pool guards.

Data client

The live load surface plus the typed-pending history surfaces of the data moat.

Degradation

The full Degraded / Priceable / ApiPending envelope contract — why nothing throws.