Skip to main content
Inflexion mixes several fixed-point conventions on purpose: an ERC-20 numéraire that is 6 decimals, a volatile token that is 18, Chainlink feeds that are 8, and an internal WAD (1e18) world for every rate. Getting these wrong is the single most common integration bug, so this page is the canonical decoder ring.
The naming rule is mechanical: a field whose name ends in Wad is 1e18-scaled fixed point (1e18 = 1.0). A USDC amount is a 6-decimal raw bigint. A price is a feed-decimal raw integer unless the field name says Wad.

The numéraire conventions table

The numéraire (token1 = dUSDC) is the unit of account for everything an LP or underwriter sees in dollars: the premium they pay, the MaxIL collateral that gets locked, the entry value V0, and the payout at expiry. If a number is “in USD,” it is a 6-decimal raw integer.

Why three different worlds (6 / 18 / 8) coexist

These are not arbitrary — each scale is fixed by an external system Inflexion does not control:

6 — the token's own decimals

dUSDC mirrors Circle’s native USDC, which is a 6-decimal ERC-20. The numéraire must match the token contract or transfers would be off by 12 orders of magnitude.

18 — the token's own decimals

dWETH mirrors WETH, an 18-decimal ERC-20. token0 < token1 by address, so token0 = dWETH and token1 = dUSDC (see the markets grid).

8 — Chainlink's convention

Every Chainlink USD aggregator on Arbitrum reports an 8-decimal answer. This is their convention, not ours; the OracleManager consumes it as-is.
WAD (1e18) is the internal lingua franca that decouples rate math from any token’s decimals. σ_ref, fairRate, the load multipliers, and the a = Pa/P0 / b = Pb/P0 ratios are all dimensionless rates, so they live in WAD where 1e18 = 1.0. This is why a *Wad suffix is load-bearing: it tells you the value has already been normalised out of token-decimal space.
Limit: dWETH and dUSDC are demo tokens on Arbitrum Sepolia, not canonical WETH/USDC. Why: there is no pre-seeded WETH/USDC v3 pool with material liquidity on Sepolia, so the deployment ships its own numéraire-correct mock pair. Mitigation: dWETH is oracle-priced via the real Chainlink ETH/USD feed, so it still moves with live ETH, and the decimal conventions (6 / 18 / 8) are identical to the eventual Arbitrum One deployment — see deployments.

WAD, basis points, and the rate stack

Every rate Inflexion publishes — fairRate, each load component, σ_ref — is a WAD value. The conversion BPS_TO_WAD = 1e14 bridges the on-chain basis-point inputs (an MM signs a loadBps; the I10 cap is a maxLoadBps) into the WAD math: 1 bp=10−4=10141018 WAD⟹BPS_TO_WAD=10141\ \text{bp} = 10^{-4} = \frac{10^{14}}{10^{18}}\ \text{WAD} \qquad\Longrightarrow\qquad \texttt{BPS\_TO\_WAD} = 10^{14} The constants are exported directly from the SDK’s parity-locked load-stack port:
So a 10% MM load (loadBps = 1000, the value on the live Path-B swap — see lifecycle) converts to WAD as 1000 × 1e14 = 1e17 = 0.10 in WAD. The load stack then computes: premium=FairPremium⋅(1+loadWad),loadWad=loadBps⋅BPS_TO_WAD\texttt{premium} = \texttt{FairPremium} \cdot \bigl(1 + \texttt{loadWad}\bigr), \qquad \texttt{loadWad} = \texttt{loadBps} \cdot \texttt{BPS\_TO\_WAD}
loadBps and maxLoadBps are the basis-point twins of the WAD load values — the same quantity in two units. The on-chain I10 cap is expressed in bps (maxLoadBps) and as a rate (maxLoad); see the load stack and the invariants.

sqrtPriceX96 and the Q64.96 fixed-point world

Uniswap v3 stores price as a sqrtPriceX96 — the square root of the price of token0 in token1, scaled by 2962^{96}: sqrtPriceX96=P⋅296⟹P=(sqrtPriceX96296)2\texttt{sqrtPriceX96} = \sqrt{P}\cdot 2^{96} \qquad\Longrightarrow\qquad P = \left(\frac{\texttt{sqrtPriceX96}}{2^{96}}\right)^{2} This is a uint160 carrying a 96-bit fractional part — the “Q64.96” format (64 integer bits, 96 fractional bits). Inflexion’s settle-path IL math (ILMath) runs entirely in Q64.96 so it never touches floating point: computeMaxIL, computeIL, and getAmountsForLiquidity are pure Q64.96.
Important: the price PP recovered from sqrtPriceX96 is token0-in-token1 in raw token units — it has not been adjusted for the 18-vs-6 decimal gap between dWETH and dUSDC. To get a human “ETH price in USD” you must additionally divide by 10(18−6)=101210^{(18-6)} = 10^{12}. This decimal-gap adjustment is the second most common integration bug after confusing *Wad fields with raw amounts.

The FairValueOracle 1e24 scale

The Stylus FairValueOracle speaks WAD on its ABI but computes internally in 1e24. Stylus bans WASM floating point at activation, so every transcendental in the Φ-sum (erf/Φ, exp, ln, sqrt) is integer fixed point; the contract lifts its WAD inputs to 1e24 for headroom and rounds the result back to WAD half-up.
You never see 1e24 from the outside. The FVO takes WAD inputs (a, b, σ_ref via STATICCALL) and returns a WAD fairRate / a numéraire-scaled FairPremium. The 1e24 lift is an internal precision device that keeps the Φ-sum machine-precise to ≤ 1e-12 — it is not part of any ABI you call. Treat the FVO as a WAD black box and read the Φ-sum page for the math.

SECONDS_PER_YEAR and time

σ_ref and the time-to-expiry TT are both annualised over a 365-day year: SECONDS_PER_YEAR=365×24×3600=31,536,000\texttt{SECONDS\_PER\_YEAR} = 365 \times 24 \times 3600 = 31{,}536{,}000 This value is shared by the on-chain VolOracle and the Stylus FVO, and it matches the Python quant model — so the annualisation is identical across the off-chain research notebook, the vol oracle, and the pricer. The market durations feed into TT as raw seconds: 7d = 604,800, 30d = 2,592,000, 90d = 7,776,000 (see the markets grid).
Durations are stored as raw seconds and are part of the marketId preimage (uint32 durationSeconds). The fairRate S-curve is a function of σ2⋅T\sigma^2 \cdot T, so the same geometry produces a different price per duration — which is exactly why the 9 markets exist. See MaxIL and the markets grid.

Practical conversions

Worked, copy-pasteable conversions for the four scales you actually touch.
dUSDC, MaxIL, premiums, V0, and payouts are 6-decimal raw bigints. The live Path-A swap (swapId 1) had V0 = 270,531.28 and MaxIL = 1,669.24 (see lifecycle). On the wire those are:
Never use Number() on a USDC bigint before dividing if the value can exceed 2^53 (~9.007e15 raw, i.e. ~9.007 billion dUSDC). For display of normal amounts it is fine; for arithmetic, stay in bigint.

Common pitfalls

A fairRateWad of 847000000000000000n is 0.847, not “847 quadrillion USDC.” Check the field name: *Wad ⇒ divide by 1e18; a plain dollar amount ⇒ divide by 1e6. The SDK encodes this in its type comments.
A price derived from sqrtPriceX96 or from raw token reserves is in raw token units and is off by 10^(18−6) = 10^12 from a human ETH/USD figure. Always apply the decimal-gap adjustment for display.
σ_ref and TT annualise over 365 days (SECONDS_PER_YEAR = 31,536,000). A 360-day convention would silently mis-scale every fairRate. The on-chain VolOracle, the Stylus FVO, and the Python model all agree on 365.

See also

Deployments

The live Arbitrum Sepolia registry — token addresses with their decimals.

Markets grid

The 9 markets, fee tiers, and the duration-in-seconds values.

SDK addresses & units

How the SDK exposes these constants and loads the on-chain address registry.

The Φ-sum

Where the WAD → 1e24 lift and the half-up rounding live.