This week on Nexus 08.21.26
Market parameters get one apply seam in the engine, an event vocabulary, and a write-ahead-log format to carry a change. A fill reports its fee per leg and can say it stated none, fee PnL is scoped to the open position and counted into the total, every identity mutation writes to an append-only audit log, and positions, PnL and account figures can be answered on behalf of a user. Funding stops accruing against a stale oracle, state snapshots declare their format and fail closed when it does not match, and withdrawals are enabled on testnet.
Market parameters and configuration
- Market parameters have one apply seam in the engine. A parameter change enters execution through a single seam,
MarketParamsUpdatedgives it an event vocabulary and a write-ahead-log wire format, andMarketView::with_params()produces a new view rather than mutating one in place — so a change takes effect in one place, is recorded like any other state change, and cannot alter a view already in use. - Seven calendared markets are configured as globex, not continuous. The seven markets that trade on a calendar carry the globex schedule, so their sessions follow the calendar they actually trade on.
- A deposed feed clears its market-open flag.
oracle_feed_market_openis cleared when a feed is deposed, so a feed that is no longer serving cannot leave a market reading as open.
Trading
- Impact price is walked on notional. The order-book walk that produces an impact price is driven by notional size, so the price returned is the one an order of that notional walks to rather than one read off a fixed depth.
- A fill carries its fee, per leg, and can say it stated none.
EngineEvent::Fillemits the fee charged per leg,WireEvent::Fillcarries those legs as optional amounts, andGET /fillsdistinguishes a fill that stated no fee from one whose fee was zero — so the fee arrives with the fill, and an absent fee reads as absent rather than as a number. /leverageis gated as a per-account route. The proxy treats/leverageas per-account rather than as a general route, so a request to it is gated on the account it names.
Risk, funding and PnL
- Funding accrual and settlement stop on a stale oracle. Both are gated on oracle staleness, so funding is not accrued or settled against a price that has stopped updating.
- Settled funding windows are retained, with a route to read them. Risk-margin keeps settled funding windows in a ring and exposes an admin route over it, so a window can be read back after it settles.
- Missed funding windows can be backfilled. An admin route backfills funding windows the indexer missed, so a gap in the funding history can be filled rather than left standing.
- A latch-suppressed cross-portfolio breach is re-scanned. Risk re-scans a cross-portfolio breach that a latch suppressed, so the breach cannot stay hidden behind the latch that first swallowed it.
- A mutating reply waits for its log record. Risk-margin holds the reply to a mutating call until that call’s write-ahead-log record is durable, so a caller is not told a mutation succeeded before it is recoverable.
- Deposit dedup runs through the risk actor. Deduplication of deposits is serialized through the risk actor instead of running beside it, so two arrivals of the same deposit cannot both be admitted.
- Fee PnL is answered per position, scoped to the open one, and counted into the total. The indexer reports
fee_pnlper position and folds it intototal_pnl, counting the open position’s fees rather than those held in the retained ring — so the total accounts for fees, and a closed position’s fees do not follow the one that replaced it.
Accounts, credentials and on-behalf-of requests
- There is an append-only audit log, and every identity mutation writes to it. The account layer defines an append-only
audit_logtrait with a Postgres implementation, and the indexer callsaudit_log.record()at all seven identity-mutation call sites — so an identity change is recorded where it cannot be edited afterwards, and none goes unrecorded. - Agent nonce enforcement is scoped to mutating methods. Nonces are enforced on the methods that change state and not on the ones that only read, so a read does not consume a nonce.
- A 429 names the bucket that refused it. A rate-limited response identifies the bucket the request exceeded, so a client can tell which limit it hit.
rate_per_secwidens toBIGINT. The column is widened, so a rate above the old column’s range can be stored rather than refused.- A request can carry an on-behalf-of-user envelope, and the views come back composed. A shared envelope names the user a request is made for, and composed on-behalf views are served for positions plus PnL and for account figures — so the calling party and the subject are distinct on the wire, and those figures arrive assembled rather than stitched together by the caller.
State and recovery
- Snapshots declare a format, boot fails closed, and recovery still finds an epoch. A state snapshot carries a format header written by the snapshot writer itself and the service refuses to boot when the header does not match; when the envelope omits the checkpoint epoch, the indexer falls back to the epoch stored in the snapshot. An unreadable snapshot stops startup instead of being half-read, and recovery has an epoch to resume from either way.
- The websocket token store is shared across replicas. Replicas read the same token store, so a token issued by one is honoured by another and a reconnect does not land on a replica that has never heard of your session.
Bridge and deposits
- Withdrawals are enabled on testnet. The withdrawal path is turned on there, so it can be exercised end to end outside a developer environment.
- An unmatched release self-heals on testnet. On testnet only, the bridge auto-refunds to clear the pause an unmatched release causes, so the pause resolves without an operator step.
The API and its clients
- 100 operations under one published spec. The spec now published from this repository describes 100 HTTP operations.
POST /leverageis documented. The spec describes the operation, so setting leverage is documented alongside the rest of the API.- Four official clients, counted against one spec. Rust, Python, TypeScript, and the CLI are the official clients, counted against the same pinned 0.9.8 API spec.
- The Rust client wraps funding samples.
GET /markets/{market_id}/funding-sampleshas a client method, so funding samples are reachable without a hand-rolled request.
Interface
- The chart interval ladder widens into a grouped popover. The trading chart offers a wider set of intervals and groups them in a popover, so more intervals are selectable from one control.
Sandboxes and simulation
- The simulation gets an Observer. An Observer component and its image land, the market-data wire is mounted where the Observer can reach it, and balance events are published on that wire behind an opt-in.
- The driver owns the bots’ tick order. Taking ownership of tick order un-parks seven gates that had been skipped, and the risk actor gains a real barrier at the step boundary.
- Two dead paths in the market maker are repaired. A reprice threshold could never be reached because
move_bpsalways parsed to zero, and a cancel never fired because it readorder_idfrom a response that spells itid.
Behind the scenes
Work landed on how changes roll out. On the website, machine-readable summaries are served at the apex, two icon-rotation disclosures declare their expanded state, the footer and partner-logo strip use the real Nexus mark, and the Halliday terms link points at the real document. Plumbing, mostly — the kind that decides whether the next change is safe to make.