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

# Monaco Protocol SDK v1.0.43

This release adds server-side TWAP parent orders that slice a large order across a time window; in-place partial cancel that shrinks a resting order without losing its queue position; a mark-price candle series on the OHLCV WebSocket channel; a `wrappedNative` balance flag that changes how the vault client deposits the chain's wrapped-native asset; and four spot cost-basis fields on portfolio assets. It also makes a full-close take-profit / stop-loss supersede the position's previous full-close leg of the same type in one atomic step, and fixes the `marginRatio` reported for accounts at zero or negative equity. Two things to act on: if you deposit the wrapped-native asset (e.g. WSEI) it now goes in as native coin with no ERC20 approval — see the vault change below; and `marginRatio` can now come back as a very large sentinel, so clamp it for display.

## Added

### TWAP parent orders

Submit a single **TWAP parent order** and the matching engine slices it into a schedule of market child orders across an execution window, averaging price over time instead of paying market impact in one print. Four authenticated methods on `sdk.trading` (`createTwapOrder(tradingPairId, side, quantity, options)` — `POST /api/v1/orders/twap`, gRPC `OrdersService.CreateTwapOrder`; `getTwapOrder(twapOrderId)` — `GET /api/v1/orders/twap/{twapOrderId}`, gRPC `GetTwapOrder`; `listTwapOrders(params?)` — `GET /api/v1/orders/twap`, gRPC `ListTwapOrders`; `cancelTwapOrder(twapOrderId)` — `POST /api/v1/orders/twap/{twapOrderId}/cancel`, gRPC `CancelTwapOrder`).

The window is exactly one of `durationSeconds` (default bounds 60 s – 30 days) or an `endTime` (RFC 3339 UTC with a `Z` suffix — non-UTC offsets are rejected — optionally with a `startTime`); other options cover `limitPrice`, `slippageToleranceBps` (default 100), `randomize` (default true; seeded ±30% size / ±30% timing jitter), `reduceOnly`, the usual margin context (`tradingMode`, `marginAccountId`, `riskBucketId`, `marginMode`, `leverage`), and a `clientTwapId` (≤36 chars, unique per user + application — a duplicate is rejected with `409`). Both spot and margin markets are supported; delegated-agent sessions are rejected. Live progress streams on the new authenticated `twap_orders` WebSocket channel via `sdk.ws.twapOrders(handler, tradingPairId?)`, delivering a `TwapOrderEvent` with the full parent state on every lifecycle transition. `@0xmonaco/types` adds the full type set (`TwapOrderState`, `CreateTwapOrderOptions`, `CreateTwapOrderResponse`, `CancelTwapOrderResponse`, `TwapOrder`, `ListTwapOrdersParams` / `ListTwapOrdersResponse`, `TwapOrderEvent`) with Zod validation of the window and margin constraints. See [TWAP Orders](/trading-mechanics/twap-orders) for the execution model.

### In-place partial cancel

`sdk.trading.cancelOrder(orderId, { remainingQuantityTarget })` (`POST /api/v1/orders/cancel` `CancelOrderRequest.remainingQuantityTarget`; gRPC `CancelOrderRequest.remaining_quantity_target`) reduces a resting order **in place** to the target remaining quantity, **keeping its queue position** — unlike `replaceOrder`, which retires the order and rests a new one at the back of the book even for a pure size-down. The released delta unlocks exactly as a cancel does (spot unlock / margin reserve). The target means "leave this much resting", so a retried request converges instead of compounding; it must be a positive multiple of the market's quantity step and strictly below the current remaining quantity (emptying an order is a full cancel's job, growing it is a replace). Omit the options argument for the full cancel that existing calls already perform. A new non-terminal `OrderPartiallyCancelled` event announces the reduction on the `orders` WebSocket channel — the order is still resting — carrying the cumulative `filledQuantity`, the reduced `remainingQuantity`, the cancellation `reason` (`null` when none — the cancel request takes no reason input), and `reducedAt`.

### Mark-price candles on the OHLCV WebSocket channel

`sdk.ws.ohlcv(tradingPairId, tradingMode, interval, handler, priceType?)` accepts an optional `priceType` (`"trade"`, `"mark"`, or `"*"`). Omitting it — or passing `"trade"` — subscribes to the trade-derived candles exactly as before; `"mark"` subscribes to the close-only mark-price series for margin pairs (each candle's open = high = low = close = the minute's closing mark, volume `0`), published on `1m`; `"*"` receives both. The argument appends a fifth token to the `ohlcv` channel string, so existing four-token subscriptions are unchanged and never receive the mark series. `@0xmonaco/types` adds the `OHLCVPriceType` union, and `OHLCVEvent` carries an optional `priceType` so a `"*"` subscriber can tell the two streams apart. (The REST candlestick `priceType` shipped in 1.0.42.)

### `wrappedNative` balance flag

`GET /api/v1/accounts/balances` and `GET /api/v1/accounts/balances/{asset_id}` (gRPC `AccountsService.GetBalances` / `GetBalanceByAsset`) now return an optional `wrappedNative` boolean per balance, surfaced as `AccountBalance.wrappedNative` in `@0xmonaco/types`. It is `true` for the chain's wrapped-native asset (e.g. WSEI) and `false` for standard ERC-20 assets. `GET /api/v1/accounts/balances/{asset_id}` returns the flag even when that asset's balance is zero; the list endpoint `GET /api/v1/accounts/balances` omits zero-balance rows. It is the signal the vault client keys native-coin deposits on (see the vault change below).

### Spot cost-basis fields on portfolio assets

`sdk.portfolio.getAssets()` (`GET /api/v1/accounts/me/portfolio/assets`; gRPC `GetPortfolioAssets`) surfaces four optional spot cost-basis fields per asset row — `avgCost`, `unrealizedPnl`, `unrealizedRoe`, and `cumRealized` (all optional decimal strings). They are populated from the spot cost-basis engine when a checkpoint exists for the asset; `unrealizedPnl` and `unrealizedRoe` additionally require a mark price, and `unrealizedRoe` is additionally omitted when the cost basis is zero.

## Changed

### Vault deposits key native-coin handling on `wrappedNative`

The vault client now decides native-coin handling from the balances API's `wrappedNative` flag instead of a zero token address. The exchange's wrapped-native asset (e.g. WSEI) carries a real ERC20 address — the vault wraps native deposits into it, so `address(0)` never appears:

* `sdk.vault.deposit(assetId, amount)` routes a `wrappedNative` asset to the payable `depositNative`, sending `amount` as `msg.value` (the vault wraps on entry) — **no ERC20 approval is required or checked**. Every other asset keeps the approve + `depositERC20` flow, and an absent or `false` flag is treated as a standard ERC-20.
* `sdk.vault.needsApproval(assetId, amount)` returns `false` for a `wrappedNative` asset without reading the on-chain allowance, since `depositNative` consumes none.
* Withdrawals of the wrapped-native asset pay out native coin (the vault unwraps); this is decided server-side and needs no request change.

### Full-close TP/SL supersedes the previous full-close leg

Attaching a full-close (`closePosition: true`) take-profit or stop-loss with `sdk.positions.attachPositionTpSl()` (REST `POST /api/v1/positions/{positionId}/tp-sl`; gRPC `PositionsService.AttachPositionTpSl`) now supersedes that position's previously active full-close legs of the same condition type: the old legs are cancelled atomically in the same engine step that creates the replacement, each announcing a `conditional_order_update` event with `reason: "cancelled"` before the replacement's `"created"`. Moving a TP or SL is therefore one call, with no window in which the position holds both levels or neither — the non-atomic cancel-then-reattach workaround is no longer needed. Three things survive a supersede: the superseded leg's OCO sibling, every fixed-`quantity` leg (laddered partial exits still stack), and legs attached to an entry order rather than to the position (entry-attached legs are excluded in both directions).

## Fixed

### `marginRatio` for accounts at zero or negative equity

`GetPositionRisk` (`GET /api/v1/positions/{positionId}/risk`) and the authenticated `account` WebSocket channel (`AccountEventData.marginRatio`) now report a maintenance-aware `marginRatio` for accounts whose equity is not positive. An account that still carries an open maintenance requirement at zero or negative equity now reports the maximum-distress ratio instead of `0` (equity exactly zero) or a negative ratio (equity gone negative from bad debt) that previously sorted as *safer* than a healthy account. Accounts with no open positions continue to report `0`. The maximum-distress value is a very large decimal string (`Decimal::MAX`, \~7.9e28); treat a ratio at or above the liquidation threshold as maximal distress and clamp it for display.

## Upgrade

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

The MCP server ships at `1.0.43` too; it runs via `npx -y @0xmonaco/mcp-server`, so restarting your assistant picks up the new version. Nothing in this release is breaking. Two things worth acting on: if you deposit the wrapped-native asset (e.g. WSEI), drop the ERC20 approval step — `deposit` now sends it as native coin through the vault's payable `depositNative`, and `needsApproval` returns `false` for it; and if you read `marginRatio`, treat a value at or above the liquidation threshold as maximal distress and clamp the `Decimal::MAX` sentinel for display.


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