> ## 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.26

# Monaco Protocol SDK v1.0.26

This release introduces one-way futures order semantics, faucet quota introspection, a mandatory market-order price band, and a hardened WebSocket reconnect contract. It rolls up the consumer-facing changes since v1.0.24 — v1.0.25 was a backend-only deploy — and adds new SDK surface plus observable behavior changes on every client (TypeScript, Rust REST, and Rust gRPC), so upgrading is recommended and there are a few action items worth reviewing before you deploy.

## Added

### Faucet quota introspection

New `sdk.faucet.getInfo()` (`GET /api/v1/faucet/info`, session-authenticated) returns the authenticated wallet's faucet quota and recent history: `remainingRequests24h`, `dailyLimit`, an optional `nextAvailableAt` (ISO 8601 — when the wallet's next faucet slot frees under the current daily limit; omitted, never null, when the rolling 24h window is empty or the limit is 0), and up to five `recentRequests` newest-first. Quota is wallet-scoped across apps and uses the same rolling-window accounting as `mint()` enforcement. Call it before `request_faucet`/`mint()` to show remaining quota instead of provoking a `429`. A matching `get_faucet_info` MCP tool ships for agents (non-mainnet networks only).

### Position TP/SL: full-close legs and OCO

`sdk.positions.attachPositionTpSl` (`POST /api/v1/positions/{positionId}/tp-sl`) adds a per-leg `closePosition` flag that resolves the full live position size when the leg triggers (omit `quantity` when `closePosition: true`), and a request-level `oco` flag that cancels the sibling leg after one triggers (`oco: true` requires both a take-profit and a stop-loss leg).

### Order cancellation cause

Order responses and WebSocket order events now expose a nullable, stable `terminalReason` when an order is cancelled: `USER_REQUESTED`, `REPLACED`, `LIQUIDATION`, `INSUFFICIENT_MARGIN`, `REDUCE_ONLY_EXHAUSTED`, `POSITION_CLOSED`, `OCO_SIBLING_TRIGGERED`, or `SYSTEM`.

### Perp risk tiers: base-quantity position cap

Perp risk tiers add `maxPositionSize`, the authoritative maximum absolute base-asset quantity for the tier. `maxPositionNotional` remains as a deprecated compatibility alias (it always carried a base quantity, not a notional) — read `maxPositionSize`.

### SDK configuration and WebSocket options

* `createMonacoSDK` accepts an optional `pollingInterval` (milliseconds) that tunes the internal viem public client's transaction-receipt poll frequency. Must be a positive finite number, otherwise `createMonacoSDK` throws `InvalidConfigError`.
* `createMonacoWebSocket(baseUrl, options)` accepts `maxReconnectAttempts`, `reconnectBaseDelayMs`, and `connectionTimeoutMs`, plus a new `onResync` callback (see Changed).

## Changed

### One-way futures order semantics

Authenticated order creation and margin risk simulation now use one-way futures semantics:

* **`side` is the authoritative direction.** `positionSide` is optional and deprecated; when supplied it must agree with `side` (`BUY`↔`LONG`, `SELL`↔`SHORT`).
* **Leverage is required for normal margin orders** and optional for reduce-only orders.
* **Entry-attached TP/SL is rejected.** Passing `takeProfit`/`stopLoss` on `placeLimitOrder`/`placeMarketOrder` now returns `400` — create position TP/SL with `attachPositionTpSl` after the position opens.

### Market-order price protection

Market orders now execute inside a mandatory server-side protective price band of 500 bps around a robust reference price (the mark price, or the median of best bid, best ask, and last trade). Fills beyond the band are cut off: the portion that fills inside the band settles and any remainder is cancelled; if nothing can fill inside the band the order is rejected as insufficient liquidity; and a market order on a market with no usable reference price is rejected as unavailable. A client `slippageToleranceBps` can only *tighten* the band, never widen it. The order-risk simulation endpoints reflect the same band and can return the same rejections. No wire types changed.

### WebSocket reconnect contract

Auto-reconnect now retries indefinitely by default with full-jitter exponential backoff capped at 30s (previously it gave up after 5 attempts) — pass `maxReconnectAttempts` to restore a finite cap. `onStatusChange` now also reports `"reconnecting"` while backing off, the client answers a server-initiated `{"type":"Ping"}` with a `Pong`, and a new `onResync` callback fires after every automatic reconnect once the connection is re-authenticated and re-subscribed. `onResync` receives `slowClient: true` when the server shed the connection with close code `1013`, so apps can refetch REST snapshots and reconcile by `(id, updatedAt)`.

<Warning>
  **Correction since this release.** The original wording is left in place above; the correction is:

  * *"reconcile by `(id, updatedAt)`"* — for orders that key cannot converge. Order detail reports `updatedAt` from the matching engine's event clock while order lists report it from the database commit clock, so the two endpoints report different values for the same order, and the commit clock can move without any state change. Orders now carry an opaque, compare-only `version` on the REST responses, on every order WebSocket event, and on the `orders` snapshot frame: reconcile on `(id, version)`, taking a snapshot row when `snapshot.version >= local.version`, and falling back to a full field comparison when it is absent (an order last written before the field existed). See [Order state versions](/developers/trade#order-state-versions).
</Warning>

### Faster transaction-receipt polling

The SDK's internal viem public client now polls for receipts every 750ms by default (previously viem's 4000ms), so `sdk.vault.deposit` and `sdk.waitForTransaction` resolve within about one to two Sei blocks. Set `pollingInterval: 4000` to restore the previous cadence.

### Faucet daily-limit counting

The faucet daily limit now counts every mint call in the rolling 24h window rather than distinct clock minutes, closing a bypass where multiple calls in the same minute consumed a single quota slot. `getInfo()`'s `remainingRequests24h` and `nextAvailableAt` reflect the same per-call counting; the minute truncation on `recentRequests[].requestedAt` is display grouping only.

### Development WebSocket ingress

The `development` network preset now connects WebSockets to `wss://ws-develop.apimonaco.xyz/ws`. The previous `wss://develop.apimonaco.xyz/ws` path remains supported during the migration window, so older SDK versions and custom `wsUrl` overrides keep working unchanged.

## Fixed

### Batch-replace taker fees attributed to the owning account

The PnL service now attributes the taker fee on a batch-replace fill to its owning margin account. A batch replace produces multiple result orders and carries no top-level taker order, so those taker fees were previously dropped — understating persisted per-account fee totals, most visibly for market-making accounts that reprice via batch replace. This corrects the cumulative `fees`, `realizedPnl`, and `totalPnl` behind `getPortfolioChart` for data recorded after this change.

## Security

* **Session public-key reuse returns `409`.** Re-running verify or creating a delegated-agent session with an already-registered session public key now returns `409 Conflict` ("resource already exists") / gRPC `already_exists`, instead of a `500` that leaked the Postgres detail and unique-constraint name. Generate a fresh session keypair per session.
* **Hardened error envelopes.** Other database failures return a generic `500` "Database error" and a malformed JSON body returns `400` "Invalid JSON payload" — none echo engine detail, constraint names, query text, or the raw parser message. Successful requests are unchanged.
* **Withdrawal-index validation.** Public `GET /api/v1/withdrawals/{withdrawal_index}` now rejects a negative or non-integer index with `400 Bad Request` instead of forwarding it to a lookup that returned a misleading `404`. Valid non-negative lookups are unchanged — `404` still means the index was never allocated.

## Upgrade

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

Action items to review:

1. **Move entry-attached TP/SL to `attachPositionTpSl`.** Any `placeLimitOrder`/`placeMarketOrder` call that passes `takeProfit`/`stopLoss` now returns `400`. Open the position first, then attach TP/SL — optionally with the new `closePosition` and `oco` flags.
2. **Drop `positionSide`; supply `leverage`.** Rely on `side` for direction, and pass `leverage` on normal margin orders (omit it only for reduce-only orders).
3. **Handle new market-order outcomes.** A market order can now come back partially filled with the remainder cancelled, or be rejected as insufficient liquidity or market unavailable. `slippageToleranceBps` only tightens the 500 bps band.
4. **Generate a fresh session keypair per session** to avoid the new `409` on reuse.
5. **Reconsider WebSocket reconnect handling.** Auto-reconnect now retries indefinitely by default — set `maxReconnectAttempts` for a finite cap, and use `onResync` to refetch snapshots and reconcile after a reconnect.


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