Monaco Protocol SDK v1.0.91
This release rolls up the consumer-facing changes shipped since v1.0.88. Fee simulation drops its deprecated whole-bps rate fields, and a TWAPclientTwapId is reserved for 30 days after its parent ends instead of forever. User trades gain margin account and order filters and a corrected UserTrade type, and TradesService.ListUserTrades is deprecated in favor of AccountsService.GetUserTrades. New public market reads cover trader positioning, taker trade flow and liquidation history, with a live market_liquidations channel and a React useLiquidationFeed hook. Sweeper deposits can be tracked by transaction hash, collateral transfers take an idempotency key, and placeLimitOrder / placeMarketOrder resend a lost response under the same key. Action items: read monacoTakerFeeBpsExact and monacoMakerRebateBpsExact instead of the removed integer rates; handle an absent quoteVolume, fee or executedAt on UserTrade; in Rust gRPC code, rename trades::UserTrade to ListedUserTrade and move to AccountsServiceClient::get_user_trades.
Breaking
Integer fee rates removed from fee simulation
simulateFees (GET /api/v1/fees/simulate; gRPC FeesService.SimulateFees) no longer returns monacoTakerFeeBps or monacoMakerRebateBps. They echoed the trading pair’s flat rate, not the tier rate you are charged. Read monacoTakerFeeBpsExact and monacoMakerRebateBpsExact instead: decimal basis-point strings such as "6.5" that match the fee charged. The fields also leave the SimulateFeeResponse type, the Rust REST and gRPC clients and the OpenAPI spec. See Trades.
TWAP client keys are reserved for 30 days
A TWAPclientTwapId (POST /api/v1/orders/twap; gRPC OrdersService.CreateTwapOrder) is reserved while its parent is live and for 30 days after it ends, instead of forever. Inside that window a duplicate is still refused with 409; after it, the same key creates a new parent. A keyed create is also refused with the retryable 503 ORDER_SUBMISSION_CAPACITY_EXCEEDED, applying nothing, once your user and application hold 10,000 reserved keys or the exchange-wide reservation ceiling is reached. See TWAP Orders.
UserTrade matches what getUserTrades returns
UserTrade from sdk.profile.getUserTrades (GET /api/v1/accounts/trades; gRPC AccountsService.GetUserTrades) adds tradingMode, makerOrderId, takerOrderId, quantityRaw, quoteVolumeRaw, feeRaw, feeToken, monacoFeeRaw, builderFeeRaw, settlementStatus, settlementTxHash and liquidityRole (MAKER or TAKER; a self-trade reads as MAKER). quoteVolume, fee and executedAt are now optional, because the API omits them when a trade has none recorded, and monacoFee can be null when fee is absent. Code that read those three fields as always present must handle undefined.
The generated Rust REST UserTrade was built from a different message with the same name; it now drops orderId, positionId, realizedPnl and timestamp, which the endpoint never sent, and gains the fields above. In monaco-grpc-sdk, monaco::api::trades::UserTrade is renamed ListedUserTrade; the wire format is unchanged. See Profile.
Deprecated
TradesService.ListUserTrades
TradesService.ListUserTrades and TradesServiceClient::list_user_trades are deprecated and will be removed. Call AccountsService.GetUserTrades, which now takes the same margin_account_id and order_id filters. The trades.UserTrade message is renamed ListedUserTrade; field numbers are unchanged. See TradesService.
Added
Trader metrics and trade flow
sdk.market.getTraderMetrics(tradingPairId) (GET /api/v1/market/pairs/{tradingPairId}/trader-metrics; gRPC MarketService.GetTraderMetrics) returns the market’s current long/short account counts, shares and ratio, plus distinct-trader counts for 1h, 24h and 7d. No account ids are returned: a position split is null when either side has fewer than five accounts, and an activity count is null below five users.
sdk.market.getTradeFlow(tradingPairId, { interval, startTime, endTime }) (GET /api/v1/market/pairs/{tradingPairId}/trade-flow; gRPC MarketService.GetTradeFlow) returns UTC buckets of taker buy and sell notional, ratio, net notional, cumulative volume delta and trade count. interval is 1m, 5m or 1h; [startTime, endTime) is in Unix milliseconds and limited to seven days and 2,048 buckets. Empty buckets are omitted, and notionals stay in the quote asset. The React useMarket hook and the MCP server (get_trader_metrics, get_trade_flow) expose both. See Market.
Public liquidation history and live feed
sdk.market.listLiquidationEvents (GET /api/v1/market/pairs/{tradingPairId}/liquidation-events; gRPC MarketService.ListLiquidationEvents) lists a market’s liquidation events newest first, with inclusive startTime, exclusive endTime, pageSize (default 50, at most 1000) and pageToken. Each event carries wallet, side, positionSize, the event-time markPrice and markNotional, which is positionSize × that same mark in the quote asset. sdk.market.getLiquidationMetrics (GET /api/v1/market/pairs/{tradingPairId}/liquidation-metrics; gRPC MarketService.GetLiquidationMetrics) returns long and short totals per 1m, 5m or 1h bucket; eventCount counts stored events, not wallets.
The public market_liquidations:{tradingPairId} WebSocket channel (sdk.ws.marketLiquidations) streams the same events live. The React useLiquidationFeed hook subscribes, backfills history after each subscription acknowledgement and reconnect, deduplicates by eventId and keeps the newest 500 events. The MCP server adds list_liquidation_events and get_liquidation_metrics. See Market and useLiquidationFeed.
Sweeper deposit status
sdk.sweeper.getDepositStatus(txHash) (GET /api/v1/sweeper/deposits/{txHash}; gRPC SweeperService.GetDepositStatus) returns where your deposits made by one transaction are, on any supported chain. Poll it until each deposit reads DEPOSITED, or FAILED with failureReason REFUNDED; the list is empty until the sweeper has indexed the transaction. sdk.sweeper.listDeposits({ pageSize?, pageToken? }) (GET /api/v1/sweeper/deposits; gRPC SweeperService.ListDeposits) lists your deposits newest first. Both require a session and return only the session’s own deposits. The SDK throws InvalidConfigError before sending a malformed txHash or a pageSize outside 1 to 100. See Vault.
Idempotent collateral transfers
Every margin collateral transfer takes an optionalidempotencyKey, in the same namespace as order create: the margin account, parent margin account, risk bucket and sub-account transfer-in / transfer-out routes, and POST /api/v1/margin/collateral/transfer. A retry with the same key and request within 15 minutes returns the first transfer’s result, movementId included, without moving money again. A different request under the same key returns IDEMPOTENCY_KEY_CONFLICT (HTTP 409 / gRPC ALREADY_EXISTS). See Retrying a transfer safely.
Per-market funding impact notional
sdk.market.getPerpMarketConfig (GET /api/v1/market/pairs/{tradingPairId}/perp/config; gRPC MarketService.GetPerpMarketConfig) returns fundingImpactNotional: the quote notional each funding premium sample walks through each side of the book. It is set per market, and every market starts at "2000". See Funding Rates.
User trade filters
getUserTrades and iterateUserTrades accept marginAccountId and orderId, matching your side of each fill. Like tradingPairId, a filtered response carries no total, and a page token resumes only the filters it was issued with. See Profile.
Changed
BuilderCodes balance follows the payout address
Shortly after Monaco moves a frontend’s payout address to a new wallet, the unclaimed balance accrued to the old wallet moves to the new one, in the same step that starts crediting it. Amounts the old wallet already claimed or withdrew do not move.sdk.buildercodes.claimBuildercodeRewards and getRewardsBalance (POST /api/v1/buildercodes/rewards/claim, GET /api/v1/buildercodes/rewards/balance) still resolve the bucket from the signed-in wallet without requiring current enrollment, so a former payout wallet can still read and claim whatever remains in its bucket. Request and response fields are unchanged. See BuilderCodes.
Faster transaction receipts
The SDK’s internal viem client now polls for transaction receipts every 200 ms by default, about half a Sei block, down from 750 ms.sdk.vault.deposit, sdk.vault.approve and sdk.waitForTransaction see a mined transaction within about half a block. Set pollingInterval: 750 on SDKConfig to keep the previous cadence. See Configuration.
Finer SEI and FARTCOIN perp ticks
The SEI/USDC and FARTCOIN/USDC perps trade on a0.00001 price tick, down from 0.0001. Resting orders were kept. Read the tick from the trading pair rather than hard-coding it.
A diverged book no longer pauses a market
A perp whose book drifts away from the oracle keeps trading, liquidating, paying funding and updating its mark like any other market. It still readsDIVERGED in last_regime for monitoring. Previously such a market refused takers and liquidations, and skipped funding, until its book re-centred. See Markets.
Auto-deleveraging starts at the bankruptcy price
With auto-deleveraging enabled, a liquidating risk bucket that is below three quarters of its maintenance margin, or has been at any point in this liquidation, goes to auto-deleveraging once its marks cross the bankruptcy prices pinned when liquidation began, whatever the order book holds, or once the ADL backstop (five minutes by default) has passed. A bucket that never falls that far stays in ordinary liquidation. This replaces the earlier rule that waited on repeated empty-book passes. See Auto-Deleveraging.Fixed
Order creates resend a lost response
WhenplaceLimitOrder or placeMarketOrder generated the idempotency key and the outcome is unknown (a network error, an unreadable success response, or HTTP 5xx including ORDER_SUBMISSION_UNAVAILABLE), the SDK re-sends the same request and key up to 3 more times after 1, 2 and 4 seconds. The server replays the original result instead of placing a second order. A maintenance OPERATIONS_BLOCKED refusal, any 4xx and a Retry-After above 5 seconds return at once; retries stop 60 seconds after the first send, or when the session changes. If every attempt is ambiguous the call throws an APIError naming the key to reuse. A key you supply, and batchCreate, still send once. See Safe Retries.
Deactivated applications
Once an application is deactivated, order creates, batch creates, replacements and TWAP creates placed through it are refused with HTTP403 / gRPC PERMISSION_DENIED and code APPLICATION_INACTIVE (per-item error.code in a batch). Reduce-only orders that close a margin position are still accepted, and spot balances can still be withdrawn. The application’s resting orders and running TWAP orders are cancelled and its copy trading follows stopped. upsertLeadTrader and upsertFollow from a deactivated application return 403 with Application is inactive.
Fee simulation matches the engine’s charge
simulateFees returns every amount truncated toward zero to the quote token’s decimals, as the engine charges it: notional, each fee and rebate, and the totals totalTakerFees, takerTotalPayment and makerTotalReceipt, now sums of the truncated parts. Totals could previously exceed the charge by one atomic unit, and a rebate under one atomic unit now reads 0.
Portfolio figures
getSummary’s current.availableValue (GET /api/v1/accounts/me/portfolio/summary) is now what you can spend or withdraw: USDC available on spot plus the parent margin account’s withdrawableCollateral. It previously valued every spot asset and counted unrealized margin gains, and it is now served even when valuationStatus is partial. getPerformance (GET /api/v1/accounts/me/portfolio/performance) reports deposits, withdrawals and netExternalFlows from the period start, so an account funded inside the period no longer reports 0. See Portfolio.
Position fees and risk
A closed position reports each reducing fee once incumFees, netRealizedPnl and realizedRoe (GET /api/v1/positions, GET /api/v1/positions/{positionId}); positions closed earlier keep the extra fees until their PnL is recomputed. getPositionRisk (GET /api/v1/positions/{positionId}/risk) prices marginRatio from the maintenance margin at the current mark, the same mark as maintenanceMarginRequired, instead of the requirement stored at the last fill. Liquidation and auto-deleveraging orders now carry the closed position’s leverage instead of 1.
Maker rebates in movements
Ledger history and movements list the BUY-side maker rebate for each fill as aTRADE credit described as Trade <id> - maker rebate <amount> <symbol>. The row was missing, so BUY makers appeared to pay the full notional; balances were always correct. See Account Balances.
Clearer and fewer order refusals
A margin reduce-only order with no risk bucket behind it is refused withreduce_only margin orders require an existing position, instead of advice to transfer collateral that could not help. Match the new text if you matched the old one. A delegated agent’s cancel is no longer held to its maxLeverage cap, which applies only to orders it creates or replaces.

