> ## Documentation Index
> Fetch the complete documentation index at: https://docs.0xmonaco.com/llms.txt
> Use this file to discover all available pages before exploring further.

# V1.0.51

# Monaco Protocol SDK v1.0.51

This release covers the consumer-facing changes since v1.0.50. Three migrations come first: stop scaling WebSocket fill `fee` values yourself, update order-event field and null checks, and give switches over WebSocket value fields a `default` branch. Orders gain a shared reconciliation `version`, connection-scoped WebSocket errors reach an `onError` callback, and React order state handles unfamiliar values and REST repair more reliably. Timestamp formatting, portfolio valuation, subscription snapshots, liquidation cleanup, and fee refresh also receive corrections; `batchCancelAll` now refuses requests above 20,000 active orders without cancelling any.

## Breaking

### Fill `fee` is a decimal quote-asset amount

On `OrderFilled`, `OrderPartiallyFilled`, and `OrderMatched`, `fee` now reports the normalized decimal quote-asset amount: `"0.004178"` USDC instead of the old raw `"4178"` at six quote decimals. **Stop dividing `fee` by `10^quoteDecimals`.** The new `feeRaw` (wire `fee_raw`) carries the integer raw quote-unit value if your accounting works in raw units; negative values mean a maker rebate.

Two existing properties still matter. This is the **Monaco fee component only**, excluding the application taker fee, so it need not equal the order's `totalTakerFees`. A taker event aggregates the fees of every trade it covers; a maker event covers one trade. `feeRaw` is required on `OrderMatched` and optional in the published `OrderFilled` and `OrderPartiallyFilled` types. See [Order Events](/sdk/typescript/websockets#order-event-types).

### Order-event types now distinguish absent fields from null values

`takerOrderId` and `makerOrderId` are removed from the three fill-event types: neither existed on the wire. Use `orderId` for the event's own order and `tradeId` for its trade reference. `totalFilled` is also removed from those fill types; use `filledQuantity` for the cumulative order fill and `lastFillQuantity` for this event's increment. `totalFilled` remains on cancellation and rejection payloads, where the server sends it.

`OrderMatched` gains its missing execution fields and now describes the taker payload exactly. Update fixtures and consumers to distinguish these groups:

* **Required:** `role`, `status`, `tradesCount`, `filledQuantity`, `filledQuantityRaw`, `remainingQuantity`, `remainingQuantityRaw`, `fee`, and `feeRaw`.
* **Always present, nullable:** `tradeId`, `executionPrice`, `executedAt`, `averageFillPrice`, `referencePrice`, `bestPrice`, `worstPrice`, `actualSlippageBps`, and `maxSlippageBps`. The trade fields are null when no trade is covered; price and slippage fields are null when unavailable.
* **Optional incremental-fill fields:** `lastFillQuantity` and `lastFillQuantityRaw`, omitted when the event carries no incremental fill.

`OrderExpired` likewise makes `filledQuantity`, `filledQuantityRaw`, `remainingQuantity`, `remainingQuantityRaw`, and `averageFillPrice` required `string | null`: the keys are always present. Branch on null rather than assuming an absent key. `OrderFilled` and `OrderPartiallyFilled` still cover both maker and taker payloads, so their execution fields are not tightened to the taker-only shape. See [WebSockets](/sdk/typescript/websockets#order-event-types) for the individual payloads.

### WebSocket value fields accept unfamiliar server strings

Many event value fields widen from a closed alias to `KnownAlias | (string & {})`, matching the parser's delivery of unknown values. This affects order values (including status, role, terminal reason, side, type, time in force, and trading mode), conditional-order values, position side/status, market status, TWAP values, instrument change kinds, OHLCV interval/mode/price type, orderbook mode/side, trade mode/maker side, and balance reasons.

The finite aliases remain exported for autocomplete, narrowing, REST filters, and validation. Add a `default` branch or an explicit narrowing check before assigning a received value to a closed model type. The broad `OrderEvent.eventType` also widens, but **named variants keep their closed `eventType` discriminants** — narrowing `OrderPlacedEvent` and its siblings still works.

## Added

### Connection-scoped WebSocket errors reach `onError`

The `ws` configuration accepts `onError({ code, message })`, also available on `createMonacoWebSocket` options. `@0xmonaco/types` exports `WebSocketErrorCode`, `WebSocketErrorInfo`, and `ErrorHandler`. Server `Error` frames belong to the connection and match no channel subscription; previously they reached no consumer handler.

Known codes are `AUTH_REQUIRED`, `AUTH_FAILED`, `CONNECTION_LIMIT`, `SUBSCRIPTION_LIMIT`, `INVALID_SUBSCRIPTION`, `INVALID_MESSAGE`, `SESSION_INVALID`, and `SNAPSHOT_UNAVAILABLE`. Recovery depends on the code:

* `AUTH_REQUIRED` means the server rejected the subscription. Authenticate, release the last local handler for that channel, then subscribe again; authentication alone leaves the locally registered subscription inactive on the server.
* `SESSION_INVALID` requires re-authentication.
* `SNAPSHOT_UNAVAILABLE` leaves the subscription active and live diffs flowing, but without its baseline. Fetch a REST baseline and reconcile it with live state.

Unknown codes are delivered unchanged, so keep a default case. See [Server Error Frames](/sdk/typescript/websockets#server-error-frames).

### A shared `version` for order reconciliation

Order detail and list reads (`GetOrder` / `ListOrders`, including `sdk.trading.getOrder()` / `getPaginatedOrders()`), every order WebSocket event, and the `orders` subscription snapshot now carry an optional `version`. It is an opaque comparator for states of **the same order**: a higher value is newer, gaps are normal, and values from different orders are not comparable.

On reconnect, keep applying live order events and accept a REST snapshot row when `snapshot.version >= local.version`. **Use `>=`, not `>`**: one sequencer step can emit placement and fill events with the same version, while the REST row represents that step's final state and wins the tie. An absent version means unknown, never zero; fall back to buffering and replaying events across the fetch for those rows.

The resting snapshot cannot recover orders that stopped resting during the disconnect. Page the execution-time-ordered `sdk.profile.getUserTrades` back through the gap for fills, and use targeted `sdk.trading.getOrder` reads for locally resting orders missing from the snapshot to resolve cancellations and expiries. Ordering the order list by creation time cannot substitute for the trade tape. See the [Market-Maker Runbook](/developers/market-maker-runbook#4-reconnect-and-resync).

### Conditional-order versions on REST and subscription snapshots

Conditional-order REST reads and the `conditional_orders` subscription snapshot gain the same kind of optional, opaque `version`. Compare versioned snapshots for the same conditional order with `snapshot.version >= local.version`; absent means unknown, gaps are normal, and comparison across conditional orders or against ordinary orders is invalid.

**Live conditional-order events deliberately omit `version`.** Apply them as state updates without version ranking. The subscription snapshot reads from the database, so a transition during that read can fall into a database-lag gap; re-read affected rows when their state matters at reconnect. See [Conditional Orders Channel](/sdk/typescript/websockets#conditional-orders-channel).

### Post-only state and missing raw execution fields

Order events expose `postOnly?: boolean` on placement, taker payloads, partial cancellation, cancellation, and expiry. A carrying variant sends `true` or omits the key; maker fills and rejections never carry it. An admitted post-only order rests and fills as a maker, so **retain the order-level flag from placement or REST** — absence on a maker fill does not mean false. `useUserOrders` now carries this state onto its order rows and preserves it through updates.

`OrderRejected` declares `totalFilledRaw` and `remainingQuantityRaw`; `OrderExpired` declares `filledQuantityRaw` and `remainingQuantityRaw`. These previously invisible fields carry integer base-unit precision alongside their decimal counterparts. The missing `OrderMatched` execution fields are covered by the exact-shape migration above.

## Changed

### Selected persisted order timestamps use fixed UTC microseconds

REST read models now render ordinary-order `createdAt`, `updatedAt`, and `expirationDate`; every conditional-order timestamp; persisted TWAP window and lifecycle timestamps; and application order-view `createdAt` / `updatedAt` with exactly six fractional digits and a `Z` suffix, for example `2026-09-05T01:23:45.123456Z`. This replaces variable fractional widths and `+00:00` on those fields. RFC 3339 parsers keep working; exact-string fixtures may need updates.

Ordinary-order lifecycle stamps — `cancelledAt`, `filledAt`, `expiredAt`, `submittedAt`, and `acknowledgedAt` — retain chrono's variable fractional width, although they use a `Z` suffix. The guarantee also does not extend to `CreateTwapOrderResponse.firstSliceAt` or `.endTime`, which retain their separate rendering.

Formatting does not align the clocks behind order detail and list `updatedAt` values. Use `version` for reconciliation rather than comparing those timestamps.

### `batchCancelAll` refuses more than 20,000 active orders

`sdk.trading.batchCancelAll` now caps a request at **20,000 active orders**. Above the cap it cancels nothing and returns REST `400` / gRPC `InvalidArgument`. Treat this as a rejected operation, not a partial cancellation. See [Trading](/developers/trade#batch-cancel) for the request's filtering options.

## Fixed

### WebSocket parsers retain fields and unfamiliar values

The movements parser now delivers `symbol`, `balanceBeforeRaw`, `balanceAfterRaw`, `lockedBeforeRaw`, and `lockedAfterRaw`, which were declared but discarded while building callbacks. TWAP updates with an unfamiliar `state` and instrument updates with an unfamiliar `change` no longer lose the whole frame. OHLCV preserves an unfamiliar `priceType` instead of blanking the field, so wildcard subscriptions can distinguish newly introduced series.

### `useUserOrders` narrows values and merges REST repair with live state

The hook no longer inserts an unknown status into the closed `Order` model: it uses the status implied by the event type or retains the previous status when no status is implied. Placements remain `SUBMITTED`. A placement with an unknown `orderType`, `side`, or `tradingMode` cannot honestly form an order row, so the hook declines it and schedules a coalesced REST repair; an unknown optional `timeInForce` remains absent.

Refresh and repair responses merge with live state instead of replacing updates that arrived while REST was in flight. The released hook still reconciles using `updatedAt`; the new order `version` contract above is available to consumers implementing their own reconciliation. See [`useUserOrders`](/sdk/react/hooks/use-user-orders).

### Portfolio performance can return partial withdrawal valuation

An external withdrawal without a usable historical price no longer fails the entire portfolio-performance response solely for that missing valuation. The unpriceable movement is omitted from withdrawal totals and the deposit totals that depend on them, and a successful response reports `valuationStatus: "partial"`. Recognized quote assets retain unit pricing; reconciliation errors can still fail the request. See [Portfolio](/sdk/typescript/portfolio).

### Subscription snapshots, liquidation cleanup, and fee refresh

Order, conditional-order, and position subscription snapshots now use stable keyset paging, preventing concurrent updates from shifting page boundaries and duplicating or skipping rows. This improves paging consistency; it does not eliminate the conditional-order database-lag gap described above.

When a liquidation maker fill closes a position, its remaining reduce-only orders are now cancelled with `POSITION_CLOSED`, releasing their reserves while preserving order history and PnL enrichment.

Fee-schedule refresh uses bounded timeouts and a consistent repeatable-read snapshot, retains the last known good schedule on failure, and retries. Transient refresh trouble no longer freezes the refresh loop or mixes fee tiers from different reads.

## Upgrade

```bash theme={null}
npm install @0xmonaco/core@1.0.51 @0xmonaco/types@1.0.51 @0xmonaco/react@1.0.51 @0xmonaco/contracts@1.0.51
# or bun
bun add @0xmonaco/core@1.0.51 @0xmonaco/types@1.0.51 @0xmonaco/react@1.0.51 @0xmonaco/contracts@1.0.51
```

Before upgrading, remove manual scaling of fill `fee`, migrate the removed and nullable order-event fields, and narrow unfamiliar WebSocket values before assigning them to closed models. Register `onError` so rejected subscriptions and missing baselines become visible, and use same-order `version` comparisons plus gap recovery when implementing reconnect reconciliation.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.