@0xmonaco/types 1.0.47 → 1.0.50-develop.9c1b239

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.
@@ -32,6 +32,42 @@ export interface MarginAccountSummary {
32
32
  unrealizedPnl: string;
33
33
  realizedPnl: string;
34
34
  updatedAt: string;
35
+ /**
36
+ * The collateral still available to open NEW orders in this risk bucket:
37
+ * the largest increase in the bucket's worst-case order reserve the risk
38
+ * engine's admission gate accepts, automatic top-up from the parent margin
39
+ * account's unallocated capacity included. Zero while the account or bucket
40
+ * is frozen for liquidation, and for an isolated bucket whose market is
41
+ * halted (a cross bucket's market is chosen per order, so a halt cannot be
42
+ * folded into its figure — a halted pair still refuses orders).
43
+ *
44
+ * The trading-side sibling of `withdrawableCollateral`, and deliberately a
45
+ * different figure: this one credits an unrealized gain in full, because a
46
+ * gain is legitimate initial margin for new positions, while a withdrawal
47
+ * never counts one. It already contains the bucket's live free collateral —
48
+ * do not add `freeCollateral` or `unrealizedPnl` on top. It can also
49
+ * legitimately differ from this row's `freeCollateral`, a persisted
50
+ * reconstruction that cannot see the engine's worst-case resting-order
51
+ * reserve.
52
+ *
53
+ * NOT additive across rows: every bucket's figure includes the SAME parent
54
+ * unallocated headroom, so summing rows multiply-counts it, and committing
55
+ * collateral in one bucket shrinks its siblings' figures.
56
+ *
57
+ * This is a requirement budget, not an order size: an order is charged the
58
+ * increase it causes in the bucket's worst-case per-pair reserve, so a
59
+ * reducing, reduce-only, or opposite-side order sheltered by a larger
60
+ * resting ladder needs less or none of it (and can be admitted even when
61
+ * this field is zero), while an order crossing a losing position can need
62
+ * more than its own margin-plus-fee. Divide by a market's initial margin
63
+ * rate for indicative notional capacity; the authoritative per-order answer
64
+ * remains `simulateRiskBucketOrderRisk`.
65
+ *
66
+ * Present only on risk-bucket rows served from a live risk engine snapshot;
67
+ * absent (the key is omitted, never null) on parent rows and on
68
+ * persisted-fallback reads.
69
+ */
70
+ availableOrderCollateral?: string;
35
71
  }
36
72
  export interface ListMarginAccountsParams {
37
73
  page?: number;
@@ -95,17 +131,43 @@ export interface TransferCollateralToParentMarginAccountRequest {
95
131
  asset: string;
96
132
  amount: string;
97
133
  }
134
+ /**
135
+ * Fund a pair's isolated risk bucket from the parent margin account's
136
+ * unallocated collateral (no wallet movement; the bucket is created if
137
+ * needed). What the money becomes when the bucket holds an open position is
138
+ * stated by `applyToPositionMargin` — the two intents want opposite fates for
139
+ * the same dollars. Either way the liquidation cushion improves identically.
140
+ */
98
141
  export interface TransferCollateralToIsolatedRiskBucketRequest extends TransferCollateralToParentMarginAccountRequest {
99
142
  marginMode?: "ISOLATED";
100
143
  tradingPairId: string;
101
144
  strategyKey?: string;
102
145
  selectedTradingPairIds?: never;
146
+ /**
147
+ * `true` (and OMITTED — the default is the human "Adjust Margin" gesture):
148
+ * the amount is COMMITTED to the sole open position's stored margin.
149
+ * Effective leverage drops and stays down, initial margin required rises by
150
+ * the amount, free collateral is unchanged — new orders cannot spend it.
151
+ *
152
+ * `false`: plain allocation. Free collateral rises and the next order can
153
+ * spend it. Programmatic funding loops that top a bucket up to a free
154
+ * collateral target MUST pass `false`, or each top-up converts into
155
+ * requirement and the loop never converges.
156
+ *
157
+ * On a flat bucket both values are a plain allocation. The response's
158
+ * `positionMarginCredited` reports what actually happened — a credit can
159
+ * degrade to a plain allocation when the persisted position row is stale
160
+ * (close/reopen race).
161
+ */
162
+ applyToPositionMargin?: boolean;
103
163
  }
104
164
  export interface TransferCollateralToCrossRiskBucketRequest extends TransferCollateralToParentMarginAccountRequest {
105
165
  marginMode: "CROSS";
106
166
  selectedTradingPairIds: string[];
107
167
  tradingPairId?: never;
108
168
  strategyKey?: never;
169
+ /** Cross risk is pooled at bucket equity — there is no per-position margin; an explicit `true` is rejected. */
170
+ applyToPositionMargin?: never;
109
171
  }
110
172
  export type TransferCollateralToRiskBucketRequest = TransferCollateralToIsolatedRiskBucketRequest | TransferCollateralToCrossRiskBucketRequest;
111
173
  export interface TransferCollateralFromParentMarginAccountRequest {
@@ -125,6 +187,16 @@ export interface TransferCollateralResponse {
125
187
  newEquity: string;
126
188
  newTotalCollateralValue: string;
127
189
  newWithdrawableCollateral: string;
190
+ /**
191
+ * Whether the transfer was committed to a position's stored margin. Present
192
+ * only when a position-margin credit was in play: `true` — the credit
193
+ * landed; `false` — a credit was requested (or defaulted) but degraded to a
194
+ * plain allocation because the bucket's persisted position row was stale
195
+ * (close/reopen race) — re-issue the Adjust Margin once the new position
196
+ * row lands if the commitment still matters. Absent (never null) on plain
197
+ * allocations, parent deposits, and releases.
198
+ */
199
+ positionMarginCredited?: boolean;
128
200
  }
129
201
  export interface GetMarginAccountMovementsParams {
130
202
  movementType?: string;
@@ -201,8 +273,9 @@ export interface MarginAccountsAPI extends BaseAPI {
201
273
  getMarginAccountSummary(marginAccountId: string, params?: GetMarginAccountSummaryParams): Promise<MarginAccountSummary>;
202
274
  getAvailableCollateral(params?: GetAvailableCollateralParams): Promise<GetAvailableCollateralResponse>;
203
275
  /**
204
- * @deprecated Prefer transferCollateralToParentMarginAccount() or
205
- * transferCollateralToRiskBucket().
276
+ * @deprecated Use `transferCollateralToRiskBucket` for bucket funding
277
+ * (which now credits a sole open position's stored margin the same way) and
278
+ * `transferCollateralToParentMarginAccount` for wallet-to-margin deposits.
206
279
  */
207
280
  transferCollateralToMarginAccount(marginAccountId: string, request: TransferCollateralRequest): Promise<TransferCollateralResponse>;
208
281
  transferCollateralToParentMarginAccount(request: TransferCollateralToParentMarginAccountRequest): Promise<TransferCollateralResponse>;
@@ -203,6 +203,18 @@ export interface PortfolioRiskBucket {
203
203
  * partial withdrawals below it.
204
204
  */
205
205
  withdrawableCollateral: string;
206
+ /**
207
+ * The collateral still available to open NEW orders in this risk bucket —
208
+ * the same engine-served admission bound as
209
+ * `MarginAccountSummary.availableOrderCollateral` (see that field for the
210
+ * full semantics: an envelope delta with parent auto top-up included, NOT
211
+ * additive across rows, zero while frozen), truncated toward zero at quote
212
+ * decimals like `withdrawableCollateral` beside it.
213
+ *
214
+ * Present only when a live risk engine snapshot served the bound; absent
215
+ * (the key is omitted, never null) on persisted-fallback reads.
216
+ */
217
+ availableOrderCollateral?: string;
206
218
  }
207
219
  export interface PortfolioMargin {
208
220
  asOf: string;
@@ -109,7 +109,7 @@ export interface MonacoSDK {
109
109
  pitpass: PitpassAPI;
110
110
  /** Testnet faucet API */
111
111
  faucet: FaucetAPI;
112
- /** Public deposit-address registration (sweeper) API */
112
+ /** Deposit-address registration (sweeper) API; requires a session */
113
113
  sweeper: SweeperAPI;
114
114
  /** Public whitelist (waitlist) submission API */
115
115
  whitelist: WhitelistAPI;
@@ -1,43 +1,59 @@
1
1
  /**
2
2
  * Sweeper Types
3
3
  *
4
- * Types for the public deposit-address registration endpoint. Wire shapes are
4
+ * Types for the deposit-address registration endpoint. Wire shapes are
5
5
  * snake_case; these are the camelCase ergonomic forms.
6
6
  *
7
- * NOTE: This endpoint is **public (unauthenticated)**. The deposit address is
8
- * derived from the (application, user) pair and its destination is fixed in the
9
- * contract's own bytecode, so a caller can only ever route funds to the user
10
- * they already belong to. Abuse is bounded by a per-client rate limit and an
11
- * active-application check instead of authentication.
7
+ * NOTE: This endpoint is **authenticated**. The credited address is the calling
8
+ * session's own rather than a request field, so a caller can only ever register
9
+ * an address they hold the session key for.
12
10
  */
11
+ import type { DepositTarget } from "@0xmonaco/contracts";
13
12
  import type { BaseAPI } from "../api";
14
13
  /**
15
14
  * What happened to the registration.
16
15
  *
17
- * - `registered` — the pair was added; its deposit address is now monitored.
18
- * - `already_registered` — the pair was known before this call; nothing was
16
+ * - `registered` — the triple was added; its deposit address is now monitored.
17
+ * - `already_registered` — the triple was known before this call; nothing was
19
18
  * re-triggered.
20
19
  */
21
20
  export type RegisterSweeperStatus = "registered" | "already_registered";
22
- /** Body for a deposit-address registration. */
21
+ /**
22
+ * Body for a deposit-address registration.
23
+ *
24
+ * Deliberately tiny: the application and the credited address both come from
25
+ * the authenticated session (`login` takes the application's client id), so the
26
+ * only thing left to say is which ledger to aim at.
27
+ */
23
28
  export interface RegisterSweeperRequest {
24
29
  /**
25
- * The application's client id — the same identifier rollup deposits carry
26
- * and `login` takes. The deposit address is derived from these exact bytes
27
- * and the application lookup is an exact string match, so the spelling must
28
- * match the registered application precisely.
30
+ * Which ledger swept deposits ask to be credited to. Defaults to `"spot"`.
31
+ *
32
+ * `"margin"` asks for the parent margin account's collateral, skipping the
33
+ * separate `transferCollateralToParentMarginAccount` step. The target is part
34
+ * of the address derivation, so the two targets yield two different deposit
35
+ * addresses for the same pair, each carrying its own request. A `"spot"`
36
+ * address is never credited to margin.
37
+ *
38
+ * `"margin"` is a request rather than a guarantee: a deposit the backend
39
+ * cannot route to collateral — an unsupported collateral asset, or a margin
40
+ * account that fails validation — is credited to the spot wallet instead, so
41
+ * funds are never stranded. Read the balance back rather than treating the
42
+ * address as proof of where the credit landed.
43
+ *
44
+ * An unrecognized value is rejected (400) rather than falling back to spot,
45
+ * which would return an address pointed at a ledger the caller did not ask
46
+ * for.
29
47
  */
30
- clientId: string;
31
- /** Address credited on the rollup, and half of the deposit-address derivation */
32
- userAddress: string;
48
+ depositTarget?: DepositTarget;
33
49
  }
34
50
  /** Result of a deposit-address registration. */
35
51
  export interface RegisterSweeperResponse {
36
- /** Whether this call added the pair or it was known before */
52
+ /** Whether this call added the triple or it was known before */
37
53
  status: RegisterSweeperStatus;
38
54
  /**
39
- * The pair's deposit address. Stable, and valid to publish and fund before
40
- * any contract exists there.
55
+ * The deposit address for this (application, user, deposit target) triple.
56
+ * Stable, and valid to publish and fund before any contract exists there.
41
57
  */
42
58
  sweeperAddress: string;
43
59
  /**
@@ -48,20 +64,26 @@ export interface RegisterSweeperResponse {
48
64
  initialSweepCheck: boolean;
49
65
  }
50
66
  /**
51
- * Sweeper API interface. The register endpoint is public (no auth required).
67
+ * Sweeper API interface. The register endpoint requires authentication.
52
68
  */
53
69
  export interface SweeperAPI extends BaseAPI {
54
70
  /**
55
- * Registers an (application, user) pair so its deterministic deposit
56
- * address is monitored and every ERC20 deposit is swept into the rollup
57
- * automatically.
71
+ * Registers an (application, user, deposit target) triple so its
72
+ * deterministic deposit address is monitored and every ERC20 deposit is
73
+ * swept into the rollup automatically.
74
+ *
75
+ * The application and the credited address both come from the authenticated
76
+ * session, so this only ever registers the caller's own address under their
77
+ * own application. Call it with no arguments for a spot address.
58
78
  *
59
79
  * Returns immediately with the derived deposit address; the one-time
60
80
  * initial balance check runs in the background. Idempotent and safe to
61
81
  * retry: re-registering answers `already_registered` with the same address
62
- * and never re-triggers the initial check. An unknown client id — any
63
- * respelling of a real one included, the lookup is exact — throws (404),
64
- * and registrations are lightly rate-limited per client (429).
82
+ * and never re-triggers the initial check.
83
+ *
84
+ * Throws on an unrecognized `depositTarget` (before sending), when the
85
+ * session's application is no longer active (403), and when the endpoint's
86
+ * global admission limit is exceeded (429).
65
87
  */
66
- register(body: RegisterSweeperRequest): Promise<RegisterSweeperResponse>;
88
+ register(body?: RegisterSweeperRequest): Promise<RegisterSweeperResponse>;
67
89
  }
@@ -1,12 +1,10 @@
1
1
  /**
2
2
  * Sweeper Types
3
3
  *
4
- * Types for the public deposit-address registration endpoint. Wire shapes are
4
+ * Types for the deposit-address registration endpoint. Wire shapes are
5
5
  * snake_case; these are the camelCase ergonomic forms.
6
6
  *
7
- * NOTE: This endpoint is **public (unauthenticated)**. The deposit address is
8
- * derived from the (application, user) pair and its destination is fixed in the
9
- * contract's own bytecode, so a caller can only ever route funds to the user
10
- * they already belong to. Abuse is bounded by a per-client rate limit and an
11
- * active-application check instead of authentication.
7
+ * NOTE: This endpoint is **authenticated**. The credited address is the calling
8
+ * session's own rather than a request field, so a caller can only ever register
9
+ * an address they hold the session key for.
12
10
  */
@@ -168,6 +168,11 @@ export type ConditionalOrderState = "PENDING_PARENT" | "ACTIVE" | "TRIGGERING" |
168
168
  * - ACTIVE: inside the execution window; child slices are firing
169
169
  * - COMPLETED: window ended (fully filled or hard-stopped with a shortfall)
170
170
  * - CANCELLED: cancelled by the user before the window ended
171
+ *
172
+ * These are the values the server sends today, not a runtime guarantee:
173
+ * `@0xmonaco/core` parses the `twap_orders` WebSocket frame leniently, so a
174
+ * state added server-side after this version ships is delivered as-is rather
175
+ * than dropping the update (0XM-2628). Match it with a default branch.
171
176
  */
172
177
  export type TwapOrderState = "PENDING" | "ACTIVE" | "COMPLETED" | "CANCELLED";
173
178
  /**
@@ -45,6 +45,7 @@ export declare const TransferCollateralToRiskBucketSchema: z.ZodObject<{
45
45
  strategyKey: z.ZodOptional<z.ZodString>;
46
46
  marginMode: z.ZodOptional<z.ZodLiteral<"ISOLATED">>;
47
47
  selectedTradingPairIds: z.ZodOptional<z.ZodNever>;
48
+ applyToPositionMargin: z.ZodOptional<z.ZodBoolean>;
48
49
  }, z.core.$strict>, z.ZodObject<{
49
50
  asset: z.ZodString;
50
51
  amount: z.ZodString;
@@ -139,6 +140,7 @@ export declare const SimulateRiskBucketOrderRiskSchema: z.ZodObject<{
139
140
  strategyKey: z.ZodOptional<z.ZodString>;
140
141
  marginMode: z.ZodOptional<z.ZodLiteral<"ISOLATED">>;
141
142
  selectedTradingPairIds: z.ZodOptional<z.ZodNever>;
143
+ applyToPositionMargin: z.ZodOptional<z.ZodBoolean>;
142
144
  }, z.core.$strict>, z.ZodObject<{
143
145
  tradingPairId: z.ZodUUID;
144
146
  side: z.ZodEnum<{
@@ -51,6 +51,10 @@ const SelectedCrossTradingPairIdsSchema = z.array(UUIDSchema).min(1, "selectedTr
51
51
  const IsolatedRiskBucketRequestSchema = RiskBucketRequestSchema.extend({
52
52
  marginMode: z.literal("ISOLATED").optional(),
53
53
  selectedTradingPairIds: z.never().optional(),
54
+ // Omitted defaults server-side to true (the Adjust Margin gesture); false
55
+ // is the plain allocation programmatic funding loops need. The CROSS form
56
+ // stays strict-rejected (no per-position margin to commit to).
57
+ applyToPositionMargin: z.boolean().optional(),
54
58
  });
55
59
  const CrossRiskBucketScopeSchema = z.object({
56
60
  marginMode: z.literal("CROSS"),
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Types for vault operations including deposits, withdrawals, and balance management.
5
5
  */
6
+ import type { DepositTarget } from "@0xmonaco/contracts";
6
7
  import type { Address } from "viem";
7
8
  import type { BaseAPI } from "../api/index";
8
9
  import type { Balance, TransactionResult, WithdrawalRetryOptions, WithdrawResult } from "./responses";
@@ -13,8 +14,13 @@ import type { Balance, TransactionResult, WithdrawalRetryOptions, WithdrawResult
13
14
  * collateral (auto-creating the account if it does not exist yet). A deposit
14
15
  * that cannot be routed to margin (unsupported asset, etc.) safely falls back
15
16
  * to spot — funds are never lost.
17
+ *
18
+ * Re-exported from `@0xmonaco/contracts` rather than redeclared: the same
19
+ * value selects the on-chain routing hint for a direct deposit and the
20
+ * derivation of a sweeper deposit address, so one definition keeps the two
21
+ * from drifting into separately-maintained unions.
16
22
  */
17
- export type DepositTarget = "spot" | "margin";
23
+ export type { DepositTarget };
18
24
  /**
19
25
  * Options for a deposit.
20
26
  */
@@ -29,6 +29,55 @@ export interface WebSocketResyncInfo {
29
29
  }
30
30
  /** Handler invoked after a reconnect resumes the live stream. */
31
31
  export type ResyncHandler = (info: WebSocketResyncInfo) => void;
32
+ /**
33
+ * Machine-readable classification the server puts on every `Error` frame so a
34
+ * client can branch on the failure without string-matching the human message.
35
+ * Mirrors `ws-api`'s `WsErrorCode` enum, whose SCREAMING_SNAKE_CASE wire
36
+ * strings are pinned on the Rust side in `ws-api/src/websocket/protocol.rs`
37
+ * and cross-checked against this union by `@0xmonaco/core`'s
38
+ * `websocket-enum-parity` test.
39
+ */
40
+ export type WebSocketErrorCode =
41
+ /** A user-specific channel was subscribed before authenticating. */
42
+ "AUTH_REQUIRED"
43
+ /** The `Authenticate` handshake was rejected; the connection is closed after this frame. */
44
+ | "AUTH_FAILED"
45
+ /** The per-user concurrent-connection cap was reached; this connection is closed after the frame. */
46
+ | "CONNECTION_LIMIT"
47
+ /** The per-connection subscription-cardinality cap was reached. */
48
+ | "SUBSCRIPTION_LIMIT"
49
+ /** A subscription request was malformed or failed parameter validation. */
50
+ | "INVALID_SUBSCRIPTION"
51
+ /** An inbound frame could not be parsed, or an unsupported frame type was sent. */
52
+ | "INVALID_MESSAGE"
53
+ /**
54
+ * A previously-authenticated session became invalid after the handshake
55
+ * (revoked, expired, or the account was banned/deactivated). Re-authenticate
56
+ * rather than blindly reconnecting into the same rejection.
57
+ */
58
+ | "SESSION_INVALID"
59
+ /**
60
+ * The subscribe-time snapshot could not be read. The subscription is still
61
+ * active and live diffs flow, but the baseline is missing — refetch it (e.g.
62
+ * from REST) rather than assuming the stream started from a coherent state.
63
+ */
64
+ | "SNAPSHOT_UNAVAILABLE";
65
+ /**
66
+ * An `Error` frame the server sent on this connection.
67
+ *
68
+ * `code` is widened past {@link WebSocketErrorCode} on purpose: a code added
69
+ * server-side after this SDK version shipped is delivered as-is rather than
70
+ * dropped, so an older client still sees that something failed and can log it.
71
+ * Narrow with a `switch` on the known values and treat the default as unknown.
72
+ */
73
+ export interface WebSocketErrorInfo {
74
+ /** Stable classification of the failure. */
75
+ code: WebSocketErrorCode | (string & {});
76
+ /** Human-readable description; for logging and display, never for branching. */
77
+ message: string;
78
+ }
79
+ /** Handler invoked for every `Error` frame the server sends. */
80
+ export type ErrorHandler = (info: WebSocketErrorInfo) => void;
32
81
  /**
33
82
  * Reconnect/resync knobs and callbacks for the Monaco WebSocket client.
34
83
  *
@@ -62,6 +111,26 @@ export interface MonacoWebSocketConfig {
62
111
  * the snapshot was in flight are newer than the snapshot rows they duplicate.
63
112
  */
64
113
  onResync?: ResyncHandler;
114
+ /**
115
+ * Called for every `Error` frame the server sends on this connection.
116
+ *
117
+ * `Error` frames are connection-scoped, not channel-scoped, so they reach no
118
+ * subscription handler — without this callback a failed subscribe, an
119
+ * invalidated session, or an unreadable subscribe-time snapshot is invisible
120
+ * to the app. Branch on `code`:
121
+ *
122
+ * - `SNAPSHOT_UNAVAILABLE` — live diffs flow but the baseline is missing;
123
+ * refetch it. The subscription itself is fine.
124
+ * - `SESSION_INVALID` — re-authenticate rather than reconnect into the same
125
+ * rejection.
126
+ * - `AUTH_REQUIRED` — a rejected SUBSCRIBE, not an invalidated session: the
127
+ * channel was never registered, and this client still holds your handler,
128
+ * so it treats the channel as subscribed and sends no new `Subscribe`.
129
+ * Re-authenticating alone leaves it dead. Release the last handler for the
130
+ * channel and subscribe again after authenticating (0XM-2644 tracks doing
131
+ * this automatically).
132
+ */
133
+ onError?: ErrorHandler;
65
134
  }
66
135
  /**
67
136
  * Raw event message interface
@@ -42,11 +42,14 @@ export interface AccountEventData {
42
42
  freeCollateral: string;
43
43
  /**
44
44
  * Account distress ratio: maintenance margin required over equity (higher is
45
- * closer to liquidation, decimal string). When equity is non-positive the
46
- * quotient is undefined, so an account that still owes a maintenance
47
- * requirement saturates to the max-decimal sentinel
48
- * (`79228162514264337593543950335`, maximal distress) and an empty account
49
- * with no requirement is `0`. Clamp the sentinel before display.
45
+ * closer to liquidation, decimal string). The quotient saturates to the
46
+ * max-decimal sentinel (`79228162514264337593543950335`, maximal distress)
47
+ * whenever it cannot be computed or represented: an account still owing a
48
+ * maintenance requirement at zero or negative equity, and equally at
49
+ * near-zero POSITIVE equity where the true ratio exceeds the decimal range.
50
+ * An empty account with no requirement is `0`. Clamp the sentinel before
51
+ * display; treat any value at or above the liquidation threshold as maximal
52
+ * distress rather than distinguishing the sentinel's causes.
50
53
  */
51
54
  marginRatio: string;
52
55
  /** Maintenance margin required to keep the account solvent (decimal string) */
@@ -45,7 +45,7 @@ export interface UserBalanceEventData {
45
45
  /** Total balance in raw format (wei) */
46
46
  totalRaw: string;
47
47
  /** Reason for the balance update */
48
- reason: BalanceUpdateReason;
48
+ reason: BalanceUpdateReason | (string & {});
49
49
  /** Reference ID for related entity (e.g., order ID, deposit ID) */
50
50
  referenceId: string | null;
51
51
  /** Timestamp when the balance was updated (ISO 8601) */
@@ -1,32 +1,94 @@
1
1
  import type { ConditionalOrderConditionType, ConditionalOrderState, ConditionalOrderTriggerSource, OrderSide, OrderType, PositionSide, TimeInForce } from "../../trading";
2
+ /**
3
+ * The canonical `reason` values carried by a **live** conditional-order update.
4
+ *
5
+ * Not the complete set of strings the field can hold: the subscribe-time
6
+ * snapshot reuses this same data shape with the literal `"snapshot"`, and the
7
+ * wire field is a free-form server string rather than a closed enum, so this
8
+ * alias is documentation and a narrowing aid only. Match on it with a default
9
+ * branch; see `ConditionalOrderEventData.reason`.
10
+ */
2
11
  export type ConditionalOrderEventReason = "created" | "activated" | "cancelled" | "parent_cancelled" | "triggered" | "failed" | "oco_cancelled";
12
+ /**
13
+ * A conditional (TP/SL) order's current state.
14
+ *
15
+ * **The value unions below are the values the server can send today, not a
16
+ * runtime guarantee** — which is why each of those fields is typed
17
+ * `Union | (string & {})`: autocomplete still offers the known values, but a
18
+ * `switch` over one needs a `default` branch because an unrecognized value
19
+ * really can arrive (0XM-2628). `@0xmonaco/core` parses this frame leniently — an
20
+ * unrecognized `orderType`, `state`, `side`, `positionSide`, `conditionType`,
21
+ * `triggerSource`, `associationType` or `timeInForce` is passed through as-is
22
+ * rather than validated, because throwing inside the WebSocket message handler
23
+ * would drop the entire update with nothing surfaced to the consumer
24
+ * (0XM-2627). Most of these unions mirror an exhaustive server-side mapping, so
25
+ * a value outside one means the server gained a variant this SDK version
26
+ * predates. `orderType` is the exception — its mapping ends in a catch-all arm,
27
+ * so its completeness rests on producer validation instead; see that field's
28
+ * own note.
29
+ *
30
+ * Consequently: match on these fields with a `default` branch rather than
31
+ * relying on exhaustiveness, exactly as you would for the free-form `reason`.
32
+ * A dropped frame is a worse failure than an unhandled value, so the parser
33
+ * chooses the latter — the same trade the position, liquidation and
34
+ * market-stats parsers already make.
35
+ */
3
36
  export interface ConditionalOrderEventData {
4
37
  conditionalOrderId: string;
5
38
  tradingPairId: string;
6
39
  marginAccountId: string;
7
40
  positionId?: string;
8
41
  parentOrderId?: string;
9
- associationType?: "POSITION" | "PARENT_ORDER";
42
+ associationType?: "POSITION" | "PARENT_ORDER" | (string & {});
10
43
  linkedGroupId?: string;
11
- conditionType: ConditionalOrderConditionType;
12
- triggerSource: ConditionalOrderTriggerSource;
44
+ conditionType: ConditionalOrderConditionType | (string & {});
45
+ triggerSource: ConditionalOrderTriggerSource | (string & {});
13
46
  triggerPrice: string;
14
- side: OrderSide;
15
- positionSide: PositionSide;
16
- orderType: OrderType;
47
+ side: OrderSide | (string & {});
48
+ positionSide: PositionSide | (string & {});
49
+ /**
50
+ * Order shape the conditional order places when it triggers.
51
+ *
52
+ * `LIMIT` and `MARKET` are the complete set: both creation paths reject
53
+ * anything else — `orderType must be MARKET or LIMIT` from the TP/SL handler
54
+ * and `parent TP/SL order_type must be MARKET or LIMIT` from the matching
55
+ * engine's leg-shape check. The other server-side `OrderType` variants
56
+ * cannot reach this event.
57
+ *
58
+ * Unlike the other fields here, that rests on validation rather than on an
59
+ * exhaustive mapping: the server's `order_type` arm ends in a catch-all that
60
+ * Debug-formats and uppercases the variant, so were validation ever relaxed
61
+ * the value would arrive as e.g. `STOPLOSS` rather than the canonical
62
+ * `STOP_LOSS`. The parser passes such a value through untouched.
63
+ */
64
+ orderType: OrderType | (string & {});
17
65
  limitPrice?: string;
18
66
  quantity?: string;
19
67
  slippageToleranceBps?: number;
20
68
  reduceOnly: boolean;
21
- timeInForce?: Extract<TimeInForce, "GTC" | "IOC">;
22
- state: ConditionalOrderState;
69
+ /**
70
+ * Time in force for a `LIMIT` conditional order; absent for `MARKET`.
71
+ *
72
+ * The full `TimeInForce` enum, not the `GTC`/`IOC` subset the creation paths
73
+ * validate: this field mirrors an unconstrained `time_in_force` column that
74
+ * the server maps exhaustively over every variant, so a value written by any
75
+ * other path reaches the wire as-is. Narrow before relying on the subset.
76
+ */
77
+ timeInForce?: TimeInForce | (string & {});
78
+ state: ConditionalOrderState | (string & {});
23
79
  triggeredOrderId?: string;
24
80
  triggeredAt?: string;
25
81
  activatedAt?: string;
26
82
  cancelledAt?: string;
27
83
  expiresAt?: string;
28
84
  failureReason?: string;
29
- reason: ConditionalOrderEventReason;
85
+ /**
86
+ * What produced this update. Free-form on the wire — the server field is a
87
+ * plain string, not an enum — but a live update's canonical values are the
88
+ * ones listed on {@link ConditionalOrderEventReason}. The subscribe-time
89
+ * snapshot builds the same shape with `"snapshot"` instead.
90
+ */
91
+ reason: string;
30
92
  updatedAt: string;
31
93
  }
32
94
  export interface ConditionalOrderEvent {
@@ -36,8 +36,18 @@ export type InstrumentChangeKind = "listing" | "delisting" | "halt" | "unhalt" |
36
36
  * Full current configuration for a market on the `instrument` channel.
37
37
  */
38
38
  export interface InstrumentEventData {
39
- /** What changed for this market */
40
- change: InstrumentChangeKind;
39
+ /**
40
+ * What changed for this market.
41
+ *
42
+ * Widened past {@link InstrumentChangeKind} on purpose: `@0xmonaco/core`
43
+ * parses this frame leniently, so a change kind added server-side after this
44
+ * SDK version ships is delivered as-is rather than dropping the frame — and
45
+ * with it the full market config the frame carries, which can hide a market
46
+ * going inactive behind an unfamiliar label (0XM-2628).
47
+ * `InstrumentChangeKind` names the values the server sends today — narrow
48
+ * with a `switch` that keeps a `default` branch.
49
+ */
50
+ change: InstrumentChangeKind | (string & {});
41
51
  /** Trading pair identifier (UUID) */
42
52
  tradingPairId: string;
43
53
  /** Market symbol, e.g. "BTC/USDC" */
@@ -85,6 +85,11 @@ export interface MarketStatsEvent {
85
85
  /**
86
86
  * A single market's row in the all-markets summary frame. A lighter shape than
87
87
  * {@link MarketStatsData}: enough to render a markets table.
88
+ *
89
+ * `marketStatus` is typed `MarketStatus | (string & {})`: `@0xmonaco/core`
90
+ * parses this frame leniently, so an unrecognized status is passed through
91
+ * rather than throwing and dropping the summary row (0XM-2628). `MarketStatus`
92
+ * names the values the server sends today — match it with a `default` branch.
88
93
  */
89
94
  export interface MarketStatsSummary {
90
95
  /** Trading pair identifier (UUID) */
@@ -114,7 +119,7 @@ export interface MarketStatsSummary {
114
119
  /** Next funding time as a millisecond epoch. Perp-only; omitted for spot. */
115
120
  fundingTimestamp?: number;
116
121
  /** Tradability label (always present) */
117
- marketStatus: MarketStatus;
122
+ marketStatus: MarketStatus | (string & {});
118
123
  }
119
124
  /**
120
125
  * All-markets summary event on the `market_stats` channel: one
@@ -21,15 +21,20 @@ export interface OHLCVEvent {
21
21
  /** Trading pair ID (UUID) */
22
22
  tradingPairId: string;
23
23
  /** Candlestick interval */
24
- interval: Interval;
24
+ interval: Interval | (string & {});
25
25
  /** Trading mode */
26
- tradingMode: TradingMode;
26
+ tradingMode: TradingMode | (string & {});
27
27
  /**
28
28
  * Price series this candle belongs to. Always a concrete series on the wire
29
29
  * (`trade` or `mark`, never the `*` selector); lets a wildcard subscriber
30
30
  * tell the two streams apart. Absent only on legacy frames that omit it.
31
+ *
32
+ * Widened past the two known values on purpose: a wildcard subscription
33
+ * matches any suffix, so a series added server-side after this version still
34
+ * arrives here, and telling the streams apart is the entire point of the
35
+ * field. Match it with a `default` branch.
31
36
  */
32
- priceType?: "trade" | "mark";
37
+ priceType?: "trade" | "mark" | (string & {});
33
38
  /** OHLCV candlestick data */
34
39
  candlestick: Candlestick;
35
40
  }
@@ -29,7 +29,7 @@ export interface OrderbookLevel {
29
29
  */
30
30
  export interface PriceChange {
31
31
  /** Order side (BUY or SELL) */
32
- side: OrderSide;
32
+ side: OrderSide | (string & {});
33
33
  /** Old price before the change */
34
34
  oldPrice?: string;
35
35
  /** New price after the change */
@@ -46,7 +46,7 @@ export interface OrderbookEvent {
46
46
  /** Trading pair ID (UUID) */
47
47
  tradingPairId: string;
48
48
  /** Trading mode (SPOT, MARGIN) */
49
- tradingMode: TradingMode;
49
+ tradingMode: TradingMode | (string & {});
50
50
  /** Bid orders (buy orders) - Full depth */
51
51
  bids: OrderbookLevel[];
52
52
  /** Ask orders (sell orders) - Full depth */