Monaco Protocol SDK v1.0.76
This release finishes the move to cursor pagination on the public trades listing and the pending-withdrawal, managed-market and BuilderCodes payout listings, and makessdk.trades.getTrades resolve to a { trades, nextPageToken } envelope. Perp risk tiers report maxPositionNotional as a USD notional cap, and markets can carry an optional USD position cap and open-interest cap checked at admission. BuilderCodes reads and claims no longer depend on the revenue-share switch. The WebSocket market_stats and instruments channels carry more market context, and an edited order’s OrderPlaced reports the fill it carried over. Action items: stop sending page to these four listings and walk them with pageToken / nextPageToken; read .trades from getTrades; read maxPositionNotional instead of maxPositionSize; handle a successful BuilderCodes config read with buildercodesEnabled: false.
Breaking
Page-number pagination is removed from four more listings
Thepage request field is gone from these listings, which now walk with pageToken: omit it (or send "") to start, then follow nextPageToken until it comes back empty. Each walk is one ordered read, so an empty nextPageToken is a definitive end.
- Public trades:
sdk.trades.getTrades(GET /api/v1/trades/{tradingPairId}; gRPCTradesService.GetTrades).pageSizedefaults to 25. The walk seeks on(executedAt, id), so a page never repeats or skips a trade when new fills land mid-walk, and still covers the recent trades window rather than archived history. - Pending withdrawals:
sdk.withdrawals.listPendingWithdrawals(GET /api/v1/withdrawals; gRPCWithdrawalsService.ListPendingWithdrawals). Default 20, newest first. - Managed-market assignments:
sdk.managedMarkets.listAssignments(GET /api/v1/managed-markets/assignments; gRPCManagedMarketsService.ListAssignments). Default 100, oldest first. - BuilderCodes payouts:
sdk.buildercodes.listPayouts(GET /api/v1/buildercodes/payouts; gRPCBuildercodeRewardsService.ListBuildercodePayouts). Default 20.
pageSize accepts 1 to 1000 (was 1 to 100), and a larger value is rejected instead of clamped. The page response field is gone; total (and totalPages on pending withdrawals and payouts) stays exact. Over REST a request that still sends page is rejected with 400. Over gRPC an old stub’s page is discarded as an unknown field and every call reads the first page, so regenerate your stubs. The TypeScript SDK and the MCP server reject a leftover page before sending.
Payout ordering changes. listPayouts now walks (createdAt, id) descending. It never skips or repeats a credit, but it is not chronological inside one persistor batch: every credit a batch writes shares a timestamp and the id tie-break is random, so a later fill can be listed ahead of an earlier one. Across batches the order is still newest-first. See BuilderCodes.
getTrades returns an envelope
sdk.trades.getTrades(tradingPairId, options) resolves to { trades, nextPageToken } instead of TradeEvent[]. options.page is gone and options.pageToken is new; passing page throws a ValidationError before any request is sent. Callers that used the array directly read .trades. The trades and their order (newest first) are unchanged. The MCP get_trades tool takes pageToken and returns nextPageToken, and its strict input schema rejects page. useTradeFeed is unchanged. See Market Data.
maxPositionNotional is a USD notional cap
On getPerpMarketConfig (GET /api/v1/market/pairs/{tradingPairId}/perp/config), each RiskTier.maxPositionNotional is now the most USD notional a position may hold at that tier’s maxLeverage: the next tier’s lowerBoundNotional, or the market’s position cap on the top tier (absent when the market is uncapped). It used to carry a base-asset quantity under the notional name. maxPositionSize is deprecated and no longer set. See Margin ladders.
Added
Market position and open-interest caps
A perp market can carry an optional USD position cap and an optional USD open-interest cap. Both are checked at admission only, priced at the mark. An order that would take its risk bucket’s position plus its same-side resting orders past the position cap is rejected withposition cap exceeded: …, and one whose opening quantity would take the market’s open interest past its cap with open interest cap reached: …, both 400 / INVALID_ARGUMENT. A position the mark carries past a cap can still be reduced, and a reduce-only order always passes. The per-base-quantity position size limit is retired, so a market is uncapped unless configured otherwise. See Margin ladders.
More fields on market_stats frames
sdk.ws.marketStats events and snapshot rows carry openInterestHeadroom (what is left of the open-interest cap at the mark, in USD notional, never below zero) and marketStatus (the same label as the market’s marketStatsAll row; pass unrecognized values through). Perp frames add fundingIntervalSeconds and lastFundingTime (a millisecond epoch, absent before the first settlement). openInterestLimit is now the cap in USD notional; it and openInterestHeadroom are omitted when the market is uncapped. A perp market is always published: until its open interest is known, openInterest and openInterestHeadroom are omitted (never "0") and every other field is still sent. See WebSockets.
Asset identity on instruments frames
sdk.ws.instruments snapshot rows and live frames carry baseAssetId, quoteAssetId, baseToken, quoteToken, baseAssetName, quoteAssetName, baseDecimals and quoteDecimals on every market, plus minLeverage on perps, so a client can label a market and scale its amounts without parsing symbol or calling REST. All are optional; a frame from an older server arrives with them undefined.
Edited orders report their carried fill
Replacing a partly filled order keeps its fills. The replacement’sOrderPlaced now carries filledQuantity, filledQuantityRaw and averageFillPrice from the original, with the order’s total quantity and PARTIALLY_FILLED, as getOrder reports it. Its fill frames report the total, cumulative fill and average across every fill. A maker fill’s averageFillPrice is now the order’s cumulative average rather than that trade’s price, which stays in executionPrice. See WebSockets.
Per-market perp price band
A perp market can be configured with its own price band, from 100 to 2,500 bps, which replaces both the 1,000 bps placement default and the 1,200 bps triggered-leg default on that market. Markets without one keep the defaults. See Perp price band.Changed
BuilderCodes reads and claims are not switch-gated
getConfig, listPayouts, getPayoutSummary, getRewardsBalance, claimBuildercodeRewards and listBuilderFeeChanges (GET /api/v1/buildercodes/config, /payouts, /payouts/summary, /rewards/balance, /builder-fee/changes, POST /api/v1/buildercodes/rewards/claim) work whether or not the revenue share is on. They return 403 / PERMISSION_DENIED only for a delegated session or, where it applies, a caller that is not the application’s payout wallet. setBuilderFee (PUT /api/v1/buildercodes/builder-fee) is refused only while both the revenue share and builder fees are off. getConfig’s buildercodesEnabled reports whether the revenue share is on and can be false on success. See BuilderCodes.
Overload refusals on cancels
When the engine’s work budget is full, cancels, like creates and replaces, can be refused with a retryable503 and error code OVERLOADED. Cancels keep a reserved share of that budget, so they are refused last.
Direct vault deposits need the exact payload
A deposit made straight to the vault contract must carry the exactapplicationData that encodeDepositApplicationData() (from @0xmonaco/contracts) produces. Apart from Monaco’s own insurance-fund top-up form, any other JSON-shaped payload is credited to the spot wallet of Monaco’s default application rather than yours. SDK deposits are unaffected. See Deposit Tokens.
Fixed
useUserOrdersand edited orders — the replacement of a partly filled order now shows the fill and average it carried over, instead of zero fill until a refresh.
Upgrade
page from getTrades, listPendingWithdrawals, listAssignments and listPayouts and loop on nextPageToken. Read .trades from getTrades. Read maxPositionNotional as a USD notional and drop maxPositionSize. Treat buildercodesEnabled: false as a valid config response.
