@nktkas/hyperliquid 0.13.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 (145) hide show
  1. package/CONTRIBUTING.md +59 -0
  2. package/LICENSE +21 -0
  3. package/README.md +363 -0
  4. package/SECURITY.md +7 -0
  5. package/esm/deps/jsr.io/@derzade/typescript-event-target/1.1.1/mod.d.ts +2 -0
  6. package/esm/deps/jsr.io/@derzade/typescript-event-target/1.1.1/mod.d.ts.map +1 -0
  7. package/esm/deps/jsr.io/@derzade/typescript-event-target/1.1.1/mod.js +1 -0
  8. package/esm/deps/jsr.io/@derzade/typescript-event-target/1.1.1/src/TypedEventTarget.d.ts +95 -0
  9. package/esm/deps/jsr.io/@derzade/typescript-event-target/1.1.1/src/TypedEventTarget.d.ts.map +1 -0
  10. package/esm/deps/jsr.io/@derzade/typescript-event-target/1.1.1/src/TypedEventTarget.js +10 -0
  11. package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/_assert.d.ts +23 -0
  12. package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/_assert.d.ts.map +1 -0
  13. package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/_assert.js +43 -0
  14. package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/_u64.d.ts +55 -0
  15. package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/_u64.d.ts.map +1 -0
  16. package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/_u64.js +65 -0
  17. package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/crypto.d.ts +2 -0
  18. package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/crypto.d.ts.map +1 -0
  19. package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/crypto.js +1 -0
  20. package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/sha3.d.ts +52 -0
  21. package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/sha3.d.ts.map +1 -0
  22. package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/sha3.js +283 -0
  23. package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/utils.d.ts +120 -0
  24. package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/utils.d.ts.map +1 -0
  25. package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/utils.js +211 -0
  26. package/esm/deps/jsr.io/@std/bytes/1.0.4/concat.d.ts +19 -0
  27. package/esm/deps/jsr.io/@std/bytes/1.0.4/concat.d.ts.map +1 -0
  28. package/esm/deps/jsr.io/@std/bytes/1.0.4/concat.js +32 -0
  29. package/esm/deps/jsr.io/@std/encoding/1.0.6/_validate_binary_like.d.ts +2 -0
  30. package/esm/deps/jsr.io/@std/encoding/1.0.6/_validate_binary_like.d.ts.map +1 -0
  31. package/esm/deps/jsr.io/@std/encoding/1.0.6/_validate_binary_like.js +26 -0
  32. package/esm/deps/jsr.io/@std/encoding/1.0.6/hex.d.ts +37 -0
  33. package/esm/deps/jsr.io/@std/encoding/1.0.6/hex.d.ts.map +1 -0
  34. package/esm/deps/jsr.io/@std/encoding/1.0.6/hex.js +109 -0
  35. package/esm/deps/jsr.io/@std/msgpack/1.0.2/encode.d.ts +37 -0
  36. package/esm/deps/jsr.io/@std/msgpack/1.0.2/encode.d.ts.map +1 -0
  37. package/esm/deps/jsr.io/@std/msgpack/1.0.2/encode.js +237 -0
  38. package/esm/mod.d.ts +24 -0
  39. package/esm/mod.d.ts.map +1 -0
  40. package/esm/mod.js +9 -0
  41. package/esm/package.json +3 -0
  42. package/esm/src/clients/event.d.ts +374 -0
  43. package/esm/src/clients/event.d.ts.map +1 -0
  44. package/esm/src/clients/event.js +490 -0
  45. package/esm/src/clients/public.d.ts +695 -0
  46. package/esm/src/clients/public.d.ts.map +1 -0
  47. package/esm/src/clients/public.js +704 -0
  48. package/esm/src/clients/wallet.d.ts +682 -0
  49. package/esm/src/clients/wallet.d.ts.map +1 -0
  50. package/esm/src/clients/wallet.js +984 -0
  51. package/esm/src/transports/base.d.ts +55 -0
  52. package/esm/src/transports/base.d.ts.map +1 -0
  53. package/esm/src/transports/base.js +14 -0
  54. package/esm/src/transports/http/http_transport.d.ts +78 -0
  55. package/esm/src/transports/http/http_transport.d.ts.map +1 -0
  56. package/esm/src/transports/http/http_transport.js +170 -0
  57. package/esm/src/transports/websocket/hyperliquid_event_target.d.ts +66 -0
  58. package/esm/src/transports/websocket/hyperliquid_event_target.d.ts.map +1 -0
  59. package/esm/src/transports/websocket/hyperliquid_event_target.js +33 -0
  60. package/esm/src/transports/websocket/reconnecting_websocket.d.ts +160 -0
  61. package/esm/src/transports/websocket/reconnecting_websocket.d.ts.map +1 -0
  62. package/esm/src/transports/websocket/reconnecting_websocket.js +370 -0
  63. package/esm/src/transports/websocket/websocket_request_dispatcher.d.ts +63 -0
  64. package/esm/src/transports/websocket/websocket_request_dispatcher.d.ts.map +1 -0
  65. package/esm/src/transports/websocket/websocket_request_dispatcher.js +201 -0
  66. package/esm/src/transports/websocket/websocket_transport.d.ts +117 -0
  67. package/esm/src/transports/websocket/websocket_transport.d.ts.map +1 -0
  68. package/esm/src/transports/websocket/websocket_transport.js +233 -0
  69. package/esm/src/utils/key_sort.d.ts +21 -0
  70. package/esm/src/utils/key_sort.d.ts.map +1 -0
  71. package/esm/src/utils/key_sort.js +124 -0
  72. package/esm/src/utils/signing.d.ts +109 -0
  73. package/esm/src/utils/signing.d.ts.map +1 -0
  74. package/esm/src/utils/signing.js +164 -0
  75. package/package.json +34 -0
  76. package/script/deps/jsr.io/@derzade/typescript-event-target/1.1.1/mod.d.ts +2 -0
  77. package/script/deps/jsr.io/@derzade/typescript-event-target/1.1.1/mod.d.ts.map +1 -0
  78. package/script/deps/jsr.io/@derzade/typescript-event-target/1.1.1/mod.js +17 -0
  79. package/script/deps/jsr.io/@derzade/typescript-event-target/1.1.1/src/TypedEventTarget.d.ts +95 -0
  80. package/script/deps/jsr.io/@derzade/typescript-event-target/1.1.1/src/TypedEventTarget.d.ts.map +1 -0
  81. package/script/deps/jsr.io/@derzade/typescript-event-target/1.1.1/src/TypedEventTarget.js +14 -0
  82. package/script/deps/jsr.io/@noble/hashes/1.7.1/src/_assert.d.ts +23 -0
  83. package/script/deps/jsr.io/@noble/hashes/1.7.1/src/_assert.d.ts.map +1 -0
  84. package/script/deps/jsr.io/@noble/hashes/1.7.1/src/_assert.js +49 -0
  85. package/script/deps/jsr.io/@noble/hashes/1.7.1/src/_u64.d.ts +55 -0
  86. package/script/deps/jsr.io/@noble/hashes/1.7.1/src/_u64.d.ts.map +1 -0
  87. package/script/deps/jsr.io/@noble/hashes/1.7.1/src/_u64.js +88 -0
  88. package/script/deps/jsr.io/@noble/hashes/1.7.1/src/crypto.d.ts +2 -0
  89. package/script/deps/jsr.io/@noble/hashes/1.7.1/src/crypto.d.ts.map +1 -0
  90. package/script/deps/jsr.io/@noble/hashes/1.7.1/src/crypto.js +4 -0
  91. package/script/deps/jsr.io/@noble/hashes/1.7.1/src/sha3.d.ts +52 -0
  92. package/script/deps/jsr.io/@noble/hashes/1.7.1/src/sha3.d.ts.map +1 -0
  93. package/script/deps/jsr.io/@noble/hashes/1.7.1/src/sha3.js +288 -0
  94. package/script/deps/jsr.io/@noble/hashes/1.7.1/src/utils.d.ts +120 -0
  95. package/script/deps/jsr.io/@noble/hashes/1.7.1/src/utils.d.ts.map +1 -0
  96. package/script/deps/jsr.io/@noble/hashes/1.7.1/src/utils.js +235 -0
  97. package/script/deps/jsr.io/@std/bytes/1.0.4/concat.d.ts +19 -0
  98. package/script/deps/jsr.io/@std/bytes/1.0.4/concat.d.ts.map +1 -0
  99. package/script/deps/jsr.io/@std/bytes/1.0.4/concat.js +35 -0
  100. package/script/deps/jsr.io/@std/encoding/1.0.6/_validate_binary_like.d.ts +2 -0
  101. package/script/deps/jsr.io/@std/encoding/1.0.6/_validate_binary_like.d.ts.map +1 -0
  102. package/script/deps/jsr.io/@std/encoding/1.0.6/_validate_binary_like.js +29 -0
  103. package/script/deps/jsr.io/@std/encoding/1.0.6/hex.d.ts +37 -0
  104. package/script/deps/jsr.io/@std/encoding/1.0.6/hex.d.ts.map +1 -0
  105. package/script/deps/jsr.io/@std/encoding/1.0.6/hex.js +113 -0
  106. package/script/deps/jsr.io/@std/msgpack/1.0.2/encode.d.ts +37 -0
  107. package/script/deps/jsr.io/@std/msgpack/1.0.2/encode.d.ts.map +1 -0
  108. package/script/deps/jsr.io/@std/msgpack/1.0.2/encode.js +240 -0
  109. package/script/mod.d.ts +24 -0
  110. package/script/mod.d.ts.map +1 -0
  111. package/script/mod.js +27 -0
  112. package/script/package.json +3 -0
  113. package/script/src/clients/event.d.ts +374 -0
  114. package/script/src/clients/event.d.ts.map +1 -0
  115. package/script/src/clients/event.js +494 -0
  116. package/script/src/clients/public.d.ts +695 -0
  117. package/script/src/clients/public.d.ts.map +1 -0
  118. package/script/src/clients/public.js +708 -0
  119. package/script/src/clients/wallet.d.ts +682 -0
  120. package/script/src/clients/wallet.d.ts.map +1 -0
  121. package/script/src/clients/wallet.js +989 -0
  122. package/script/src/transports/base.d.ts +55 -0
  123. package/script/src/transports/base.d.ts.map +1 -0
  124. package/script/src/transports/base.js +18 -0
  125. package/script/src/transports/http/http_transport.d.ts +78 -0
  126. package/script/src/transports/http/http_transport.d.ts.map +1 -0
  127. package/script/src/transports/http/http_transport.js +175 -0
  128. package/script/src/transports/websocket/hyperliquid_event_target.d.ts +66 -0
  129. package/script/src/transports/websocket/hyperliquid_event_target.d.ts.map +1 -0
  130. package/script/src/transports/websocket/hyperliquid_event_target.js +37 -0
  131. package/script/src/transports/websocket/reconnecting_websocket.d.ts +160 -0
  132. package/script/src/transports/websocket/reconnecting_websocket.d.ts.map +1 -0
  133. package/script/src/transports/websocket/reconnecting_websocket.js +374 -0
  134. package/script/src/transports/websocket/websocket_request_dispatcher.d.ts +63 -0
  135. package/script/src/transports/websocket/websocket_request_dispatcher.d.ts.map +1 -0
  136. package/script/src/transports/websocket/websocket_request_dispatcher.js +206 -0
  137. package/script/src/transports/websocket/websocket_transport.d.ts +117 -0
  138. package/script/src/transports/websocket/websocket_transport.d.ts.map +1 -0
  139. package/script/src/transports/websocket/websocket_transport.js +237 -0
  140. package/script/src/utils/key_sort.d.ts +21 -0
  141. package/script/src/utils/key_sort.d.ts.map +1 -0
  142. package/script/src/utils/key_sort.js +127 -0
  143. package/script/src/utils/signing.d.ts +109 -0
  144. package/script/src/utils/signing.d.ts.map +1 -0
  145. package/script/src/utils/signing.js +172 -0
@@ -0,0 +1,984 @@
1
+ import { sorters } from "../utils/key_sort.js";
2
+ import { signL1Action, signUserSignedAction, } from "../utils/signing.js";
3
+ // ———————————————Errors———————————————
4
+ /** Error thrown when the API returns an error response. */
5
+ export class ApiRequestError extends Error {
6
+ constructor(response) {
7
+ let message = "";
8
+ if (response.status === "err") {
9
+ message = response.response;
10
+ }
11
+ else {
12
+ if ("statuses" in response.response.data) {
13
+ message = response.response.data.statuses
14
+ .reduce((acc, status, index) => {
15
+ if (typeof status === "object" && "error" in status) {
16
+ acc.push(`[${index}] ${status.error}`);
17
+ }
18
+ return acc;
19
+ }, [])
20
+ .join(", ");
21
+ }
22
+ else {
23
+ if (typeof response.response.data.status === "object" && "error" in response.response.data.status) {
24
+ message = response.response.data.status.error;
25
+ }
26
+ }
27
+ }
28
+ super(message);
29
+ Object.defineProperty(this, "response", {
30
+ enumerable: true,
31
+ configurable: true,
32
+ writable: true,
33
+ value: response
34
+ });
35
+ this.name = "ApiRequestError";
36
+ }
37
+ }
38
+ // ———————————————Client———————————————
39
+ /**
40
+ * Wallet client for interacting with the Hyperliquid API.
41
+ * @typeParam T - The transport used to connect to the Hyperliquid API.
42
+ * @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.
43
+ */
44
+ export class WalletClient {
45
+ /**
46
+ * Initialises a new instance.
47
+ * @param args - The parameters for the client.
48
+ *
49
+ * @example Private key via [viem](https://viem.sh/docs/clients/wallet#local-accounts-private-key-mnemonic-etc)
50
+ * ```ts
51
+ * import * as hl from "@nktkas/hyperliquid";
52
+ * import { privateKeyToAccount } from "viem/accounts";
53
+ *
54
+ * const wallet = privateKeyToAccount("0x...");
55
+ *
56
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
57
+ * const client = new hl.WalletClient({ wallet, transport });
58
+ * ```
59
+ *
60
+ * @example Private key via [ethers.js](https://docs.ethers.org/v6/api/wallet/#Wallet)
61
+ * ```ts
62
+ * import * as hl from "@nktkas/hyperliquid";
63
+ * import { ethers } from "ethers";
64
+ *
65
+ * const wallet = new ethers.Wallet("0x...");
66
+ *
67
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
68
+ * const client = new hl.WalletClient({ wallet, transport });
69
+ * ```
70
+ *
71
+ * @example External wallet (e.g. MetaMask) via [viem](https://viem.sh/docs/clients/wallet#optional-hoist-the-account)
72
+ * ```ts
73
+ * import * as hl from "@nktkas/hyperliquid";
74
+ * import { createWalletClient, custom } from "viem";
75
+ * import { arbitrum } from "viem/chains";
76
+ *
77
+ * const [account] = await window.ethereum.request({ method: "eth_requestAccounts" });
78
+ * const wallet = createWalletClient({ account, chain: arbitrum, transport: custom(window.ethereum) });
79
+ *
80
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
81
+ * const client = new hl.WalletClient({ wallet, transport });
82
+ * ```
83
+ */
84
+ constructor(args) {
85
+ /** The transport used to connect to the Hyperliquid API. */
86
+ Object.defineProperty(this, "transport", {
87
+ enumerable: true,
88
+ configurable: true,
89
+ writable: true,
90
+ value: void 0
91
+ });
92
+ /** The WalletClient/Account ([viem](https://viem.sh/docs/clients/wallet)) or Signer ([ethers.js](https://docs.ethers.org/v6/api/providers/#Signer)) used for signing transactions. */
93
+ Object.defineProperty(this, "wallet", {
94
+ enumerable: true,
95
+ configurable: true,
96
+ writable: true,
97
+ value: void 0
98
+ });
99
+ /** Specifies whether the client uses testnet. */
100
+ Object.defineProperty(this, "isTestnet", {
101
+ enumerable: true,
102
+ configurable: true,
103
+ writable: true,
104
+ value: void 0
105
+ });
106
+ /** Sets a default vaultAddress to be used if no vaultAddress is explicitly passed to a method. */
107
+ Object.defineProperty(this, "defaultVaultAddress", {
108
+ enumerable: true,
109
+ configurable: true,
110
+ writable: true,
111
+ value: void 0
112
+ });
113
+ this.transport = args.transport;
114
+ this.wallet = args.wallet;
115
+ this.isTestnet = args.isTestnet ?? false;
116
+ this.defaultVaultAddress = args.defaultVaultAddress;
117
+ }
118
+ // ———————————————Actions———————————————
119
+ /**
120
+ * Approve an agent to sign on behalf of the master or sub-accounts.
121
+ * @param args - The parameters for the request.
122
+ * @param signal - An optional abort signal
123
+ * @returns {SuccessResponse} Successful response without specific data.
124
+ * @throws {ApiRequestError} When the API returns an error response.
125
+ *
126
+ * @see {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#approve-an-api-wallet | Hyperliquid GitBook}
127
+ * @example
128
+ * ```ts
129
+ * import * as hl from "@nktkas/hyperliquid";
130
+ * import { privateKeyToAccount } from "viem/accounts";
131
+ *
132
+ * const wallet = privateKeyToAccount("0x...");
133
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
134
+ * const client = new hl.WalletClient({ wallet, transport });
135
+ *
136
+ * const result = await client.approveAgent({
137
+ * agentAddress: "0x...",
138
+ * agentName: "agentName",
139
+ * });
140
+ */
141
+ async approveAgent(args, signal) {
142
+ const action = {
143
+ ...args,
144
+ type: "approveAgent",
145
+ hyperliquidChain: this.isTestnet ? "Testnet" : "Mainnet",
146
+ signatureChainId: args.signatureChainId ?? this.isTestnet ? "0x66eee" : "0xa4b1",
147
+ nonce: args.nonce ?? Date.now(),
148
+ };
149
+ const signature = await signUserSignedAction(this.wallet, action, {
150
+ "HyperliquidTransaction:ApproveAgent": [
151
+ { name: "hyperliquidChain", type: "string" },
152
+ { name: "agentAddress", type: "address" },
153
+ { name: "agentName", type: "string" },
154
+ { name: "nonce", type: "uint64" },
155
+ ],
156
+ }, parseInt(action.signatureChainId, 16));
157
+ const request = {
158
+ action,
159
+ signature,
160
+ nonce: action.nonce,
161
+ };
162
+ const response = await this.transport.request("action", request, signal);
163
+ this._validateResponse(response);
164
+ return response;
165
+ }
166
+ /**
167
+ * Approve a max fee rate for a builder address.
168
+ * @param args - The parameters for the request.
169
+ * @param signal - An optional abort signal.
170
+ * @returns {SuccessResponse} Successful response without specific data.
171
+ * @throws {ApiRequestError} When the API returns an error response.
172
+ *
173
+ * @see {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#approve-a-builder-fee | Hyperliquid GitBook}
174
+ * @example
175
+ * ```ts
176
+ * import * as hl from "@nktkas/hyperliquid";
177
+ * import { privateKeyToAccount } from "viem/accounts";
178
+ *
179
+ * const wallet = privateKeyToAccount("0x...");
180
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
181
+ * const client = new hl.WalletClient({ wallet, transport });
182
+ *
183
+ * const result = await client.approveBuilderFee({
184
+ * maxFeeRate: "0.01%",
185
+ * builder: "0x...",
186
+ * });
187
+ */
188
+ async approveBuilderFee(args, signal) {
189
+ const action = {
190
+ ...args,
191
+ type: "approveBuilderFee",
192
+ hyperliquidChain: this.isTestnet ? "Testnet" : "Mainnet",
193
+ signatureChainId: args.signatureChainId ?? this.isTestnet ? "0x66eee" : "0xa4b1",
194
+ nonce: args.nonce ?? Date.now(),
195
+ };
196
+ const signature = await signUserSignedAction(this.wallet, action, {
197
+ "HyperliquidTransaction:ApproveBuilderFee": [
198
+ { name: "hyperliquidChain", type: "string" },
199
+ { name: "maxFeeRate", type: "string" },
200
+ { name: "builder", type: "address" },
201
+ { name: "nonce", type: "uint64" },
202
+ ],
203
+ }, parseInt(action.signatureChainId, 16));
204
+ const request = {
205
+ action,
206
+ signature,
207
+ nonce: action.nonce,
208
+ };
209
+ const response = await this.transport.request("action", request, signal);
210
+ this._validateResponse(response);
211
+ return response;
212
+ }
213
+ /**
214
+ * Modify multiple orders.
215
+ * @param args - The parameters for the request.
216
+ * @param signal - An optional abort signal.
217
+ * @returns {OrderResponseSuccess} Successful variant of {@link OrderResponse} without error statuses.
218
+ * @throws {ApiRequestError} When the API returns an error response.
219
+ *
220
+ * @see {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#modify-multiple-orders | Hyperliquid GitBook}
221
+ * @example
222
+ * ```ts
223
+ * import * as hl from "@nktkas/hyperliquid";
224
+ * import { privateKeyToAccount } from "viem/accounts";
225
+ *
226
+ * const wallet = privateKeyToAccount("0x...");
227
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
228
+ * const client = new hl.WalletClient({ wallet, transport });
229
+ *
230
+ * const result = await client.batchModify({
231
+ * modifies: [{
232
+ * oid: 123, // Order ID
233
+ * order: {
234
+ * a: 0, // Asset index
235
+ * b: true, // Buy order
236
+ * p: "31000", // New price
237
+ * s: "0.2", // New size
238
+ * r: false, // Not reduce-only
239
+ * t: {
240
+ * limit: {
241
+ * tif: "Gtc", // Good-til-cancelled
242
+ * },
243
+ * },
244
+ * c: "0x...", // Optional: Client Order ID
245
+ * },
246
+ * }],
247
+ * });
248
+ * ```
249
+ */
250
+ async batchModify(args, signal) {
251
+ const { vaultAddress = this.defaultVaultAddress, nonce = Date.now(), ...actionArgs } = args;
252
+ const sortedAction = sorters.batchModify({ type: "batchModify", ...actionArgs });
253
+ const signature = await signL1Action(this.wallet, this.isTestnet, sortedAction, nonce, vaultAddress);
254
+ const request = {
255
+ action: sortedAction,
256
+ signature,
257
+ nonce,
258
+ vaultAddress,
259
+ };
260
+ const response = await this.transport.request("action", request, signal);
261
+ this._validateResponse(response);
262
+ return response;
263
+ }
264
+ /**
265
+ * Cancel order(s).
266
+ * @param args - The parameters for the request.
267
+ * @param signal - An optional abort signal.
268
+ * @returns {CancelResponseSuccess} Successful variant of {@link CancelResponse} without error statuses.
269
+ * @throws {ApiRequestError} When the API returns an error response.
270
+ *
271
+ * @see {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s | Hyperliquid GitBook}
272
+ * @example
273
+ * ```ts
274
+ * import * as hl from "@nktkas/hyperliquid";
275
+ * import { privateKeyToAccount } from "viem/accounts";
276
+ *
277
+ * const wallet = privateKeyToAccount("0x...");
278
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
279
+ * const client = new hl.WalletClient({ wallet, transport });
280
+ *
281
+ * const result = await client.cancel({
282
+ * cancels: [{
283
+ * a: 0, // Asset index
284
+ * o: 123, // Order ID
285
+ * }],
286
+ * });
287
+ * ```
288
+ */
289
+ async cancel(args, signal) {
290
+ const { vaultAddress = this.defaultVaultAddress, nonce = Date.now(), ...actionArgs } = args;
291
+ const sortedAction = sorters.cancel({ type: "cancel", ...actionArgs });
292
+ const signature = await signL1Action(this.wallet, this.isTestnet, sortedAction, nonce, vaultAddress);
293
+ const request = {
294
+ action: sortedAction,
295
+ signature,
296
+ nonce,
297
+ vaultAddress,
298
+ };
299
+ const response = await this.transport.request("action", request, signal);
300
+ this._validateResponse(response);
301
+ return response;
302
+ }
303
+ /**
304
+ * Cancel order(s) by Client Order ID.
305
+ * @param args - The parameters for the request.
306
+ * @param signal - An optional abort signal.
307
+ * @returns {CancelResponseSuccess} Successful variant of {@link CancelResponse} without error statuses.
308
+ * @throws {ApiRequestError} When the API returns an error response.
309
+ *
310
+ * @see {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s-by-cloid | Hyperliquid GitBook}
311
+ * @example
312
+ * ```ts
313
+ * import * as hl from "@nktkas/hyperliquid";
314
+ * import { privateKeyToAccount } from "viem/accounts";
315
+ *
316
+ * const wallet = privateKeyToAccount("0x...");
317
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
318
+ * const client = new hl.WalletClient({ wallet, transport });
319
+ *
320
+ * const result = await client.cancelByCloid({
321
+ * cancels: [{
322
+ * asset: 0,
323
+ * cloid: "0x...", // Client Order ID
324
+ * }],
325
+ * });
326
+ * ```
327
+ */
328
+ async cancelByCloid(args, signal) {
329
+ const { vaultAddress = this.defaultVaultAddress, nonce = Date.now(), ...actionArgs } = args;
330
+ const sortedAction = sorters.cancelByCloid({ type: "cancelByCloid", ...actionArgs });
331
+ const signature = await signL1Action(this.wallet, this.isTestnet, sortedAction, nonce, vaultAddress);
332
+ const request = {
333
+ action: sortedAction,
334
+ signature,
335
+ nonce,
336
+ vaultAddress,
337
+ };
338
+ const response = await this.transport.request("action", request, signal);
339
+ this._validateResponse(response);
340
+ return response;
341
+ }
342
+ /**
343
+ * Create a sub-account.
344
+ * @param args - The parameters for the request.
345
+ * @param signal - An optional abort signal.
346
+ * @returns {CreateSubAccountResponse} Response for creating a sub-account.
347
+ * @throws {ApiRequestError} When the API returns an error response.
348
+ *
349
+ * @example
350
+ * ```ts
351
+ * import * as hl from "@nktkas/hyperliquid";
352
+ * import { privateKeyToAccount } from "viem/accounts";
353
+ *
354
+ * const wallet = privateKeyToAccount("0x...");
355
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
356
+ * const client = new hl.WalletClient({ wallet, transport });
357
+ *
358
+ * const result = await client.createSubAccount({
359
+ * name: "subAccountName",
360
+ * });
361
+ * ```
362
+ */
363
+ async createSubAccount(args, signal) {
364
+ const { nonce = Date.now(), ...actionArgs } = args;
365
+ const sortedAction = sorters.createSubAccount({ type: "createSubAccount", ...actionArgs });
366
+ const signature = await signL1Action(this.wallet, this.isTestnet, sortedAction, nonce);
367
+ const request = {
368
+ action: sortedAction,
369
+ signature,
370
+ nonce,
371
+ };
372
+ const response = await this.transport.request("action", request, signal);
373
+ this._validateResponse(response);
374
+ return response;
375
+ }
376
+ /**
377
+ * Modify an order.
378
+ * @param args - The parameters for the request.
379
+ * @param signal - An optional abort signal.
380
+ * @returns {SuccessResponse} Successful response without specific data.
381
+ * @throws {ApiRequestError} When the API returns an error response.
382
+ *
383
+ * @see {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#modify-an-order | Hyperliquid GitBook}
384
+ * @example
385
+ * ```ts
386
+ * import * as hl from "@nktkas/hyperliquid";
387
+ * import { privateKeyToAccount } from "viem/accounts";
388
+ *
389
+ * const wallet = privateKeyToAccount("0x...");
390
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
391
+ * const client = new hl.WalletClient({ wallet, transport });
392
+ *
393
+ * const result = await client.modify({
394
+ * oid: 123, // Order ID
395
+ * order: {
396
+ * a: 0, // Asset index
397
+ * b: true, // Buy order
398
+ * p: "31000", // New price
399
+ * s: "0.2", // New size
400
+ * r: false, // Not reduce-only
401
+ * t: {
402
+ * limit: {
403
+ * tif: "Gtc", // Good-til-cancelled
404
+ * },
405
+ * },
406
+ * c: "0x...", // Optional: Client Order ID
407
+ * },
408
+ * });
409
+ * ```
410
+ */
411
+ async modify(args, signal) {
412
+ const { vaultAddress = this.defaultVaultAddress, nonce = Date.now(), ...actionArgs } = args;
413
+ const sortedAction = sorters.modify({ type: "modify", ...actionArgs });
414
+ const signature = await signL1Action(this.wallet, this.isTestnet, sortedAction, nonce, vaultAddress);
415
+ const request = {
416
+ action: sortedAction,
417
+ signature,
418
+ nonce,
419
+ vaultAddress,
420
+ };
421
+ const response = await this.transport.request("action", request, signal);
422
+ this._validateResponse(response);
423
+ return response;
424
+ }
425
+ /**
426
+ * Place an order(s).
427
+ * @param args - The parameters for the request.
428
+ * @param signal - An optional abort signal.
429
+ * @returns {OrderResponseSuccess} Successful variant of {@link OrderResponse} without error statuses.
430
+ * @throws {ApiRequestError} When the API returns an error response.
431
+ *
432
+ * @see {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#place-an-order | Hyperliquid GitBook}
433
+ * @example
434
+ * ```ts
435
+ * import * as hl from "@nktkas/hyperliquid";
436
+ * import { privateKeyToAccount } from "viem/accounts";
437
+ *
438
+ * const wallet = privateKeyToAccount("0x...");
439
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
440
+ * const client = new hl.WalletClient({ wallet, transport });
441
+ *
442
+ * const result = await client.order({
443
+ * orders: [{
444
+ * a: 0, // Asset index
445
+ * b: true, // Buy order
446
+ * p: "30000", // Price
447
+ * s: "0.1", // Size
448
+ * r: false, // Not reduce-only
449
+ * t: {
450
+ * limit: {
451
+ * tif: "Gtc", // Good-til-cancelled
452
+ * },
453
+ * },
454
+ * c: "0x...", // Optional: Client Order ID
455
+ * }],
456
+ * grouping: "na", // No grouping
457
+ * });
458
+ * ```
459
+ */
460
+ async order(args, signal) {
461
+ const clonedArgs = structuredClone(args); // Clone to prevent mutation of original object
462
+ const { vaultAddress = this.defaultVaultAddress, nonce = Date.now(), ...actionArgs } = clonedArgs;
463
+ if (actionArgs.builder)
464
+ actionArgs.builder.b = actionArgs.builder.b.toLowerCase();
465
+ const sortedAction = sorters.order({ type: "order", ...actionArgs });
466
+ const signature = await signL1Action(this.wallet, this.isTestnet, sortedAction, nonce, vaultAddress);
467
+ const request = {
468
+ action: sortedAction,
469
+ signature,
470
+ nonce,
471
+ vaultAddress,
472
+ };
473
+ const response = await this.transport.request("action", request, signal);
474
+ this._validateResponse(response);
475
+ return response;
476
+ }
477
+ /**
478
+ * Schedule a time to cancel all open orders.
479
+ * @param args - The parameters for the request.
480
+ * @param signal - An optional abort signal.
481
+ * @returns {SuccessResponse} Successful response without specific data.
482
+ * @throws {ApiRequestError} When the API returns an error response.
483
+ *
484
+ * @see {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#schedule-cancel-dead-mans-switch | Hyperliquid GitBook}
485
+ * @example
486
+ * ```ts
487
+ * import * as hl from "@nktkas/hyperliquid";
488
+ * import { privateKeyToAccount } from "viem/accounts";
489
+ *
490
+ * const wallet = privateKeyToAccount("0x...");
491
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
492
+ * const client = new hl.WalletClient({ wallet, transport });
493
+ *
494
+ * const result = await client.scheduleCancel({
495
+ * time: Date.now() + 3600000, // Schedule cancellation 1 hour from now
496
+ * });
497
+ * ```
498
+ */
499
+ async scheduleCancel(args = {}, signal) {
500
+ const { vaultAddress = this.defaultVaultAddress, nonce = Date.now(), ...actionArgs } = args;
501
+ const sortedAction = sorters.scheduleCancel({ type: "scheduleCancel", ...actionArgs });
502
+ const signature = await signL1Action(this.wallet, this.isTestnet, sortedAction, nonce, vaultAddress);
503
+ const request = {
504
+ action: sortedAction,
505
+ signature,
506
+ nonce,
507
+ vaultAddress,
508
+ };
509
+ const response = await this.transport.request("action", request, signal);
510
+ this._validateResponse(response);
511
+ return response;
512
+ }
513
+ /**
514
+ * Set a referral code.
515
+ * @param args - The parameters for the request.
516
+ * @param signal - An optional abort signal.
517
+ * @returns {SuccessResponse} Successful response without specific data.
518
+ * @throws {ApiRequestError} When the API returns an error response.
519
+ *
520
+ * @example
521
+ * ```ts
522
+ * import * as hl from "@nktkas/hyperliquid";
523
+ * import { privateKeyToAccount } from "viem/accounts";
524
+ *
525
+ * const wallet = privateKeyToAccount("0x...");
526
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
527
+ * const client = new hl.WalletClient({ wallet, transport });
528
+ *
529
+ * const result = await client.setReferrer({
530
+ * code: "TEST",
531
+ * });
532
+ * ```
533
+ */
534
+ async setReferrer(args, signal) {
535
+ const { nonce = Date.now(), ...actionArgs } = args;
536
+ const sortedAction = sorters.setReferrer({ type: "setReferrer", ...actionArgs });
537
+ const signature = await signL1Action(this.wallet, this.isTestnet, sortedAction, nonce);
538
+ const request = {
539
+ action: sortedAction,
540
+ signature,
541
+ nonce,
542
+ };
543
+ const response = await this.transport.request("action", request, signal);
544
+ this._validateResponse(response);
545
+ return response;
546
+ }
547
+ /**
548
+ * Transfer a spot asset on L1 to another address.
549
+ * @param args - The parameters for the request.
550
+ * @param signal - An optional abort signal.
551
+ * @returns {SuccessResponse} Successful response without specific data.
552
+ * @throws {ApiRequestError} When the API returns an error response.
553
+ *
554
+ * @see {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#l1-spot-transfer | Hyperliquid GitBook}
555
+ * @example
556
+ * ```ts
557
+ * import * as hl from "@nktkas/hyperliquid";
558
+ * import { privateKeyToAccount } from "viem/accounts";
559
+ *
560
+ * const wallet = privateKeyToAccount("0x...");
561
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
562
+ * const client = new hl.WalletClient({ wallet, transport });
563
+ *
564
+ * const result = await client.spotSend({
565
+ * destination: "0x...",
566
+ * token: "USDC:0xeb62eee3685fc4c43992febcd9e75443",
567
+ * amount: "1",
568
+ * });
569
+ * ```
570
+ */
571
+ async spotSend(args, signal) {
572
+ const action = {
573
+ ...args,
574
+ type: "spotSend",
575
+ hyperliquidChain: this.isTestnet ? "Testnet" : "Mainnet",
576
+ signatureChainId: args.signatureChainId ?? this.isTestnet ? "0x66eee" : "0xa4b1",
577
+ time: args.time ?? Date.now(),
578
+ };
579
+ const signature = await signUserSignedAction(this.wallet, action, {
580
+ "HyperliquidTransaction:SpotSend": [
581
+ { name: "hyperliquidChain", type: "string" },
582
+ { name: "destination", type: "string" },
583
+ { name: "token", type: "string" },
584
+ { name: "amount", type: "string" },
585
+ { name: "time", type: "uint64" },
586
+ ],
587
+ }, parseInt(action.signatureChainId, 16));
588
+ const request = {
589
+ action,
590
+ signature,
591
+ nonce: action.time,
592
+ };
593
+ const response = await this.transport.request("action", request, signal);
594
+ this._validateResponse(response);
595
+ return response;
596
+ }
597
+ /**
598
+ * Transfer between sub-accounts.
599
+ * @param args - The parameters for the request.
600
+ * @param signal - An optional abort signal.
601
+ * @returns {SuccessResponse} Successful response without specific data.
602
+ * @throws {ApiRequestError} When the API returns an error response.
603
+ *
604
+ * @example
605
+ * ```ts
606
+ * import * as hl from "@nktkas/hyperliquid";
607
+ * import { privateKeyToAccount } from "viem/accounts";
608
+ *
609
+ * const wallet = privateKeyToAccount("0x...");
610
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
611
+ * const client = new hl.WalletClient({ wallet, transport });
612
+ *
613
+ * const result = await client.subAccountTransfer({
614
+ * subAccountUser: "0x...",
615
+ * isDeposit: true,
616
+ * usd: 1000000, // 1 USD in raw units (float amount * 1e6)
617
+ * });
618
+ * ```
619
+ */
620
+ async subAccountTransfer(args, signal) {
621
+ const { nonce = Date.now(), ...actionArgs } = args;
622
+ const sortedAction = sorters.subAccountTransfer({ type: "subAccountTransfer", ...actionArgs });
623
+ const signature = await signL1Action(this.wallet, this.isTestnet, sortedAction, nonce);
624
+ const request = {
625
+ action: sortedAction,
626
+ signature,
627
+ nonce,
628
+ };
629
+ const response = await this.transport.request("action", request, signal);
630
+ this._validateResponse(response);
631
+ return response;
632
+ }
633
+ /**
634
+ * Cancel a TWAP order.
635
+ * @param args - The parameters for the request.
636
+ * @param signal - An optional abort signal.
637
+ * @returns {TwapCancelResponseSuccess} Successful variant of {@link TwapCancelResponse} without error status.
638
+ * @throws {ApiRequestError} When the API returns an error response.
639
+ *
640
+ * @see {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-a-twap-order | Hyperliquid GitBook}
641
+ * @example
642
+ * ```ts
643
+ * import * as hl from "@nktkas/hyperliquid";
644
+ * import { privateKeyToAccount } from "viem/accounts";
645
+ *
646
+ * const wallet = privateKeyToAccount("0x...");
647
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
648
+ * const client = new hl.WalletClient({ wallet, transport });
649
+ *
650
+ * const result = await client.twapCancel({
651
+ * a: 0, // Asset index
652
+ * t: 1, // TWAP ID
653
+ * });
654
+ * ```
655
+ */
656
+ async twapCancel(args, signal) {
657
+ const { vaultAddress = this.defaultVaultAddress, nonce = Date.now(), ...actionArgs } = args;
658
+ const sortedAction = sorters.twapCancel({ type: "twapCancel", ...actionArgs });
659
+ const signature = await signL1Action(this.wallet, this.isTestnet, sortedAction, nonce, vaultAddress);
660
+ const request = {
661
+ action: sortedAction,
662
+ signature,
663
+ nonce,
664
+ vaultAddress,
665
+ };
666
+ const response = await this.transport.request("action", request, signal);
667
+ this._validateResponse(response);
668
+ return response;
669
+ }
670
+ /**
671
+ * Place a TWAP order.
672
+ * @param args - The parameters for the request.
673
+ * @param signal - An optional abort signal.
674
+ * @returns {TwapOrderResponseSuccess} Successful variant of {@link TwapOrderResponse} without error status.
675
+ * @throws {ApiRequestError} When the API returns an error response.
676
+ *
677
+ * @see {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#place-a-twap-order | Hyperliquid GitBook}
678
+ * @example
679
+ * ```ts
680
+ * import * as hl from "@nktkas/hyperliquid";
681
+ * import { privateKeyToAccount } from "viem/accounts";
682
+ *
683
+ * const wallet = privateKeyToAccount("0x...");
684
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
685
+ * const client = new hl.WalletClient({ wallet, transport });
686
+ *
687
+ * const result = await client.twapOrder({
688
+ * a: 0, // Asset index
689
+ * b: true, // Buy order
690
+ * s: "1", // Size
691
+ * r: false, // Not reduce-only
692
+ * m: 10, // Duration in minutes
693
+ * t: true, // Randomize order timing
694
+ * });
695
+ * ```
696
+ */
697
+ async twapOrder(args, signal) {
698
+ const { vaultAddress = this.defaultVaultAddress, nonce = Date.now(), ...actionArgs } = args;
699
+ const sortedAction = sorters.twapOrder({ type: "twapOrder", twap: actionArgs });
700
+ const signature = await signL1Action(this.wallet, this.isTestnet, sortedAction, nonce, vaultAddress);
701
+ const request = {
702
+ action: sortedAction,
703
+ signature,
704
+ nonce,
705
+ vaultAddress,
706
+ };
707
+ const response = await this.transport.request("action", request, signal);
708
+ this._validateResponse(response);
709
+ return response;
710
+ }
711
+ /**
712
+ * Update isolated margin for a position.
713
+ * @param args - The parameters for the request.
714
+ * @param signal - An optional abort signal.
715
+ * @returns {SuccessResponse} Successful response without specific data.
716
+ * @throws {ApiRequestError} When the API returns an error response.
717
+ *
718
+ * @see {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#update-isolated-margin | Hyperliquid GitBook}
719
+ * @example
720
+ * ```ts
721
+ * import * as hl from "@nktkas/hyperliquid";
722
+ * import { privateKeyToAccount } from "viem/accounts";
723
+ *
724
+ * const wallet = privateKeyToAccount("0x...");
725
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
726
+ * const client = new hl.WalletClient({ wallet, transport });
727
+ *
728
+ * const result = await client.updateIsolatedMargin({
729
+ * asset: 0,
730
+ * isBuy: true, // Add to long position
731
+ * ntli: 1000, // Add 1000 USD margin (integer only)
732
+ * });
733
+ * ```
734
+ */
735
+ async updateIsolatedMargin(args, signal) {
736
+ const { vaultAddress = this.defaultVaultAddress, nonce = Date.now(), ...actionArgs } = args;
737
+ const sortedAction = sorters.updateIsolatedMargin({ type: "updateIsolatedMargin", ...actionArgs });
738
+ const signature = await signL1Action(this.wallet, this.isTestnet, sortedAction, nonce, vaultAddress);
739
+ const request = {
740
+ action: sortedAction,
741
+ signature,
742
+ nonce,
743
+ vaultAddress,
744
+ };
745
+ const response = await this.transport.request("action", request, signal);
746
+ this._validateResponse(response);
747
+ return response;
748
+ }
749
+ /**
750
+ * Update leverage for cross or isolated margin.
751
+ * @param args - The parameters for the request.
752
+ * @param signal - An optional abort signal.
753
+ * @returns {SuccessResponse} Successful response without specific data.
754
+ * @throws {ApiRequestError} When the API returns an error response.
755
+ *
756
+ * @see {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#update-leverage | Hyperliquid GitBook}
757
+ * @example
758
+ * ```ts
759
+ * import * as hl from "@nktkas/hyperliquid";
760
+ * import { privateKeyToAccount } from "viem/accounts";
761
+ *
762
+ * const wallet = privateKeyToAccount("0x...");
763
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
764
+ * const client = new hl.WalletClient({ wallet, transport });
765
+ *
766
+ * const result = await client.updateLeverage({
767
+ * asset: 0,
768
+ * isCross: true,
769
+ * leverage: 5,
770
+ * });
771
+ * ```
772
+ */
773
+ async updateLeverage(args, signal) {
774
+ const { vaultAddress = this.defaultVaultAddress, nonce = Date.now(), ...actionArgs } = args;
775
+ const sortedAction = sorters.updateLeverage({ type: "updateLeverage", ...actionArgs });
776
+ const signature = await signL1Action(this.wallet, this.isTestnet, sortedAction, nonce, vaultAddress);
777
+ const request = {
778
+ action: sortedAction,
779
+ signature,
780
+ nonce,
781
+ vaultAddress,
782
+ };
783
+ const response = await this.transport.request("action", request, signal);
784
+ this._validateResponse(response);
785
+ return response;
786
+ }
787
+ /**
788
+ * Transfer funds between Spot and Perp accounts.
789
+ * @param args - The parameters for the request.
790
+ * @param signal - An optional abort signal.
791
+ * @returns {SuccessResponse} Successful response without specific data.
792
+ * @throws {ApiRequestError} When the API returns an error response.
793
+ *
794
+ * @see {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#transfer-from-spot-account-to-perp-account-and-vice-versa | Hyperliquid GitBook}
795
+ * @example
796
+ * ```ts
797
+ * import * as hl from "@nktkas/hyperliquid";
798
+ * import { privateKeyToAccount } from "viem/accounts";
799
+ *
800
+ * const wallet = privateKeyToAccount("0x...");
801
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
802
+ * const client = new hl.WalletClient({ wallet, transport });
803
+ *
804
+ * const result = await client.usdClassTransfer({
805
+ * amount: "1000",
806
+ * toPerp: true, // Transfer from Spot to Perp
807
+ * });
808
+ * ```
809
+ */
810
+ async usdClassTransfer(args, signal) {
811
+ const action = {
812
+ ...args,
813
+ type: "usdClassTransfer",
814
+ hyperliquidChain: this.isTestnet ? "Testnet" : "Mainnet",
815
+ signatureChainId: args.signatureChainId ?? this.isTestnet ? "0x66eee" : "0xa4b1",
816
+ nonce: args.nonce ?? Date.now(),
817
+ };
818
+ const signature = await signUserSignedAction(this.wallet, action, {
819
+ "HyperliquidTransaction:UsdClassTransfer": [
820
+ { name: "hyperliquidChain", type: "string" },
821
+ { name: "amount", type: "string" },
822
+ { name: "toPerp", type: "bool" },
823
+ { name: "nonce", type: "uint64" },
824
+ ],
825
+ }, parseInt(action.signatureChainId, 16));
826
+ const request = {
827
+ action,
828
+ signature,
829
+ nonce: action.nonce,
830
+ };
831
+ const response = await this.transport.request("action", request, signal);
832
+ this._validateResponse(response);
833
+ return response;
834
+ }
835
+ /**
836
+ * Transfer USDC on L1 to another address.
837
+ * @param args - The parameters for the request.
838
+ * @param signal - An optional abort signal.
839
+ * @returns {SuccessResponse} Successful response without specific data.
840
+ * @throws {ApiRequestError} When the API returns an error response.
841
+ *
842
+ * @see {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#l1-usdc-transfer | Hyperliquid GitBook}
843
+ * @example
844
+ * ```ts
845
+ * import * as hl from "@nktkas/hyperliquid";
846
+ * import { privateKeyToAccount } from "viem/accounts";
847
+ *
848
+ * const wallet = privateKeyToAccount("0x...");
849
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
850
+ * const client = new hl.WalletClient({ wallet, transport });
851
+ *
852
+ * const result = await client.usdSend({
853
+ * destination: "0x...",
854
+ * amount: "1000",
855
+ * });
856
+ * ```
857
+ */
858
+ async usdSend(args, signal) {
859
+ const action = {
860
+ ...args,
861
+ type: "usdSend",
862
+ hyperliquidChain: this.isTestnet ? "Testnet" : "Mainnet",
863
+ signatureChainId: args.signatureChainId ?? this.isTestnet ? "0x66eee" : "0xa4b1",
864
+ time: args.time ?? Date.now(),
865
+ };
866
+ const signature = await signUserSignedAction(this.wallet, action, {
867
+ "HyperliquidTransaction:UsdSend": [
868
+ { name: "hyperliquidChain", type: "string" },
869
+ { name: "destination", type: "string" },
870
+ { name: "amount", type: "string" },
871
+ { name: "time", type: "uint64" },
872
+ ],
873
+ }, parseInt(action.signatureChainId, 16));
874
+ const request = {
875
+ action,
876
+ signature,
877
+ nonce: action.time,
878
+ };
879
+ const response = await this.transport.request("action", request, signal);
880
+ this._validateResponse(response);
881
+ return response;
882
+ }
883
+ /**
884
+ * Transfer funds to/from a vault.
885
+ * @param args - The parameters for the request.
886
+ * @param signal - An optional abort signal.
887
+ * @returns {SuccessResponse} Successful response without specific data.
888
+ * @throws {ApiRequestError} When the API returns an error response.
889
+ *
890
+ * @see {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#deposit-or-withdraw-from-a-vault | Hyperliquid GitBook}
891
+ * @example
892
+ * ```ts
893
+ * import * as hl from "@nktkas/hyperliquid";
894
+ * import { privateKeyToAccount } from "viem/accounts";
895
+ *
896
+ * const wallet = privateKeyToAccount("0x...");
897
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
898
+ * const client = new hl.WalletClient({ wallet, transport });
899
+ *
900
+ * const result = await client.vaultTransfer({
901
+ * vaultAddress: "0x...",
902
+ * isDeposit: true,
903
+ * usd: 1000000, // 1 USD in raw units (float amount * 1e6)
904
+ * });
905
+ * ```
906
+ */
907
+ async vaultTransfer(args, signal) {
908
+ const { nonce = Date.now(), ...actionArgs } = args;
909
+ const sortedAction = sorters.vaultTransfer({ type: "vaultTransfer", ...actionArgs });
910
+ const signature = await signL1Action(this.wallet, this.isTestnet, sortedAction, nonce);
911
+ const request = {
912
+ action: sortedAction,
913
+ signature,
914
+ nonce,
915
+ };
916
+ const response = await this.transport.request("action", request, signal);
917
+ this._validateResponse(response);
918
+ return response;
919
+ }
920
+ /**
921
+ * Initiate a withdrawal request.
922
+ * @param args - The parameters for the request.
923
+ * @param signal - An optional abort signal.
924
+ * @returns {SuccessResponse} Successful response without specific data.
925
+ * @throws {ApiRequestError} When the API returns an error response.
926
+ *
927
+ * @see {@link https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#initiate-a-withdrawal-request | Hyperliquid GitBook}
928
+ * @example
929
+ * ```ts
930
+ * import * as hl from "@nktkas/hyperliquid";
931
+ * import { privateKeyToAccount } from "viem/accounts";
932
+ *
933
+ * const wallet = privateKeyToAccount("0x...");
934
+ * const transport = new hl.HttpTransport(); // or WebSocketTransport
935
+ * const client = new hl.WalletClient({ wallet, transport });
936
+ *
937
+ * const result = await client.withdraw3({
938
+ * destination: "0x...",
939
+ * amount: "1000",
940
+ * });
941
+ * ```
942
+ */
943
+ async withdraw3(args, signal) {
944
+ const action = {
945
+ ...args,
946
+ type: "withdraw3",
947
+ hyperliquidChain: this.isTestnet ? "Testnet" : "Mainnet",
948
+ signatureChainId: args.signatureChainId ?? this.isTestnet ? "0x66eee" : "0xa4b1",
949
+ time: args.time ?? Date.now(),
950
+ };
951
+ const signature = await signUserSignedAction(this.wallet, action, {
952
+ "HyperliquidTransaction:Withdraw": [
953
+ { name: "hyperliquidChain", type: "string" },
954
+ { name: "destination", type: "string" },
955
+ { name: "amount", type: "string" },
956
+ { name: "time", type: "uint64" },
957
+ ],
958
+ }, parseInt(action.signatureChainId, 16));
959
+ const request = {
960
+ action,
961
+ signature,
962
+ nonce: action.time,
963
+ };
964
+ const response = await this.transport.request("action", request, signal);
965
+ this._validateResponse(response);
966
+ return response;
967
+ }
968
+ /** Validate a response from the API. */
969
+ _validateResponse(response) {
970
+ if (response.status === "err") {
971
+ throw new ApiRequestError(response);
972
+ }
973
+ else if (response.response.type === "order" || response.response.type === "cancel") {
974
+ if (response.response.data.statuses.some((status) => typeof status === "object" && "error" in status)) {
975
+ throw new ApiRequestError(response);
976
+ }
977
+ }
978
+ else if (response.response.type === "twapOrder" || response.response.type === "twapCancel") {
979
+ if (typeof response.response.data.status === "object" && "error" in response.response.data.status) {
980
+ throw new ApiRequestError(response);
981
+ }
982
+ }
983
+ }
984
+ }