@nktkas/hyperliquid 0.22.1 → 0.22.2
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.
- package/README.md +84 -27
- package/esm/mod.d.ts +1 -1
- package/esm/mod.d.ts.map +1 -1
- package/esm/src/clients/exchange.d.ts +136 -166
- package/esm/src/clients/exchange.d.ts.map +1 -1
- package/esm/src/clients/exchange.js +121 -146
- package/esm/src/clients/multiSign.d.ts +121 -280
- package/esm/src/clients/multiSign.d.ts.map +1 -1
- package/esm/src/clients/multiSign.js +123 -246
- package/esm/src/signing/_ethers.d.ts +33 -0
- package/esm/src/signing/_ethers.d.ts.map +1 -0
- package/esm/src/signing/_ethers.js +12 -0
- package/esm/src/signing/_private_key.d.ts +22 -0
- package/esm/src/signing/_private_key.d.ts.map +1 -0
- package/esm/src/signing/_private_key.js +124 -0
- package/esm/src/signing/_sorter.d.ts +154 -0
- package/esm/src/signing/_sorter.d.ts.map +1 -0
- package/esm/src/{signing.js → signing/_sorter.js} +0 -400
- package/esm/src/signing/_viem.d.ts +23 -0
- package/esm/src/signing/_viem.d.ts.map +1 -0
- package/esm/src/signing/_viem.js +6 -0
- package/esm/src/signing/_window.d.ts +23 -0
- package/esm/src/signing/_window.d.ts.map +1 -0
- package/esm/src/signing/_window.js +29 -0
- package/esm/src/signing/mod.d.ts +251 -0
- package/esm/src/signing/mod.d.ts.map +1 -0
- package/esm/src/signing/mod.js +352 -0
- package/package.json +6 -5
- package/script/mod.d.ts +1 -1
- package/script/mod.d.ts.map +1 -1
- package/script/src/clients/exchange.d.ts +136 -166
- package/script/src/clients/exchange.d.ts.map +1 -1
- package/script/src/clients/exchange.js +205 -230
- package/script/src/clients/multiSign.d.ts +121 -280
- package/script/src/clients/multiSign.d.ts.map +1 -1
- package/script/src/clients/multiSign.js +168 -291
- package/script/src/signing/_ethers.d.ts +33 -0
- package/script/src/signing/_ethers.d.ts.map +1 -0
- package/script/src/signing/_ethers.js +26 -0
- package/script/src/signing/_private_key.d.ts +22 -0
- package/script/src/signing/_private_key.d.ts.map +1 -0
- package/script/src/signing/_private_key.js +138 -0
- package/script/src/signing/_sorter.d.ts +154 -0
- package/script/src/signing/_sorter.d.ts.map +1 -0
- package/script/src/{signing.js → signing/_sorter.js} +1 -409
- package/script/src/signing/_viem.d.ts +23 -0
- package/script/src/signing/_viem.d.ts.map +1 -0
- package/script/src/signing/_viem.js +19 -0
- package/script/src/signing/_window.d.ts +23 -0
- package/script/src/signing/_window.d.ts.map +1 -0
- package/script/src/signing/_window.js +43 -0
- package/script/src/signing/mod.d.ts +251 -0
- package/script/src/signing/mod.d.ts.map +1 -0
- package/script/src/signing/mod.js +387 -0
- package/esm/src/signing.d.ts +0 -463
- package/esm/src/signing.d.ts.map +0 -1
- package/script/src/signing.d.ts +0 -463
- package/script/src/signing.d.ts.map +0 -1
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This module contains functions for generating Hyperliquid transaction signatures
|
|
3
|
+
* and interfaces to various wallet implementations.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { signL1Action } from "@nktkas/hyperliquid/signing";
|
|
8
|
+
*
|
|
9
|
+
* const action = {
|
|
10
|
+
* type: "cancel",
|
|
11
|
+
* cancels: [{ a: 0, o: 12345 }],
|
|
12
|
+
* };
|
|
13
|
+
* const nonce = Date.now();
|
|
14
|
+
*
|
|
15
|
+
* const signature = await signL1Action({
|
|
16
|
+
* wallet,
|
|
17
|
+
* action,
|
|
18
|
+
* nonce,
|
|
19
|
+
* isTestnet: true, // Change to false for mainnet
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* import { signUserSignedAction } from "@nktkas/hyperliquid/signing";
|
|
25
|
+
*
|
|
26
|
+
* const action = {
|
|
27
|
+
* type: "approveAgent",
|
|
28
|
+
* hyperliquidChain: "Testnet", // "Mainnet" or "Testnet"
|
|
29
|
+
* signatureChainId: "0x66eee",
|
|
30
|
+
* nonce: Date.now(),
|
|
31
|
+
* agentAddress: "0x...",
|
|
32
|
+
* agentName: "Agent",
|
|
33
|
+
* };
|
|
34
|
+
*
|
|
35
|
+
* const signature = await signUserSignedAction({
|
|
36
|
+
* wallet,
|
|
37
|
+
* action,
|
|
38
|
+
* types: {
|
|
39
|
+
* "HyperliquidTransaction:ApproveAgent": [
|
|
40
|
+
* { name: "hyperliquidChain", type: "string" },
|
|
41
|
+
* { name: "agentAddress", type: "address" },
|
|
42
|
+
* { name: "agentName", type: "string" },
|
|
43
|
+
* { name: "nonce", type: "uint64" },
|
|
44
|
+
* ],
|
|
45
|
+
* },
|
|
46
|
+
* chainId: parseInt(action.signatureChainId, 16),
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @module
|
|
51
|
+
*/
|
|
52
|
+
import { type ValueMap, type ValueType } from "../../deps/jsr.io/@std/msgpack/1.0.3/encode.js";
|
|
53
|
+
import { type AbstractEthersSigner, type AbstractEthersV5Signer, isAbstractEthersSigner, isAbstractEthersV5Signer } from "./_ethers.js";
|
|
54
|
+
import { isValidPrivateKey } from "./_private_key.js";
|
|
55
|
+
import { type AbstractViemWalletClient, isAbstractViemWalletClient } from "./_viem.js";
|
|
56
|
+
import { type AbstractWindowEthereum, isAbstractWindowEthereum } from "./_window.js";
|
|
57
|
+
import type { Hex } from "../base.js";
|
|
58
|
+
export { type AbstractEthersSigner, type AbstractEthersV5Signer, type AbstractViemWalletClient, type AbstractWindowEthereum, type Hex, isAbstractEthersSigner, isAbstractEthersV5Signer, isAbstractViemWalletClient, isAbstractWindowEthereum, isValidPrivateKey, type ValueMap, type ValueType, };
|
|
59
|
+
export * from "./_sorter.js";
|
|
60
|
+
/** Abstract interface for a wallet that can sign typed data. */
|
|
61
|
+
export type AbstractWallet = Hex | AbstractViemWalletClient | AbstractEthersSigner | AbstractEthersV5Signer | AbstractWindowEthereum;
|
|
62
|
+
export interface Signature {
|
|
63
|
+
r: Hex;
|
|
64
|
+
s: Hex;
|
|
65
|
+
v: number;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Create a hash of the L1 action.
|
|
69
|
+
*
|
|
70
|
+
* Note: Hash generation depends on the order of the action keys.
|
|
71
|
+
*
|
|
72
|
+
* @param action - The action to be hashed.
|
|
73
|
+
* @param nonce - Unique request identifier (recommended current timestamp in ms).
|
|
74
|
+
* @param vaultAddress - Optional vault address used in the action.
|
|
75
|
+
* @param expiresAfter - Optional expiration time of the action in milliseconds since the epoch.
|
|
76
|
+
* @returns The hash of the action.
|
|
77
|
+
*/
|
|
78
|
+
export declare function createL1ActionHash(action: ValueType, nonce: number, vaultAddress?: Hex, expiresAfter?: number): Hex;
|
|
79
|
+
/**
|
|
80
|
+
* Sign an L1 action.
|
|
81
|
+
*
|
|
82
|
+
* Note: Signature generation depends on the order of the action keys.
|
|
83
|
+
* @param args - Arguments for signing the action.
|
|
84
|
+
* @returns The signature components r, s, and v.
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* import { signL1Action } from "@nktkas/hyperliquid/signing";
|
|
88
|
+
*
|
|
89
|
+
* const privateKey = "0x..."; // or `viem`, `ethers`
|
|
90
|
+
*
|
|
91
|
+
* const action = {
|
|
92
|
+
* type: "cancel",
|
|
93
|
+
* cancels: [
|
|
94
|
+
* { a: 0, o: 12345 }, // Asset index and order ID
|
|
95
|
+
* ],
|
|
96
|
+
* };
|
|
97
|
+
* const nonce = Date.now();
|
|
98
|
+
*
|
|
99
|
+
* const signature = await signL1Action({
|
|
100
|
+
* wallet: privateKey,
|
|
101
|
+
* action,
|
|
102
|
+
* nonce,
|
|
103
|
+
* isTestnet: true, // Change to false for mainnet
|
|
104
|
+
* });
|
|
105
|
+
*
|
|
106
|
+
* const response = await fetch("https://api.hyperliquid-testnet.xyz/exchange", {
|
|
107
|
+
* method: "POST",
|
|
108
|
+
* headers: { "Content-Type": "application/json" },
|
|
109
|
+
* body: JSON.stringify({ action, signature, nonce }),
|
|
110
|
+
* });
|
|
111
|
+
* const body = await response.json();
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
export declare function signL1Action(args: {
|
|
115
|
+
/** Wallet to sign the action. */
|
|
116
|
+
wallet: AbstractWallet;
|
|
117
|
+
/** The action to be signed. */
|
|
118
|
+
action: ValueType;
|
|
119
|
+
/** Unique request identifier (recommended current timestamp in ms). */
|
|
120
|
+
nonce: number;
|
|
121
|
+
/** Indicates if the action is for the testnet. Default is `false`. */
|
|
122
|
+
isTestnet?: boolean;
|
|
123
|
+
/** Optional vault address used in the action. */
|
|
124
|
+
vaultAddress?: Hex;
|
|
125
|
+
/** Optional expiration time of the action in milliseconds since the epoch. */
|
|
126
|
+
expiresAfter?: number;
|
|
127
|
+
}): Promise<Signature>;
|
|
128
|
+
/**
|
|
129
|
+
* Sign a user-signed action.
|
|
130
|
+
*
|
|
131
|
+
* Note: Signature generation depends on the order of types.
|
|
132
|
+
*
|
|
133
|
+
* @param args - Arguments for signing the action.
|
|
134
|
+
* @returns The signature components r, s, and v.
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* import { signUserSignedAction } from "@nktkas/hyperliquid/signing";
|
|
138
|
+
*
|
|
139
|
+
* const privateKey = "0x..."; // or `viem`, `ethers`
|
|
140
|
+
*
|
|
141
|
+
* const action = {
|
|
142
|
+
* type: "approveAgent",
|
|
143
|
+
* hyperliquidChain: "Testnet", // "Mainnet" or "Testnet"
|
|
144
|
+
* signatureChainId: "0x66eee",
|
|
145
|
+
* nonce: Date.now(),
|
|
146
|
+
* agentAddress: "0x...", // Change to your agent address
|
|
147
|
+
* agentName: "Agent",
|
|
148
|
+
* };
|
|
149
|
+
*
|
|
150
|
+
* const signature = await signUserSignedAction({
|
|
151
|
+
* wallet: privateKey,
|
|
152
|
+
* action,
|
|
153
|
+
* types: {
|
|
154
|
+
* "HyperliquidTransaction:ApproveAgent": [
|
|
155
|
+
* { name: "hyperliquidChain", type: "string" },
|
|
156
|
+
* { name: "agentAddress", type: "address" },
|
|
157
|
+
* { name: "agentName", type: "string" },
|
|
158
|
+
* { name: "nonce", type: "uint64" },
|
|
159
|
+
* ],
|
|
160
|
+
* },
|
|
161
|
+
* chainId: parseInt(action.signatureChainId, 16),
|
|
162
|
+
* });
|
|
163
|
+
*
|
|
164
|
+
* const response = await fetch("https://api.hyperliquid-testnet.xyz/exchange", {
|
|
165
|
+
* method: "POST",
|
|
166
|
+
* headers: { "Content-Type": "application/json" },
|
|
167
|
+
* body: JSON.stringify({ action, signature, nonce: action.nonce }),
|
|
168
|
+
* });
|
|
169
|
+
* const body = await response.json();
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
export declare function signUserSignedAction(args: {
|
|
173
|
+
/** Wallet to sign the action. */
|
|
174
|
+
wallet: AbstractWallet;
|
|
175
|
+
/** The action to be signed. */
|
|
176
|
+
action: Record<string, unknown>;
|
|
177
|
+
/** The types of the action. */
|
|
178
|
+
types: {
|
|
179
|
+
[key: string]: {
|
|
180
|
+
name: string;
|
|
181
|
+
type: string;
|
|
182
|
+
}[];
|
|
183
|
+
};
|
|
184
|
+
/** The chain ID. */
|
|
185
|
+
chainId: number;
|
|
186
|
+
}): Promise<Signature>;
|
|
187
|
+
/**
|
|
188
|
+
* Sign a multi-signature action.
|
|
189
|
+
*
|
|
190
|
+
* Note: Signature generation depends on the order of the action keys.
|
|
191
|
+
*
|
|
192
|
+
* @param args - Arguments for signing the action.
|
|
193
|
+
* @returns The signature components r, s, and v.
|
|
194
|
+
* @example
|
|
195
|
+
* ```ts
|
|
196
|
+
* import { signL1Action, signMultiSigAction } from "@nktkas/hyperliquid/signing";
|
|
197
|
+
* import { privateKeyToAccount } from "viem/accounts";
|
|
198
|
+
*
|
|
199
|
+
* const wallet = privateKeyToAccount("0x...");
|
|
200
|
+
* const multiSigUser = "0x..."; // Multi-sig user address
|
|
201
|
+
*
|
|
202
|
+
* const nonce = Date.now();
|
|
203
|
+
* const action = { // Example action
|
|
204
|
+
* type: "scheduleCancel",
|
|
205
|
+
* time: Date.now() + 10000
|
|
206
|
+
* };
|
|
207
|
+
*
|
|
208
|
+
* // First, create signature from one of the authorized signers
|
|
209
|
+
* const signature = await signL1Action({
|
|
210
|
+
* wallet,
|
|
211
|
+
* action: [multiSigUser.toLowerCase(), wallet.address.toLowerCase(), action],
|
|
212
|
+
* nonce,
|
|
213
|
+
* isTestnet: true,
|
|
214
|
+
* });
|
|
215
|
+
*
|
|
216
|
+
* // Then use it in the multi-sig action
|
|
217
|
+
* const multiSigSignature = await signMultiSigAction({
|
|
218
|
+
* wallet,
|
|
219
|
+
* action: {
|
|
220
|
+
* type: "multiSig",
|
|
221
|
+
* signatureChainId: "0x66eee",
|
|
222
|
+
* signatures: [signature],
|
|
223
|
+
* payload: {
|
|
224
|
+
* multiSigUser,
|
|
225
|
+
* outerSigner: wallet.address,
|
|
226
|
+
* action,
|
|
227
|
+
* }
|
|
228
|
+
* },
|
|
229
|
+
* nonce,
|
|
230
|
+
* hyperliquidChain: "Testnet",
|
|
231
|
+
* signatureChainId: "0x66eee",
|
|
232
|
+
* });
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
export declare function signMultiSigAction(args: {
|
|
236
|
+
/** Wallet to sign the action. */
|
|
237
|
+
wallet: AbstractWallet;
|
|
238
|
+
/** The action to be signed. */
|
|
239
|
+
action: ValueMap;
|
|
240
|
+
/** Unique request identifier (recommended current timestamp in ms). */
|
|
241
|
+
nonce: number;
|
|
242
|
+
/** Optional vault address used in the action. */
|
|
243
|
+
vaultAddress?: Hex;
|
|
244
|
+
/** Optional expiration time of the action in milliseconds since the epoch. */
|
|
245
|
+
expiresAfter?: number;
|
|
246
|
+
/** HyperLiquid network ("Mainnet" or "Testnet"). */
|
|
247
|
+
hyperliquidChain: "Mainnet" | "Testnet";
|
|
248
|
+
/** Chain ID used for signing. */
|
|
249
|
+
signatureChainId: Hex;
|
|
250
|
+
}): Promise<Signature>;
|
|
251
|
+
//# sourceMappingURL=mod.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../../src/src/signing/mod.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This module contains functions for generating Hyperliquid transaction signatures
|
|
3
|
+
* and interfaces to various wallet implementations.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { signL1Action } from "@nktkas/hyperliquid/signing";
|
|
8
|
+
*
|
|
9
|
+
* const action = {
|
|
10
|
+
* type: "cancel",
|
|
11
|
+
* cancels: [{ a: 0, o: 12345 }],
|
|
12
|
+
* };
|
|
13
|
+
* const nonce = Date.now();
|
|
14
|
+
*
|
|
15
|
+
* const signature = await signL1Action({
|
|
16
|
+
* wallet,
|
|
17
|
+
* action,
|
|
18
|
+
* nonce,
|
|
19
|
+
* isTestnet: true, // Change to false for mainnet
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* import { signUserSignedAction } from "@nktkas/hyperliquid/signing";
|
|
25
|
+
*
|
|
26
|
+
* const action = {
|
|
27
|
+
* type: "approveAgent",
|
|
28
|
+
* hyperliquidChain: "Testnet", // "Mainnet" or "Testnet"
|
|
29
|
+
* signatureChainId: "0x66eee",
|
|
30
|
+
* nonce: Date.now(),
|
|
31
|
+
* agentAddress: "0x...",
|
|
32
|
+
* agentName: "Agent",
|
|
33
|
+
* };
|
|
34
|
+
*
|
|
35
|
+
* const signature = await signUserSignedAction({
|
|
36
|
+
* wallet,
|
|
37
|
+
* action,
|
|
38
|
+
* types: {
|
|
39
|
+
* "HyperliquidTransaction:ApproveAgent": [
|
|
40
|
+
* { name: "hyperliquidChain", type: "string" },
|
|
41
|
+
* { name: "agentAddress", type: "address" },
|
|
42
|
+
* { name: "agentName", type: "string" },
|
|
43
|
+
* { name: "nonce", type: "uint64" },
|
|
44
|
+
* ],
|
|
45
|
+
* },
|
|
46
|
+
* chainId: parseInt(action.signatureChainId, 16),
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @module
|
|
51
|
+
*/
|
|
52
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
53
|
+
if (k2 === undefined) k2 = k;
|
|
54
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
55
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
56
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
57
|
+
}
|
|
58
|
+
Object.defineProperty(o, k2, desc);
|
|
59
|
+
}) : (function(o, m, k, k2) {
|
|
60
|
+
if (k2 === undefined) k2 = k;
|
|
61
|
+
o[k2] = m[k];
|
|
62
|
+
}));
|
|
63
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
64
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
65
|
+
};
|
|
66
|
+
(function (factory) {
|
|
67
|
+
if (typeof module === "object" && typeof module.exports === "object") {
|
|
68
|
+
var v = factory(require, exports);
|
|
69
|
+
if (v !== undefined) module.exports = v;
|
|
70
|
+
}
|
|
71
|
+
else if (typeof define === "function" && define.amd) {
|
|
72
|
+
define(["require", "exports", "@noble/hashes/sha3", "../../deps/jsr.io/@std/msgpack/1.0.3/encode.js", "../../deps/jsr.io/@std/encoding/1.0.10/hex.js", "../../deps/jsr.io/@std/bytes/1.0.6/concat.js", "./_ethers.js", "./_private_key.js", "./_viem.js", "./_window.js", "./_sorter.js"], factory);
|
|
73
|
+
}
|
|
74
|
+
})(function (require, exports) {
|
|
75
|
+
"use strict";
|
|
76
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
77
|
+
exports.isValidPrivateKey = exports.isAbstractWindowEthereum = exports.isAbstractViemWalletClient = exports.isAbstractEthersV5Signer = exports.isAbstractEthersSigner = void 0;
|
|
78
|
+
exports.createL1ActionHash = createL1ActionHash;
|
|
79
|
+
exports.signL1Action = signL1Action;
|
|
80
|
+
exports.signUserSignedAction = signUserSignedAction;
|
|
81
|
+
exports.signMultiSigAction = signMultiSigAction;
|
|
82
|
+
const sha3_1 = require("@noble/hashes/sha3");
|
|
83
|
+
const encode_js_1 = require("../../deps/jsr.io/@std/msgpack/1.0.3/encode.js");
|
|
84
|
+
const hex_js_1 = require("../../deps/jsr.io/@std/encoding/1.0.10/hex.js");
|
|
85
|
+
const concat_js_1 = require("../../deps/jsr.io/@std/bytes/1.0.6/concat.js");
|
|
86
|
+
const _ethers_js_1 = require("./_ethers.js");
|
|
87
|
+
Object.defineProperty(exports, "isAbstractEthersSigner", { enumerable: true, get: function () { return _ethers_js_1.isAbstractEthersSigner; } });
|
|
88
|
+
Object.defineProperty(exports, "isAbstractEthersV5Signer", { enumerable: true, get: function () { return _ethers_js_1.isAbstractEthersV5Signer; } });
|
|
89
|
+
const _private_key_js_1 = require("./_private_key.js");
|
|
90
|
+
Object.defineProperty(exports, "isValidPrivateKey", { enumerable: true, get: function () { return _private_key_js_1.isValidPrivateKey; } });
|
|
91
|
+
const _viem_js_1 = require("./_viem.js");
|
|
92
|
+
Object.defineProperty(exports, "isAbstractViemWalletClient", { enumerable: true, get: function () { return _viem_js_1.isAbstractViemWalletClient; } });
|
|
93
|
+
const _window_js_1 = require("./_window.js");
|
|
94
|
+
Object.defineProperty(exports, "isAbstractWindowEthereum", { enumerable: true, get: function () { return _window_js_1.isAbstractWindowEthereum; } });
|
|
95
|
+
__exportStar(require("./_sorter.js"), exports);
|
|
96
|
+
/**
|
|
97
|
+
* Create a hash of the L1 action.
|
|
98
|
+
*
|
|
99
|
+
* Note: Hash generation depends on the order of the action keys.
|
|
100
|
+
*
|
|
101
|
+
* @param action - The action to be hashed.
|
|
102
|
+
* @param nonce - Unique request identifier (recommended current timestamp in ms).
|
|
103
|
+
* @param vaultAddress - Optional vault address used in the action.
|
|
104
|
+
* @param expiresAfter - Optional expiration time of the action in milliseconds since the epoch.
|
|
105
|
+
* @returns The hash of the action.
|
|
106
|
+
*/
|
|
107
|
+
function createL1ActionHash(action, nonce, vaultAddress, expiresAfter) {
|
|
108
|
+
// 1. Action
|
|
109
|
+
const actionBytes = (0, encode_js_1.encode)(normalizeIntegersForMsgPack(action));
|
|
110
|
+
// 2. Nonce
|
|
111
|
+
const nonceBytes = new Uint8Array(8);
|
|
112
|
+
new DataView(nonceBytes.buffer).setBigUint64(0, BigInt(nonce));
|
|
113
|
+
// 3. Vault address
|
|
114
|
+
const vaultMarker = vaultAddress ? Uint8Array.of(1) : Uint8Array.of(0);
|
|
115
|
+
const vaultBytes = vaultAddress ? (0, hex_js_1.decodeHex)(vaultAddress.slice(2)) : new Uint8Array();
|
|
116
|
+
// 4. Expires after
|
|
117
|
+
let expiresMarker;
|
|
118
|
+
let expiresBytes;
|
|
119
|
+
if (expiresAfter !== undefined) {
|
|
120
|
+
expiresMarker = Uint8Array.of(0);
|
|
121
|
+
expiresBytes = new Uint8Array(8);
|
|
122
|
+
new DataView(expiresBytes.buffer).setBigUint64(0, BigInt(expiresAfter));
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
expiresMarker = new Uint8Array();
|
|
126
|
+
expiresBytes = new Uint8Array();
|
|
127
|
+
}
|
|
128
|
+
// Create a keccak256 hash
|
|
129
|
+
const bytes = (0, concat_js_1.concat)([
|
|
130
|
+
actionBytes,
|
|
131
|
+
nonceBytes,
|
|
132
|
+
vaultMarker,
|
|
133
|
+
vaultBytes,
|
|
134
|
+
expiresMarker,
|
|
135
|
+
expiresBytes,
|
|
136
|
+
]);
|
|
137
|
+
const hash = (0, sha3_1.keccak_256)(bytes);
|
|
138
|
+
return `0x${(0, hex_js_1.encodeHex)(hash)}`;
|
|
139
|
+
}
|
|
140
|
+
/** Layer to make {@link https://jsr.io/@std/msgpack | @std/msgpack} compatible with {@link https://github.com/msgpack/msgpack-javascript | @msgpack/msgpack}. */
|
|
141
|
+
function normalizeIntegersForMsgPack(obj) {
|
|
142
|
+
const THIRTY_ONE_BITS = 2147483648;
|
|
143
|
+
const THIRTY_TWO_BITS = 4294967296;
|
|
144
|
+
if (typeof obj === "number" && Number.isInteger(obj) &&
|
|
145
|
+
obj <= Number.MAX_SAFE_INTEGER && obj >= Number.MIN_SAFE_INTEGER &&
|
|
146
|
+
(obj >= THIRTY_TWO_BITS || obj < -THIRTY_ONE_BITS)) {
|
|
147
|
+
return BigInt(obj);
|
|
148
|
+
}
|
|
149
|
+
if (Array.isArray(obj)) {
|
|
150
|
+
return obj.map(normalizeIntegersForMsgPack);
|
|
151
|
+
}
|
|
152
|
+
if (obj && typeof obj === "object" && obj !== null) {
|
|
153
|
+
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, normalizeIntegersForMsgPack(value)]));
|
|
154
|
+
}
|
|
155
|
+
return obj;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Sign an L1 action.
|
|
159
|
+
*
|
|
160
|
+
* Note: Signature generation depends on the order of the action keys.
|
|
161
|
+
* @param args - Arguments for signing the action.
|
|
162
|
+
* @returns The signature components r, s, and v.
|
|
163
|
+
* @example
|
|
164
|
+
* ```ts
|
|
165
|
+
* import { signL1Action } from "@nktkas/hyperliquid/signing";
|
|
166
|
+
*
|
|
167
|
+
* const privateKey = "0x..."; // or `viem`, `ethers`
|
|
168
|
+
*
|
|
169
|
+
* const action = {
|
|
170
|
+
* type: "cancel",
|
|
171
|
+
* cancels: [
|
|
172
|
+
* { a: 0, o: 12345 }, // Asset index and order ID
|
|
173
|
+
* ],
|
|
174
|
+
* };
|
|
175
|
+
* const nonce = Date.now();
|
|
176
|
+
*
|
|
177
|
+
* const signature = await signL1Action({
|
|
178
|
+
* wallet: privateKey,
|
|
179
|
+
* action,
|
|
180
|
+
* nonce,
|
|
181
|
+
* isTestnet: true, // Change to false for mainnet
|
|
182
|
+
* });
|
|
183
|
+
*
|
|
184
|
+
* const response = await fetch("https://api.hyperliquid-testnet.xyz/exchange", {
|
|
185
|
+
* method: "POST",
|
|
186
|
+
* headers: { "Content-Type": "application/json" },
|
|
187
|
+
* body: JSON.stringify({ action, signature, nonce }),
|
|
188
|
+
* });
|
|
189
|
+
* const body = await response.json();
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
async function signL1Action(args) {
|
|
193
|
+
const { wallet, action, nonce, isTestnet = false, vaultAddress, expiresAfter, } = args;
|
|
194
|
+
const domain = {
|
|
195
|
+
name: "Exchange",
|
|
196
|
+
version: "1",
|
|
197
|
+
chainId: 1337, // hyperliquid requires a fixed chain
|
|
198
|
+
verifyingContract: "0x0000000000000000000000000000000000000000",
|
|
199
|
+
};
|
|
200
|
+
const types = {
|
|
201
|
+
Agent: [
|
|
202
|
+
{ name: "source", type: "string" },
|
|
203
|
+
{ name: "connectionId", type: "bytes32" },
|
|
204
|
+
],
|
|
205
|
+
};
|
|
206
|
+
const actionHash = createL1ActionHash(action, nonce, vaultAddress, expiresAfter);
|
|
207
|
+
const message = {
|
|
208
|
+
source: isTestnet ? "b" : "a",
|
|
209
|
+
connectionId: actionHash,
|
|
210
|
+
};
|
|
211
|
+
const signature = await abstractSignTypedData({ wallet, domain, types, message });
|
|
212
|
+
return splitSignature(signature);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Sign a user-signed action.
|
|
216
|
+
*
|
|
217
|
+
* Note: Signature generation depends on the order of types.
|
|
218
|
+
*
|
|
219
|
+
* @param args - Arguments for signing the action.
|
|
220
|
+
* @returns The signature components r, s, and v.
|
|
221
|
+
* @example
|
|
222
|
+
* ```ts
|
|
223
|
+
* import { signUserSignedAction } from "@nktkas/hyperliquid/signing";
|
|
224
|
+
*
|
|
225
|
+
* const privateKey = "0x..."; // or `viem`, `ethers`
|
|
226
|
+
*
|
|
227
|
+
* const action = {
|
|
228
|
+
* type: "approveAgent",
|
|
229
|
+
* hyperliquidChain: "Testnet", // "Mainnet" or "Testnet"
|
|
230
|
+
* signatureChainId: "0x66eee",
|
|
231
|
+
* nonce: Date.now(),
|
|
232
|
+
* agentAddress: "0x...", // Change to your agent address
|
|
233
|
+
* agentName: "Agent",
|
|
234
|
+
* };
|
|
235
|
+
*
|
|
236
|
+
* const signature = await signUserSignedAction({
|
|
237
|
+
* wallet: privateKey,
|
|
238
|
+
* action,
|
|
239
|
+
* types: {
|
|
240
|
+
* "HyperliquidTransaction:ApproveAgent": [
|
|
241
|
+
* { name: "hyperliquidChain", type: "string" },
|
|
242
|
+
* { name: "agentAddress", type: "address" },
|
|
243
|
+
* { name: "agentName", type: "string" },
|
|
244
|
+
* { name: "nonce", type: "uint64" },
|
|
245
|
+
* ],
|
|
246
|
+
* },
|
|
247
|
+
* chainId: parseInt(action.signatureChainId, 16),
|
|
248
|
+
* });
|
|
249
|
+
*
|
|
250
|
+
* const response = await fetch("https://api.hyperliquid-testnet.xyz/exchange", {
|
|
251
|
+
* method: "POST",
|
|
252
|
+
* headers: { "Content-Type": "application/json" },
|
|
253
|
+
* body: JSON.stringify({ action, signature, nonce: action.nonce }),
|
|
254
|
+
* });
|
|
255
|
+
* const body = await response.json();
|
|
256
|
+
* ```
|
|
257
|
+
*/
|
|
258
|
+
async function signUserSignedAction(args) {
|
|
259
|
+
const { wallet, action, types, chainId } = args;
|
|
260
|
+
const domain = {
|
|
261
|
+
name: "HyperliquidSignTransaction",
|
|
262
|
+
version: "1",
|
|
263
|
+
chainId,
|
|
264
|
+
verifyingContract: "0x0000000000000000000000000000000000000000",
|
|
265
|
+
};
|
|
266
|
+
const signature = await abstractSignTypedData({ wallet, domain, types, message: action });
|
|
267
|
+
return splitSignature(signature);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Sign a multi-signature action.
|
|
271
|
+
*
|
|
272
|
+
* Note: Signature generation depends on the order of the action keys.
|
|
273
|
+
*
|
|
274
|
+
* @param args - Arguments for signing the action.
|
|
275
|
+
* @returns The signature components r, s, and v.
|
|
276
|
+
* @example
|
|
277
|
+
* ```ts
|
|
278
|
+
* import { signL1Action, signMultiSigAction } from "@nktkas/hyperliquid/signing";
|
|
279
|
+
* import { privateKeyToAccount } from "viem/accounts";
|
|
280
|
+
*
|
|
281
|
+
* const wallet = privateKeyToAccount("0x...");
|
|
282
|
+
* const multiSigUser = "0x..."; // Multi-sig user address
|
|
283
|
+
*
|
|
284
|
+
* const nonce = Date.now();
|
|
285
|
+
* const action = { // Example action
|
|
286
|
+
* type: "scheduleCancel",
|
|
287
|
+
* time: Date.now() + 10000
|
|
288
|
+
* };
|
|
289
|
+
*
|
|
290
|
+
* // First, create signature from one of the authorized signers
|
|
291
|
+
* const signature = await signL1Action({
|
|
292
|
+
* wallet,
|
|
293
|
+
* action: [multiSigUser.toLowerCase(), wallet.address.toLowerCase(), action],
|
|
294
|
+
* nonce,
|
|
295
|
+
* isTestnet: true,
|
|
296
|
+
* });
|
|
297
|
+
*
|
|
298
|
+
* // Then use it in the multi-sig action
|
|
299
|
+
* const multiSigSignature = await signMultiSigAction({
|
|
300
|
+
* wallet,
|
|
301
|
+
* action: {
|
|
302
|
+
* type: "multiSig",
|
|
303
|
+
* signatureChainId: "0x66eee",
|
|
304
|
+
* signatures: [signature],
|
|
305
|
+
* payload: {
|
|
306
|
+
* multiSigUser,
|
|
307
|
+
* outerSigner: wallet.address,
|
|
308
|
+
* action,
|
|
309
|
+
* }
|
|
310
|
+
* },
|
|
311
|
+
* nonce,
|
|
312
|
+
* hyperliquidChain: "Testnet",
|
|
313
|
+
* signatureChainId: "0x66eee",
|
|
314
|
+
* });
|
|
315
|
+
* ```
|
|
316
|
+
*/
|
|
317
|
+
async function signMultiSigAction(args) {
|
|
318
|
+
const { wallet, action, nonce, hyperliquidChain, signatureChainId, vaultAddress, expiresAfter, } = args;
|
|
319
|
+
const multiSigActionHash = createL1ActionHash(action, nonce, vaultAddress, expiresAfter);
|
|
320
|
+
const message = {
|
|
321
|
+
multiSigActionHash,
|
|
322
|
+
hyperliquidChain,
|
|
323
|
+
signatureChainId,
|
|
324
|
+
nonce,
|
|
325
|
+
};
|
|
326
|
+
return await signUserSignedAction({
|
|
327
|
+
wallet,
|
|
328
|
+
action: message,
|
|
329
|
+
types: {
|
|
330
|
+
"HyperliquidTransaction:SendMultiSig": [
|
|
331
|
+
{ name: "hyperliquidChain", type: "string" },
|
|
332
|
+
{ name: "multiSigActionHash", type: "bytes32" },
|
|
333
|
+
{ name: "nonce", type: "uint64" },
|
|
334
|
+
],
|
|
335
|
+
},
|
|
336
|
+
chainId: parseInt(signatureChainId, 16),
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
/** Signs typed data with the provided wallet using EIP-712. */
|
|
340
|
+
async function abstractSignTypedData(args) {
|
|
341
|
+
const { wallet, domain, types, message } = args;
|
|
342
|
+
if ((0, _private_key_js_1.isValidPrivateKey)(wallet)) {
|
|
343
|
+
return await (0, _private_key_js_1.signTypedDataWithPrivateKey)({
|
|
344
|
+
privateKey: wallet,
|
|
345
|
+
domain,
|
|
346
|
+
types,
|
|
347
|
+
primaryType: Object.keys(types)[0],
|
|
348
|
+
message,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
else if ((0, _viem_js_1.isAbstractViemWalletClient)(wallet)) {
|
|
352
|
+
return await wallet.signTypedData({
|
|
353
|
+
domain,
|
|
354
|
+
types: {
|
|
355
|
+
EIP712Domain: [
|
|
356
|
+
{ name: "name", type: "string" },
|
|
357
|
+
{ name: "version", type: "string" },
|
|
358
|
+
{ name: "chainId", type: "uint256" },
|
|
359
|
+
{ name: "verifyingContract", type: "address" },
|
|
360
|
+
],
|
|
361
|
+
...types,
|
|
362
|
+
},
|
|
363
|
+
primaryType: Object.keys(types)[0],
|
|
364
|
+
message,
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
else if ((0, _ethers_js_1.isAbstractEthersSigner)(wallet)) {
|
|
368
|
+
return await wallet.signTypedData(domain, types, message);
|
|
369
|
+
}
|
|
370
|
+
else if ((0, _ethers_js_1.isAbstractEthersV5Signer)(wallet)) {
|
|
371
|
+
return await wallet._signTypedData(domain, types, message);
|
|
372
|
+
}
|
|
373
|
+
else if ((0, _window_js_1.isAbstractWindowEthereum)(wallet)) {
|
|
374
|
+
return await (0, _window_js_1.signTypedDataWithWindowEthereum)(wallet, domain, types, message);
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
throw new Error("Unsupported wallet for signing typed data");
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
/** Splits a signature hexadecimal string into its components. */
|
|
381
|
+
function splitSignature(signature) {
|
|
382
|
+
const r = `0x${signature.slice(2, 66)}`;
|
|
383
|
+
const s = `0x${signature.slice(66, 130)}`;
|
|
384
|
+
const v = parseInt(signature.slice(130, 132), 16);
|
|
385
|
+
return { r, s, v };
|
|
386
|
+
}
|
|
387
|
+
});
|