Docs
Architecture

The State Model

Everything the exchange knows, committed to a single hash.

The exchange's entire state — every account, every market, every resting order — reduces to one number: a root hash. The settlement contract holds that root, each proof advances it, and anyone can rebuild it from the public blocks and check that they arrive at the same number. This page is the shape of what sits underneath it.

One root

The state root commits to two big trees and a little bookkeeping:

stateRoot = Hash( accountsRoot, marketsRoot, extensionsRoot, lastBlockTimestamp )

accountsRoot is the root of the tree of every account; marketsRoot, the tree of every market; extensionsRoot carries the yield-distribution registry; lastBlockTimestamp is the time the last block closed. Change one order in one market, and the change is felt all the way up through that market's leaf, the markets tree, and into the state root — so the single root is a fingerprint of the whole exchange at that instant.

state root+ extensionsRoot · + lastBlockTimestampaccountsRootmarketsRootdepth 24depth 24 · 50 livean account leafa market leaf· owner address· key slots × 4· collateral — cross-margin· position slots × 8· yield checkpoint· config — ticks, fees, margins· risk state — mark, funding· book root → 40-level tree· open interest, accrued fees
The whole exchange under one hash. Two depth-24 Merkle trees — every account, every market — plus the extensions root and a timestamp fold into the single state root the settlement contract holds. Each account and each market is one leaf, shown expanded; a market's order book is itself a tree (below).

For the curious

Every hash here is Poseidon2 over the Goldilocks field — the same hash the proof system is built on, which is what lets a circuit open and re-fold a path through these trees cheaply. Leaves and empty slots are field-element digests; an empty slot is literally zero.

Accounts

Accounts live in a depth-24 tree — room for about 16.7 million of them — indexed by account number. The first few indices are reserved: index 0 is untargetable — it is the tree's stand-in for an empty account and can never hold funds — index 1 is the insurance fund, index 2 is the protocol fee sink, and real users start at 3.

A single account leaf holds five things:

FieldWhat it is
Owner addressThe STRATO address the account ultimately belongs to. Set when the account is created and paid out to on exit.
Key slotsUp to four trading keys (slots 0–3).
CollateralOne USDλ balance. Margin is cross — this single balance backs every open position.
PositionsUp to eight open positions.
Yield checkpointThe account's place in the yield stream, so USDλ yield accrues without touching every account each round.

There is no account-level nonce and no per-position collateral — one balance, one owner, a handful of keys and positions. That flatness is deliberate: it keeps the leaf small enough for a circuit to open and update in a few hashes.

Trading keys vs. the owner address

An account has four key slots. Slot 0 is the root key, registered when the account is created at deposit; the others are added or rotated with a KeyUpdate. Each slot is an independent signing key with its own nonce stream, and signatures are Schnorr over the ecGFp5 curve.

A trading key is not the owner address. The keys sign orders and withdrawals day to day; the owner address is the account's root of custody — the only place a forced exit will ever pay. You can rotate or lose every trading key and still be the only party that can pull the funds out. That separation is what makes the exit guarantee hold.

Positions

Eight position slots means an account can be open in up to eight markets at once. Each occupied slot records just what the risk engine needs:

  • Which market, and which side — long or short. Size itself is unsigned; the side carries the sign.
  • Size, in that market's size steps.
  • Entry notional — the cumulative quote value the position was opened at. Average entry price is entry notional over size.
  • A funding snapshot — the market's funding accumulator the last time this position was touched.

From these, valuing a position is arithmetic against the market's mark price. Unrealized PnL is the gap between current notional (size × mark) and entry notional, signed by side. Funding is lazy: each market keeps a running sum of funding rates, and a position owes the difference between that sum now and its stored snapshot — so no process has to walk every position every funding hour. Equity is collateral plus PnL plus funding across all eight slots, and the initial- and maintenance-margin requirements are fractions of the total notional. Fall below maintenance and the account becomes liquidatable as a whole.

Markets

Markets live in their own depth-24 tree, indexed by market id; the current testnet runs 50 of them. A market leaf splits into three parts, grouped the way the prover reads them:

  • Config — the fixed parameters: tick and lot sizes, margin rates, fee rates, funding interval and clamp, the caps on order size and open interest.
  • Risk state — the mark price, the funding accumulator, and the last oracle time. This is exactly what the risk engine touches on every match and liquidation, so it is hashed as its own group.
  • Book state — the index price, the premium samples that feed funding, open interest, accrued fees, and the root of the order book.

The order book is a tree

The book is stored so that finding the best price is one short walk, never a scan across every resting order — and here is how. A market's central limit order book is not a list off to the side; it is itself a Merkle tree, one leaf per resting order, whose root sits inside the market leaf.

The trick is in the leaf index. An order's position in the tree is its price followed by its arrival sequence — an ask at 5,010 that arrived third sits at leaf (5,010, 3), while an ask at 5,008 that arrived later still sorts ahead of it, because price comes first. So the tree is sorted by price–time priority by construction: the best ask is the leftmost live leaf on the sell side, the best bid the rightmost on the buy side. And every interior node carries running totals — separately for each side — of the size and the notional beneath it. A node is not just a hash of its children; it is a hash of its children plus the sum of everything under it.

book rootΣ 18Σ 7Σ 115 @ 1002 @ 1018 @ 1033 @ 104best askeach node = its subtree's totallower pricehigher price →
The sell side of one market, shown four orders wide. Leaves are individual orders, placed so that position encodes price then arrival order; each interior node also stores the total size (and notional) beneath it, so Σ at the root is the whole side's depth. The real tree is 40 levels deep — 16 bits of price, 24 of sequence — and holds both sides at once.

Those running totals are what make a match cheap to prove. To fill an incoming order the prover does not scan the book — it walks from the root to the best price, and the totals along the way tell it exactly how much size sits at or better than any level. Inserting, reducing, or cancelling an order rewrites a single root-to-leaf path and re-folds the sums above it. The whole book — best price, depth, open interest — is legible from one path, which is precisely why a Match costs a handful of bytes and a small circuit rather than a walk over thousands of orders.

What gets published

None of this tree lives only in the sequencer's memory. Every block publishes a compact record for each transaction — only the fields that transaction actually uses, down to a few bytes for a match — and the whole payload commits to STRATO under one hash. That is the data-availability guarantee: the records are complete and public, so any follower can replay them, rebuild every tree on this page, and confirm the state root it computes is the one the proof settled. The state is never something you have to take the operator's word for.

On this page