@nktkas/hyperliquid 0.15.4 → 0.17.0

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 (68) hide show
  1. package/README.md +47 -89
  2. package/esm/src/base.d.ts +1 -0
  3. package/esm/src/base.d.ts.map +1 -1
  4. package/esm/src/clients/public.d.ts +6 -6
  5. package/esm/src/clients/public.d.ts.map +1 -1
  6. package/esm/src/clients/public.js +237 -54
  7. package/esm/src/clients/wallet.d.ts +121 -94
  8. package/esm/src/clients/wallet.d.ts.map +1 -1
  9. package/esm/src/clients/wallet.js +303 -206
  10. package/esm/src/signing.d.ts +117 -34
  11. package/esm/src/signing.d.ts.map +1 -1
  12. package/esm/src/signing.js +83 -19
  13. package/esm/src/transports/http/http_transport.d.ts +15 -27
  14. package/esm/src/transports/http/http_transport.d.ts.map +1 -1
  15. package/esm/src/transports/http/http_transport.js +20 -15
  16. package/esm/src/transports/websocket/_reconnecting_websocket.d.ts +1 -3
  17. package/esm/src/transports/websocket/_reconnecting_websocket.d.ts.map +1 -1
  18. package/esm/src/transports/websocket/websocket_transport.d.ts +6 -2
  19. package/esm/src/transports/websocket/websocket_transport.d.ts.map +1 -1
  20. package/esm/src/types/exchange/requests.d.ts +28 -14
  21. package/esm/src/types/exchange/requests.d.ts.map +1 -1
  22. package/esm/src/types/info/accounts.d.ts +4 -0
  23. package/esm/src/types/info/accounts.d.ts.map +1 -1
  24. package/esm/src/types/info/assets.d.ts +2 -0
  25. package/esm/src/types/info/assets.d.ts.map +1 -1
  26. package/esm/src/types/info/orders.d.ts +28 -20
  27. package/esm/src/types/info/orders.d.ts.map +1 -1
  28. package/esm/src/types/info/requests.d.ts +36 -18
  29. package/esm/src/types/info/requests.d.ts.map +1 -1
  30. package/esm/src/types/info/vaults.d.ts +2 -0
  31. package/esm/src/types/info/vaults.d.ts.map +1 -1
  32. package/esm/src/types/mod.d.ts +23 -0
  33. package/esm/src/types/mod.d.ts.map +1 -1
  34. package/esm/src/types/mod.js +23 -0
  35. package/package.json +4 -1
  36. package/script/src/base.d.ts +1 -0
  37. package/script/src/base.d.ts.map +1 -1
  38. package/script/src/clients/public.d.ts +6 -6
  39. package/script/src/clients/public.d.ts.map +1 -1
  40. package/script/src/clients/public.js +237 -54
  41. package/script/src/clients/wallet.d.ts +121 -94
  42. package/script/src/clients/wallet.d.ts.map +1 -1
  43. package/script/src/clients/wallet.js +302 -205
  44. package/script/src/signing.d.ts +117 -34
  45. package/script/src/signing.d.ts.map +1 -1
  46. package/script/src/signing.js +84 -15
  47. package/script/src/transports/http/http_transport.d.ts +15 -27
  48. package/script/src/transports/http/http_transport.d.ts.map +1 -1
  49. package/script/src/transports/http/http_transport.js +20 -15
  50. package/script/src/transports/websocket/_reconnecting_websocket.d.ts +1 -3
  51. package/script/src/transports/websocket/_reconnecting_websocket.d.ts.map +1 -1
  52. package/script/src/transports/websocket/websocket_transport.d.ts +6 -2
  53. package/script/src/transports/websocket/websocket_transport.d.ts.map +1 -1
  54. package/script/src/types/exchange/requests.d.ts +28 -14
  55. package/script/src/types/exchange/requests.d.ts.map +1 -1
  56. package/script/src/types/info/accounts.d.ts +4 -0
  57. package/script/src/types/info/accounts.d.ts.map +1 -1
  58. package/script/src/types/info/assets.d.ts +2 -0
  59. package/script/src/types/info/assets.d.ts.map +1 -1
  60. package/script/src/types/info/orders.d.ts +28 -20
  61. package/script/src/types/info/orders.d.ts.map +1 -1
  62. package/script/src/types/info/requests.d.ts +36 -18
  63. package/script/src/types/info/requests.d.ts.map +1 -1
  64. package/script/src/types/info/vaults.d.ts +2 -0
  65. package/script/src/types/info/vaults.d.ts.map +1 -1
  66. package/script/src/types/mod.d.ts +23 -0
  67. package/script/src/types/mod.d.ts.map +1 -1
  68. package/script/src/types/mod.js +23 -0
@@ -1,5 +1,5 @@
1
1
  import { HyperliquidError } from "../base.js";
2
- import { signL1Action, signUserSignedAction, } from "../signing.js";
2
+ import { isAbstractEthersSigner, isAbstractEthersV5Signer, isAbstractViemWalletClient, isAbstractWindowEthereum, signL1Action, signUserSignedAction, } from "../signing.js";
3
3
  // ——————————————— Errors ———————————————
4
4
  /** Error thrown when the API returns an error response. */
5
5
  export class ApiRequestError extends HyperliquidError {
@@ -40,23 +40,38 @@ export class ApiRequestError extends HyperliquidError {
40
40
  }
41
41
  }
42
42
  // ——————————————— Client ———————————————
43
- /**
44
- * Wallet client for interacting with the Hyperliquid API.
45
- * @typeParam T The transport used to connect to the Hyperliquid API.
46
- * @typeParam W The WalletClient/Account ([viem](https://viem.sh/docs/clients/wallet)) or Signer ([ethers.js](https://docs.ethers.io/v6/api/providers/#Signer)) used for signing transactions.
47
- */
48
- export class WalletClient {
49
- /** Gets the next nonce for signing transactions. */
50
- get _nonce() {
43
+ /** Nonce manager for generating unique nonces for signing transactions. */
44
+ class NonceManager {
45
+ constructor() {
46
+ /** The last nonce used for signing transactions. */
47
+ Object.defineProperty(this, "lastNonce", {
48
+ enumerable: true,
49
+ configurable: true,
50
+ writable: true,
51
+ value: 0
52
+ });
53
+ }
54
+ /**
55
+ * Gets the next nonce for signing transactions.
56
+ * @returns The next nonce.
57
+ */
58
+ getNonce() {
51
59
  let nonce = Date.now();
52
- if (nonce <= this._lastNonce) {
53
- nonce = ++this._lastNonce;
60
+ if (nonce <= this.lastNonce) {
61
+ nonce = ++this.lastNonce;
54
62
  }
55
63
  else {
56
- this._lastNonce = nonce;
64
+ this.lastNonce = nonce;
57
65
  }
58
66
  return nonce;
59
67
  }
68
+ }
69
+ /**
70
+ * Wallet client for interacting with the Hyperliquid API.
71
+ * @typeParam T The transport used to connect to the Hyperliquid API.
72
+ * @typeParam W The WalletClient/Account ([viem](https://viem.sh/docs/clients/wallet)) or Signer ([ethers.js](https://docs.ethers.io/v6/api/providers/#Signer)) used for signing transactions.
73
+ */
74
+ export class WalletClient {
60
75
  /**
61
76
  * Initialises a new instance.
62
77
  * @param args - The parameters for the client.
@@ -142,18 +157,19 @@ export class WalletClient {
142
157
  writable: true,
143
158
  value: void 0
144
159
  });
145
- /** The last nonce used for signing transactions. */
146
- Object.defineProperty(this, "_lastNonce", {
160
+ /** Function to get the next nonce for signing transactions. */
161
+ Object.defineProperty(this, "nonceManager", {
147
162
  enumerable: true,
148
163
  configurable: true,
149
164
  writable: true,
150
- value: 0
165
+ value: void 0
151
166
  });
152
167
  this.transport = args.transport;
153
168
  this.wallet = args.wallet;
154
169
  this.isTestnet = args.isTestnet ?? false;
155
170
  this.defaultVaultAddress = args.defaultVaultAddress;
156
- this.signatureChainId = args.signatureChainId ?? (this.isTestnet ? "0x66eee" : "0xa4b1");
171
+ this.signatureChainId = args.signatureChainId ?? this._guessSignatureChainId;
172
+ this.nonceManager = args.nonceManager ?? new NonceManager().getNonce;
157
173
  }
158
174
  // ——————————————— Exchange API ———————————————
159
175
  /**
@@ -185,8 +201,10 @@ export class WalletClient {
185
201
  ...args,
186
202
  type: "approveAgent",
187
203
  hyperliquidChain: this.isTestnet ? "Testnet" : "Mainnet",
188
- signatureChainId: this.signatureChainId,
189
- nonce: args.nonce ?? this._nonce,
204
+ signatureChainId: typeof this.signatureChainId === "string"
205
+ ? this.signatureChainId
206
+ : await this.signatureChainId(),
207
+ nonce: await this.nonceManager(),
190
208
  };
191
209
  // Sign the action
192
210
  const signature = await signUserSignedAction({
@@ -238,8 +256,10 @@ export class WalletClient {
238
256
  ...args,
239
257
  type: "approveBuilderFee",
240
258
  hyperliquidChain: this.isTestnet ? "Testnet" : "Mainnet",
241
- signatureChainId: this.signatureChainId,
242
- nonce: args.nonce ?? this._nonce,
259
+ signatureChainId: typeof this.signatureChainId === "string"
260
+ ? this.signatureChainId
261
+ : await this.signatureChainId(),
262
+ nonce: await this.nonceManager(),
243
263
  };
244
264
  // Sign the action
245
265
  const signature = await signUserSignedAction({
@@ -301,8 +321,9 @@ export class WalletClient {
301
321
  */
302
322
  async batchModify(args, signal) {
303
323
  // Destructure the parameters
304
- const { vaultAddress = this.defaultVaultAddress, nonce = this._nonce, ...actionArgs } = args;
324
+ const { vaultAddress = this.defaultVaultAddress, ...actionArgs } = args;
305
325
  // Construct an action
326
+ const nonce = await this.nonceManager();
306
327
  const action = {
307
328
  type: "batchModify",
308
329
  modifies: actionArgs.modifies.map((modify) => {
@@ -377,8 +398,9 @@ export class WalletClient {
377
398
  */
378
399
  async cancel(args, signal) {
379
400
  // Destructure the parameters
380
- const { vaultAddress = this.defaultVaultAddress, nonce = this._nonce, ...actionArgs } = args;
401
+ const { vaultAddress = this.defaultVaultAddress, ...actionArgs } = args;
381
402
  // Construct an action
403
+ const nonce = await this.nonceManager();
382
404
  const action = {
383
405
  type: "cancel",
384
406
  cancels: actionArgs.cancels.map((cancel) => ({
@@ -401,6 +423,58 @@ export class WalletClient {
401
423
  this._validateResponse(response);
402
424
  return response;
403
425
  }
426
+ /**
427
+ * Cancel order(s) by cloid.
428
+ * @param args - The parameters for the request.
429
+ * @param signal - An optional abort signal.
430
+ * @returns Successful variant of {@link CancelResponse} without error statuses.
431
+ * @throws {ApiRequestError} When the API returns an error response.
432
+ *
433
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s-by-cloid
434
+ * @example
435
+ * ```ts
436
+ * import * as hl from "@nktkas/hyperliquid";
437
+ * import { privateKeyToAccount } from "viem/accounts";
438
+ *
439
+ * const wallet = privateKeyToAccount("0x...");
440
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
441
+ * const client = new hl.WalletClient({ wallet, transport });
442
+ *
443
+ * const result = await client.cancelByCloid({
444
+ * cancels: [{
445
+ * asset: 0,
446
+ * cloid: "0x...", // Client Order ID
447
+ * }],
448
+ * });
449
+ * ```
450
+ */
451
+ async cancelByCloid(args, signal) {
452
+ // Destructure the parameters
453
+ const { vaultAddress = this.defaultVaultAddress, ...actionArgs } = args;
454
+ // Construct an action
455
+ const nonce = await this.nonceManager();
456
+ const action = {
457
+ type: "cancelByCloid",
458
+ cancels: actionArgs.cancels.map((cancel) => ({
459
+ asset: cancel.asset,
460
+ cloid: cancel.cloid,
461
+ })),
462
+ };
463
+ // Sign the action
464
+ const signature = await signL1Action({
465
+ wallet: this.wallet,
466
+ action,
467
+ nonce,
468
+ isTestnet: this.isTestnet,
469
+ vaultAddress,
470
+ });
471
+ // Send a request
472
+ const request = { action, signature, nonce, vaultAddress };
473
+ const response = await this.transport.request("exchange", request, signal);
474
+ // Validate a response
475
+ this._validateResponse(response);
476
+ return response;
477
+ }
404
478
  /**
405
479
  * Deposit into staking balance.
406
480
  * @param args - The parameters for the request.
@@ -427,8 +501,10 @@ export class WalletClient {
427
501
  ...args,
428
502
  type: "cDeposit",
429
503
  hyperliquidChain: this.isTestnet ? "Testnet" : "Mainnet",
430
- signatureChainId: this.signatureChainId,
431
- nonce: args.nonce ?? this._nonce,
504
+ signatureChainId: typeof this.signatureChainId === "string"
505
+ ? this.signatureChainId
506
+ : await this.signatureChainId(),
507
+ nonce: await this.nonceManager(),
432
508
  };
433
509
  // Sign the action
434
510
  const signature = await signUserSignedAction({
@@ -470,10 +546,9 @@ export class WalletClient {
470
546
  * const result = await client.claimRewards();
471
547
  * ```
472
548
  */
473
- async claimRewards(args = {}, signal) {
474
- // Destructure the parameters
475
- const { nonce = this._nonce, } = args;
549
+ async claimRewards(signal) {
476
550
  // Construct an action
551
+ const nonce = await this.nonceManager();
477
552
  const sortedAction = { type: "claimRewards" };
478
553
  // Sign the action
479
554
  const signature = await signL1Action({
@@ -490,13 +565,13 @@ export class WalletClient {
490
565
  return response;
491
566
  }
492
567
  /**
493
- * Cancel order(s) by cloid.
568
+ * Create a sub-account.
494
569
  * @param args - The parameters for the request.
495
570
  * @param signal - An optional abort signal.
496
- * @returns Successful variant of {@link CancelResponse} without error statuses.
571
+ * @returns Response for creating a sub-account.
497
572
  * @throws {ApiRequestError} When the API returns an error response.
498
573
  *
499
- * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s-by-cloid
574
+ * @see null - no documentation
500
575
  * @example
501
576
  * ```ts
502
577
  * import * as hl from "@nktkas/hyperliquid";
@@ -506,24 +581,15 @@ export class WalletClient {
506
581
  * const transport = new hl.HttpTransport(); // or WebSocketTransport
507
582
  * const client = new hl.WalletClient({ wallet, transport });
508
583
  *
509
- * const result = await client.cancelByCloid({
510
- * cancels: [{
511
- * asset: 0,
512
- * cloid: "0x...", // Client Order ID
513
- * }],
514
- * });
584
+ * const result = await client.createSubAccount({ name: "subAccountName" });
515
585
  * ```
516
586
  */
517
- async cancelByCloid(args, signal) {
518
- // Destructure the parameters
519
- const { vaultAddress = this.defaultVaultAddress, nonce = this._nonce, ...actionArgs } = args;
587
+ async createSubAccount(args, signal) {
520
588
  // Construct an action
589
+ const nonce = await this.nonceManager();
521
590
  const action = {
522
- type: "cancelByCloid",
523
- cancels: actionArgs.cancels.map((cancel) => ({
524
- asset: cancel.asset,
525
- cloid: cancel.cloid,
526
- })),
591
+ type: "createSubAccount",
592
+ name: args.name,
527
593
  };
528
594
  // Sign the action
529
595
  const signature = await signL1Action({
@@ -531,72 +597,22 @@ export class WalletClient {
531
597
  action,
532
598
  nonce,
533
599
  isTestnet: this.isTestnet,
534
- vaultAddress,
535
600
  });
536
601
  // Send a request
537
- const request = { action, signature, nonce, vaultAddress };
538
- const response = await this.transport.request("exchange", request, signal);
539
- // Validate a response
540
- this._validateResponse(response);
541
- return response;
542
- }
543
- /**
544
- * Withdraw from staking balance.
545
- * @param args - The parameters for the request.
546
- * @param signal - An optional abort signal.
547
- * @returns Successful response without specific data.
548
- * @throws {ApiRequestError} When the API returns an error response.
549
- *
550
- * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#withdraw-from-staking
551
- * @example
552
- * ```ts
553
- * import * as hl from "@nktkas/hyperliquid";
554
- * import { privateKeyToAccount } from "viem/accounts";
555
- *
556
- * const wallet = privateKeyToAccount("0x...");
557
- * const transport = new hl.HttpTransport(); // or WebSocketTransport
558
- * const client = new hl.WalletClient({ wallet, transport });
559
- *
560
- * const result = await client.cWithdraw({ wei: 1 * 1e8 });
561
- * ```
562
- */
563
- async cWithdraw(args, signal) {
564
- // Construct an action
565
- const action = {
566
- ...args,
567
- type: "cWithdraw",
568
- hyperliquidChain: this.isTestnet ? "Testnet" : "Mainnet",
569
- signatureChainId: this.signatureChainId,
570
- nonce: args.nonce ?? this._nonce,
571
- };
572
- // Sign the action
573
- const signature = await signUserSignedAction({
574
- wallet: this.wallet,
575
- action,
576
- types: {
577
- "HyperliquidTransaction:CWithdraw": [
578
- { name: "hyperliquidChain", type: "string" },
579
- { name: "wei", type: "uint64" },
580
- { name: "nonce", type: "uint64" },
581
- ],
582
- },
583
- chainId: parseInt(action.signatureChainId, 16),
584
- });
585
- // Send a request
586
- const request = { action, signature, nonce: action.nonce };
602
+ const request = { action, signature, nonce };
587
603
  const response = await this.transport.request("exchange", request, signal);
588
604
  // Validate a response
589
605
  this._validateResponse(response);
590
606
  return response;
591
607
  }
592
608
  /**
593
- * Configure block type for EVM transactions.
609
+ * Create a vault.
594
610
  * @param args - The parameters for the request.
595
611
  * @param signal - An optional abort signal.
596
- * @returns Response for creating a sub-account.
612
+ * @returns Response for creating a vault.
597
613
  * @throws {ApiRequestError} When the API returns an error response.
598
614
  *
599
- * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/evm/dual-block-architecture
615
+ * @see null - no documentation
600
616
  * @example
601
617
  * ```ts
602
618
  * import * as hl from "@nktkas/hyperliquid";
@@ -606,16 +622,22 @@ export class WalletClient {
606
622
  * const transport = new hl.HttpTransport(); // or WebSocketTransport
607
623
  * const client = new hl.WalletClient({ wallet, transport });
608
624
  *
609
- * const result = await client.evmUserModify({ usingBigBlocks: true });
625
+ * const result = await client.createVault({
626
+ * name: "VaultName",
627
+ * description: "This is an example of a vault description",
628
+ * initialUsd: 100 * 1e6,
629
+ * });
610
630
  * ```
611
631
  */
612
- async evmUserModify(args, signal) {
613
- // Destructure the parameters
614
- const { nonce = this._nonce, ...actionArgs } = args;
632
+ async createVault(args, signal) {
615
633
  // Construct an action
634
+ const nonce = await this.nonceManager();
616
635
  const action = {
617
- type: "evmUserModify",
618
- usingBigBlocks: actionArgs.usingBigBlocks,
636
+ type: "createVault",
637
+ name: args.name,
638
+ description: args.description,
639
+ initialUsd: args.initialUsd,
640
+ nonce,
619
641
  };
620
642
  // Sign the action
621
643
  const signature = await signL1Action({
@@ -632,13 +654,13 @@ export class WalletClient {
632
654
  return response;
633
655
  }
634
656
  /**
635
- * Create a sub-account.
657
+ * Withdraw from staking balance.
636
658
  * @param args - The parameters for the request.
637
659
  * @param signal - An optional abort signal.
638
- * @returns Response for creating a sub-account.
660
+ * @returns Successful response without specific data.
639
661
  * @throws {ApiRequestError} When the API returns an error response.
640
662
  *
641
- * @see null - no documentation
663
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#withdraw-from-staking
642
664
  * @example
643
665
  * ```ts
644
666
  * import * as hl from "@nktkas/hyperliquid";
@@ -648,39 +670,48 @@ export class WalletClient {
648
670
  * const transport = new hl.HttpTransport(); // or WebSocketTransport
649
671
  * const client = new hl.WalletClient({ wallet, transport });
650
672
  *
651
- * const result = await client.createSubAccount({ name: "subAccountName" });
673
+ * const result = await client.cWithdraw({ wei: 1 * 1e8 });
652
674
  * ```
653
675
  */
654
- async createSubAccount(args, signal) {
655
- // Destructure the parameters
656
- const { nonce = this._nonce, ...actionArgs } = args;
676
+ async cWithdraw(args, signal) {
657
677
  // Construct an action
658
678
  const action = {
659
- type: "createSubAccount",
660
- name: actionArgs.name,
679
+ ...args,
680
+ type: "cWithdraw",
681
+ hyperliquidChain: this.isTestnet ? "Testnet" : "Mainnet",
682
+ signatureChainId: typeof this.signatureChainId === "string"
683
+ ? this.signatureChainId
684
+ : await this.signatureChainId(),
685
+ nonce: await this.nonceManager(),
661
686
  };
662
687
  // Sign the action
663
- const signature = await signL1Action({
688
+ const signature = await signUserSignedAction({
664
689
  wallet: this.wallet,
665
690
  action,
666
- nonce,
667
- isTestnet: this.isTestnet,
691
+ types: {
692
+ "HyperliquidTransaction:CWithdraw": [
693
+ { name: "hyperliquidChain", type: "string" },
694
+ { name: "wei", type: "uint64" },
695
+ { name: "nonce", type: "uint64" },
696
+ ],
697
+ },
698
+ chainId: parseInt(action.signatureChainId, 16),
668
699
  });
669
700
  // Send a request
670
- const request = { action, signature, nonce };
701
+ const request = { action, signature, nonce: action.nonce };
671
702
  const response = await this.transport.request("exchange", request, signal);
672
703
  // Validate a response
673
704
  this._validateResponse(response);
674
705
  return response;
675
706
  }
676
707
  /**
677
- * Create a vault.
708
+ * Configure block type for EVM transactions.
678
709
  * @param args - The parameters for the request.
679
710
  * @param signal - An optional abort signal.
680
- * @returns Response for creating a vault.
711
+ * @returns Response for creating a sub-account.
681
712
  * @throws {ApiRequestError} When the API returns an error response.
682
713
  *
683
- * @see null - no documentation
714
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/evm/dual-block-architecture
684
715
  * @example
685
716
  * ```ts
686
717
  * import * as hl from "@nktkas/hyperliquid";
@@ -690,23 +721,15 @@ export class WalletClient {
690
721
  * const transport = new hl.HttpTransport(); // or WebSocketTransport
691
722
  * const client = new hl.WalletClient({ wallet, transport });
692
723
  *
693
- * const result = await client.createVault({
694
- * name: "VaultName",
695
- * description: "This is an example of a vault description",
696
- * initialUsd: 100 * 1e6,
697
- * });
724
+ * const result = await client.evmUserModify({ usingBigBlocks: true });
698
725
  * ```
699
726
  */
700
- async createVault(args, signal) {
701
- // Destructure the parameters
702
- const { nonce = this._nonce, ...actionArgs } = args;
727
+ async evmUserModify(args, signal) {
703
728
  // Construct an action
729
+ const nonce = await this.nonceManager();
704
730
  const action = {
705
- type: "createVault",
706
- name: actionArgs.name,
707
- description: actionArgs.description,
708
- initialUsd: actionArgs.initialUsd,
709
- nonce,
731
+ type: "evmUserModify",
732
+ usingBigBlocks: args.usingBigBlocks,
710
733
  };
711
734
  // Sign the action
712
735
  const signature = await signL1Action({
@@ -759,8 +782,9 @@ export class WalletClient {
759
782
  */
760
783
  async modify(args, signal) {
761
784
  // Destructure the parameters
762
- const { vaultAddress = this.defaultVaultAddress, nonce = this._nonce, ...actionArgs } = args;
785
+ const { vaultAddress = this.defaultVaultAddress, ...actionArgs } = args;
763
786
  // Construct an action
787
+ const nonce = await this.nonceManager();
764
788
  const action = {
765
789
  type: "modify",
766
790
  oid: actionArgs.oid,
@@ -840,8 +864,9 @@ export class WalletClient {
840
864
  */
841
865
  async order(args, signal) {
842
866
  // Destructure the parameters
843
- const { vaultAddress = this.defaultVaultAddress, nonce = this._nonce, ...actionArgs } = args;
867
+ const { vaultAddress = this.defaultVaultAddress, ...actionArgs } = args;
844
868
  // Construct an action
869
+ const nonce = await this.nonceManager();
845
870
  const action = {
846
871
  type: "order",
847
872
  orders: actionArgs.orders.map((order) => {
@@ -895,6 +920,47 @@ export class WalletClient {
895
920
  this._validateResponse(response);
896
921
  return response;
897
922
  }
923
+ /**
924
+ * Reserve additional rate-limited actions for a fee.
925
+ * @param args - The parameters for the request.
926
+ * @param signal - An optional abort signal.
927
+ * @returns Successful response indicating the weight reservation.
928
+ * @throws {ApiRequestError} When the API returns an error response.
929
+ *
930
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#reserve-additional-actions
931
+ * @example
932
+ * ```ts
933
+ * import * as hl from "@nktkas/hyperliquid";
934
+ * import { privateKeyToAccount } from "viem/accounts";
935
+ *
936
+ * const wallet = privateKeyToAccount("0x...");
937
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
938
+ * const client = new hl.WalletClient({ wallet, transport });
939
+ *
940
+ * const result = await client.reserveRequestWeight({ weight: 10 });
941
+ * ```
942
+ */
943
+ async reserveRequestWeight(args, signal) {
944
+ // Construct an action
945
+ const nonce = await this.nonceManager();
946
+ const action = {
947
+ type: "reserveRequestWeight",
948
+ weight: args.weight,
949
+ };
950
+ // Sign the action
951
+ const signature = await signL1Action({
952
+ wallet: this.wallet,
953
+ action,
954
+ nonce,
955
+ isTestnet: this.isTestnet,
956
+ });
957
+ // Send a request
958
+ const request = { action, signature, nonce };
959
+ const response = await this.transport.request("exchange", request, signal);
960
+ // Validate a response
961
+ this._validateResponse(response);
962
+ return response;
963
+ }
898
964
  /**
899
965
  * Schedule a time to cancel all open orders.
900
966
  * @param args - The parameters for the request.
@@ -917,8 +983,9 @@ export class WalletClient {
917
983
  */
918
984
  async scheduleCancel(args = {}, signal) {
919
985
  // Destructure the parameters
920
- const { vaultAddress = this.defaultVaultAddress, nonce = this._nonce, ...actionArgs } = args;
986
+ const { vaultAddress = this.defaultVaultAddress, ...actionArgs } = args;
921
987
  // Construct an action
988
+ const nonce = await this.nonceManager();
922
989
  const action = {
923
990
  type: "scheduleCancel",
924
991
  time: actionArgs.time,
@@ -961,12 +1028,11 @@ export class WalletClient {
961
1028
  * ```
962
1029
  */
963
1030
  async setDisplayName(args, signal) {
964
- // Destructure the parameters
965
- const { nonce = this._nonce, ...actionArgs } = args;
966
1031
  // Construct an action
1032
+ const nonce = await this.nonceManager();
967
1033
  const action = {
968
1034
  type: "setDisplayName",
969
- displayName: actionArgs.displayName,
1035
+ displayName: args.displayName,
970
1036
  };
971
1037
  // Sign the action
972
1038
  const signature = await signL1Action({
@@ -1003,12 +1069,11 @@ export class WalletClient {
1003
1069
  * ```
1004
1070
  */
1005
1071
  async setReferrer(args, signal) {
1006
- // Destructure the parameters
1007
- const { nonce = this._nonce, ...actionArgs } = args;
1008
1072
  // Construct an action
1073
+ const nonce = await this.nonceManager();
1009
1074
  const action = {
1010
1075
  type: "setReferrer",
1011
- code: actionArgs.code,
1076
+ code: args.code,
1012
1077
  };
1013
1078
  // Sign the action
1014
1079
  const signature = await signL1Action({
@@ -1057,48 +1122,47 @@ export class WalletClient {
1057
1122
  * ```
1058
1123
  */
1059
1124
  async spotDeploy(args, signal) {
1060
- // Destructure the parameters
1061
- const { nonce = this._nonce, ...actionArgs } = args;
1062
1125
  // Construct an action
1126
+ const nonce = await this.nonceManager();
1063
1127
  let action;
1064
- if ("registerToken2" in actionArgs) {
1128
+ if ("registerToken2" in args) {
1065
1129
  action = {
1066
1130
  type: "spotDeploy",
1067
1131
  registerToken2: {
1068
1132
  spec: {
1069
- name: actionArgs.registerToken2.spec.name,
1070
- szDecimals: actionArgs.registerToken2.spec.szDecimals,
1071
- weiDecimals: actionArgs.registerToken2.spec.weiDecimals,
1133
+ name: args.registerToken2.spec.name,
1134
+ szDecimals: args.registerToken2.spec.szDecimals,
1135
+ weiDecimals: args.registerToken2.spec.weiDecimals,
1072
1136
  },
1073
- maxGas: actionArgs.registerToken2.maxGas,
1074
- fullName: actionArgs.registerToken2.fullName,
1137
+ maxGas: args.registerToken2.maxGas,
1138
+ fullName: args.registerToken2.fullName,
1075
1139
  },
1076
1140
  };
1077
1141
  }
1078
- else if ("userGenesis" in actionArgs) {
1142
+ else if ("userGenesis" in args) {
1079
1143
  action = {
1080
1144
  type: "spotDeploy",
1081
1145
  userGenesis: {
1082
- token: actionArgs.userGenesis.token,
1083
- userAndWei: actionArgs.userGenesis.userAndWei,
1084
- existingTokenAndWei: actionArgs.userGenesis.existingTokenAndWei,
1146
+ token: args.userGenesis.token,
1147
+ userAndWei: args.userGenesis.userAndWei,
1148
+ existingTokenAndWei: args.userGenesis.existingTokenAndWei,
1085
1149
  },
1086
1150
  };
1087
1151
  }
1088
- else if ("genesis" in actionArgs) {
1152
+ else if ("genesis" in args) {
1089
1153
  action = {
1090
1154
  type: "spotDeploy",
1091
1155
  genesis: {
1092
- token: actionArgs.genesis.token,
1093
- maxSupply: actionArgs.genesis.maxSupply,
1156
+ token: args.genesis.token,
1157
+ maxSupply: args.genesis.maxSupply,
1094
1158
  },
1095
1159
  };
1096
1160
  }
1097
- else if ("registerSpot" in actionArgs) {
1161
+ else if ("registerSpot" in args) {
1098
1162
  action = {
1099
1163
  type: "spotDeploy",
1100
1164
  registerSpot: {
1101
- tokens: actionArgs.registerSpot.tokens,
1165
+ tokens: args.registerSpot.tokens,
1102
1166
  },
1103
1167
  };
1104
1168
  }
@@ -1106,11 +1170,11 @@ export class WalletClient {
1106
1170
  action = {
1107
1171
  type: "spotDeploy",
1108
1172
  registerHyperliquidity: {
1109
- spot: actionArgs.registerHyperliquidity.spot,
1110
- startPx: actionArgs.registerHyperliquidity.startPx,
1111
- orderSz: actionArgs.registerHyperliquidity.orderSz,
1112
- nOrders: actionArgs.registerHyperliquidity.nOrders,
1113
- nSeededLevels: actionArgs.registerHyperliquidity.nSeededLevels,
1173
+ spot: args.registerHyperliquidity.spot,
1174
+ startPx: args.registerHyperliquidity.startPx,
1175
+ orderSz: args.registerHyperliquidity.orderSz,
1176
+ nOrders: args.registerHyperliquidity.nOrders,
1177
+ nSeededLevels: args.registerHyperliquidity.nSeededLevels,
1114
1178
  },
1115
1179
  };
1116
1180
  }
@@ -1158,8 +1222,10 @@ export class WalletClient {
1158
1222
  ...args,
1159
1223
  type: "spotSend",
1160
1224
  hyperliquidChain: this.isTestnet ? "Testnet" : "Mainnet",
1161
- signatureChainId: this.signatureChainId,
1162
- time: args.time ?? this._nonce,
1225
+ signatureChainId: typeof this.signatureChainId === "string"
1226
+ ? this.signatureChainId
1227
+ : await this.signatureChainId(),
1228
+ time: await this.nonceManager(),
1163
1229
  };
1164
1230
  // Sign the action
1165
1231
  const signature = await signUserSignedAction({
@@ -1206,13 +1272,12 @@ export class WalletClient {
1206
1272
  * ```
1207
1273
  */
1208
1274
  async spotUser(args, signal) {
1209
- // Destructure the parameters
1210
- const { nonce = this._nonce, ...actionArgs } = args;
1211
1275
  // Construct an action
1276
+ const nonce = await this.nonceManager();
1212
1277
  const action = {
1213
1278
  type: "spotUser",
1214
1279
  toggleSpotDusting: {
1215
- optOut: actionArgs.toggleSpotDusting.optOut,
1280
+ optOut: args.toggleSpotDusting.optOut,
1216
1281
  },
1217
1282
  };
1218
1283
  // Sign the action
@@ -1255,15 +1320,14 @@ export class WalletClient {
1255
1320
  * ```
1256
1321
  */
1257
1322
  async subAccountSpotTransfer(args, signal) {
1258
- // Destructure the parameters
1259
- const { nonce = this._nonce, ...actionArgs } = args;
1260
1323
  // Construct an action
1324
+ const nonce = await this.nonceManager();
1261
1325
  const action = {
1262
1326
  type: "subAccountSpotTransfer",
1263
- subAccountUser: actionArgs.subAccountUser,
1264
- isDeposit: actionArgs.isDeposit,
1265
- token: actionArgs.token,
1266
- amount: actionArgs.amount,
1327
+ subAccountUser: args.subAccountUser,
1328
+ isDeposit: args.isDeposit,
1329
+ token: args.token,
1330
+ amount: args.amount,
1267
1331
  };
1268
1332
  // Sign the action
1269
1333
  const signature = await signL1Action({
@@ -1304,14 +1368,13 @@ export class WalletClient {
1304
1368
  * ```
1305
1369
  */
1306
1370
  async subAccountTransfer(args, signal) {
1307
- // Destructure the parameters
1308
- const { nonce = this._nonce, ...actionArgs } = args;
1309
1371
  // Construct an action
1372
+ const nonce = await this.nonceManager();
1310
1373
  const action = {
1311
1374
  type: "subAccountTransfer",
1312
- subAccountUser: actionArgs.subAccountUser,
1313
- isDeposit: actionArgs.isDeposit,
1314
- usd: actionArgs.usd,
1375
+ subAccountUser: args.subAccountUser,
1376
+ isDeposit: args.isDeposit,
1377
+ usd: args.usd,
1315
1378
  };
1316
1379
  // Sign the action
1317
1380
  const signature = await signL1Action({
@@ -1357,8 +1420,10 @@ export class WalletClient {
1357
1420
  ...args,
1358
1421
  type: "tokenDelegate",
1359
1422
  hyperliquidChain: this.isTestnet ? "Testnet" : "Mainnet",
1360
- signatureChainId: this.signatureChainId,
1361
- nonce: args.nonce ?? this._nonce,
1423
+ signatureChainId: typeof this.signatureChainId === "string"
1424
+ ? this.signatureChainId
1425
+ : await this.signatureChainId(),
1426
+ nonce: await this.nonceManager(),
1362
1427
  };
1363
1428
  // Sign the action
1364
1429
  const signature = await signUserSignedAction({
@@ -1407,8 +1472,9 @@ export class WalletClient {
1407
1472
  */
1408
1473
  async twapCancel(args, signal) {
1409
1474
  // Destructure the parameters
1410
- const { vaultAddress = this.defaultVaultAddress, nonce = this._nonce, ...actionArgs } = args;
1475
+ const { vaultAddress = this.defaultVaultAddress, ...actionArgs } = args;
1411
1476
  // Construct an action
1477
+ const nonce = await this.nonceManager();
1412
1478
  const action = {
1413
1479
  type: "twapCancel",
1414
1480
  a: actionArgs.a,
@@ -1458,8 +1524,9 @@ export class WalletClient {
1458
1524
  */
1459
1525
  async twapOrder(args, signal) {
1460
1526
  // Destructure the parameters
1461
- const { vaultAddress = this.defaultVaultAddress, nonce = this._nonce, ...actionArgs } = args;
1527
+ const { vaultAddress = this.defaultVaultAddress, ...actionArgs } = args;
1462
1528
  // Construct an action
1529
+ const nonce = await this.nonceManager();
1463
1530
  const action = {
1464
1531
  type: "twapOrder",
1465
1532
  twap: {
@@ -1512,8 +1579,9 @@ export class WalletClient {
1512
1579
  */
1513
1580
  async updateIsolatedMargin(args, signal) {
1514
1581
  // Destructure the parameters
1515
- const { vaultAddress = this.defaultVaultAddress, nonce = this._nonce, ...actionArgs } = args;
1582
+ const { vaultAddress = this.defaultVaultAddress, ...actionArgs } = args;
1516
1583
  // Construct an action
1584
+ const nonce = await this.nonceManager();
1517
1585
  const action = {
1518
1586
  type: "updateIsolatedMargin",
1519
1587
  asset: actionArgs.asset,
@@ -1561,8 +1629,9 @@ export class WalletClient {
1561
1629
  */
1562
1630
  async updateLeverage(args, signal) {
1563
1631
  // Destructure the parameters
1564
- const { vaultAddress = this.defaultVaultAddress, nonce = this._nonce, ...actionArgs } = args;
1632
+ const { vaultAddress = this.defaultVaultAddress, ...actionArgs } = args;
1565
1633
  // Construct an action
1634
+ const nonce = await this.nonceManager();
1566
1635
  const action = {
1567
1636
  type: "updateLeverage",
1568
1637
  asset: actionArgs.asset,
@@ -1613,8 +1682,10 @@ export class WalletClient {
1613
1682
  ...args,
1614
1683
  type: "usdClassTransfer",
1615
1684
  hyperliquidChain: this.isTestnet ? "Testnet" : "Mainnet",
1616
- signatureChainId: this.signatureChainId,
1617
- nonce: args.nonce ?? this._nonce,
1685
+ signatureChainId: typeof this.signatureChainId === "string"
1686
+ ? this.signatureChainId
1687
+ : await this.signatureChainId(),
1688
+ nonce: await this.nonceManager(),
1618
1689
  };
1619
1690
  // Sign the action
1620
1691
  const signature = await signUserSignedAction({
@@ -1666,8 +1737,10 @@ export class WalletClient {
1666
1737
  ...args,
1667
1738
  type: "usdSend",
1668
1739
  hyperliquidChain: this.isTestnet ? "Testnet" : "Mainnet",
1669
- signatureChainId: this.signatureChainId,
1670
- time: args.time ?? this._nonce,
1740
+ signatureChainId: typeof this.signatureChainId === "string"
1741
+ ? this.signatureChainId
1742
+ : await this.signatureChainId(),
1743
+ time: await this.nonceManager(),
1671
1744
  };
1672
1745
  // Sign the action
1673
1746
  const signature = await signUserSignedAction({
@@ -1714,13 +1787,12 @@ export class WalletClient {
1714
1787
  * ```
1715
1788
  */
1716
1789
  async vaultDistribute(args, signal) {
1717
- // Destructure the parameters
1718
- const { nonce = this._nonce, ...actionArgs } = args;
1719
1790
  // Construct an action
1791
+ const nonce = await this.nonceManager();
1720
1792
  const action = {
1721
1793
  type: "vaultDistribute",
1722
- vaultAddress: actionArgs.vaultAddress,
1723
- usd: actionArgs.usd,
1794
+ vaultAddress: args.vaultAddress,
1795
+ usd: args.usd,
1724
1796
  };
1725
1797
  // Sign the action
1726
1798
  const signature = await signL1Action({
@@ -1761,14 +1833,13 @@ export class WalletClient {
1761
1833
  * ```
1762
1834
  */
1763
1835
  async vaultModify(args, signal) {
1764
- // Destructure the parameters
1765
- const { nonce = this._nonce, ...actionArgs } = args;
1766
1836
  // Construct an action
1837
+ const nonce = await this.nonceManager();
1767
1838
  const action = {
1768
1839
  type: "vaultModify",
1769
- vaultAddress: actionArgs.vaultAddress,
1770
- allowDeposits: actionArgs.allowDeposits,
1771
- alwaysCloseOnWithdraw: actionArgs.alwaysCloseOnWithdraw,
1840
+ vaultAddress: args.vaultAddress,
1841
+ allowDeposits: args.allowDeposits,
1842
+ alwaysCloseOnWithdraw: args.alwaysCloseOnWithdraw,
1772
1843
  };
1773
1844
  // Sign the action
1774
1845
  const signature = await signL1Action({
@@ -1809,14 +1880,13 @@ export class WalletClient {
1809
1880
  * ```
1810
1881
  */
1811
1882
  async vaultTransfer(args, signal) {
1812
- // Destructure the parameters
1813
- const { nonce = this._nonce, ...actionArgs } = args;
1814
1883
  // Construct an action
1884
+ const nonce = await this.nonceManager();
1815
1885
  const action = {
1816
1886
  type: "vaultTransfer",
1817
- vaultAddress: actionArgs.vaultAddress,
1818
- isDeposit: actionArgs.isDeposit,
1819
- usd: actionArgs.usd,
1887
+ vaultAddress: args.vaultAddress,
1888
+ isDeposit: args.isDeposit,
1889
+ usd: args.usd,
1820
1890
  };
1821
1891
  // Sign the action
1822
1892
  const signature = await signL1Action({
@@ -1861,8 +1931,10 @@ export class WalletClient {
1861
1931
  ...args,
1862
1932
  type: "withdraw3",
1863
1933
  hyperliquidChain: this.isTestnet ? "Testnet" : "Mainnet",
1864
- signatureChainId: this.signatureChainId,
1865
- time: args.time ?? this._nonce,
1934
+ signatureChainId: typeof this.signatureChainId === "string"
1935
+ ? this.signatureChainId
1936
+ : await this.signatureChainId(),
1937
+ time: await this.nonceManager(),
1866
1938
  };
1867
1939
  // Sign the action
1868
1940
  const signature = await signUserSignedAction({
@@ -1894,6 +1966,31 @@ export class WalletClient {
1894
1966
  const newFrac = fracPart.replace(/0+$/, "");
1895
1967
  return newFrac ? `${intPart}.${newFrac}` : intPart;
1896
1968
  }
1969
+ /** Guesses the chain ID based on the wallet type or the isTestnet flag. */
1970
+ async _guessSignatureChainId() {
1971
+ // Trying to get chain ID of the wallet
1972
+ if (isAbstractViemWalletClient(this.wallet)) {
1973
+ if ("getChainId" in this.wallet && typeof this.wallet.getChainId === "function") {
1974
+ const chainId = await this.wallet.getChainId();
1975
+ return `0x${chainId.toString(16)}`;
1976
+ }
1977
+ }
1978
+ else if (isAbstractEthersSigner(this.wallet) || isAbstractEthersV5Signer(this.wallet)) {
1979
+ if ("provider" in this.wallet &&
1980
+ typeof this.wallet.provider === "object" && this.wallet.provider !== null &&
1981
+ "getNetwork" in this.wallet.provider &&
1982
+ typeof this.wallet.provider.getNetwork === "function") {
1983
+ const network = await this.wallet.provider.getNetwork();
1984
+ return `0x${network.chainId.toString(16)}`;
1985
+ }
1986
+ }
1987
+ else if (isAbstractWindowEthereum(this.wallet)) {
1988
+ const [chainId] = await this.wallet.request({ method: "eth_chainId", params: [] });
1989
+ return chainId;
1990
+ }
1991
+ // Attempt to guess chain ID based on isTestnet
1992
+ return this.isTestnet ? "0x66eee" : "0xa4b1";
1993
+ }
1897
1994
  /** Validate a response from the API. */
1898
1995
  _validateResponse(response) {
1899
1996
  if (response.status === "err") {