@nktkas/hyperliquid 0.19.1 → 0.20.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 (136) hide show
  1. package/CONTRIBUTING.md +4 -2
  2. package/README.md +36 -35
  3. package/esm/_dnt.polyfills.d.ts +20 -0
  4. package/esm/_dnt.polyfills.d.ts.map +1 -0
  5. package/esm/_dnt.polyfills.js +12 -0
  6. package/esm/mod.d.ts +3 -0
  7. package/esm/mod.d.ts.map +1 -1
  8. package/esm/mod.js +2 -0
  9. package/esm/src/base.d.ts +1 -47
  10. package/esm/src/base.d.ts.map +1 -1
  11. package/esm/src/base.js +1 -8
  12. package/esm/src/clients/event.d.ts +6 -4
  13. package/esm/src/clients/event.d.ts.map +1 -1
  14. package/esm/src/clients/event.js +58 -77
  15. package/esm/src/clients/public.d.ts +26 -5
  16. package/esm/src/clients/public.d.ts.map +1 -1
  17. package/esm/src/clients/public.js +29 -41
  18. package/esm/src/clients/wallet.d.ts +200 -26
  19. package/esm/src/clients/wallet.d.ts.map +1 -1
  20. package/esm/src/clients/wallet.js +306 -284
  21. package/esm/src/signing.d.ts +80 -5
  22. package/esm/src/signing.d.ts.map +1 -1
  23. package/esm/src/signing.js +96 -7
  24. package/esm/src/transports/base.d.ts +49 -0
  25. package/esm/src/transports/base.d.ts.map +1 -0
  26. package/esm/src/transports/base.js +8 -0
  27. package/esm/src/transports/http/http_transport.d.ts +8 -5
  28. package/esm/src/transports/http/http_transport.d.ts.map +1 -1
  29. package/esm/src/transports/http/http_transport.js +15 -62
  30. package/esm/src/transports/websocket/_hyperliquid_event_target.d.ts +36 -39
  31. package/esm/src/transports/websocket/_hyperliquid_event_target.d.ts.map +1 -1
  32. package/esm/src/transports/websocket/_reconnecting_websocket.d.ts +18 -25
  33. package/esm/src/transports/websocket/_reconnecting_websocket.d.ts.map +1 -1
  34. package/esm/src/transports/websocket/_reconnecting_websocket.js +80 -179
  35. package/{script/src/transports/websocket/_websocket_request_dispatcher.d.ts → esm/src/transports/websocket/_websocket_async_request.d.ts} +14 -18
  36. package/esm/src/transports/websocket/_websocket_async_request.d.ts.map +1 -0
  37. package/esm/src/transports/websocket/{_websocket_request_dispatcher.js → _websocket_async_request.js} +42 -75
  38. package/esm/src/transports/websocket/websocket_transport.d.ts +38 -28
  39. package/esm/src/transports/websocket/websocket_transport.d.ts.map +1 -1
  40. package/esm/src/transports/websocket/websocket_transport.js +61 -76
  41. package/esm/src/types/exchange/requests.d.ts +278 -66
  42. package/esm/src/types/exchange/requests.d.ts.map +1 -1
  43. package/esm/src/types/info/assets.d.ts +0 -48
  44. package/esm/src/types/info/assets.d.ts.map +1 -1
  45. package/esm/src/types/info/markets.d.ts +52 -0
  46. package/esm/src/types/info/markets.d.ts.map +1 -0
  47. package/esm/src/types/info/markets.js +1 -0
  48. package/esm/src/types/info/orders.d.ts +1 -1
  49. package/esm/src/types/info/orders.d.ts.map +1 -1
  50. package/esm/src/types/info/requests.d.ts +14 -5
  51. package/esm/src/types/info/requests.d.ts.map +1 -1
  52. package/esm/src/types/mod.d.ts +4 -0
  53. package/esm/src/types/mod.d.ts.map +1 -1
  54. package/esm/src/types/mod.js +3 -1
  55. package/esm/src/types/subscriptions/requests.d.ts +2 -0
  56. package/esm/src/types/subscriptions/requests.d.ts.map +1 -1
  57. package/package.json +12 -9
  58. package/script/_dnt.polyfills.d.ts +20 -0
  59. package/script/_dnt.polyfills.d.ts.map +1 -0
  60. package/script/_dnt.polyfills.js +23 -0
  61. package/script/mod.d.ts +3 -0
  62. package/script/mod.d.ts.map +1 -1
  63. package/script/mod.js +3 -1
  64. package/script/src/base.d.ts +1 -47
  65. package/script/src/base.d.ts.map +1 -1
  66. package/script/src/base.js +2 -10
  67. package/script/src/clients/event.d.ts +6 -4
  68. package/script/src/clients/event.d.ts.map +1 -1
  69. package/script/src/clients/event.js +58 -77
  70. package/script/src/clients/public.d.ts +26 -5
  71. package/script/src/clients/public.d.ts.map +1 -1
  72. package/script/src/clients/public.js +29 -41
  73. package/script/src/clients/wallet.d.ts +200 -26
  74. package/script/src/clients/wallet.d.ts.map +1 -1
  75. package/script/src/clients/wallet.js +305 -283
  76. package/script/src/signing.d.ts +80 -5
  77. package/script/src/signing.d.ts.map +1 -1
  78. package/script/src/signing.js +148 -58
  79. package/script/src/transports/base.d.ts +49 -0
  80. package/script/src/transports/base.d.ts.map +1 -0
  81. package/script/src/transports/base.js +22 -0
  82. package/script/src/transports/http/http_transport.d.ts +8 -5
  83. package/script/src/transports/http/http_transport.d.ts.map +1 -1
  84. package/script/src/transports/http/http_transport.js +16 -63
  85. package/script/src/transports/websocket/_hyperliquid_event_target.d.ts +36 -39
  86. package/script/src/transports/websocket/_hyperliquid_event_target.d.ts.map +1 -1
  87. package/script/src/transports/websocket/_reconnecting_websocket.d.ts +18 -25
  88. package/script/src/transports/websocket/_reconnecting_websocket.d.ts.map +1 -1
  89. package/script/src/transports/websocket/_reconnecting_websocket.js +81 -180
  90. package/{esm/src/transports/websocket/_websocket_request_dispatcher.d.ts → script/src/transports/websocket/_websocket_async_request.d.ts} +14 -18
  91. package/script/src/transports/websocket/_websocket_async_request.d.ts.map +1 -0
  92. package/script/src/transports/websocket/{_websocket_request_dispatcher.js → _websocket_async_request.js} +45 -78
  93. package/script/src/transports/websocket/websocket_transport.d.ts +38 -28
  94. package/script/src/transports/websocket/websocket_transport.d.ts.map +1 -1
  95. package/script/src/transports/websocket/websocket_transport.js +63 -78
  96. package/script/src/types/exchange/requests.d.ts +278 -66
  97. package/script/src/types/exchange/requests.d.ts.map +1 -1
  98. package/script/src/types/info/assets.d.ts +0 -48
  99. package/script/src/types/info/assets.d.ts.map +1 -1
  100. package/script/src/types/info/markets.d.ts +52 -0
  101. package/script/src/types/info/markets.d.ts.map +1 -0
  102. package/script/{deps/jsr.io/@noble/hashes/1.8.0/src/crypto.js → src/types/info/markets.js} +0 -2
  103. package/script/src/types/info/orders.d.ts +1 -1
  104. package/script/src/types/info/orders.d.ts.map +1 -1
  105. package/script/src/types/info/requests.d.ts +14 -5
  106. package/script/src/types/info/requests.d.ts.map +1 -1
  107. package/script/src/types/mod.d.ts +4 -0
  108. package/script/src/types/mod.d.ts.map +1 -1
  109. package/script/src/types/mod.js +25 -22
  110. package/script/src/types/subscriptions/requests.d.ts +2 -0
  111. package/script/src/types/subscriptions/requests.d.ts.map +1 -1
  112. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/_u64.d.ts +0 -55
  113. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/_u64.d.ts.map +0 -1
  114. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/_u64.js +0 -66
  115. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/crypto.d.ts +0 -2
  116. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/crypto.d.ts.map +0 -1
  117. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/crypto.js +0 -1
  118. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/sha3.d.ts +0 -53
  119. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/sha3.d.ts.map +0 -1
  120. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/sha3.js +0 -294
  121. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/utils.d.ts +0 -161
  122. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/utils.d.ts.map +0 -1
  123. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/utils.js +0 -280
  124. package/esm/src/transports/websocket/_websocket_request_dispatcher.d.ts.map +0 -1
  125. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/_u64.d.ts +0 -55
  126. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/_u64.d.ts.map +0 -1
  127. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/_u64.js +0 -99
  128. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/crypto.d.ts +0 -2
  129. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/crypto.d.ts.map +0 -1
  130. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/sha3.d.ts +0 -53
  131. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/sha3.d.ts.map +0 -1
  132. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/sha3.js +0 -309
  133. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/utils.d.ts +0 -161
  134. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/utils.d.ts.map +0 -1
  135. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/utils.js +0 -322
  136. package/script/src/transports/websocket/_websocket_request_dispatcher.d.ts.map +0 -1
@@ -1,7 +1,8 @@
1
1
  import { HyperliquidError } from "../base.js";
2
- import { isAbstractEthersSigner, isAbstractEthersV5Signer, isAbstractViemWalletClient, isAbstractWindowEthereum, signL1Action, signUserSignedAction, } from "../signing.js";
2
+ import { isAbstractEthersSigner, isAbstractEthersV5Signer, isAbstractExtendedViemWalletClient, isAbstractViemWalletClient, isAbstractWindowEthereum, signL1Action, signMultiSigAction, signUserSignedAction, } from "../signing.js";
3
3
  /** Error thrown when the API returns an error response. */
4
4
  export class ApiRequestError extends HyperliquidError {
5
+ response;
5
6
  constructor(response) {
6
7
  let message = "Cannot process API request";
7
8
  if (response.status === "err") {
@@ -29,26 +30,14 @@ export class ApiRequestError extends HyperliquidError {
29
30
  }
30
31
  }
31
32
  super(message);
32
- Object.defineProperty(this, "response", {
33
- enumerable: true,
34
- configurable: true,
35
- writable: true,
36
- value: response
37
- });
33
+ this.response = response;
38
34
  this.name = "ApiRequestError";
39
35
  }
40
36
  }
41
37
  /** Nonce manager for generating unique nonces for signing transactions. */
42
38
  class NonceManager {
43
- constructor() {
44
- /** The last nonce used for signing transactions. */
45
- Object.defineProperty(this, "lastNonce", {
46
- enumerable: true,
47
- configurable: true,
48
- writable: true,
49
- value: 0
50
- });
51
- }
39
+ /** The last nonce used for signing transactions. */
40
+ lastNonce = 0;
52
41
  /**
53
42
  * Gets the next nonce for signing transactions.
54
43
  * @returns The next nonce.
@@ -70,6 +59,13 @@ class NonceManager {
70
59
  * @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.
71
60
  */
72
61
  export class WalletClient {
62
+ transport;
63
+ wallet;
64
+ isTestnet;
65
+ defaultVaultAddress;
66
+ defaultExpiresAfter;
67
+ signatureChainId;
68
+ nonceManager;
73
69
  /**
74
70
  * Initialises a new instance.
75
71
  * @param args - The parameters for the client.
@@ -117,58 +113,6 @@ export class WalletClient {
117
113
  * ```
118
114
  */
119
115
  constructor(args) {
120
- /** The transport used to connect to the Hyperliquid API. */
121
- Object.defineProperty(this, "transport", {
122
- enumerable: true,
123
- configurable: true,
124
- writable: true,
125
- value: void 0
126
- });
127
- /** The `viem`, `ethers.js`, or `window.ethereum` wallet used for signing transactions. */
128
- Object.defineProperty(this, "wallet", {
129
- enumerable: true,
130
- configurable: true,
131
- writable: true,
132
- value: void 0
133
- });
134
- /** Specifies whether the client uses testnet. */
135
- Object.defineProperty(this, "isTestnet", {
136
- enumerable: true,
137
- configurable: true,
138
- writable: true,
139
- value: void 0
140
- });
141
- /** Sets a default vaultAddress to be used if no vaultAddress is explicitly passed to a method. */
142
- Object.defineProperty(this, "defaultVaultAddress", {
143
- enumerable: true,
144
- configurable: true,
145
- writable: true,
146
- value: void 0
147
- });
148
- /** Sets a default expiresAfter to be used if no expiresAfter is explicitly passed to a method. */
149
- Object.defineProperty(this, "defaultExpiresAfter", {
150
- enumerable: true,
151
- configurable: true,
152
- writable: true,
153
- value: void 0
154
- });
155
- /**
156
- * The network that will be used to sign transactions.
157
- * Must match the network of the {@link wallet}.
158
- */
159
- Object.defineProperty(this, "signatureChainId", {
160
- enumerable: true,
161
- configurable: true,
162
- writable: true,
163
- value: void 0
164
- });
165
- /** Function to get the next nonce for signing transactions. */
166
- Object.defineProperty(this, "nonceManager", {
167
- enumerable: true,
168
- configurable: true,
169
- writable: true,
170
- value: void 0
171
- });
172
116
  this.transport = args.transport;
173
117
  this.wallet = args.wallet;
174
118
  this.isTestnet = args.isTestnet ?? false;
@@ -224,11 +168,7 @@ export class WalletClient {
224
168
  if (action.agentName === "")
225
169
  delete action.agentName;
226
170
  // Send a request
227
- const request = { action, signature, nonce: action.nonce };
228
- const response = await this.transport.request("exchange", request, signal);
229
- // Validate a response
230
- this._validateResponse(response);
231
- return response;
171
+ return await this._request({ action, signature, nonce: action.nonce }, signal);
232
172
  }
233
173
  /**
234
174
  * Approve a maximum fee rate for a builder.
@@ -274,11 +214,7 @@ export class WalletClient {
274
214
  chainId: parseInt(action.signatureChainId, 16),
275
215
  });
276
216
  // Send a request
277
- const request = { action, signature, nonce: action.nonce };
278
- const response = await this.transport.request("exchange", request, signal);
279
- // Validate a response
280
- this._validateResponse(response);
281
- return response;
217
+ return await this._request({ action, signature, nonce: action.nonce }, signal);
282
218
  }
283
219
  /**
284
220
  * Modify multiple orders.
@@ -364,11 +300,7 @@ export class WalletClient {
364
300
  expiresAfter,
365
301
  });
366
302
  // Send a request
367
- const request = { action, signature, nonce, vaultAddress, expiresAfter };
368
- const response = await this.transport.request("exchange", request, signal);
369
- // Validate a response
370
- this._validateResponse(response);
371
- return response;
303
+ return await this._request({ action, signature, nonce, vaultAddress, expiresAfter }, signal);
372
304
  }
373
305
  /**
374
306
  * Cancel order(s).
@@ -417,11 +349,7 @@ export class WalletClient {
417
349
  expiresAfter,
418
350
  });
419
351
  // Send a request
420
- const request = { action, signature, nonce, vaultAddress, expiresAfter };
421
- const response = await this.transport.request("exchange", request, signal);
422
- // Validate a response
423
- this._validateResponse(response);
424
- return response;
352
+ return await this._request({ action, signature, nonce, vaultAddress, expiresAfter }, signal);
425
353
  }
426
354
  /**
427
355
  * Cancel order(s) by cloid.
@@ -469,11 +397,7 @@ export class WalletClient {
469
397
  expiresAfter,
470
398
  });
471
399
  // Send a request
472
- const request = { action, signature, nonce, vaultAddress, expiresAfter };
473
- const response = await this.transport.request("exchange", request, signal);
474
- // Validate a response
475
- this._validateResponse(response);
476
- return response;
400
+ return await this._request({ action, signature, nonce, vaultAddress, expiresAfter }, signal);
477
401
  }
478
402
  /**
479
403
  * Transfer native token from the user's spot account into staking for delegating to validators.
@@ -518,11 +442,7 @@ export class WalletClient {
518
442
  chainId: parseInt(action.signatureChainId, 16),
519
443
  });
520
444
  // Send a request
521
- const request = { action, signature, nonce: action.nonce };
522
- const response = await this.transport.request("exchange", request, signal);
523
- // Validate a response
524
- this._validateResponse(response);
525
- return response;
445
+ return await this._request({ action, signature, nonce: action.nonce }, signal);
526
446
  }
527
447
  /**
528
448
  * Claim rewards from referral program.
@@ -556,11 +476,55 @@ export class WalletClient {
556
476
  isTestnet: this.isTestnet,
557
477
  });
558
478
  // Send a request
559
- const request = { action, signature, nonce };
560
- const response = await this.transport.request("exchange", request, signal);
561
- // Validate a response
562
- this._validateResponse(response);
563
- return response;
479
+ return await this._request({ action, signature, nonce }, signal);
480
+ }
481
+ /**
482
+ * Convert a single-signature account to a multi-signature account.
483
+ * @param args - The parameters for the request.
484
+ * @param signal - An optional abort signal.
485
+ * @returns Successful response without specific data.
486
+ * @throws {ApiRequestError} When the API returns an error response.
487
+ *
488
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/hypercore/multi-sig
489
+ * @example
490
+ * ```ts
491
+ * import * as hl from "@nktkas/hyperliquid";
492
+ * import { privateKeyToAccount } from "viem/accounts";
493
+ *
494
+ * const wallet = privateKeyToAccount("0x...");
495
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
496
+ * const client = new hl.WalletClient({ wallet, transport });
497
+ *
498
+ * const result = await client.convertToMultiSigUser({
499
+ * authorizedUsers: ["0x...", "0x..."],
500
+ * threshold: 2,
501
+ * });
502
+ * ```
503
+ */
504
+ async convertToMultiSigUser(args, signal) {
505
+ // Construct an action
506
+ const action = {
507
+ type: "convertToMultiSigUser",
508
+ hyperliquidChain: this._getHyperliquidChain(),
509
+ signatureChainId: await this._getSignatureChainId(),
510
+ signers: JSON.stringify(args),
511
+ nonce: await this.nonceManager(),
512
+ };
513
+ // Sign the action
514
+ const signature = await signUserSignedAction({
515
+ wallet: this.wallet,
516
+ action,
517
+ types: {
518
+ "HyperliquidTransaction:ConvertToMultiSigUser": [
519
+ { name: "hyperliquidChain", type: "string" },
520
+ { name: "signers", type: "string" },
521
+ { name: "nonce", type: "uint64" },
522
+ ],
523
+ },
524
+ chainId: parseInt(action.signatureChainId, 16),
525
+ });
526
+ // Send a request
527
+ return await this._request({ action, signature, nonce: action.nonce }, signal);
564
528
  }
565
529
  /**
566
530
  * Create a sub-account.
@@ -597,11 +561,7 @@ export class WalletClient {
597
561
  isTestnet: this.isTestnet,
598
562
  });
599
563
  // Send a request
600
- const request = { action, signature, nonce };
601
- const response = await this.transport.request("exchange", request, signal);
602
- // Validate a response
603
- this._validateResponse(response);
604
- return response;
564
+ return await this._request({ action, signature, nonce }, signal);
605
565
  }
606
566
  /**
607
567
  * Create a vault.
@@ -645,11 +605,81 @@ export class WalletClient {
645
605
  isTestnet: this.isTestnet,
646
606
  });
647
607
  // Send a request
648
- const request = { action, signature, nonce };
649
- const response = await this.transport.request("exchange", request, signal);
650
- // Validate a response
651
- this._validateResponse(response);
652
- return response;
608
+ return await this._request({ action, signature, nonce }, signal);
609
+ }
610
+ async cSignerAction(args, signal) {
611
+ // Destructure the parameters
612
+ const { expiresAfter = await this._getDefaultExpiresAfter(), ...actionArgs } = args;
613
+ // Construct an action
614
+ const nonce = await this.nonceManager();
615
+ const action = {
616
+ type: "CSignerAction",
617
+ ...actionArgs,
618
+ };
619
+ // Sign the action
620
+ const signature = await signL1Action({
621
+ wallet: this.wallet,
622
+ action,
623
+ nonce,
624
+ isTestnet: this.isTestnet,
625
+ expiresAfter,
626
+ });
627
+ // Send a request
628
+ return await this._request({ action, signature, nonce, expiresAfter }, signal);
629
+ }
630
+ async cValidatorAction(args, signal) {
631
+ // Destructure the parameters
632
+ const { expiresAfter = await this._getDefaultExpiresAfter(), ...actionArgs } = args;
633
+ // Construct an action
634
+ const nonce = await this.nonceManager();
635
+ let action;
636
+ if ("changeProfile" in actionArgs) {
637
+ action = {
638
+ type: "CValidatorAction",
639
+ changeProfile: {
640
+ node_ip: actionArgs.changeProfile.node_ip ?? null,
641
+ name: actionArgs.changeProfile.name ?? null,
642
+ description: actionArgs.changeProfile.description ?? null,
643
+ unjailed: actionArgs.changeProfile.unjailed,
644
+ disable_delegations: actionArgs.changeProfile.disable_delegations ?? null,
645
+ commission_bps: actionArgs.changeProfile.commission_bps ?? null,
646
+ signer: actionArgs.changeProfile.signer?.toLowerCase() ?? null,
647
+ },
648
+ };
649
+ }
650
+ else if ("register" in actionArgs) {
651
+ action = {
652
+ type: "CValidatorAction",
653
+ register: {
654
+ profile: {
655
+ node_ip: { Ip: actionArgs.register.profile.node_ip.Ip },
656
+ name: actionArgs.register.profile.name,
657
+ description: actionArgs.register.profile.description,
658
+ delegations_disabled: actionArgs.register.profile.delegations_disabled,
659
+ commission_bps: actionArgs.register.profile.commission_bps,
660
+ signer: actionArgs.register.profile.signer?.toLowerCase(),
661
+ },
662
+ unjailed: actionArgs.register.unjailed,
663
+ initial_wei: actionArgs.register.initial_wei,
664
+ },
665
+ };
666
+ }
667
+ else {
668
+ action = {
669
+ type: "CValidatorAction",
670
+ unregister: actionArgs.unregister,
671
+ };
672
+ }
673
+ // Sign the action
674
+ const signature = await signL1Action({
675
+ wallet: this.wallet,
676
+ action,
677
+ nonce,
678
+ isTestnet: this.isTestnet,
679
+ expiresAfter,
680
+ });
681
+ // Send a request
682
+ return await this._request({ action, signature, nonce, expiresAfter }, signal);
653
683
  }
654
684
  /**
655
685
  * Transfer native token from staking into the user's spot account.
@@ -694,11 +724,7 @@ export class WalletClient {
694
724
  chainId: parseInt(action.signatureChainId, 16),
695
725
  });
696
726
  // Send a request
697
- const request = { action, signature, nonce: action.nonce };
698
- const response = await this.transport.request("exchange", request, signal);
699
- // Validate a response
700
- this._validateResponse(response);
701
- return response;
727
+ return await this._request({ action, signature, nonce: action.nonce }, signal);
702
728
  }
703
729
  /**
704
730
  * Configure block type for EVM transactions.
@@ -735,11 +761,7 @@ export class WalletClient {
735
761
  isTestnet: this.isTestnet,
736
762
  });
737
763
  // Send a request
738
- const request = { action, signature, nonce };
739
- const response = await this.transport.request("exchange", request, signal);
740
- // Validate a response
741
- this._validateResponse(response);
742
- return response;
764
+ return await this._request({ action, signature, nonce }, signal);
743
765
  }
744
766
  /**
745
767
  * Modify an order.
@@ -818,11 +840,82 @@ export class WalletClient {
818
840
  expiresAfter,
819
841
  });
820
842
  // Send a request
821
- const request = { action, signature, nonce, vaultAddress, expiresAfter };
822
- const response = await this.transport.request("exchange", request, signal);
823
- // Validate a response
824
- this._validateResponse(response);
825
- return response;
843
+ return await this._request({ action, signature, nonce, vaultAddress, expiresAfter }, signal);
844
+ }
845
+ /**
846
+ * A multi-signature request.
847
+ * @param args - The parameters for the request.
848
+ * @param signal - An optional abort signal.
849
+ * @returns Successful response without specific data.
850
+ * @throws {ApiRequestError} When the API returns an error response.
851
+ *
852
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/hypercore/multi-sig
853
+ * @example
854
+ * ```ts
855
+ * import * as hl from "@nktkas/hyperliquid";
856
+ * import { privateKeyToAccount } from "viem/accounts";
857
+ *
858
+ * const wallet = privateKeyToAccount("0x...");
859
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
860
+ * const client = new hl.WalletClient({ wallet, transport });
861
+ *
862
+ * const multiSigUser = "0x..."; // Multi-sig user address
863
+ *
864
+ * const nonce = Date.now();
865
+ * const action = { type: "scheduleCancel", time: Date.now() + 10000 };
866
+ *
867
+ * const signature = await hl.signL1Action({
868
+ * wallet,
869
+ * action: [multiSigUser.toLowerCase(), signer1.address.toLowerCase(), action],
870
+ * nonce,
871
+ * isTestnet: true,
872
+ * });
873
+ *
874
+ * const result = await client.multiSig({
875
+ * signatures: [signature],
876
+ * payload: {
877
+ * multiSigUser,
878
+ * outerSigner: wallet.address,
879
+ * action,
880
+ * },
881
+ * nonce,
882
+ * });
883
+ * ```
884
+ * @unstable May not behave as expected and the interface may change in the future.
885
+ */
886
+ async multiSig(args, signal) {
887
+ // Destructure the parameters
888
+ const { vaultAddress = this.defaultVaultAddress, expiresAfter = await this._getDefaultExpiresAfter(), nonce, ...actionArgs } = args;
889
+ // Construct an action
890
+ const hyperliquidChain = this._getHyperliquidChain();
891
+ const action = {
892
+ type: "multiSig",
893
+ signatureChainId: await this._getSignatureChainId(),
894
+ signatures: actionArgs.signatures.map((signature) => ({
895
+ r: signature.r.replace(/^0x0+/, "0x").toLowerCase(),
896
+ s: signature.s.replace(/^0x0+/, "0x").toLowerCase(),
897
+ v: signature.v,
898
+ })),
899
+ payload: {
900
+ multiSigUser: actionArgs.payload.multiSigUser.toLowerCase(),
901
+ outerSigner: actionArgs.payload.outerSigner.toLowerCase(),
902
+ action: actionArgs.payload.action,
903
+ },
904
+ };
905
+ // Sign the action
906
+ const actionForMultiSig = structuredClone(action);
907
+ delete actionForMultiSig.type;
908
+ const signature = await signMultiSigAction({
909
+ wallet: this.wallet,
910
+ action: actionForMultiSig,
911
+ nonce,
912
+ vaultAddress,
913
+ expiresAfter,
914
+ hyperliquidChain,
915
+ signatureChainId: action.signatureChainId,
916
+ });
917
+ // Send a request
918
+ return await this._request({ action, signature, nonce, vaultAddress, expiresAfter }, signal);
826
919
  }
827
920
  /**
828
921
  * Place an order(s).
@@ -912,22 +1005,8 @@ export class WalletClient {
912
1005
  expiresAfter,
913
1006
  });
914
1007
  // Send a request
915
- const request = { action, signature, nonce, vaultAddress, expiresAfter };
916
- const response = await this.transport.request("exchange", request, signal);
917
- // Validate a response
918
- this._validateResponse(response);
919
- return response;
1008
+ return await this._request({ action, signature, nonce, vaultAddress, expiresAfter }, signal);
920
1009
  }
921
- /**
922
- * Deploying HIP-3 assets.
923
- * @param args - The parameters for the request.
924
- * @param signal - An optional abort signal.
925
- * @returns Successful response without specific data.
926
- * @throws {ApiRequestError} When the API returns an error response.
927
- *
928
- * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/deploying-hip-3-assets
929
- * @untested
930
- */
931
1010
  async perpDeploy(args, signal) {
932
1011
  // Construct an action
933
1012
  const nonce = await this.nonceManager();
@@ -974,11 +1053,60 @@ export class WalletClient {
974
1053
  isTestnet: this.isTestnet,
975
1054
  });
976
1055
  // Send a request
977
- const request = { action, signature, nonce };
978
- const response = await this.transport.request("exchange", request, signal);
979
- // Validate a response
980
- this._validateResponse(response);
981
- return response;
1056
+ return await this._request({ action, signature, nonce }, signal);
1057
+ }
1058
+ /**
1059
+ * Transfer funds between Spot account and Perp dex account.
1060
+ * @param args - The parameters for the request.
1061
+ * @param signal - An optional abort signal.
1062
+ * @returns Successful response without specific data.
1063
+ * @throws {ApiRequestError} When the API returns an error response.
1064
+ *
1065
+ * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#transfer-from-spot-account-to-perp-account-and-vice-versa
1066
+ * @example
1067
+ * ```ts
1068
+ * import * as hl from "@nktkas/hyperliquid";
1069
+ * import { privateKeyToAccount } from "viem/accounts";
1070
+ *
1071
+ * const wallet = privateKeyToAccount("0x...");
1072
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
1073
+ * const client = new hl.WalletClient({ wallet, transport });
1074
+ *
1075
+ * const result = await client.perpDexClassTransfer({
1076
+ * dex: "test",
1077
+ * token: "USDC",
1078
+ * amount: "1",
1079
+ * toPerp: true,
1080
+ * });
1081
+ * ```
1082
+ */
1083
+ async perpDexClassTransfer(args, signal) {
1084
+ // Construct an action
1085
+ const action = {
1086
+ ...args,
1087
+ type: "PerpDexClassTransfer",
1088
+ hyperliquidChain: this._getHyperliquidChain(),
1089
+ signatureChainId: await this._getSignatureChainId(),
1090
+ nonce: await this.nonceManager(),
1091
+ };
1092
+ // Sign the action
1093
+ const signature = await signUserSignedAction({
1094
+ wallet: this.wallet,
1095
+ action,
1096
+ types: {
1097
+ "HyperliquidTransaction:PerpDexClassTransfer": [
1098
+ { name: "hyperliquidChain", type: "string" },
1099
+ { name: "dex", type: "string" },
1100
+ { name: "token", type: "string" },
1101
+ { name: "amount", type: "string" },
1102
+ { name: "toPerp", type: "bool" },
1103
+ { name: "nonce", type: "uint64" },
1104
+ ],
1105
+ },
1106
+ chainId: parseInt(action.signatureChainId, 16),
1107
+ });
1108
+ // Send a request
1109
+ return await this._request({ action, signature, nonce: action.nonce }, signal);
982
1110
  }
983
1111
  /**
984
1112
  * Create a referral code.
@@ -1015,11 +1143,7 @@ export class WalletClient {
1015
1143
  isTestnet: this.isTestnet,
1016
1144
  });
1017
1145
  // Send a request
1018
- const request = { action, signature, nonce };
1019
- const response = await this.transport.request("exchange", request, signal);
1020
- // Validate a response
1021
- this._validateResponse(response);
1022
- return response;
1146
+ return await this._request({ action, signature, nonce }, signal);
1023
1147
  }
1024
1148
  /**
1025
1149
  * Reserve additional rate-limited actions for a fee.
@@ -1059,33 +1183,11 @@ export class WalletClient {
1059
1183
  expiresAfter,
1060
1184
  });
1061
1185
  // Send a request
1062
- const request = { action, signature, nonce, expiresAfter };
1063
- const response = await this.transport.request("exchange", request, signal);
1064
- // Validate a response
1065
- this._validateResponse(response);
1066
- return response;
1186
+ return await this._request({ action, signature, nonce, expiresAfter }, signal);
1067
1187
  }
1068
- /**
1069
- * Schedule a cancel-all operation at a future time.
1070
- * @param args - The parameters for the request.
1071
- * @param signal - An optional abort signal.
1072
- * @returns Successful response without specific data.
1073
- * @throws {ApiRequestError} When the API returns an error response.
1074
- *
1075
- * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#schedule-cancel-dead-mans-switch
1076
- * @example
1077
- * ```ts
1078
- * import * as hl from "@nktkas/hyperliquid";
1079
- * import { privateKeyToAccount } from "viem/accounts";
1080
- *
1081
- * const wallet = privateKeyToAccount("0x...");
1082
- * const transport = new hl.HttpTransport(); // or WebSocketTransport
1083
- * const client = new hl.WalletClient({ wallet, transport });
1084
- *
1085
- * const result = await client.scheduleCancel({ time: Date.now() + 3600000 });
1086
- * ```
1087
- */
1088
- async scheduleCancel(args = {}, signal) {
1188
+ async scheduleCancel(args_or_signal, maybeSignal) {
1189
+ const args = args_or_signal instanceof AbortSignal ? {} : args_or_signal ?? {};
1190
+ const signal = args_or_signal instanceof AbortSignal ? args_or_signal : maybeSignal;
1089
1191
  // Destructure the parameters
1090
1192
  const { vaultAddress = this.defaultVaultAddress, expiresAfter = await this._getDefaultExpiresAfter(), ...actionArgs } = args;
1091
1193
  // Construct an action
@@ -1106,11 +1208,7 @@ export class WalletClient {
1106
1208
  expiresAfter,
1107
1209
  });
1108
1210
  // Send a request
1109
- const request = { action, signature, nonce, vaultAddress, expiresAfter };
1110
- const response = await this.transport.request("exchange", request, signal);
1111
- // Validate a response
1112
- this._validateResponse(response);
1113
- return response;
1211
+ return await this._request({ action, signature, nonce, vaultAddress, expiresAfter }, signal);
1114
1212
  }
1115
1213
  /**
1116
1214
  * Set the display name in the leaderboard.
@@ -1147,11 +1245,7 @@ export class WalletClient {
1147
1245
  isTestnet: this.isTestnet,
1148
1246
  });
1149
1247
  // Send a request
1150
- const request = { action, signature, nonce };
1151
- const response = await this.transport.request("exchange", request, signal);
1152
- // Validate a response
1153
- this._validateResponse(response);
1154
- return response;
1248
+ return await this._request({ action, signature, nonce }, signal);
1155
1249
  }
1156
1250
  /**
1157
1251
  * Set a referral code.
@@ -1188,22 +1282,8 @@ export class WalletClient {
1188
1282
  isTestnet: this.isTestnet,
1189
1283
  });
1190
1284
  // Send a request
1191
- const request = { action, signature, nonce };
1192
- const response = await this.transport.request("exchange", request, signal);
1193
- // Validate a response
1194
- this._validateResponse(response);
1195
- return response;
1285
+ return await this._request({ action, signature, nonce }, signal);
1196
1286
  }
1197
- /**
1198
- * Deploying HIP-1 and HIP-2 assets.
1199
- * @param args - The parameters for the request.
1200
- * @param signal - An optional abort signal.
1201
- * @returns Successful response without specific data.
1202
- * @throws {ApiRequestError} When the API returns an error response.
1203
- *
1204
- * @see https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/deploying-hip-1-and-hip-2-assets
1205
- * @untested
1206
- */
1207
1287
  async spotDeploy(args, signal) {
1208
1288
  // Construct an action
1209
1289
  const nonce = await this.nonceManager();
@@ -1292,11 +1372,7 @@ export class WalletClient {
1292
1372
  isTestnet: this.isTestnet,
1293
1373
  });
1294
1374
  // Send a request
1295
- const request = { action, signature, nonce };
1296
- const response = await this.transport.request("exchange", request, signal);
1297
- // Validate a response
1298
- this._validateResponse(response);
1299
- return response;
1375
+ return await this._request({ action, signature, nonce }, signal);
1300
1376
  }
1301
1377
  /**
1302
1378
  * Send spot assets to another address.
@@ -1347,11 +1423,7 @@ export class WalletClient {
1347
1423
  chainId: parseInt(action.signatureChainId, 16),
1348
1424
  });
1349
1425
  // Send a request
1350
- const request = { action, signature, nonce: action.time };
1351
- const response = await this.transport.request("exchange", request, signal);
1352
- // Validate a response
1353
- this._validateResponse(response);
1354
- return response;
1426
+ return await this._request({ action, signature, nonce: action.time }, signal);
1355
1427
  }
1356
1428
  /**
1357
1429
  * Opt Out of Spot Dusting.
@@ -1390,11 +1462,7 @@ export class WalletClient {
1390
1462
  isTestnet: this.isTestnet,
1391
1463
  });
1392
1464
  // Send a request
1393
- const request = { action, signature, nonce };
1394
- const response = await this.transport.request("exchange", request, signal);
1395
- // Validate a response
1396
- this._validateResponse(response);
1397
- return response;
1465
+ return await this._request({ action, signature, nonce }, signal);
1398
1466
  }
1399
1467
  /**
1400
1468
  * Transfer between sub-accounts (spot).
@@ -1439,11 +1507,7 @@ export class WalletClient {
1439
1507
  isTestnet: this.isTestnet,
1440
1508
  });
1441
1509
  // Send a request
1442
- const request = { action, signature, nonce };
1443
- const response = await this.transport.request("exchange", request, signal);
1444
- // Validate a response
1445
- this._validateResponse(response);
1446
- return response;
1510
+ return await this._request({ action, signature, nonce }, signal);
1447
1511
  }
1448
1512
  /**
1449
1513
  * Transfer between sub-accounts (perpetual).
@@ -1486,11 +1550,7 @@ export class WalletClient {
1486
1550
  isTestnet: this.isTestnet,
1487
1551
  });
1488
1552
  // Send a request
1489
- const request = { action, signature, nonce };
1490
- const response = await this.transport.request("exchange", request, signal);
1491
- // Validate a response
1492
- this._validateResponse(response);
1493
- return response;
1553
+ return await this._request({ action, signature, nonce }, signal);
1494
1554
  }
1495
1555
  /**
1496
1556
  * Delegate or undelegate native tokens to or from a validator.
@@ -1541,11 +1601,7 @@ export class WalletClient {
1541
1601
  chainId: parseInt(action.signatureChainId, 16),
1542
1602
  });
1543
1603
  // Send a request
1544
- const request = { action, signature, nonce: action.nonce };
1545
- const response = await this.transport.request("exchange", request, signal);
1546
- // Validate a response
1547
- this._validateResponse(response);
1548
- return response;
1604
+ return await this._request({ action, signature, nonce: action.nonce }, signal);
1549
1605
  }
1550
1606
  /**
1551
1607
  * Cancel a TWAP order.
@@ -1590,11 +1646,7 @@ export class WalletClient {
1590
1646
  expiresAfter,
1591
1647
  });
1592
1648
  // Send a request
1593
- const request = { action, signature, nonce, vaultAddress, expiresAfter };
1594
- const response = await this.transport.request("exchange", request, signal);
1595
- // Validate a response
1596
- this._validateResponse(response);
1597
- return response;
1649
+ return await this._request({ action, signature, nonce, vaultAddress, expiresAfter }, signal);
1598
1650
  }
1599
1651
  /**
1600
1652
  * Place a TWAP order.
@@ -1649,11 +1701,7 @@ export class WalletClient {
1649
1701
  expiresAfter,
1650
1702
  });
1651
1703
  // Send a request
1652
- const request = { action, signature, nonce, vaultAddress, expiresAfter };
1653
- const response = await this.transport.request("exchange", request, signal);
1654
- // Validate a response
1655
- this._validateResponse(response);
1656
- return response;
1704
+ return await this._request({ action, signature, nonce, vaultAddress, expiresAfter }, signal);
1657
1705
  }
1658
1706
  /**
1659
1707
  * Add or remove margin from isolated position.
@@ -1696,11 +1744,7 @@ export class WalletClient {
1696
1744
  expiresAfter,
1697
1745
  });
1698
1746
  // Send a request
1699
- const request = { action, signature, nonce, vaultAddress, expiresAfter };
1700
- const response = await this.transport.request("exchange", request, signal);
1701
- // Validate a response
1702
- this._validateResponse(response);
1703
- return response;
1747
+ return await this._request({ action, signature, nonce, vaultAddress, expiresAfter }, signal);
1704
1748
  }
1705
1749
  /**
1706
1750
  * Update cross or isolated leverage on a coin.
@@ -1743,14 +1787,10 @@ export class WalletClient {
1743
1787
  expiresAfter,
1744
1788
  });
1745
1789
  // Send a request
1746
- const request = { action, signature, nonce, vaultAddress, expiresAfter };
1747
- const response = await this.transport.request("exchange", request, signal);
1748
- // Validate a response
1749
- this._validateResponse(response);
1750
- return response;
1790
+ return await this._request({ action, signature, nonce, vaultAddress, expiresAfter }, signal);
1751
1791
  }
1752
1792
  /**
1753
- * Transfer funds between Spot and Perp accounts.
1793
+ * Transfer funds between Spot account and Perp account.
1754
1794
  * @param args - The parameters for the request.
1755
1795
  * @param signal - An optional abort signal.
1756
1796
  * @returns Successful response without specific data.
@@ -1793,11 +1833,7 @@ export class WalletClient {
1793
1833
  chainId: parseInt(action.signatureChainId, 16),
1794
1834
  });
1795
1835
  // Send a request
1796
- const request = { action, signature, nonce: action.nonce };
1797
- const response = await this.transport.request("exchange", request, signal);
1798
- // Validate a response
1799
- this._validateResponse(response);
1800
- return response;
1836
+ return await this._request({ action, signature, nonce: action.nonce }, signal);
1801
1837
  }
1802
1838
  /**
1803
1839
  * Send usd to another address.
@@ -1843,11 +1879,7 @@ export class WalletClient {
1843
1879
  chainId: parseInt(action.signatureChainId, 16),
1844
1880
  });
1845
1881
  // Send a request
1846
- const request = { action, signature, nonce: action.time };
1847
- const response = await this.transport.request("exchange", request, signal);
1848
- // Validate a response
1849
- this._validateResponse(response);
1850
- return response;
1882
+ return await this._request({ action, signature, nonce: action.time }, signal);
1851
1883
  }
1852
1884
  /**
1853
1885
  * Distribute funds from a vault between followers.
@@ -1885,11 +1917,7 @@ export class WalletClient {
1885
1917
  isTestnet: this.isTestnet,
1886
1918
  });
1887
1919
  // Send a request
1888
- const request = { action, signature, nonce };
1889
- const response = await this.transport.request("exchange", request, signal);
1890
- // Validate a response
1891
- this._validateResponse(response);
1892
- return response;
1920
+ return await this._request({ action, signature, nonce }, signal);
1893
1921
  }
1894
1922
  /**
1895
1923
  * Modify a vault's configuration.
@@ -1932,11 +1960,7 @@ export class WalletClient {
1932
1960
  isTestnet: this.isTestnet,
1933
1961
  });
1934
1962
  // Send a request
1935
- const request = { action, signature, nonce };
1936
- const response = await this.transport.request("exchange", request, signal);
1937
- // Validate a response
1938
- this._validateResponse(response);
1939
- return response;
1963
+ return await this._request({ action, signature, nonce }, signal);
1940
1964
  }
1941
1965
  /**
1942
1966
  * Deposit or withdraw from a vault.
@@ -1982,11 +2006,7 @@ export class WalletClient {
1982
2006
  expiresAfter,
1983
2007
  });
1984
2008
  // Send a request
1985
- const request = { action, signature, nonce, expiresAfter };
1986
- const response = await this.transport.request("exchange", request, signal);
1987
- // Validate a response
1988
- this._validateResponse(response);
1989
- return response;
2009
+ return await this._request({ action, signature, nonce, expiresAfter }, signal);
1990
2010
  }
1991
2011
  /**
1992
2012
  * Initiate a withdrawal request.
@@ -2032,9 +2052,11 @@ export class WalletClient {
2032
2052
  chainId: parseInt(action.signatureChainId, 16),
2033
2053
  });
2034
2054
  // Send a request
2035
- const request = { action, signature, nonce: action.time };
2036
- const response = await this.transport.request("exchange", request, signal);
2037
- // Validate a response
2055
+ return await this._request({ action, signature, nonce: action.time }, signal);
2056
+ }
2057
+ /** Send an API request and validate the response. */
2058
+ async _request(payload, signal) {
2059
+ const response = await this.transport.request("exchange", payload, signal);
2038
2060
  this._validateResponse(response);
2039
2061
  return response;
2040
2062
  }
@@ -2049,7 +2071,7 @@ export class WalletClient {
2049
2071
  /** Guesses the chain ID based on the wallet type or the isTestnet flag. */
2050
2072
  async _guessSignatureChainId() {
2051
2073
  // Trying to get chain ID of the wallet
2052
- if (isAbstractViemWalletClient(this.wallet)) {
2074
+ if (isAbstractViemWalletClient(this.wallet) || isAbstractExtendedViemWalletClient(this.wallet)) {
2053
2075
  if ("getChainId" in this.wallet && typeof this.wallet.getChainId === "function") {
2054
2076
  const chainId = await this.wallet.getChainId();
2055
2077
  return `0x${chainId.toString(16)}`;