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.
@@ -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