@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.
- package/CONTRIBUTING.md +59 -0
- package/LICENSE +21 -0
- package/README.md +363 -0
- package/SECURITY.md +7 -0
- package/esm/deps/jsr.io/@derzade/typescript-event-target/1.1.1/mod.d.ts +2 -0
- package/esm/deps/jsr.io/@derzade/typescript-event-target/1.1.1/mod.d.ts.map +1 -0
- package/esm/deps/jsr.io/@derzade/typescript-event-target/1.1.1/mod.js +1 -0
- package/esm/deps/jsr.io/@derzade/typescript-event-target/1.1.1/src/TypedEventTarget.d.ts +95 -0
- package/esm/deps/jsr.io/@derzade/typescript-event-target/1.1.1/src/TypedEventTarget.d.ts.map +1 -0
- package/esm/deps/jsr.io/@derzade/typescript-event-target/1.1.1/src/TypedEventTarget.js +10 -0
- package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/_assert.d.ts +23 -0
- package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/_assert.d.ts.map +1 -0
- package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/_assert.js +43 -0
- package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/_u64.d.ts +55 -0
- package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/_u64.d.ts.map +1 -0
- package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/_u64.js +65 -0
- package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/crypto.d.ts +2 -0
- package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/crypto.d.ts.map +1 -0
- package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/crypto.js +1 -0
- package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/sha3.d.ts +52 -0
- package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/sha3.d.ts.map +1 -0
- package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/sha3.js +283 -0
- package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/utils.d.ts +120 -0
- package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/utils.d.ts.map +1 -0
- package/esm/deps/jsr.io/@noble/hashes/1.7.1/src/utils.js +211 -0
- package/esm/deps/jsr.io/@std/bytes/1.0.4/concat.d.ts +19 -0
- package/esm/deps/jsr.io/@std/bytes/1.0.4/concat.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/bytes/1.0.4/concat.js +32 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.6/_validate_binary_like.d.ts +2 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.6/_validate_binary_like.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.6/_validate_binary_like.js +26 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.6/hex.d.ts +37 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.6/hex.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.6/hex.js +109 -0
- package/esm/deps/jsr.io/@std/msgpack/1.0.2/encode.d.ts +37 -0
- package/esm/deps/jsr.io/@std/msgpack/1.0.2/encode.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/msgpack/1.0.2/encode.js +237 -0
- package/esm/mod.d.ts +24 -0
- package/esm/mod.d.ts.map +1 -0
- package/esm/mod.js +9 -0
- package/esm/package.json +3 -0
- package/esm/src/clients/event.d.ts +374 -0
- package/esm/src/clients/event.d.ts.map +1 -0
- package/esm/src/clients/event.js +490 -0
- package/esm/src/clients/public.d.ts +695 -0
- package/esm/src/clients/public.d.ts.map +1 -0
- package/esm/src/clients/public.js +704 -0
- package/esm/src/clients/wallet.d.ts +682 -0
- package/esm/src/clients/wallet.d.ts.map +1 -0
- package/esm/src/clients/wallet.js +984 -0
- package/esm/src/transports/base.d.ts +55 -0
- package/esm/src/transports/base.d.ts.map +1 -0
- package/esm/src/transports/base.js +14 -0
- package/esm/src/transports/http/http_transport.d.ts +78 -0
- package/esm/src/transports/http/http_transport.d.ts.map +1 -0
- package/esm/src/transports/http/http_transport.js +170 -0
- package/esm/src/transports/websocket/hyperliquid_event_target.d.ts +66 -0
- package/esm/src/transports/websocket/hyperliquid_event_target.d.ts.map +1 -0
- package/esm/src/transports/websocket/hyperliquid_event_target.js +33 -0
- package/esm/src/transports/websocket/reconnecting_websocket.d.ts +160 -0
- package/esm/src/transports/websocket/reconnecting_websocket.d.ts.map +1 -0
- package/esm/src/transports/websocket/reconnecting_websocket.js +370 -0
- package/esm/src/transports/websocket/websocket_request_dispatcher.d.ts +63 -0
- package/esm/src/transports/websocket/websocket_request_dispatcher.d.ts.map +1 -0
- package/esm/src/transports/websocket/websocket_request_dispatcher.js +201 -0
- package/esm/src/transports/websocket/websocket_transport.d.ts +117 -0
- package/esm/src/transports/websocket/websocket_transport.d.ts.map +1 -0
- package/esm/src/transports/websocket/websocket_transport.js +233 -0
- package/esm/src/utils/key_sort.d.ts +21 -0
- package/esm/src/utils/key_sort.d.ts.map +1 -0
- package/esm/src/utils/key_sort.js +124 -0
- package/esm/src/utils/signing.d.ts +109 -0
- package/esm/src/utils/signing.d.ts.map +1 -0
- package/esm/src/utils/signing.js +164 -0
- package/package.json +34 -0
- package/script/deps/jsr.io/@derzade/typescript-event-target/1.1.1/mod.d.ts +2 -0
- package/script/deps/jsr.io/@derzade/typescript-event-target/1.1.1/mod.d.ts.map +1 -0
- package/script/deps/jsr.io/@derzade/typescript-event-target/1.1.1/mod.js +17 -0
- package/script/deps/jsr.io/@derzade/typescript-event-target/1.1.1/src/TypedEventTarget.d.ts +95 -0
- package/script/deps/jsr.io/@derzade/typescript-event-target/1.1.1/src/TypedEventTarget.d.ts.map +1 -0
- package/script/deps/jsr.io/@derzade/typescript-event-target/1.1.1/src/TypedEventTarget.js +14 -0
- package/script/deps/jsr.io/@noble/hashes/1.7.1/src/_assert.d.ts +23 -0
- package/script/deps/jsr.io/@noble/hashes/1.7.1/src/_assert.d.ts.map +1 -0
- package/script/deps/jsr.io/@noble/hashes/1.7.1/src/_assert.js +49 -0
- package/script/deps/jsr.io/@noble/hashes/1.7.1/src/_u64.d.ts +55 -0
- package/script/deps/jsr.io/@noble/hashes/1.7.1/src/_u64.d.ts.map +1 -0
- package/script/deps/jsr.io/@noble/hashes/1.7.1/src/_u64.js +88 -0
- package/script/deps/jsr.io/@noble/hashes/1.7.1/src/crypto.d.ts +2 -0
- package/script/deps/jsr.io/@noble/hashes/1.7.1/src/crypto.d.ts.map +1 -0
- package/script/deps/jsr.io/@noble/hashes/1.7.1/src/crypto.js +4 -0
- package/script/deps/jsr.io/@noble/hashes/1.7.1/src/sha3.d.ts +52 -0
- package/script/deps/jsr.io/@noble/hashes/1.7.1/src/sha3.d.ts.map +1 -0
- package/script/deps/jsr.io/@noble/hashes/1.7.1/src/sha3.js +288 -0
- package/script/deps/jsr.io/@noble/hashes/1.7.1/src/utils.d.ts +120 -0
- package/script/deps/jsr.io/@noble/hashes/1.7.1/src/utils.d.ts.map +1 -0
- package/script/deps/jsr.io/@noble/hashes/1.7.1/src/utils.js +235 -0
- package/script/deps/jsr.io/@std/bytes/1.0.4/concat.d.ts +19 -0
- package/script/deps/jsr.io/@std/bytes/1.0.4/concat.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/bytes/1.0.4/concat.js +35 -0
- package/script/deps/jsr.io/@std/encoding/1.0.6/_validate_binary_like.d.ts +2 -0
- package/script/deps/jsr.io/@std/encoding/1.0.6/_validate_binary_like.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/encoding/1.0.6/_validate_binary_like.js +29 -0
- package/script/deps/jsr.io/@std/encoding/1.0.6/hex.d.ts +37 -0
- package/script/deps/jsr.io/@std/encoding/1.0.6/hex.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/encoding/1.0.6/hex.js +113 -0
- package/script/deps/jsr.io/@std/msgpack/1.0.2/encode.d.ts +37 -0
- package/script/deps/jsr.io/@std/msgpack/1.0.2/encode.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/msgpack/1.0.2/encode.js +240 -0
- package/script/mod.d.ts +24 -0
- package/script/mod.d.ts.map +1 -0
- package/script/mod.js +27 -0
- package/script/package.json +3 -0
- package/script/src/clients/event.d.ts +374 -0
- package/script/src/clients/event.d.ts.map +1 -0
- package/script/src/clients/event.js +494 -0
- package/script/src/clients/public.d.ts +695 -0
- package/script/src/clients/public.d.ts.map +1 -0
- package/script/src/clients/public.js +708 -0
- package/script/src/clients/wallet.d.ts +682 -0
- package/script/src/clients/wallet.d.ts.map +1 -0
- package/script/src/clients/wallet.js +989 -0
- package/script/src/transports/base.d.ts +55 -0
- package/script/src/transports/base.d.ts.map +1 -0
- package/script/src/transports/base.js +18 -0
- package/script/src/transports/http/http_transport.d.ts +78 -0
- package/script/src/transports/http/http_transport.d.ts.map +1 -0
- package/script/src/transports/http/http_transport.js +175 -0
- package/script/src/transports/websocket/hyperliquid_event_target.d.ts +66 -0
- package/script/src/transports/websocket/hyperliquid_event_target.d.ts.map +1 -0
- package/script/src/transports/websocket/hyperliquid_event_target.js +37 -0
- package/script/src/transports/websocket/reconnecting_websocket.d.ts +160 -0
- package/script/src/transports/websocket/reconnecting_websocket.d.ts.map +1 -0
- package/script/src/transports/websocket/reconnecting_websocket.js +374 -0
- package/script/src/transports/websocket/websocket_request_dispatcher.d.ts +63 -0
- package/script/src/transports/websocket/websocket_request_dispatcher.d.ts.map +1 -0
- package/script/src/transports/websocket/websocket_request_dispatcher.js +206 -0
- package/script/src/transports/websocket/websocket_transport.d.ts +117 -0
- package/script/src/transports/websocket/websocket_transport.d.ts.map +1 -0
- package/script/src/transports/websocket/websocket_transport.js +237 -0
- package/script/src/utils/key_sort.d.ts +21 -0
- package/script/src/utils/key_sort.d.ts.map +1 -0
- package/script/src/utils/key_sort.js +127 -0
- package/script/src/utils/signing.d.ts +109 -0
- package/script/src/utils/signing.d.ts.map +1 -0
- 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
|
+
}
|