@nktkas/hyperliquid 0.25.0-beta.1 → 0.25.0-beta.3

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 (284) hide show
  1. package/README.md +64 -16
  2. package/esm/bin/cli.d.ts +3 -0
  3. package/esm/bin/cli.d.ts.map +1 -0
  4. package/esm/bin/cli.js +452 -0
  5. package/esm/bin/cli.js.map +1 -0
  6. package/{script/src/errors.d.ts → esm/src/_errors.d.ts} +1 -1
  7. package/esm/src/_errors.d.ts.map +1 -0
  8. package/esm/src/{errors.js → _errors.js} +1 -0
  9. package/esm/src/_errors.js.map +1 -0
  10. package/esm/src/clients/exchange.d.ts +4 -11
  11. package/esm/src/clients/exchange.d.ts.map +1 -1
  12. package/esm/src/clients/exchange.js +8 -9
  13. package/esm/src/clients/exchange.js.map +1 -0
  14. package/esm/src/clients/info.d.ts +86 -2
  15. package/esm/src/clients/info.d.ts.map +1 -1
  16. package/esm/src/clients/info.js +103 -1
  17. package/esm/src/clients/info.js.map +1 -0
  18. package/esm/src/clients/multiSign.d.ts +1 -1
  19. package/esm/src/clients/multiSign.d.ts.map +1 -1
  20. package/esm/src/clients/multiSign.js +3 -2
  21. package/esm/src/clients/multiSign.js.map +1 -0
  22. package/esm/src/clients/subscription.js +1 -0
  23. package/esm/src/clients/subscription.js.map +1 -0
  24. package/esm/src/mod.d.ts +21 -0
  25. package/esm/src/mod.d.ts.map +1 -0
  26. package/esm/src/mod.js +14 -0
  27. package/esm/src/mod.js.map +1 -0
  28. package/esm/src/schemas/_base.d.ts +11 -3
  29. package/esm/src/schemas/_base.d.ts.map +1 -1
  30. package/esm/src/schemas/_base.js +30 -2
  31. package/esm/src/schemas/_base.js.map +1 -0
  32. package/esm/src/schemas/exchange/requests.d.ts +1872 -1872
  33. package/esm/src/schemas/exchange/requests.d.ts.map +1 -1
  34. package/esm/src/schemas/exchange/requests.js +277 -281
  35. package/esm/src/schemas/exchange/requests.js.map +1 -0
  36. package/esm/src/schemas/exchange/responses.d.ts +51 -51
  37. package/esm/src/schemas/exchange/responses.js +55 -54
  38. package/esm/src/schemas/exchange/responses.js.map +1 -0
  39. package/esm/src/schemas/explorer/requests.d.ts +5 -5
  40. package/esm/src/schemas/explorer/requests.js +6 -5
  41. package/esm/src/schemas/explorer/requests.js.map +1 -0
  42. package/esm/src/schemas/explorer/responses.d.ts +10 -10
  43. package/esm/src/schemas/explorer/responses.js +12 -11
  44. package/esm/src/schemas/explorer/responses.js.map +1 -0
  45. package/esm/src/schemas/info/accounts.d.ts +1042 -296
  46. package/esm/src/schemas/info/accounts.d.ts.map +1 -1
  47. package/esm/src/schemas/info/accounts.js +154 -109
  48. package/esm/src/schemas/info/accounts.js.map +1 -0
  49. package/esm/src/schemas/info/assets.d.ts +130 -101
  50. package/esm/src/schemas/info/assets.d.ts.map +1 -1
  51. package/esm/src/schemas/info/assets.js +69 -49
  52. package/esm/src/schemas/info/assets.js.map +1 -0
  53. package/esm/src/schemas/info/markets.d.ts +35 -18
  54. package/esm/src/schemas/info/markets.d.ts.map +1 -1
  55. package/esm/src/schemas/info/markets.js +27 -15
  56. package/esm/src/schemas/info/markets.js.map +1 -0
  57. package/esm/src/schemas/info/orders.d.ts +151 -151
  58. package/esm/src/schemas/info/orders.js +37 -36
  59. package/esm/src/schemas/info/orders.js.map +1 -0
  60. package/esm/src/schemas/info/requests.d.ts +145 -88
  61. package/esm/src/schemas/info/requests.d.ts.map +1 -1
  62. package/esm/src/schemas/info/requests.js +116 -73
  63. package/esm/src/schemas/info/requests.js.map +1 -0
  64. package/esm/src/schemas/info/validators.d.ts +60 -39
  65. package/esm/src/schemas/info/validators.d.ts.map +1 -1
  66. package/esm/src/schemas/info/validators.js +40 -26
  67. package/esm/src/schemas/info/validators.js.map +1 -0
  68. package/esm/src/schemas/info/vaults.d.ts +59 -59
  69. package/esm/src/schemas/info/vaults.js +20 -19
  70. package/esm/src/schemas/info/vaults.js.map +1 -0
  71. package/esm/src/schemas/mod.d.ts +4 -3
  72. package/esm/src/schemas/mod.d.ts.map +1 -1
  73. package/esm/src/schemas/mod.js +5 -3
  74. package/esm/src/schemas/mod.js.map +1 -0
  75. package/esm/src/schemas/subscriptions/requests.d.ts +23 -23
  76. package/esm/src/schemas/subscriptions/requests.d.ts.map +1 -1
  77. package/esm/src/schemas/subscriptions/requests.js +25 -24
  78. package/esm/src/schemas/subscriptions/requests.js.map +1 -0
  79. package/esm/src/schemas/subscriptions/responses.d.ts +547 -547
  80. package/esm/src/schemas/subscriptions/responses.js +41 -40
  81. package/esm/src/schemas/subscriptions/responses.js.map +1 -0
  82. package/esm/src/signing/mod.d.ts +1 -1
  83. package/esm/src/signing/mod.d.ts.map +1 -1
  84. package/esm/src/signing/mod.js +3 -2
  85. package/esm/src/signing/mod.js.map +1 -0
  86. package/esm/src/signing/signTypedData/ethers.d.ts.map +1 -0
  87. package/esm/src/signing/{_signTypedData → signTypedData}/ethers.js +1 -0
  88. package/esm/src/signing/signTypedData/ethers.js.map +1 -0
  89. package/esm/src/signing/signTypedData/mod.d.ts.map +1 -0
  90. package/esm/src/signing/{_signTypedData → signTypedData}/mod.js +1 -0
  91. package/esm/src/signing/signTypedData/mod.js.map +1 -0
  92. package/esm/src/signing/signTypedData/private_key.d.ts.map +1 -0
  93. package/esm/src/signing/{_signTypedData → signTypedData}/private_key.js +10 -8
  94. package/esm/src/signing/signTypedData/private_key.js.map +1 -0
  95. package/esm/src/signing/signTypedData/viem.d.ts.map +1 -0
  96. package/esm/src/signing/{_signTypedData → signTypedData}/viem.js +1 -0
  97. package/esm/src/signing/signTypedData/viem.js.map +1 -0
  98. package/esm/src/transports/base.d.ts +4 -4
  99. package/esm/src/transports/base.d.ts.map +1 -1
  100. package/esm/src/transports/base.js +3 -2
  101. package/esm/src/transports/base.js.map +1 -0
  102. package/esm/src/transports/http/http_transport.d.ts +1 -1
  103. package/esm/src/transports/http/http_transport.js +1 -0
  104. package/esm/src/transports/http/http_transport.js.map +1 -0
  105. package/esm/src/transports/websocket/_hyperliquid_event_target.js +1 -0
  106. package/esm/src/transports/websocket/_hyperliquid_event_target.js.map +1 -0
  107. package/esm/src/transports/websocket/_reconnecting_websocket.js +1 -0
  108. package/esm/src/transports/websocket/_reconnecting_websocket.js.map +1 -0
  109. package/esm/src/transports/websocket/_websocket_async_request.js +1 -0
  110. package/esm/src/transports/websocket/_websocket_async_request.js.map +1 -0
  111. package/esm/src/transports/websocket/websocket_transport.d.ts +7 -0
  112. package/esm/src/transports/websocket/websocket_transport.d.ts.map +1 -1
  113. package/esm/src/transports/websocket/websocket_transport.js +4 -0
  114. package/esm/src/transports/websocket/websocket_transport.js.map +1 -0
  115. package/package.json +15 -7
  116. package/script/bin/cli.d.ts +3 -0
  117. package/script/bin/cli.d.ts.map +1 -0
  118. package/script/bin/cli.js +490 -0
  119. package/script/bin/cli.js.map +1 -0
  120. package/{esm/src/errors.d.ts → script/src/_errors.d.ts} +1 -1
  121. package/script/src/_errors.d.ts.map +1 -0
  122. package/script/src/{errors.js → _errors.js} +1 -0
  123. package/script/src/_errors.js.map +1 -0
  124. package/script/src/clients/exchange.d.ts +4 -11
  125. package/script/src/clients/exchange.d.ts.map +1 -1
  126. package/script/src/clients/exchange.js +9 -10
  127. package/script/src/clients/exchange.js.map +1 -0
  128. package/script/src/clients/info.d.ts +86 -2
  129. package/script/src/clients/info.d.ts.map +1 -1
  130. package/script/src/clients/info.js +102 -0
  131. package/script/src/clients/info.js.map +1 -0
  132. package/script/src/clients/multiSign.d.ts +1 -1
  133. package/script/src/clients/multiSign.d.ts.map +1 -1
  134. package/script/src/clients/multiSign.js +3 -2
  135. package/script/src/clients/multiSign.js.map +1 -0
  136. package/script/src/clients/subscription.js +1 -0
  137. package/script/src/clients/subscription.js.map +1 -0
  138. package/script/src/mod.d.ts +21 -0
  139. package/script/src/mod.d.ts.map +1 -0
  140. package/script/{mod.js → src/mod.js} +13 -8
  141. package/script/src/mod.js.map +1 -0
  142. package/script/src/schemas/_base.d.ts +11 -3
  143. package/script/src/schemas/_base.d.ts.map +1 -1
  144. package/script/src/schemas/_base.js +31 -3
  145. package/script/src/schemas/_base.js.map +1 -0
  146. package/script/src/schemas/exchange/requests.d.ts +1872 -1872
  147. package/script/src/schemas/exchange/requests.d.ts.map +1 -1
  148. package/script/src/schemas/exchange/requests.js +276 -280
  149. package/script/src/schemas/exchange/requests.js.map +1 -0
  150. package/script/src/schemas/exchange/responses.d.ts +51 -51
  151. package/script/src/schemas/exchange/responses.js +54 -53
  152. package/script/src/schemas/exchange/responses.js.map +1 -0
  153. package/script/src/schemas/explorer/requests.d.ts +5 -5
  154. package/script/src/schemas/explorer/requests.js +5 -4
  155. package/script/src/schemas/explorer/requests.js.map +1 -0
  156. package/script/src/schemas/explorer/responses.d.ts +10 -10
  157. package/script/src/schemas/explorer/responses.js +11 -10
  158. package/script/src/schemas/explorer/responses.js.map +1 -0
  159. package/script/src/schemas/info/accounts.d.ts +1042 -296
  160. package/script/src/schemas/info/accounts.d.ts.map +1 -1
  161. package/script/src/schemas/info/accounts.js +154 -109
  162. package/script/src/schemas/info/accounts.js.map +1 -0
  163. package/script/src/schemas/info/assets.d.ts +130 -101
  164. package/script/src/schemas/info/assets.d.ts.map +1 -1
  165. package/script/src/schemas/info/assets.js +69 -49
  166. package/script/src/schemas/info/assets.js.map +1 -0
  167. package/script/src/schemas/info/markets.d.ts +35 -18
  168. package/script/src/schemas/info/markets.d.ts.map +1 -1
  169. package/script/src/schemas/info/markets.js +27 -15
  170. package/script/src/schemas/info/markets.js.map +1 -0
  171. package/script/src/schemas/info/orders.d.ts +151 -151
  172. package/script/src/schemas/info/orders.js +36 -35
  173. package/script/src/schemas/info/orders.js.map +1 -0
  174. package/script/src/schemas/info/requests.d.ts +145 -88
  175. package/script/src/schemas/info/requests.d.ts.map +1 -1
  176. package/script/src/schemas/info/requests.js +116 -73
  177. package/script/src/schemas/info/requests.js.map +1 -0
  178. package/script/src/schemas/info/validators.d.ts +60 -39
  179. package/script/src/schemas/info/validators.d.ts.map +1 -1
  180. package/script/src/schemas/info/validators.js +40 -26
  181. package/script/src/schemas/info/validators.js.map +1 -0
  182. package/script/src/schemas/info/vaults.d.ts +59 -59
  183. package/script/src/schemas/info/vaults.js +19 -18
  184. package/script/src/schemas/info/vaults.js.map +1 -0
  185. package/script/src/schemas/mod.d.ts +4 -3
  186. package/script/src/schemas/mod.d.ts.map +1 -1
  187. package/script/src/schemas/mod.js +8 -5
  188. package/script/src/schemas/mod.js.map +1 -0
  189. package/script/src/schemas/subscriptions/requests.d.ts +23 -23
  190. package/script/src/schemas/subscriptions/requests.d.ts.map +1 -1
  191. package/script/src/schemas/subscriptions/requests.js +24 -23
  192. package/script/src/schemas/subscriptions/requests.js.map +1 -0
  193. package/script/src/schemas/subscriptions/responses.d.ts +547 -547
  194. package/script/src/schemas/subscriptions/responses.js +40 -39
  195. package/script/src/schemas/subscriptions/responses.js.map +1 -0
  196. package/script/src/signing/mod.d.ts +1 -1
  197. package/script/src/signing/mod.d.ts.map +1 -1
  198. package/script/src/signing/mod.js +4 -3
  199. package/script/src/signing/mod.js.map +1 -0
  200. package/script/src/signing/signTypedData/ethers.d.ts.map +1 -0
  201. package/script/src/signing/{_signTypedData → signTypedData}/ethers.js +1 -0
  202. package/script/src/signing/signTypedData/ethers.js.map +1 -0
  203. package/script/src/signing/signTypedData/mod.d.ts.map +1 -0
  204. package/script/src/signing/{_signTypedData → signTypedData}/mod.js +1 -0
  205. package/script/src/signing/signTypedData/mod.js.map +1 -0
  206. package/script/src/signing/signTypedData/private_key.d.ts.map +1 -0
  207. package/script/src/signing/{_signTypedData → signTypedData}/private_key.js +17 -15
  208. package/script/src/signing/signTypedData/private_key.js.map +1 -0
  209. package/script/src/signing/signTypedData/viem.d.ts.map +1 -0
  210. package/script/src/signing/{_signTypedData → signTypedData}/viem.js +1 -0
  211. package/script/src/signing/signTypedData/viem.js.map +1 -0
  212. package/script/src/transports/base.d.ts +4 -4
  213. package/script/src/transports/base.d.ts.map +1 -1
  214. package/script/src/transports/base.js +4 -3
  215. package/script/src/transports/base.js.map +1 -0
  216. package/script/src/transports/http/http_transport.d.ts +1 -1
  217. package/script/src/transports/http/http_transport.js +1 -0
  218. package/script/src/transports/http/http_transport.js.map +1 -0
  219. package/script/src/transports/websocket/_hyperliquid_event_target.js +1 -0
  220. package/script/src/transports/websocket/_hyperliquid_event_target.js.map +1 -0
  221. package/script/src/transports/websocket/_reconnecting_websocket.js +1 -0
  222. package/script/src/transports/websocket/_reconnecting_websocket.js.map +1 -0
  223. package/script/src/transports/websocket/_websocket_async_request.js +1 -0
  224. package/script/src/transports/websocket/_websocket_async_request.js.map +1 -0
  225. package/script/src/transports/websocket/websocket_transport.d.ts +7 -0
  226. package/script/src/transports/websocket/websocket_transport.d.ts.map +1 -1
  227. package/script/src/transports/websocket/websocket_transport.js +4 -0
  228. package/script/src/transports/websocket/websocket_transport.js.map +1 -0
  229. package/src/bin/cli.ts +481 -0
  230. package/src/src/_errors.ts +7 -0
  231. package/src/src/clients/exchange.ts +2246 -0
  232. package/src/src/clients/info.ts +2110 -0
  233. package/src/src/clients/multiSign.ts +183 -0
  234. package/src/src/clients/subscription.ts +841 -0
  235. package/src/src/mod.ts +29 -0
  236. package/src/src/schemas/_base.ts +82 -0
  237. package/src/src/schemas/exchange/requests.ts +3052 -0
  238. package/src/src/schemas/exchange/responses.ts +540 -0
  239. package/src/src/schemas/explorer/requests.ts +65 -0
  240. package/src/src/schemas/explorer/responses.ts +138 -0
  241. package/src/src/schemas/info/accounts.ts +1598 -0
  242. package/src/src/schemas/info/assets.ts +693 -0
  243. package/src/src/schemas/info/markets.ts +171 -0
  244. package/src/src/schemas/info/orders.ts +597 -0
  245. package/src/src/schemas/info/requests.ts +1401 -0
  246. package/src/src/schemas/info/validators.ts +297 -0
  247. package/src/src/schemas/info/vaults.ts +262 -0
  248. package/src/src/schemas/mod.ts +121 -0
  249. package/src/src/schemas/subscriptions/requests.ts +514 -0
  250. package/src/src/schemas/subscriptions/responses.ts +576 -0
  251. package/src/src/signing/mod.ts +572 -0
  252. package/src/src/signing/signTypedData/ethers.ts +59 -0
  253. package/src/src/signing/signTypedData/mod.ts +121 -0
  254. package/src/src/signing/signTypedData/private_key.ts +234 -0
  255. package/src/src/signing/signTypedData/viem.ts +55 -0
  256. package/src/src/transports/base.ts +54 -0
  257. package/src/src/transports/http/http_transport.ts +208 -0
  258. package/src/src/transports/websocket/_hyperliquid_event_target.ts +118 -0
  259. package/src/src/transports/websocket/_reconnecting_websocket.ts +404 -0
  260. package/src/src/transports/websocket/_websocket_async_request.ts +229 -0
  261. package/src/src/transports/websocket/websocket_transport.ts +394 -0
  262. package/esm/mod.d.ts +0 -20
  263. package/esm/mod.d.ts.map +0 -1
  264. package/esm/mod.js +0 -11
  265. package/esm/src/errors.d.ts.map +0 -1
  266. package/esm/src/signing/_signTypedData/ethers.d.ts.map +0 -1
  267. package/esm/src/signing/_signTypedData/mod.d.ts.map +0 -1
  268. package/esm/src/signing/_signTypedData/private_key.d.ts.map +0 -1
  269. package/esm/src/signing/_signTypedData/viem.d.ts.map +0 -1
  270. package/script/mod.d.ts +0 -20
  271. package/script/mod.d.ts.map +0 -1
  272. package/script/src/errors.d.ts.map +0 -1
  273. package/script/src/signing/_signTypedData/ethers.d.ts.map +0 -1
  274. package/script/src/signing/_signTypedData/mod.d.ts.map +0 -1
  275. package/script/src/signing/_signTypedData/private_key.d.ts.map +0 -1
  276. package/script/src/signing/_signTypedData/viem.d.ts.map +0 -1
  277. /package/esm/src/signing/{_signTypedData → signTypedData}/ethers.d.ts +0 -0
  278. /package/esm/src/signing/{_signTypedData → signTypedData}/mod.d.ts +0 -0
  279. /package/esm/src/signing/{_signTypedData → signTypedData}/private_key.d.ts +0 -0
  280. /package/esm/src/signing/{_signTypedData → signTypedData}/viem.d.ts +0 -0
  281. /package/script/src/signing/{_signTypedData → signTypedData}/ethers.d.ts +0 -0
  282. /package/script/src/signing/{_signTypedData → signTypedData}/mod.d.ts +0 -0
  283. /package/script/src/signing/{_signTypedData → signTypedData}/private_key.d.ts +0 -0
  284. /package/script/src/signing/{_signTypedData → signTypedData}/viem.d.ts +0 -0
@@ -0,0 +1,572 @@
1
+ /**
2
+ * This module contains functions for generating Hyperliquid transaction signatures.
3
+ *
4
+ * @example Signing an L1 action
5
+ * ```ts
6
+ * import { signL1Action } from "@nktkas/hyperliquid/signing";
7
+ * import { CancelRequest, parser } from "@nktkas/hyperliquid/schemas";
8
+ *
9
+ * const privateKey = "0x..."; // `viem`, `ethers`, or private key directly
10
+ *
11
+ * const action = parser(CancelRequest.entries.action)({ // for correct signature generation
12
+ * type: "cancel",
13
+ * cancels: [
14
+ * { a: 0, o: 12345 },
15
+ * ],
16
+ * });
17
+ * const nonce = Date.now();
18
+ *
19
+ * const signature = await signL1Action({ wallet: privateKey, action, nonce });
20
+ *
21
+ * // Send the signed action to the Hyperliquid API
22
+ * const response = await fetch("https://api.hyperliquid.xyz/exchange", {
23
+ * method: "POST",
24
+ * headers: { "Content-Type": "application/json" },
25
+ * body: JSON.stringify({ action, signature, nonce }),
26
+ * });
27
+ * const body = await response.json();
28
+ * ```
29
+ *
30
+ * @example Signing a user-signed action
31
+ * ```ts
32
+ * import { signUserSignedAction, userSignedActionEip712Types } from "@nktkas/hyperliquid/signing";
33
+ * import { ApproveAgentRequest, parser } from "@nktkas/hyperliquid/schemas";
34
+ *
35
+ * const privateKey = "0x..."; // `viem`, `ethers`, or private key directly
36
+ *
37
+ * const action = parser(ApproveAgentRequest.entries.action)({ // for correct signature generation
38
+ * type: "approveAgent",
39
+ * signatureChainId: "0x66eee",
40
+ * hyperliquidChain: "Mainnet",
41
+ * agentAddress: "0x...",
42
+ * agentName: "Agent",
43
+ * nonce: Date.now(),
44
+ * });
45
+ *
46
+ * const signature = await signUserSignedAction({
47
+ * wallet: privateKey,
48
+ * action,
49
+ * types: userSignedActionEip712Types[action.type],
50
+ * });
51
+ *
52
+ * // Send the signed action to the Hyperliquid API
53
+ * const response = await fetch("https://api.hyperliquid.xyz/exchange", {
54
+ * method: "POST",
55
+ * headers: { "Content-Type": "application/json" },
56
+ * body: JSON.stringify({ action, signature, nonce: action.nonce }),
57
+ * });
58
+ * const body = await response.json();
59
+ * ```
60
+ *
61
+ * @example Signing a multi-signature action
62
+ * ```ts
63
+ * import { signL1Action, signMultiSigAction } from "@nktkas/hyperliquid/signing";
64
+ * import { MultiSigRequest, parser, ScheduleCancelRequest } from "@nktkas/hyperliquid/schemas";
65
+ * import { privateKeyToAccount } from "npm:viem/accounts";
66
+ *
67
+ * const wallet = privateKeyToAccount("0x..."); // or `ethers`, private key directly
68
+ * const multiSigUser = "0x...";
69
+ *
70
+ * const action = parser(ScheduleCancelRequest.entries.action)({ // for correct signature generation
71
+ * type: "scheduleCancel",
72
+ * time: Date.now() + 10000,
73
+ * });
74
+ * const nonce = Date.now();
75
+ *
76
+ * // Create the required number of signatures
77
+ * const signatures = await Promise.all(["0x...", "0x..."].map(async (signerPrivKey) => {
78
+ * return await signL1Action({
79
+ * wallet: signerPrivKey as `0x${string}`,
80
+ * action: [multiSigUser.toLowerCase(), wallet.address.toLowerCase(), action],
81
+ * nonce,
82
+ * });
83
+ * }));
84
+ *
85
+ * // // or user-signed action
86
+ * // const signatures = await Promise.all(["0x...", "0x..."].map(async (signerPrivKey) => {
87
+ * // return await signUserSignedAction({
88
+ * // wallet: signerPrivKey as `0x${string}`,
89
+ * // action: {
90
+ * // ...action,
91
+ * // payloadMultiSigUser: multiSigUser,
92
+ * // outerSigner: wallet.address,
93
+ * // },
94
+ * // types: userSignedActionEip712Types[action.type],
95
+ * // });
96
+ * // }));
97
+ *
98
+ * // Then use signatures in the multi-sig action
99
+ * const multiSigAction = parser(MultiSigRequest.entries.action)({
100
+ * type: "multiSig",
101
+ * signatureChainId: "0x66eee",
102
+ * signatures,
103
+ * payload: {
104
+ * multiSigUser,
105
+ * outerSigner: wallet.address,
106
+ * action,
107
+ * },
108
+ * });
109
+ * const multiSigSignature = await signMultiSigAction({ wallet, action: multiSigAction, nonce });
110
+ *
111
+ * // Send the multi-sig action to the Hyperliquid API
112
+ * const response = await fetch("https://api.hyperliquid.xyz/exchange", {
113
+ * method: "POST",
114
+ * headers: { "Content-Type": "application/json" },
115
+ * body: JSON.stringify({ action: multiSigAction, signature: multiSigSignature, nonce }),
116
+ * });
117
+ * const body = await response.json();
118
+ * ```
119
+ *
120
+ * @module
121
+ */
122
+
123
+ import { keccak_256 } from "@noble/hashes/sha3.js";
124
+ import { etc } from "@noble/secp256k1";
125
+ import { encode as encodeMsgpack } from "@msgpack/msgpack";
126
+ import {
127
+ type AbstractWallet,
128
+ getWalletAddress,
129
+ getWalletChainId,
130
+ type Signature,
131
+ signTypedData,
132
+ } from "./signTypedData/mod.js";
133
+
134
+ export { type AbstractWallet, getWalletAddress, getWalletChainId, type Signature };
135
+
136
+ /** EIP-712 type definitions for user-signed actions. */
137
+ export const userSignedActionEip712Types = {
138
+ approveAgent: {
139
+ "HyperliquidTransaction:ApproveAgent": [
140
+ { name: "hyperliquidChain", type: "string" },
141
+ { name: "agentAddress", type: "address" },
142
+ { name: "agentName", type: "string" },
143
+ { name: "nonce", type: "uint64" },
144
+ ],
145
+ },
146
+ approveBuilderFee: {
147
+ "HyperliquidTransaction:ApproveBuilderFee": [
148
+ { name: "hyperliquidChain", type: "string" },
149
+ { name: "maxFeeRate", type: "string" },
150
+ { name: "builder", type: "address" },
151
+ { name: "nonce", type: "uint64" },
152
+ ],
153
+ },
154
+ cDeposit: {
155
+ "HyperliquidTransaction:CDeposit": [
156
+ { name: "hyperliquidChain", type: "string" },
157
+ { name: "wei", type: "uint64" },
158
+ { name: "nonce", type: "uint64" },
159
+ ],
160
+ },
161
+ convertToMultiSigUser: {
162
+ "HyperliquidTransaction:ConvertToMultiSigUser": [
163
+ { name: "hyperliquidChain", type: "string" },
164
+ { name: "signers", type: "string" },
165
+ { name: "nonce", type: "uint64" },
166
+ ],
167
+ },
168
+ cWithdraw: {
169
+ "HyperliquidTransaction:CWithdraw": [
170
+ { name: "hyperliquidChain", type: "string" },
171
+ { name: "wei", type: "uint64" },
172
+ { name: "nonce", type: "uint64" },
173
+ ],
174
+ },
175
+ multiSig: {
176
+ "HyperliquidTransaction:SendMultiSig": [
177
+ { name: "hyperliquidChain", type: "string" },
178
+ { name: "multiSigActionHash", type: "bytes32" },
179
+ { name: "nonce", type: "uint64" },
180
+ ],
181
+ },
182
+ sendAsset: {
183
+ "HyperliquidTransaction:SendAsset": [
184
+ { name: "hyperliquidChain", type: "string" },
185
+ { name: "destination", type: "string" },
186
+ { name: "sourceDex", type: "string" },
187
+ { name: "destinationDex", type: "string" },
188
+ { name: "token", type: "string" },
189
+ { name: "amount", type: "string" },
190
+ { name: "fromSubAccount", type: "string" },
191
+ { name: "nonce", type: "uint64" },
192
+ ],
193
+ },
194
+ spotSend: {
195
+ "HyperliquidTransaction:SpotSend": [
196
+ { name: "hyperliquidChain", type: "string" },
197
+ { name: "destination", type: "string" },
198
+ { name: "token", type: "string" },
199
+ { name: "amount", type: "string" },
200
+ { name: "time", type: "uint64" },
201
+ ],
202
+ },
203
+ tokenDelegate: {
204
+ "HyperliquidTransaction:TokenDelegate": [
205
+ { name: "hyperliquidChain", type: "string" },
206
+ { name: "validator", type: "address" },
207
+ { name: "wei", type: "uint64" },
208
+ { name: "isUndelegate", type: "bool" },
209
+ { name: "nonce", type: "uint64" },
210
+ ],
211
+ },
212
+ usdClassTransfer: {
213
+ "HyperliquidTransaction:UsdClassTransfer": [
214
+ { name: "hyperliquidChain", type: "string" },
215
+ { name: "amount", type: "string" },
216
+ { name: "toPerp", type: "bool" },
217
+ { name: "nonce", type: "uint64" },
218
+ ],
219
+ },
220
+ usdSend: {
221
+ "HyperliquidTransaction:UsdSend": [
222
+ { name: "hyperliquidChain", type: "string" },
223
+ { name: "destination", type: "string" },
224
+ { name: "amount", type: "string" },
225
+ { name: "time", type: "uint64" },
226
+ ],
227
+ },
228
+ withdraw3: {
229
+ "HyperliquidTransaction:Withdraw": [
230
+ { name: "hyperliquidChain", type: "string" },
231
+ { name: "destination", type: "string" },
232
+ { name: "amount", type: "string" },
233
+ { name: "time", type: "uint64" },
234
+ ],
235
+ },
236
+ };
237
+
238
+ /**
239
+ * Create a hash of the L1 action.
240
+ * @example
241
+ * ```ts
242
+ * import { signL1Action } from "@nktkas/hyperliquid/signing";
243
+ * import { CancelRequest, parser } from "@nktkas/hyperliquid/schemas";
244
+ *
245
+ * const action = parser(CancelRequest.entries.action)({ // for correct signature generation
246
+ * type: "cancel",
247
+ * cancels: [
248
+ * { a: 0, o: 12345 },
249
+ * ],
250
+ * });
251
+ * const nonce = Date.now();
252
+ *
253
+ * const actionHash = createL1ActionHash({ action, nonce });
254
+ * ```
255
+ */
256
+ export function createL1ActionHash(args: {
257
+ /** The action to be hashed (hash depends on key order). */
258
+ action: Record<string, unknown> | unknown[];
259
+ /** The current timestamp in ms. */
260
+ nonce: number;
261
+ /** Optional vault address used in the action. */
262
+ vaultAddress?: `0x${string}`;
263
+ /** Optional expiration time of the action in ms since the epoch. */
264
+ expiresAfter?: number;
265
+ }): `0x${string}` {
266
+ const { action, nonce, vaultAddress, expiresAfter } = args;
267
+
268
+ // 1. Action
269
+ const actionBytes = encodeMsgpack(action);
270
+
271
+ // 2. Nonce
272
+ const nonceBytes = toUint64Bytes(nonce);
273
+
274
+ // 3. Vault address
275
+ const vaultMarker = vaultAddress ? new Uint8Array([1]) : new Uint8Array([0]);
276
+ const vaultBytes = vaultAddress ? etc.hexToBytes(vaultAddress.slice(2)) : new Uint8Array();
277
+
278
+ // 4. Expires after
279
+ const expiresMarker = expiresAfter !== undefined ? new Uint8Array([0]) : new Uint8Array();
280
+ const expiresBytes = expiresAfter !== undefined ? toUint64Bytes(expiresAfter) : new Uint8Array();
281
+
282
+ // Create a hash
283
+ const bytes = etc.concatBytes(
284
+ actionBytes,
285
+ nonceBytes,
286
+ vaultMarker,
287
+ vaultBytes,
288
+ expiresMarker,
289
+ expiresBytes,
290
+ );
291
+ const hash = keccak_256(bytes);
292
+ return `0x${etc.bytesToHex(hash)}`;
293
+ }
294
+
295
+ function toUint64Bytes(n: bigint | number | string): Uint8Array {
296
+ const bytes = new Uint8Array(8);
297
+ new DataView(bytes.buffer).setBigUint64(0, BigInt(n));
298
+ return bytes;
299
+ }
300
+
301
+ /**
302
+ * Sign an L1 action.
303
+ * @example
304
+ * ```ts
305
+ * import { signL1Action } from "@nktkas/hyperliquid/signing";
306
+ * import { CancelRequest, parser } from "@nktkas/hyperliquid/schemas";
307
+ *
308
+ * const privateKey = "0x..."; // `viem`, `ethers`, or private key directly
309
+ *
310
+ * const action = parser(CancelRequest.entries.action)({ // for correct signature generation
311
+ * type: "cancel",
312
+ * cancels: [
313
+ * { a: 0, o: 12345 },
314
+ * ],
315
+ * });
316
+ * const nonce = Date.now();
317
+ *
318
+ * const signature = await signL1Action({ wallet: privateKey, action, nonce });
319
+ *
320
+ * // Send the signed action to the Hyperliquid API
321
+ * const response = await fetch("https://api.hyperliquid.xyz/exchange", {
322
+ * method: "POST",
323
+ * headers: { "Content-Type": "application/json" },
324
+ * body: JSON.stringify({ action, signature, nonce }),
325
+ * });
326
+ * const body = await response.json();
327
+ * ```
328
+ */
329
+ export async function signL1Action(args: {
330
+ /** Wallet to sign the action. */
331
+ wallet: AbstractWallet;
332
+ /** The action to be signed (hash depends on key order). */
333
+ action: Record<string, unknown> | unknown[];
334
+ /** The current timestamp in ms. */
335
+ nonce: number;
336
+ /** Indicates if the action is for the testnet. (default: false) */
337
+ isTestnet?: boolean;
338
+ /** Optional vault address used in the action. */
339
+ vaultAddress?: `0x${string}`;
340
+ /** Optional expiration time of the action in ms since the epoch. */
341
+ expiresAfter?: number;
342
+ }): Promise<Signature> {
343
+ const {
344
+ wallet,
345
+ action,
346
+ nonce,
347
+ isTestnet = false,
348
+ vaultAddress,
349
+ expiresAfter,
350
+ } = args;
351
+
352
+ const actionHash = createL1ActionHash({ action, nonce, vaultAddress, expiresAfter });
353
+ const message = {
354
+ source: isTestnet ? "b" : "a",
355
+ connectionId: actionHash,
356
+ };
357
+
358
+ return await signTypedData({
359
+ wallet,
360
+ domain: {
361
+ name: "Exchange",
362
+ version: "1",
363
+ chainId: 1337, // hyperliquid requires chainId to be 1337
364
+ verifyingContract: "0x0000000000000000000000000000000000000000",
365
+ },
366
+ types: {
367
+ Agent: [
368
+ { name: "source", type: "string" },
369
+ { name: "connectionId", type: "bytes32" },
370
+ ],
371
+ },
372
+ primaryType: "Agent",
373
+ message,
374
+ });
375
+ }
376
+
377
+ /**
378
+ * Sign a user-signed action.
379
+ * @example
380
+ * ```ts
381
+ * import { signUserSignedAction, userSignedActionEip712Types } from "@nktkas/hyperliquid/signing";
382
+ * import { ApproveAgentRequest, parser } from "@nktkas/hyperliquid/schemas";
383
+ *
384
+ * const privateKey = "0x..."; // `viem`, `ethers`, or private key directly
385
+ *
386
+ * const action = parser(ApproveAgentRequest.entries.action)({ // for correct signature generation
387
+ * type: "approveAgent",
388
+ * signatureChainId: "0x66eee",
389
+ * hyperliquidChain: "Mainnet",
390
+ * agentAddress: "0x...",
391
+ * agentName: "Agent",
392
+ * nonce: Date.now(),
393
+ * });
394
+ *
395
+ * const signature = await signUserSignedAction({
396
+ * wallet: privateKey,
397
+ * action,
398
+ * types: userSignedActionEip712Types[action.type],
399
+ * });
400
+ *
401
+ * // Send the signed action to the Hyperliquid API
402
+ * const response = await fetch("https://api.hyperliquid.xyz/exchange", {
403
+ * method: "POST",
404
+ * headers: { "Content-Type": "application/json" },
405
+ * body: JSON.stringify({ action, signature, nonce: action.nonce }),
406
+ * });
407
+ * const body = await response.json();
408
+ * ```
409
+ */
410
+ export async function signUserSignedAction(args: {
411
+ /** Wallet to sign the action. */
412
+ wallet: AbstractWallet;
413
+ /** The action to be signed (hex strings must be in lower case). */
414
+ action:
415
+ & {
416
+ signatureChainId: `0x${string}`;
417
+ [key: string]: unknown;
418
+ }
419
+ // special case for multi-sign payload
420
+ & (
421
+ | { payloadMultiSigUser: `0x${string}`; outerSigner: `0x${string}` }
422
+ | { payloadMultiSigUser?: undefined; outerSigner?: undefined }
423
+ );
424
+ /** The types of the action (hash depends on key order). */
425
+ types: {
426
+ [key: string]: {
427
+ name: string;
428
+ type: string;
429
+ }[];
430
+ };
431
+ }): Promise<Signature> {
432
+ let { wallet, action, types } = args;
433
+
434
+ if (action.type === "approveAgent" && !action.agentName) { // special case for `approveAgent`
435
+ action = { ...action, agentName: "" }; // set to empty string instead of null
436
+ }
437
+ if ("payloadMultiSigUser" in action && "outerSigner" in action) { // special case for multi-sign payload
438
+ types = structuredClone(types); // for safe mutation
439
+ Object.values(types)[0].splice( // array mutation
440
+ 1, // after `hyperliquidChain`
441
+ 0, // do not remove any elements
442
+ { name: "payloadMultiSigUser", type: "address" },
443
+ { name: "outerSigner", type: "address" },
444
+ );
445
+ }
446
+
447
+ return await signTypedData({
448
+ wallet,
449
+ domain: {
450
+ name: "HyperliquidSignTransaction",
451
+ version: "1",
452
+ chainId: parseInt(action.signatureChainId),
453
+ verifyingContract: "0x0000000000000000000000000000000000000000",
454
+ },
455
+ types,
456
+ primaryType: Object.keys(types)[0],
457
+ message: action,
458
+ });
459
+ }
460
+
461
+ /**
462
+ * Sign a multi-signature action.
463
+ * @example
464
+ * ```ts
465
+ * import { signL1Action, signMultiSigAction } from "@nktkas/hyperliquid/signing";
466
+ * import { MultiSigRequest, parser, ScheduleCancelRequest } from "@nktkas/hyperliquid/schemas";
467
+ * import { privateKeyToAccount } from "npm:viem/accounts";
468
+ *
469
+ * const wallet = privateKeyToAccount("0x..."); // or `ethers`, private key directly
470
+ * const multiSigUser = "0x...";
471
+ *
472
+ * const action = parser(ScheduleCancelRequest.entries.action)({ // for correct signature generation
473
+ * type: "scheduleCancel",
474
+ * time: Date.now() + 10000,
475
+ * });
476
+ * const nonce = Date.now();
477
+ *
478
+ * // Create the required number of signatures
479
+ * const signatures = await Promise.all(["0x...", "0x..."].map(async (signerPrivKey) => {
480
+ * return await signL1Action({
481
+ * wallet: signerPrivKey as `0x${string}`,
482
+ * action: [multiSigUser.toLowerCase(), wallet.address.toLowerCase(), action],
483
+ * nonce,
484
+ * });
485
+ * }));
486
+ *
487
+ * // // or user-signed action
488
+ * // const signatures = await Promise.all(["0x...", "0x..."].map(async (signerPrivKey) => {
489
+ * // return await signUserSignedAction({
490
+ * // wallet: signerPrivKey as `0x${string}`,
491
+ * // action: {
492
+ * // ...action,
493
+ * // payloadMultiSigUser: multiSigUser,
494
+ * // outerSigner: wallet.address,
495
+ * // },
496
+ * // types: userSignedActionEip712Types[action.type],
497
+ * // });
498
+ * // }));
499
+ *
500
+ * // Then use signatures in the multi-sig action
501
+ * const multiSigAction = parser(MultiSigRequest.entries.action)({
502
+ * type: "multiSig",
503
+ * signatureChainId: "0x66eee",
504
+ * signatures,
505
+ * payload: {
506
+ * multiSigUser,
507
+ * outerSigner: wallet.address,
508
+ * action,
509
+ * },
510
+ * });
511
+ * const multiSigSignature = await signMultiSigAction({ wallet, action: multiSigAction, nonce });
512
+ *
513
+ * // Send the multi-sig action to the Hyperliquid API
514
+ * const response = await fetch("https://api.hyperliquid.xyz/exchange", {
515
+ * method: "POST",
516
+ * headers: { "Content-Type": "application/json" },
517
+ * body: JSON.stringify({ action: multiSigAction, signature: multiSigSignature, nonce }),
518
+ * });
519
+ * const body = await response.json();
520
+ * ```
521
+ */
522
+ export async function signMultiSigAction(args: {
523
+ /** Wallet to sign the action. */
524
+ wallet: AbstractWallet;
525
+ /** The action to be signed (hash depends on key order). */
526
+ action: {
527
+ signatureChainId: `0x${string}`;
528
+ [key: string]: unknown;
529
+ };
530
+ /** The current timestamp in ms. */
531
+ nonce: number;
532
+ /** Indicates if the action is for the testnet. (default: false) */
533
+ isTestnet?: boolean;
534
+ /** Optional vault address used in the action. */
535
+ vaultAddress?: `0x${string}`;
536
+ /** Optional expiration time of the action in ms since the epoch. */
537
+ expiresAfter?: number;
538
+ }): Promise<Signature> {
539
+ let {
540
+ wallet,
541
+ action,
542
+ nonce,
543
+ isTestnet = false,
544
+ vaultAddress,
545
+ expiresAfter,
546
+ } = args;
547
+
548
+ if ("type" in action) {
549
+ action = structuredClone(action); // for safe mutation
550
+ delete action.type;
551
+ }
552
+
553
+ const multiSigActionHash = createL1ActionHash({ action, nonce, vaultAddress, expiresAfter });
554
+ const message = {
555
+ hyperliquidChain: isTestnet ? "Testnet" : "Mainnet",
556
+ multiSigActionHash,
557
+ nonce,
558
+ };
559
+
560
+ return await signTypedData({
561
+ wallet,
562
+ domain: {
563
+ name: "HyperliquidSignTransaction",
564
+ version: "1",
565
+ chainId: parseInt(action.signatureChainId),
566
+ verifyingContract: "0x0000000000000000000000000000000000000000",
567
+ },
568
+ types: userSignedActionEip712Types.multiSig,
569
+ primaryType: Object.keys(userSignedActionEip712Types.multiSig)[0],
570
+ message,
571
+ });
572
+ }
@@ -0,0 +1,59 @@
1
+ /** Abstract interface for an {@link https://docs.ethers.org/v6/api/providers/#Signer | ethers.js signer}. */
2
+ export interface AbstractEthersV6Signer {
3
+ signTypedData(
4
+ domain: {
5
+ name: string;
6
+ version: string;
7
+ chainId: number;
8
+ verifyingContract: string;
9
+ },
10
+ types: {
11
+ [key: string]: {
12
+ name: string;
13
+ type: string;
14
+ }[];
15
+ },
16
+ value: Record<string, unknown>,
17
+ ): Promise<string>;
18
+ getAddress?(): Promise<string>;
19
+ provider?:
20
+ | { getNetwork(): Promise<{ chainId: number | bigint }> }
21
+ | null;
22
+ }
23
+
24
+ /** Abstract interface for an {@link https://docs.ethers.org/v5/api/signer/ | ethers.js v5 signer}. */
25
+ export interface AbstractEthersV5Signer {
26
+ _signTypedData(
27
+ domain: {
28
+ name: string;
29
+ version: string;
30
+ chainId: number;
31
+ verifyingContract: string;
32
+ },
33
+ types: {
34
+ [key: string]: {
35
+ name: string;
36
+ type: string;
37
+ }[];
38
+ },
39
+ value: Record<string, unknown>,
40
+ ): Promise<string>;
41
+ getAddress?(): Promise<string>;
42
+ provider?:
43
+ | { getNetwork(): Promise<{ chainId: number | bigint }> }
44
+ | null;
45
+ }
46
+
47
+ /** Checks if the given value is an abstract ethers signer. */
48
+ export function isAbstractEthersV6Signer(client: unknown): client is AbstractEthersV6Signer {
49
+ return typeof client === "object" && client !== null &&
50
+ "signTypedData" in client && typeof client.signTypedData === "function" &&
51
+ client.signTypedData.length === 3;
52
+ }
53
+
54
+ /** Checks if the given value is an abstract ethers v5 signer. */
55
+ export function isAbstractEthersV5Signer(client: unknown): client is AbstractEthersV5Signer {
56
+ return typeof client === "object" && client !== null &&
57
+ "_signTypedData" in client && typeof client._signTypedData === "function" &&
58
+ client._signTypedData.length === 3;
59
+ }