@0xmonaco/core 1.0.69 → 1.0.70
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/dist/api/copy-trading/api.d.ts +94 -0
- package/dist/api/copy-trading/api.js +207 -0
- package/dist/api/copy-trading/index.d.ts +6 -0
- package/dist/api/copy-trading/index.js +6 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +1 -0
- package/dist/api/perp/routes.d.ts +2 -4
- package/dist/api/profile/api.d.ts +20 -17
- package/dist/api/profile/api.js +24 -31
- package/dist/api/trading/api.d.ts +15 -27
- package/dist/api/trading/api.js +31 -72
- package/dist/api/websocket/websocket.js +97 -0
- package/dist/coverage.d.ts +13 -0
- package/dist/coverage.js +13 -0
- package/dist/sdk.d.ts +2 -1
- package/dist/sdk.js +5 -0
- package/package.json +3 -3
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copy Trading API Implementation (0XM-2851)
|
|
3
|
+
*
|
|
4
|
+
* Lead trader profiles and the public leaderboard, and the caller's follows.
|
|
5
|
+
* Followers allocate collateral to a per-leader copy account (a cross risk
|
|
6
|
+
* bucket in their margin account) and every fill the leader makes is mirrored
|
|
7
|
+
* into it.
|
|
8
|
+
*
|
|
9
|
+
* Leaders are addressed by their custom TraderCode handle. The leaderboard, a
|
|
10
|
+
* leader's profile and a leader's closed trades are public; every other call
|
|
11
|
+
* is signed and scoped to the session's account.
|
|
12
|
+
*
|
|
13
|
+
* The REST gateway rejects unknown request fields, so every request body and
|
|
14
|
+
* query string is built key by key from validated params.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const { leaders } = await sdk.copyTrading.listLeadTraders({ sort: "roi", window: "30d" });
|
|
19
|
+
* const leader = leaders[0].profile.leader.handle!;
|
|
20
|
+
* const { followId } = await sdk.copyTrading.upsertFollow({ leader, allocation: "1000", slPct: "0.25" });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
import type { CopyTradingAPI, GetFollowResponse, GetLeadTraderResponse, ListFollowLeaderPositionsResponse, ListLeadTraderClosedTradesParams, ListLeadTraderClosedTradesResponse, ListLeadTraderOpenPositionsResponse, ListLeadTradersParams, ListLeadTradersResponse, ListMyFollowersParams, ListMyFollowersResponse, ListMyFollowsParams, ListMyFollowsResponse, PreviewFollowParams, PreviewFollowResponse, StopFollowResponse, UpsertFollowParams, UpsertFollowResponse, UpsertLeadTraderParams, UpsertLeadTraderResponse } from "@0xmonaco/types";
|
|
24
|
+
import { BaseAPI } from "../base";
|
|
25
|
+
export declare class CopyTradingAPIImpl extends BaseAPI implements CopyTradingAPI {
|
|
26
|
+
/**
|
|
27
|
+
* List lead traders (the public leaderboard), highest first by `sort`
|
|
28
|
+
* (default `roi`) over `window` (default `30d`). No session needed.
|
|
29
|
+
*
|
|
30
|
+
* Cursor paged: pass the previous response's `nextPageToken` with the SAME
|
|
31
|
+
* sort and window; an empty token means the end. Rows come from a periodic
|
|
32
|
+
* leaderboard snapshot taken at `asOf`.
|
|
33
|
+
*/
|
|
34
|
+
listLeadTraders(params?: ListLeadTradersParams): Promise<ListLeadTradersResponse>;
|
|
35
|
+
/**
|
|
36
|
+
* Get one lead trader by custom TraderCode handle: profile, follow summary
|
|
37
|
+
* and stats for 7d, 30d, 90d and all. No session needed. 404 for an unknown
|
|
38
|
+
* or suspended leader.
|
|
39
|
+
*/
|
|
40
|
+
getLeadTrader(handle: string): Promise<GetLeadTraderResponse>;
|
|
41
|
+
/**
|
|
42
|
+
* List a lead trader's closed trades — partial and full closes,
|
|
43
|
+
* liquidations and auto-deleveraging — newest first. No session needed.
|
|
44
|
+
*/
|
|
45
|
+
listLeadTraderClosedTrades(handle: string, params?: ListLeadTraderClosedTradesParams): Promise<ListLeadTraderClosedTradesResponse>;
|
|
46
|
+
/**
|
|
47
|
+
* List a lead trader's open positions. Only current followers of that
|
|
48
|
+
* leader may read them (403 otherwise).
|
|
49
|
+
*/
|
|
50
|
+
listLeadTraderOpenPositions(handle: string): Promise<ListLeadTraderOpenPositionsResponse>;
|
|
51
|
+
/**
|
|
52
|
+
* Register as a lead trader, or edit your profile. The profile is replaced
|
|
53
|
+
* as sent: an omitted `bio` or `minAllocation` clears it and an omitted
|
|
54
|
+
* `status` means `ACTIVE`; an omitted `shareBps` keeps the current share.
|
|
55
|
+
*/
|
|
56
|
+
upsertLeadTrader(params?: UpsertLeadTraderParams): Promise<UpsertLeadTraderResponse>;
|
|
57
|
+
/** Get your own lead trader profile (404 when you are not a lead trader). */
|
|
58
|
+
getMyLeadTrader(): Promise<GetLeadTraderResponse>;
|
|
59
|
+
/** List your followers, as a leader. Cursor paged, up to 1000 per page. */
|
|
60
|
+
listMyFollowers(params?: ListMyFollowersParams): Promise<ListMyFollowersResponse>;
|
|
61
|
+
/**
|
|
62
|
+
* Follow a lead trader (no `followId`), or edit one of your follows
|
|
63
|
+
* (`followId` set).
|
|
64
|
+
*
|
|
65
|
+
* An edit REPLACES the follow's settings: every optional setting left out
|
|
66
|
+
* reverts to its default, so an edit that omits `slPct` removes the
|
|
67
|
+
* stop-loss. The leader comes from the stored follow on an edit, so
|
|
68
|
+
* `leader` may be omitted there.
|
|
69
|
+
*/
|
|
70
|
+
upsertFollow(params: UpsertFollowParams): Promise<UpsertFollowResponse>;
|
|
71
|
+
/**
|
|
72
|
+
* Preview what a follow with these terms would open if it set
|
|
73
|
+
* `copyExisting`, as totals only: estimated margin and fees, and how many
|
|
74
|
+
* of the leader's positions would and would not be copied. Read-only;
|
|
75
|
+
* nothing is placed or reserved.
|
|
76
|
+
*/
|
|
77
|
+
previewFollow(params: PreviewFollowParams): Promise<PreviewFollowResponse>;
|
|
78
|
+
/** Stop one of your follows: the leader's fills stop being mirrored. */
|
|
79
|
+
stopFollow(followId: string): Promise<StopFollowResponse>;
|
|
80
|
+
/** List your follows, newest first. Cursor paged, up to 1000 per page. */
|
|
81
|
+
listMyFollows(params?: ListMyFollowsParams): Promise<ListMyFollowsResponse>;
|
|
82
|
+
/**
|
|
83
|
+
* Get one of your follows with its most recent skipped mirrors (up to 100)
|
|
84
|
+
* and `copyAccountEquity`, the copy account's marked equity (absent when it
|
|
85
|
+
* could not be read).
|
|
86
|
+
*/
|
|
87
|
+
getFollow(followId: string): Promise<GetFollowResponse>;
|
|
88
|
+
/**
|
|
89
|
+
* List the open positions of the leader one of your follows copies. The
|
|
90
|
+
* leader comes from the follow, so this works after the leader releases
|
|
91
|
+
* their handle. 404 for a follow that is not yours; 403 for a stopped one.
|
|
92
|
+
*/
|
|
93
|
+
listFollowLeaderPositions(followId: string): Promise<ListFollowLeaderPositionsResponse>;
|
|
94
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copy Trading API Implementation (0XM-2851)
|
|
3
|
+
*
|
|
4
|
+
* Lead trader profiles and the public leaderboard, and the caller's follows.
|
|
5
|
+
* Followers allocate collateral to a per-leader copy account (a cross risk
|
|
6
|
+
* bucket in their margin account) and every fill the leader makes is mirrored
|
|
7
|
+
* into it.
|
|
8
|
+
*
|
|
9
|
+
* Leaders are addressed by their custom TraderCode handle. The leaderboard, a
|
|
10
|
+
* leader's profile and a leader's closed trades are public; every other call
|
|
11
|
+
* is signed and scoped to the session's account.
|
|
12
|
+
*
|
|
13
|
+
* The REST gateway rejects unknown request fields, so every request body and
|
|
14
|
+
* query string is built key by key from validated params.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const { leaders } = await sdk.copyTrading.listLeadTraders({ sort: "roi", window: "30d" });
|
|
19
|
+
* const leader = leaders[0].profile.leader.handle!;
|
|
20
|
+
* const { followId } = await sdk.copyTrading.upsertFollow({ leader, allocation: "1000", slPct: "0.25" });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
import { LeaderHandleSchema, ListLeadTraderClosedTradesSchema, ListLeadTradersSchema, ListMyFollowersSchema, ListMyFollowsSchema, PreviewFollowSchema, UpsertFollowSchema, UpsertLeadTraderSchema, UUIDSchema, validate, } from "@0xmonaco/types";
|
|
24
|
+
import { BaseAPI } from "../base";
|
|
25
|
+
const BASE = "/api/v1/copy-trading";
|
|
26
|
+
/** `?k=v&...` from the defined entries, or `""` when there are none. */
|
|
27
|
+
function queryString(params) {
|
|
28
|
+
const search = new URLSearchParams();
|
|
29
|
+
for (const [key, value] of Object.entries(params)) {
|
|
30
|
+
if (value !== undefined)
|
|
31
|
+
search.append(key, String(value));
|
|
32
|
+
}
|
|
33
|
+
const encoded = search.toString();
|
|
34
|
+
return encoded ? `?${encoded}` : "";
|
|
35
|
+
}
|
|
36
|
+
/** The leader path segment for a validated handle. */
|
|
37
|
+
function leaderPath(handle) {
|
|
38
|
+
return `${BASE}/leaders/${encodeURIComponent(validate(LeaderHandleSchema, handle))}`;
|
|
39
|
+
}
|
|
40
|
+
/** The follow path segment for a validated follow id. */
|
|
41
|
+
function followPath(followId) {
|
|
42
|
+
return `${BASE}/follows/${validate(UUIDSchema, followId)}`;
|
|
43
|
+
}
|
|
44
|
+
export class CopyTradingAPIImpl extends BaseAPI {
|
|
45
|
+
/**
|
|
46
|
+
* List lead traders (the public leaderboard), highest first by `sort`
|
|
47
|
+
* (default `roi`) over `window` (default `30d`). No session needed.
|
|
48
|
+
*
|
|
49
|
+
* Cursor paged: pass the previous response's `nextPageToken` with the SAME
|
|
50
|
+
* sort and window; an empty token means the end. Rows come from a periodic
|
|
51
|
+
* leaderboard snapshot taken at `asOf`.
|
|
52
|
+
*/
|
|
53
|
+
async listLeadTraders(params = {}) {
|
|
54
|
+
const { sort, window, pageSize, pageToken } = validate(ListLeadTradersSchema, params);
|
|
55
|
+
return await this.makePublicRequest(`${BASE}/leaders${queryString({ sort, window, pageSize, pageToken })}`, {
|
|
56
|
+
method: "GET",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get one lead trader by custom TraderCode handle: profile, follow summary
|
|
61
|
+
* and stats for 7d, 30d, 90d and all. No session needed. 404 for an unknown
|
|
62
|
+
* or suspended leader.
|
|
63
|
+
*/
|
|
64
|
+
async getLeadTrader(handle) {
|
|
65
|
+
return await this.makePublicRequest(leaderPath(handle), { method: "GET" });
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* List a lead trader's closed trades — partial and full closes,
|
|
69
|
+
* liquidations and auto-deleveraging — newest first. No session needed.
|
|
70
|
+
*/
|
|
71
|
+
async listLeadTraderClosedTrades(handle, params = {}) {
|
|
72
|
+
const path = leaderPath(handle);
|
|
73
|
+
const { pageSize, pageToken } = validate(ListLeadTraderClosedTradesSchema, params);
|
|
74
|
+
return await this.makePublicRequest(`${path}/closed-trades${queryString({ pageSize, pageToken })}`, {
|
|
75
|
+
method: "GET",
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* List a lead trader's open positions. Only current followers of that
|
|
80
|
+
* leader may read them (403 otherwise).
|
|
81
|
+
*/
|
|
82
|
+
async listLeadTraderOpenPositions(handle) {
|
|
83
|
+
return await this.makeAuthenticatedRequest(`${leaderPath(handle)}/positions`, { method: "GET" });
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Register as a lead trader, or edit your profile. The profile is replaced
|
|
87
|
+
* as sent: an omitted `bio` or `minAllocation` clears it and an omitted
|
|
88
|
+
* `status` means `ACTIVE`; an omitted `shareBps` keeps the current share.
|
|
89
|
+
*/
|
|
90
|
+
async upsertLeadTrader(params = {}) {
|
|
91
|
+
const { shareBps, bio, status, minAllocation } = validate(UpsertLeadTraderSchema, params);
|
|
92
|
+
const body = {};
|
|
93
|
+
if (shareBps !== undefined)
|
|
94
|
+
body.shareBps = shareBps;
|
|
95
|
+
if (bio !== undefined)
|
|
96
|
+
body.bio = bio;
|
|
97
|
+
if (status !== undefined)
|
|
98
|
+
body.status = status;
|
|
99
|
+
if (minAllocation !== undefined)
|
|
100
|
+
body.minAllocation = minAllocation;
|
|
101
|
+
return await this.makeAuthenticatedRequest(`${BASE}/leaders/me`, {
|
|
102
|
+
method: "PUT",
|
|
103
|
+
body: JSON.stringify(body),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
/** Get your own lead trader profile (404 when you are not a lead trader). */
|
|
107
|
+
async getMyLeadTrader() {
|
|
108
|
+
return await this.makeAuthenticatedRequest(`${BASE}/leaders/me`, { method: "GET" });
|
|
109
|
+
}
|
|
110
|
+
/** List your followers, as a leader. Cursor paged, up to 1000 per page. */
|
|
111
|
+
async listMyFollowers(params = {}) {
|
|
112
|
+
const { pageSize, pageToken } = validate(ListMyFollowersSchema, params);
|
|
113
|
+
return await this.makeAuthenticatedRequest(`${BASE}/leaders/me/followers${queryString({ pageSize, pageToken })}`, {
|
|
114
|
+
method: "GET",
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Follow a lead trader (no `followId`), or edit one of your follows
|
|
119
|
+
* (`followId` set).
|
|
120
|
+
*
|
|
121
|
+
* An edit REPLACES the follow's settings: every optional setting left out
|
|
122
|
+
* reverts to its default, so an edit that omits `slPct` removes the
|
|
123
|
+
* stop-loss. The leader comes from the stored follow on an edit, so
|
|
124
|
+
* `leader` may be omitted there.
|
|
125
|
+
*/
|
|
126
|
+
async upsertFollow(params) {
|
|
127
|
+
const validated = validate(UpsertFollowSchema, params);
|
|
128
|
+
const body = {};
|
|
129
|
+
if (validated.followId !== undefined)
|
|
130
|
+
body.followId = validated.followId;
|
|
131
|
+
// The gateway requires the `leader` key on every request; an edit takes the
|
|
132
|
+
// leader from the stored follow and accepts it empty.
|
|
133
|
+
body.leader = validated.leader ?? "";
|
|
134
|
+
body.allocation = validated.allocation;
|
|
135
|
+
if (validated.marginModePolicy !== undefined)
|
|
136
|
+
body.marginModePolicy = validated.marginModePolicy;
|
|
137
|
+
if (validated.sizingMode !== undefined)
|
|
138
|
+
body.sizingMode = validated.sizingMode;
|
|
139
|
+
if (validated.sizingParam !== undefined)
|
|
140
|
+
body.sizingParam = validated.sizingParam;
|
|
141
|
+
if (validated.leverageMode !== undefined)
|
|
142
|
+
body.leverageMode = validated.leverageMode;
|
|
143
|
+
if (validated.fixedLeverage !== undefined)
|
|
144
|
+
body.fixedLeverage = validated.fixedLeverage;
|
|
145
|
+
if (validated.slPct !== undefined)
|
|
146
|
+
body.slPct = validated.slPct;
|
|
147
|
+
if (validated.tradingPairIds !== undefined)
|
|
148
|
+
body.markets = { tradingPairIds: validated.tradingPairIds };
|
|
149
|
+
if (validated.copyExisting !== undefined)
|
|
150
|
+
body.copyExisting = validated.copyExisting;
|
|
151
|
+
return await this.makeAuthenticatedRequest(`${BASE}/follows`, {
|
|
152
|
+
method: "POST",
|
|
153
|
+
body: JSON.stringify(body),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Preview what a follow with these terms would open if it set
|
|
158
|
+
* `copyExisting`, as totals only: estimated margin and fees, and how many
|
|
159
|
+
* of the leader's positions would and would not be copied. Read-only;
|
|
160
|
+
* nothing is placed or reserved.
|
|
161
|
+
*/
|
|
162
|
+
async previewFollow(params) {
|
|
163
|
+
const validated = validate(PreviewFollowSchema, params);
|
|
164
|
+
const body = { leader: validated.leader, allocation: validated.allocation };
|
|
165
|
+
if (validated.marginModePolicy !== undefined)
|
|
166
|
+
body.marginModePolicy = validated.marginModePolicy;
|
|
167
|
+
if (validated.sizingMode !== undefined)
|
|
168
|
+
body.sizingMode = validated.sizingMode;
|
|
169
|
+
if (validated.sizingParam !== undefined)
|
|
170
|
+
body.sizingParam = validated.sizingParam;
|
|
171
|
+
if (validated.leverageMode !== undefined)
|
|
172
|
+
body.leverageMode = validated.leverageMode;
|
|
173
|
+
if (validated.fixedLeverage !== undefined)
|
|
174
|
+
body.fixedLeverage = validated.fixedLeverage;
|
|
175
|
+
if (validated.tradingPairIds !== undefined)
|
|
176
|
+
body.markets = { tradingPairIds: validated.tradingPairIds };
|
|
177
|
+
return await this.makeAuthenticatedRequest(`${BASE}/follows/preview`, {
|
|
178
|
+
method: "POST",
|
|
179
|
+
body: JSON.stringify(body),
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
/** Stop one of your follows: the leader's fills stop being mirrored. */
|
|
183
|
+
async stopFollow(followId) {
|
|
184
|
+
return await this.makeAuthenticatedRequest(`${followPath(followId)}/stop`, { method: "POST" });
|
|
185
|
+
}
|
|
186
|
+
/** List your follows, newest first. Cursor paged, up to 1000 per page. */
|
|
187
|
+
async listMyFollows(params = {}) {
|
|
188
|
+
const { pageSize, pageToken } = validate(ListMyFollowsSchema, params);
|
|
189
|
+
return await this.makeAuthenticatedRequest(`${BASE}/follows${queryString({ pageSize, pageToken })}`, { method: "GET" });
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Get one of your follows with its most recent skipped mirrors (up to 100)
|
|
193
|
+
* and `copyAccountEquity`, the copy account's marked equity (absent when it
|
|
194
|
+
* could not be read).
|
|
195
|
+
*/
|
|
196
|
+
async getFollow(followId) {
|
|
197
|
+
return await this.makeAuthenticatedRequest(followPath(followId), { method: "GET" });
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* List the open positions of the leader one of your follows copies. The
|
|
201
|
+
* leader comes from the follow, so this works after the leader releases
|
|
202
|
+
* their handle. 404 for a follow that is not yours; 403 for a stopped one.
|
|
203
|
+
*/
|
|
204
|
+
async listFollowLeaderPositions(followId) {
|
|
205
|
+
return await this.makeAuthenticatedRequest(`${followPath(followId)}/leader-positions`, { method: "GET" });
|
|
206
|
+
}
|
|
207
|
+
}
|
package/dist/api/index.d.ts
CHANGED
package/dist/api/index.js
CHANGED
|
@@ -2,8 +2,8 @@ export declare const perpRoutes: {
|
|
|
2
2
|
readonly orders: {
|
|
3
3
|
readonly create: () => string;
|
|
4
4
|
readonly list: (params?: {
|
|
5
|
-
page?: number;
|
|
6
5
|
pageSize?: number;
|
|
6
|
+
pageToken?: string;
|
|
7
7
|
status?: string;
|
|
8
8
|
tradingPair?: string;
|
|
9
9
|
tradingMode?: string;
|
|
@@ -21,7 +21,6 @@ export declare const perpRoutes: {
|
|
|
21
21
|
marginAccountId?: string;
|
|
22
22
|
tradingPairId?: string;
|
|
23
23
|
state?: string;
|
|
24
|
-
page?: number;
|
|
25
24
|
pageSize?: number;
|
|
26
25
|
pageToken?: string;
|
|
27
26
|
}) => string;
|
|
@@ -31,7 +30,6 @@ export declare const perpRoutes: {
|
|
|
31
30
|
readonly listTwap: (params?: {
|
|
32
31
|
state?: string;
|
|
33
32
|
tradingPairId?: string;
|
|
34
|
-
page?: number;
|
|
35
33
|
pageSize?: number;
|
|
36
34
|
pageToken?: string;
|
|
37
35
|
}) => string;
|
|
@@ -115,8 +113,8 @@ export declare const perpRoutes: {
|
|
|
115
113
|
readonly user: (params?: {
|
|
116
114
|
marginAccountId?: string;
|
|
117
115
|
tradingPairId?: string;
|
|
118
|
-
page?: number;
|
|
119
116
|
pageSize?: number;
|
|
117
|
+
pageToken?: string;
|
|
120
118
|
}) => string;
|
|
121
119
|
};
|
|
122
120
|
readonly applications: {
|
|
@@ -50,8 +50,13 @@ export declare class ProfileAPIImpl extends BaseAPI implements ProfileAPI {
|
|
|
50
50
|
* Fetches the user's transaction history from the /api/v1/accounts/movements endpoint.
|
|
51
51
|
* Requires a valid access token to be set.
|
|
52
52
|
*
|
|
53
|
+
* The response `total` and `totalPages` are bounded by the listing's pagination reach:
|
|
54
|
+
* exact up to `pageSize` x 10,000 rows (10,000 pages) and saturating there, so a user
|
|
55
|
+
* with more matching movements than the listing can page through reads the cap, not
|
|
56
|
+
* their lifetime total. A `page` above 10,000 is rejected.
|
|
57
|
+
*
|
|
53
58
|
* @param params - Optional query parameters for pagination and filtering
|
|
54
|
-
* @param params.page - Page number (starts from 1, default: 1)
|
|
59
|
+
* @param params.page - Page number (starts from 1, default: 1, at most 10,000)
|
|
55
60
|
* @param params.limit - Number of items per page (default: 20, max: 100)
|
|
56
61
|
* @param params.entryType - Filter by entry type (CREDIT, DEBIT, LOCK, UNLOCK, FEE)
|
|
57
62
|
* @param params.transactionType - Filter by transaction type (DEPOSIT, WITHDRAWAL, TRADE, FEE, FUNDING, LIQUIDATION, INTEREST, REWARD)
|
|
@@ -171,23 +176,16 @@ export declare class ProfileAPIImpl extends BaseAPI implements ProfileAPI {
|
|
|
171
176
|
*
|
|
172
177
|
* When neither `page` nor `pageToken` is passed, the SDK drives cursor (pageToken)
|
|
173
178
|
* pagination: it starts a cursor walk from the newest row and the response's
|
|
174
|
-
* `nextPageToken` resumes it.
|
|
175
|
-
*
|
|
179
|
+
* `nextPageToken` resumes it. Responses carry no item count: the `trades`
|
|
180
|
+
* table is too large to count behind a filter.
|
|
176
181
|
*
|
|
177
182
|
* @param params - Optional query parameters for pagination and filtering
|
|
178
|
-
* @param params.
|
|
179
|
-
* from 1, at most 10,000). Passing it selects legacy page-number mode, which only sees
|
|
180
|
-
* recent (hot) history and populates `total`/`totalPages` — bounded at the pagination
|
|
181
|
-
* reach (`total` saturates at `pageSize` × 10,000 rows, `totalPages` at 10,000 pages).
|
|
182
|
-
* Use cursor pagination (`pageToken`) instead.
|
|
183
|
-
* @param params.pageSize - Number of items per page (default: 20; max 100
|
|
184
|
-
* in page-number mode, up to 1000 when pageToken is present)
|
|
183
|
+
* @param params.pageSize - Number of items per page (default: 20; up to 1000)
|
|
185
184
|
* @param params.tradingPairId - Filter by trading pair ID (UUID)
|
|
186
185
|
* @param params.pageToken - Pagination cursor: pass `""` to start a cursor walk from
|
|
187
|
-
* the newest row; pass a previous response's `nextPageToken` to resume.
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
* `pageToken` starts a cursor walk (`pageToken=""`).
|
|
186
|
+
* the newest row; pass a previous response's `nextPageToken` to resume. Omitting it
|
|
187
|
+
* starts the same walk. Every walk covers full trade history, hot and archived rows
|
|
188
|
+
* merged.
|
|
191
189
|
* @returns Promise resolving to paginated trades response
|
|
192
190
|
* @throws {ValidationError} When the provided params fail client-side validation
|
|
193
191
|
* @throws {APIError} When the request fails or user is not authenticated
|
|
@@ -214,10 +212,10 @@ export declare class ProfileAPIImpl extends BaseAPI implements ProfileAPI {
|
|
|
214
212
|
* Starts a cursor walk (`pageToken: ""`) and follows each response's
|
|
215
213
|
* `nextPageToken` until the server proves exhaustion (a page with zero rows
|
|
216
214
|
* and an empty token). Covers full trade history — hot and archived rows
|
|
217
|
-
* merged
|
|
215
|
+
* merged.
|
|
218
216
|
*
|
|
219
|
-
* @param params - Optional filters and page size; `
|
|
220
|
-
*
|
|
217
|
+
* @param params - Optional filters and page size; `pageToken` is managed by
|
|
218
|
+
* the iterator and cannot be passed.
|
|
221
219
|
* @returns Async generator yielding trades newest-first
|
|
222
220
|
* @throws {APIError} When any underlying request fails
|
|
223
221
|
*
|
|
@@ -235,6 +233,11 @@ export declare class ProfileAPIImpl extends BaseAPI implements ProfileAPI {
|
|
|
235
233
|
* Fetches funding payments from the /api/v1/accounts/funding-payments endpoint.
|
|
236
234
|
* Requires a valid access token to be set.
|
|
237
235
|
*
|
|
236
|
+
* The response `total` and `totalPages` are bounded by the listing's pagination reach:
|
|
237
|
+
* exact up to `pageSize` x 10,000 rows (10,000 pages) and saturating there, so a user
|
|
238
|
+
* with more matching payments than the listing can page through reads the cap, not
|
|
239
|
+
* their lifetime total. A `page` above 10,000 is rejected.
|
|
240
|
+
*
|
|
238
241
|
* @param params - Optional query parameters for pagination and filtering
|
|
239
242
|
* @returns Promise resolving to paginated funding payments response
|
|
240
243
|
* @throws {APIError} When the request fails or user is not authenticated
|
package/dist/api/profile/api.js
CHANGED
|
@@ -53,8 +53,13 @@ export class ProfileAPIImpl extends BaseAPI {
|
|
|
53
53
|
* Fetches the user's transaction history from the /api/v1/accounts/movements endpoint.
|
|
54
54
|
* Requires a valid access token to be set.
|
|
55
55
|
*
|
|
56
|
+
* The response `total` and `totalPages` are bounded by the listing's pagination reach:
|
|
57
|
+
* exact up to `pageSize` x 10,000 rows (10,000 pages) and saturating there, so a user
|
|
58
|
+
* with more matching movements than the listing can page through reads the cap, not
|
|
59
|
+
* their lifetime total. A `page` above 10,000 is rejected.
|
|
60
|
+
*
|
|
56
61
|
* @param params - Optional query parameters for pagination and filtering
|
|
57
|
-
* @param params.page - Page number (starts from 1, default: 1)
|
|
62
|
+
* @param params.page - Page number (starts from 1, default: 1, at most 10,000)
|
|
58
63
|
* @param params.limit - Number of items per page (default: 20, max: 100)
|
|
59
64
|
* @param params.entryType - Filter by entry type (CREDIT, DEBIT, LOCK, UNLOCK, FEE)
|
|
60
65
|
* @param params.transactionType - Filter by transaction type (DEPOSIT, WITHDRAWAL, TRADE, FEE, FUNDING, LIQUIDATION, INTEREST, REWARD)
|
|
@@ -222,23 +227,16 @@ export class ProfileAPIImpl extends BaseAPI {
|
|
|
222
227
|
*
|
|
223
228
|
* When neither `page` nor `pageToken` is passed, the SDK drives cursor (pageToken)
|
|
224
229
|
* pagination: it starts a cursor walk from the newest row and the response's
|
|
225
|
-
* `nextPageToken` resumes it.
|
|
226
|
-
*
|
|
230
|
+
* `nextPageToken` resumes it. Responses carry no item count: the `trades`
|
|
231
|
+
* table is too large to count behind a filter.
|
|
227
232
|
*
|
|
228
233
|
* @param params - Optional query parameters for pagination and filtering
|
|
229
|
-
* @param params.
|
|
230
|
-
* from 1, at most 10,000). Passing it selects legacy page-number mode, which only sees
|
|
231
|
-
* recent (hot) history and populates `total`/`totalPages` — bounded at the pagination
|
|
232
|
-
* reach (`total` saturates at `pageSize` × 10,000 rows, `totalPages` at 10,000 pages).
|
|
233
|
-
* Use cursor pagination (`pageToken`) instead.
|
|
234
|
-
* @param params.pageSize - Number of items per page (default: 20; max 100
|
|
235
|
-
* in page-number mode, up to 1000 when pageToken is present)
|
|
234
|
+
* @param params.pageSize - Number of items per page (default: 20; up to 1000)
|
|
236
235
|
* @param params.tradingPairId - Filter by trading pair ID (UUID)
|
|
237
236
|
* @param params.pageToken - Pagination cursor: pass `""` to start a cursor walk from
|
|
238
|
-
* the newest row; pass a previous response's `nextPageToken` to resume.
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
* `pageToken` starts a cursor walk (`pageToken=""`).
|
|
237
|
+
* the newest row; pass a previous response's `nextPageToken` to resume. Omitting it
|
|
238
|
+
* starts the same walk. Every walk covers full trade history, hot and archived rows
|
|
239
|
+
* merged.
|
|
242
240
|
* @returns Promise resolving to paginated trades response
|
|
243
241
|
* @throws {ValidationError} When the provided params fail client-side validation
|
|
244
242
|
* @throws {APIError} When the request fails or user is not authenticated
|
|
@@ -261,27 +259,17 @@ export class ProfileAPIImpl extends BaseAPI {
|
|
|
261
259
|
if (params) {
|
|
262
260
|
validate(GetUserTradesSchema, params);
|
|
263
261
|
}
|
|
264
|
-
// Legacy offset mode only when the caller explicitly asked for a page and
|
|
265
|
-
// no cursor was given; everything else drives cursor (pageToken) mode.
|
|
266
|
-
const legacyOffsetMode = params?.page !== undefined && params?.pageToken === undefined;
|
|
267
262
|
const searchParams = new URLSearchParams();
|
|
268
|
-
if (legacyOffsetMode && params?.page !== undefined) {
|
|
269
|
-
searchParams.append("page", params.page.toString());
|
|
270
|
-
}
|
|
271
263
|
if (params?.pageSize !== undefined) {
|
|
272
264
|
searchParams.append("pageSize", params.pageSize.toString());
|
|
273
265
|
}
|
|
274
266
|
if (params?.tradingPairId !== undefined) {
|
|
275
267
|
searchParams.append("tradingPairId", params.tradingPairId);
|
|
276
268
|
}
|
|
277
|
-
//
|
|
278
|
-
//
|
|
279
|
-
//
|
|
280
|
-
|
|
281
|
-
// a cursor walk (`pageToken=""`).
|
|
282
|
-
if (!legacyOffsetMode) {
|
|
283
|
-
searchParams.append("pageToken", params?.pageToken ?? "");
|
|
284
|
-
}
|
|
269
|
+
// One pagination mode. `pageToken` is sent even as the empty string — the
|
|
270
|
+
// server selects the walk by the token's PRESENCE, not its value — so it
|
|
271
|
+
// must not be dropped the way a falsy value usually would be.
|
|
272
|
+
searchParams.append("pageToken", params?.pageToken ?? "");
|
|
285
273
|
const queryString = searchParams.toString();
|
|
286
274
|
const url = queryString ? `/api/v1/accounts/trades?${queryString}` : "/api/v1/accounts/trades";
|
|
287
275
|
return await this.makeAuthenticatedRequest(url);
|
|
@@ -293,10 +281,10 @@ export class ProfileAPIImpl extends BaseAPI {
|
|
|
293
281
|
* Starts a cursor walk (`pageToken: ""`) and follows each response's
|
|
294
282
|
* `nextPageToken` until the server proves exhaustion (a page with zero rows
|
|
295
283
|
* and an empty token). Covers full trade history — hot and archived rows
|
|
296
|
-
* merged
|
|
284
|
+
* merged.
|
|
297
285
|
*
|
|
298
|
-
* @param params - Optional filters and page size; `
|
|
299
|
-
*
|
|
286
|
+
* @param params - Optional filters and page size; `pageToken` is managed by
|
|
287
|
+
* the iterator and cannot be passed.
|
|
300
288
|
* @returns Async generator yielding trades newest-first
|
|
301
289
|
* @throws {APIError} When any underlying request fails
|
|
302
290
|
*
|
|
@@ -327,6 +315,11 @@ export class ProfileAPIImpl extends BaseAPI {
|
|
|
327
315
|
* Fetches funding payments from the /api/v1/accounts/funding-payments endpoint.
|
|
328
316
|
* Requires a valid access token to be set.
|
|
329
317
|
*
|
|
318
|
+
* The response `total` and `totalPages` are bounded by the listing's pagination reach:
|
|
319
|
+
* exact up to `pageSize` x 10,000 rows (10,000 pages) and saturating there, so a user
|
|
320
|
+
* with more matching payments than the listing can page through reads the cap, not
|
|
321
|
+
* their lifetime total. A `page` above 10,000 is rejected.
|
|
322
|
+
*
|
|
330
323
|
* @param params - Optional query parameters for pagination and filtering
|
|
331
324
|
* @returns Promise resolving to paginated funding payments response
|
|
332
325
|
* @throws {APIError} When the request fails or user is not authenticated
|
|
@@ -197,14 +197,10 @@ export declare class TradingAPIImpl extends BaseAPI implements TradingAPI {
|
|
|
197
197
|
* via each response's `nextPageToken` until that token comes back empty. A
|
|
198
198
|
* cursor page size may go up to 1000.
|
|
199
199
|
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
* no COUNT.
|
|
205
|
-
*
|
|
206
|
-
* @param params - Optional filters and pagination; `pageToken` drives cursor
|
|
207
|
-
* mode, `page` drives the deprecated legacy mode
|
|
200
|
+
* `total` is the count of matching rows, bounded at a server ceiling of
|
|
201
|
+
* 10,000 and saturating there.
|
|
202
|
+
*
|
|
203
|
+
* @param params - Optional filters and cursor pagination via `pageToken`
|
|
208
204
|
* @returns Promise resolving to ListConditionalOrdersResponse with orders and pagination info
|
|
209
205
|
* @throws {APIError} When API communication fails
|
|
210
206
|
*/
|
|
@@ -334,17 +330,13 @@ export declare class TradingAPIImpl extends BaseAPI implements TradingAPI {
|
|
|
334
330
|
* @param params.status - Filter by order status (e.g., "SUBMITTED", "FILLED"), or by
|
|
335
331
|
* any of several statuses at once by passing an array (e.g., ["SUBMITTED", "PARTIALLY_FILLED"]) (optional)
|
|
336
332
|
* @param params.tradingPairId - Filter by trading pair UUID (optional)
|
|
337
|
-
* @param params.
|
|
338
|
-
*
|
|
339
|
-
* modes populate `total`/`totalPages` (bounded — see `totalCapped`); use cursor
|
|
340
|
-
* pagination (`pageToken`) instead for full history.
|
|
341
|
-
* @param params.pageSize - Number of orders per page (defaults to 10, must be > 0; max 100
|
|
342
|
-
* in page-number mode, up to 1000 when pageToken is present)
|
|
333
|
+
* @param params.pageSize - Number of orders per page (defaults to 10, must be > 0;
|
|
334
|
+
* up to 1000)
|
|
343
335
|
* @param params.pageToken - Pagination cursor: pass `""` to start a cursor walk from
|
|
344
336
|
* the newest (or oldest, for `orderBy: "ASC"`) row; pass a previous response's
|
|
345
|
-
* `nextPageToken` to resume.
|
|
346
|
-
*
|
|
347
|
-
*
|
|
337
|
+
* `nextPageToken` to resume. Omitting it starts the same walk. Every walk covers
|
|
338
|
+
* full order history, hot and archived rows merged. `total`/`totalPages` are
|
|
339
|
+
* bounded — see `totalCapped`.
|
|
348
340
|
* @returns Promise resolving to GetPaginatedOrdersResponse with orders and pagination info
|
|
349
341
|
* @throws {APIError} When API communication fails
|
|
350
342
|
*
|
|
@@ -378,10 +370,10 @@ export declare class TradingAPIImpl extends BaseAPI implements TradingAPI {
|
|
|
378
370
|
* Starts a cursor walk (`pageToken: ""`) and follows each response's
|
|
379
371
|
* `nextPageToken` until the server proves exhaustion (a page with zero rows
|
|
380
372
|
* and an empty token). Covers full order history — hot and archived rows
|
|
381
|
-
* merged
|
|
373
|
+
* merged.
|
|
382
374
|
*
|
|
383
|
-
* @param params - Optional filters and page size; `
|
|
384
|
-
*
|
|
375
|
+
* @param params - Optional filters and page size; `pageToken` is managed by
|
|
376
|
+
* the iterator and cannot be passed.
|
|
385
377
|
* @returns Async generator yielding orders newest-first (or oldest-first for
|
|
386
378
|
* `orderBy: "ASC"`)
|
|
387
379
|
* @throws {APIError} When any underlying request fails
|
|
@@ -535,14 +527,10 @@ export declare class TradingAPIImpl extends BaseAPI implements TradingAPI {
|
|
|
535
527
|
* via each response's `nextPageToken` until that token comes back empty. A
|
|
536
528
|
* cursor page size may go up to 1000.
|
|
537
529
|
*
|
|
538
|
-
*
|
|
539
|
-
*
|
|
540
|
-
* bounded `total` (exact up to `pageSize` x 10,000 rows, saturating there);
|
|
541
|
-
* `page` is capped at 10,000. Cursor mode returns `total`/`page` as 0 and runs
|
|
542
|
-
* no COUNT.
|
|
530
|
+
* `total` is the count of matching rows, bounded at a server ceiling of
|
|
531
|
+
* 10,000 and saturating there.
|
|
543
532
|
*
|
|
544
|
-
* @param params - Optional filters and pagination
|
|
545
|
-
* mode, `page` drives the deprecated legacy mode
|
|
533
|
+
* @param params - Optional filters and cursor pagination via `pageToken`
|
|
546
534
|
* @returns Promise resolving to ListTwapOrdersResponse with orders and pagination info
|
|
547
535
|
* @throws {APIError} When API communication fails
|
|
548
536
|
*
|
package/dist/api/trading/api.js
CHANGED
|
@@ -282,14 +282,10 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
282
282
|
* via each response's `nextPageToken` until that token comes back empty. A
|
|
283
283
|
* cursor page size may go up to 1000.
|
|
284
284
|
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
* no COUNT.
|
|
290
|
-
*
|
|
291
|
-
* @param params - Optional filters and pagination; `pageToken` drives cursor
|
|
292
|
-
* mode, `page` drives the deprecated legacy mode
|
|
285
|
+
* `total` is the count of matching rows, bounded at a server ceiling of
|
|
286
|
+
* 10,000 and saturating there.
|
|
287
|
+
*
|
|
288
|
+
* @param params - Optional filters and cursor pagination via `pageToken`
|
|
293
289
|
* @returns Promise resolving to ListConditionalOrdersResponse with orders and pagination info
|
|
294
290
|
* @throws {APIError} When API communication fails
|
|
295
291
|
*/
|
|
@@ -297,24 +293,16 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
297
293
|
if (params) {
|
|
298
294
|
validate(ListConditionalOrdersSchema, params);
|
|
299
295
|
}
|
|
300
|
-
const {
|
|
301
|
-
|
|
302
|
-
// cursor was given; everything else drives cursor (pageToken) mode.
|
|
303
|
-
const legacyOffsetMode = page !== undefined && pageToken === undefined;
|
|
304
|
-
// Cursor requests may use pages up to 1000 (keyset reads); page-number
|
|
305
|
-
// requests keep the server's 100 cap.
|
|
306
|
-
const boundedPageSize = Math.min(Math.max(pageSize, 1), legacyOffsetMode ? 100 : 1000);
|
|
296
|
+
const { pageSize = 20, marginAccountId, tradingPairId, state, pageToken } = params || {};
|
|
297
|
+
const boundedPageSize = Math.min(Math.max(pageSize, 1), 1000);
|
|
307
298
|
return await this.makeAuthenticatedRequest(perpRoutes.orders.listConditional({
|
|
308
299
|
marginAccountId,
|
|
309
300
|
tradingPairId,
|
|
310
301
|
state,
|
|
311
|
-
// Legacy mode sends `page` and omits `pageToken`; cursor mode omits
|
|
312
|
-
// `page` and sends `pageToken` — present even as the empty string, the
|
|
313
|
-
// documented way to start a walk (the server selects cursor mode by the
|
|
314
|
-
// token's presence, not its value).
|
|
315
|
-
page: legacyOffsetMode ? page : undefined,
|
|
316
302
|
pageSize: boundedPageSize,
|
|
317
|
-
|
|
303
|
+
// Sent even as the empty string: the server starts a walk on the
|
|
304
|
+
// token's PRESENCE, not its value.
|
|
305
|
+
pageToken: pageToken ?? "",
|
|
318
306
|
}), { method: "GET" });
|
|
319
307
|
}
|
|
320
308
|
/**
|
|
@@ -522,17 +510,13 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
522
510
|
* @param params.status - Filter by order status (e.g., "SUBMITTED", "FILLED"), or by
|
|
523
511
|
* any of several statuses at once by passing an array (e.g., ["SUBMITTED", "PARTIALLY_FILLED"]) (optional)
|
|
524
512
|
* @param params.tradingPairId - Filter by trading pair UUID (optional)
|
|
525
|
-
* @param params.
|
|
526
|
-
*
|
|
527
|
-
* modes populate `total`/`totalPages` (bounded — see `totalCapped`); use cursor
|
|
528
|
-
* pagination (`pageToken`) instead for full history.
|
|
529
|
-
* @param params.pageSize - Number of orders per page (defaults to 10, must be > 0; max 100
|
|
530
|
-
* in page-number mode, up to 1000 when pageToken is present)
|
|
513
|
+
* @param params.pageSize - Number of orders per page (defaults to 10, must be > 0;
|
|
514
|
+
* up to 1000)
|
|
531
515
|
* @param params.pageToken - Pagination cursor: pass `""` to start a cursor walk from
|
|
532
516
|
* the newest (or oldest, for `orderBy: "ASC"`) row; pass a previous response's
|
|
533
|
-
* `nextPageToken` to resume.
|
|
534
|
-
*
|
|
535
|
-
*
|
|
517
|
+
* `nextPageToken` to resume. Omitting it starts the same walk. Every walk covers
|
|
518
|
+
* full order history, hot and archived rows merged. `total`/`totalPages` are
|
|
519
|
+
* bounded — see `totalCapped`.
|
|
536
520
|
* @returns Promise resolving to GetPaginatedOrdersResponse with orders and pagination info
|
|
537
521
|
* @throws {APIError} When API communication fails
|
|
538
522
|
*
|
|
@@ -564,19 +548,10 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
564
548
|
validate(GetPaginatedOrdersSchema, params);
|
|
565
549
|
}
|
|
566
550
|
// Set pagination defaults with destructuring and validation
|
|
567
|
-
const {
|
|
551
|
+
const { pageSize: requestedPageSize = 10, status, tradingPairId, tradingMode, marginAccountId, pageToken } = params || {};
|
|
568
552
|
const validPageSize = requestedPageSize > 0 ? requestedPageSize : 10;
|
|
569
|
-
|
|
570
|
-
// no cursor was given; everything else drives cursor (pageToken) mode.
|
|
571
|
-
const legacyOffsetMode = page !== undefined && pageToken === undefined;
|
|
572
|
-
// Cursor requests may use pages up to 1000 (keyset reads); page-number
|
|
573
|
-
// requests keep the server's 100 cap.
|
|
574
|
-
const pageSize = Math.min(validPageSize, legacyOffsetMode ? 100 : 1000);
|
|
553
|
+
const pageSize = Math.min(validPageSize, 1000);
|
|
575
554
|
const searchParams = new URLSearchParams();
|
|
576
|
-
if (legacyOffsetMode) {
|
|
577
|
-
const validPage = page > 0 ? page : 1;
|
|
578
|
-
searchParams.append("page", validPage.toString());
|
|
579
|
-
}
|
|
580
555
|
searchParams.append("pageSize", pageSize.toString());
|
|
581
556
|
// An array filter is sent as one comma-separated `status` value, which the
|
|
582
557
|
// API reads as "any of these", so several statuses cost a single request.
|
|
@@ -593,14 +568,10 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
593
568
|
if (marginAccountId) {
|
|
594
569
|
searchParams.append("marginAccountId", marginAccountId);
|
|
595
570
|
}
|
|
596
|
-
//
|
|
597
|
-
//
|
|
598
|
-
//
|
|
599
|
-
|
|
600
|
-
// a cursor walk (`pageToken=""`).
|
|
601
|
-
if (!legacyOffsetMode) {
|
|
602
|
-
searchParams.append("pageToken", pageToken ?? "");
|
|
603
|
-
}
|
|
571
|
+
// One pagination mode. `pageToken` is sent even as the empty string — the
|
|
572
|
+
// server selects the walk by the token's PRESENCE, not its value — so it
|
|
573
|
+
// must not be dropped the way a falsy value usually would be.
|
|
574
|
+
searchParams.append("pageToken", pageToken ?? "");
|
|
604
575
|
const endpoint = `/api/v1/orders?${searchParams.toString()}`;
|
|
605
576
|
return await this.makeAuthenticatedRequest(endpoint, {
|
|
606
577
|
method: "GET",
|
|
@@ -613,10 +584,10 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
613
584
|
* Starts a cursor walk (`pageToken: ""`) and follows each response's
|
|
614
585
|
* `nextPageToken` until the server proves exhaustion (a page with zero rows
|
|
615
586
|
* and an empty token). Covers full order history — hot and archived rows
|
|
616
|
-
* merged
|
|
587
|
+
* merged.
|
|
617
588
|
*
|
|
618
|
-
* @param params - Optional filters and page size; `
|
|
619
|
-
*
|
|
589
|
+
* @param params - Optional filters and page size; `pageToken` is managed by
|
|
590
|
+
* the iterator and cannot be passed.
|
|
620
591
|
* @returns Async generator yielding orders newest-first (or oldest-first for
|
|
621
592
|
* `orderBy: "ASC"`)
|
|
622
593
|
* @throws {APIError} When any underlying request fails
|
|
@@ -845,14 +816,10 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
845
816
|
* via each response's `nextPageToken` until that token comes back empty. A
|
|
846
817
|
* cursor page size may go up to 1000.
|
|
847
818
|
*
|
|
848
|
-
*
|
|
849
|
-
*
|
|
850
|
-
* bounded `total` (exact up to `pageSize` x 10,000 rows, saturating there);
|
|
851
|
-
* `page` is capped at 10,000. Cursor mode returns `total`/`page` as 0 and runs
|
|
852
|
-
* no COUNT.
|
|
819
|
+
* `total` is the count of matching rows, bounded at a server ceiling of
|
|
820
|
+
* 10,000 and saturating there.
|
|
853
821
|
*
|
|
854
|
-
* @param params - Optional filters and pagination
|
|
855
|
-
* mode, `page` drives the deprecated legacy mode
|
|
822
|
+
* @param params - Optional filters and cursor pagination via `pageToken`
|
|
856
823
|
* @returns Promise resolving to ListTwapOrdersResponse with orders and pagination info
|
|
857
824
|
* @throws {APIError} When API communication fails
|
|
858
825
|
*
|
|
@@ -866,23 +833,15 @@ export class TradingAPIImpl extends BaseAPI {
|
|
|
866
833
|
if (params) {
|
|
867
834
|
validate(ListTwapOrdersSchema, params);
|
|
868
835
|
}
|
|
869
|
-
const {
|
|
870
|
-
|
|
871
|
-
// cursor was given; everything else drives cursor (pageToken) mode.
|
|
872
|
-
const legacyOffsetMode = page !== undefined && pageToken === undefined;
|
|
873
|
-
// Cursor requests may use pages up to 1000 (keyset reads); page-number
|
|
874
|
-
// requests keep the server's 100 cap.
|
|
875
|
-
const boundedPageSize = Math.min(Math.max(pageSize, 1), legacyOffsetMode ? 100 : 1000);
|
|
836
|
+
const { pageSize = 20, state, tradingPairId, pageToken } = params || {};
|
|
837
|
+
const boundedPageSize = Math.min(Math.max(pageSize, 1), 1000);
|
|
876
838
|
return await this.makeAuthenticatedRequest(perpRoutes.orders.listTwap({
|
|
877
839
|
state,
|
|
878
840
|
tradingPairId,
|
|
879
|
-
// Legacy mode sends `page` and omits `pageToken`; cursor mode omits
|
|
880
|
-
// `page` and sends `pageToken` — present even as the empty string, the
|
|
881
|
-
// documented way to start a walk (the server selects cursor mode by the
|
|
882
|
-
// token's presence, not its value).
|
|
883
|
-
page: legacyOffsetMode ? page : undefined,
|
|
884
841
|
pageSize: boundedPageSize,
|
|
885
|
-
|
|
842
|
+
// Sent even as the empty string: the server starts a walk on the
|
|
843
|
+
// token's PRESENCE, not its value.
|
|
844
|
+
pageToken: pageToken ?? "",
|
|
886
845
|
}), { method: "GET" });
|
|
887
846
|
}
|
|
888
847
|
}
|
|
@@ -69,6 +69,12 @@ function readBoolean(source, field) {
|
|
|
69
69
|
}
|
|
70
70
|
return value;
|
|
71
71
|
}
|
|
72
|
+
function readOptionalBoolean(source, field) {
|
|
73
|
+
const value = source[field];
|
|
74
|
+
if (value === undefined || value === null)
|
|
75
|
+
return undefined;
|
|
76
|
+
return readBoolean(source, field);
|
|
77
|
+
}
|
|
72
78
|
/**
|
|
73
79
|
* Read a wire sequence counter: a non-negative safe integer. The server
|
|
74
80
|
* serializes Rust `u64` sequence fields as plain JSON numbers, so a negative,
|
|
@@ -528,6 +534,67 @@ function parseTwapOrderEventData(raw) {
|
|
|
528
534
|
}
|
|
529
535
|
return data;
|
|
530
536
|
}
|
|
537
|
+
/**
|
|
538
|
+
* camelCase a `copy` channel payload and drop explicit `null`s, so the result
|
|
539
|
+
* matches the optional (`?:`) fields of the published copy event types. Only
|
|
540
|
+
* the named identity fields are validated.
|
|
541
|
+
*/
|
|
542
|
+
function copyPayload(raw, what, required) {
|
|
543
|
+
if (!isRecord(raw)) {
|
|
544
|
+
throw new Error(`Invalid copy ${what}: data must be an object`);
|
|
545
|
+
}
|
|
546
|
+
const data = keysToCamelCase(raw);
|
|
547
|
+
for (const key of Object.keys(data)) {
|
|
548
|
+
if (data[key] === null) {
|
|
549
|
+
delete data[key];
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
for (const field of required) {
|
|
553
|
+
const value = data[field];
|
|
554
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
555
|
+
throw new Error(`Invalid copy ${what}: ${field} must be a non-empty string`);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return data;
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Parse a copy relationship row: the `copy_relationship_update` payload, and
|
|
562
|
+
* each subscribe-time snapshot row. The identity fields and `status` are
|
|
563
|
+
* required; every value field (status, policies, `change`, `stopReason`) is
|
|
564
|
+
* passed through unchecked, so a label this SDK version predates is delivered
|
|
565
|
+
* rather than dropping the update (0XM-2627). The declared unions document the
|
|
566
|
+
* values the server sends today.
|
|
567
|
+
*/
|
|
568
|
+
function parseCopyRelationshipEventData(raw) {
|
|
569
|
+
return copyPayload(raw, "relationship update", ["relationshipId", "status"]);
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Parse a `copy_skip` payload. The skip `reason` is passed through unchecked
|
|
573
|
+
* for the same reason as the relationship labels.
|
|
574
|
+
*/
|
|
575
|
+
function parseCopySkipEventData(raw) {
|
|
576
|
+
return copyPayload(raw, "skip", ["relationshipId", "reason"]);
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Parse a `copy` channel frame. `event_type` is the channel-class
|
|
580
|
+
* discriminator that picks the payload shape, so it is matched strictly: a
|
|
581
|
+
* frame of any other type (such as the reserved `copy_payout`) is rejected
|
|
582
|
+
* rather than parsed as the wrong shape.
|
|
583
|
+
*/
|
|
584
|
+
function parseCopyEvent(rawData) {
|
|
585
|
+
if (!isRecord(rawData)) {
|
|
586
|
+
throw new Error("Invalid copy event: payload must be an object");
|
|
587
|
+
}
|
|
588
|
+
const userId = rawData.user_id;
|
|
589
|
+
if (typeof userId !== "string" || userId.length === 0) {
|
|
590
|
+
throw new Error("Invalid copy event: user_id must be a non-empty string");
|
|
591
|
+
}
|
|
592
|
+
const eventType = readEnum(rawData, "event_type", ["copy_relationship_update", "copy_skip"]);
|
|
593
|
+
if (eventType === "copy_relationship_update") {
|
|
594
|
+
return { eventType, userId, data: parseCopyRelationshipEventData(rawData.data) };
|
|
595
|
+
}
|
|
596
|
+
return { eventType, userId, data: parseCopySkipEventData(rawData.data) };
|
|
597
|
+
}
|
|
531
598
|
/**
|
|
532
599
|
* Parse a user balance payload. Shared by the live event and the subscribe-time
|
|
533
600
|
* snapshot (see {@link parseConditionalOrderEventData}).
|
|
@@ -597,6 +664,10 @@ function parseOrderSnapshotItem(raw) {
|
|
|
597
664
|
const clientOrderId = readOptionalString(item, "clientOrderId");
|
|
598
665
|
const selfTradePreventionMode = readOptionalString(item, "selfTradePreventionMode");
|
|
599
666
|
const parentOrderId = readOptionalString(item, "parentOrderId");
|
|
667
|
+
const postOnly = readOptionalBoolean(item, "postOnly");
|
|
668
|
+
const expirationDate = readOptionalString(item, "expirationDate");
|
|
669
|
+
const triggerPrice = readOptionalString(item, "triggerPrice");
|
|
670
|
+
const positionSide = readOptionalString(item, "positionSide");
|
|
600
671
|
const version = readOptionalNumber(item, "version");
|
|
601
672
|
return {
|
|
602
673
|
orderId: readString(item, "orderId"),
|
|
@@ -634,6 +705,12 @@ function parseOrderSnapshotItem(raw) {
|
|
|
634
705
|
// Spread in conditionally too: absent for an order that is not a TWAP
|
|
635
706
|
// child, and absent must stay absent.
|
|
636
707
|
...(parentOrderId === undefined ? {} : { parentOrderId }),
|
|
708
|
+
// The four REST order-shape fields, each omitted by the server when REST
|
|
709
|
+
// omits it, so absent must stay absent.
|
|
710
|
+
...(postOnly === undefined ? {} : { postOnly }),
|
|
711
|
+
...(expirationDate === undefined ? {} : { expirationDate }),
|
|
712
|
+
...(triggerPrice === undefined ? {} : { triggerPrice }),
|
|
713
|
+
...(positionSide === undefined ? {} : { positionSide }),
|
|
637
714
|
// Spread in conditionally for the same reason as `clientOrderId`: the
|
|
638
715
|
// server omits the key when unknown, and absent must stay absent rather
|
|
639
716
|
// than becoming `version: undefined` — a resync compares this value, and
|
|
@@ -1420,6 +1497,25 @@ export function createMonacoWebSocket(baseUrl, options = {}, serverClock = new S
|
|
|
1420
1497
|
}
|
|
1421
1498
|
}, onSnapshot && snapshotFrameHandler("TWAP orders", parseTwapOrderEventData, onSnapshot));
|
|
1422
1499
|
};
|
|
1500
|
+
/**
|
|
1501
|
+
* Subscribe to the authenticated follower's copy trading stream: every
|
|
1502
|
+
* change to one of their follows, and every leader fill a follow could not
|
|
1503
|
+
* mirror. Bare channel only — relationships span markets. The snapshot is
|
|
1504
|
+
* the follower's live follows (`change: "snapshot"`).
|
|
1505
|
+
*/
|
|
1506
|
+
const subscribeCopy = (handler, onSnapshot) => {
|
|
1507
|
+
if (!handler) {
|
|
1508
|
+
throw new Error("copy subscription requires a handler");
|
|
1509
|
+
}
|
|
1510
|
+
return subscribe("copy", (rawData) => {
|
|
1511
|
+
try {
|
|
1512
|
+
handler(parseCopyEvent(rawData));
|
|
1513
|
+
}
|
|
1514
|
+
catch (err) {
|
|
1515
|
+
console.error("WebSocket: Error processing copy event", err);
|
|
1516
|
+
}
|
|
1517
|
+
}, onSnapshot && snapshotFrameHandler("copy", parseCopyRelationshipEventData, onSnapshot));
|
|
1518
|
+
};
|
|
1423
1519
|
/**
|
|
1424
1520
|
* Subscribe to authenticated user's position updates.
|
|
1425
1521
|
* Requires authentication - user is identified from the signed session-key
|
|
@@ -1718,6 +1814,7 @@ export function createMonacoWebSocket(baseUrl, options = {}, serverClock = new S
|
|
|
1718
1814
|
balances: subscribeBalances,
|
|
1719
1815
|
conditionalOrders: subscribeConditionalOrders,
|
|
1720
1816
|
twapOrders: subscribeTwapOrders,
|
|
1817
|
+
copy: subscribeCopy,
|
|
1721
1818
|
positions: subscribePositions,
|
|
1722
1819
|
liquidations: subscribeLiquidations,
|
|
1723
1820
|
account: subscribeAccount,
|
package/dist/coverage.d.ts
CHANGED
|
@@ -10,6 +10,19 @@ export declare const COVERED: {
|
|
|
10
10
|
cancel_conditional_order: string;
|
|
11
11
|
get_conditional_order: string;
|
|
12
12
|
cancel_order: string;
|
|
13
|
+
upsert_lead_trader: string;
|
|
14
|
+
get_my_lead_trader: string;
|
|
15
|
+
list_my_followers: string;
|
|
16
|
+
list_lead_traders: string;
|
|
17
|
+
get_lead_trader: string;
|
|
18
|
+
list_lead_trader_closed_trades: string;
|
|
19
|
+
list_lead_trader_open_positions: string;
|
|
20
|
+
upsert_follow: string;
|
|
21
|
+
stop_follow: string;
|
|
22
|
+
list_my_follows: string;
|
|
23
|
+
get_follow: string;
|
|
24
|
+
list_follow_leader_positions: string;
|
|
25
|
+
preview_follow: string;
|
|
13
26
|
cancel_twap_order: string;
|
|
14
27
|
create_twap_order: string;
|
|
15
28
|
get_twap_order: string;
|
package/dist/coverage.js
CHANGED
|
@@ -10,6 +10,19 @@ export const COVERED = {
|
|
|
10
10
|
cancel_conditional_order: "cancelConditionalOrder",
|
|
11
11
|
get_conditional_order: "getConditionalOrder",
|
|
12
12
|
cancel_order: "cancelOrder",
|
|
13
|
+
upsert_lead_trader: "copyTrading.upsertLeadTrader",
|
|
14
|
+
get_my_lead_trader: "copyTrading.getMyLeadTrader",
|
|
15
|
+
list_my_followers: "copyTrading.listMyFollowers",
|
|
16
|
+
list_lead_traders: "copyTrading.listLeadTraders",
|
|
17
|
+
get_lead_trader: "copyTrading.getLeadTrader",
|
|
18
|
+
list_lead_trader_closed_trades: "copyTrading.listLeadTraderClosedTrades",
|
|
19
|
+
list_lead_trader_open_positions: "copyTrading.listLeadTraderOpenPositions",
|
|
20
|
+
upsert_follow: "copyTrading.upsertFollow",
|
|
21
|
+
stop_follow: "copyTrading.stopFollow",
|
|
22
|
+
list_my_follows: "copyTrading.listMyFollows",
|
|
23
|
+
get_follow: "copyTrading.getFollow",
|
|
24
|
+
list_follow_leader_positions: "copyTrading.listFollowLeaderPositions",
|
|
25
|
+
preview_follow: "copyTrading.previewFollow",
|
|
13
26
|
cancel_twap_order: "cancelTwapOrder",
|
|
14
27
|
create_twap_order: "createTwapOrder",
|
|
15
28
|
get_twap_order: "getTwapOrder",
|
package/dist/sdk.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ApplicationsAPI, AuthAPI, AuthState, BuildercodesAPI, DelegatedAgentsAPI, FaucetAPI, FeesAPI, ManagedMarketsAPI, MarginAccountsAPI, MarketAPI, MonacoSDK, Network, PitpassAPI, PortfolioAPI, PositionsAPI, ProfileAPI, PulseAPI, SDKConfig, SubAccountsAPI, SweeperAPI, TradingAPI, VaultAPI, WhitelistAPI, WithdrawalsAPI } from "@0xmonaco/types";
|
|
1
|
+
import type { ApplicationsAPI, AuthAPI, AuthState, BuildercodesAPI, CopyTradingAPI, DelegatedAgentsAPI, FaucetAPI, FeesAPI, ManagedMarketsAPI, MarginAccountsAPI, MarketAPI, MonacoSDK, Network, PitpassAPI, PortfolioAPI, PositionsAPI, ProfileAPI, PulseAPI, SDKConfig, SubAccountsAPI, SweeperAPI, TradingAPI, VaultAPI, WhitelistAPI, WithdrawalsAPI } from "@0xmonaco/types";
|
|
2
2
|
import { type Address, type PublicClient, type TransactionReceipt, type WalletClient } from "viem";
|
|
3
3
|
import { type MonacoWebSocket, OrderbookAPIImpl, TradesAPIImpl } from "./api";
|
|
4
4
|
export declare class MonacoSDKImpl implements MonacoSDK {
|
|
@@ -7,6 +7,7 @@ export declare class MonacoSDKImpl implements MonacoSDK {
|
|
|
7
7
|
applications: ApplicationsAPI;
|
|
8
8
|
fees: FeesAPI;
|
|
9
9
|
buildercodes: BuildercodesAPI;
|
|
10
|
+
copyTrading: CopyTradingAPI;
|
|
10
11
|
pitpass: PitpassAPI;
|
|
11
12
|
vault: VaultAPI;
|
|
12
13
|
withdrawals: WithdrawalsAPI;
|
package/dist/sdk.js
CHANGED
|
@@ -4,6 +4,7 @@ import { sei, seiTestnet } from "viem/chains";
|
|
|
4
4
|
import { ApplicationsAPIImpl, createMonacoWebSocket, OrderbookAPIImpl, TradesAPIImpl } from "./api";
|
|
5
5
|
import { AuthAPIImpl } from "./api/auth";
|
|
6
6
|
import { BuildercodesAPIImpl } from "./api/buildercodes";
|
|
7
|
+
import { CopyTradingAPIImpl } from "./api/copy-trading";
|
|
7
8
|
import { DelegatedAgentsAPIImpl } from "./api/delegated-agents";
|
|
8
9
|
import { FaucetAPIImpl } from "./api/faucet";
|
|
9
10
|
import { FeesAPIImpl } from "./api/fees";
|
|
@@ -48,6 +49,7 @@ export class MonacoSDKImpl {
|
|
|
48
49
|
applications;
|
|
49
50
|
fees;
|
|
50
51
|
buildercodes;
|
|
52
|
+
copyTrading;
|
|
51
53
|
pitpass;
|
|
52
54
|
vault;
|
|
53
55
|
withdrawals;
|
|
@@ -81,6 +83,7 @@ export class MonacoSDKImpl {
|
|
|
81
83
|
this.applications.setSessionKeypair(credentials);
|
|
82
84
|
this.fees.setSessionKeypair(credentials);
|
|
83
85
|
this.buildercodes.setSessionKeypair(credentials);
|
|
86
|
+
this.copyTrading.setSessionKeypair(credentials);
|
|
84
87
|
this.pitpass.setSessionKeypair(credentials);
|
|
85
88
|
this.vault.setSessionKeypair(credentials);
|
|
86
89
|
this.withdrawals.setSessionKeypair(credentials);
|
|
@@ -123,6 +126,7 @@ export class MonacoSDKImpl {
|
|
|
123
126
|
this.applications.setServerKey(serverKey);
|
|
124
127
|
this.fees.setServerKey(serverKey);
|
|
125
128
|
this.buildercodes.setServerKey(serverKey);
|
|
129
|
+
this.copyTrading.setServerKey(serverKey);
|
|
126
130
|
this.pitpass.setServerKey(serverKey);
|
|
127
131
|
this.vault.setServerKey(serverKey);
|
|
128
132
|
this.withdrawals.setServerKey(serverKey);
|
|
@@ -211,6 +215,7 @@ export class MonacoSDKImpl {
|
|
|
211
215
|
this.delegatedAgents = configureSigning(new DelegatedAgentsAPIImpl(apiUrl));
|
|
212
216
|
this.fees = configureSigning(new FeesAPIImpl(apiUrl));
|
|
213
217
|
this.buildercodes = configureSigning(new BuildercodesAPIImpl(apiUrl));
|
|
218
|
+
this.copyTrading = configureSigning(new CopyTradingAPIImpl(apiUrl));
|
|
214
219
|
this.pitpass = configureSigning(new PitpassAPIImpl(apiUrl));
|
|
215
220
|
this.profile = configureSigning(new ProfileAPIImpl(apiUrl));
|
|
216
221
|
this.vault = configureSigning(new VaultAPIImpl(this.publicClient, this.walletClient, this.chain, this.applications, this.profile, apiUrl));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@0xmonaco/core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.70",
|
|
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.70",
|
|
23
|
+
"@0xmonaco/types": "1.0.70",
|
|
24
24
|
"@noble/curves": "^1.9.1",
|
|
25
25
|
"@noble/hashes": "^2.4.0",
|
|
26
26
|
"http-status-codes": "^2.3.0"
|