This week on Nexus 08.31.26
Open interest is published as a public contract with long and short reported separately, an order-book level that cannot be parsed is dropped rather than served at zero, and cancels draw from their own rate-limit bucket. An isolated-margin change is durable before it is acknowledged, a takeover is declined when a leg has no live mark, and the collateral total rebuilt at boot is compared against the last one published. Sealed event-log segments stream to object storage while local copies are pruned, boot streams the logs instead of materialising them, and a corrupt acknowledged tail is quarantined as loss. A market listing calls risk before the engine and fails closed, max_open_interest_notional and price_band_bps are published in the spec, and the Python and TypeScript clients close most of the gap to the operations that spec describes. Here is what shipped.
Trading and orders
- The per-account position is bounded at submit. The engine checks a submitted order against a per-account position bound before it reaches the book, so an account cannot be carried past that bound by an order that has already been accepted.
- Cancels draw from their own rate-limit bucket. The indexer meters cancellations in a bucket of their own, so a burst of cancels no longer spends the allowance an order placement needs.
- Liquidations are exempt from
max_order_size. The order book exempts a liquidation from the per-order size cap, so a position larger thanmax_order_sizecan be closed in a single order rather than in pieces. - Price precision comes from the venue’s tick, not a table. Shared client code derives a market’s price precision from the tick size the venue publishes instead of a hard-coded table, so precision follows the market’s own contract as that contract changes.
Risk, funding and collateral
- A bankrupt account’s funding integral is carried, not dropped. Risk-margin keeps the funding integral of an account that goes bankrupt instead of discarding it, so what that account owed or was owed in funding stays accounted for.
- A takeover is declined when a leg has no live mark. The engine refuses to take over a position while one of its legs has no live mark price, so a takeover is never priced off a mark that is missing.
- Isolated add- and remove-margin are durable before they are acknowledged. An isolated-margin adjustment is written to the write-ahead log and gated on that write, so the change is recorded before the caller is told it happened.
- Collateral rebuilt at boot is published, and compared against the last figure published. Risk publishes the collateral total it reconstructs during boot recovery and the indexer compares it against the previous published figure, so a recovery that disagrees with the state before it is visible rather than silent.
Markets, listings and parameters
- A listing calls risk before the engine, and fails closed. A market listing is applied in a fixed order — risk first, then the engine — and stops on the first failure, so a market cannot come up in the engine without the risk side that governs it.
- A market-parameter update has an admin endpoint, and carries an interim actor. The admin market-parameter update endpoint is wired through the API module and
MarketParamsUpdatednow carries an interim actor field, ahead of full principal resolution, so a parameter change arrives over a route and the event carries a first record of who made it. max_open_interest_notionalandprice_band_bpsare published in the spec. Both market parameters are described in the published API spec, so a client can read the open-interest ceiling and the price band a market enforces instead of inferring them from rejections.- Resume restores the lifecycle state a market held before it halted. When the engine resumes, it restores each market’s pre-halt lifecycle state, so a resume returns markets to where they were rather than to a default.
Admin access and grants
- Admin routes resolve a principal and record the grant verdict. An admin route resolves the calling principal, decides the grant through a witness the handler cannot forge, and records the verdict it reached;
/adminreads carry the operator bearer token.
State, recovery and the write-ahead log
- The journal, the grant table and ledger postings each get an owner that is captured and replayed. Each of those state families now has a single owner that can be captured into a snapshot and replayed from the log, with the grant table taking the fourth write-ahead-log arm and ledger postings the fifth.
- Sealed event-log segments stream to object storage, and the local copy is pruned. A sealed segment of the event write-ahead log is streamed off the box to object storage and the local copy is pruned once it is safe to drop, so the log stops growing without bound on disk.
- The event-log cursor is replayed when the indexer reconnects. Exchange-state replays from the cursor an indexer last acknowledged when that indexer reconnects, so a reconnect resumes where it left off instead of starting over.
- A corrupt acknowledged tail is treated as loss and quarantined. When the tail of the log is corrupt at a point already acknowledged, it is treated as data loss and quarantined rather than read through, so the damage is contained and declared instead of being carried forward.
- Boot streams the logs instead of materialising them. Neither the event log nor the deposit log is read into memory whole at boot; both are streamed and bounded, so start-up memory no longer scales with the length of the log.
The ledger
- Postings are balanced, and checked against the tape. A ledger-engine crate keeps double-entry postings that must balance and enforces the entry and posting invariants against the tape, so an unbalanced entry is refused where it is written rather than found later.
Market data and the interface
- Open interest is a public contract, with long and short reported separately. The indexer publishes open interest as a documented surface and reports the long and short sides as separate figures rather than one net number.
- A ticker channel feeds
watchTicker. The indexer serves a ticker WebSocket channel, so a client callingwatchTickerhas a feed behind it instead of polling for the same figures. - The indexer stops publishing figures it cannot stand behind. An order-book level that cannot be parsed is dropped rather than served as a zero, and an unbounded
/candlesrequest no longer returns seed bars. - CCXT compatibility is paged correctly, counted against a denominator, and labelled declared.
fetchOHLCVpages forward from the requestedstartTimerather than backward from now, operation and CCXT-Pro channel coverage is measured against a denominator and gated on a recorded decision instead of a percentage, and the badge in the interface says support is declared, not tested. - Preferences and a disclosure acknowledgement are stored on a user’s behalf. The BFF keeps a preferences store and records that a user acknowledged the disclosure banner, both on behalf of that user, so the choice survives the session that made it.
Accounts and credentials
- Credential verification, sessions and agent records answer over HTTP. The credential verifier, the session authority and the agent store are reached over HTTP routes rather than in process, so the accounts layer is a service the rest of the Exchange calls instead of a library it links.
Price feeds
- ETH-USDX-PERP takes its price from Pyth Hermes. The oracle reads the ETH-USDX-PERP feed from Pyth Hermes, so the mark for that market is derived from an oracle network’s price rather than from the venue it previously followed.
Bridge and deposits
depositTotakes a beneficiary. TheNexusVaultcontract accepts a deposit made on behalf of a named beneficiary, so the account credited need not be the address that sent the funds.- Bridge deposit and withdrawal counters are durable, and tell the two apart. Risk holds its bridge deposit and withdrawal counters durably and discriminates between the two directions, so the counts survive a restart and neither direction is read as the other.
The API contract
POST /orders/batchreturns the 201 it documents. The batch order endpoint answers with the documented 201, and the versioned orders alias documents the same contract as the route it mirrors, so the two agree with each other and with the spec.
Client SDKs
- The Python client covers 66 of the spec’s 68 operations. The remaining 15 operations are implemented, taking the client from 51 to 66 of the 68 operations in its pinned spec, and
base_urlanddirect_base_urlare exposed in place of a bare environment variable. - The TypeScript client implements 11 more spec operations. Eleven operations the client did not cover are implemented, and it can read an account’s funding payments.
- The Rust client surfaces
stp,max_slippage_bpsandcancellation_reason. The three fields are exposed on the client’s types, and the durable mainnet base points at the host root rather than/v1. - The MCP server maps the three bridge wallet-registration routes. Those routes are exposed as MCP tools, and the gateway stops advertising a hosted MCP server as available.
Sandboxes, simulation and the build
Most of the plumbing this window went into the sandboxes and the simulation fleet: a fixture YAML becomes an ExchangeSnapshot the engine boots from, order sizes are derived from each market’s contract so 32 of 32 markets are runnable where 7 were before, a stepped run keeps its history over the Observer’s control-plane wire, a run names the environment it happened inside, and a per-release lane runs the maker against every published image. The Observer logs a cap refusal and declares a null position, the simulated oracle feeder aligns to the market’s own tick rather than BTC’s, and the bots read an absent replica count as zero.
Elsewhere in the engine’s own plumbing: the indexer builds from its own cargo workspace and an engine-free image, service images build from a shared dependency layer, state files are fsynced on the paths that write them, older snapshots still decode against the current fields, order-to-ack latency is banded with its SLO encoded alongside it, a halted market raises an alert, and risk’s pre-trade rejections are counted in exchange_order_rejections.
Behind the scenes
Alongside all of that, work landed on how access and secrets are controlled, and on how changes are rolled out.