@0xmonaco/core 0.8.7 → 0.8.10

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.
Files changed (48) hide show
  1. package/dist/api/applications/api.d.ts +61 -8
  2. package/dist/api/applications/api.js +71 -7
  3. package/dist/api/auth/api.d.ts +44 -76
  4. package/dist/api/auth/api.js +61 -104
  5. package/dist/api/base.d.ts +48 -7
  6. package/dist/api/base.js +95 -12
  7. package/dist/api/delegated-agents/api.d.ts +2 -1
  8. package/dist/api/delegated-agents/api.js +4 -0
  9. package/dist/api/faucet/api.d.ts +25 -0
  10. package/dist/api/faucet/api.js +29 -0
  11. package/dist/api/faucet/index.d.ts +1 -0
  12. package/dist/api/faucet/index.js +1 -0
  13. package/dist/api/index.d.ts +4 -0
  14. package/dist/api/index.js +4 -0
  15. package/dist/api/margin-accounts/api.d.ts +3 -4
  16. package/dist/api/margin-accounts/api.js +8 -15
  17. package/dist/api/market/api.d.ts +3 -1
  18. package/dist/api/market/api.js +8 -0
  19. package/dist/api/orderbook/api.js +2 -1
  20. package/dist/api/perp/routes.d.ts +62 -4
  21. package/dist/api/perp/routes.js +27 -4
  22. package/dist/api/profile/api.d.ts +18 -1
  23. package/dist/api/profile/api.js +41 -1
  24. package/dist/api/sub-accounts/api.d.ts +62 -0
  25. package/dist/api/sub-accounts/api.js +80 -0
  26. package/dist/api/sub-accounts/index.d.ts +1 -0
  27. package/dist/api/sub-accounts/index.js +1 -0
  28. package/dist/api/trades/api.d.ts +12 -1
  29. package/dist/api/trades/api.js +13 -1
  30. package/dist/api/trading/api.d.ts +5 -2
  31. package/dist/api/trading/api.js +13 -27
  32. package/dist/api/websocket/types.d.ts +5 -5
  33. package/dist/api/websocket/websocket.js +43 -22
  34. package/dist/api/whitelist/api.d.ts +27 -0
  35. package/dist/api/whitelist/api.js +32 -0
  36. package/dist/api/whitelist/index.d.ts +1 -0
  37. package/dist/api/whitelist/index.js +1 -0
  38. package/dist/api/withdrawals/api.d.ts +15 -0
  39. package/dist/api/withdrawals/api.js +27 -0
  40. package/dist/api/withdrawals/index.d.ts +1 -0
  41. package/dist/api/withdrawals/index.js +1 -0
  42. package/dist/coverage.d.ts +85 -0
  43. package/dist/coverage.js +85 -0
  44. package/dist/crypto/session.d.ts +40 -0
  45. package/dist/crypto/session.js +60 -0
  46. package/dist/sdk.d.ts +56 -18
  47. package/dist/sdk.js +156 -53
  48. package/package.json +5 -3
package/dist/sdk.js CHANGED
@@ -4,25 +4,44 @@ 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 { DelegatedAgentsAPIImpl } from "./api/delegated-agents";
7
+ import { FaucetAPIImpl } from "./api/faucet";
7
8
  import { FeesAPIImpl } from "./api/fees";
8
9
  import { MarginAccountsAPIImpl } from "./api/margin-accounts";
9
10
  import { MarketAPIImpl } from "./api/market";
10
11
  import { PositionsAPIImpl } from "./api/positions";
11
12
  import { ProfileAPIImpl } from "./api/profile";
13
+ import { SubAccountsAPIImpl } from "./api/sub-accounts";
12
14
  import { TradingAPIImpl } from "./api/trading";
13
15
  import { VaultAPIImpl } from "./api/vault";
16
+ import { WhitelistAPIImpl } from "./api/whitelist";
17
+ import { WithdrawalsAPIImpl } from "./api/withdrawals";
18
+ import { generateSessionKeypair, privateKeyHex, publicKeyHex } from "./crypto/session";
14
19
  import { APIError, InvalidConfigError, InvalidStateError } from "./errors";
15
20
  import { resolveApiUrl, resolveWsUrl } from "./networks";
21
+ /** Validate a user-supplied URL override, returning it unchanged when valid. */
22
+ function validateUrl(value, field) {
23
+ try {
24
+ new URL(value);
25
+ }
26
+ catch (_e) {
27
+ throw new InvalidConfigError(`${field} must be a valid URL, got: ${value}`, field);
28
+ }
29
+ return value;
30
+ }
16
31
  export class MonacoSDKImpl {
17
32
  auth;
18
33
  delegatedAgents;
19
34
  applications;
20
35
  fees;
21
36
  vault;
37
+ withdrawals;
22
38
  trading;
23
39
  market;
24
40
  marginAccounts;
25
41
  positions;
42
+ subAccounts;
43
+ faucet;
44
+ whitelist;
26
45
  profile;
27
46
  orderbook;
28
47
  trades;
@@ -33,22 +52,69 @@ export class MonacoSDKImpl {
33
52
  network;
34
53
  chain;
35
54
  /**
36
- * Propagate the access token to all APIs and WebSocket
55
+ * Propagate the session keypair (or `undefined` to clear) to all APIs and
56
+ * the WebSocket client.
57
+ */
58
+ propagateSession(credentials) {
59
+ this.auth.setSessionKeypair(credentials);
60
+ this.delegatedAgents.setSessionKeypair(credentials);
61
+ this.applications.setSessionKeypair(credentials);
62
+ this.fees.setSessionKeypair(credentials);
63
+ this.vault.setSessionKeypair(credentials);
64
+ this.withdrawals.setSessionKeypair(credentials);
65
+ this.trading.setSessionKeypair(credentials);
66
+ this.market.setSessionKeypair(credentials);
67
+ this.marginAccounts.setSessionKeypair(credentials);
68
+ this.positions.setSessionKeypair(credentials);
69
+ this.subAccounts.setSessionKeypair(credentials);
70
+ this.faucet.setSessionKeypair(credentials);
71
+ this.whitelist.setSessionKeypair(credentials);
72
+ this.profile.setSessionKeypair(credentials);
73
+ this.orderbook.setSessionKeypair(credentials);
74
+ this.trades.setSessionKeypair(credentials);
75
+ this.ws.setSessionKeypair(credentials);
76
+ }
77
+ /**
78
+ * Set (or clear) the application secret key used for backend-authenticated
79
+ * requests (those annotated `#[require_backend]` on the gateway, e.g. the
80
+ * `applications` reporting endpoints).
81
+ *
82
+ * The raw `sk_...` key is sent in the `x-server-key` header on each such
83
+ * request. This is independent of {@link login}/session auth — a client may
84
+ * hold both a session and a server key at once.
85
+ *
86
+ * @param serverKey - The application secret key (`sk_...`), or `undefined` to clear.
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * sdk.setServerKey("sk_live_...");
91
+ * const orders = await sdk.applications.listApplicationOrders({ status: "FILLED" });
92
+ * ```
37
93
  */
38
- propagateAccessToken(accessToken) {
39
- this.auth.setAccessToken(accessToken);
40
- this.delegatedAgents.setAccessToken(accessToken);
41
- this.applications.setAccessToken(accessToken);
42
- this.fees.setAccessToken(accessToken);
43
- this.vault.setAccessToken(accessToken);
44
- this.trading.setAccessToken(accessToken);
45
- this.market.setAccessToken(accessToken);
46
- this.marginAccounts.setAccessToken(accessToken);
47
- this.positions.setAccessToken(accessToken);
48
- this.profile.setAccessToken(accessToken);
49
- this.orderbook.setAccessToken(accessToken);
50
- this.trades.setAccessToken(accessToken);
51
- this.ws.setToken(accessToken);
94
+ setServerKey(serverKey) {
95
+ this.auth.setServerKey(serverKey);
96
+ this.delegatedAgents.setServerKey(serverKey);
97
+ this.applications.setServerKey(serverKey);
98
+ this.fees.setServerKey(serverKey);
99
+ this.vault.setServerKey(serverKey);
100
+ this.withdrawals.setServerKey(serverKey);
101
+ this.trading.setServerKey(serverKey);
102
+ this.market.setServerKey(serverKey);
103
+ this.marginAccounts.setServerKey(serverKey);
104
+ this.positions.setServerKey(serverKey);
105
+ this.subAccounts.setServerKey(serverKey);
106
+ this.faucet.setServerKey(serverKey);
107
+ this.whitelist.setServerKey(serverKey);
108
+ this.profile.setServerKey(serverKey);
109
+ this.orderbook.setServerKey(serverKey);
110
+ this.trades.setServerKey(serverKey);
111
+ }
112
+ /** Extract the session keypair from an auth state. */
113
+ sessionFromAuthState(authState) {
114
+ return {
115
+ publicKey: authState.sessionPublicKey,
116
+ privateKey: authState.sessionPrivateKey,
117
+ };
52
118
  }
53
119
  constructor(cfg) {
54
120
  // Validate network - must be a preset
@@ -67,8 +133,8 @@ export class MonacoSDKImpl {
67
133
  catch (_e) {
68
134
  throw new InvalidConfigError(`seiRpcUrl must be a valid URL, got: ${cfg.seiRpcUrl}`, "seiRpcUrl");
69
135
  }
70
- // Infer WebSocket URL from network
71
- const wsUrl = resolveWsUrl(this.network);
136
+ // Resolve the WebSocket URL: explicit override (validated) or network preset.
137
+ const wsUrl = cfg.wsUrl ? validateUrl(cfg.wsUrl, "wsUrl") : resolveWsUrl(this.network);
72
138
  // Use Sei mainnet chain only for "mainnet" network, testnet for everything else
73
139
  const chain = this.network === "mainnet" ? sei : seiTestnet;
74
140
  this.chain = chain;
@@ -78,8 +144,8 @@ export class MonacoSDKImpl {
78
144
  chain,
79
145
  transport,
80
146
  });
81
- // Resolve the API URL (from preset or custom URL)
82
- const apiUrl = resolveApiUrl(this.network);
147
+ // Resolve the API URL: explicit override (validated) or network preset.
148
+ const apiUrl = cfg.apiUrl ? validateUrl(cfg.apiUrl, "apiUrl") : resolveApiUrl(this.network);
83
149
  // Validate wallet client chain if provided
84
150
  if (cfg.walletClient) {
85
151
  if (cfg.walletClient.chain?.id !== chain.id) {
@@ -92,11 +158,15 @@ export class MonacoSDKImpl {
92
158
  this.market = new MarketAPIImpl(apiUrl);
93
159
  this.marginAccounts = new MarginAccountsAPIImpl(apiUrl);
94
160
  this.positions = new PositionsAPIImpl(apiUrl);
161
+ this.subAccounts = new SubAccountsAPIImpl(apiUrl);
162
+ this.faucet = new FaucetAPIImpl(apiUrl);
163
+ this.whitelist = new WhitelistAPIImpl(apiUrl);
95
164
  this.auth = new AuthAPIImpl(this.walletClient, this.chain, apiUrl);
96
165
  this.delegatedAgents = new DelegatedAgentsAPIImpl(apiUrl);
97
166
  this.fees = new FeesAPIImpl(apiUrl);
98
167
  this.profile = new ProfileAPIImpl(apiUrl);
99
168
  this.vault = new VaultAPIImpl(this.publicClient, this.walletClient, this.chain, this.applications, this.profile, apiUrl);
169
+ this.withdrawals = new WithdrawalsAPIImpl(apiUrl);
100
170
  this.trading = new TradingAPIImpl(apiUrl);
101
171
  this.orderbook = new OrderbookAPIImpl(apiUrl);
102
172
  this.trades = new TradesAPIImpl(apiUrl);
@@ -107,14 +177,16 @@ export class MonacoSDKImpl {
107
177
  /**
108
178
  * Authenticate the user
109
179
  *
110
- * Returns an AuthState object containing:
111
- * - `accessToken`: For making authenticated API requests
112
- * - `refreshToken`: For refreshing tokens AND revoking (logout)
113
- * - `expiresAt`: When the access token expires
180
+ * Generates a session keypair, has the wallet authorize it, and returns an
181
+ * AuthState object containing:
182
+ * - `sessionPublicKey` / `sessionPrivateKey`: the session keypair used to
183
+ * sign subsequent requests (the private key is the credential persist it
184
+ * to survive reloads without re-prompting the wallet)
185
+ * - `expiresAt`: When the session expires
114
186
  * - `user`: User information
115
187
  *
116
- * Note: Use `sdk.logout()` to revoke the token and clean up, or call
117
- * `sdk.auth.revokeToken()` directly to just revoke.
188
+ * Note: Use `sdk.logout()` to revoke the session and clean up, or call
189
+ * `sdk.auth.revokeSession()` directly to just revoke.
118
190
  *
119
191
  * @param clientId - The client ID for authentication
120
192
  * @param options - Optional configuration
@@ -128,30 +200,57 @@ export class MonacoSDKImpl {
128
200
  * // Login and auto-connect WebSocket
129
201
  * const authState = await sdk.login(clientId, { connectWebSocket: true });
130
202
  *
131
- * // Manual WebSocket connection
132
- * await sdk.ws.connect();
133
- *
134
203
  * // Later, to revoke:
135
- * await sdk.auth.revokeToken(); // ✅
204
+ * await sdk.auth.revokeSession(); // ✅
136
205
  * // Or revoke and disconnect WebSocket:
137
- * await sdk.logout(); // ✅ Calls revokeToken internally and disconnects WebSocket
206
+ * await sdk.logout(); // ✅ Calls revokeSession internally and disconnects WebSocket
138
207
  * ```
139
208
  */
140
209
  async login(clientId, options) {
141
- const response = await this.auth.authenticate(clientId);
142
- this.authState = {
143
- accessToken: response.accessToken,
144
- refreshToken: response.refreshToken,
145
- expiresAt: response.expiresAt,
146
- user: response.user,
147
- };
148
- this.propagateAccessToken(this.authState.accessToken);
210
+ this.authState = await this.auth.authenticate(clientId);
211
+ this.propagateSession(this.sessionFromAuthState(this.authState));
149
212
  // Auto-connect WebSocket if requested
150
213
  if (options?.connectWebSocket) {
151
214
  await this.ws.connect();
152
215
  }
153
216
  return this.authState;
154
217
  }
218
+ /**
219
+ * Create and adopt an owner-scoped delegated session.
220
+ *
221
+ * This must be called while authenticated as the agent wallet. The delegated
222
+ * session uses a fresh ed25519 keypair generated locally; the current agent
223
+ * session signs the registration request, and subsequent SDK calls use the
224
+ * delegated session keypair.
225
+ */
226
+ async loginAsDelegatedOwner(ownerUserId) {
227
+ if (!this.authState) {
228
+ throw new APIError("No active agent session to create delegated session", {
229
+ endpoint: "delegated-agents/sessions",
230
+ statusCode: StatusCodes.UNAUTHORIZED,
231
+ });
232
+ }
233
+ const keypair = generateSessionKeypair();
234
+ const session = {
235
+ publicKey: publicKeyHex(keypair),
236
+ privateKey: privateKeyHex(keypair),
237
+ };
238
+ const delegatedSession = await this.delegatedAgents.createDelegatedSession({
239
+ ownerUserId,
240
+ sessionPublicKey: session.publicKey,
241
+ });
242
+ this.authState = {
243
+ sessionPublicKey: session.publicKey,
244
+ sessionPrivateKey: session.privateKey,
245
+ expiresAt: delegatedSession.expires_at,
246
+ user: {
247
+ id: delegatedSession.owner_user_id,
248
+ address: delegatedSession.agent_address,
249
+ },
250
+ };
251
+ this.propagateSession(this.sessionFromAuthState(this.authState));
252
+ return this.authState;
253
+ }
155
254
  /**
156
255
  * Get the current authentication state
157
256
  *
@@ -168,59 +267,63 @@ export class MonacoSDKImpl {
168
267
  */
169
268
  setAuthState(authState) {
170
269
  this.authState = authState;
171
- this.propagateAccessToken(authState.accessToken);
270
+ this.propagateSession(this.sessionFromAuthState(authState));
172
271
  }
173
272
  /**
174
273
  * Log the user out
175
274
  *
176
- * This method revokes the refresh token (if available), disconnects all authenticated
275
+ * This method revokes the session (if authenticated), disconnects all authenticated
177
276
  * WebSocket channels, and clears the local auth state.
178
- * It internally calls `auth.revokeToken()` to invalidate the token on the server.
277
+ * It internally calls `auth.revokeSession()` to invalidate the session on the server.
179
278
  *
180
279
  * @example
181
280
  * ```typescript
182
281
  * await sdk.logout();
183
- * // Token is revoked, authenticated WebSockets disconnected, and local state cleared
282
+ * // Session is revoked, authenticated WebSockets disconnected, and local state cleared
184
283
  * ```
185
284
  */
186
285
  async logout() {
187
- if (this.authState?.refreshToken) {
286
+ if (this.authState) {
188
287
  try {
189
- await this.auth.revokeToken();
288
+ await this.auth.revokeSession();
190
289
  }
191
290
  catch (error) {
192
291
  // Log but don't throw - we want to clear the local state regardless
193
- console.warn("Failed to revoke token on logout:", error);
292
+ console.warn("Failed to revoke session on logout:", error);
194
293
  }
195
294
  }
196
295
  this.authState = undefined;
197
- this.propagateAccessToken("");
296
+ this.propagateSession(undefined);
198
297
  this.ws.disconnect();
199
298
  }
200
299
  /**
201
- * Refresh the access token
300
+ * Refresh the current session, extending its expiry.
301
+ *
302
+ * Signs a refresh request with the active session key and updates the local
303
+ * `expiresAt`. The session keypair is unchanged. If no session is active, or
304
+ * the session has expired/been revoked, this throws.
305
+ *
202
306
  * @returns The updated authentication state
203
307
  */
204
308
  async refreshAuth() {
205
- if (!this.authState?.refreshToken) {
206
- throw new APIError("No refresh token available", {
309
+ if (!this.authState) {
310
+ throw new APIError("No active session to refresh", {
207
311
  endpoint: "auth/refresh",
208
312
  statusCode: StatusCodes.UNAUTHORIZED,
209
313
  });
210
314
  }
211
315
  try {
212
- const response = await this.auth.refreshToken(this.authState.refreshToken);
316
+ const response = await this.auth.refreshSession();
213
317
  this.authState = {
214
318
  ...this.authState,
215
- accessToken: response.accessToken,
216
319
  expiresAt: response.expiresAt,
217
320
  };
218
- this.propagateAccessToken(this.authState.accessToken);
219
321
  return this.authState;
220
322
  }
221
323
  catch (error) {
222
- // If refresh fails, set the auth state to undefined
324
+ // If refresh fails, the session is no longer usable.
223
325
  this.authState = undefined;
326
+ this.propagateSession(undefined);
224
327
  throw error;
225
328
  }
226
329
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xmonaco/core",
3
- "version": "0.8.7",
3
+ "version": "0.8.10",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,8 +23,10 @@
23
23
  "viem": "^2.45.2"
24
24
  },
25
25
  "dependencies": {
26
- "@0xmonaco/contracts": "0.8.7",
27
- "@0xmonaco/types": "0.8.7",
26
+ "@0xmonaco/contracts": "0.8.10",
27
+ "@0xmonaco/types": "0.8.10",
28
+ "@noble/curves": "^1.9.1",
29
+ "@noble/hashes": "^1.8.0",
28
30
  "http-status-codes": "^2.3.0"
29
31
  },
30
32
  "devDependencies": {