Orderbook Contract
Status: M1 verified Last verified: 2026-07-19
Official sources: HL.DOC.INFO.L2BOOK.2026-07-19, HL.DOC.WS.L2BOOK.2026-07-19
Hyperliquid documents the L2 schema but does not publish generic mid, spread, VWAP, or slippage formulas. The formulas below are Math-owned local-exact calculations over one explicit frozen snapshot; they do not predict queue position, latency, or submitted-order fills.
Normalized L2 snapshot
- Public snapshot input is
{ levels: [bids, asks] }. levels, bids, and asks are dense plain arrays with own data entries; each side contains at most the official snapshot maximum of 20 levels. Accessors, sparse arrays, custom keys/prototypes, and longer sides are invalid input.- Every level is exactly
{ px, sz, n }, with positive decimal-stringpx/szand positive safe integern. - Bids are strictly descending by price; asks are strictly ascending. Duplicate levels are invalid.
- As a Math-owned structural invariant, if both sides exist, best bid must be strictly below best ask. Hyperliquid documents the schema but not this validation rule; it is imposed so a normalized frozen snapshot cannot silently encode a locked/crossed state. Live fixtures provide only observational support for the invariant.
- Response spelling such as trailing zeroes is normalized before calculation. No protocol rounding is applied to a recorded level.
hl.orderbook.metrics v1
Source ID: HLM.SPEC.ORDERBOOK.METRICS.V1
- Requires at least one bid and one ask. A structurally valid one-sided/empty book returns
indeterminatewith explicit missing paths; it does not copy theallMidslast-trade fallback. bestBid = bids[0].px;bestAsk = asks[0].px.mid = (bestBid + bestAsk) / 2.spread = bestAsk - bestBid.spreadBps = spread / mid * 10000.- Decimal division uses the v1 Decimal40 kernel (40 significant digits, HALF_EVEN) and records that boundary in
trace.rounding. - Authority is
local-exact; maturity isstable. - The public result is
MathResult<{ bestBid: string; bestAsk: string; mid: string; spread: string; spreadBps: string }>: valid two-sided input returnsok; malformed levels, ordering, duplicate, locked, or crossed input returnsinvalid-input; a structurally valid one-sided/empty input returnsindeterminatewith codetwo-sided-book-requiredand missing JSON pointers for the absent sides.not-applicableis not used. - Trace formula ID is
hl.orderbook.metricsv1. SourceRefs contain this spec, the official L2 schema, andDECIMALJS.10.6.0; assumptions contain onefrozen-inputentry for/levels; rounding records the Decimal40/HALF_EVEN divisions used for mid/spread bps.
hl.orderbook.fill.simulate v1
Source ID: HLM.SPEC.ORDERBOOK.FILL.V1
Input is exactly { levels, side, amount, referencePrice }:
sideisbuyorsell; buys walk asks best-to-worst and sells walk bids best-to-worst.referencePriceis a positive decimal string and is never inferred.amountis either{ kind: "size", value }or{ kind: "notional", value, szDecimals }, with a non-negative decimalvalue.- Notional
szDecimalsis a safe integer from0through8, matching the supported precision metadata bound and preventing an unbounded Decimal quantization request. - A zero requested amount is valid but returns
not-applicable. - Size requests fill
min(remainingSize, levelSize)at each level. - Notional requests consume full levels while possible. The final partial level computes
remainingNotional / levelPrice, then rounds size down toszDecimals; any unspendable remainder stays unfilled. - If that final down-quantized size is zero, omit the fill entirely. With no earlier fill, completion is
none; with earlier fills, completion ispartial. For notional requests,unfilledAmountis the exact requested notional minus the exact filled notional. For size requests it is requested size minus filled size. - Result completion is
none,partial, orfull; it always reports fills, filled size/notional, and the unfilled amount.nonehas no synthetic VWAP/slippage fields. - For a non-empty fill,
vwap = totalNotional / filledSize, andworstPriceis the final fill price. - Adverse slippage is signed and side-aware:
- buy:
(vwap / referencePrice - 1) * 10000; - sell:
(1 - vwap / referencePrice) * 10000. Price improvement is therefore negative.
- buy:
- Division uses Decimal40/HALF_EVEN and is recorded in
trace.rounding; a notional partial-size quantization recordsdownseparately. - Authority is
local-exact; maturity isstablefor the frozen input only. - A nonzero request returns
MathResult<{ completion: "none" | "partial" | "full"; fills: readonly { px: string; sz: string; notional: string }[]; filledSize: string; filledNotional: string; unfilledAmount: string; vwap?: string; worstPrice?: string; slippageBps?: string }>. Malformed shape/book/amount/reference input returnsinvalid-input. Zero amount returnsnot-applicablewith codezero-fill-amountand the amount value path. The deterministic walk does not returnindeterminate; lack of book depth is represented bynoneorpartialdata. - Trace formula ID is
hl.orderbook.fill.simulatev1. SourceRefs contain this spec, the official L2 schema, andDECIMALJS.10.6.0; assumptions containfrozen-inputfor/levelsandfill-modelbook-vwap; Decimal40 divisions and any final size-down quantization are recorded in rounding.
Trace bound
The result may contain every consumed fill, but trace does not duplicate book levels or fills. It records side counts, request/reference values, aggregate totals, and a frozen-input assumption. This keeps trace allocation bounded independently of future snapshot depth limits.
Oracle boundary
- The official Python SDK provides L2 schema/type evidence only; it does not implement these formulas, so formula oracle state is
not-supported. - Dated mainnet/testnet L2 fixtures provide replay input and schema evidence. They are partial oracle coverage, not server confirmation that a future market order would receive the simulated fills.