opentool 0.7.13 → 0.8.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/dist/adapters/hyperliquid/index.d.ts +414 -0
- package/dist/adapters/hyperliquid/index.js +1411 -0
- package/dist/adapters/hyperliquid/index.js.map +1 -0
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/index.js +74 -8
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1527 -98
- package/dist/index.js.map +1 -1
- package/dist/store/index.d.ts +24 -1
- package/dist/store/index.js +45 -2
- package/dist/store/index.js.map +1 -1
- package/dist/{wallets/index.d.ts → types-BVLpaY4O.d.ts} +7 -24
- package/dist/wallet/index.d.ts +29 -0
- package/dist/{wallets → wallet}/index.js +65 -19
- package/dist/wallet/index.js.map +1 -0
- package/package.json +11 -8
- package/dist/wallets/index.js.map +0 -1
|
@@ -0,0 +1,1411 @@
|
|
|
1
|
+
import { parseUnits, encodeFunctionData, erc20Abi } from 'viem';
|
|
2
|
+
import { encode } from '@msgpack/msgpack';
|
|
3
|
+
import { keccak_256 } from '@noble/hashes/sha3';
|
|
4
|
+
import { hexToBytes, concatBytes, bytesToHex } from '@noble/hashes/utils';
|
|
5
|
+
|
|
6
|
+
// src/adapters/hyperliquid/index.ts
|
|
7
|
+
|
|
8
|
+
// src/store/index.ts
|
|
9
|
+
var StoreError = class extends Error {
|
|
10
|
+
constructor(message, status, causeData) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.status = status;
|
|
13
|
+
this.causeData = causeData;
|
|
14
|
+
this.name = "StoreError";
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
function resolveConfig(options) {
|
|
18
|
+
const baseUrl = options?.baseUrl ?? process.env.BASE_URL ?? "https://api.openpond.ai";
|
|
19
|
+
const apiKey = options?.apiKey ?? process.env.OPENPOND_API_KEY;
|
|
20
|
+
if (!baseUrl) {
|
|
21
|
+
throw new StoreError("BASE_URL is required to store activity events");
|
|
22
|
+
}
|
|
23
|
+
if (!apiKey) {
|
|
24
|
+
throw new StoreError(
|
|
25
|
+
"OPENPOND_API_KEY is required to store activity events"
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
const normalizedBaseUrl = baseUrl.replace(/\/$/, "");
|
|
29
|
+
const fetchFn = options?.fetchFn ?? globalThis.fetch;
|
|
30
|
+
if (!fetchFn) {
|
|
31
|
+
throw new StoreError("Fetch is not available in this environment");
|
|
32
|
+
}
|
|
33
|
+
return { baseUrl: normalizedBaseUrl, apiKey, fetchFn };
|
|
34
|
+
}
|
|
35
|
+
async function store(input, options) {
|
|
36
|
+
const { baseUrl, apiKey, fetchFn } = resolveConfig(options);
|
|
37
|
+
const url = `${baseUrl}/apps/positions/tx`;
|
|
38
|
+
let response;
|
|
39
|
+
try {
|
|
40
|
+
response = await fetchFn(url, {
|
|
41
|
+
method: "POST",
|
|
42
|
+
headers: {
|
|
43
|
+
"content-type": "application/json",
|
|
44
|
+
"openpond-api-key": apiKey
|
|
45
|
+
},
|
|
46
|
+
body: JSON.stringify(input)
|
|
47
|
+
});
|
|
48
|
+
} catch (error) {
|
|
49
|
+
throw new StoreError("Failed to reach store endpoint", void 0, error);
|
|
50
|
+
}
|
|
51
|
+
if (!response.ok) {
|
|
52
|
+
let body;
|
|
53
|
+
try {
|
|
54
|
+
body = await response.json();
|
|
55
|
+
} catch {
|
|
56
|
+
body = await response.text().catch(() => void 0);
|
|
57
|
+
}
|
|
58
|
+
throw new StoreError(
|
|
59
|
+
`Store request failed with status ${response.status}`,
|
|
60
|
+
response.status,
|
|
61
|
+
body
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
const data = await response.json();
|
|
66
|
+
return {
|
|
67
|
+
id: data.id ?? "",
|
|
68
|
+
status: data.status ?? null
|
|
69
|
+
};
|
|
70
|
+
} catch {
|
|
71
|
+
return { id: "", status: null };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
75
|
+
var API_BASES = {
|
|
76
|
+
mainnet: "https://api.hyperliquid.xyz",
|
|
77
|
+
testnet: "https://api.hyperliquid-testnet.xyz"
|
|
78
|
+
};
|
|
79
|
+
var HL_ENDPOINT = {
|
|
80
|
+
mainnet: "https://api.hyperliquid.xyz",
|
|
81
|
+
testnet: "https://api.hyperliquid-testnet.xyz"
|
|
82
|
+
};
|
|
83
|
+
var HL_CHAIN_LABEL = {
|
|
84
|
+
mainnet: "Mainnet",
|
|
85
|
+
testnet: "Testnet"
|
|
86
|
+
};
|
|
87
|
+
var HL_BRIDGE_ADDRESSES = {
|
|
88
|
+
mainnet: "0x2df1c51e09aecf9cacb7bc98cb1742757f163df7",
|
|
89
|
+
testnet: "0x08cfc1b6b2dcf36a1480b99353a354aa8ac56f89"
|
|
90
|
+
};
|
|
91
|
+
var HL_USDC_ADDRESSES = {
|
|
92
|
+
mainnet: "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
|
|
93
|
+
testnet: "0x1baAbB04529D43a73232B713C0FE471f7c7334d5"
|
|
94
|
+
};
|
|
95
|
+
var HL_SIGNATURE_CHAIN_ID = {
|
|
96
|
+
mainnet: "0xa4b1",
|
|
97
|
+
testnet: "0x66eee"
|
|
98
|
+
};
|
|
99
|
+
var EXCHANGE_TYPED_DATA_DOMAIN = {
|
|
100
|
+
name: "Exchange",
|
|
101
|
+
version: "1",
|
|
102
|
+
chainId: 1337,
|
|
103
|
+
verifyingContract: "0x0000000000000000000000000000000000000000"
|
|
104
|
+
};
|
|
105
|
+
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
106
|
+
var MIN_DEPOSIT_USDC = 5;
|
|
107
|
+
var BUILDER_CODE = {
|
|
108
|
+
address: "0x4b2aec4F91612849d6e20C9c1881FabB1A48cd12",
|
|
109
|
+
fee: 100
|
|
110
|
+
};
|
|
111
|
+
var metaCache = /* @__PURE__ */ new Map();
|
|
112
|
+
var HyperliquidApiError = class extends Error {
|
|
113
|
+
constructor(message, response) {
|
|
114
|
+
super(message);
|
|
115
|
+
this.response = response;
|
|
116
|
+
this.name = "HyperliquidApiError";
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
var HyperliquidGuardError = class extends Error {
|
|
120
|
+
constructor(message) {
|
|
121
|
+
super(message);
|
|
122
|
+
this.name = "HyperliquidGuardError";
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
var HyperliquidTermsError = class extends HyperliquidGuardError {
|
|
126
|
+
constructor(message = "Hyperliquid terms must be accepted before proceeding.") {
|
|
127
|
+
super(message);
|
|
128
|
+
this.name = "HyperliquidTermsError";
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
var HyperliquidBuilderApprovalError = class extends HyperliquidGuardError {
|
|
132
|
+
constructor(message = "Hyperliquid builder approval is required before using builder codes.") {
|
|
133
|
+
super(message);
|
|
134
|
+
this.name = "HyperliquidBuilderApprovalError";
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
function createMonotonicNonceFactory(start = Date.now()) {
|
|
138
|
+
let last = start;
|
|
139
|
+
return () => {
|
|
140
|
+
const now = Date.now();
|
|
141
|
+
if (now > last) {
|
|
142
|
+
last = now;
|
|
143
|
+
} else {
|
|
144
|
+
last += 1;
|
|
145
|
+
}
|
|
146
|
+
return last;
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
async function getUniverse(args) {
|
|
150
|
+
const cacheKey = `${args.environment}:${args.baseUrl}`;
|
|
151
|
+
const cached = metaCache.get(cacheKey);
|
|
152
|
+
if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
|
|
153
|
+
return cached.universe;
|
|
154
|
+
}
|
|
155
|
+
const response = await args.fetcher(`${args.baseUrl}/info`, {
|
|
156
|
+
method: "POST",
|
|
157
|
+
headers: { "content-type": "application/json" },
|
|
158
|
+
body: JSON.stringify({ type: "meta" })
|
|
159
|
+
});
|
|
160
|
+
const json = await response.json().catch(() => null);
|
|
161
|
+
if (!response.ok || !json?.universe) {
|
|
162
|
+
throw new HyperliquidApiError(
|
|
163
|
+
"Unable to load Hyperliquid metadata.",
|
|
164
|
+
json ?? { status: response.status }
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
metaCache.set(cacheKey, { fetchedAt: Date.now(), universe: json.universe });
|
|
168
|
+
return json.universe;
|
|
169
|
+
}
|
|
170
|
+
function resolveAssetIndex(symbol, universe) {
|
|
171
|
+
const [raw] = symbol.split("-");
|
|
172
|
+
const target = raw.trim();
|
|
173
|
+
const index = universe.findIndex(
|
|
174
|
+
(entry) => entry.name.toUpperCase() === target.toUpperCase()
|
|
175
|
+
);
|
|
176
|
+
if (index === -1) {
|
|
177
|
+
throw new Error(`Unknown Hyperliquid asset symbol: ${symbol}`);
|
|
178
|
+
}
|
|
179
|
+
return index;
|
|
180
|
+
}
|
|
181
|
+
function toApiDecimal(value) {
|
|
182
|
+
if (typeof value === "string") {
|
|
183
|
+
return value;
|
|
184
|
+
}
|
|
185
|
+
if (typeof value === "bigint") {
|
|
186
|
+
return value.toString();
|
|
187
|
+
}
|
|
188
|
+
if (!Number.isFinite(value)) {
|
|
189
|
+
throw new Error("Numeric values must be finite.");
|
|
190
|
+
}
|
|
191
|
+
const asString = value.toString();
|
|
192
|
+
if (/e/i.test(asString)) {
|
|
193
|
+
const [mantissa, exponentPart] = asString.split(/e/i);
|
|
194
|
+
const exponent = Number(exponentPart);
|
|
195
|
+
const [integerPart, fractionalPart = ""] = mantissa.split(".");
|
|
196
|
+
if (exponent >= 0) {
|
|
197
|
+
return integerPart + fractionalPart.padEnd(exponent + fractionalPart.length, "0");
|
|
198
|
+
}
|
|
199
|
+
const zeros = "0".repeat(Math.abs(exponent) - 1);
|
|
200
|
+
return `0.${zeros}${integerPart}${fractionalPart}`.replace(/\.0+$/, "");
|
|
201
|
+
}
|
|
202
|
+
return asString;
|
|
203
|
+
}
|
|
204
|
+
function normalizeHex(value) {
|
|
205
|
+
const lower = value.toLowerCase();
|
|
206
|
+
return lower.replace(/^0x0+/, "0x") || "0x0";
|
|
207
|
+
}
|
|
208
|
+
function normalizeAddress(value) {
|
|
209
|
+
return normalizeHex(value);
|
|
210
|
+
}
|
|
211
|
+
async function signL1Action(args) {
|
|
212
|
+
const { wallet, action, nonce, vaultAddress, expiresAfter, isTestnet } = args;
|
|
213
|
+
const actionHash = createL1ActionHash({
|
|
214
|
+
action,
|
|
215
|
+
nonce,
|
|
216
|
+
vaultAddress,
|
|
217
|
+
expiresAfter
|
|
218
|
+
});
|
|
219
|
+
const message = {
|
|
220
|
+
source: isTestnet ? "b" : "a",
|
|
221
|
+
connectionId: actionHash
|
|
222
|
+
};
|
|
223
|
+
const signatureHex = await wallet.walletClient.signTypedData({
|
|
224
|
+
account: wallet.account,
|
|
225
|
+
domain: EXCHANGE_TYPED_DATA_DOMAIN,
|
|
226
|
+
types: {
|
|
227
|
+
Agent: [
|
|
228
|
+
{ name: "source", type: "string" },
|
|
229
|
+
{ name: "connectionId", type: "bytes32" }
|
|
230
|
+
]
|
|
231
|
+
},
|
|
232
|
+
primaryType: "Agent",
|
|
233
|
+
message
|
|
234
|
+
});
|
|
235
|
+
return splitSignature(signatureHex);
|
|
236
|
+
}
|
|
237
|
+
async function signSpotSend(args) {
|
|
238
|
+
const {
|
|
239
|
+
wallet,
|
|
240
|
+
hyperliquidChain,
|
|
241
|
+
signatureChainId,
|
|
242
|
+
destination,
|
|
243
|
+
token,
|
|
244
|
+
amount,
|
|
245
|
+
time
|
|
246
|
+
} = args;
|
|
247
|
+
const domain = {
|
|
248
|
+
name: "HyperliquidSignTransaction",
|
|
249
|
+
version: "1",
|
|
250
|
+
chainId: Number.parseInt(signatureChainId, 16),
|
|
251
|
+
verifyingContract: ZERO_ADDRESS
|
|
252
|
+
};
|
|
253
|
+
const message = {
|
|
254
|
+
hyperliquidChain,
|
|
255
|
+
destination,
|
|
256
|
+
token,
|
|
257
|
+
amount,
|
|
258
|
+
time
|
|
259
|
+
};
|
|
260
|
+
const types = {
|
|
261
|
+
"HyperliquidTransaction:SpotSend": [
|
|
262
|
+
{ name: "hyperliquidChain", type: "string" },
|
|
263
|
+
{ name: "destination", type: "string" },
|
|
264
|
+
{ name: "token", type: "string" },
|
|
265
|
+
{ name: "amount", type: "string" },
|
|
266
|
+
{ name: "time", type: "uint64" }
|
|
267
|
+
]
|
|
268
|
+
};
|
|
269
|
+
const signatureHex = await wallet.walletClient.signTypedData({
|
|
270
|
+
account: wallet.account,
|
|
271
|
+
domain,
|
|
272
|
+
types,
|
|
273
|
+
primaryType: "HyperliquidTransaction:SpotSend",
|
|
274
|
+
message
|
|
275
|
+
});
|
|
276
|
+
return splitSignature(signatureHex);
|
|
277
|
+
}
|
|
278
|
+
async function signApproveBuilderFee(args) {
|
|
279
|
+
const { wallet, maxFeeRate, nonce, signatureChainId, isTestnet } = args;
|
|
280
|
+
const hyperliquidChain = isTestnet ? "Testnet" : "Mainnet";
|
|
281
|
+
const domain = {
|
|
282
|
+
name: "HyperliquidSignTransaction",
|
|
283
|
+
version: "1",
|
|
284
|
+
chainId: Number.parseInt(signatureChainId, 16),
|
|
285
|
+
verifyingContract: ZERO_ADDRESS
|
|
286
|
+
};
|
|
287
|
+
const message = {
|
|
288
|
+
hyperliquidChain,
|
|
289
|
+
maxFeeRate,
|
|
290
|
+
builder: BUILDER_CODE.address,
|
|
291
|
+
nonce
|
|
292
|
+
};
|
|
293
|
+
const types = {
|
|
294
|
+
"HyperliquidTransaction:ApproveBuilderFee": [
|
|
295
|
+
{ name: "hyperliquidChain", type: "string" },
|
|
296
|
+
{ name: "maxFeeRate", type: "string" },
|
|
297
|
+
{ name: "builder", type: "address" },
|
|
298
|
+
{ name: "nonce", type: "uint64" }
|
|
299
|
+
]
|
|
300
|
+
};
|
|
301
|
+
const signatureHex = await wallet.walletClient.signTypedData({
|
|
302
|
+
account: wallet.account,
|
|
303
|
+
domain,
|
|
304
|
+
types,
|
|
305
|
+
primaryType: "HyperliquidTransaction:ApproveBuilderFee",
|
|
306
|
+
message
|
|
307
|
+
});
|
|
308
|
+
return splitSignature(signatureHex);
|
|
309
|
+
}
|
|
310
|
+
function splitSignature(signature) {
|
|
311
|
+
const cleaned = signature.slice(2);
|
|
312
|
+
const rHex = `0x${cleaned.slice(0, 64)}`;
|
|
313
|
+
const sHex = `0x${cleaned.slice(64, 128)}`;
|
|
314
|
+
let v = parseInt(cleaned.slice(128, 130), 16);
|
|
315
|
+
if (Number.isNaN(v)) {
|
|
316
|
+
throw new Error("Invalid signature returned by wallet client.");
|
|
317
|
+
}
|
|
318
|
+
if (v < 27) {
|
|
319
|
+
v += 27;
|
|
320
|
+
}
|
|
321
|
+
const normalizedV = v === 27 || v === 28 ? v : v % 2 ? 27 : 28;
|
|
322
|
+
return {
|
|
323
|
+
r: normalizeHex(rHex),
|
|
324
|
+
s: normalizeHex(sHex),
|
|
325
|
+
v: normalizedV
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
function createL1ActionHash(args) {
|
|
329
|
+
const { action, nonce, vaultAddress, expiresAfter } = args;
|
|
330
|
+
const actionBytes = encode(action, { ignoreUndefined: true });
|
|
331
|
+
const nonceBytes = toUint64Bytes(nonce);
|
|
332
|
+
const vaultMarker = vaultAddress ? new Uint8Array([1]) : new Uint8Array([0]);
|
|
333
|
+
const vaultBytes = vaultAddress ? hexToBytes(vaultAddress.slice(2)) : new Uint8Array();
|
|
334
|
+
const hasExpiresAfter = typeof expiresAfter === "number";
|
|
335
|
+
const expiresMarker = hasExpiresAfter ? new Uint8Array([0]) : new Uint8Array();
|
|
336
|
+
const expiresBytes = hasExpiresAfter && expiresAfter !== void 0 ? toUint64Bytes(expiresAfter) : new Uint8Array();
|
|
337
|
+
const bytes = concatBytes(
|
|
338
|
+
actionBytes,
|
|
339
|
+
nonceBytes,
|
|
340
|
+
vaultMarker,
|
|
341
|
+
vaultBytes,
|
|
342
|
+
expiresMarker,
|
|
343
|
+
expiresBytes
|
|
344
|
+
);
|
|
345
|
+
const hash = keccak_256(bytes);
|
|
346
|
+
return `0x${bytesToHex(hash)}`;
|
|
347
|
+
}
|
|
348
|
+
function toUint64Bytes(value) {
|
|
349
|
+
const bytes = new Uint8Array(8);
|
|
350
|
+
new DataView(bytes.buffer).setBigUint64(0, BigInt(value));
|
|
351
|
+
return bytes;
|
|
352
|
+
}
|
|
353
|
+
function getBridgeAddress(env) {
|
|
354
|
+
const override = process.env.HYPERLIQUID_BRIDGE_ADDRESS;
|
|
355
|
+
if (override?.trim()) {
|
|
356
|
+
return normalizeAddress(override);
|
|
357
|
+
}
|
|
358
|
+
return HL_BRIDGE_ADDRESSES[env];
|
|
359
|
+
}
|
|
360
|
+
function getUsdcAddress(env) {
|
|
361
|
+
const override = process.env.HYPERLIQUID_USDC_ADDRESS;
|
|
362
|
+
if (override?.trim()) {
|
|
363
|
+
return normalizeAddress(override);
|
|
364
|
+
}
|
|
365
|
+
return HL_USDC_ADDRESSES[env];
|
|
366
|
+
}
|
|
367
|
+
function getSignatureChainId(env) {
|
|
368
|
+
const override = process.env.HYPERLIQUID_SIGNATURE_CHAIN_ID;
|
|
369
|
+
const selected = override?.trim() || HL_SIGNATURE_CHAIN_ID[env];
|
|
370
|
+
return normalizeHex(selected);
|
|
371
|
+
}
|
|
372
|
+
function assertPositiveNumber(value, label) {
|
|
373
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
374
|
+
throw new Error(`${label} must be a positive number.`);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// src/adapters/hyperliquid/exchange.ts
|
|
379
|
+
var HyperliquidExchangeClient = class {
|
|
380
|
+
constructor(args) {
|
|
381
|
+
this.wallet = args.wallet;
|
|
382
|
+
this.environment = args.environment ?? "mainnet";
|
|
383
|
+
this.vaultAddress = args.vaultAddress;
|
|
384
|
+
this.expiresAfter = args.expiresAfter;
|
|
385
|
+
const resolvedNonceSource = args.walletNonceProvider ?? args.wallet.nonceSource ?? args.nonceSource;
|
|
386
|
+
if (!resolvedNonceSource) {
|
|
387
|
+
throw new Error(
|
|
388
|
+
"Wallet nonce source is required for Hyperliquid exchange actions."
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
this.nonceSource = resolvedNonceSource;
|
|
392
|
+
}
|
|
393
|
+
cancel(cancels) {
|
|
394
|
+
return cancelHyperliquidOrders({
|
|
395
|
+
wallet: this.wallet,
|
|
396
|
+
cancels,
|
|
397
|
+
environment: this.environment,
|
|
398
|
+
vaultAddress: this.vaultAddress,
|
|
399
|
+
expiresAfter: this.expiresAfter,
|
|
400
|
+
nonceSource: this.nonceSource
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
cancelByCloid(cancels) {
|
|
404
|
+
return cancelHyperliquidOrdersByCloid({
|
|
405
|
+
wallet: this.wallet,
|
|
406
|
+
cancels,
|
|
407
|
+
environment: this.environment,
|
|
408
|
+
vaultAddress: this.vaultAddress,
|
|
409
|
+
expiresAfter: this.expiresAfter,
|
|
410
|
+
nonceSource: this.nonceSource
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
cancelAll() {
|
|
414
|
+
return cancelAllHyperliquidOrders({
|
|
415
|
+
wallet: this.wallet,
|
|
416
|
+
environment: this.environment,
|
|
417
|
+
vaultAddress: this.vaultAddress,
|
|
418
|
+
expiresAfter: this.expiresAfter,
|
|
419
|
+
nonceSource: this.nonceSource
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
scheduleCancel(time) {
|
|
423
|
+
return scheduleHyperliquidCancel({
|
|
424
|
+
wallet: this.wallet,
|
|
425
|
+
time,
|
|
426
|
+
environment: this.environment,
|
|
427
|
+
vaultAddress: this.vaultAddress,
|
|
428
|
+
expiresAfter: this.expiresAfter,
|
|
429
|
+
nonceSource: this.nonceSource
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
modify(modification) {
|
|
433
|
+
return modifyHyperliquidOrder({
|
|
434
|
+
wallet: this.wallet,
|
|
435
|
+
modification,
|
|
436
|
+
environment: this.environment,
|
|
437
|
+
vaultAddress: this.vaultAddress,
|
|
438
|
+
expiresAfter: this.expiresAfter,
|
|
439
|
+
nonceSource: this.nonceSource
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
batchModify(modifications) {
|
|
443
|
+
return batchModifyHyperliquidOrders({
|
|
444
|
+
wallet: this.wallet,
|
|
445
|
+
modifications,
|
|
446
|
+
environment: this.environment,
|
|
447
|
+
vaultAddress: this.vaultAddress,
|
|
448
|
+
expiresAfter: this.expiresAfter,
|
|
449
|
+
nonceSource: this.nonceSource
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
twapOrder(twap) {
|
|
453
|
+
return placeHyperliquidTwapOrder({
|
|
454
|
+
wallet: this.wallet,
|
|
455
|
+
twap,
|
|
456
|
+
environment: this.environment,
|
|
457
|
+
vaultAddress: this.vaultAddress,
|
|
458
|
+
expiresAfter: this.expiresAfter,
|
|
459
|
+
nonceSource: this.nonceSource
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
twapCancel(cancel) {
|
|
463
|
+
return cancelHyperliquidTwapOrder({
|
|
464
|
+
wallet: this.wallet,
|
|
465
|
+
cancel,
|
|
466
|
+
environment: this.environment,
|
|
467
|
+
vaultAddress: this.vaultAddress,
|
|
468
|
+
expiresAfter: this.expiresAfter,
|
|
469
|
+
nonceSource: this.nonceSource
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
updateLeverage(input) {
|
|
473
|
+
return updateHyperliquidLeverage({
|
|
474
|
+
wallet: this.wallet,
|
|
475
|
+
input,
|
|
476
|
+
environment: this.environment,
|
|
477
|
+
vaultAddress: this.vaultAddress,
|
|
478
|
+
expiresAfter: this.expiresAfter,
|
|
479
|
+
nonceSource: this.nonceSource
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
updateIsolatedMargin(input) {
|
|
483
|
+
return updateHyperliquidIsolatedMargin({
|
|
484
|
+
wallet: this.wallet,
|
|
485
|
+
input,
|
|
486
|
+
environment: this.environment,
|
|
487
|
+
vaultAddress: this.vaultAddress,
|
|
488
|
+
expiresAfter: this.expiresAfter,
|
|
489
|
+
nonceSource: this.nonceSource
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
reserveRequestWeight(weight) {
|
|
493
|
+
return reserveHyperliquidRequestWeight({
|
|
494
|
+
wallet: this.wallet,
|
|
495
|
+
weight,
|
|
496
|
+
environment: this.environment,
|
|
497
|
+
vaultAddress: this.vaultAddress,
|
|
498
|
+
expiresAfter: this.expiresAfter,
|
|
499
|
+
nonceSource: this.nonceSource
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
spotSend(params) {
|
|
503
|
+
return sendHyperliquidSpot({
|
|
504
|
+
wallet: this.wallet,
|
|
505
|
+
environment: this.environment,
|
|
506
|
+
nonceSource: this.nonceSource,
|
|
507
|
+
...params
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
async function cancelHyperliquidOrders(options) {
|
|
512
|
+
options.cancels.forEach((c) => assertSymbol(c.symbol));
|
|
513
|
+
const action = {
|
|
514
|
+
type: "cancel",
|
|
515
|
+
cancels: await withAssetIndexes(options, options.cancels, (idx, entry) => ({
|
|
516
|
+
a: idx,
|
|
517
|
+
o: entry.oid
|
|
518
|
+
}))
|
|
519
|
+
};
|
|
520
|
+
return submitExchangeAction(options, action);
|
|
521
|
+
}
|
|
522
|
+
async function cancelHyperliquidOrdersByCloid(options) {
|
|
523
|
+
options.cancels.forEach((c) => assertSymbol(c.symbol));
|
|
524
|
+
const action = {
|
|
525
|
+
type: "cancelByCloid",
|
|
526
|
+
cancels: await withAssetIndexes(
|
|
527
|
+
options,
|
|
528
|
+
options.cancels,
|
|
529
|
+
(idx, entry) => ({
|
|
530
|
+
a: idx,
|
|
531
|
+
c: normalizeAddress(entry.cloid)
|
|
532
|
+
})
|
|
533
|
+
)
|
|
534
|
+
};
|
|
535
|
+
return submitExchangeAction(options, action);
|
|
536
|
+
}
|
|
537
|
+
async function cancelAllHyperliquidOrders(options) {
|
|
538
|
+
const action = { type: "cancelAll" };
|
|
539
|
+
return submitExchangeAction(options, action);
|
|
540
|
+
}
|
|
541
|
+
async function scheduleHyperliquidCancel(options) {
|
|
542
|
+
if (options.time !== null) {
|
|
543
|
+
assertPositiveNumber(options.time, "time");
|
|
544
|
+
}
|
|
545
|
+
const action = { type: "scheduleCancel", time: options.time };
|
|
546
|
+
return submitExchangeAction(options, action);
|
|
547
|
+
}
|
|
548
|
+
async function modifyHyperliquidOrder(options) {
|
|
549
|
+
const { modification } = options;
|
|
550
|
+
const order = await buildOrder(modification.order, options);
|
|
551
|
+
const action = {
|
|
552
|
+
type: "modify",
|
|
553
|
+
oid: modification.oid,
|
|
554
|
+
order
|
|
555
|
+
};
|
|
556
|
+
return submitExchangeAction(options, action);
|
|
557
|
+
}
|
|
558
|
+
async function batchModifyHyperliquidOrders(options) {
|
|
559
|
+
options.modifications.forEach((m) => assertSymbol(m.order.symbol));
|
|
560
|
+
const modifies = await Promise.all(
|
|
561
|
+
options.modifications.map(async (mod) => ({
|
|
562
|
+
oid: mod.oid,
|
|
563
|
+
order: await buildOrder(mod.order, options)
|
|
564
|
+
}))
|
|
565
|
+
);
|
|
566
|
+
const action = {
|
|
567
|
+
type: "batchModify",
|
|
568
|
+
modifies
|
|
569
|
+
};
|
|
570
|
+
return submitExchangeAction(options, action);
|
|
571
|
+
}
|
|
572
|
+
async function placeHyperliquidTwapOrder(options) {
|
|
573
|
+
const { twap } = options;
|
|
574
|
+
assertSymbol(twap.symbol);
|
|
575
|
+
assertPositiveDecimal(twap.size, "size");
|
|
576
|
+
assertPositiveNumber(twap.minutes, "minutes");
|
|
577
|
+
const env = options.environment ?? "mainnet";
|
|
578
|
+
const universe = await getUniverse({
|
|
579
|
+
baseUrl: API_BASES[env],
|
|
580
|
+
environment: env,
|
|
581
|
+
fetcher: fetch
|
|
582
|
+
});
|
|
583
|
+
const asset = resolveAssetIndex(twap.symbol, universe);
|
|
584
|
+
const action = {
|
|
585
|
+
type: "twapOrder",
|
|
586
|
+
twap: {
|
|
587
|
+
a: asset,
|
|
588
|
+
b: twap.side === "buy",
|
|
589
|
+
s: toApiDecimal(twap.size),
|
|
590
|
+
r: Boolean(twap.reduceOnly),
|
|
591
|
+
m: twap.minutes,
|
|
592
|
+
t: Boolean(twap.randomize)
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
return submitExchangeAction(options, action);
|
|
596
|
+
}
|
|
597
|
+
async function cancelHyperliquidTwapOrder(options) {
|
|
598
|
+
assertSymbol(options.cancel.symbol);
|
|
599
|
+
const env = options.environment ?? "mainnet";
|
|
600
|
+
const universe = await getUniverse({
|
|
601
|
+
baseUrl: API_BASES[env],
|
|
602
|
+
environment: env,
|
|
603
|
+
fetcher: fetch
|
|
604
|
+
});
|
|
605
|
+
const asset = resolveAssetIndex(options.cancel.symbol, universe);
|
|
606
|
+
const action = {
|
|
607
|
+
type: "twapCancel",
|
|
608
|
+
a: asset,
|
|
609
|
+
t: options.cancel.twapId
|
|
610
|
+
};
|
|
611
|
+
return submitExchangeAction(options, action);
|
|
612
|
+
}
|
|
613
|
+
async function updateHyperliquidLeverage(options) {
|
|
614
|
+
assertSymbol(options.input.symbol);
|
|
615
|
+
assertPositiveNumber(options.input.leverage, "leverage");
|
|
616
|
+
const env = options.environment ?? "mainnet";
|
|
617
|
+
const universe = await getUniverse({
|
|
618
|
+
baseUrl: API_BASES[env],
|
|
619
|
+
environment: env,
|
|
620
|
+
fetcher: fetch
|
|
621
|
+
});
|
|
622
|
+
const asset = resolveAssetIndex(options.input.symbol, universe);
|
|
623
|
+
const action = {
|
|
624
|
+
type: "updateLeverage",
|
|
625
|
+
asset,
|
|
626
|
+
isCross: options.input.leverageMode === "cross",
|
|
627
|
+
leverage: options.input.leverage
|
|
628
|
+
};
|
|
629
|
+
return submitExchangeAction(options, action);
|
|
630
|
+
}
|
|
631
|
+
async function updateHyperliquidIsolatedMargin(options) {
|
|
632
|
+
assertSymbol(options.input.symbol);
|
|
633
|
+
assertPositiveNumber(options.input.ntli, "ntli");
|
|
634
|
+
const env = options.environment ?? "mainnet";
|
|
635
|
+
const universe = await getUniverse({
|
|
636
|
+
baseUrl: API_BASES[env],
|
|
637
|
+
environment: env,
|
|
638
|
+
fetcher: fetch
|
|
639
|
+
});
|
|
640
|
+
const asset = resolveAssetIndex(options.input.symbol, universe);
|
|
641
|
+
const action = {
|
|
642
|
+
type: "updateIsolatedMargin",
|
|
643
|
+
asset,
|
|
644
|
+
isBuy: options.input.isBuy,
|
|
645
|
+
ntli: options.input.ntli
|
|
646
|
+
};
|
|
647
|
+
return submitExchangeAction(options, action);
|
|
648
|
+
}
|
|
649
|
+
async function reserveHyperliquidRequestWeight(options) {
|
|
650
|
+
assertPositiveNumber(options.weight, "weight");
|
|
651
|
+
const action = {
|
|
652
|
+
type: "reserveRequestWeight",
|
|
653
|
+
weight: options.weight
|
|
654
|
+
};
|
|
655
|
+
return submitExchangeAction(options, action);
|
|
656
|
+
}
|
|
657
|
+
async function createHyperliquidSubAccount(options) {
|
|
658
|
+
assertString(options.name, "name");
|
|
659
|
+
const action = {
|
|
660
|
+
type: "createSubAccount",
|
|
661
|
+
name: options.name
|
|
662
|
+
};
|
|
663
|
+
return submitExchangeAction(options, action);
|
|
664
|
+
}
|
|
665
|
+
async function transferHyperliquidSubAccount(options) {
|
|
666
|
+
assertString(options.subAccountUser, "subAccountUser");
|
|
667
|
+
const usdScaled = normalizeUsdToInt(options.usd);
|
|
668
|
+
const action = {
|
|
669
|
+
type: "subAccountTransfer",
|
|
670
|
+
subAccountUser: normalizeAddress(options.subAccountUser),
|
|
671
|
+
isDeposit: Boolean(options.isDeposit),
|
|
672
|
+
usd: usdScaled
|
|
673
|
+
};
|
|
674
|
+
return submitExchangeAction(options, action);
|
|
675
|
+
}
|
|
676
|
+
async function sendHyperliquidSpot(options) {
|
|
677
|
+
const env = options.environment ?? "mainnet";
|
|
678
|
+
if (!options.wallet.account || !options.wallet.walletClient) {
|
|
679
|
+
throw new Error("Wallet with signing capability is required for spotSend.");
|
|
680
|
+
}
|
|
681
|
+
assertString(options.token, "token");
|
|
682
|
+
assertPositiveDecimal(options.amount, "amount");
|
|
683
|
+
const signatureChainId = getSignatureChainId(env);
|
|
684
|
+
const hyperliquidChain = HL_CHAIN_LABEL[env];
|
|
685
|
+
const nonce = options.nonce ?? options.nonceSource?.() ?? Date.now();
|
|
686
|
+
const time = BigInt(nonce);
|
|
687
|
+
const signature = await signSpotSend({
|
|
688
|
+
wallet: options.wallet,
|
|
689
|
+
hyperliquidChain,
|
|
690
|
+
signatureChainId,
|
|
691
|
+
destination: normalizeAddress(options.destination),
|
|
692
|
+
token: options.token,
|
|
693
|
+
amount: toApiDecimal(options.amount),
|
|
694
|
+
time
|
|
695
|
+
});
|
|
696
|
+
const action = {
|
|
697
|
+
type: "spotSend",
|
|
698
|
+
hyperliquidChain,
|
|
699
|
+
signatureChainId,
|
|
700
|
+
destination: normalizeAddress(options.destination),
|
|
701
|
+
token: options.token,
|
|
702
|
+
amount: toApiDecimal(options.amount),
|
|
703
|
+
time: nonce
|
|
704
|
+
};
|
|
705
|
+
return postExchange(env, { action, nonce, signature });
|
|
706
|
+
}
|
|
707
|
+
async function submitExchangeAction(options, action) {
|
|
708
|
+
if (!options.wallet?.account || !options.wallet.walletClient) {
|
|
709
|
+
throw new Error("Hyperliquid exchange actions require a signing wallet.");
|
|
710
|
+
}
|
|
711
|
+
const env = options.environment ?? "mainnet";
|
|
712
|
+
const nonceSource = options.walletNonceProvider ?? options.wallet.nonceSource ?? options.nonceSource;
|
|
713
|
+
if (!nonceSource && options.nonce === void 0) {
|
|
714
|
+
throw new Error("Wallet nonce source is required for Hyperliquid exchange actions.");
|
|
715
|
+
}
|
|
716
|
+
const effectiveNonce = options.nonce ?? nonceSource?.();
|
|
717
|
+
if (effectiveNonce === void 0) {
|
|
718
|
+
throw new Error("Hyperliquid exchange actions require a nonce.");
|
|
719
|
+
}
|
|
720
|
+
const signature = await signL1Action({
|
|
721
|
+
wallet: options.wallet,
|
|
722
|
+
action,
|
|
723
|
+
nonce: effectiveNonce,
|
|
724
|
+
vaultAddress: options.vaultAddress ? normalizeAddress(options.vaultAddress) : void 0,
|
|
725
|
+
expiresAfter: options.expiresAfter,
|
|
726
|
+
isTestnet: env === "testnet"
|
|
727
|
+
});
|
|
728
|
+
const body = {
|
|
729
|
+
action,
|
|
730
|
+
nonce: effectiveNonce,
|
|
731
|
+
signature
|
|
732
|
+
};
|
|
733
|
+
if (options.vaultAddress) {
|
|
734
|
+
body.vaultAddress = normalizeAddress(options.vaultAddress);
|
|
735
|
+
}
|
|
736
|
+
if (typeof options.expiresAfter === "number") {
|
|
737
|
+
body.expiresAfter = options.expiresAfter;
|
|
738
|
+
}
|
|
739
|
+
return postExchange(env, body);
|
|
740
|
+
}
|
|
741
|
+
async function withAssetIndexes(options, entries, mapper) {
|
|
742
|
+
const env = options.environment ?? "mainnet";
|
|
743
|
+
const universe = await getUniverse({
|
|
744
|
+
baseUrl: API_BASES[env],
|
|
745
|
+
environment: env,
|
|
746
|
+
fetcher: fetch
|
|
747
|
+
});
|
|
748
|
+
return Promise.all(
|
|
749
|
+
entries.map(async (entry) => {
|
|
750
|
+
const assetIndex = resolveAssetIndex(entry.symbol, universe);
|
|
751
|
+
return mapper(assetIndex, entry);
|
|
752
|
+
})
|
|
753
|
+
);
|
|
754
|
+
}
|
|
755
|
+
async function buildOrder(intent, options) {
|
|
756
|
+
assertSymbol(intent.symbol);
|
|
757
|
+
assertPositiveDecimal(intent.price, "price");
|
|
758
|
+
assertPositiveDecimal(intent.size, "size");
|
|
759
|
+
const env = options.environment ?? "mainnet";
|
|
760
|
+
const universe = await getUniverse({
|
|
761
|
+
baseUrl: API_BASES[env],
|
|
762
|
+
environment: env,
|
|
763
|
+
fetcher: fetch
|
|
764
|
+
});
|
|
765
|
+
const assetIndex = resolveAssetIndex(intent.symbol, universe);
|
|
766
|
+
const limitOrTrigger = intent.trigger ? mapTrigger(intent.trigger) : {
|
|
767
|
+
limit: {
|
|
768
|
+
tif: intent.tif ?? "Ioc"
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
return {
|
|
772
|
+
a: assetIndex,
|
|
773
|
+
b: intent.side === "buy",
|
|
774
|
+
p: toApiDecimal(intent.price),
|
|
775
|
+
s: toApiDecimal(intent.size),
|
|
776
|
+
r: intent.reduceOnly ?? false,
|
|
777
|
+
t: limitOrTrigger,
|
|
778
|
+
...intent.clientId ? {
|
|
779
|
+
c: normalizeAddress(intent.clientId)
|
|
780
|
+
} : {}
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
function mapTrigger(trigger) {
|
|
784
|
+
assertPositiveDecimal(trigger.triggerPx, "triggerPx");
|
|
785
|
+
return {
|
|
786
|
+
trigger: {
|
|
787
|
+
isMarket: Boolean(trigger.isMarket),
|
|
788
|
+
triggerPx: toApiDecimal(trigger.triggerPx),
|
|
789
|
+
tpsl: trigger.tpsl
|
|
790
|
+
}
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
function assertSymbol(value) {
|
|
794
|
+
assertString(value, "symbol");
|
|
795
|
+
}
|
|
796
|
+
function normalizeUsdToInt(value) {
|
|
797
|
+
if (typeof value === "bigint") {
|
|
798
|
+
if (value < 0n) {
|
|
799
|
+
throw new Error("usd must be non-negative.");
|
|
800
|
+
}
|
|
801
|
+
return Number(value);
|
|
802
|
+
}
|
|
803
|
+
const parsed = typeof value === "string" ? Number.parseFloat(value) : Number(value);
|
|
804
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
805
|
+
throw new Error("usd must be a non-negative number.");
|
|
806
|
+
}
|
|
807
|
+
return Math.round(parsed * 1e6);
|
|
808
|
+
}
|
|
809
|
+
function assertString(value, label) {
|
|
810
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
811
|
+
throw new Error(`${label} must be a non-empty string.`);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
function assertPositiveDecimal(value, label) {
|
|
815
|
+
if (typeof value === "number") {
|
|
816
|
+
assertPositiveNumber(value, label);
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
if (typeof value === "bigint") {
|
|
820
|
+
if (value <= 0n) {
|
|
821
|
+
throw new Error(`${label} must be positive.`);
|
|
822
|
+
}
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
assertString(value, label);
|
|
826
|
+
}
|
|
827
|
+
async function postExchange(env, body) {
|
|
828
|
+
const response = await fetch(`${API_BASES[env]}/exchange`, {
|
|
829
|
+
method: "POST",
|
|
830
|
+
headers: { "content-type": "application/json" },
|
|
831
|
+
body: JSON.stringify(body)
|
|
832
|
+
});
|
|
833
|
+
const json = await response.json().catch(() => null);
|
|
834
|
+
if (!response.ok || !json) {
|
|
835
|
+
throw new HyperliquidApiError(
|
|
836
|
+
"Hyperliquid exchange action failed.",
|
|
837
|
+
json ?? { status: response.status }
|
|
838
|
+
);
|
|
839
|
+
}
|
|
840
|
+
if (json.status !== "ok") {
|
|
841
|
+
throw new HyperliquidApiError("Hyperliquid exchange returned error.", json);
|
|
842
|
+
}
|
|
843
|
+
return json;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// src/adapters/hyperliquid/info.ts
|
|
847
|
+
async function postInfo(environment, payload) {
|
|
848
|
+
const baseUrl = API_BASES[environment];
|
|
849
|
+
const response = await fetch(`${baseUrl}/info`, {
|
|
850
|
+
method: "POST",
|
|
851
|
+
headers: { "content-type": "application/json" },
|
|
852
|
+
body: JSON.stringify(payload)
|
|
853
|
+
});
|
|
854
|
+
const data = await response.json().catch(() => null);
|
|
855
|
+
if (!response.ok) {
|
|
856
|
+
throw new HyperliquidApiError(
|
|
857
|
+
"Hyperliquid info request failed.",
|
|
858
|
+
data ?? { status: response.status }
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
return data;
|
|
862
|
+
}
|
|
863
|
+
var HyperliquidInfoClient = class {
|
|
864
|
+
constructor(environment = "mainnet") {
|
|
865
|
+
this.environment = environment;
|
|
866
|
+
}
|
|
867
|
+
meta() {
|
|
868
|
+
return fetchHyperliquidMeta(this.environment);
|
|
869
|
+
}
|
|
870
|
+
metaAndAssetCtxs() {
|
|
871
|
+
return fetchHyperliquidMetaAndAssetCtxs(this.environment);
|
|
872
|
+
}
|
|
873
|
+
spotMeta() {
|
|
874
|
+
return fetchHyperliquidSpotMeta(this.environment);
|
|
875
|
+
}
|
|
876
|
+
spotMetaAndAssetCtxs() {
|
|
877
|
+
return fetchHyperliquidSpotMetaAndAssetCtxs(this.environment);
|
|
878
|
+
}
|
|
879
|
+
assetCtxs() {
|
|
880
|
+
return fetchHyperliquidAssetCtxs(this.environment);
|
|
881
|
+
}
|
|
882
|
+
spotAssetCtxs() {
|
|
883
|
+
return fetchHyperliquidSpotAssetCtxs(this.environment);
|
|
884
|
+
}
|
|
885
|
+
openOrders(user) {
|
|
886
|
+
return fetchHyperliquidOpenOrders({ user, environment: this.environment });
|
|
887
|
+
}
|
|
888
|
+
frontendOpenOrders(user) {
|
|
889
|
+
return fetchHyperliquidFrontendOpenOrders({
|
|
890
|
+
user,
|
|
891
|
+
environment: this.environment
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
orderStatus(user, oid) {
|
|
895
|
+
return fetchHyperliquidOrderStatus({
|
|
896
|
+
user,
|
|
897
|
+
oid,
|
|
898
|
+
environment: this.environment
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
historicalOrders(user) {
|
|
902
|
+
return fetchHyperliquidHistoricalOrders({
|
|
903
|
+
user,
|
|
904
|
+
environment: this.environment
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
userFills(user) {
|
|
908
|
+
return fetchHyperliquidUserFills({ user, environment: this.environment });
|
|
909
|
+
}
|
|
910
|
+
userFillsByTime(user, startTime, endTime) {
|
|
911
|
+
return fetchHyperliquidUserFillsByTime({
|
|
912
|
+
user,
|
|
913
|
+
startTime,
|
|
914
|
+
endTime,
|
|
915
|
+
environment: this.environment
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
userRateLimit(user) {
|
|
919
|
+
return fetchHyperliquidUserRateLimit({
|
|
920
|
+
user,
|
|
921
|
+
environment: this.environment
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
preTransferCheck(user, source) {
|
|
925
|
+
return fetchHyperliquidPreTransferCheck({
|
|
926
|
+
user,
|
|
927
|
+
source,
|
|
928
|
+
environment: this.environment
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
spotClearinghouseState(user) {
|
|
932
|
+
return fetchHyperliquidSpotClearinghouseState({
|
|
933
|
+
user,
|
|
934
|
+
environment: this.environment
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
};
|
|
938
|
+
async function fetchHyperliquidMeta(environment = "mainnet") {
|
|
939
|
+
return postInfo(environment, { type: "meta" });
|
|
940
|
+
}
|
|
941
|
+
async function fetchHyperliquidMetaAndAssetCtxs(environment = "mainnet") {
|
|
942
|
+
return postInfo(environment, { type: "metaAndAssetCtxs" });
|
|
943
|
+
}
|
|
944
|
+
async function fetchHyperliquidSpotMeta(environment = "mainnet") {
|
|
945
|
+
return postInfo(environment, { type: "spotMeta" });
|
|
946
|
+
}
|
|
947
|
+
async function fetchHyperliquidSpotMetaAndAssetCtxs(environment = "mainnet") {
|
|
948
|
+
return postInfo(environment, { type: "spotMetaAndAssetCtxs" });
|
|
949
|
+
}
|
|
950
|
+
async function fetchHyperliquidAssetCtxs(environment = "mainnet") {
|
|
951
|
+
return postInfo(environment, { type: "assetCtxs" });
|
|
952
|
+
}
|
|
953
|
+
async function fetchHyperliquidSpotAssetCtxs(environment = "mainnet") {
|
|
954
|
+
return postInfo(environment, { type: "spotAssetCtxs" });
|
|
955
|
+
}
|
|
956
|
+
async function fetchHyperliquidOpenOrders(params) {
|
|
957
|
+
const env = params.environment ?? "mainnet";
|
|
958
|
+
return postInfo(env, { type: "openOrders", user: normalizeAddress(params.user) });
|
|
959
|
+
}
|
|
960
|
+
async function fetchHyperliquidFrontendOpenOrders(params) {
|
|
961
|
+
const env = params.environment ?? "mainnet";
|
|
962
|
+
return postInfo(env, {
|
|
963
|
+
type: "frontendOpenOrders",
|
|
964
|
+
user: normalizeAddress(params.user)
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
async function fetchHyperliquidOrderStatus(params) {
|
|
968
|
+
const env = params.environment ?? "mainnet";
|
|
969
|
+
return postInfo(env, {
|
|
970
|
+
type: "orderStatus",
|
|
971
|
+
user: normalizeAddress(params.user),
|
|
972
|
+
oid: params.oid
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
async function fetchHyperliquidHistoricalOrders(params) {
|
|
976
|
+
const env = params.environment ?? "mainnet";
|
|
977
|
+
return postInfo(env, {
|
|
978
|
+
type: "historicalOrders",
|
|
979
|
+
user: normalizeAddress(params.user)
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
async function fetchHyperliquidUserFills(params) {
|
|
983
|
+
const env = params.environment ?? "mainnet";
|
|
984
|
+
return postInfo(env, {
|
|
985
|
+
type: "userFills",
|
|
986
|
+
user: normalizeAddress(params.user)
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
async function fetchHyperliquidUserFillsByTime(params) {
|
|
990
|
+
const env = params.environment ?? "mainnet";
|
|
991
|
+
return postInfo(env, {
|
|
992
|
+
type: "userFillsByTime",
|
|
993
|
+
user: normalizeAddress(params.user),
|
|
994
|
+
startTime: params.startTime,
|
|
995
|
+
endTime: params.endTime
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
async function fetchHyperliquidUserRateLimit(params) {
|
|
999
|
+
const env = params.environment ?? "mainnet";
|
|
1000
|
+
return postInfo(env, {
|
|
1001
|
+
type: "userRateLimit",
|
|
1002
|
+
user: normalizeAddress(params.user)
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
1005
|
+
async function fetchHyperliquidPreTransferCheck(params) {
|
|
1006
|
+
const env = params.environment ?? "mainnet";
|
|
1007
|
+
return postInfo(env, {
|
|
1008
|
+
type: "preTransferCheck",
|
|
1009
|
+
user: normalizeAddress(params.user),
|
|
1010
|
+
source: normalizeAddress(params.source)
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
async function fetchHyperliquidSpotClearinghouseState(params) {
|
|
1014
|
+
const env = params.environment ?? "mainnet";
|
|
1015
|
+
return postInfo(env, {
|
|
1016
|
+
type: "spotClearinghouseState",
|
|
1017
|
+
user: normalizeAddress(params.user)
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
// src/adapters/hyperliquid/index.ts
|
|
1022
|
+
async function placeHyperliquidOrder(options) {
|
|
1023
|
+
const {
|
|
1024
|
+
wallet,
|
|
1025
|
+
orders,
|
|
1026
|
+
grouping = "na",
|
|
1027
|
+
environment,
|
|
1028
|
+
vaultAddress,
|
|
1029
|
+
expiresAfter,
|
|
1030
|
+
nonce
|
|
1031
|
+
} = options;
|
|
1032
|
+
const effectiveBuilder = BUILDER_CODE;
|
|
1033
|
+
if (!wallet?.account || !wallet.walletClient) {
|
|
1034
|
+
throw new Error(
|
|
1035
|
+
"Hyperliquid order signing requires a wallet with signing capabilities."
|
|
1036
|
+
);
|
|
1037
|
+
}
|
|
1038
|
+
if (!orders.length) {
|
|
1039
|
+
throw new Error("At least one order is required.");
|
|
1040
|
+
}
|
|
1041
|
+
const inferredEnvironment = environment ?? "mainnet";
|
|
1042
|
+
const resolvedBaseUrl = API_BASES[inferredEnvironment];
|
|
1043
|
+
const universe = await getUniverse({
|
|
1044
|
+
baseUrl: resolvedBaseUrl,
|
|
1045
|
+
environment: inferredEnvironment,
|
|
1046
|
+
fetcher: fetch
|
|
1047
|
+
});
|
|
1048
|
+
const preparedOrders = orders.map((intent) => {
|
|
1049
|
+
const assetIndex = resolveAssetIndex(intent.symbol, universe);
|
|
1050
|
+
const limitOrTrigger = intent.trigger ? {
|
|
1051
|
+
trigger: {
|
|
1052
|
+
isMarket: Boolean(intent.trigger.isMarket),
|
|
1053
|
+
triggerPx: toApiDecimal(intent.trigger.triggerPx),
|
|
1054
|
+
tpsl: intent.trigger.tpsl
|
|
1055
|
+
}
|
|
1056
|
+
} : {
|
|
1057
|
+
limit: {
|
|
1058
|
+
tif: intent.tif ?? "Ioc"
|
|
1059
|
+
}
|
|
1060
|
+
};
|
|
1061
|
+
const order = {
|
|
1062
|
+
a: assetIndex,
|
|
1063
|
+
b: intent.side === "buy",
|
|
1064
|
+
p: toApiDecimal(intent.price),
|
|
1065
|
+
s: toApiDecimal(intent.size),
|
|
1066
|
+
r: intent.reduceOnly ?? false,
|
|
1067
|
+
t: limitOrTrigger,
|
|
1068
|
+
...intent.clientId ? {
|
|
1069
|
+
c: normalizeHex(intent.clientId)
|
|
1070
|
+
} : {}
|
|
1071
|
+
};
|
|
1072
|
+
return order;
|
|
1073
|
+
});
|
|
1074
|
+
const action = {
|
|
1075
|
+
type: "order",
|
|
1076
|
+
orders: preparedOrders,
|
|
1077
|
+
grouping
|
|
1078
|
+
};
|
|
1079
|
+
if (effectiveBuilder) {
|
|
1080
|
+
action.builder = {
|
|
1081
|
+
b: normalizeAddress(effectiveBuilder.address),
|
|
1082
|
+
f: effectiveBuilder.fee
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
const effectiveNonce = nonce ?? Date.now();
|
|
1086
|
+
const signature = await signL1Action({
|
|
1087
|
+
wallet,
|
|
1088
|
+
action,
|
|
1089
|
+
nonce: effectiveNonce,
|
|
1090
|
+
...vaultAddress ? { vaultAddress } : {},
|
|
1091
|
+
...typeof expiresAfter === "number" ? { expiresAfter } : {},
|
|
1092
|
+
isTestnet: inferredEnvironment === "testnet"
|
|
1093
|
+
});
|
|
1094
|
+
const body = {
|
|
1095
|
+
action,
|
|
1096
|
+
nonce: effectiveNonce,
|
|
1097
|
+
signature
|
|
1098
|
+
};
|
|
1099
|
+
if (vaultAddress) {
|
|
1100
|
+
body.vaultAddress = normalizeAddress(vaultAddress);
|
|
1101
|
+
}
|
|
1102
|
+
if (typeof expiresAfter === "number") {
|
|
1103
|
+
body.expiresAfter = expiresAfter;
|
|
1104
|
+
}
|
|
1105
|
+
const response = await fetch(`${resolvedBaseUrl}/exchange`, {
|
|
1106
|
+
method: "POST",
|
|
1107
|
+
headers: { "content-type": "application/json" },
|
|
1108
|
+
body: JSON.stringify(body)
|
|
1109
|
+
});
|
|
1110
|
+
const rawText = await response.text().catch(() => null);
|
|
1111
|
+
let parsed = null;
|
|
1112
|
+
if (rawText && rawText.length) {
|
|
1113
|
+
try {
|
|
1114
|
+
parsed = JSON.parse(rawText);
|
|
1115
|
+
} catch {
|
|
1116
|
+
parsed = rawText;
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
const json = parsed && typeof parsed === "object" && "status" in parsed ? parsed : null;
|
|
1120
|
+
if (!response.ok || !json) {
|
|
1121
|
+
const detail = parsed?.error ?? parsed?.message ?? (typeof parsed === "string" ? parsed : rawText);
|
|
1122
|
+
const suffix = detail ? ` Detail: ${detail}` : "";
|
|
1123
|
+
throw new HyperliquidApiError(
|
|
1124
|
+
`Failed to submit Hyperliquid order.${suffix}`,
|
|
1125
|
+
parsed ?? rawText ?? { status: response.status }
|
|
1126
|
+
);
|
|
1127
|
+
}
|
|
1128
|
+
if (json.status !== "ok") {
|
|
1129
|
+
const detail = parsed?.error ?? rawText;
|
|
1130
|
+
throw new HyperliquidApiError(
|
|
1131
|
+
detail ? `Hyperliquid API returned an error status: ${detail}` : "Hyperliquid API returned an error status.",
|
|
1132
|
+
json
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
const statuses = json.response?.data?.statuses ?? [];
|
|
1136
|
+
const errorStatuses = statuses.filter(
|
|
1137
|
+
(entry) => "error" in entry
|
|
1138
|
+
);
|
|
1139
|
+
if (errorStatuses.length) {
|
|
1140
|
+
const message = errorStatuses.map((entry) => entry.error).join(", ");
|
|
1141
|
+
throw new HyperliquidApiError(
|
|
1142
|
+
message || "Hyperliquid rejected the order.",
|
|
1143
|
+
json
|
|
1144
|
+
);
|
|
1145
|
+
}
|
|
1146
|
+
return json;
|
|
1147
|
+
}
|
|
1148
|
+
async function depositToHyperliquidBridge(options) {
|
|
1149
|
+
const { environment, amount, wallet } = options;
|
|
1150
|
+
const parsedAmount = Number(amount);
|
|
1151
|
+
if (!Number.isFinite(parsedAmount) || parsedAmount <= 0) {
|
|
1152
|
+
throw new Error("Deposit amount must be a positive number.");
|
|
1153
|
+
}
|
|
1154
|
+
if (parsedAmount < MIN_DEPOSIT_USDC) {
|
|
1155
|
+
throw new Error(`Minimum deposit is ${MIN_DEPOSIT_USDC} USDC.`);
|
|
1156
|
+
}
|
|
1157
|
+
if (!wallet.account || !wallet.walletClient) {
|
|
1158
|
+
throw new Error("Wallet with signing capability is required for deposit.");
|
|
1159
|
+
}
|
|
1160
|
+
const bridgeAddress = getBridgeAddress(environment);
|
|
1161
|
+
const usdcAddress = getUsdcAddress(environment);
|
|
1162
|
+
const amountUnits = parseUnits(amount, 6);
|
|
1163
|
+
if (!wallet.walletClient || !wallet.publicClient) {
|
|
1164
|
+
throw new Error(
|
|
1165
|
+
"Wallet client and public client are required for deposit."
|
|
1166
|
+
);
|
|
1167
|
+
}
|
|
1168
|
+
const walletClient = wallet.walletClient;
|
|
1169
|
+
const publicClient = wallet.publicClient;
|
|
1170
|
+
const data = encodeFunctionData({
|
|
1171
|
+
abi: erc20Abi,
|
|
1172
|
+
functionName: "transfer",
|
|
1173
|
+
args: [bridgeAddress, amountUnits]
|
|
1174
|
+
});
|
|
1175
|
+
const txHash = await walletClient.sendTransaction({
|
|
1176
|
+
account: wallet.account,
|
|
1177
|
+
to: usdcAddress,
|
|
1178
|
+
data
|
|
1179
|
+
});
|
|
1180
|
+
await publicClient.waitForTransactionReceipt({ hash: txHash });
|
|
1181
|
+
return {
|
|
1182
|
+
txHash,
|
|
1183
|
+
amount: parsedAmount,
|
|
1184
|
+
amountUnits: amountUnits.toString(),
|
|
1185
|
+
environment,
|
|
1186
|
+
bridgeAddress
|
|
1187
|
+
};
|
|
1188
|
+
}
|
|
1189
|
+
async function withdrawFromHyperliquid(options) {
|
|
1190
|
+
const { environment, amount, destination, wallet } = options;
|
|
1191
|
+
const parsedAmount = Number(amount);
|
|
1192
|
+
if (!Number.isFinite(parsedAmount) || parsedAmount <= 0) {
|
|
1193
|
+
throw new Error("Withdraw amount must be a positive number.");
|
|
1194
|
+
}
|
|
1195
|
+
if (!wallet.account || !wallet.walletClient || !wallet.publicClient) {
|
|
1196
|
+
throw new Error(
|
|
1197
|
+
"Wallet client and public client are required for withdraw."
|
|
1198
|
+
);
|
|
1199
|
+
}
|
|
1200
|
+
const signatureChainId = getSignatureChainId(environment);
|
|
1201
|
+
const hyperliquidChain = HL_CHAIN_LABEL[environment];
|
|
1202
|
+
const domain = {
|
|
1203
|
+
name: "HyperliquidSignTransaction",
|
|
1204
|
+
version: "1",
|
|
1205
|
+
chainId: Number.parseInt(signatureChainId, 16),
|
|
1206
|
+
verifyingContract: ZERO_ADDRESS
|
|
1207
|
+
};
|
|
1208
|
+
const time = BigInt(Date.now());
|
|
1209
|
+
const nonce = Number(time);
|
|
1210
|
+
const normalizedDestination = normalizeAddress(destination);
|
|
1211
|
+
const message = {
|
|
1212
|
+
hyperliquidChain,
|
|
1213
|
+
destination: normalizedDestination,
|
|
1214
|
+
amount: parsedAmount.toString(),
|
|
1215
|
+
time
|
|
1216
|
+
};
|
|
1217
|
+
const types = {
|
|
1218
|
+
"HyperliquidTransaction:Withdraw": [
|
|
1219
|
+
{ name: "hyperliquidChain", type: "string" },
|
|
1220
|
+
{ name: "destination", type: "string" },
|
|
1221
|
+
{ name: "amount", type: "string" },
|
|
1222
|
+
{ name: "time", type: "uint64" }
|
|
1223
|
+
]
|
|
1224
|
+
};
|
|
1225
|
+
const signatureHex = await wallet.walletClient.signTypedData({
|
|
1226
|
+
account: wallet.account,
|
|
1227
|
+
domain,
|
|
1228
|
+
types,
|
|
1229
|
+
primaryType: "HyperliquidTransaction:Withdraw",
|
|
1230
|
+
message
|
|
1231
|
+
});
|
|
1232
|
+
const signature = splitSignature(signatureHex);
|
|
1233
|
+
const payload = {
|
|
1234
|
+
action: {
|
|
1235
|
+
type: "withdraw3",
|
|
1236
|
+
signatureChainId,
|
|
1237
|
+
hyperliquidChain,
|
|
1238
|
+
destination: normalizedDestination,
|
|
1239
|
+
amount: parsedAmount.toString(),
|
|
1240
|
+
time: nonce
|
|
1241
|
+
},
|
|
1242
|
+
nonce,
|
|
1243
|
+
signature
|
|
1244
|
+
};
|
|
1245
|
+
const endpoint = `${HL_ENDPOINT[environment]}/exchange`;
|
|
1246
|
+
const response = await fetch(endpoint, {
|
|
1247
|
+
method: "POST",
|
|
1248
|
+
headers: { "content-type": "application/json" },
|
|
1249
|
+
body: JSON.stringify(payload)
|
|
1250
|
+
});
|
|
1251
|
+
const json = await response.json().catch(() => null);
|
|
1252
|
+
if (!response.ok || json?.status !== "ok") {
|
|
1253
|
+
throw new Error(
|
|
1254
|
+
`Hyperliquid withdraw failed: ${json?.response ?? json?.error ?? response.statusText}`
|
|
1255
|
+
);
|
|
1256
|
+
}
|
|
1257
|
+
return {
|
|
1258
|
+
amount: parsedAmount,
|
|
1259
|
+
destination: normalizedDestination,
|
|
1260
|
+
environment,
|
|
1261
|
+
nonce,
|
|
1262
|
+
status: json.status ?? "ok"
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
async function fetchHyperliquidClearinghouseState(params) {
|
|
1266
|
+
const { environment, walletAddress } = params;
|
|
1267
|
+
const response = await fetch(`${HL_ENDPOINT[environment]}/info`, {
|
|
1268
|
+
method: "POST",
|
|
1269
|
+
headers: { "content-type": "application/json" },
|
|
1270
|
+
body: JSON.stringify({ type: "clearinghouseState", user: walletAddress })
|
|
1271
|
+
});
|
|
1272
|
+
const data = await response.json().catch(() => null);
|
|
1273
|
+
return {
|
|
1274
|
+
ok: response.ok,
|
|
1275
|
+
data
|
|
1276
|
+
};
|
|
1277
|
+
}
|
|
1278
|
+
async function approveHyperliquidBuilderFee(options) {
|
|
1279
|
+
const { environment, wallet, nonce, signatureChainId } = options;
|
|
1280
|
+
if (!wallet?.account || !wallet.walletClient) {
|
|
1281
|
+
throw new Error(
|
|
1282
|
+
"Hyperliquid builder approval requires a wallet with signing capabilities."
|
|
1283
|
+
);
|
|
1284
|
+
}
|
|
1285
|
+
const maxFeeRateValue = BUILDER_CODE.fee / 1e3;
|
|
1286
|
+
const formattedPercent = `${maxFeeRateValue}%`;
|
|
1287
|
+
const normalizedBuilder = normalizeAddress(BUILDER_CODE.address);
|
|
1288
|
+
const inferredEnvironment = environment ?? "mainnet";
|
|
1289
|
+
const resolvedBaseUrl = API_BASES[inferredEnvironment];
|
|
1290
|
+
const maxFeeRate = formattedPercent;
|
|
1291
|
+
const effectiveNonce = nonce ?? Date.now();
|
|
1292
|
+
const signatureNonce = BigInt(effectiveNonce);
|
|
1293
|
+
const signatureChainHex = signatureChainId ?? getSignatureChainId(inferredEnvironment);
|
|
1294
|
+
const approvalSignature = await signApproveBuilderFee({
|
|
1295
|
+
wallet,
|
|
1296
|
+
maxFeeRate,
|
|
1297
|
+
nonce: signatureNonce,
|
|
1298
|
+
signatureChainId: signatureChainHex,
|
|
1299
|
+
isTestnet: inferredEnvironment === "testnet"
|
|
1300
|
+
});
|
|
1301
|
+
const action = {
|
|
1302
|
+
type: "approveBuilderFee",
|
|
1303
|
+
maxFeeRate,
|
|
1304
|
+
builder: normalizedBuilder,
|
|
1305
|
+
hyperliquidChain: HL_CHAIN_LABEL[inferredEnvironment],
|
|
1306
|
+
signatureChainId: signatureChainHex,
|
|
1307
|
+
nonce: effectiveNonce
|
|
1308
|
+
};
|
|
1309
|
+
const payload = {
|
|
1310
|
+
action,
|
|
1311
|
+
nonce: effectiveNonce,
|
|
1312
|
+
signature: approvalSignature
|
|
1313
|
+
};
|
|
1314
|
+
const response = await fetch(`${resolvedBaseUrl}/exchange`, {
|
|
1315
|
+
method: "POST",
|
|
1316
|
+
headers: { "content-type": "application/json" },
|
|
1317
|
+
body: JSON.stringify(payload)
|
|
1318
|
+
});
|
|
1319
|
+
const rawText = await response.text().catch(() => null);
|
|
1320
|
+
let parsed = null;
|
|
1321
|
+
if (rawText && rawText.length) {
|
|
1322
|
+
try {
|
|
1323
|
+
parsed = JSON.parse(rawText);
|
|
1324
|
+
} catch {
|
|
1325
|
+
parsed = rawText;
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
const json = parsed && typeof parsed === "object" && "status" in parsed ? parsed : null;
|
|
1329
|
+
if (!response.ok || !json) {
|
|
1330
|
+
const detail = parsed?.error ?? parsed?.message ?? (typeof parsed === "string" ? parsed : rawText);
|
|
1331
|
+
const suffix = detail ? ` Detail: ${detail}` : "";
|
|
1332
|
+
throw new HyperliquidApiError(
|
|
1333
|
+
`Failed to submit builder approval.${suffix}`,
|
|
1334
|
+
parsed ?? rawText ?? { status: response.status }
|
|
1335
|
+
);
|
|
1336
|
+
}
|
|
1337
|
+
if (json.status !== "ok") {
|
|
1338
|
+
const detail = parsed?.error ?? rawText;
|
|
1339
|
+
throw new HyperliquidApiError(
|
|
1340
|
+
detail ? `Hyperliquid builder approval returned an error: ${detail}` : "Hyperliquid builder approval returned an error.",
|
|
1341
|
+
json
|
|
1342
|
+
);
|
|
1343
|
+
}
|
|
1344
|
+
return json;
|
|
1345
|
+
}
|
|
1346
|
+
async function getHyperliquidMaxBuilderFee(params) {
|
|
1347
|
+
const { environment, user } = params;
|
|
1348
|
+
const resolvedBaseUrl = API_BASES[environment];
|
|
1349
|
+
const response = await fetch(`${resolvedBaseUrl}/info`, {
|
|
1350
|
+
method: "POST",
|
|
1351
|
+
headers: { "content-type": "application/json" },
|
|
1352
|
+
body: JSON.stringify({
|
|
1353
|
+
type: "maxBuilderFee",
|
|
1354
|
+
user: normalizeAddress(user),
|
|
1355
|
+
builder: BUILDER_CODE.address
|
|
1356
|
+
})
|
|
1357
|
+
});
|
|
1358
|
+
const data = await response.json().catch(() => null);
|
|
1359
|
+
if (!response.ok) {
|
|
1360
|
+
throw new HyperliquidApiError(
|
|
1361
|
+
"Failed to query max builder fee.",
|
|
1362
|
+
data ?? { status: response.status }
|
|
1363
|
+
);
|
|
1364
|
+
}
|
|
1365
|
+
return data;
|
|
1366
|
+
}
|
|
1367
|
+
async function recordHyperliquidTermsAcceptance(input) {
|
|
1368
|
+
const { environment, walletAddress, storeOptions } = input;
|
|
1369
|
+
return store(
|
|
1370
|
+
{
|
|
1371
|
+
source: "hyperliquid",
|
|
1372
|
+
ref: `${environment}-terms-${Date.now()}`,
|
|
1373
|
+
status: "info",
|
|
1374
|
+
walletAddress,
|
|
1375
|
+
action: "terms",
|
|
1376
|
+
metadata: {
|
|
1377
|
+
environment,
|
|
1378
|
+
note: "Hyperliquid does not expose a terms endpoint; this records local acknowledgement only."
|
|
1379
|
+
}
|
|
1380
|
+
},
|
|
1381
|
+
storeOptions
|
|
1382
|
+
);
|
|
1383
|
+
}
|
|
1384
|
+
async function recordHyperliquidBuilderApproval(input) {
|
|
1385
|
+
const { environment, walletAddress, storeOptions } = input;
|
|
1386
|
+
const maxFeeRate = `${BUILDER_CODE.fee / 1e3}%`;
|
|
1387
|
+
return store(
|
|
1388
|
+
{
|
|
1389
|
+
source: "hyperliquid",
|
|
1390
|
+
ref: `${environment}-builder-${Date.now()}`,
|
|
1391
|
+
status: "info",
|
|
1392
|
+
walletAddress,
|
|
1393
|
+
action: "builder-approval",
|
|
1394
|
+
metadata: {
|
|
1395
|
+
environment,
|
|
1396
|
+
builder: BUILDER_CODE.address,
|
|
1397
|
+
maxFeeRate
|
|
1398
|
+
}
|
|
1399
|
+
},
|
|
1400
|
+
storeOptions
|
|
1401
|
+
);
|
|
1402
|
+
}
|
|
1403
|
+
var __hyperliquidInternals = {
|
|
1404
|
+
toApiDecimal,
|
|
1405
|
+
createL1ActionHash,
|
|
1406
|
+
splitSignature
|
|
1407
|
+
};
|
|
1408
|
+
|
|
1409
|
+
export { HyperliquidApiError, HyperliquidBuilderApprovalError, HyperliquidExchangeClient, HyperliquidGuardError, HyperliquidInfoClient, HyperliquidTermsError, __hyperliquidInternals, approveHyperliquidBuilderFee, batchModifyHyperliquidOrders, cancelAllHyperliquidOrders, cancelHyperliquidOrders, cancelHyperliquidOrdersByCloid, cancelHyperliquidTwapOrder, createHyperliquidSubAccount, createMonotonicNonceFactory, depositToHyperliquidBridge, fetchHyperliquidAssetCtxs, fetchHyperliquidClearinghouseState, fetchHyperliquidFrontendOpenOrders, fetchHyperliquidHistoricalOrders, fetchHyperliquidMeta, fetchHyperliquidMetaAndAssetCtxs, fetchHyperliquidOpenOrders, fetchHyperliquidOrderStatus, fetchHyperliquidPreTransferCheck, fetchHyperliquidSpotAssetCtxs, fetchHyperliquidSpotClearinghouseState, fetchHyperliquidSpotMeta, fetchHyperliquidSpotMetaAndAssetCtxs, fetchHyperliquidUserFills, fetchHyperliquidUserFillsByTime, fetchHyperliquidUserRateLimit, getHyperliquidMaxBuilderFee, modifyHyperliquidOrder, placeHyperliquidOrder, placeHyperliquidTwapOrder, recordHyperliquidBuilderApproval, recordHyperliquidTermsAcceptance, reserveHyperliquidRequestWeight, scheduleHyperliquidCancel, sendHyperliquidSpot, transferHyperliquidSubAccount, updateHyperliquidIsolatedMargin, updateHyperliquidLeverage, withdrawFromHyperliquid };
|
|
1410
|
+
//# sourceMappingURL=index.js.map
|
|
1411
|
+
//# sourceMappingURL=index.js.map
|