@0xmonaco/types 1.0.46 → 1.0.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,11 @@
1
1
  import type { Address, PublicClient, TransactionReceipt, WalletClient } from "viem";
2
2
  import type { ApplicationsAPI } from "../applications";
3
- import type { AuthAPI, AuthState, SessionCredentials } from "../auth/index";
3
+ import type { AuthAPI, AuthState } from "../auth/index";
4
4
  import type { DelegatedAgentsAPI } from "../delegated-agents";
5
5
  import type { FaucetAPI } from "../faucet";
6
6
  import type { FeesAPI } from "../fees";
7
7
  import type { MarginAccountsAPI } from "../margin-accounts";
8
- import type { Interval, MarketAPI } from "../market";
8
+ import type { MarketAPI } from "../market";
9
9
  import type { PitpassAPI } from "../pitpass";
10
10
  import type { PortfolioAPI } from "../portfolio";
11
11
  import type { PositionsAPI } from "../positions";
@@ -15,7 +15,7 @@ import type { SubAccountsAPI } from "../sub-accounts";
15
15
  import type { SweeperAPI } from "../sweeper";
16
16
  import type { TradingAPI, TradingMode } from "../trading";
17
17
  import type { VaultAPI } from "../vault";
18
- import type { ConditionalOrderEvent, MonacoWebSocketConfig, OHLCVEvent, OrderbookEvent, OrderbookQuotationMode, OrderEvent, TradeEvent, TwapOrderEvent, UserBalanceEvent, UserMovementEvent } from "../websocket";
18
+ import type { MonacoWebSocket, MonacoWebSocketConfig, OrderbookEvent, OrderbookQuotationMode, TradeEvent } from "../websocket";
19
19
  import type { WhitelistAPI } from "../whitelist";
20
20
  import type { WithdrawalsAPI } from "../withdrawals";
21
21
  import type { Network } from "./network";
@@ -139,23 +139,8 @@ export interface MonacoSDK {
139
139
  pageSize?: number;
140
140
  }) => Promise<TradeEvent[]>;
141
141
  };
142
- /** WebSocket client for real-time data (orders, orderbook, ohlcv) */
143
- ws: {
144
- connect: () => Promise<void>;
145
- disconnect: () => void;
146
- isConnected: () => boolean;
147
- getStatus: () => "connected" | "connecting" | "disconnected" | "reconnecting";
148
- setSessionKeypair: (credentials: SessionCredentials | undefined) => void;
149
- orders: (tradingPairId: string, tradingMode: TradingMode, handler: (event: OrderEvent) => void) => () => void;
150
- orderbook: (tradingPairId: string, tradingMode: TradingMode, magnitude: number, quotationMode: OrderbookQuotationMode, handler: (event: OrderbookEvent) => void) => () => void;
151
- ohlcv: (tradingPairId: string, tradingMode: TradingMode, interval: Interval, handler: (event: OHLCVEvent) => void) => () => void;
152
- trades: (tradingPairId: string, handler: (event: TradeEvent) => void) => () => void;
153
- movements: (handler: (event: UserMovementEvent) => void) => () => void;
154
- userOrders: (handler: (event: OrderEvent) => void) => () => void;
155
- balances: (handler: (event: UserBalanceEvent) => void) => () => void;
156
- conditionalOrders: (handler: (event: ConditionalOrderEvent) => void, tradingPairId?: string) => () => void;
157
- twapOrders: (handler: (event: TwapOrderEvent) => void, tradingPairId?: string) => () => void;
158
- };
142
+ /** WebSocket client for real-time data — the full typed channel surface of {@link MonacoWebSocket} */
143
+ ws: MonacoWebSocket;
159
144
  /** Wallet client for all blockchain operations (undefined until set) */
160
145
  walletClient: WalletClient | undefined;
161
146
  /** Public client for read-only blockchain operations */
@@ -48,8 +48,11 @@ export interface TradingAPI extends BaseAPI {
48
48
  /**
49
49
  * Client-assigned correlation handle, echoed back on order reads and
50
50
  * order WebSocket events. At most 64 characters from [A-Za-z0-9._:-].
51
- * Not de-duplicated and not unique — a replacement re-states it and
52
- * inherits nothing from the original order.
51
+ * Uniqueness is enforced only among your orders that are resting on the
52
+ * book; an order that never rests does not take the handle, and the value
53
+ * is released on any terminal state. It does not make a retry safe —
54
+ * resubmitting after a lost response can execute a second time. A
55
+ * replacement re-states it and inherits nothing from the original order.
53
56
  */
54
57
  clientOrderId?: string;
55
58
  takeProfit?: ParentTpSlLegParams;
@@ -80,8 +83,11 @@ export interface TradingAPI extends BaseAPI {
80
83
  /**
81
84
  * Client-assigned correlation handle, echoed back on order reads and
82
85
  * order WebSocket events. At most 64 characters from [A-Za-z0-9._:-].
83
- * Not de-duplicated and not unique — a replacement re-states it and
84
- * inherits nothing from the original order.
86
+ * Uniqueness is enforced only among your orders that are resting on the
87
+ * book; an order that never rests does not take the handle, and the value
88
+ * is released on any terminal state. It does not make a retry safe —
89
+ * resubmitting after a lost response can execute a second time. A
90
+ * replacement re-states it and inherits nothing from the original order.
85
91
  */
86
92
  clientOrderId?: string;
87
93
  takeProfit?: ParentTpSlLegParams;
@@ -142,8 +148,14 @@ export interface TradingAPI extends BaseAPI {
142
148
  /**
143
149
  * Client-assigned correlation handle, echoed back on order reads and
144
150
  * order WebSocket events. At most 64 characters from [A-Za-z0-9._:-].
145
- * Not de-duplicated and not unique — a replacement re-states it and
146
- * inherits nothing from the original order.
151
+ * Uniqueness is enforced only among your orders that are resting on the
152
+ * book; an order that never rests does not take the handle, and the value
153
+ * is released on any terminal state. A replacement re-states it and
154
+ * inherits nothing from the original order. A retry of this replace cannot
155
+ * double-execute — it names the original order id, which the engine
156
+ * revalidates at sequence time, so a second attempt returns
157
+ * ORDER_NOT_FOUND — but that code is ambiguous on its own, so reconcile to
158
+ * find the replacement's new order id rather than to rule out a duplicate.
147
159
  */
148
160
  clientOrderId?: string;
149
161
  }): Promise<ReplaceOrderResponse>;
@@ -222,6 +234,6 @@ export interface TradingAPI extends BaseAPI {
222
234
  */
223
235
  listTwapOrders(params?: ListTwapOrdersParams): Promise<ListTwapOrdersResponse>;
224
236
  }
225
- export type { ConditionalOrderConditionType, ConditionalOrderState, ConditionalOrderTriggerSource, Order, OrderRole, OrderSide, OrderStatus, OrderStatusFilter, OrderTerminalReason, OrderType, PositionSide, TimeInForce, TradingMode, TwapOrderState, } from "./orders";
237
+ export type { ConditionalOrderConditionType, ConditionalOrderState, ConditionalOrderTriggerSource, Order, OrderRole, OrderSide, OrderStatus, OrderStatusFilter, OrderTerminalReason, OrderType, PositionSide, TimeInForce, TradingMode, TwapExecutionStyle, TwapOrderState, } from "./orders";
226
238
  export { ORDER_STATUS_VALUES } from "./orders";
227
239
  export type { BatchCancelError, BatchCancelOrdersResponse, BatchCancelResult, BatchCreateOrderParams, BatchCreateOrdersResponse, BatchCreateResult, BatchError, BatchReplaceOrderParams, BatchReplaceOrdersResponse, BatchReplaceResult, CancelConditionalOrderResponse, CancelOrderResponse, CancelTwapOrderResponse, ConditionalOrder, CreateOrderResponse, CreateTwapOrderOptions, CreateTwapOrderResponse, GetOrderResponse, GetPaginatedOrdersParams, GetPaginatedOrdersResponse, GetTwapOrderTcaResponse, ListConditionalOrdersParams, ListConditionalOrdersResponse, ListTwapOrdersParams, ListTwapOrdersResponse, MatchResult, ParentTpSlLegParams, ReplaceOrderResponse, TwapOrder, UpdatedFields, } from "./responses";
@@ -74,8 +74,10 @@ export interface Order {
74
74
  * Client-assigned correlation handle as stored: the value supplied on create
75
75
  * or replace, with surrounding whitespace trimmed. Absent when the order
76
76
  * carried none, including every order placed before the field was accepted on
77
- * write. Not unique — several orders may share one value, so a lookup by it
78
- * can be ambiguous.
77
+ * write. Uniqueness is enforced only among your orders that are resting on
78
+ * the book, so several of your orders may share one value over time and a
79
+ * lookup by it can be ambiguous: an order that never rests never takes the
80
+ * handle, and the value is released on any terminal state.
79
81
  */
80
82
  clientOrderId?: string;
81
83
  /** Position ID linked to the order, when available */
@@ -168,3 +170,10 @@ export type ConditionalOrderState = "PENDING_PARENT" | "ACTIVE" | "TRIGGERING" |
168
170
  * - CANCELLED: cancelled by the user before the window ended
169
171
  */
170
172
  export type TwapOrderState = "PENDING" | "ACTIVE" | "COMPLETED" | "CANCELLED";
173
+ /**
174
+ * How a TWAP parent executes each slice.
175
+ * - TAKER (default): banded MARKET slices fired at each slot
176
+ * - PASSIVE: post-only children rested at the touch, with a taker sweep at
177
+ * each slice deadline
178
+ */
179
+ export type TwapExecutionStyle = "TAKER" | "PASSIVE";
@@ -4,7 +4,7 @@
4
4
  * Response types for trading operations.
5
5
  */
6
6
  import type { MarginMode } from "../margin-accounts";
7
- import type { ConditionalOrderConditionType, ConditionalOrderState, ConditionalOrderTriggerSource, Order, OrderSide, OrderStatus, OrderStatusFilter, OrderType, PositionSide, TimeInForce, TradingMode, TwapOrderState } from "./orders";
7
+ import type { ConditionalOrderConditionType, ConditionalOrderState, ConditionalOrderTriggerSource, Order, OrderSide, OrderStatus, OrderStatusFilter, OrderType, PositionSide, TimeInForce, TradingMode, TwapExecutionStyle, TwapOrderState } from "./orders";
8
8
  /**
9
9
  * Match result information for order execution.
10
10
  * Contains detailed information about trades, fills, and execution quality.
@@ -378,8 +378,11 @@ export interface BatchCreateOrderParams {
378
378
  /**
379
379
  * Client-assigned correlation handle, echoed back on order reads and on
380
380
  * order WebSocket events. At most 64 characters from [A-Za-z0-9._:-].
381
- * Monaco does not de-duplicate on it and does not enforce uniqueness —
382
- * it correlates a response to a request, it does not make a retry safe.
381
+ * Uniqueness is enforced only among your orders that are resting on the
382
+ * book; an order that never rests does not take the handle, and the value
383
+ * is released on any terminal state. It correlates a response to a request
384
+ * and does not make a retry safe — resubmitting after a lost response can
385
+ * execute a second time.
383
386
  */
384
387
  clientOrderId?: string;
385
388
  }
@@ -403,8 +406,13 @@ export interface BatchReplaceOrderParams {
403
406
  /**
404
407
  * Client-assigned correlation handle, echoed back on order reads and on
405
408
  * order WebSocket events. At most 64 characters from [A-Za-z0-9._:-].
406
- * Monaco does not de-duplicate on it and does not enforce uniqueness —
407
- * it correlates a response to a request, it does not make a retry safe.
409
+ * Uniqueness is enforced only among your orders that are resting on the
410
+ * book; an order that never rests does not take the handle, and the value
411
+ * is released on any terminal state. It correlates a response to a request.
412
+ * Each item names its own original order id, which the engine revalidates at
413
+ * sequence time, so retrying a batch cannot replace an already-replaced
414
+ * original a second time; reconcile per item on the results and their new
415
+ * order ids rather than to rule out duplicate execution.
408
416
  */
409
417
  clientOrderId?: string;
410
418
  }
@@ -491,6 +499,15 @@ export interface CreateTwapOrderOptions {
491
499
  * reproducible to compliance but unpredictable to the market.
492
500
  */
493
501
  randomize?: boolean;
502
+ /**
503
+ * Child execution style. "TAKER" (default): each slice executes
504
+ * immediately as a banded MARKET order. "PASSIVE": each slice rests as a
505
+ * post-only limit at the same-side touch (maker where possible, repriced
506
+ * to follow the touch), and the leftover is swept as a banded MARKET order
507
+ * at the slice deadline; passive parents use a slower default slice
508
+ * cadence (~60s).
509
+ */
510
+ executionStyle?: "TAKER" | "PASSIVE";
494
511
  /** Whether the TWAP parent is reduce-only (margin only). Child orders inherit it and clamp to the live position. */
495
512
  reduceOnly?: boolean;
496
513
  /** Trading mode: "SPOT" or "MARGIN" (default: "SPOT"). */
@@ -507,6 +524,23 @@ export interface CreateTwapOrderOptions {
507
524
  strategyKey?: string;
508
525
  /** Use master account balance for sub-account orders. */
509
526
  useMasterBalance?: boolean;
527
+ /**
528
+ * Price-triggered activation: the parent waits (PENDING) until the
529
+ * reference price reaches or crosses this price in `triggerDirection`,
530
+ * then runs a floating window of `durationSeconds` from the trigger
531
+ * instant. Requires `triggerDirection` and `durationSeconds`; incompatible
532
+ * with `startTime`/`endTime`. Rejected if already met at creation.
533
+ */
534
+ triggerPrice?: string;
535
+ /** Crossing direction for `triggerPrice`: "ABOVE" or "BELOW". Required with `triggerPrice`. */
536
+ triggerDirection?: "ABOVE" | "BELOW";
537
+ /**
538
+ * Deadline for the trigger to fire (RFC 3339, UTC only — Z suffix). If it
539
+ * has not fired by then the parent cancels with terminal reason
540
+ * 'trigger expired'. Only valid with `triggerPrice`; defaults to creation
541
+ * + the maximum window (30 days).
542
+ */
543
+ conditionalExpiry?: string;
510
544
  /** Client-assigned idempotency key (max 36 chars), unique per user and application. A duplicate is rejected with 409. */
511
545
  clientTwapId?: string;
512
546
  }
@@ -589,6 +623,8 @@ export interface TwapOrder {
589
623
  clientTwapId?: string;
590
624
  /** Whether seeded size/timing randomization is applied to the schedule */
591
625
  randomize: boolean;
626
+ /** Child execution style: "TAKER" (banded MARKET slices) or "PASSIVE" (post-only children at the touch, taker sweep at each slice deadline) */
627
+ executionStyle: TwapExecutionStyle;
592
628
  /** Window start (ISO 8601) */
593
629
  startTime: string;
594
630
  /** Window end (ISO 8601). Execution stops hard at this time. */
@@ -611,6 +647,14 @@ export interface TwapOrder {
611
647
  state: TwapOrderState;
612
648
  /** Terminal cause detail, e.g. an end-of-window shortfall ('ended with shortfall <qty>'); absent for non-terminal parents */
613
649
  terminalReason?: string;
650
+ /** Price-triggered activation level, when this parent is conditional */
651
+ triggerPrice?: string;
652
+ /** Trigger crossing direction: "ABOVE" or "BELOW" */
653
+ triggerDirection?: string;
654
+ /** Deadline for the trigger to fire (ISO 8601 UTC); reaching it cancels the parent ('trigger expired') */
655
+ conditionalExpiry?: string;
656
+ /** When the trigger fired and the floating window started (ISO 8601 UTC); absent while waiting */
657
+ triggeredAt?: string;
614
658
  /** Creation timestamp (ISO 8601) */
615
659
  createdAt: string;
616
660
  /** Last update timestamp (ISO 8601) */
@@ -331,12 +331,6 @@ export declare const TwapOrderStateSchema: z.ZodEnum<{
331
331
  PENDING: "PENDING";
332
332
  COMPLETED: "COMPLETED";
333
333
  }>;
334
- /**
335
- * Create TWAP Order validation schema
336
- *
337
- * Validates parameters for creating a TWAP parent order. The execution
338
- * window is mandatory: exactly one of durationSeconds or endTime.
339
- */
340
334
  export declare const CreateTwapOrderSchema: z.ZodObject<{
341
335
  tradingPairId: z.ZodUUID;
342
336
  side: z.ZodEnum<{
@@ -351,6 +345,10 @@ export declare const CreateTwapOrderSchema: z.ZodObject<{
351
345
  limitPrice: z.ZodOptional<z.ZodString>;
352
346
  slippageToleranceBps: z.ZodOptional<z.ZodNumber>;
353
347
  randomize: z.ZodOptional<z.ZodBoolean>;
348
+ executionStyle: z.ZodOptional<z.ZodEnum<{
349
+ TAKER: "TAKER";
350
+ PASSIVE: "PASSIVE";
351
+ }>>;
354
352
  reduceOnly: z.ZodOptional<z.ZodBoolean>;
355
353
  tradingMode: z.ZodOptional<z.ZodEnum<{
356
354
  SPOT: "SPOT";
@@ -366,6 +364,12 @@ export declare const CreateTwapOrderSchema: z.ZodObject<{
366
364
  strategyKey: z.ZodOptional<z.ZodString>;
367
365
  useMasterBalance: z.ZodOptional<z.ZodBoolean>;
368
366
  clientTwapId: z.ZodOptional<z.ZodString>;
367
+ triggerPrice: z.ZodOptional<z.ZodString>;
368
+ triggerDirection: z.ZodOptional<z.ZodEnum<{
369
+ ABOVE: "ABOVE";
370
+ BELOW: "BELOW";
371
+ }>>;
372
+ conditionalExpiry: z.ZodOptional<z.ZodISODateTime>;
369
373
  }, z.core.$strip>;
370
374
  }, z.core.$strip>;
371
375
  export declare const CancelTwapOrderSchema: z.ZodObject<{
@@ -386,6 +386,8 @@ const TwapDurationSecondsSchema = z.union([
386
386
  * Validates parameters for creating a TWAP parent order. The execution
387
387
  * window is mandatory: exactly one of durationSeconds or endTime.
388
388
  */
389
+ /** Maximum TWAP window, and therefore the cap on `conditionalExpiry` (30 days). */
390
+ const MAX_TWAP_WINDOW_MS = 30 * 24 * 60 * 60 * 1000;
389
391
  export const CreateTwapOrderSchema = z
390
392
  .object({
391
393
  tradingPairId: UUIDSchema,
@@ -398,6 +400,7 @@ export const CreateTwapOrderSchema = z
398
400
  limitPrice: PositiveDecimalStringSchema.optional(),
399
401
  slippageToleranceBps: TwapSlippageToleranceBpsSchema.optional(),
400
402
  randomize: z.boolean().optional(),
403
+ executionStyle: z.enum(["TAKER", "PASSIVE"]).optional(),
401
404
  reduceOnly: z.boolean().optional(),
402
405
  tradingMode: TradingModeSchema.optional(),
403
406
  marginAccountId: UUIDSchema.optional(),
@@ -407,6 +410,9 @@ export const CreateTwapOrderSchema = z
407
410
  strategyKey: z.string().min(1).max(128).optional(),
408
411
  useMasterBalance: z.boolean().optional(),
409
412
  clientTwapId: z.string().min(1).max(36, "clientTwapId cannot exceed 36 characters").optional(),
413
+ triggerPrice: PositiveDecimalStringSchema.optional(),
414
+ triggerDirection: z.enum(["ABOVE", "BELOW"]).optional(),
415
+ conditionalExpiry: ISO8601DateSchema.optional(),
410
416
  }),
411
417
  })
412
418
  .refine((data) => (data.options.durationSeconds !== undefined) !== (data.options.endTime !== undefined), {
@@ -436,6 +442,48 @@ export const CreateTwapOrderSchema = z
436
442
  .refine((data) => data.options.tradingMode !== "MARGIN" || data.options.reduceOnly === true || data.options.leverage !== undefined, {
437
443
  message: "leverage is required for normal MARGIN TWAP orders",
438
444
  path: ["options", "leverage"],
445
+ })
446
+ .refine((data) => (data.options.triggerPrice !== undefined) === (data.options.triggerDirection !== undefined), {
447
+ message: "triggerPrice and triggerDirection are both-or-neither",
448
+ path: ["options", "triggerDirection"],
449
+ })
450
+ .refine((data) => data.options.triggerPrice === undefined || data.options.durationSeconds !== undefined, {
451
+ message: "conditional TWAP (triggerPrice) requires durationSeconds — the window floats from the trigger instant",
452
+ path: ["options", "durationSeconds"],
453
+ })
454
+ .refine((data) => data.options.triggerPrice === undefined || (data.options.startTime === undefined && data.options.endTime === undefined), {
455
+ message: "triggerPrice is incompatible with startTime/endTime",
456
+ path: ["options", "triggerPrice"],
457
+ })
458
+ .refine((data) => data.options.conditionalExpiry === undefined || data.options.triggerPrice !== undefined, {
459
+ message: "conditionalExpiry is only valid together with triggerPrice",
460
+ path: ["options", "conditionalExpiry"],
461
+ })
462
+ // The two VALUE rules on conditionalExpiry, mirroring the server. Without
463
+ // them the schema only checks the timestamp's shape and every deadline in
464
+ // the past — or beyond the maximum window — round-trips to a 400. The
465
+ // UTC-suffix rule stays server-side: ISO8601DateSchema deliberately accepts
466
+ // any valid offset, and narrowing it here would change an unrelated shared
467
+ // schema.
468
+ .refine((data) => {
469
+ const raw = data.options.conditionalExpiry;
470
+ if (raw === undefined)
471
+ return true;
472
+ const at = Date.parse(raw);
473
+ return Number.isNaN(at) || at > Date.now();
474
+ }, {
475
+ message: "conditionalExpiry must be in the future",
476
+ path: ["options", "conditionalExpiry"],
477
+ })
478
+ .refine((data) => {
479
+ const raw = data.options.conditionalExpiry;
480
+ if (raw === undefined)
481
+ return true;
482
+ const at = Date.parse(raw);
483
+ return Number.isNaN(at) || at - Date.now() <= MAX_TWAP_WINDOW_MS;
484
+ }, {
485
+ message: "conditionalExpiry cannot be more than 30 days after creation (the maximum window)",
486
+ path: ["options", "conditionalExpiry"],
439
487
  });
440
488
  export const CancelTwapOrderSchema = z.object({
441
489
  twapOrderId: UUIDSchema,
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Monaco WebSocket client surface.
3
+ *
4
+ * The canonical, hand-written subscription interface implemented by
5
+ * `@0xmonaco/core`'s `createMonacoWebSocket` and exposed as `MonacoSDK.ws`.
6
+ * It lives here (not in `@0xmonaco/core`) so every package types the same
7
+ * surface — the channel-coverage lock in
8
+ * `tests/websocket/channel-coverage.test.ts` parses this file as the source
9
+ * of truth for the SDK's channel surface.
10
+ */
11
+ import type { SessionCredentials } from "../auth/index";
12
+ import type { Interval } from "../market";
13
+ import type { TradingMode } from "../trading";
14
+ import type { WebSocketStatus } from "./base";
15
+ import type { OrderbookQuotationMode } from "./clients/orderbook-client";
16
+ import type { AccountEvent, ConditionalOrderEvent, InstrumentEvent, LiquidationEvent, MarketStatsAllEvent, MarketStatsEvent, OHLCVEvent, OHLCVPriceType, OrderbookEvent, OrderEvent, PositionEvent, TradeEvent, TwapOrderEvent, UserBalanceEvent, UserMovementEvent } from "./events";
17
+ export type MessageHandler<T> = (data: T) => void;
18
+ export interface MonacoWebSocket {
19
+ /** Connect to the WebSocket server */
20
+ connect: () => Promise<void>;
21
+ /** Disconnect from the WebSocket server */
22
+ disconnect: () => void;
23
+ /** Check if currently connected */
24
+ isConnected: () => boolean;
25
+ /** Get current websocket connection status */
26
+ getStatus: () => WebSocketStatus;
27
+ /** Set (or clear) the session keypair used to authenticate the connection */
28
+ setSessionKeypair: (credentials: SessionCredentials | undefined) => void;
29
+ /** Subscribe to order events (requires authentication) */
30
+ orders: (tradingPairId: string, tradingMode: TradingMode, handler: MessageHandler<OrderEvent>) => () => void;
31
+ /** Subscribe to orderbook events (public) */
32
+ orderbook: (tradingPairId: string, tradingMode: TradingMode, magnitude: number, quotationMode: OrderbookQuotationMode, handler: MessageHandler<OrderbookEvent>) => () => void;
33
+ /** Subscribe to OHLCV candlestick events (public) */
34
+ ohlcv: (tradingPairId: string, tradingMode: TradingMode, interval: Interval, handler: MessageHandler<OHLCVEvent>, priceType?: OHLCVPriceType) => () => void;
35
+ /** Subscribe to trade events (public) */
36
+ trades: (tradingPairId: string, handler: MessageHandler<TradeEvent>) => () => void;
37
+ /** Subscribe to user movement events (requires authentication) */
38
+ movements: (handler: MessageHandler<UserMovementEvent>) => () => void;
39
+ /** Subscribe to user order events for all trading pairs (requires authentication) */
40
+ userOrders: (handler: MessageHandler<OrderEvent>) => () => void;
41
+ /** Subscribe to user balance events (requires authentication) */
42
+ balances: (handler: MessageHandler<UserBalanceEvent>) => () => void;
43
+ /** Subscribe to conditional TP/SL lifecycle events (requires authentication) */
44
+ conditionalOrders: (handler: MessageHandler<ConditionalOrderEvent>, tradingPairId?: string) => () => void;
45
+ /** Subscribe to TWAP parent-order lifecycle events (requires authentication) */
46
+ twapOrders: (handler: MessageHandler<TwapOrderEvent>, tradingPairId?: string) => () => void;
47
+ /** Subscribe to position state updates (requires authentication); omit `tradingPairId` for all pairs */
48
+ positions: (handler: MessageHandler<PositionEvent>, tradingPairId?: string) => () => void;
49
+ /** Subscribe to liquidation alerts (requires authentication); omit `tradingPairId` for all pairs */
50
+ liquidations: (handler: MessageHandler<LiquidationEvent>, tradingPairId?: string) => () => void;
51
+ /** Subscribe to account-level margin health updates for the authenticated user (requires authentication) */
52
+ account: (handler: MessageHandler<AccountEvent>) => () => void;
53
+ /** Subscribe to market lifecycle + config changes (public); omit `tradingPairId` for all markets */
54
+ instruments: (handler: MessageHandler<InstrumentEvent>, tradingPairId?: string) => () => void;
55
+ /** Subscribe to per-market statistics for one trading pair (public) */
56
+ marketStats: (tradingPairId: string, handler: MessageHandler<MarketStatsEvent>) => () => void;
57
+ /** Subscribe to the all-markets statistics summary (public) */
58
+ marketStatsAll: (handler: MessageHandler<MarketStatsAllEvent>) => () => void;
59
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Monaco WebSocket client surface.
3
+ *
4
+ * The canonical, hand-written subscription interface implemented by
5
+ * `@0xmonaco/core`'s `createMonacoWebSocket` and exposed as `MonacoSDK.ws`.
6
+ * It lives here (not in `@0xmonaco/core`) so every package types the same
7
+ * surface — the channel-coverage lock in
8
+ * `tests/websocket/channel-coverage.test.ts` parses this file as the source
9
+ * of truth for the SDK's channel surface.
10
+ */
@@ -16,6 +16,24 @@
16
16
  export interface AccountEventData {
17
17
  /** Margin account this update describes (UUID) */
18
18
  marginAccountId: string;
19
+ /**
20
+ * Monotonic per-account counter within one producer run. It advances only on
21
+ * published frames, may SKIP values (at-most-once delivery, conflation), and
22
+ * resets to zero when the producer restarts — which can happen while your
23
+ * WebSocket stays connected, because the socket is owned by a different
24
+ * service. It is therefore never a gap detector and never a cross-restart
25
+ * total order.
26
+ *
27
+ * Dedupe rule: order frames per account by `updatedAt`, newest wins; use
28
+ * `sequence` only to break ties between frames carrying the SAME `updatedAt`
29
+ * (those come from the same producer run).
30
+ *
31
+ * There is no subscribe-time snapshot: an account with active exposure
32
+ * delivers a baseline within ~30s (keepalive republish), but a FLAT account
33
+ * is silent until it re-activates — fetch the margin-accounts REST endpoint
34
+ * when an immediate flat baseline is needed.
35
+ */
36
+ sequence: number;
19
37
  /** Mark-inclusive account equity: collateral + unrealized PnL + funding (decimal string) */
20
38
  equity: string;
21
39
  /** Raw deposited collateral in USD (decimal string) */
@@ -62,10 +62,21 @@ export interface CommonOrderEventData {
62
62
  /**
63
63
  * Client-assigned correlation handle, echoed so an event can be matched to
64
64
  * the request that placed the order without a round trip to `getOrder`.
65
- * Carried on every order event that inherits these fields — placed, taker and
66
- * maker fills, cancelled, rejected and expired — so a submit whose HTTP
67
- * response was lost can be resolved from the stream alone. Omitted when the
68
- * order carried none. Wire: `client_order_id`.
65
+ * Carried on every order event that inherits these fields — the `OrderPlaced`
66
+ * acknowledgement, taker and maker fills, cancellation, expiry, and the
67
+ * `OrderRejected` raised after acceptance — an IOC/FOK that cannot fill, or a
68
+ * MARKET order whose apparent liquidity is invalidated by maker-risk
69
+ * revalidation — so a matching event is positive proof that a submit whose HTTP
70
+ * response was lost did land. Two separate caveats: a create rejected *before* acceptance
71
+ * (malformed, post-only would cross, handle conflict, a plain MARKET submit
72
+ * with no liquidity) emits no event at all; and the stream is not replayable, so a subscription opened
73
+ * late or gapped misses events it would otherwise have carried — and because
74
+ * the fan-out is non-persistent Core NATS, the service can re-establish an
75
+ * ended upstream subscription without closing your socket, so events can be
76
+ * missed while the connection still looks healthy. A matching event is
77
+ * positive proof the order was accepted; silence is NEVER evidence it was
78
+ * not, and no client-observable condition makes it so. Never resubmit on
79
+ * silence. Omitted when the order carried none. Wire: `client_order_id`.
69
80
  */
70
81
  clientOrderId?: string;
71
82
  }
@@ -1,8 +1,14 @@
1
- import type { OrderSide, TradingMode, TwapOrderState } from "../../trading";
1
+ import type { OrderSide, TradingMode, TwapExecutionStyle, TwapOrderState } from "../../trading";
2
2
  /**
3
3
  * Mutation that produced a TWAP parent-order snapshot.
4
+ *
5
+ * PASSIVE-style parents add three reasons: `passive_child_placed` (a
6
+ * post-only child now rests at the touch), `child_repriced` (the resting
7
+ * child atomically moved to the new touch), and `passive_fill` (maker fills
8
+ * on the resting child folded into the parent). Taker sweeps and crossing
9
+ * takes surface as the existing `slice_placed`.
4
10
  */
5
- export type TwapOrderEventReason = "created" | "slice_placed" | "slice_skipped" | "cancelled" | "completed";
11
+ export type TwapOrderEventReason = "created" | "slice_placed" | "slice_skipped" | "passive_child_placed" | "child_repriced" | "passive_fill" | "cancelled" | "completed" | "triggered" | "trigger_expired";
6
12
  /**
7
13
  * TWAP parent-order snapshot carried by a `twap_orders` WebSocket event.
8
14
  * The server publishes the full read model on every lifecycle transition
@@ -34,6 +40,8 @@ export interface TwapOrderEventData {
34
40
  strategyKey?: string;
35
41
  clientTwapId?: string;
36
42
  randomize: boolean;
43
+ /** Child execution style: "TAKER" (banded MARKET slices) or "PASSIVE" (post-only children at the touch, taker sweep at each slice deadline) */
44
+ executionStyle: TwapExecutionStyle;
37
45
  /** Window start (ISO 8601) */
38
46
  startAt: string;
39
47
  /** Window end (ISO 8601). Execution stops hard at this time. */
@@ -50,6 +58,12 @@ export interface TwapOrderEventData {
50
58
  state: TwapOrderState;
51
59
  /** Terminal annotation, e.g. "ended with shortfall 1.5"; absent for non-terminal parents */
52
60
  terminalReason?: string;
61
+ /** Conditional configuration + activation stamp (parity with the REST read
62
+ * model). All absent on unconditional parents. */
63
+ triggerPrice?: string;
64
+ triggerDirection?: "ABOVE" | "BELOW";
65
+ conditionalExpiry?: string;
66
+ triggeredAt?: string;
53
67
  createdAt: string;
54
68
  updatedAt: string;
55
69
  cancelledAt?: string;
@@ -4,5 +4,6 @@
4
4
  * Fundamental definitions for Websocket connections, errors and events.
5
5
  */
6
6
  export * from "./base";
7
+ export * from "./client";
7
8
  export * from "./clients/orderbook-client";
8
9
  export * from "./events";
@@ -4,5 +4,6 @@
4
4
  * Fundamental definitions for Websocket connections, errors and events.
5
5
  */
6
6
  export * from "./base";
7
+ export * from "./client";
7
8
  export * from "./clients/orderbook-client";
8
9
  export * from "./events";
@@ -1505,8 +1505,16 @@ export interface paths {
1505
1505
  * Failure semantics: an item that fails validation, or whose original
1506
1506
  * cannot be found, leaves the original resting. An item whose replacement
1507
1507
  * fails to PLACE (for example insufficient balance or self-trade
1508
- * prevention) reports the error with its original already cancelled — the
1509
- * original is never silently left resting after a failed replacement.
1508
+ * prevention) reports the error with its original already cancelled.
1509
+ *
1510
+ * POST_ONLY_WOULD_CROSS is the exception: a post-only replacement that
1511
+ * would cross is refused BEFORE the cancel pass, against the book as it
1512
+ * will stand once the batch's own cancels are applied, so the item
1513
+ * normally reports the error with its original still resting. It is not a
1514
+ * guarantee — the pre-cancel check cannot see what pass 2 will insert or
1515
+ * consume, nor an original that fails to cancel, and the same original
1516
+ * listed twice is judged per occurrence — so confirm against open orders
1517
+ * rather than relying on the code alone.
1510
1518
  */
1511
1519
  post: operations["batch_replace_orders"];
1512
1520
  delete?: never;
@@ -2790,7 +2798,7 @@ export interface components {
2790
2798
  */
2791
2799
  postOnly?: boolean | null;
2792
2800
  /**
2793
- * @description Client-assigned correlation handle, echoed back on order reads (detail and list) and on order WebSocket events. At most 64 characters from [A-Za-z0-9._:-]; surrounding whitespace is trimmed before storage, and a blank or whitespace-only value is treated as absent. Monaco stores and returns this value but does NOT de-duplicate on it and does not enforce uniqueness — it correlates a response to a request, it does not make a retry safe. A create whose response was lost must still be reconciled against ListOrders before resubmitting.
2801
+ * @description Client-assigned correlation handle, echoed back on order reads (detail and list) and on order WebSocket events. At most 64 characters from [A-Za-z0-9._:-]; surrounding whitespace is trimmed before storage, and a blank or whitespace-only value is treated as absent. Uniqueness is enforced only among your orders that are RESTING on the book: an item reusing a value another of your resting orders still holds fails that item alone — the batch itself returns 2xx / OK and the offending item's result slot carries error.code CLIENT_ORDER_ID_CONFLICT; no transport-level 409 / ALREADY_EXISTS is raised. An order that never rests — MARKET, IOC/FOK, or a LIMIT that fills completely on arrival — does not take the handle, and the value is released the moment any order reaches a terminal state. It is therefore NOT an idempotency key: resubmitting after a lost response can execute a second time. Reconcile a lost response against the order WebSocket stream, which carries this value on the submit acknowledgement and on fills, including for orders that never rest; order history is replica-backed and can omit an order that did land. The stream is not replayable and has no sequence number to backfill from, and its fan-out is non-persistent Core NATS: the service can re-establish an ended upstream subscription without closing your socket, so events can be missed while your connection still looks healthy. A matching event is therefore positive proof the order was accepted, but silence is NEVER evidence it was not, and no client-observable condition makes it so. Absent positive evidence the outcome is unresolved: hold and escalate rather than resubmitting. Rejections split in two: an item rejected before acceptance (malformed, post-only would cross, handle conflict, a plain MARKET submit with no liquidity, rejected during pricing) fails only that item — a per-item error in an otherwise-successful response — emits no event and is never written to order history (an item rejected AFTER acceptance is persisted with status REJECTED, so only the pre-acceptance class is absent); an accepted LIMIT with IOC or FOK that cannot fill, or an accepted MARKET order whose apparent liquidity is invalidated by maker-risk revalidation, reports matchResult.status REJECTED in its result slot and emits OrderPlaced then OrderRejected, both carrying this value. Neither the batch's 2xx nor a populated result slot therefore means the order executed. Where no surface is conclusive, do not resubmit.
2794
2802
  * @example quote-btc-1130-a
2795
2803
  */
2796
2804
  clientOrderId?: string | null;
@@ -2869,7 +2877,7 @@ export interface components {
2869
2877
  */
2870
2878
  postOnly?: boolean | null;
2871
2879
  /**
2872
- * @description Client-assigned correlation handle, echoed back on order reads (detail and list) and on order WebSocket events. At most 64 characters from [A-Za-z0-9._:-]; surrounding whitespace is trimmed before storage, and a blank or whitespace-only value is treated as absent. Monaco stores and returns this value but does NOT de-duplicate on it and does not enforce uniqueness — it correlates a response to a request, it does not make a retry safe. A create whose response was lost must still be reconciled against ListOrders before resubmitting. A replacement is a new order with a new id, so it carries its own value and inherits nothing from the original — restate it to keep the handle.
2880
+ * @description Client-assigned correlation handle, echoed back on order reads (detail and list) and on order WebSocket events. At most 64 characters from [A-Za-z0-9._:-]; surrounding whitespace is trimmed before storage, and a blank or whitespace-only value is treated as absent. Uniqueness is enforced only among your orders that are RESTING on the book: an item reusing a value another of your resting orders still holds fails that item alone — the batch itself returns 2xx / OK and the offending item's result slot carries error.code CLIENT_ORDER_ID_CONFLICT; no transport-level 409 / ALREADY_EXISTS is raised. An order that never rests — MARKET, IOC/FOK, or a LIMIT that fills completely on arrival — does not take the handle, and the value is released the moment any order reaches a terminal state. It is therefore NOT an idempotency key, though on this replace path a retry cannot double-execute: the request names the original order id, and the sequencer revalidates that original in memory and on the book at sequence time, so once the first replacement succeeds the original is gone and a retry is rejected with ORDER_NOT_FOUND rather than placing a second order. That code is itself ambiguous — the original may instead have filled or been cancelled — so the risk here is acting on a stale view, not duplicate execution. Reconcile a lost response against the order WebSocket stream, which carries this value on the submit acknowledgement and on fills, including for orders that never rest; order history is replica-backed and can omit an order that did land. The stream is not replayable and has no sequence number to backfill from, and its fan-out is non-persistent Core NATS: the service can re-establish an ended upstream subscription without closing your socket, so events can be missed while your connection still looks healthy. A matching event is therefore positive proof the order was accepted, but silence is NEVER evidence it was not, and no client-observable condition makes it so. Absent positive evidence the outcome is unresolved: hold and escalate rather than resubmitting. A replace item carries no order type or time-in-force and its original must still be RESTING, so the IOC/FOK and MARKET post-acceptance rejection shapes are unreachable here. Failures split by WHEN they occur, and the difference decides whether your original survives. Before sequencing: a malformed value is caught up front and rejects the whole batch with HTTP 400 / gRPC INVALID_ARGUMENT, and a per-item validation failure fails that item with no mutation and no event. A pre-cancel gate then drops two more classes before anything is cancelled — a handle conflict, and a post-only replacement that would cross the book as it will stand once this batch's originals are cancelled — so in the ordinary POST_ONLY_WOULD_CROSS case the item fails with its original still RESTING and untouched. After that the endpoint is CANCEL-FIRST: the original is cancelled in pass 1, so a residual placement failure then — a self-trade rejection, or a crossing that only became apparent in pass 2 — leaves the original CANCELLED and emits its cancellation events (terminal reason 'replaced') while the item reports the placement error and no replacement is placed. Never assume a failed item left your original resting; read results[] and the stream. Single ReplaceOrder differs: it is atomic, and a rejected replacement leaves the original untouched. Where no surface is conclusive, do not resubmit. A replacement is a new order with a new id, so it carries its own value and inherits nothing from the original — restate it to keep the handle.
2873
2881
  * @example quote-btc-1130-a
2874
2882
  */
2875
2883
  clientOrderId?: string | null;
@@ -3296,7 +3304,7 @@ export interface components {
3296
3304
  */
3297
3305
  postOnly?: boolean | null;
3298
3306
  /**
3299
- * @description Client-assigned correlation handle, echoed back on order reads (detail and list) and on order WebSocket events. At most 64 characters from [A-Za-z0-9._:-]; surrounding whitespace is trimmed before storage, and a blank or whitespace-only value is treated as absent. Monaco stores and returns this value but does NOT de-duplicate on it and does not enforce uniqueness — it correlates a response to a request, it does not make a retry safe. A create whose response was lost must still be reconciled against ListOrders before resubmitting.
3307
+ * @description Client-assigned correlation handle, echoed back on order reads (detail and list) and on order WebSocket events. At most 64 characters from [A-Za-z0-9._:-]; surrounding whitespace is trimmed before storage, and a blank or whitespace-only value is treated as absent. Uniqueness is enforced only among your orders that are RESTING on the book: a create or replace reusing a value another of your resting orders still holds is rejected with HTTP 409 / gRPC ALREADY_EXISTS and the code CLIENT_ORDER_ID_CONFLICT. An order that never rests — MARKET, IOC/FOK, or a LIMIT that fills completely on arrival — does not take the handle, and the value is released the moment any order reaches a terminal state. It is therefore NOT an idempotency key: resubmitting after a lost response can execute a second time. Reconcile a lost response against the order WebSocket stream, which carries this value on the submit acknowledgement and on fills, including for orders that never rest; order history is replica-backed and can omit an order that did land. The stream is not replayable and has no sequence number to backfill from, and its fan-out is non-persistent Core NATS: the service can re-establish an ended upstream subscription without closing your socket, so events can be missed while your connection still looks healthy. A matching event is therefore positive proof the order was accepted, but silence is NEVER evidence it was not, and no client-observable condition makes it so. Absent positive evidence the outcome is unresolved: hold and escalate rather than resubmitting. Rejections split in two: one rejected before acceptance (malformed, post-only would cross, handle conflict, a plain MARKET submit with no liquidity, rejected during pricing) fails the request, emits no event and is never written to order history (an order rejected AFTER acceptance is persisted with status REJECTED, so only the pre-acceptance class is absent); an accepted LIMIT with IOC or FOK that cannot fill, or an accepted MARKET order whose apparent liquidity is invalidated by maker-risk revalidation, returns 2xx with matchResult.status REJECTED and emits OrderPlaced then OrderRejected, both carrying this value. A 2xx therefore does not mean the order executed. Where no surface is conclusive, do not resubmit.
3300
3308
  * @example quote-btc-1130-a
3301
3309
  */
3302
3310
  clientOrderId?: string | null;
@@ -3444,6 +3452,28 @@ export interface components {
3444
3452
  * @example oms-3f6a1c
3445
3453
  */
3446
3454
  clientTwapId?: string | null;
3455
+ /**
3456
+ * @description Child execution style. TAKER (default): each slice executes immediately as a banded MARKET order. PASSIVE: each slice rests as a post-only limit at the same-side touch (maker where possible, repriced to follow the touch, never beyond the parent limit price or the protective band), and the leftover is swept as a banded MARKET order at the slice deadline. Passive parents use a slower default slice cadence (~60s).
3457
+ * @example PASSIVE
3458
+ * @enum {string|null}
3459
+ */
3460
+ executionStyle?: "TAKER" | "PASSIVE" | null;
3461
+ /**
3462
+ * @description Price-triggered activation: the parent waits (PENDING) until the reference price reaches or crosses this price in triggerDirection, then runs a floating window of durationSeconds from the trigger instant. Requires triggerDirection and durationSeconds; incompatible with startTime/endTime. Rejected if the condition is already met at creation. Margin markets arm against the oracle mark and the create is rejected while the market has no mark yet (retry once one is published); once the parent is waiting, activation evaluates the mark when it is available and the venue reference price (book-derived median, last-trade fallback) when it is not, so a mark outage cannot leave a live trigger unwatched. Spot markets use the venue reference price throughout.
3463
+ * @example 98000.00
3464
+ */
3465
+ triggerPrice?: string | null;
3466
+ /**
3467
+ * @description Which way the reference price must cross triggerPrice to activate: ABOVE (activate when price rises to or through it) or BELOW (falls to or through it). Required with triggerPrice; no exact print is required — a reference price observed at or beyond the level activates. The condition is evaluated on the engine's own polling cadence rather than on every market tick, so a price that crosses and reverts entirely between two observations is not seen; there is no high/low watermark.
3468
+ * @example BELOW
3469
+ * @enum {string|null}
3470
+ */
3471
+ triggerDirection?: "ABOVE" | "BELOW" | null;
3472
+ /**
3473
+ * @description Deadline for the trigger to fire (RFC 3339, UTC only — Z suffix; non-UTC offsets rejected). If the trigger has not fired by then the parent cancels with terminal reason 'trigger expired'. Only valid with triggerPrice; must be in the future and at most the maximum window (default 30 days) from creation, which is also the default when omitted.
3474
+ * @example 2026-09-01T00:00:00Z
3475
+ */
3476
+ conditionalExpiry?: string | null;
3447
3477
  };
3448
3478
  CreateTwapOrderResponse: {
3449
3479
  /**
@@ -3463,7 +3493,7 @@ export interface components {
3463
3493
  */
3464
3494
  message?: string | null;
3465
3495
  /**
3466
- * @description Initial parent state: always PENDING at create; the parent activates on its first attempted slice
3496
+ * @description Initial parent state: always PENDING at create. An unconditional parent activates on its first attempted slice; a conditional one (triggerPrice set) stays PENDING until its trigger fires.
3467
3497
  * @example PENDING
3468
3498
  */
3469
3499
  state?: string | null;
@@ -3484,12 +3514,12 @@ export interface components {
3484
3514
  */
3485
3515
  plannedSlices?: number | null;
3486
3516
  /**
3487
- * @description Planned time of the first slice (ISO 8601)
3517
+ * @description Planned time of the first slice (ISO 8601). PROVISIONAL for a conditional parent (triggerPrice set): its window floats from the trigger instant, which is unknown at create, so this is computed from the provisional [create, create + durationSeconds] window and is re-anchored when the trigger fires. Read the armed window back from the TWAP read model (startAt / endAt / triggeredAt) instead of scheduling on this value.
3488
3518
  * @example 2026-08-01T10:00:27Z
3489
3519
  */
3490
3520
  firstSliceAt?: string | null;
3491
3521
  /**
3492
- * @description Resolved window end (ISO 8601). Execution never continues past it.
3522
+ * @description Resolved window end (ISO 8601). Execution never continues past it. PROVISIONAL for a conditional parent (triggerPrice set) for the same reason as firstSliceAt: the real window is [trigger instant, trigger instant + durationSeconds] and is re-anchored on activation.
3493
3523
  * @example 2026-08-01T11:00:00Z
3494
3524
  */
3495
3525
  endTime?: string | null;
@@ -4399,7 +4429,7 @@ export interface components {
4399
4429
  */
4400
4430
  remainingQuantityRaw?: string | null;
4401
4431
  /**
4402
- * @description Client-assigned correlation handle as stored: the value supplied on create or replace, with surrounding whitespace trimmed. Absent when the order carried none, including every order placed before the field was accepted on write. Not unique: Monaco neither de-duplicates nor enforces uniqueness, so several orders may share one value and a lookup by it can be ambiguous.
4432
+ * @description Client-assigned correlation handle as stored: the value supplied on create or replace, with surrounding whitespace trimmed. Absent when the order carried none, including every order placed before the field was accepted on write. Uniqueness is enforced only among your orders that are RESTING on the book, so several of your orders may share one value over time and a lookup by it can be ambiguous: an order that never rests never takes the handle, and the value is released the moment any order reaches a terminal state. It is a correlation handle, not an idempotency key.
4403
4433
  * @example quote-btc-1130-a
4404
4434
  */
4405
4435
  clientOrderId?: string | null;
@@ -6455,7 +6485,7 @@ export interface components {
6455
6485
  };
6456
6486
  ReplaceOrderRequest: {
6457
6487
  /**
6458
- * @description Client-assigned correlation handle, echoed back on order reads (detail and list) and on order WebSocket events. At most 64 characters from [A-Za-z0-9._:-]; surrounding whitespace is trimmed before storage, and a blank or whitespace-only value is treated as absent. Monaco stores and returns this value but does NOT de-duplicate on it and does not enforce uniqueness — it correlates a response to a request, it does not make a retry safe. A create whose response was lost must still be reconciled against ListOrders before resubmitting. A replacement is a new order with a new id, so it carries its own value and inherits nothing from the original — restate it to keep the handle.
6488
+ * @description Client-assigned correlation handle, echoed back on order reads (detail and list) and on order WebSocket events. At most 64 characters from [A-Za-z0-9._:-]; surrounding whitespace is trimmed before storage, and a blank or whitespace-only value is treated as absent. Uniqueness is enforced only among your orders that are RESTING on the book: a create or replace reusing a value another of your resting orders still holds is rejected with HTTP 409 / gRPC ALREADY_EXISTS and the code CLIENT_ORDER_ID_CONFLICT. An order that never rests — MARKET, IOC/FOK, or a LIMIT that fills completely on arrival — does not take the handle, and the value is released the moment any order reaches a terminal state. It is therefore NOT an idempotency key, though on this replace path a retry cannot double-execute: the request names the original order id, and the sequencer revalidates that original in memory and on the book at sequence time, so once the first replacement succeeds the original is gone and a retry is rejected with ORDER_NOT_FOUND rather than placing a second order. That code is itself ambiguous — the original may instead have filled or been cancelled — so the risk here is acting on a stale view, not duplicate execution. Reconcile a lost response against the order WebSocket stream, which carries this value on the submit acknowledgement and on fills, including for orders that never rest; order history is replica-backed and can omit an order that did land. The stream is not replayable and has no sequence number to backfill from, and its fan-out is non-persistent Core NATS: the service can re-establish an ended upstream subscription without closing your socket, so events can be missed while your connection still looks healthy. A matching event is therefore positive proof the order was accepted, but silence is NEVER evidence it was not, and no client-observable condition makes it so. Absent positive evidence the outcome is unresolved: hold and escalate rather than resubmitting. A replacement carries no order type or time-in-force and its original must still be RESTING, so the post-acceptance rejection shapes are unreachable here: the reachable failures are all pre-acceptance — malformed, post-only would cross, handle conflict, or the original no longer resting (ORDER_NOT_FOUND) — and each fails the request, emits no event and is never written to order history (an order rejected AFTER acceptance is persisted with status REJECTED, so only the pre-acceptance class is absent). Where no surface is conclusive, do not resubmit. A replacement is a new order with a new id, so it carries its own value and inherits nothing from the original — restate it to keep the handle.
6459
6489
  * @example quote-btc-1130-a
6460
6490
  */
6461
6491
  clientOrderId?: string | null;
@@ -7460,6 +7490,19 @@ export interface components {
7460
7490
  cancelledAt?: string | null;
7461
7491
  /** @description Completion timestamp (ISO 8601) */
7462
7492
  completedAt?: string | null;
7493
+ /**
7494
+ * @description Child execution style: TAKER (banded MARKET slices) or PASSIVE (post-only children at the touch with a taker sweep at each slice deadline)
7495
+ * @example TAKER
7496
+ */
7497
+ executionStyle?: string | null;
7498
+ /** @description Price-triggered activation level, when this parent is conditional */
7499
+ triggerPrice?: string | null;
7500
+ /** @description Trigger crossing direction: ABOVE or BELOW */
7501
+ triggerDirection?: string | null;
7502
+ /** @description Deadline for the trigger to fire (ISO 8601 UTC); reaching it cancels the parent with terminal reason 'trigger expired' */
7503
+ conditionalExpiry?: string | null;
7504
+ /** @description When the trigger fired and the floating window started (ISO 8601 UTC); unset while waiting */
7505
+ triggeredAt?: string | null;
7463
7506
  };
7464
7507
  UpdateLimitRequest: {
7465
7508
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xmonaco/types",
3
- "version": "1.0.46",
3
+ "version": "1.0.47",
4
4
  "type": "module",
5
5
  "homepage": "https://docs.0xmonaco.com/sdk/typescript",
6
6
  "main": "./dist/index.js",
@@ -16,7 +16,7 @@
16
16
  "lint": "biome lint ."
17
17
  },
18
18
  "dependencies": {
19
- "@0xmonaco/contracts": "1.0.46",
19
+ "@0xmonaco/contracts": "1.0.47",
20
20
  "zod": "^4.1.12"
21
21
  },
22
22
  "peerDependencies": {