@0xmonaco/core 0.7.7 → 0.7.9

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 (77) hide show
  1. package/dist/api/applications/api.d.ts +43 -0
  2. package/dist/api/applications/api.js +54 -0
  3. package/dist/api/applications/index.d.ts +4 -0
  4. package/dist/api/applications/index.js +4 -0
  5. package/dist/api/auth/api.d.ts +206 -0
  6. package/dist/api/auth/api.js +305 -0
  7. package/dist/api/auth/index.d.ts +4 -0
  8. package/dist/api/auth/index.js +4 -0
  9. package/dist/api/base.d.ts +123 -0
  10. package/dist/api/base.js +286 -0
  11. package/dist/api/fees/api.d.ts +72 -0
  12. package/dist/api/fees/api.js +90 -0
  13. package/dist/api/fees/index.d.ts +6 -0
  14. package/dist/api/fees/index.js +6 -0
  15. package/dist/api/index.d.ts +18 -0
  16. package/dist/api/index.js +18 -0
  17. package/dist/api/margin-accounts/api.d.ts +12 -0
  18. package/dist/api/margin-accounts/api.js +69 -0
  19. package/dist/api/margin-accounts/index.d.ts +1 -0
  20. package/dist/api/margin-accounts/index.js +1 -0
  21. package/dist/api/market/api.d.ts +20 -0
  22. package/dist/api/market/api.js +97 -0
  23. package/dist/api/market/index.d.ts +1 -0
  24. package/dist/api/market/index.js +1 -0
  25. package/dist/api/orderbook/api.d.ts +15 -0
  26. package/dist/api/orderbook/api.js +37 -0
  27. package/dist/api/orderbook/index.d.ts +1 -0
  28. package/dist/api/orderbook/index.js +1 -0
  29. package/dist/api/perp/index.d.ts +1 -0
  30. package/dist/api/perp/index.js +1 -0
  31. package/dist/api/perp/routes.d.ts +133 -0
  32. package/dist/api/perp/routes.js +85 -0
  33. package/dist/api/positions/api.d.ts +12 -0
  34. package/dist/api/positions/api.js +86 -0
  35. package/dist/api/positions/index.d.ts +1 -0
  36. package/dist/api/positions/index.js +1 -0
  37. package/dist/api/profile/api.d.ts +191 -0
  38. package/dist/api/profile/api.js +259 -0
  39. package/dist/api/profile/index.d.ts +6 -0
  40. package/dist/api/profile/index.js +6 -0
  41. package/dist/api/trades/api.d.ts +44 -0
  42. package/dist/api/trades/api.js +42 -0
  43. package/dist/api/trades/index.d.ts +1 -0
  44. package/dist/api/trades/index.js +1 -0
  45. package/dist/api/trading/api.d.ts +301 -0
  46. package/dist/api/trading/api.js +497 -0
  47. package/dist/api/trading/index.d.ts +4 -0
  48. package/dist/api/trading/index.js +4 -0
  49. package/dist/api/vault/api.d.ts +261 -0
  50. package/dist/api/vault/api.js +506 -0
  51. package/dist/api/vault/index.d.ts +4 -0
  52. package/dist/api/vault/index.js +4 -0
  53. package/dist/api/websocket/index.d.ts +3 -0
  54. package/dist/api/websocket/index.js +3 -0
  55. package/dist/api/websocket/types.d.ts +41 -0
  56. package/dist/api/websocket/types.js +0 -0
  57. package/dist/api/websocket/utils.d.ts +8 -0
  58. package/dist/api/websocket/utils.js +22 -0
  59. package/dist/api/websocket/websocket.d.ts +5 -0
  60. package/dist/api/websocket/websocket.js +560 -0
  61. package/dist/errors/errors.d.ts +381 -0
  62. package/dist/errors/errors.js +815 -0
  63. package/dist/errors/index.d.ts +1 -0
  64. package/dist/errors/index.js +1 -0
  65. package/dist/index.d.ts +5 -0
  66. package/dist/index.js +5 -0
  67. package/dist/networks/index.d.ts +1 -0
  68. package/dist/networks/index.js +1 -0
  69. package/dist/networks/networks.d.ts +21 -0
  70. package/dist/networks/networks.js +46 -0
  71. package/dist/sdk.d.ts +134 -0
  72. package/dist/sdk.js +294 -0
  73. package/dist/utils/index.d.ts +1 -0
  74. package/dist/utils/index.js +1 -0
  75. package/dist/utils/magnitude.d.ts +26 -0
  76. package/dist/utils/magnitude.js +31 -0
  77. package/package.json +3 -3
@@ -0,0 +1,506 @@
1
+ /**
2
+ * Vault API Implementation
3
+ *
4
+ * Handles vault operations including deposits, withdrawals, and ERC20 approvals.
5
+ * Implements the signature flow for deposit/withdraw operations via API Gateway.
6
+ *
7
+ * This class provides a complete interface for interacting with the Monaco vault contract,
8
+ * including token approvals, deposits, withdrawals, and balance queries. All operations
9
+ * use EIP-712 signatures for security and go through the API Gateway for validation.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const vaultAPI = new VaultAPIImpl(
14
+ * publicClient,
15
+ * walletClient,
16
+ * vaultAddress,
17
+ * apiUrl,
18
+ * chain
19
+ * );
20
+ *
21
+ * // Deposit tokens
22
+ * const result = await vaultAPI.deposit(tokenAddress, parseEther("100"));
23
+ * console.log(`Deposit transaction: ${result.hash}`);
24
+ * ```
25
+ */
26
+ import { CONTRACT_ABIS } from "@0xmonaco/contracts";
27
+ import { ApproveTokenSchema, DepositSchema, validate, WithdrawSchema } from "@0xmonaco/types";
28
+ import { erc20Abi, zeroAddress } from "viem";
29
+ import { APIError, ContractError, InvalidConfigError } from "../../errors";
30
+ import { BaseAPI } from "../base";
31
+ export class VaultAPIImpl extends BaseAPI {
32
+ publicClient;
33
+ chain;
34
+ applicationsAPI;
35
+ profileAPI;
36
+ walletClient;
37
+ /**
38
+ * Creates a new VaultAPI instance.
39
+ *
40
+ * @param publicClient - The viem public client for reading blockchain state
41
+ * @param walletClient - The viem wallet client for signing transactions (optional)
42
+ * @param chain - The blockchain network configuration
43
+ * @param applicationsAPI - The applications API instance for fetching vault address
44
+ * @param profileAPI - The profile API instance for fetching asset information
45
+ * @param apiUrl - The base URL for the Monaco API Gateway
46
+ */
47
+ constructor(publicClient, walletClient, chain, applicationsAPI, profileAPI, apiUrl) {
48
+ super(apiUrl);
49
+ this.publicClient = publicClient;
50
+ this.chain = chain;
51
+ this.walletClient = walletClient;
52
+ this.applicationsAPI = applicationsAPI;
53
+ this.profileAPI = profileAPI;
54
+ }
55
+ /**
56
+ * Sets the wallet client for signing transactions.
57
+ * Used when the wallet becomes available after SDK initialization.
58
+ */
59
+ setWalletClient(walletClient) {
60
+ this.walletClient = walletClient;
61
+ }
62
+ /**
63
+ * Fetches the vault contract address from the applications API.
64
+ *
65
+ * @returns Promise resolving to the vault contract address
66
+ * @throws {APIError} When vault address cannot be retrieved
67
+ * @private
68
+ */
69
+ async getVaultAddress() {
70
+ const config = await this.applicationsAPI.getApplicationConfig();
71
+ return config.vaultContractAddress;
72
+ }
73
+ /**
74
+ * Fetches the application's client ID from the applications API.
75
+ * The client ID is embedded in on-chain deposit calls so the indexer can
76
+ * attribute the deposit to the correct application.
77
+ *
78
+ * @returns Promise resolving to the application client ID
79
+ * @private
80
+ */
81
+ async getClientId() {
82
+ const config = await this.applicationsAPI.getApplicationConfig();
83
+ return config.clientId;
84
+ }
85
+ /**
86
+ * Resolves an asset ID to its token address and determines if it's a native token.
87
+ *
88
+ * @param assetId - The asset identifier (UUID) to resolve
89
+ * @returns Promise resolving to object with tokenAddress and isNativeToken flag
90
+ * @throws {ContractError} When asset ID cannot be resolved
91
+ * @private
92
+ */
93
+ async resolveAsset(assetId) {
94
+ let tokenAddress;
95
+ try {
96
+ const assetBalance = await this.profileAPI.getUserBalanceByAssetId(assetId);
97
+ tokenAddress = assetBalance.token;
98
+ }
99
+ catch (error) {
100
+ // Differentiate between network errors and asset not found
101
+ if (error instanceof APIError) {
102
+ if (error.statusCode === 404) {
103
+ throw new ContractError(`Asset ID '${assetId}' does not exist`, {
104
+ revertReason: "ASSET_NOT_FOUND",
105
+ cause: error,
106
+ });
107
+ }
108
+ // Network or other API errors - preserve retry-ability context
109
+ throw new ContractError(`Failed to resolve asset ID '${assetId}': ${error.retryable ? "Network error occurred" : "API request failed"}`, {
110
+ revertReason: error.retryable ? "NETWORK_ERROR" : "API_ERROR",
111
+ cause: error,
112
+ });
113
+ }
114
+ // Unknown error type
115
+ throw new ContractError(`Failed to resolve asset ID '${assetId}': Unexpected error`, {
116
+ revertReason: "UNKNOWN_ERROR",
117
+ cause: error instanceof Error ? error : undefined,
118
+ });
119
+ }
120
+ const isNativeToken = tokenAddress === zeroAddress;
121
+ return { tokenAddress, isNativeToken };
122
+ }
123
+ /**
124
+ * Approves the vault contract to spend tokens on behalf of the user.
125
+ *
126
+ * This method creates and sends an ERC20 approve transaction to allow the vault
127
+ * to transfer tokens from the user's wallet. Approval is required before any
128
+ * deposit operations can be performed.
129
+ *
130
+ * @param assetId - The asset identifier (UUID) to approve
131
+ * @param amount - The maximum amount of tokens the vault can spend (as bigint)
132
+ * @param autoWait - Whether to automatically wait for transaction confirmation (defaults to true)
133
+ * @returns Promise resolving to TransactionResult with transaction details
134
+ * @throws {ContractError} When approval transaction fails or asset not found
135
+ * @throws {InvalidConfigError} When wallet account is not available
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * // Approve vault to spend up to 1000 USDC (auto-waits by default)
140
+ * const result = await vaultAPI.approve(
141
+ * "123e4567-e89b-12d3-a456-426614174000",
142
+ * parseUnits("1000", 6)
143
+ * );
144
+ * console.log(`Approval transaction: ${result.hash}`);
145
+ * console.log(`Status: ${result.status}`); // "confirmed" if successful
146
+ *
147
+ * // Or skip auto-waiting
148
+ * const result = await vaultAPI.approve(
149
+ * "123e4567-e89b-12d3-a456-426614174000",
150
+ * parseUnits("1000", 6),
151
+ * false
152
+ * );
153
+ * // Then manually wait later if needed
154
+ * const receipt = await sdk.waitForTransaction(result.hash);
155
+ * ```
156
+ */
157
+ async approve(assetId, amount, autoWait = true) {
158
+ if (!this.walletClient) {
159
+ throw new InvalidConfigError("Wallet client not set. Connect a wallet first.", "walletClient");
160
+ }
161
+ // Validate inputs
162
+ validate(ApproveTokenSchema, { assetId, amount, autoWait });
163
+ const vaultAddress = await this.getVaultAddress();
164
+ const { tokenAddress } = await this.resolveAsset(assetId);
165
+ const account = this.walletClient.account;
166
+ if (!account) {
167
+ throw new InvalidConfigError("No account available in wallet client", "account");
168
+ }
169
+ const nonce = account.getNonce ? await account.getNonce() : 0n;
170
+ // Use writeContract - handles nonce, gas estimation, signing, and sending automatically
171
+ const hash = await this.walletClient.writeContract({
172
+ address: tokenAddress,
173
+ abi: erc20Abi,
174
+ functionName: "approve",
175
+ args: [vaultAddress, amount],
176
+ chain: this.chain,
177
+ account,
178
+ });
179
+ const txResult = {
180
+ nonce,
181
+ hash,
182
+ status: "pending",
183
+ };
184
+ // Handle auto-waiting for transaction confirmation
185
+ return await this.waitForTransaction(txResult, autoWait);
186
+ }
187
+ /**
188
+ * Deposits tokens into the Monaco vault.
189
+ *
190
+ * Deposits the specified amount of tokens into the vault contract. The method
191
+ * first checks if sufficient approval exists, then obtains a signature from the
192
+ * API Gateway, and finally executes the deposit transaction on-chain.
193
+ *
194
+ * Note: This method requires prior approval via the `approve()` method.
195
+ *
196
+ * @param assetId - The asset identifier (UUID) to deposit
197
+ * @param amount - The amount of tokens to deposit (as bigint)
198
+ * @param autoWait - Whether to automatically wait for transaction confirmation (defaults to true)
199
+ * @returns Promise resolving to TransactionResult with transaction details
200
+ * @throws {ContractError} When deposit fails or approval is insufficient
201
+ * @throws {APIError} When the asset is not found or the assetId is invalid
202
+ * @throws {InvalidConfigError} When wallet account is not available
203
+ *
204
+ * @example
205
+ * ```typescript
206
+ * // Deposit 100 USDC into the vault (auto-waits by default)
207
+ * const result = await vaultAPI.deposit(
208
+ * "123e4567-e89b-12d3-a456-426614174000",
209
+ * parseUnits("100", 6)
210
+ * );
211
+ * console.log(`Deposit transaction: ${result.hash}`);
212
+ * console.log(`Status: ${result.status}`); // "confirmed" if successful
213
+ *
214
+ * // Or skip auto-waiting
215
+ * const result = await vaultAPI.deposit(
216
+ * "123e4567-e89b-12d3-a456-426614174000",
217
+ * parseUnits("100", 6),
218
+ * false
219
+ * );
220
+ * // Then manually wait later if needed
221
+ * const receipt = await sdk.waitForTransaction(result.hash);
222
+ * ```
223
+ */
224
+ async deposit(assetId, amount, autoWait = true) {
225
+ if (!this.walletClient) {
226
+ throw new InvalidConfigError("Wallet client not set. Connect a wallet first.", "walletClient");
227
+ }
228
+ // Validate inputs
229
+ validate(DepositSchema, { assetId, amount, autoWait });
230
+ const vaultAddress = await this.getVaultAddress();
231
+ const clientId = await this.getClientId();
232
+ const { tokenAddress, isNativeToken } = await this.resolveAsset(assetId);
233
+ if (!isNativeToken) {
234
+ // Check if approval is needed before proceeding
235
+ const needsApproval = await this.needsApproval(assetId, amount);
236
+ if (needsApproval) {
237
+ throw new ContractError(`Approval required before deposit. Please invoke approve() first for asset ${assetId} (token address: ${tokenAddress}).`, {
238
+ revertReason: "APPROVAL_REQUIRED",
239
+ });
240
+ }
241
+ }
242
+ const walletAccount = this.walletClient.account;
243
+ if (!walletAccount) {
244
+ throw new InvalidConfigError("No account available in wallet client", "account");
245
+ }
246
+ // For native SEI (zero address), use depositNative (payable); for ERC20 tokens, use depositERC20
247
+ let hash;
248
+ if (isNativeToken) {
249
+ hash = await this.walletClient.writeContract({
250
+ address: vaultAddress,
251
+ abi: CONTRACT_ABIS.vault,
252
+ functionName: "depositNative",
253
+ args: [walletAccount.address, clientId],
254
+ account: walletAccount,
255
+ chain: this.chain,
256
+ value: amount,
257
+ });
258
+ }
259
+ else {
260
+ hash = await this.walletClient.writeContract({
261
+ address: vaultAddress,
262
+ abi: CONTRACT_ABIS.vault,
263
+ functionName: "depositERC20",
264
+ args: [walletAccount.address, clientId, tokenAddress, amount],
265
+ account: walletAccount,
266
+ chain: this.chain,
267
+ });
268
+ }
269
+ const nonce = walletAccount.getNonce ? await walletAccount.getNonce() : 0n;
270
+ const txResult = {
271
+ hash,
272
+ status: "pending",
273
+ nonce,
274
+ };
275
+ return await this.waitForTransaction(txResult, autoWait);
276
+ }
277
+ /**
278
+ * Initiates a withdrawal through the API Gateway and submits the resulting
279
+ * pre-signed calldata on-chain via the connected wallet.
280
+ *
281
+ * The gateway allocates a `withdrawalIndex` via the matching engine and returns
282
+ * ABI-encoded calldata for `executeSignedWithdrawal(...)` signed by the
283
+ * server-side `WITHDRAWAL_SIGNER`. The user's wallet pays gas to submit it,
284
+ * but the contract authenticates against the embedded signature — not the
285
+ * `msg.sender`. The connected wallet's address is sent as the on-chain
286
+ * `destination`.
287
+ *
288
+ * @param assetId - The asset identifier (UUID) to withdraw
289
+ * @param amount - The raw token amount to withdraw (as bigint)
290
+ * @param autoWait - Whether to automatically wait for transaction confirmation (defaults to true)
291
+ * @returns Promise resolving to `{ withdrawalIndex, transaction }`
292
+ * @throws {APIError} When the asset is not found or the request is rejected
293
+ * @throws {ContractError} When the on-chain submission fails
294
+ * @throws {InvalidConfigError} When wallet account is not available
295
+ *
296
+ * @example
297
+ * ```typescript
298
+ * // Withdraw 50 USDC, wait for on-chain confirmation
299
+ * const result = await vaultAPI.withdraw(
300
+ * "123e4567-e89b-12d3-a456-426614174000",
301
+ * parseUnits("50", 6),
302
+ * );
303
+ * console.log(`Withdrawal index: ${result.withdrawalIndex}`);
304
+ * console.log(`Tx hash: ${result.hash}, status: ${result.status}`);
305
+ *
306
+ * // Or skip auto-waiting and finalise later
307
+ * const result = await vaultAPI.withdraw(
308
+ * "123e4567-e89b-12d3-a456-426614174000",
309
+ * parseUnits("50", 6),
310
+ * false,
311
+ * );
312
+ * const receipt = await sdk.waitForTransaction(result.hash);
313
+ * ```
314
+ */
315
+ async withdraw(assetId, amount, autoWait = true) {
316
+ if (!this.walletClient) {
317
+ throw new InvalidConfigError("Wallet client not set. Connect a wallet first.", "walletClient");
318
+ }
319
+ const walletAccount = this.walletClient.account;
320
+ if (!walletAccount) {
321
+ throw new InvalidConfigError("No account available in wallet client", "account");
322
+ }
323
+ const destination = walletAccount.address.toLowerCase();
324
+ validate(WithdrawSchema, { assetId, amount, destination, autoWait });
325
+ // 1. Gateway allocates withdrawal_index + returns pre-signed
326
+ // executeSignedWithdrawal calldata along with the vault address to send
327
+ // it to. Sourcing the vault address from this response (instead of
328
+ // GET /applications/config) keeps the calldata + target contract in
329
+ // lockstep and avoids an extra round-trip.
330
+ const { withdrawal_index: withdrawalIndex, vault_address: vaultAddress, calldata, } = await this.makeAuthenticatedRequest("/api/v1/withdrawals", {
331
+ method: "POST",
332
+ body: JSON.stringify({
333
+ asset_id: assetId,
334
+ amount: amount.toString(),
335
+ destination,
336
+ }),
337
+ });
338
+ // 2. Submit the calldata on-chain through the connected wallet.
339
+ let hash;
340
+ try {
341
+ hash = await this.walletClient.sendTransaction({
342
+ to: vaultAddress,
343
+ data: calldata,
344
+ account: walletAccount,
345
+ chain: this.chain,
346
+ });
347
+ }
348
+ catch (error) {
349
+ throw new ContractError(`Failed to submit executeSignedWithdrawal for withdrawal ${withdrawalIndex}: ${error instanceof Error ? error.message : "unknown error"}`, { cause: error instanceof Error ? error : undefined });
350
+ }
351
+ const nonce = walletAccount.getNonce ? await walletAccount.getNonce() : 0n;
352
+ const txResult = {
353
+ hash,
354
+ status: "pending",
355
+ nonce,
356
+ };
357
+ const settled = await this.waitForTransaction(txResult, autoWait);
358
+ return { ...settled, withdrawalIndex };
359
+ }
360
+ /**
361
+ * Retries a previously-initiated withdrawal whose on-chain submission never
362
+ * landed — e.g. the wallet rejected the tx, the page reloaded before the
363
+ * receipt came back, or a stuck mempool entry needs resending.
364
+ *
365
+ * Re-fetches the same `executeSignedWithdrawal` calldata the gateway
366
+ * generated when the withdrawal was initiated, then submits it through the
367
+ * connected wallet. Does NOT initiate a new withdrawal — the matching engine
368
+ * already debited the balance and allocated the index. The contract is
369
+ * idempotent against double-submission of a settled withdrawal: it will
370
+ * revert once the index is consumed on-chain.
371
+ *
372
+ * @param withdrawalIndex - The index returned by the original `withdraw()` call
373
+ * @param autoWait - Whether to await on-chain confirmation (defaults to true)
374
+ * @returns Promise resolving to `{ withdrawalIndex, ...transaction }`
375
+ * @throws {APIError} When the index doesn't exist
376
+ * @throws {ContractError} When the on-chain submission fails
377
+ * @throws {InvalidConfigError} When wallet account is not available
378
+ */
379
+ async retryWithdrawal(withdrawalIndex, autoWait = true) {
380
+ if (!this.walletClient) {
381
+ throw new InvalidConfigError("Wallet client not set. Connect a wallet first.", "walletClient");
382
+ }
383
+ const walletAccount = this.walletClient.account;
384
+ if (!walletAccount) {
385
+ throw new InvalidConfigError("No account available in wallet client", "account");
386
+ }
387
+ const { vault_address: vaultAddress, calldata } = await this.makePublicRequest(`/api/v1/withdrawals/${withdrawalIndex}`);
388
+ let hash;
389
+ try {
390
+ hash = await this.walletClient.sendTransaction({
391
+ to: vaultAddress,
392
+ data: calldata,
393
+ account: walletAccount,
394
+ chain: this.chain,
395
+ });
396
+ }
397
+ catch (error) {
398
+ throw new ContractError(`Failed to resubmit executeSignedWithdrawal for withdrawal ${withdrawalIndex}: ${error instanceof Error ? error.message : "unknown error"}`, { cause: error instanceof Error ? error : undefined });
399
+ }
400
+ const nonce = walletAccount.getNonce ? await walletAccount.getNonce() : 0n;
401
+ const txResult = {
402
+ hash,
403
+ status: "pending",
404
+ nonce,
405
+ };
406
+ const settled = await this.waitForTransaction(txResult, autoWait);
407
+ return { ...settled, withdrawalIndex };
408
+ }
409
+ /**
410
+ * Retrieves the user's token balance in the vault.
411
+ *
412
+ * @param _assetId - The asset identifier (UUID) to check balance for
413
+ * @returns Promise that always rejects with deprecation error
414
+ * @throws {APIError} Always throws - this method is deprecated
415
+ * @deprecated Use `profileAPI.getUserBalances()` or `profileAPI.getUserBalanceByAssetId()` instead.
416
+ */
417
+ async getBalance(_assetId) {
418
+ throw new APIError("getBalance() is deprecated and no longer supported. Please use profileAPI.getUserBalances() or profileAPI.getUserBalanceByAssetId() instead for balance data.", { statusCode: 410 });
419
+ }
420
+ /**
421
+ * Retrieves the current allowance for a token.
422
+ *
423
+ * Queries the ERC20 token contract to get the current allowance granted to the
424
+ * vault contract for spending tokens on behalf of the user.
425
+ *
426
+ * @param assetId - The asset identifier (UUID) to check allowance for
427
+ * @returns Promise resolving to the current allowance amount as bigint
428
+ * @throws {ContractError} When allowance retrieval fails or asset not found
429
+ *
430
+ * @example
431
+ * ```typescript
432
+ * const allowance = await vaultAPI.getAllowance("123e4567-e89b-12d3-a456-426614174000");
433
+ * console.log(`Current allowance: ${formatUnits(allowance, 6)} USDC`);
434
+ * ```
435
+ */
436
+ async getAllowance(assetId) {
437
+ if (!this.walletClient) {
438
+ throw new InvalidConfigError("Wallet client not set. Connect a wallet first.", "walletClient");
439
+ }
440
+ const vaultAddress = await this.getVaultAddress();
441
+ const addresses = await this.walletClient.getAddresses();
442
+ const account = addresses[0];
443
+ if (!account) {
444
+ throw new InvalidConfigError("No account found in wallet client.", "walletClient");
445
+ }
446
+ const { tokenAddress } = await this.resolveAsset(assetId);
447
+ return (await this.publicClient.readContract({
448
+ address: tokenAddress,
449
+ abi: erc20Abi,
450
+ functionName: "allowance",
451
+ args: [account, vaultAddress],
452
+ }));
453
+ }
454
+ /**
455
+ * Checks if approval is needed for a specific amount.
456
+ *
457
+ * Compares the current allowance with the requested amount to determine if
458
+ * the user needs to approve more tokens before performing operations.
459
+ *
460
+ * @param assetId - The asset identifier (UUID) to check for
461
+ * @param amount - The amount to check approval for (as bigint)
462
+ * @returns Promise resolving to true if approval is needed, false otherwise
463
+ * @throws {ContractError} When approval check fails or asset not found
464
+ *
465
+ * @example
466
+ * ```typescript
467
+ * const needsApproval = await vaultAPI.needsApproval(
468
+ * "123e4567-e89b-12d3-a456-426614174000",
469
+ * parseUnits("100", 6)
470
+ * );
471
+ *
472
+ * if (needsApproval) {
473
+ * console.log("Approval required before deposit");
474
+ * await vaultAPI.approve("123e4567-e89b-12d3-a456-426614174000", parseUnits("100", 6));
475
+ * }
476
+ * ```
477
+ */
478
+ async needsApproval(assetId, amount) {
479
+ const allowance = await this.getAllowance(assetId);
480
+ return allowance < amount;
481
+ }
482
+ async waitForTransaction(txResult, autoWait = true, options = {}) {
483
+ if (!autoWait) {
484
+ return txResult;
485
+ }
486
+ const { confirmations = 1, timeout = 60000 } = options;
487
+ try {
488
+ const receipt = await this.publicClient.waitForTransactionReceipt({
489
+ hash: txResult.hash,
490
+ confirmations,
491
+ timeout,
492
+ });
493
+ return {
494
+ ...txResult,
495
+ status: receipt.status === "success" ? "confirmed" : "failed",
496
+ receipt,
497
+ };
498
+ }
499
+ catch {
500
+ return {
501
+ ...txResult,
502
+ status: "failed",
503
+ };
504
+ }
505
+ }
506
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Vault API Module
3
+ */
4
+ export { VaultAPIImpl } from "./api";
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Vault API Module
3
+ */
4
+ export { VaultAPIImpl } from "./api";
@@ -0,0 +1,3 @@
1
+ export * from "./types";
2
+ export * from "./utils";
3
+ export * from "./websocket";
@@ -0,0 +1,3 @@
1
+ export * from "./types";
2
+ export * from "./utils";
3
+ export * from "./websocket";
@@ -0,0 +1,41 @@
1
+ import type { ConditionalOrderEvent, Interval, OHLCVEvent, OrderbookEvent, OrderbookQuotationMode, OrderEvent, TradeEvent, TradingMode, UserBalanceEvent, UserMovementEvent, WebSocketStatus } from "@0xmonaco/types";
2
+ export type StatusHandler = (status: WebSocketStatus) => void;
3
+ export type MessageHandler<T> = (data: T) => void;
4
+ export interface MonacoWebSocketOptions {
5
+ /** JWT access token for authenticated channels (orders) */
6
+ token?: string;
7
+ /** Enable auto-reconnect on disconnect (default: true) */
8
+ autoReconnect?: boolean;
9
+ /** Maximum reconnection attempts (default: 5) */
10
+ maxReconnectAttempts?: number;
11
+ /** Callback for connection status changes */
12
+ onStatusChange?: StatusHandler;
13
+ }
14
+ export interface MonacoWebSocket {
15
+ /** Connect to the WebSocket server */
16
+ connect: () => Promise<void>;
17
+ /** Disconnect from the WebSocket server */
18
+ disconnect: () => void;
19
+ /** Check if currently connected */
20
+ isConnected: () => boolean;
21
+ /** Get current websocket connection status */
22
+ getStatus: () => WebSocketStatus;
23
+ /** Update the access token (for re-auth) */
24
+ setToken: (token: string) => void;
25
+ /** Subscribe to order events (requires authentication) */
26
+ orders: (tradingPairId: string, tradingMode: TradingMode, handler: MessageHandler<OrderEvent>) => () => void;
27
+ /** Subscribe to orderbook events (public) */
28
+ orderbook: (tradingPairId: string, tradingMode: TradingMode, magnitude: number, quotationMode: OrderbookQuotationMode, handler: MessageHandler<OrderbookEvent>) => () => void;
29
+ /** Subscribe to OHLCV candlestick events (public) */
30
+ ohlcv: (tradingPairId: string, tradingMode: TradingMode, interval: Interval, handler: MessageHandler<OHLCVEvent>) => () => void;
31
+ /** Subscribe to trade events (public) */
32
+ trades: (tradingPairId: string, handler: MessageHandler<TradeEvent>) => () => void;
33
+ /** Subscribe to user movement events (requires authentication) */
34
+ movements: (handler: MessageHandler<UserMovementEvent>) => () => void;
35
+ /** Subscribe to user order events for all trading pairs (requires authentication) */
36
+ userOrders: (handler: MessageHandler<OrderEvent>) => () => void;
37
+ /** Subscribe to user balance events (requires authentication) */
38
+ balances: (handler: MessageHandler<UserBalanceEvent>) => () => void;
39
+ /** Subscribe to conditional TP/SL lifecycle events (requires authentication) */
40
+ conditionalOrders: (handler: MessageHandler<ConditionalOrderEvent>, tradingPairId?: string) => () => void;
41
+ }
File without changes
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Convert snake_case to camelCase
3
+ */
4
+ export declare function toCamelCase(str: string): string;
5
+ /**
6
+ * Recursively convert object keys from snake_case to camelCase
7
+ */
8
+ export declare function keysToCamelCase<T>(obj: unknown): T;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Convert snake_case to camelCase
3
+ */
4
+ export function toCamelCase(str) {
5
+ return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
6
+ }
7
+ /**
8
+ * Recursively convert object keys from snake_case to camelCase
9
+ */
10
+ export function keysToCamelCase(obj) {
11
+ if (obj === null || obj === undefined)
12
+ return obj;
13
+ if (typeof obj !== "object")
14
+ return obj;
15
+ if (Array.isArray(obj))
16
+ return obj.map((item) => keysToCamelCase(item));
17
+ const result = {};
18
+ for (const [key, value] of Object.entries(obj)) {
19
+ result[toCamelCase(key)] = typeof value === "object" && value !== null ? keysToCamelCase(value) : value;
20
+ }
21
+ return result;
22
+ }
@@ -0,0 +1,5 @@
1
+ import type { MonacoWebSocket, MonacoWebSocketOptions } from "./types";
2
+ /**
3
+ * Create a Monaco WebSocket client
4
+ */
5
+ export declare function createMonacoWebSocket(baseUrl: string, options?: MonacoWebSocketOptions): MonacoWebSocket;