@0xmonaco/core 1.0.74 → 1.0.76
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.
- package/README.md +0 -5
- package/dist/api/applications/api.d.ts +53 -22
- package/dist/api/applications/api.js +88 -22
- package/dist/api/auth/api.d.ts +1 -3
- package/dist/api/auth/api.js +1 -3
- package/dist/api/base.d.ts +0 -35
- package/dist/api/base.js +0 -54
- package/dist/api/buildercodes/api.d.ts +3 -4
- package/dist/api/buildercodes/api.js +6 -7
- package/dist/api/managed-markets/index.js +4 -2
- package/dist/api/margin-accounts/api.d.ts +2 -0
- package/dist/api/margin-accounts/api.js +16 -2
- package/dist/api/market/api.js +3 -1
- package/dist/api/perp/routes.d.ts +19 -12
- package/dist/api/perp/routes.js +2 -0
- package/dist/api/pitpass/api.d.ts +11 -8
- package/dist/api/pitpass/api.js +24 -11
- package/dist/api/positions/api.d.ts +20 -8
- package/dist/api/positions/api.js +20 -8
- package/dist/api/profile/api.d.ts +55 -18
- package/dist/api/profile/api.js +77 -28
- package/dist/api/trades/api.d.ts +38 -7
- package/dist/api/trades/api.js +38 -11
- package/dist/api/trading/api.d.ts +6 -11
- package/dist/api/trading/api.js +6 -11
- package/dist/api/websocket/websocket.js +149 -24
- package/dist/api/withdrawals/api.js +3 -1
- package/dist/coverage.d.ts +2 -0
- package/dist/coverage.js +2 -0
- package/dist/sdk.d.ts +0 -18
- package/dist/sdk.js +0 -42
- package/package.json +3 -3
package/dist/api/trades/api.d.ts
CHANGED
|
@@ -26,23 +26,54 @@ export declare function parseRawTradeEvent(raw: RawTradeEvent): TradeEvent;
|
|
|
26
26
|
* Options for fetching trades
|
|
27
27
|
*/
|
|
28
28
|
export interface GetTradesOptions {
|
|
29
|
-
/**
|
|
30
|
-
page?: number;
|
|
31
|
-
/** Maximum number of records to return (default: 25, max: 100) */
|
|
29
|
+
/** Maximum number of records to return (default: 25, max: 1000) */
|
|
32
30
|
pageSize?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Cursor from a previous response's `nextPageToken`. Omit (or pass "") to
|
|
33
|
+
* start at the most recent trade.
|
|
34
|
+
*/
|
|
35
|
+
pageToken?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* One page of a pair's trade feed.
|
|
39
|
+
*
|
|
40
|
+
* `nextPageToken` is empty exactly when the walk is finished — the server
|
|
41
|
+
* over-fetches one row to prove it — so a caller can stop on the empty token
|
|
42
|
+
* without a confirming extra request.
|
|
43
|
+
*/
|
|
44
|
+
export interface GetTradesPage {
|
|
45
|
+
/** Trades in this page, newest first. */
|
|
46
|
+
trades: TradeEvent[];
|
|
47
|
+
/** Cursor to pass as `pageToken` for the next page; "" when exhausted. */
|
|
48
|
+
nextPageToken: string;
|
|
33
49
|
}
|
|
34
50
|
/**
|
|
35
51
|
* Trades API for fetching historical trade data
|
|
36
52
|
*/
|
|
37
53
|
export declare class TradesAPIImpl extends BaseAPI {
|
|
38
54
|
/**
|
|
39
|
-
* Get historical trades for a trading pair
|
|
55
|
+
* Get one page of historical trades for a trading pair.
|
|
56
|
+
*
|
|
57
|
+
* Cursor paged (0XM-2821): the page number was removed because `trades` is
|
|
58
|
+
* appended to continuously, so an offset silently repeated the newest trades
|
|
59
|
+
* as fills landed mid-walk. Start with no `pageToken` and follow
|
|
60
|
+
* `nextPageToken` until it comes back empty.
|
|
40
61
|
*
|
|
41
62
|
* @param tradingPairId - The trading pair UUID
|
|
42
|
-
* @param options -
|
|
43
|
-
* @returns
|
|
63
|
+
* @param options - Cursor pagination options
|
|
64
|
+
* @returns One page of TradeEvent records sorted by executedAt descending (newest first), plus the next cursor
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* let pageToken: string | undefined;
|
|
69
|
+
* do {
|
|
70
|
+
* const page = await sdk.trades.getTrades(pairId, { pageSize: 100, pageToken });
|
|
71
|
+
* handle(page.trades);
|
|
72
|
+
* pageToken = page.nextPageToken || undefined;
|
|
73
|
+
* } while (pageToken);
|
|
74
|
+
* ```
|
|
44
75
|
*/
|
|
45
|
-
getTrades(tradingPairId: string, options?: GetTradesOptions): Promise<
|
|
76
|
+
getTrades(tradingPairId: string, options?: GetTradesOptions): Promise<GetTradesPage>;
|
|
46
77
|
/**
|
|
47
78
|
* Get a single trade by its UUID.
|
|
48
79
|
*
|
package/dist/api/trades/api.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GetTradesSchema, validate } from "@0xmonaco/types";
|
|
1
2
|
import { BaseAPI } from "../base";
|
|
2
3
|
import { perpRoutes } from "../perp";
|
|
3
4
|
/**
|
|
@@ -22,23 +23,49 @@ export function parseRawTradeEvent(raw) {
|
|
|
22
23
|
*/
|
|
23
24
|
export class TradesAPIImpl extends BaseAPI {
|
|
24
25
|
/**
|
|
25
|
-
* Get historical trades for a trading pair
|
|
26
|
+
* Get one page of historical trades for a trading pair.
|
|
27
|
+
*
|
|
28
|
+
* Cursor paged (0XM-2821): the page number was removed because `trades` is
|
|
29
|
+
* appended to continuously, so an offset silently repeated the newest trades
|
|
30
|
+
* as fills landed mid-walk. Start with no `pageToken` and follow
|
|
31
|
+
* `nextPageToken` until it comes back empty.
|
|
26
32
|
*
|
|
27
33
|
* @param tradingPairId - The trading pair UUID
|
|
28
|
-
* @param options -
|
|
29
|
-
* @returns
|
|
34
|
+
* @param options - Cursor pagination options
|
|
35
|
+
* @returns One page of TradeEvent records sorted by executedAt descending (newest first), plus the next cursor
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* let pageToken: string | undefined;
|
|
40
|
+
* do {
|
|
41
|
+
* const page = await sdk.trades.getTrades(pairId, { pageSize: 100, pageToken });
|
|
42
|
+
* handle(page.trades);
|
|
43
|
+
* pageToken = page.nextPageToken || undefined;
|
|
44
|
+
* } while (pageToken);
|
|
45
|
+
* ```
|
|
30
46
|
*/
|
|
31
47
|
async getTrades(tradingPairId, options = {}) {
|
|
32
|
-
|
|
33
|
-
// Ensure pageSize is a positive number between 1 and 100, defaulting to 25
|
|
34
|
-
const pageSize = options.pageSize != null && options.pageSize > 0 ? Math.min(options.pageSize, 100) : 25;
|
|
48
|
+
validate(GetTradesSchema, options);
|
|
35
49
|
const params = new URLSearchParams();
|
|
36
|
-
|
|
37
|
-
|
|
50
|
+
// Only send what the caller set: the server owns the 25 default, so
|
|
51
|
+
// restating it here would pin the SDK to a value the API can move.
|
|
52
|
+
if (options.pageSize != null) {
|
|
53
|
+
params.set("pageSize", String(options.pageSize));
|
|
54
|
+
}
|
|
55
|
+
if (options.pageToken != null && options.pageToken !== "") {
|
|
56
|
+
params.set("pageToken", options.pageToken);
|
|
38
57
|
}
|
|
39
|
-
params.
|
|
40
|
-
const response = await this.makePublicRequest(`/api/v1/trades/${encodeURIComponent(tradingPairId)}
|
|
41
|
-
return
|
|
58
|
+
const query = params.toString();
|
|
59
|
+
const response = await this.makePublicRequest(`/api/v1/trades/${encodeURIComponent(tradingPairId)}${query === "" ? "" : `?${query}`}`);
|
|
60
|
+
return {
|
|
61
|
+
// `?? []` because an empty page omits `trades` entirely; without it the
|
|
62
|
+
// last page of a walk would throw instead of ending it.
|
|
63
|
+
trades: (response.trades ?? []).map(parseRawTradeEvent),
|
|
64
|
+
// Absent rather than "" on a wire that omits empty strings: either way the
|
|
65
|
+
// walk is finished, and a caller testing `nextPageToken || undefined`
|
|
66
|
+
// must not see `undefined` become a truthy string.
|
|
67
|
+
nextPageToken: response.nextPageToken ?? "",
|
|
68
|
+
};
|
|
42
69
|
}
|
|
43
70
|
/**
|
|
44
71
|
* Get a single trade by its UUID.
|
|
@@ -315,11 +315,10 @@ export declare class TradingAPIImpl extends BaseAPI implements TradingAPI {
|
|
|
315
315
|
* Gets orders based on query parameters, cursor-paginated by default.
|
|
316
316
|
*
|
|
317
317
|
* Retrieves orders with optional filtering by status, trading pair, and pagination.
|
|
318
|
-
* Every
|
|
319
|
-
*
|
|
320
|
-
* (
|
|
321
|
-
*
|
|
322
|
-
* working set.
|
|
318
|
+
* Every row is a BOOK order (`LIMIT` or `MARKET`); filter `status` to
|
|
319
|
+
* `["SUBMITTED", "PARTIALLY_FILLED"]` for the resting working set. TWAP parents and
|
|
320
|
+
* conditional (TP/SL) orders are not rows here — list them with `listTwapOrders`
|
|
321
|
+
* and `listConditionalOrders`.
|
|
323
322
|
* When neither `page` nor `pageToken` is passed, the SDK drives cursor (pageToken)
|
|
324
323
|
* pagination: it starts a cursor walk from the newest (or oldest, for
|
|
325
324
|
* `orderBy: "ASC"`) row and the response's `nextPageToken` resumes it. Both modes
|
|
@@ -342,13 +341,9 @@ export declare class TradingAPIImpl extends BaseAPI implements TradingAPI {
|
|
|
342
341
|
*
|
|
343
342
|
* @example
|
|
344
343
|
* ```typescript
|
|
345
|
-
* //
|
|
344
|
+
* // The resting working set (book orders only)
|
|
346
345
|
* const open = await tradingAPI.getPaginatedOrders({ status: ["SUBMITTED", "PARTIALLY_FILLED"] });
|
|
347
|
-
* for (const order of open.orders)
|
|
348
|
-
* if (order.orderType === "TWAP") console.log("TWAP parent", order.twap?.slicesPlaced);
|
|
349
|
-
* else if (order.orderType === "CONDITIONAL") console.log("trigger", order.conditional?.triggerPrice);
|
|
350
|
-
* else console.log("resting", order.price);
|
|
351
|
-
* }
|
|
346
|
+
* for (const order of open.orders) console.log("resting", order.quantity, "@", order.price);
|
|
352
347
|
* ```
|
|
353
348
|
*
|
|
354
349
|
* @example
|
package/dist/api/trading/api.js
CHANGED
|
@@ -495,11 +495,10 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
495
495
|
* Gets orders based on query parameters, cursor-paginated by default.
|
|
496
496
|
*
|
|
497
497
|
* Retrieves orders with optional filtering by status, trading pair, and pagination.
|
|
498
|
-
* Every
|
|
499
|
-
*
|
|
500
|
-
* (
|
|
501
|
-
*
|
|
502
|
-
* working set.
|
|
498
|
+
* Every row is a BOOK order (`LIMIT` or `MARKET`); filter `status` to
|
|
499
|
+
* `["SUBMITTED", "PARTIALLY_FILLED"]` for the resting working set. TWAP parents and
|
|
500
|
+
* conditional (TP/SL) orders are not rows here — list them with `listTwapOrders`
|
|
501
|
+
* and `listConditionalOrders`.
|
|
503
502
|
* When neither `page` nor `pageToken` is passed, the SDK drives cursor (pageToken)
|
|
504
503
|
* pagination: it starts a cursor walk from the newest (or oldest, for
|
|
505
504
|
* `orderBy: "ASC"`) row and the response's `nextPageToken` resumes it. Both modes
|
|
@@ -522,13 +521,9 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
522
521
|
*
|
|
523
522
|
* @example
|
|
524
523
|
* ```typescript
|
|
525
|
-
* //
|
|
524
|
+
* // The resting working set (book orders only)
|
|
526
525
|
* const open = await tradingAPI.getPaginatedOrders({ status: ["SUBMITTED", "PARTIALLY_FILLED"] });
|
|
527
|
-
* for (const order of open.orders)
|
|
528
|
-
* if (order.orderType === "TWAP") console.log("TWAP parent", order.twap?.slicesPlaced);
|
|
529
|
-
* else if (order.orderType === "CONDITIONAL") console.log("trigger", order.conditional?.triggerPrice);
|
|
530
|
-
* else console.log("resting", order.price);
|
|
531
|
-
* }
|
|
526
|
+
* for (const order of open.orders) console.log("resting", order.quantity, "@", order.price);
|
|
532
527
|
* ```
|
|
533
528
|
*
|
|
534
529
|
* @example
|
|
@@ -245,6 +245,9 @@ function parsePositionEventData(raw) {
|
|
|
245
245
|
orderId: readOptionalString(data, "orderId"),
|
|
246
246
|
reason: readString(data, "reason"),
|
|
247
247
|
updatedAt: readString(data, "updatedAt"),
|
|
248
|
+
// Optional: an older deployment does not send it, and the server omits it
|
|
249
|
+
// when it does not know when the position opened.
|
|
250
|
+
openedAt: readOptionalString(data, "openedAt"),
|
|
248
251
|
// Opaque durable row version (0XM-2673). `readOptionalSequence`, not
|
|
249
252
|
// `readOptionalNumber`: this is an ordering counter, so a fractional,
|
|
250
253
|
// negative, or unsafe-integer value would silently corrupt every
|
|
@@ -269,6 +272,42 @@ function parsePositionEvent(rawData) {
|
|
|
269
272
|
data: parsePositionEventData(rawData.data),
|
|
270
273
|
};
|
|
271
274
|
}
|
|
275
|
+
/** The `positions` channel's valuation frame discriminator. */
|
|
276
|
+
const POSITION_VALUATION_EVENT_TYPE = "position_valuation";
|
|
277
|
+
/**
|
|
278
|
+
* Whether a `positions` channel frame is a periodic valuation rather than a
|
|
279
|
+
* lifecycle update. Checked on the raw discriminator BEFORE any lifecycle
|
|
280
|
+
* field is read, so a valuation never reaches the lifecycle parser.
|
|
281
|
+
*/
|
|
282
|
+
function isPositionValuationFrame(rawData) {
|
|
283
|
+
return isRecord(rawData) && rawData.event_type === POSITION_VALUATION_EVENT_TYPE;
|
|
284
|
+
}
|
|
285
|
+
function parsePositionValuationEvent(rawData) {
|
|
286
|
+
if (!isRecord(rawData)) {
|
|
287
|
+
throw new Error("Invalid position valuation event: payload must be an object");
|
|
288
|
+
}
|
|
289
|
+
if (!isRecord(rawData.data)) {
|
|
290
|
+
throw new Error("Invalid position valuation event: data must be an object");
|
|
291
|
+
}
|
|
292
|
+
const data = keysToCamelCase(rawData.data);
|
|
293
|
+
// Always present on the wire; `null` when the server cannot derive one.
|
|
294
|
+
const liquidationPrice = data.liquidationPrice === null ? null : readString(data, "liquidationPrice");
|
|
295
|
+
return {
|
|
296
|
+
eventType: readEnum(rawData, "event_type", [POSITION_VALUATION_EVENT_TYPE]),
|
|
297
|
+
userId: readString(rawData, "user_id"),
|
|
298
|
+
data: {
|
|
299
|
+
positionId: readString(data, "positionId"),
|
|
300
|
+
marginAccountId: readString(data, "marginAccountId"),
|
|
301
|
+
tradingPairId: readString(data, "tradingPairId"),
|
|
302
|
+
markPrice: readString(data, "markPrice"),
|
|
303
|
+
unrealizedPnl: readString(data, "unrealizedPnl"),
|
|
304
|
+
liquidationPrice,
|
|
305
|
+
initialMarginRequired: readString(data, "initialMarginRequired"),
|
|
306
|
+
maintenanceMarginRequired: readString(data, "maintenanceMarginRequired"),
|
|
307
|
+
valuedAt: readString(data, "valuedAt"),
|
|
308
|
+
},
|
|
309
|
+
};
|
|
310
|
+
}
|
|
272
311
|
/**
|
|
273
312
|
* Parse a liquidation alert's payload. Shared by the live event and the
|
|
274
313
|
* subscribe-time snapshot (see {@link parseConditionalOrderEventData}).
|
|
@@ -360,6 +399,7 @@ function parseMarketStatsData(raw) {
|
|
|
360
399
|
bestAskPrice: readOptionalString(data, "bestAskPrice"),
|
|
361
400
|
openInterest: readOptionalString(data, "openInterest"),
|
|
362
401
|
openInterestLimit: readOptionalString(data, "openInterestLimit"),
|
|
402
|
+
openInterestHeadroom: readOptionalString(data, "openInterestHeadroom"),
|
|
363
403
|
lastTradePrice: readOptionalString(data, "lastTradePrice"),
|
|
364
404
|
dailyBaseTokenVolume: readOptionalString(data, "dailyBaseTokenVolume"),
|
|
365
405
|
dailyQuoteTokenVolume: readOptionalString(data, "dailyQuoteTokenVolume"),
|
|
@@ -374,6 +414,11 @@ function parseMarketStatsData(raw) {
|
|
|
374
414
|
baseInterestRate: readOptionalString(data, "baseInterestRate"),
|
|
375
415
|
fundingClampSmall: readOptionalString(data, "fundingClampSmall"),
|
|
376
416
|
fundingClampBig: readOptionalString(data, "fundingClampBig"),
|
|
417
|
+
// Lenient like the summary's marketStatus: an unrecognized value passes
|
|
418
|
+
// through rather than dropping the frame.
|
|
419
|
+
marketStatus: readOptionalString(data, "marketStatus"),
|
|
420
|
+
fundingIntervalSeconds: readOptionalNumber(data, "fundingIntervalSeconds"),
|
|
421
|
+
lastFundingTime: readOptionalNumber(data, "lastFundingTime"),
|
|
377
422
|
};
|
|
378
423
|
}
|
|
379
424
|
function parseMarketStatsEvent(rawData) {
|
|
@@ -451,6 +496,17 @@ function parseInstrumentEventData(raw) {
|
|
|
451
496
|
// non-string value still throws.
|
|
452
497
|
baseIconUrl: readOptionalString(data, "baseIconUrl") ?? null,
|
|
453
498
|
quoteIconUrl: readOptionalString(data, "quoteIconUrl") ?? null,
|
|
499
|
+
// Asset identity and minLeverage: a server that predates them omits the
|
|
500
|
+
// keys, so absent reads as `undefined` and never as a made-up `0` or `""`.
|
|
501
|
+
baseAssetId: readOptionalString(data, "baseAssetId"),
|
|
502
|
+
quoteAssetId: readOptionalString(data, "quoteAssetId"),
|
|
503
|
+
baseToken: readOptionalString(data, "baseToken"),
|
|
504
|
+
quoteToken: readOptionalString(data, "quoteToken"),
|
|
505
|
+
baseAssetName: readOptionalString(data, "baseAssetName"),
|
|
506
|
+
quoteAssetName: readOptionalString(data, "quoteAssetName"),
|
|
507
|
+
baseDecimals: readOptionalNumber(data, "baseDecimals"),
|
|
508
|
+
quoteDecimals: readOptionalNumber(data, "quoteDecimals"),
|
|
509
|
+
minLeverage: readOptionalString(data, "minLeverage"),
|
|
454
510
|
maxLeverage: readOptionalString(data, "maxLeverage"),
|
|
455
511
|
initialMarginRate: readOptionalString(data, "initialMarginRate"),
|
|
456
512
|
maintenanceMarginRate: readOptionalString(data, "maintenanceMarginRate"),
|
|
@@ -772,6 +828,10 @@ export function createMonacoWebSocket(baseUrl, options = {}, serverClock = new S
|
|
|
772
828
|
let ws = null;
|
|
773
829
|
let session = options.session;
|
|
774
830
|
let reconnectAttempts = 0;
|
|
831
|
+
// Whether a socket has opened since the client was created or last
|
|
832
|
+
// disconnect()ed, so a status consumer can tell a first connect that keeps
|
|
833
|
+
// failing from a lost working connection.
|
|
834
|
+
let hasConnected = false;
|
|
775
835
|
let reconnectTimer = null;
|
|
776
836
|
let heartbeatTimer = null;
|
|
777
837
|
let autoReconnect = options.autoReconnect ?? true;
|
|
@@ -823,7 +883,9 @@ export function createMonacoWebSocket(baseUrl, options = {}, serverClock = new S
|
|
|
823
883
|
return reconnectTimer ? "reconnecting" : "disconnected";
|
|
824
884
|
switch (ws.readyState) {
|
|
825
885
|
case WebSocket.CONNECTING:
|
|
826
|
-
|
|
886
|
+
// A retry's socket is still inside the outage the last status
|
|
887
|
+
// reported, so it reads as reconnecting, not connecting.
|
|
888
|
+
return reconnectAttempts > 0 ? "reconnecting" : "connecting";
|
|
827
889
|
case WebSocket.OPEN:
|
|
828
890
|
return "connected";
|
|
829
891
|
default:
|
|
@@ -833,6 +895,43 @@ export function createMonacoWebSocket(baseUrl, options = {}, serverClock = new S
|
|
|
833
895
|
}
|
|
834
896
|
};
|
|
835
897
|
const getUrl = () => baseUrl;
|
|
898
|
+
/**
|
|
899
|
+
* The single place a status change is reported. Recovery must not hinge on
|
|
900
|
+
* the application's observer, so an error it throws is logged, not
|
|
901
|
+
* propagated into the connection lifecycle. An async observer is assignable
|
|
902
|
+
* to the void-returning handler type, so its rejection is logged the same
|
|
903
|
+
* way rather than left unhandled.
|
|
904
|
+
*/
|
|
905
|
+
const emitStatus = (status, nextRetryDelayMs, attempt = reconnectAttempts) => {
|
|
906
|
+
const info = { attempt, hasConnected };
|
|
907
|
+
if (nextRetryDelayMs !== undefined) {
|
|
908
|
+
info.nextRetryDelayMs = nextRetryDelayMs;
|
|
909
|
+
}
|
|
910
|
+
const logObserverError = (err) => console.error("WebSocket: onStatusChange threw", err);
|
|
911
|
+
try {
|
|
912
|
+
const result = options.onStatusChange?.(status, info);
|
|
913
|
+
// Any thenable, not just this realm's Promise: an async handler from
|
|
914
|
+
// another realm (an iframe) returns a promise `instanceof` misses.
|
|
915
|
+
if (typeof result?.then === "function") {
|
|
916
|
+
Promise.resolve(result).catch(logObserverError);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
catch (err) {
|
|
920
|
+
logObserverError(err);
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
/**
|
|
924
|
+
* Report a terminal "disconnected", which ends the retry cycle so the next
|
|
925
|
+
* connect() reports "connecting" with a fresh retry budget. The counter is
|
|
926
|
+
* reset before the observer runs, so a connect() made from inside the
|
|
927
|
+
* callback already starts the new cycle; the status still reports the
|
|
928
|
+
* retries the cycle ran.
|
|
929
|
+
*/
|
|
930
|
+
const emitTerminalDisconnected = () => {
|
|
931
|
+
const attempt = reconnectAttempts;
|
|
932
|
+
reconnectAttempts = 0;
|
|
933
|
+
emitStatus("disconnected", undefined, attempt);
|
|
934
|
+
};
|
|
836
935
|
/**
|
|
837
936
|
* Send the signed auth handshake as the first message after the socket
|
|
838
937
|
* opens. The client signs `WS-AUTH\n<pubkey>\n<ts>` with the session private
|
|
@@ -876,13 +975,15 @@ export function createMonacoWebSocket(baseUrl, options = {}, serverClock = new S
|
|
|
876
975
|
reconnectTimer = null;
|
|
877
976
|
}
|
|
878
977
|
};
|
|
978
|
+
// Whether the retry cycle may schedule another attempt.
|
|
979
|
+
const retryBudgetLeft = () => autoReconnect && reconnectAttempts < maxReconnectAttempts;
|
|
879
980
|
const scheduleReconnect = () => {
|
|
880
981
|
// Single scheduling authority: a failed attempt can report through both
|
|
881
982
|
// the connect() rejection and the socket's own close event — an armed
|
|
882
983
|
// timer means the retry is already owned.
|
|
883
984
|
if (reconnectTimer)
|
|
884
985
|
return;
|
|
885
|
-
if (!
|
|
986
|
+
if (!retryBudgetLeft()) {
|
|
886
987
|
console.error("WebSocket: Max reconnect attempts reached");
|
|
887
988
|
return;
|
|
888
989
|
}
|
|
@@ -902,10 +1003,14 @@ export function createMonacoWebSocket(baseUrl, options = {}, serverClock = new S
|
|
|
902
1003
|
return;
|
|
903
1004
|
connect().catch((err) => {
|
|
904
1005
|
console.warn("WebSocket: Failed to reconnect:", err);
|
|
905
|
-
|
|
1006
|
+
// Not when the failure already ended the retry cycle (the last
|
|
1007
|
+
// retry's socket could not be constructed).
|
|
1008
|
+
if (reconnectAttempts > 0) {
|
|
1009
|
+
scheduleReconnect();
|
|
1010
|
+
}
|
|
906
1011
|
});
|
|
907
1012
|
}, delay);
|
|
908
|
-
|
|
1013
|
+
emitStatus("reconnecting", delay);
|
|
909
1014
|
};
|
|
910
1015
|
const send = (data) => {
|
|
911
1016
|
if (ws?.readyState === WebSocket.OPEN) {
|
|
@@ -1035,6 +1140,7 @@ export function createMonacoWebSocket(baseUrl, options = {}, serverClock = new S
|
|
|
1035
1140
|
return;
|
|
1036
1141
|
}
|
|
1037
1142
|
reconnectAttempts = 0;
|
|
1143
|
+
hasConnected = true;
|
|
1038
1144
|
// A retry armed before this open (e.g. a manual connect() during
|
|
1039
1145
|
// backoff) is moot now — left running it would suppress the
|
|
1040
1146
|
// terminal disconnected emit and reopen a socket after a clean
|
|
@@ -1045,7 +1151,7 @@ export function createMonacoWebSocket(baseUrl, options = {}, serverClock = new S
|
|
|
1045
1151
|
// (orders, balances, …) are authorized when the Subscribe arrives.
|
|
1046
1152
|
sendAuthenticate();
|
|
1047
1153
|
resubscribeAll();
|
|
1048
|
-
|
|
1154
|
+
emitStatus("connected");
|
|
1049
1155
|
// Resync-join order: the live stream resumes first (auth +
|
|
1050
1156
|
// subscribe above), then the application is asked to refetch
|
|
1051
1157
|
// snapshots and reconcile against each channel's authoritative
|
|
@@ -1118,13 +1224,8 @@ export function createMonacoWebSocket(baseUrl, options = {}, serverClock = new S
|
|
|
1118
1224
|
if (pendingResyncCode === null) {
|
|
1119
1225
|
pendingResyncCode = event.code;
|
|
1120
1226
|
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
}
|
|
1124
|
-
finally {
|
|
1125
|
-
// Recovery must not hinge on the status observer not throwing.
|
|
1126
|
-
options.onReauthenticationRequired?.({ code: authError.code, message: authError.message, closeCode: event.code });
|
|
1127
|
-
}
|
|
1227
|
+
emitStatus("disconnected");
|
|
1228
|
+
options.onReauthenticationRequired?.({ code: authError.code, message: authError.message, closeCode: event.code });
|
|
1128
1229
|
return;
|
|
1129
1230
|
}
|
|
1130
1231
|
// The app already handed over a replacement session on this socket.
|
|
@@ -1135,14 +1236,10 @@ export function createMonacoWebSocket(baseUrl, options = {}, serverClock = new S
|
|
|
1135
1236
|
if (pendingResyncCode === null) {
|
|
1136
1237
|
pendingResyncCode = event.code;
|
|
1137
1238
|
}
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
connect().catch((err) => {
|
|
1143
|
-
console.warn("WebSocket: Failed to connect with the replacement session:", err);
|
|
1144
|
-
});
|
|
1145
|
-
}
|
|
1239
|
+
emitStatus("disconnected");
|
|
1240
|
+
connect().catch((err) => {
|
|
1241
|
+
console.warn("WebSocket: Failed to connect with the replacement session:", err);
|
|
1242
|
+
});
|
|
1146
1243
|
return;
|
|
1147
1244
|
}
|
|
1148
1245
|
// Reconnect on abnormal close. 1013 is the server's slow-client
|
|
@@ -1159,13 +1256,26 @@ export function createMonacoWebSocket(baseUrl, options = {}, serverClock = new S
|
|
|
1159
1256
|
// "disconnected" is terminal: suppressed while a retry is armed
|
|
1160
1257
|
// (scheduleReconnect emitted "reconnecting" instead).
|
|
1161
1258
|
if (!reconnectTimer) {
|
|
1162
|
-
|
|
1259
|
+
emitTerminalDisconnected();
|
|
1163
1260
|
}
|
|
1164
1261
|
};
|
|
1165
1262
|
socket.onerror = () => clearTimeout(timeout);
|
|
1263
|
+
// A retry's socket stays inside the outage "reconnecting" already
|
|
1264
|
+
// reported; only a connection opened outside a retry cycle is new.
|
|
1265
|
+
if (reconnectAttempts === 0) {
|
|
1266
|
+
emitStatus("connecting");
|
|
1267
|
+
}
|
|
1166
1268
|
}
|
|
1167
1269
|
catch (err) {
|
|
1168
|
-
|
|
1270
|
+
// The socket could not be constructed. Inside a retry cycle the retry
|
|
1271
|
+
// timer schedules the next attempt while the budget lasts; otherwise
|
|
1272
|
+
// nothing follows, so this ends the cycle.
|
|
1273
|
+
if (reconnectTimer || (reconnectAttempts > 0 && retryBudgetLeft())) {
|
|
1274
|
+
emitStatus("disconnected");
|
|
1275
|
+
}
|
|
1276
|
+
else {
|
|
1277
|
+
emitTerminalDisconnected();
|
|
1278
|
+
}
|
|
1169
1279
|
reject(err);
|
|
1170
1280
|
}
|
|
1171
1281
|
});
|
|
@@ -1180,7 +1290,8 @@ export function createMonacoWebSocket(baseUrl, options = {}, serverClock = new S
|
|
|
1180
1290
|
instrumentBaseline.clear();
|
|
1181
1291
|
ws?.close(1000, "Client disconnect");
|
|
1182
1292
|
ws = null;
|
|
1183
|
-
|
|
1293
|
+
hasConnected = false;
|
|
1294
|
+
emitTerminalDisconnected();
|
|
1184
1295
|
};
|
|
1185
1296
|
const subscribe = (channel, handler, snapshotHandler) => {
|
|
1186
1297
|
const isFirstSubscriber = !handlers.has(channel);
|
|
@@ -1522,8 +1633,11 @@ export function createMonacoWebSocket(baseUrl, options = {}, serverClock = new S
|
|
|
1522
1633
|
* handshake. Omit `tradingPairId` for all pairs, or pass one to filter.
|
|
1523
1634
|
* Detected broadcast lag closes the connection with 1013; reconcile
|
|
1524
1635
|
* missed keys and terminal updates on reconnect.
|
|
1636
|
+
*
|
|
1637
|
+
* The channel also carries periodic `position_valuation` frames. Those go to
|
|
1638
|
+
* `onValuation` only, never to `handler`, and are ignored without one.
|
|
1525
1639
|
*/
|
|
1526
|
-
const subscribePositions = (handler, tradingPairId, onSnapshot) => {
|
|
1640
|
+
const subscribePositions = (handler, tradingPairId, onSnapshot, onValuation) => {
|
|
1527
1641
|
if (!handler) {
|
|
1528
1642
|
throw new Error("positions subscription requires a handler");
|
|
1529
1643
|
}
|
|
@@ -1532,6 +1646,17 @@ export function createMonacoWebSocket(baseUrl, options = {}, serverClock = new S
|
|
|
1532
1646
|
}
|
|
1533
1647
|
const channel = tradingPairId ? `positions:${tradingPairId}` : "positions";
|
|
1534
1648
|
return subscribe(channel, (rawData) => {
|
|
1649
|
+
if (isPositionValuationFrame(rawData)) {
|
|
1650
|
+
if (!onValuation)
|
|
1651
|
+
return;
|
|
1652
|
+
try {
|
|
1653
|
+
onValuation(parsePositionValuationEvent(rawData));
|
|
1654
|
+
}
|
|
1655
|
+
catch (err) {
|
|
1656
|
+
console.error("WebSocket: Error processing position valuation event", err);
|
|
1657
|
+
}
|
|
1658
|
+
return;
|
|
1659
|
+
}
|
|
1535
1660
|
try {
|
|
1536
1661
|
handler(parsePositionEvent(rawData));
|
|
1537
1662
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ListPendingWithdrawalsSchema, validate } from "@0xmonaco/types";
|
|
1
2
|
import { BaseAPI } from "../base";
|
|
2
3
|
import { perpRoutes } from "../perp";
|
|
3
4
|
/**
|
|
@@ -30,6 +31,7 @@ export class WithdrawalsAPIImpl extends BaseAPI {
|
|
|
30
31
|
async listPendingWithdrawals(params) {
|
|
31
32
|
// The gateway serves camelCase (the REST wire format), which matches the
|
|
32
33
|
// public surface, so the response is returned directly with no remapping.
|
|
33
|
-
|
|
34
|
+
validate(ListPendingWithdrawalsSchema, params ?? {});
|
|
35
|
+
return this.makeAuthenticatedRequest(perpRoutes.withdrawals.list({ pageSize: params?.pageSize, pageToken: params?.pageToken }));
|
|
34
36
|
}
|
|
35
37
|
}
|
package/dist/coverage.d.ts
CHANGED
|
@@ -137,6 +137,8 @@ export declare const COVERED: {
|
|
|
137
137
|
close_sub_account: string;
|
|
138
138
|
get_margin_account_pnl: string;
|
|
139
139
|
transfer_collateral: string;
|
|
140
|
+
transfer_collateral_to_sub_account: string;
|
|
141
|
+
transfer_collateral_from_sub_account: string;
|
|
140
142
|
claim_buildercode_rewards: string;
|
|
141
143
|
set_builder_fee: string;
|
|
142
144
|
transfer_rewards: string;
|
package/dist/coverage.js
CHANGED
|
@@ -137,6 +137,8 @@ export const COVERED = {
|
|
|
137
137
|
close_sub_account: "closeMarginSubAccount",
|
|
138
138
|
get_margin_account_pnl: "getMarginAccountPnl",
|
|
139
139
|
transfer_collateral: "transferMarginCollateral",
|
|
140
|
+
transfer_collateral_to_sub_account: "transferCollateralToSubAccount",
|
|
141
|
+
transfer_collateral_from_sub_account: "transferCollateralFromSubAccount",
|
|
140
142
|
claim_buildercode_rewards: "buildercodes.claimBuildercodeRewards",
|
|
141
143
|
set_builder_fee: "buildercodes.setBuilderFee",
|
|
142
144
|
transfer_rewards: "pitpass.transferRewards",
|
package/dist/sdk.d.ts
CHANGED
|
@@ -36,24 +36,6 @@ export declare class MonacoSDKImpl implements MonacoSDK {
|
|
|
36
36
|
* the WebSocket client.
|
|
37
37
|
*/
|
|
38
38
|
private propagateSession;
|
|
39
|
-
/**
|
|
40
|
-
* Set (or clear) the application secret key used for backend-authenticated
|
|
41
|
-
* requests (those annotated `#[require_backend]` on the gateway, e.g. the
|
|
42
|
-
* `applications` reporting endpoints).
|
|
43
|
-
*
|
|
44
|
-
* The raw `sk_...` key is sent in the `x-server-key` header on each such
|
|
45
|
-
* request. This is independent of {@link login}/session auth — a client may
|
|
46
|
-
* hold both a session and a server key at once.
|
|
47
|
-
*
|
|
48
|
-
* @param serverKey - The application secret key (`sk_...`), or `undefined` to clear.
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* ```typescript
|
|
52
|
-
* sdk.setServerKey("sk_live_...");
|
|
53
|
-
* const orders = await sdk.applications.listApplicationOrders({ status: "FILLED" });
|
|
54
|
-
* ```
|
|
55
|
-
*/
|
|
56
|
-
setServerKey(serverKey: string | undefined): void;
|
|
57
39
|
/** Extract the session keypair from an auth state. */
|
|
58
40
|
private sessionFromAuthState;
|
|
59
41
|
constructor(cfg: SDKConfig);
|
package/dist/sdk.js
CHANGED
|
@@ -103,48 +103,6 @@ export class MonacoSDKImpl {
|
|
|
103
103
|
this.trades.setSessionKeypair(credentials);
|
|
104
104
|
this.ws.setSessionKeypair(credentials);
|
|
105
105
|
}
|
|
106
|
-
/**
|
|
107
|
-
* Set (or clear) the application secret key used for backend-authenticated
|
|
108
|
-
* requests (those annotated `#[require_backend]` on the gateway, e.g. the
|
|
109
|
-
* `applications` reporting endpoints).
|
|
110
|
-
*
|
|
111
|
-
* The raw `sk_...` key is sent in the `x-server-key` header on each such
|
|
112
|
-
* request. This is independent of {@link login}/session auth — a client may
|
|
113
|
-
* hold both a session and a server key at once.
|
|
114
|
-
*
|
|
115
|
-
* @param serverKey - The application secret key (`sk_...`), or `undefined` to clear.
|
|
116
|
-
*
|
|
117
|
-
* @example
|
|
118
|
-
* ```typescript
|
|
119
|
-
* sdk.setServerKey("sk_live_...");
|
|
120
|
-
* const orders = await sdk.applications.listApplicationOrders({ status: "FILLED" });
|
|
121
|
-
* ```
|
|
122
|
-
*/
|
|
123
|
-
setServerKey(serverKey) {
|
|
124
|
-
this.auth.setServerKey(serverKey);
|
|
125
|
-
this.delegatedAgents.setServerKey(serverKey);
|
|
126
|
-
this.applications.setServerKey(serverKey);
|
|
127
|
-
this.fees.setServerKey(serverKey);
|
|
128
|
-
this.buildercodes.setServerKey(serverKey);
|
|
129
|
-
this.copyTrading.setServerKey(serverKey);
|
|
130
|
-
this.pitpass.setServerKey(serverKey);
|
|
131
|
-
this.vault.setServerKey(serverKey);
|
|
132
|
-
this.withdrawals.setServerKey(serverKey);
|
|
133
|
-
this.trading.setServerKey(serverKey);
|
|
134
|
-
this.market.setServerKey(serverKey);
|
|
135
|
-
this.marginAccounts.setServerKey(serverKey);
|
|
136
|
-
this.positions.setServerKey(serverKey);
|
|
137
|
-
this.portfolio.setServerKey(serverKey);
|
|
138
|
-
this.subAccounts.setServerKey(serverKey);
|
|
139
|
-
this.faucet.setServerKey(serverKey);
|
|
140
|
-
this.sweeper.setServerKey(serverKey);
|
|
141
|
-
this.managedMarkets.setServerKey(serverKey);
|
|
142
|
-
this.whitelist.setServerKey(serverKey);
|
|
143
|
-
this.pulse.setServerKey(serverKey);
|
|
144
|
-
this.profile.setServerKey(serverKey);
|
|
145
|
-
this.orderbook.setServerKey(serverKey);
|
|
146
|
-
this.trades.setServerKey(serverKey);
|
|
147
|
-
}
|
|
148
106
|
/** Extract the session keypair from an auth state. */
|
|
149
107
|
sessionFromAuthState(authState) {
|
|
150
108
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@0xmonaco/core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.76",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"homepage": "https://docs.0xmonaco.com/sdk/typescript",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"viem": "^2.45.2"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@0xmonaco/contracts": "1.0.
|
|
23
|
-
"@0xmonaco/types": "1.0.
|
|
22
|
+
"@0xmonaco/contracts": "1.0.76",
|
|
23
|
+
"@0xmonaco/types": "1.0.76",
|
|
24
24
|
"@noble/curves": "^1.9.1",
|
|
25
25
|
"@noble/hashes": "^2.4.0",
|
|
26
26
|
"http-status-codes": "^2.3.0"
|