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
package/dist/index.js
CHANGED
|
@@ -6,11 +6,14 @@ import * as path5 from 'path';
|
|
|
6
6
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
7
7
|
import { zodToJsonSchema } from '@alcyone-labs/zod-to-json-schema';
|
|
8
8
|
import { z } from 'zod';
|
|
9
|
-
import { zeroAddress, createWalletClient, http, createPublicClient } from 'viem';
|
|
9
|
+
import { zeroAddress, createWalletClient, http, createPublicClient, parseUnits, encodeFunctionData, erc20Abi } from 'viem';
|
|
10
10
|
import { privateKeyToAccount } from 'viem/accounts';
|
|
11
11
|
import { arbitrumSepolia, arbitrum, baseSepolia, mainnet, base } from 'viem/chains';
|
|
12
12
|
import { Turnkey } from '@turnkey/sdk-server';
|
|
13
13
|
import { createAccount } from '@turnkey/viem';
|
|
14
|
+
import { encode } from '@msgpack/msgpack';
|
|
15
|
+
import { keccak_256 } from '@noble/hashes/sha3';
|
|
16
|
+
import { hexToBytes, concatBytes, bytesToHex } from '@noble/hashes/utils';
|
|
14
17
|
import { tmpdir } from 'os';
|
|
15
18
|
import { build } from 'esbuild';
|
|
16
19
|
import { createRequire } from 'module';
|
|
@@ -1343,6 +1346,18 @@ function normalizePrivateKey(raw) {
|
|
|
1343
1346
|
}
|
|
1344
1347
|
return withPrefix;
|
|
1345
1348
|
}
|
|
1349
|
+
function createNonceSource(start = Date.now()) {
|
|
1350
|
+
let last = start;
|
|
1351
|
+
return () => {
|
|
1352
|
+
const now = Date.now();
|
|
1353
|
+
if (now > last) {
|
|
1354
|
+
last = now;
|
|
1355
|
+
} else {
|
|
1356
|
+
last += 1;
|
|
1357
|
+
}
|
|
1358
|
+
return last;
|
|
1359
|
+
};
|
|
1360
|
+
}
|
|
1346
1361
|
function createPrivateKeyProvider(config) {
|
|
1347
1362
|
const privateKey = normalizePrivateKey(config.privateKey);
|
|
1348
1363
|
const account = privateKeyToAccount(privateKey);
|
|
@@ -1388,7 +1403,20 @@ function createPrivateKeyProvider(config) {
|
|
|
1388
1403
|
publicClient,
|
|
1389
1404
|
sendTransaction,
|
|
1390
1405
|
getNativeBalance,
|
|
1391
|
-
transfer
|
|
1406
|
+
transfer,
|
|
1407
|
+
nonceSource: createNonceSource()
|
|
1408
|
+
};
|
|
1409
|
+
}
|
|
1410
|
+
function createNonceSource2(start = Date.now()) {
|
|
1411
|
+
let last = start;
|
|
1412
|
+
return () => {
|
|
1413
|
+
const now = Date.now();
|
|
1414
|
+
if (now > last) {
|
|
1415
|
+
last = now;
|
|
1416
|
+
} else {
|
|
1417
|
+
last += 1;
|
|
1418
|
+
}
|
|
1419
|
+
return last;
|
|
1392
1420
|
};
|
|
1393
1421
|
}
|
|
1394
1422
|
async function createTurnkeyProvider(config) {
|
|
@@ -1446,11 +1474,12 @@ async function createTurnkeyProvider(config) {
|
|
|
1446
1474
|
publicClient,
|
|
1447
1475
|
sendTransaction,
|
|
1448
1476
|
getNativeBalance,
|
|
1449
|
-
transfer
|
|
1477
|
+
transfer,
|
|
1478
|
+
nonceSource: createNonceSource2()
|
|
1450
1479
|
};
|
|
1451
1480
|
}
|
|
1452
1481
|
|
|
1453
|
-
// src/
|
|
1482
|
+
// src/wallet/index.ts
|
|
1454
1483
|
function resolveChainSlug(reference) {
|
|
1455
1484
|
if (reference === void 0) {
|
|
1456
1485
|
return Object.entries(chains).find(([, meta]) => meta.id === DEFAULT_CHAIN.id)?.[0] || DEFAULT_CHAIN.slug;
|
|
@@ -1492,40 +1521,59 @@ function getRpcUrl(chain, options) {
|
|
|
1492
1521
|
return entry.rpcUrl(options);
|
|
1493
1522
|
}
|
|
1494
1523
|
async function wallet(options = {}) {
|
|
1495
|
-
|
|
1524
|
+
const envPrivateKey = process.env.PRIVATE_KEY?.trim();
|
|
1525
|
+
const envTurnkey = {
|
|
1526
|
+
organizationId: process.env.TURNKEY_SUBORG_ID?.trim(),
|
|
1527
|
+
apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY?.trim(),
|
|
1528
|
+
apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY?.trim(),
|
|
1529
|
+
signWith: process.env.TURNKEY_WALLET_ADDRESS?.trim(),
|
|
1530
|
+
apiBaseUrl: process.env.TURNKEY_API_BASE_URL?.trim()
|
|
1531
|
+
};
|
|
1532
|
+
const effectivePrivateKey = options.privateKey ?? envPrivateKey;
|
|
1533
|
+
const hasTurnkeyEnv = envTurnkey.organizationId && envTurnkey.apiPublicKey && envTurnkey.apiPrivateKey && envTurnkey.signWith;
|
|
1534
|
+
const effectiveTurnkey = options.turnkey ?? (hasTurnkeyEnv ? {
|
|
1535
|
+
organizationId: envTurnkey.organizationId,
|
|
1536
|
+
apiPublicKey: envTurnkey.apiPublicKey,
|
|
1537
|
+
apiPrivateKey: envTurnkey.apiPrivateKey,
|
|
1538
|
+
signWith: envTurnkey.signWith,
|
|
1539
|
+
...envTurnkey.apiBaseUrl ? { apiBaseUrl: envTurnkey.apiBaseUrl } : {}
|
|
1540
|
+
} : void 0);
|
|
1541
|
+
if (effectivePrivateKey && effectiveTurnkey) {
|
|
1496
1542
|
throw new Error("wallet() cannot be initialized with both privateKey and turnkey credentials");
|
|
1497
1543
|
}
|
|
1498
1544
|
const slug = resolveChainSlug(options.chain);
|
|
1499
1545
|
const chain = chains[slug];
|
|
1500
1546
|
const tokens2 = tokens[slug] ?? {};
|
|
1501
1547
|
const overrides = {};
|
|
1502
|
-
|
|
1503
|
-
|
|
1548
|
+
const envRpcUrl = process.env.RPC_URL?.trim();
|
|
1549
|
+
const envApiKey = process.env.ALCHEMY_API_KEY?.trim();
|
|
1550
|
+
if (options.rpcUrl ?? envRpcUrl) {
|
|
1551
|
+
overrides.url = options.rpcUrl ?? envRpcUrl;
|
|
1504
1552
|
}
|
|
1505
|
-
if (options.apiKey) {
|
|
1506
|
-
overrides.apiKey = options.apiKey;
|
|
1553
|
+
if (options.apiKey ?? envApiKey) {
|
|
1554
|
+
overrides.apiKey = options.apiKey ?? envApiKey;
|
|
1507
1555
|
}
|
|
1508
1556
|
const rpcUrl = getRpcUrl(slug, overrides);
|
|
1509
1557
|
let providerType = "readonly";
|
|
1510
1558
|
let signerProvider;
|
|
1511
|
-
if (
|
|
1559
|
+
if (effectivePrivateKey) {
|
|
1512
1560
|
signerProvider = createPrivateKeyProvider({
|
|
1513
1561
|
chain,
|
|
1514
1562
|
rpcUrl,
|
|
1515
|
-
privateKey:
|
|
1563
|
+
privateKey: effectivePrivateKey
|
|
1516
1564
|
});
|
|
1517
1565
|
providerType = "privateKey";
|
|
1518
|
-
} else if (
|
|
1566
|
+
} else if (effectiveTurnkey) {
|
|
1519
1567
|
const turnkeyConfig = {
|
|
1520
1568
|
chain,
|
|
1521
1569
|
rpcUrl,
|
|
1522
|
-
organizationId:
|
|
1523
|
-
apiPublicKey:
|
|
1524
|
-
apiPrivateKey:
|
|
1525
|
-
signWith:
|
|
1570
|
+
organizationId: effectiveTurnkey.organizationId,
|
|
1571
|
+
apiPublicKey: effectiveTurnkey.apiPublicKey,
|
|
1572
|
+
apiPrivateKey: effectiveTurnkey.apiPrivateKey,
|
|
1573
|
+
signWith: effectiveTurnkey.signWith
|
|
1526
1574
|
};
|
|
1527
|
-
if (
|
|
1528
|
-
turnkeyConfig.apiBaseUrl =
|
|
1575
|
+
if (effectiveTurnkey.apiBaseUrl) {
|
|
1576
|
+
turnkeyConfig.apiBaseUrl = effectiveTurnkey.apiBaseUrl;
|
|
1529
1577
|
}
|
|
1530
1578
|
signerProvider = await createTurnkeyProvider(turnkeyConfig);
|
|
1531
1579
|
providerType = "turnkey";
|
|
@@ -1540,7 +1588,8 @@ async function wallet(options = {}) {
|
|
|
1540
1588
|
rpcUrl,
|
|
1541
1589
|
providerType,
|
|
1542
1590
|
publicClient,
|
|
1543
|
-
getRpcUrl: (override) => getRpcUrl(slug, override)
|
|
1591
|
+
getRpcUrl: (override) => getRpcUrl(slug, override),
|
|
1592
|
+
...signerProvider ? { address: signerProvider.address } : {}
|
|
1544
1593
|
};
|
|
1545
1594
|
if (signerProvider) {
|
|
1546
1595
|
const { publicClient: _ignored, ...rest } = signerProvider;
|
|
@@ -1563,6 +1612,1450 @@ var walletToolkit = {
|
|
|
1563
1612
|
wallet
|
|
1564
1613
|
};
|
|
1565
1614
|
|
|
1615
|
+
// src/store/index.ts
|
|
1616
|
+
var StoreError = class extends Error {
|
|
1617
|
+
constructor(message, status, causeData) {
|
|
1618
|
+
super(message);
|
|
1619
|
+
this.status = status;
|
|
1620
|
+
this.causeData = causeData;
|
|
1621
|
+
this.name = "StoreError";
|
|
1622
|
+
}
|
|
1623
|
+
};
|
|
1624
|
+
function resolveConfig(options) {
|
|
1625
|
+
const baseUrl = options?.baseUrl ?? process.env.BASE_URL ?? "https://api.openpond.ai";
|
|
1626
|
+
const apiKey = options?.apiKey ?? process.env.OPENPOND_API_KEY;
|
|
1627
|
+
if (!baseUrl) {
|
|
1628
|
+
throw new StoreError("BASE_URL is required to store activity events");
|
|
1629
|
+
}
|
|
1630
|
+
if (!apiKey) {
|
|
1631
|
+
throw new StoreError(
|
|
1632
|
+
"OPENPOND_API_KEY is required to store activity events"
|
|
1633
|
+
);
|
|
1634
|
+
}
|
|
1635
|
+
const normalizedBaseUrl = baseUrl.replace(/\/$/, "");
|
|
1636
|
+
const fetchFn = options?.fetchFn ?? globalThis.fetch;
|
|
1637
|
+
if (!fetchFn) {
|
|
1638
|
+
throw new StoreError("Fetch is not available in this environment");
|
|
1639
|
+
}
|
|
1640
|
+
return { baseUrl: normalizedBaseUrl, apiKey, fetchFn };
|
|
1641
|
+
}
|
|
1642
|
+
async function store(input, options) {
|
|
1643
|
+
const { baseUrl, apiKey, fetchFn } = resolveConfig(options);
|
|
1644
|
+
const url = `${baseUrl}/apps/positions/tx`;
|
|
1645
|
+
let response;
|
|
1646
|
+
try {
|
|
1647
|
+
response = await fetchFn(url, {
|
|
1648
|
+
method: "POST",
|
|
1649
|
+
headers: {
|
|
1650
|
+
"content-type": "application/json",
|
|
1651
|
+
"openpond-api-key": apiKey
|
|
1652
|
+
},
|
|
1653
|
+
body: JSON.stringify(input)
|
|
1654
|
+
});
|
|
1655
|
+
} catch (error) {
|
|
1656
|
+
throw new StoreError("Failed to reach store endpoint", void 0, error);
|
|
1657
|
+
}
|
|
1658
|
+
if (!response.ok) {
|
|
1659
|
+
let body;
|
|
1660
|
+
try {
|
|
1661
|
+
body = await response.json();
|
|
1662
|
+
} catch {
|
|
1663
|
+
body = await response.text().catch(() => void 0);
|
|
1664
|
+
}
|
|
1665
|
+
throw new StoreError(
|
|
1666
|
+
`Store request failed with status ${response.status}`,
|
|
1667
|
+
response.status,
|
|
1668
|
+
body
|
|
1669
|
+
);
|
|
1670
|
+
}
|
|
1671
|
+
try {
|
|
1672
|
+
const data = await response.json();
|
|
1673
|
+
return {
|
|
1674
|
+
id: data.id ?? "",
|
|
1675
|
+
status: data.status ?? null
|
|
1676
|
+
};
|
|
1677
|
+
} catch {
|
|
1678
|
+
return { id: "", status: null };
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
async function retrieve(params, options) {
|
|
1682
|
+
const { baseUrl, apiKey, fetchFn } = resolveConfig(options);
|
|
1683
|
+
const url = new URL(`${baseUrl}/apps/positions/tx`);
|
|
1684
|
+
if (params?.source) url.searchParams.set("source", params.source);
|
|
1685
|
+
if (params?.walletAddress) url.searchParams.set("walletAddress", params.walletAddress);
|
|
1686
|
+
if (params?.symbol) url.searchParams.set("symbol", params.symbol);
|
|
1687
|
+
if (params?.status?.length) url.searchParams.set("status", params.status.join(","));
|
|
1688
|
+
if (typeof params?.since === "number") url.searchParams.set("since", params.since.toString());
|
|
1689
|
+
if (typeof params?.until === "number") url.searchParams.set("until", params.until.toString());
|
|
1690
|
+
if (typeof params?.limit === "number") url.searchParams.set("limit", params.limit.toString());
|
|
1691
|
+
if (params?.cursor) url.searchParams.set("cursor", params.cursor);
|
|
1692
|
+
if (params?.history) url.searchParams.set("history", "true");
|
|
1693
|
+
let response;
|
|
1694
|
+
try {
|
|
1695
|
+
response = await fetchFn(url.toString(), {
|
|
1696
|
+
method: "GET",
|
|
1697
|
+
headers: {
|
|
1698
|
+
"content-type": "application/json",
|
|
1699
|
+
"openpond-api-key": apiKey
|
|
1700
|
+
}
|
|
1701
|
+
});
|
|
1702
|
+
} catch (error) {
|
|
1703
|
+
throw new StoreError("Failed to reach store endpoint", void 0, error);
|
|
1704
|
+
}
|
|
1705
|
+
if (!response.ok) {
|
|
1706
|
+
let body;
|
|
1707
|
+
try {
|
|
1708
|
+
body = await response.json();
|
|
1709
|
+
} catch {
|
|
1710
|
+
body = await response.text().catch(() => void 0);
|
|
1711
|
+
}
|
|
1712
|
+
throw new StoreError(
|
|
1713
|
+
`Store retrieve failed with status ${response.status}`,
|
|
1714
|
+
response.status,
|
|
1715
|
+
body
|
|
1716
|
+
);
|
|
1717
|
+
}
|
|
1718
|
+
const data = await response.json().catch(() => null);
|
|
1719
|
+
if (!data) {
|
|
1720
|
+
return { items: [], cursor: null };
|
|
1721
|
+
}
|
|
1722
|
+
return data;
|
|
1723
|
+
}
|
|
1724
|
+
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
1725
|
+
var API_BASES = {
|
|
1726
|
+
mainnet: "https://api.hyperliquid.xyz",
|
|
1727
|
+
testnet: "https://api.hyperliquid-testnet.xyz"
|
|
1728
|
+
};
|
|
1729
|
+
var HL_ENDPOINT = {
|
|
1730
|
+
mainnet: "https://api.hyperliquid.xyz",
|
|
1731
|
+
testnet: "https://api.hyperliquid-testnet.xyz"
|
|
1732
|
+
};
|
|
1733
|
+
var HL_CHAIN_LABEL = {
|
|
1734
|
+
mainnet: "Mainnet",
|
|
1735
|
+
testnet: "Testnet"
|
|
1736
|
+
};
|
|
1737
|
+
var HL_BRIDGE_ADDRESSES = {
|
|
1738
|
+
mainnet: "0x2df1c51e09aecf9cacb7bc98cb1742757f163df7",
|
|
1739
|
+
testnet: "0x08cfc1b6b2dcf36a1480b99353a354aa8ac56f89"
|
|
1740
|
+
};
|
|
1741
|
+
var HL_USDC_ADDRESSES = {
|
|
1742
|
+
mainnet: "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
|
|
1743
|
+
testnet: "0x1baAbB04529D43a73232B713C0FE471f7c7334d5"
|
|
1744
|
+
};
|
|
1745
|
+
var HL_SIGNATURE_CHAIN_ID = {
|
|
1746
|
+
mainnet: "0xa4b1",
|
|
1747
|
+
testnet: "0x66eee"
|
|
1748
|
+
};
|
|
1749
|
+
var EXCHANGE_TYPED_DATA_DOMAIN = {
|
|
1750
|
+
name: "Exchange",
|
|
1751
|
+
version: "1",
|
|
1752
|
+
chainId: 1337,
|
|
1753
|
+
verifyingContract: "0x0000000000000000000000000000000000000000"
|
|
1754
|
+
};
|
|
1755
|
+
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
1756
|
+
var MIN_DEPOSIT_USDC = 5;
|
|
1757
|
+
var BUILDER_CODE = {
|
|
1758
|
+
address: "0x4b2aec4F91612849d6e20C9c1881FabB1A48cd12",
|
|
1759
|
+
fee: 100
|
|
1760
|
+
};
|
|
1761
|
+
var metaCache = /* @__PURE__ */ new Map();
|
|
1762
|
+
var HyperliquidApiError = class extends Error {
|
|
1763
|
+
constructor(message, response) {
|
|
1764
|
+
super(message);
|
|
1765
|
+
this.response = response;
|
|
1766
|
+
this.name = "HyperliquidApiError";
|
|
1767
|
+
}
|
|
1768
|
+
};
|
|
1769
|
+
var HyperliquidGuardError = class extends Error {
|
|
1770
|
+
constructor(message) {
|
|
1771
|
+
super(message);
|
|
1772
|
+
this.name = "HyperliquidGuardError";
|
|
1773
|
+
}
|
|
1774
|
+
};
|
|
1775
|
+
var HyperliquidTermsError = class extends HyperliquidGuardError {
|
|
1776
|
+
constructor(message = "Hyperliquid terms must be accepted before proceeding.") {
|
|
1777
|
+
super(message);
|
|
1778
|
+
this.name = "HyperliquidTermsError";
|
|
1779
|
+
}
|
|
1780
|
+
};
|
|
1781
|
+
var HyperliquidBuilderApprovalError = class extends HyperliquidGuardError {
|
|
1782
|
+
constructor(message = "Hyperliquid builder approval is required before using builder codes.") {
|
|
1783
|
+
super(message);
|
|
1784
|
+
this.name = "HyperliquidBuilderApprovalError";
|
|
1785
|
+
}
|
|
1786
|
+
};
|
|
1787
|
+
function createMonotonicNonceFactory(start = Date.now()) {
|
|
1788
|
+
let last = start;
|
|
1789
|
+
return () => {
|
|
1790
|
+
const now = Date.now();
|
|
1791
|
+
if (now > last) {
|
|
1792
|
+
last = now;
|
|
1793
|
+
} else {
|
|
1794
|
+
last += 1;
|
|
1795
|
+
}
|
|
1796
|
+
return last;
|
|
1797
|
+
};
|
|
1798
|
+
}
|
|
1799
|
+
async function getUniverse(args) {
|
|
1800
|
+
const cacheKey = `${args.environment}:${args.baseUrl}`;
|
|
1801
|
+
const cached = metaCache.get(cacheKey);
|
|
1802
|
+
if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
|
|
1803
|
+
return cached.universe;
|
|
1804
|
+
}
|
|
1805
|
+
const response = await args.fetcher(`${args.baseUrl}/info`, {
|
|
1806
|
+
method: "POST",
|
|
1807
|
+
headers: { "content-type": "application/json" },
|
|
1808
|
+
body: JSON.stringify({ type: "meta" })
|
|
1809
|
+
});
|
|
1810
|
+
const json = await response.json().catch(() => null);
|
|
1811
|
+
if (!response.ok || !json?.universe) {
|
|
1812
|
+
throw new HyperliquidApiError(
|
|
1813
|
+
"Unable to load Hyperliquid metadata.",
|
|
1814
|
+
json ?? { status: response.status }
|
|
1815
|
+
);
|
|
1816
|
+
}
|
|
1817
|
+
metaCache.set(cacheKey, { fetchedAt: Date.now(), universe: json.universe });
|
|
1818
|
+
return json.universe;
|
|
1819
|
+
}
|
|
1820
|
+
function resolveAssetIndex(symbol, universe) {
|
|
1821
|
+
const [raw] = symbol.split("-");
|
|
1822
|
+
const target = raw.trim();
|
|
1823
|
+
const index = universe.findIndex(
|
|
1824
|
+
(entry) => entry.name.toUpperCase() === target.toUpperCase()
|
|
1825
|
+
);
|
|
1826
|
+
if (index === -1) {
|
|
1827
|
+
throw new Error(`Unknown Hyperliquid asset symbol: ${symbol}`);
|
|
1828
|
+
}
|
|
1829
|
+
return index;
|
|
1830
|
+
}
|
|
1831
|
+
function toApiDecimal(value) {
|
|
1832
|
+
if (typeof value === "string") {
|
|
1833
|
+
return value;
|
|
1834
|
+
}
|
|
1835
|
+
if (typeof value === "bigint") {
|
|
1836
|
+
return value.toString();
|
|
1837
|
+
}
|
|
1838
|
+
if (!Number.isFinite(value)) {
|
|
1839
|
+
throw new Error("Numeric values must be finite.");
|
|
1840
|
+
}
|
|
1841
|
+
const asString = value.toString();
|
|
1842
|
+
if (/e/i.test(asString)) {
|
|
1843
|
+
const [mantissa, exponentPart] = asString.split(/e/i);
|
|
1844
|
+
const exponent = Number(exponentPart);
|
|
1845
|
+
const [integerPart, fractionalPart = ""] = mantissa.split(".");
|
|
1846
|
+
if (exponent >= 0) {
|
|
1847
|
+
return integerPart + fractionalPart.padEnd(exponent + fractionalPart.length, "0");
|
|
1848
|
+
}
|
|
1849
|
+
const zeros = "0".repeat(Math.abs(exponent) - 1);
|
|
1850
|
+
return `0.${zeros}${integerPart}${fractionalPart}`.replace(/\.0+$/, "");
|
|
1851
|
+
}
|
|
1852
|
+
return asString;
|
|
1853
|
+
}
|
|
1854
|
+
function normalizeHex(value) {
|
|
1855
|
+
const lower = value.toLowerCase();
|
|
1856
|
+
return lower.replace(/^0x0+/, "0x") || "0x0";
|
|
1857
|
+
}
|
|
1858
|
+
function normalizeAddress(value) {
|
|
1859
|
+
return normalizeHex(value);
|
|
1860
|
+
}
|
|
1861
|
+
async function signL1Action(args) {
|
|
1862
|
+
const { wallet: wallet2, action, nonce, vaultAddress, expiresAfter, isTestnet } = args;
|
|
1863
|
+
const actionHash = createL1ActionHash({
|
|
1864
|
+
action,
|
|
1865
|
+
nonce,
|
|
1866
|
+
vaultAddress,
|
|
1867
|
+
expiresAfter
|
|
1868
|
+
});
|
|
1869
|
+
const message = {
|
|
1870
|
+
source: isTestnet ? "b" : "a",
|
|
1871
|
+
connectionId: actionHash
|
|
1872
|
+
};
|
|
1873
|
+
const signatureHex = await wallet2.walletClient.signTypedData({
|
|
1874
|
+
account: wallet2.account,
|
|
1875
|
+
domain: EXCHANGE_TYPED_DATA_DOMAIN,
|
|
1876
|
+
types: {
|
|
1877
|
+
Agent: [
|
|
1878
|
+
{ name: "source", type: "string" },
|
|
1879
|
+
{ name: "connectionId", type: "bytes32" }
|
|
1880
|
+
]
|
|
1881
|
+
},
|
|
1882
|
+
primaryType: "Agent",
|
|
1883
|
+
message
|
|
1884
|
+
});
|
|
1885
|
+
return splitSignature(signatureHex);
|
|
1886
|
+
}
|
|
1887
|
+
async function signSpotSend(args) {
|
|
1888
|
+
const {
|
|
1889
|
+
wallet: wallet2,
|
|
1890
|
+
hyperliquidChain,
|
|
1891
|
+
signatureChainId,
|
|
1892
|
+
destination,
|
|
1893
|
+
token: token2,
|
|
1894
|
+
amount,
|
|
1895
|
+
time
|
|
1896
|
+
} = args;
|
|
1897
|
+
const domain = {
|
|
1898
|
+
name: "HyperliquidSignTransaction",
|
|
1899
|
+
version: "1",
|
|
1900
|
+
chainId: Number.parseInt(signatureChainId, 16),
|
|
1901
|
+
verifyingContract: ZERO_ADDRESS
|
|
1902
|
+
};
|
|
1903
|
+
const message = {
|
|
1904
|
+
hyperliquidChain,
|
|
1905
|
+
destination,
|
|
1906
|
+
token: token2,
|
|
1907
|
+
amount,
|
|
1908
|
+
time
|
|
1909
|
+
};
|
|
1910
|
+
const types = {
|
|
1911
|
+
"HyperliquidTransaction:SpotSend": [
|
|
1912
|
+
{ name: "hyperliquidChain", type: "string" },
|
|
1913
|
+
{ name: "destination", type: "string" },
|
|
1914
|
+
{ name: "token", type: "string" },
|
|
1915
|
+
{ name: "amount", type: "string" },
|
|
1916
|
+
{ name: "time", type: "uint64" }
|
|
1917
|
+
]
|
|
1918
|
+
};
|
|
1919
|
+
const signatureHex = await wallet2.walletClient.signTypedData({
|
|
1920
|
+
account: wallet2.account,
|
|
1921
|
+
domain,
|
|
1922
|
+
types,
|
|
1923
|
+
primaryType: "HyperliquidTransaction:SpotSend",
|
|
1924
|
+
message
|
|
1925
|
+
});
|
|
1926
|
+
return splitSignature(signatureHex);
|
|
1927
|
+
}
|
|
1928
|
+
async function signApproveBuilderFee(args) {
|
|
1929
|
+
const { wallet: wallet2, maxFeeRate, nonce, signatureChainId, isTestnet } = args;
|
|
1930
|
+
const hyperliquidChain = isTestnet ? "Testnet" : "Mainnet";
|
|
1931
|
+
const domain = {
|
|
1932
|
+
name: "HyperliquidSignTransaction",
|
|
1933
|
+
version: "1",
|
|
1934
|
+
chainId: Number.parseInt(signatureChainId, 16),
|
|
1935
|
+
verifyingContract: ZERO_ADDRESS
|
|
1936
|
+
};
|
|
1937
|
+
const message = {
|
|
1938
|
+
hyperliquidChain,
|
|
1939
|
+
maxFeeRate,
|
|
1940
|
+
builder: BUILDER_CODE.address,
|
|
1941
|
+
nonce
|
|
1942
|
+
};
|
|
1943
|
+
const types = {
|
|
1944
|
+
"HyperliquidTransaction:ApproveBuilderFee": [
|
|
1945
|
+
{ name: "hyperliquidChain", type: "string" },
|
|
1946
|
+
{ name: "maxFeeRate", type: "string" },
|
|
1947
|
+
{ name: "builder", type: "address" },
|
|
1948
|
+
{ name: "nonce", type: "uint64" }
|
|
1949
|
+
]
|
|
1950
|
+
};
|
|
1951
|
+
const signatureHex = await wallet2.walletClient.signTypedData({
|
|
1952
|
+
account: wallet2.account,
|
|
1953
|
+
domain,
|
|
1954
|
+
types,
|
|
1955
|
+
primaryType: "HyperliquidTransaction:ApproveBuilderFee",
|
|
1956
|
+
message
|
|
1957
|
+
});
|
|
1958
|
+
return splitSignature(signatureHex);
|
|
1959
|
+
}
|
|
1960
|
+
function splitSignature(signature) {
|
|
1961
|
+
const cleaned = signature.slice(2);
|
|
1962
|
+
const rHex = `0x${cleaned.slice(0, 64)}`;
|
|
1963
|
+
const sHex = `0x${cleaned.slice(64, 128)}`;
|
|
1964
|
+
let v = parseInt(cleaned.slice(128, 130), 16);
|
|
1965
|
+
if (Number.isNaN(v)) {
|
|
1966
|
+
throw new Error("Invalid signature returned by wallet client.");
|
|
1967
|
+
}
|
|
1968
|
+
if (v < 27) {
|
|
1969
|
+
v += 27;
|
|
1970
|
+
}
|
|
1971
|
+
const normalizedV = v === 27 || v === 28 ? v : v % 2 ? 27 : 28;
|
|
1972
|
+
return {
|
|
1973
|
+
r: normalizeHex(rHex),
|
|
1974
|
+
s: normalizeHex(sHex),
|
|
1975
|
+
v: normalizedV
|
|
1976
|
+
};
|
|
1977
|
+
}
|
|
1978
|
+
function createL1ActionHash(args) {
|
|
1979
|
+
const { action, nonce, vaultAddress, expiresAfter } = args;
|
|
1980
|
+
const actionBytes = encode(action, { ignoreUndefined: true });
|
|
1981
|
+
const nonceBytes = toUint64Bytes(nonce);
|
|
1982
|
+
const vaultMarker = vaultAddress ? new Uint8Array([1]) : new Uint8Array([0]);
|
|
1983
|
+
const vaultBytes = vaultAddress ? hexToBytes(vaultAddress.slice(2)) : new Uint8Array();
|
|
1984
|
+
const hasExpiresAfter = typeof expiresAfter === "number";
|
|
1985
|
+
const expiresMarker = hasExpiresAfter ? new Uint8Array([0]) : new Uint8Array();
|
|
1986
|
+
const expiresBytes = hasExpiresAfter && expiresAfter !== void 0 ? toUint64Bytes(expiresAfter) : new Uint8Array();
|
|
1987
|
+
const bytes = concatBytes(
|
|
1988
|
+
actionBytes,
|
|
1989
|
+
nonceBytes,
|
|
1990
|
+
vaultMarker,
|
|
1991
|
+
vaultBytes,
|
|
1992
|
+
expiresMarker,
|
|
1993
|
+
expiresBytes
|
|
1994
|
+
);
|
|
1995
|
+
const hash = keccak_256(bytes);
|
|
1996
|
+
return `0x${bytesToHex(hash)}`;
|
|
1997
|
+
}
|
|
1998
|
+
function toUint64Bytes(value) {
|
|
1999
|
+
const bytes = new Uint8Array(8);
|
|
2000
|
+
new DataView(bytes.buffer).setBigUint64(0, BigInt(value));
|
|
2001
|
+
return bytes;
|
|
2002
|
+
}
|
|
2003
|
+
function getBridgeAddress(env) {
|
|
2004
|
+
const override = process.env.HYPERLIQUID_BRIDGE_ADDRESS;
|
|
2005
|
+
if (override?.trim()) {
|
|
2006
|
+
return normalizeAddress(override);
|
|
2007
|
+
}
|
|
2008
|
+
return HL_BRIDGE_ADDRESSES[env];
|
|
2009
|
+
}
|
|
2010
|
+
function getUsdcAddress(env) {
|
|
2011
|
+
const override = process.env.HYPERLIQUID_USDC_ADDRESS;
|
|
2012
|
+
if (override?.trim()) {
|
|
2013
|
+
return normalizeAddress(override);
|
|
2014
|
+
}
|
|
2015
|
+
return HL_USDC_ADDRESSES[env];
|
|
2016
|
+
}
|
|
2017
|
+
function getSignatureChainId(env) {
|
|
2018
|
+
const override = process.env.HYPERLIQUID_SIGNATURE_CHAIN_ID;
|
|
2019
|
+
const selected = override?.trim() || HL_SIGNATURE_CHAIN_ID[env];
|
|
2020
|
+
return normalizeHex(selected);
|
|
2021
|
+
}
|
|
2022
|
+
function assertPositiveNumber(value, label) {
|
|
2023
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
2024
|
+
throw new Error(`${label} must be a positive number.`);
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
// src/adapters/hyperliquid/exchange.ts
|
|
2029
|
+
var HyperliquidExchangeClient = class {
|
|
2030
|
+
constructor(args) {
|
|
2031
|
+
this.wallet = args.wallet;
|
|
2032
|
+
this.environment = args.environment ?? "mainnet";
|
|
2033
|
+
this.vaultAddress = args.vaultAddress;
|
|
2034
|
+
this.expiresAfter = args.expiresAfter;
|
|
2035
|
+
const resolvedNonceSource = args.walletNonceProvider ?? args.wallet.nonceSource ?? args.nonceSource;
|
|
2036
|
+
if (!resolvedNonceSource) {
|
|
2037
|
+
throw new Error(
|
|
2038
|
+
"Wallet nonce source is required for Hyperliquid exchange actions."
|
|
2039
|
+
);
|
|
2040
|
+
}
|
|
2041
|
+
this.nonceSource = resolvedNonceSource;
|
|
2042
|
+
}
|
|
2043
|
+
cancel(cancels) {
|
|
2044
|
+
return cancelHyperliquidOrders({
|
|
2045
|
+
wallet: this.wallet,
|
|
2046
|
+
cancels,
|
|
2047
|
+
environment: this.environment,
|
|
2048
|
+
vaultAddress: this.vaultAddress,
|
|
2049
|
+
expiresAfter: this.expiresAfter,
|
|
2050
|
+
nonceSource: this.nonceSource
|
|
2051
|
+
});
|
|
2052
|
+
}
|
|
2053
|
+
cancelByCloid(cancels) {
|
|
2054
|
+
return cancelHyperliquidOrdersByCloid({
|
|
2055
|
+
wallet: this.wallet,
|
|
2056
|
+
cancels,
|
|
2057
|
+
environment: this.environment,
|
|
2058
|
+
vaultAddress: this.vaultAddress,
|
|
2059
|
+
expiresAfter: this.expiresAfter,
|
|
2060
|
+
nonceSource: this.nonceSource
|
|
2061
|
+
});
|
|
2062
|
+
}
|
|
2063
|
+
cancelAll() {
|
|
2064
|
+
return cancelAllHyperliquidOrders({
|
|
2065
|
+
wallet: this.wallet,
|
|
2066
|
+
environment: this.environment,
|
|
2067
|
+
vaultAddress: this.vaultAddress,
|
|
2068
|
+
expiresAfter: this.expiresAfter,
|
|
2069
|
+
nonceSource: this.nonceSource
|
|
2070
|
+
});
|
|
2071
|
+
}
|
|
2072
|
+
scheduleCancel(time) {
|
|
2073
|
+
return scheduleHyperliquidCancel({
|
|
2074
|
+
wallet: this.wallet,
|
|
2075
|
+
time,
|
|
2076
|
+
environment: this.environment,
|
|
2077
|
+
vaultAddress: this.vaultAddress,
|
|
2078
|
+
expiresAfter: this.expiresAfter,
|
|
2079
|
+
nonceSource: this.nonceSource
|
|
2080
|
+
});
|
|
2081
|
+
}
|
|
2082
|
+
modify(modification) {
|
|
2083
|
+
return modifyHyperliquidOrder({
|
|
2084
|
+
wallet: this.wallet,
|
|
2085
|
+
modification,
|
|
2086
|
+
environment: this.environment,
|
|
2087
|
+
vaultAddress: this.vaultAddress,
|
|
2088
|
+
expiresAfter: this.expiresAfter,
|
|
2089
|
+
nonceSource: this.nonceSource
|
|
2090
|
+
});
|
|
2091
|
+
}
|
|
2092
|
+
batchModify(modifications) {
|
|
2093
|
+
return batchModifyHyperliquidOrders({
|
|
2094
|
+
wallet: this.wallet,
|
|
2095
|
+
modifications,
|
|
2096
|
+
environment: this.environment,
|
|
2097
|
+
vaultAddress: this.vaultAddress,
|
|
2098
|
+
expiresAfter: this.expiresAfter,
|
|
2099
|
+
nonceSource: this.nonceSource
|
|
2100
|
+
});
|
|
2101
|
+
}
|
|
2102
|
+
twapOrder(twap) {
|
|
2103
|
+
return placeHyperliquidTwapOrder({
|
|
2104
|
+
wallet: this.wallet,
|
|
2105
|
+
twap,
|
|
2106
|
+
environment: this.environment,
|
|
2107
|
+
vaultAddress: this.vaultAddress,
|
|
2108
|
+
expiresAfter: this.expiresAfter,
|
|
2109
|
+
nonceSource: this.nonceSource
|
|
2110
|
+
});
|
|
2111
|
+
}
|
|
2112
|
+
twapCancel(cancel) {
|
|
2113
|
+
return cancelHyperliquidTwapOrder({
|
|
2114
|
+
wallet: this.wallet,
|
|
2115
|
+
cancel,
|
|
2116
|
+
environment: this.environment,
|
|
2117
|
+
vaultAddress: this.vaultAddress,
|
|
2118
|
+
expiresAfter: this.expiresAfter,
|
|
2119
|
+
nonceSource: this.nonceSource
|
|
2120
|
+
});
|
|
2121
|
+
}
|
|
2122
|
+
updateLeverage(input) {
|
|
2123
|
+
return updateHyperliquidLeverage({
|
|
2124
|
+
wallet: this.wallet,
|
|
2125
|
+
input,
|
|
2126
|
+
environment: this.environment,
|
|
2127
|
+
vaultAddress: this.vaultAddress,
|
|
2128
|
+
expiresAfter: this.expiresAfter,
|
|
2129
|
+
nonceSource: this.nonceSource
|
|
2130
|
+
});
|
|
2131
|
+
}
|
|
2132
|
+
updateIsolatedMargin(input) {
|
|
2133
|
+
return updateHyperliquidIsolatedMargin({
|
|
2134
|
+
wallet: this.wallet,
|
|
2135
|
+
input,
|
|
2136
|
+
environment: this.environment,
|
|
2137
|
+
vaultAddress: this.vaultAddress,
|
|
2138
|
+
expiresAfter: this.expiresAfter,
|
|
2139
|
+
nonceSource: this.nonceSource
|
|
2140
|
+
});
|
|
2141
|
+
}
|
|
2142
|
+
reserveRequestWeight(weight) {
|
|
2143
|
+
return reserveHyperliquidRequestWeight({
|
|
2144
|
+
wallet: this.wallet,
|
|
2145
|
+
weight,
|
|
2146
|
+
environment: this.environment,
|
|
2147
|
+
vaultAddress: this.vaultAddress,
|
|
2148
|
+
expiresAfter: this.expiresAfter,
|
|
2149
|
+
nonceSource: this.nonceSource
|
|
2150
|
+
});
|
|
2151
|
+
}
|
|
2152
|
+
spotSend(params) {
|
|
2153
|
+
return sendHyperliquidSpot({
|
|
2154
|
+
wallet: this.wallet,
|
|
2155
|
+
environment: this.environment,
|
|
2156
|
+
nonceSource: this.nonceSource,
|
|
2157
|
+
...params
|
|
2158
|
+
});
|
|
2159
|
+
}
|
|
2160
|
+
};
|
|
2161
|
+
async function cancelHyperliquidOrders(options) {
|
|
2162
|
+
options.cancels.forEach((c) => assertSymbol(c.symbol));
|
|
2163
|
+
const action = {
|
|
2164
|
+
type: "cancel",
|
|
2165
|
+
cancels: await withAssetIndexes(options, options.cancels, (idx, entry) => ({
|
|
2166
|
+
a: idx,
|
|
2167
|
+
o: entry.oid
|
|
2168
|
+
}))
|
|
2169
|
+
};
|
|
2170
|
+
return submitExchangeAction(options, action);
|
|
2171
|
+
}
|
|
2172
|
+
async function cancelHyperliquidOrdersByCloid(options) {
|
|
2173
|
+
options.cancels.forEach((c) => assertSymbol(c.symbol));
|
|
2174
|
+
const action = {
|
|
2175
|
+
type: "cancelByCloid",
|
|
2176
|
+
cancels: await withAssetIndexes(
|
|
2177
|
+
options,
|
|
2178
|
+
options.cancels,
|
|
2179
|
+
(idx, entry) => ({
|
|
2180
|
+
a: idx,
|
|
2181
|
+
c: normalizeAddress(entry.cloid)
|
|
2182
|
+
})
|
|
2183
|
+
)
|
|
2184
|
+
};
|
|
2185
|
+
return submitExchangeAction(options, action);
|
|
2186
|
+
}
|
|
2187
|
+
async function cancelAllHyperliquidOrders(options) {
|
|
2188
|
+
const action = { type: "cancelAll" };
|
|
2189
|
+
return submitExchangeAction(options, action);
|
|
2190
|
+
}
|
|
2191
|
+
async function scheduleHyperliquidCancel(options) {
|
|
2192
|
+
if (options.time !== null) {
|
|
2193
|
+
assertPositiveNumber(options.time, "time");
|
|
2194
|
+
}
|
|
2195
|
+
const action = { type: "scheduleCancel", time: options.time };
|
|
2196
|
+
return submitExchangeAction(options, action);
|
|
2197
|
+
}
|
|
2198
|
+
async function modifyHyperliquidOrder(options) {
|
|
2199
|
+
const { modification } = options;
|
|
2200
|
+
const order = await buildOrder(modification.order, options);
|
|
2201
|
+
const action = {
|
|
2202
|
+
type: "modify",
|
|
2203
|
+
oid: modification.oid,
|
|
2204
|
+
order
|
|
2205
|
+
};
|
|
2206
|
+
return submitExchangeAction(options, action);
|
|
2207
|
+
}
|
|
2208
|
+
async function batchModifyHyperliquidOrders(options) {
|
|
2209
|
+
options.modifications.forEach((m) => assertSymbol(m.order.symbol));
|
|
2210
|
+
const modifies = await Promise.all(
|
|
2211
|
+
options.modifications.map(async (mod) => ({
|
|
2212
|
+
oid: mod.oid,
|
|
2213
|
+
order: await buildOrder(mod.order, options)
|
|
2214
|
+
}))
|
|
2215
|
+
);
|
|
2216
|
+
const action = {
|
|
2217
|
+
type: "batchModify",
|
|
2218
|
+
modifies
|
|
2219
|
+
};
|
|
2220
|
+
return submitExchangeAction(options, action);
|
|
2221
|
+
}
|
|
2222
|
+
async function placeHyperliquidTwapOrder(options) {
|
|
2223
|
+
const { twap } = options;
|
|
2224
|
+
assertSymbol(twap.symbol);
|
|
2225
|
+
assertPositiveDecimal(twap.size, "size");
|
|
2226
|
+
assertPositiveNumber(twap.minutes, "minutes");
|
|
2227
|
+
const env = options.environment ?? "mainnet";
|
|
2228
|
+
const universe = await getUniverse({
|
|
2229
|
+
baseUrl: API_BASES[env],
|
|
2230
|
+
environment: env,
|
|
2231
|
+
fetcher: fetch
|
|
2232
|
+
});
|
|
2233
|
+
const asset = resolveAssetIndex(twap.symbol, universe);
|
|
2234
|
+
const action = {
|
|
2235
|
+
type: "twapOrder",
|
|
2236
|
+
twap: {
|
|
2237
|
+
a: asset,
|
|
2238
|
+
b: twap.side === "buy",
|
|
2239
|
+
s: toApiDecimal(twap.size),
|
|
2240
|
+
r: Boolean(twap.reduceOnly),
|
|
2241
|
+
m: twap.minutes,
|
|
2242
|
+
t: Boolean(twap.randomize)
|
|
2243
|
+
}
|
|
2244
|
+
};
|
|
2245
|
+
return submitExchangeAction(options, action);
|
|
2246
|
+
}
|
|
2247
|
+
async function cancelHyperliquidTwapOrder(options) {
|
|
2248
|
+
assertSymbol(options.cancel.symbol);
|
|
2249
|
+
const env = options.environment ?? "mainnet";
|
|
2250
|
+
const universe = await getUniverse({
|
|
2251
|
+
baseUrl: API_BASES[env],
|
|
2252
|
+
environment: env,
|
|
2253
|
+
fetcher: fetch
|
|
2254
|
+
});
|
|
2255
|
+
const asset = resolveAssetIndex(options.cancel.symbol, universe);
|
|
2256
|
+
const action = {
|
|
2257
|
+
type: "twapCancel",
|
|
2258
|
+
a: asset,
|
|
2259
|
+
t: options.cancel.twapId
|
|
2260
|
+
};
|
|
2261
|
+
return submitExchangeAction(options, action);
|
|
2262
|
+
}
|
|
2263
|
+
async function updateHyperliquidLeverage(options) {
|
|
2264
|
+
assertSymbol(options.input.symbol);
|
|
2265
|
+
assertPositiveNumber(options.input.leverage, "leverage");
|
|
2266
|
+
const env = options.environment ?? "mainnet";
|
|
2267
|
+
const universe = await getUniverse({
|
|
2268
|
+
baseUrl: API_BASES[env],
|
|
2269
|
+
environment: env,
|
|
2270
|
+
fetcher: fetch
|
|
2271
|
+
});
|
|
2272
|
+
const asset = resolveAssetIndex(options.input.symbol, universe);
|
|
2273
|
+
const action = {
|
|
2274
|
+
type: "updateLeverage",
|
|
2275
|
+
asset,
|
|
2276
|
+
isCross: options.input.leverageMode === "cross",
|
|
2277
|
+
leverage: options.input.leverage
|
|
2278
|
+
};
|
|
2279
|
+
return submitExchangeAction(options, action);
|
|
2280
|
+
}
|
|
2281
|
+
async function updateHyperliquidIsolatedMargin(options) {
|
|
2282
|
+
assertSymbol(options.input.symbol);
|
|
2283
|
+
assertPositiveNumber(options.input.ntli, "ntli");
|
|
2284
|
+
const env = options.environment ?? "mainnet";
|
|
2285
|
+
const universe = await getUniverse({
|
|
2286
|
+
baseUrl: API_BASES[env],
|
|
2287
|
+
environment: env,
|
|
2288
|
+
fetcher: fetch
|
|
2289
|
+
});
|
|
2290
|
+
const asset = resolveAssetIndex(options.input.symbol, universe);
|
|
2291
|
+
const action = {
|
|
2292
|
+
type: "updateIsolatedMargin",
|
|
2293
|
+
asset,
|
|
2294
|
+
isBuy: options.input.isBuy,
|
|
2295
|
+
ntli: options.input.ntli
|
|
2296
|
+
};
|
|
2297
|
+
return submitExchangeAction(options, action);
|
|
2298
|
+
}
|
|
2299
|
+
async function reserveHyperliquidRequestWeight(options) {
|
|
2300
|
+
assertPositiveNumber(options.weight, "weight");
|
|
2301
|
+
const action = {
|
|
2302
|
+
type: "reserveRequestWeight",
|
|
2303
|
+
weight: options.weight
|
|
2304
|
+
};
|
|
2305
|
+
return submitExchangeAction(options, action);
|
|
2306
|
+
}
|
|
2307
|
+
async function createHyperliquidSubAccount(options) {
|
|
2308
|
+
assertString(options.name, "name");
|
|
2309
|
+
const action = {
|
|
2310
|
+
type: "createSubAccount",
|
|
2311
|
+
name: options.name
|
|
2312
|
+
};
|
|
2313
|
+
return submitExchangeAction(options, action);
|
|
2314
|
+
}
|
|
2315
|
+
async function transferHyperliquidSubAccount(options) {
|
|
2316
|
+
assertString(options.subAccountUser, "subAccountUser");
|
|
2317
|
+
const usdScaled = normalizeUsdToInt(options.usd);
|
|
2318
|
+
const action = {
|
|
2319
|
+
type: "subAccountTransfer",
|
|
2320
|
+
subAccountUser: normalizeAddress(options.subAccountUser),
|
|
2321
|
+
isDeposit: Boolean(options.isDeposit),
|
|
2322
|
+
usd: usdScaled
|
|
2323
|
+
};
|
|
2324
|
+
return submitExchangeAction(options, action);
|
|
2325
|
+
}
|
|
2326
|
+
async function sendHyperliquidSpot(options) {
|
|
2327
|
+
const env = options.environment ?? "mainnet";
|
|
2328
|
+
if (!options.wallet.account || !options.wallet.walletClient) {
|
|
2329
|
+
throw new Error("Wallet with signing capability is required for spotSend.");
|
|
2330
|
+
}
|
|
2331
|
+
assertString(options.token, "token");
|
|
2332
|
+
assertPositiveDecimal(options.amount, "amount");
|
|
2333
|
+
const signatureChainId = getSignatureChainId(env);
|
|
2334
|
+
const hyperliquidChain = HL_CHAIN_LABEL[env];
|
|
2335
|
+
const nonce = options.nonce ?? options.nonceSource?.() ?? Date.now();
|
|
2336
|
+
const time = BigInt(nonce);
|
|
2337
|
+
const signature = await signSpotSend({
|
|
2338
|
+
wallet: options.wallet,
|
|
2339
|
+
hyperliquidChain,
|
|
2340
|
+
signatureChainId,
|
|
2341
|
+
destination: normalizeAddress(options.destination),
|
|
2342
|
+
token: options.token,
|
|
2343
|
+
amount: toApiDecimal(options.amount),
|
|
2344
|
+
time
|
|
2345
|
+
});
|
|
2346
|
+
const action = {
|
|
2347
|
+
type: "spotSend",
|
|
2348
|
+
hyperliquidChain,
|
|
2349
|
+
signatureChainId,
|
|
2350
|
+
destination: normalizeAddress(options.destination),
|
|
2351
|
+
token: options.token,
|
|
2352
|
+
amount: toApiDecimal(options.amount),
|
|
2353
|
+
time: nonce
|
|
2354
|
+
};
|
|
2355
|
+
return postExchange(env, { action, nonce, signature });
|
|
2356
|
+
}
|
|
2357
|
+
async function submitExchangeAction(options, action) {
|
|
2358
|
+
if (!options.wallet?.account || !options.wallet.walletClient) {
|
|
2359
|
+
throw new Error("Hyperliquid exchange actions require a signing wallet.");
|
|
2360
|
+
}
|
|
2361
|
+
const env = options.environment ?? "mainnet";
|
|
2362
|
+
const nonceSource = options.walletNonceProvider ?? options.wallet.nonceSource ?? options.nonceSource;
|
|
2363
|
+
if (!nonceSource && options.nonce === void 0) {
|
|
2364
|
+
throw new Error("Wallet nonce source is required for Hyperliquid exchange actions.");
|
|
2365
|
+
}
|
|
2366
|
+
const effectiveNonce = options.nonce ?? nonceSource?.();
|
|
2367
|
+
if (effectiveNonce === void 0) {
|
|
2368
|
+
throw new Error("Hyperliquid exchange actions require a nonce.");
|
|
2369
|
+
}
|
|
2370
|
+
const signature = await signL1Action({
|
|
2371
|
+
wallet: options.wallet,
|
|
2372
|
+
action,
|
|
2373
|
+
nonce: effectiveNonce,
|
|
2374
|
+
vaultAddress: options.vaultAddress ? normalizeAddress(options.vaultAddress) : void 0,
|
|
2375
|
+
expiresAfter: options.expiresAfter,
|
|
2376
|
+
isTestnet: env === "testnet"
|
|
2377
|
+
});
|
|
2378
|
+
const body = {
|
|
2379
|
+
action,
|
|
2380
|
+
nonce: effectiveNonce,
|
|
2381
|
+
signature
|
|
2382
|
+
};
|
|
2383
|
+
if (options.vaultAddress) {
|
|
2384
|
+
body.vaultAddress = normalizeAddress(options.vaultAddress);
|
|
2385
|
+
}
|
|
2386
|
+
if (typeof options.expiresAfter === "number") {
|
|
2387
|
+
body.expiresAfter = options.expiresAfter;
|
|
2388
|
+
}
|
|
2389
|
+
return postExchange(env, body);
|
|
2390
|
+
}
|
|
2391
|
+
async function withAssetIndexes(options, entries, mapper) {
|
|
2392
|
+
const env = options.environment ?? "mainnet";
|
|
2393
|
+
const universe = await getUniverse({
|
|
2394
|
+
baseUrl: API_BASES[env],
|
|
2395
|
+
environment: env,
|
|
2396
|
+
fetcher: fetch
|
|
2397
|
+
});
|
|
2398
|
+
return Promise.all(
|
|
2399
|
+
entries.map(async (entry) => {
|
|
2400
|
+
const assetIndex = resolveAssetIndex(entry.symbol, universe);
|
|
2401
|
+
return mapper(assetIndex, entry);
|
|
2402
|
+
})
|
|
2403
|
+
);
|
|
2404
|
+
}
|
|
2405
|
+
async function buildOrder(intent, options) {
|
|
2406
|
+
assertSymbol(intent.symbol);
|
|
2407
|
+
assertPositiveDecimal(intent.price, "price");
|
|
2408
|
+
assertPositiveDecimal(intent.size, "size");
|
|
2409
|
+
const env = options.environment ?? "mainnet";
|
|
2410
|
+
const universe = await getUniverse({
|
|
2411
|
+
baseUrl: API_BASES[env],
|
|
2412
|
+
environment: env,
|
|
2413
|
+
fetcher: fetch
|
|
2414
|
+
});
|
|
2415
|
+
const assetIndex = resolveAssetIndex(intent.symbol, universe);
|
|
2416
|
+
const limitOrTrigger = intent.trigger ? mapTrigger(intent.trigger) : {
|
|
2417
|
+
limit: {
|
|
2418
|
+
tif: intent.tif ?? "Ioc"
|
|
2419
|
+
}
|
|
2420
|
+
};
|
|
2421
|
+
return {
|
|
2422
|
+
a: assetIndex,
|
|
2423
|
+
b: intent.side === "buy",
|
|
2424
|
+
p: toApiDecimal(intent.price),
|
|
2425
|
+
s: toApiDecimal(intent.size),
|
|
2426
|
+
r: intent.reduceOnly ?? false,
|
|
2427
|
+
t: limitOrTrigger,
|
|
2428
|
+
...intent.clientId ? {
|
|
2429
|
+
c: normalizeAddress(intent.clientId)
|
|
2430
|
+
} : {}
|
|
2431
|
+
};
|
|
2432
|
+
}
|
|
2433
|
+
function mapTrigger(trigger) {
|
|
2434
|
+
assertPositiveDecimal(trigger.triggerPx, "triggerPx");
|
|
2435
|
+
return {
|
|
2436
|
+
trigger: {
|
|
2437
|
+
isMarket: Boolean(trigger.isMarket),
|
|
2438
|
+
triggerPx: toApiDecimal(trigger.triggerPx),
|
|
2439
|
+
tpsl: trigger.tpsl
|
|
2440
|
+
}
|
|
2441
|
+
};
|
|
2442
|
+
}
|
|
2443
|
+
function assertSymbol(value) {
|
|
2444
|
+
assertString(value, "symbol");
|
|
2445
|
+
}
|
|
2446
|
+
function normalizeUsdToInt(value) {
|
|
2447
|
+
if (typeof value === "bigint") {
|
|
2448
|
+
if (value < 0n) {
|
|
2449
|
+
throw new Error("usd must be non-negative.");
|
|
2450
|
+
}
|
|
2451
|
+
return Number(value);
|
|
2452
|
+
}
|
|
2453
|
+
const parsed = typeof value === "string" ? Number.parseFloat(value) : Number(value);
|
|
2454
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
2455
|
+
throw new Error("usd must be a non-negative number.");
|
|
2456
|
+
}
|
|
2457
|
+
return Math.round(parsed * 1e6);
|
|
2458
|
+
}
|
|
2459
|
+
function assertString(value, label) {
|
|
2460
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
2461
|
+
throw new Error(`${label} must be a non-empty string.`);
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
function assertPositiveDecimal(value, label) {
|
|
2465
|
+
if (typeof value === "number") {
|
|
2466
|
+
assertPositiveNumber(value, label);
|
|
2467
|
+
return;
|
|
2468
|
+
}
|
|
2469
|
+
if (typeof value === "bigint") {
|
|
2470
|
+
if (value <= 0n) {
|
|
2471
|
+
throw new Error(`${label} must be positive.`);
|
|
2472
|
+
}
|
|
2473
|
+
return;
|
|
2474
|
+
}
|
|
2475
|
+
assertString(value, label);
|
|
2476
|
+
}
|
|
2477
|
+
async function postExchange(env, body) {
|
|
2478
|
+
const response = await fetch(`${API_BASES[env]}/exchange`, {
|
|
2479
|
+
method: "POST",
|
|
2480
|
+
headers: { "content-type": "application/json" },
|
|
2481
|
+
body: JSON.stringify(body)
|
|
2482
|
+
});
|
|
2483
|
+
const json = await response.json().catch(() => null);
|
|
2484
|
+
if (!response.ok || !json) {
|
|
2485
|
+
throw new HyperliquidApiError(
|
|
2486
|
+
"Hyperliquid exchange action failed.",
|
|
2487
|
+
json ?? { status: response.status }
|
|
2488
|
+
);
|
|
2489
|
+
}
|
|
2490
|
+
if (json.status !== "ok") {
|
|
2491
|
+
throw new HyperliquidApiError("Hyperliquid exchange returned error.", json);
|
|
2492
|
+
}
|
|
2493
|
+
return json;
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
// src/adapters/hyperliquid/info.ts
|
|
2497
|
+
async function postInfo(environment, payload) {
|
|
2498
|
+
const baseUrl = API_BASES[environment];
|
|
2499
|
+
const response = await fetch(`${baseUrl}/info`, {
|
|
2500
|
+
method: "POST",
|
|
2501
|
+
headers: { "content-type": "application/json" },
|
|
2502
|
+
body: JSON.stringify(payload)
|
|
2503
|
+
});
|
|
2504
|
+
const data = await response.json().catch(() => null);
|
|
2505
|
+
if (!response.ok) {
|
|
2506
|
+
throw new HyperliquidApiError(
|
|
2507
|
+
"Hyperliquid info request failed.",
|
|
2508
|
+
data ?? { status: response.status }
|
|
2509
|
+
);
|
|
2510
|
+
}
|
|
2511
|
+
return data;
|
|
2512
|
+
}
|
|
2513
|
+
var HyperliquidInfoClient = class {
|
|
2514
|
+
constructor(environment = "mainnet") {
|
|
2515
|
+
this.environment = environment;
|
|
2516
|
+
}
|
|
2517
|
+
meta() {
|
|
2518
|
+
return fetchHyperliquidMeta(this.environment);
|
|
2519
|
+
}
|
|
2520
|
+
metaAndAssetCtxs() {
|
|
2521
|
+
return fetchHyperliquidMetaAndAssetCtxs(this.environment);
|
|
2522
|
+
}
|
|
2523
|
+
spotMeta() {
|
|
2524
|
+
return fetchHyperliquidSpotMeta(this.environment);
|
|
2525
|
+
}
|
|
2526
|
+
spotMetaAndAssetCtxs() {
|
|
2527
|
+
return fetchHyperliquidSpotMetaAndAssetCtxs(this.environment);
|
|
2528
|
+
}
|
|
2529
|
+
assetCtxs() {
|
|
2530
|
+
return fetchHyperliquidAssetCtxs(this.environment);
|
|
2531
|
+
}
|
|
2532
|
+
spotAssetCtxs() {
|
|
2533
|
+
return fetchHyperliquidSpotAssetCtxs(this.environment);
|
|
2534
|
+
}
|
|
2535
|
+
openOrders(user) {
|
|
2536
|
+
return fetchHyperliquidOpenOrders({ user, environment: this.environment });
|
|
2537
|
+
}
|
|
2538
|
+
frontendOpenOrders(user) {
|
|
2539
|
+
return fetchHyperliquidFrontendOpenOrders({
|
|
2540
|
+
user,
|
|
2541
|
+
environment: this.environment
|
|
2542
|
+
});
|
|
2543
|
+
}
|
|
2544
|
+
orderStatus(user, oid) {
|
|
2545
|
+
return fetchHyperliquidOrderStatus({
|
|
2546
|
+
user,
|
|
2547
|
+
oid,
|
|
2548
|
+
environment: this.environment
|
|
2549
|
+
});
|
|
2550
|
+
}
|
|
2551
|
+
historicalOrders(user) {
|
|
2552
|
+
return fetchHyperliquidHistoricalOrders({
|
|
2553
|
+
user,
|
|
2554
|
+
environment: this.environment
|
|
2555
|
+
});
|
|
2556
|
+
}
|
|
2557
|
+
userFills(user) {
|
|
2558
|
+
return fetchHyperliquidUserFills({ user, environment: this.environment });
|
|
2559
|
+
}
|
|
2560
|
+
userFillsByTime(user, startTime, endTime) {
|
|
2561
|
+
return fetchHyperliquidUserFillsByTime({
|
|
2562
|
+
user,
|
|
2563
|
+
startTime,
|
|
2564
|
+
endTime,
|
|
2565
|
+
environment: this.environment
|
|
2566
|
+
});
|
|
2567
|
+
}
|
|
2568
|
+
userRateLimit(user) {
|
|
2569
|
+
return fetchHyperliquidUserRateLimit({
|
|
2570
|
+
user,
|
|
2571
|
+
environment: this.environment
|
|
2572
|
+
});
|
|
2573
|
+
}
|
|
2574
|
+
preTransferCheck(user, source) {
|
|
2575
|
+
return fetchHyperliquidPreTransferCheck({
|
|
2576
|
+
user,
|
|
2577
|
+
source,
|
|
2578
|
+
environment: this.environment
|
|
2579
|
+
});
|
|
2580
|
+
}
|
|
2581
|
+
spotClearinghouseState(user) {
|
|
2582
|
+
return fetchHyperliquidSpotClearinghouseState({
|
|
2583
|
+
user,
|
|
2584
|
+
environment: this.environment
|
|
2585
|
+
});
|
|
2586
|
+
}
|
|
2587
|
+
};
|
|
2588
|
+
async function fetchHyperliquidMeta(environment = "mainnet") {
|
|
2589
|
+
return postInfo(environment, { type: "meta" });
|
|
2590
|
+
}
|
|
2591
|
+
async function fetchHyperliquidMetaAndAssetCtxs(environment = "mainnet") {
|
|
2592
|
+
return postInfo(environment, { type: "metaAndAssetCtxs" });
|
|
2593
|
+
}
|
|
2594
|
+
async function fetchHyperliquidSpotMeta(environment = "mainnet") {
|
|
2595
|
+
return postInfo(environment, { type: "spotMeta" });
|
|
2596
|
+
}
|
|
2597
|
+
async function fetchHyperliquidSpotMetaAndAssetCtxs(environment = "mainnet") {
|
|
2598
|
+
return postInfo(environment, { type: "spotMetaAndAssetCtxs" });
|
|
2599
|
+
}
|
|
2600
|
+
async function fetchHyperliquidAssetCtxs(environment = "mainnet") {
|
|
2601
|
+
return postInfo(environment, { type: "assetCtxs" });
|
|
2602
|
+
}
|
|
2603
|
+
async function fetchHyperliquidSpotAssetCtxs(environment = "mainnet") {
|
|
2604
|
+
return postInfo(environment, { type: "spotAssetCtxs" });
|
|
2605
|
+
}
|
|
2606
|
+
async function fetchHyperliquidOpenOrders(params) {
|
|
2607
|
+
const env = params.environment ?? "mainnet";
|
|
2608
|
+
return postInfo(env, { type: "openOrders", user: normalizeAddress(params.user) });
|
|
2609
|
+
}
|
|
2610
|
+
async function fetchHyperliquidFrontendOpenOrders(params) {
|
|
2611
|
+
const env = params.environment ?? "mainnet";
|
|
2612
|
+
return postInfo(env, {
|
|
2613
|
+
type: "frontendOpenOrders",
|
|
2614
|
+
user: normalizeAddress(params.user)
|
|
2615
|
+
});
|
|
2616
|
+
}
|
|
2617
|
+
async function fetchHyperliquidOrderStatus(params) {
|
|
2618
|
+
const env = params.environment ?? "mainnet";
|
|
2619
|
+
return postInfo(env, {
|
|
2620
|
+
type: "orderStatus",
|
|
2621
|
+
user: normalizeAddress(params.user),
|
|
2622
|
+
oid: params.oid
|
|
2623
|
+
});
|
|
2624
|
+
}
|
|
2625
|
+
async function fetchHyperliquidHistoricalOrders(params) {
|
|
2626
|
+
const env = params.environment ?? "mainnet";
|
|
2627
|
+
return postInfo(env, {
|
|
2628
|
+
type: "historicalOrders",
|
|
2629
|
+
user: normalizeAddress(params.user)
|
|
2630
|
+
});
|
|
2631
|
+
}
|
|
2632
|
+
async function fetchHyperliquidUserFills(params) {
|
|
2633
|
+
const env = params.environment ?? "mainnet";
|
|
2634
|
+
return postInfo(env, {
|
|
2635
|
+
type: "userFills",
|
|
2636
|
+
user: normalizeAddress(params.user)
|
|
2637
|
+
});
|
|
2638
|
+
}
|
|
2639
|
+
async function fetchHyperliquidUserFillsByTime(params) {
|
|
2640
|
+
const env = params.environment ?? "mainnet";
|
|
2641
|
+
return postInfo(env, {
|
|
2642
|
+
type: "userFillsByTime",
|
|
2643
|
+
user: normalizeAddress(params.user),
|
|
2644
|
+
startTime: params.startTime,
|
|
2645
|
+
endTime: params.endTime
|
|
2646
|
+
});
|
|
2647
|
+
}
|
|
2648
|
+
async function fetchHyperliquidUserRateLimit(params) {
|
|
2649
|
+
const env = params.environment ?? "mainnet";
|
|
2650
|
+
return postInfo(env, {
|
|
2651
|
+
type: "userRateLimit",
|
|
2652
|
+
user: normalizeAddress(params.user)
|
|
2653
|
+
});
|
|
2654
|
+
}
|
|
2655
|
+
async function fetchHyperliquidPreTransferCheck(params) {
|
|
2656
|
+
const env = params.environment ?? "mainnet";
|
|
2657
|
+
return postInfo(env, {
|
|
2658
|
+
type: "preTransferCheck",
|
|
2659
|
+
user: normalizeAddress(params.user),
|
|
2660
|
+
source: normalizeAddress(params.source)
|
|
2661
|
+
});
|
|
2662
|
+
}
|
|
2663
|
+
async function fetchHyperliquidSpotClearinghouseState(params) {
|
|
2664
|
+
const env = params.environment ?? "mainnet";
|
|
2665
|
+
return postInfo(env, {
|
|
2666
|
+
type: "spotClearinghouseState",
|
|
2667
|
+
user: normalizeAddress(params.user)
|
|
2668
|
+
});
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2671
|
+
// src/adapters/hyperliquid/index.ts
|
|
2672
|
+
async function placeHyperliquidOrder(options) {
|
|
2673
|
+
const {
|
|
2674
|
+
wallet: wallet2,
|
|
2675
|
+
orders,
|
|
2676
|
+
grouping = "na",
|
|
2677
|
+
environment,
|
|
2678
|
+
vaultAddress,
|
|
2679
|
+
expiresAfter,
|
|
2680
|
+
nonce
|
|
2681
|
+
} = options;
|
|
2682
|
+
const effectiveBuilder = BUILDER_CODE;
|
|
2683
|
+
if (!wallet2?.account || !wallet2.walletClient) {
|
|
2684
|
+
throw new Error(
|
|
2685
|
+
"Hyperliquid order signing requires a wallet with signing capabilities."
|
|
2686
|
+
);
|
|
2687
|
+
}
|
|
2688
|
+
if (!orders.length) {
|
|
2689
|
+
throw new Error("At least one order is required.");
|
|
2690
|
+
}
|
|
2691
|
+
const inferredEnvironment = environment ?? "mainnet";
|
|
2692
|
+
const resolvedBaseUrl = API_BASES[inferredEnvironment];
|
|
2693
|
+
const universe = await getUniverse({
|
|
2694
|
+
baseUrl: resolvedBaseUrl,
|
|
2695
|
+
environment: inferredEnvironment,
|
|
2696
|
+
fetcher: fetch
|
|
2697
|
+
});
|
|
2698
|
+
const preparedOrders = orders.map((intent) => {
|
|
2699
|
+
const assetIndex = resolveAssetIndex(intent.symbol, universe);
|
|
2700
|
+
const limitOrTrigger = intent.trigger ? {
|
|
2701
|
+
trigger: {
|
|
2702
|
+
isMarket: Boolean(intent.trigger.isMarket),
|
|
2703
|
+
triggerPx: toApiDecimal(intent.trigger.triggerPx),
|
|
2704
|
+
tpsl: intent.trigger.tpsl
|
|
2705
|
+
}
|
|
2706
|
+
} : {
|
|
2707
|
+
limit: {
|
|
2708
|
+
tif: intent.tif ?? "Ioc"
|
|
2709
|
+
}
|
|
2710
|
+
};
|
|
2711
|
+
const order = {
|
|
2712
|
+
a: assetIndex,
|
|
2713
|
+
b: intent.side === "buy",
|
|
2714
|
+
p: toApiDecimal(intent.price),
|
|
2715
|
+
s: toApiDecimal(intent.size),
|
|
2716
|
+
r: intent.reduceOnly ?? false,
|
|
2717
|
+
t: limitOrTrigger,
|
|
2718
|
+
...intent.clientId ? {
|
|
2719
|
+
c: normalizeHex(intent.clientId)
|
|
2720
|
+
} : {}
|
|
2721
|
+
};
|
|
2722
|
+
return order;
|
|
2723
|
+
});
|
|
2724
|
+
const action = {
|
|
2725
|
+
type: "order",
|
|
2726
|
+
orders: preparedOrders,
|
|
2727
|
+
grouping
|
|
2728
|
+
};
|
|
2729
|
+
if (effectiveBuilder) {
|
|
2730
|
+
action.builder = {
|
|
2731
|
+
b: normalizeAddress(effectiveBuilder.address),
|
|
2732
|
+
f: effectiveBuilder.fee
|
|
2733
|
+
};
|
|
2734
|
+
}
|
|
2735
|
+
const effectiveNonce = nonce ?? Date.now();
|
|
2736
|
+
const signature = await signL1Action({
|
|
2737
|
+
wallet: wallet2,
|
|
2738
|
+
action,
|
|
2739
|
+
nonce: effectiveNonce,
|
|
2740
|
+
...vaultAddress ? { vaultAddress } : {},
|
|
2741
|
+
...typeof expiresAfter === "number" ? { expiresAfter } : {},
|
|
2742
|
+
isTestnet: inferredEnvironment === "testnet"
|
|
2743
|
+
});
|
|
2744
|
+
const body = {
|
|
2745
|
+
action,
|
|
2746
|
+
nonce: effectiveNonce,
|
|
2747
|
+
signature
|
|
2748
|
+
};
|
|
2749
|
+
if (vaultAddress) {
|
|
2750
|
+
body.vaultAddress = normalizeAddress(vaultAddress);
|
|
2751
|
+
}
|
|
2752
|
+
if (typeof expiresAfter === "number") {
|
|
2753
|
+
body.expiresAfter = expiresAfter;
|
|
2754
|
+
}
|
|
2755
|
+
const response = await fetch(`${resolvedBaseUrl}/exchange`, {
|
|
2756
|
+
method: "POST",
|
|
2757
|
+
headers: { "content-type": "application/json" },
|
|
2758
|
+
body: JSON.stringify(body)
|
|
2759
|
+
});
|
|
2760
|
+
const rawText = await response.text().catch(() => null);
|
|
2761
|
+
let parsed = null;
|
|
2762
|
+
if (rawText && rawText.length) {
|
|
2763
|
+
try {
|
|
2764
|
+
parsed = JSON.parse(rawText);
|
|
2765
|
+
} catch {
|
|
2766
|
+
parsed = rawText;
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
const json = parsed && typeof parsed === "object" && "status" in parsed ? parsed : null;
|
|
2770
|
+
if (!response.ok || !json) {
|
|
2771
|
+
const detail = parsed?.error ?? parsed?.message ?? (typeof parsed === "string" ? parsed : rawText);
|
|
2772
|
+
const suffix = detail ? ` Detail: ${detail}` : "";
|
|
2773
|
+
throw new HyperliquidApiError(
|
|
2774
|
+
`Failed to submit Hyperliquid order.${suffix}`,
|
|
2775
|
+
parsed ?? rawText ?? { status: response.status }
|
|
2776
|
+
);
|
|
2777
|
+
}
|
|
2778
|
+
if (json.status !== "ok") {
|
|
2779
|
+
const detail = parsed?.error ?? rawText;
|
|
2780
|
+
throw new HyperliquidApiError(
|
|
2781
|
+
detail ? `Hyperliquid API returned an error status: ${detail}` : "Hyperliquid API returned an error status.",
|
|
2782
|
+
json
|
|
2783
|
+
);
|
|
2784
|
+
}
|
|
2785
|
+
const statuses = json.response?.data?.statuses ?? [];
|
|
2786
|
+
const errorStatuses = statuses.filter(
|
|
2787
|
+
(entry) => "error" in entry
|
|
2788
|
+
);
|
|
2789
|
+
if (errorStatuses.length) {
|
|
2790
|
+
const message = errorStatuses.map((entry) => entry.error).join(", ");
|
|
2791
|
+
throw new HyperliquidApiError(
|
|
2792
|
+
message || "Hyperliquid rejected the order.",
|
|
2793
|
+
json
|
|
2794
|
+
);
|
|
2795
|
+
}
|
|
2796
|
+
return json;
|
|
2797
|
+
}
|
|
2798
|
+
async function depositToHyperliquidBridge(options) {
|
|
2799
|
+
const { environment, amount, wallet: wallet2 } = options;
|
|
2800
|
+
const parsedAmount = Number(amount);
|
|
2801
|
+
if (!Number.isFinite(parsedAmount) || parsedAmount <= 0) {
|
|
2802
|
+
throw new Error("Deposit amount must be a positive number.");
|
|
2803
|
+
}
|
|
2804
|
+
if (parsedAmount < MIN_DEPOSIT_USDC) {
|
|
2805
|
+
throw new Error(`Minimum deposit is ${MIN_DEPOSIT_USDC} USDC.`);
|
|
2806
|
+
}
|
|
2807
|
+
if (!wallet2.account || !wallet2.walletClient) {
|
|
2808
|
+
throw new Error("Wallet with signing capability is required for deposit.");
|
|
2809
|
+
}
|
|
2810
|
+
const bridgeAddress = getBridgeAddress(environment);
|
|
2811
|
+
const usdcAddress = getUsdcAddress(environment);
|
|
2812
|
+
const amountUnits = parseUnits(amount, 6);
|
|
2813
|
+
if (!wallet2.walletClient || !wallet2.publicClient) {
|
|
2814
|
+
throw new Error(
|
|
2815
|
+
"Wallet client and public client are required for deposit."
|
|
2816
|
+
);
|
|
2817
|
+
}
|
|
2818
|
+
const walletClient = wallet2.walletClient;
|
|
2819
|
+
const publicClient = wallet2.publicClient;
|
|
2820
|
+
const data = encodeFunctionData({
|
|
2821
|
+
abi: erc20Abi,
|
|
2822
|
+
functionName: "transfer",
|
|
2823
|
+
args: [bridgeAddress, amountUnits]
|
|
2824
|
+
});
|
|
2825
|
+
const txHash = await walletClient.sendTransaction({
|
|
2826
|
+
account: wallet2.account,
|
|
2827
|
+
to: usdcAddress,
|
|
2828
|
+
data
|
|
2829
|
+
});
|
|
2830
|
+
await publicClient.waitForTransactionReceipt({ hash: txHash });
|
|
2831
|
+
return {
|
|
2832
|
+
txHash,
|
|
2833
|
+
amount: parsedAmount,
|
|
2834
|
+
amountUnits: amountUnits.toString(),
|
|
2835
|
+
environment,
|
|
2836
|
+
bridgeAddress
|
|
2837
|
+
};
|
|
2838
|
+
}
|
|
2839
|
+
async function withdrawFromHyperliquid(options) {
|
|
2840
|
+
const { environment, amount, destination, wallet: wallet2 } = options;
|
|
2841
|
+
const parsedAmount = Number(amount);
|
|
2842
|
+
if (!Number.isFinite(parsedAmount) || parsedAmount <= 0) {
|
|
2843
|
+
throw new Error("Withdraw amount must be a positive number.");
|
|
2844
|
+
}
|
|
2845
|
+
if (!wallet2.account || !wallet2.walletClient || !wallet2.publicClient) {
|
|
2846
|
+
throw new Error(
|
|
2847
|
+
"Wallet client and public client are required for withdraw."
|
|
2848
|
+
);
|
|
2849
|
+
}
|
|
2850
|
+
const signatureChainId = getSignatureChainId(environment);
|
|
2851
|
+
const hyperliquidChain = HL_CHAIN_LABEL[environment];
|
|
2852
|
+
const domain = {
|
|
2853
|
+
name: "HyperliquidSignTransaction",
|
|
2854
|
+
version: "1",
|
|
2855
|
+
chainId: Number.parseInt(signatureChainId, 16),
|
|
2856
|
+
verifyingContract: ZERO_ADDRESS
|
|
2857
|
+
};
|
|
2858
|
+
const time = BigInt(Date.now());
|
|
2859
|
+
const nonce = Number(time);
|
|
2860
|
+
const normalizedDestination = normalizeAddress(destination);
|
|
2861
|
+
const message = {
|
|
2862
|
+
hyperliquidChain,
|
|
2863
|
+
destination: normalizedDestination,
|
|
2864
|
+
amount: parsedAmount.toString(),
|
|
2865
|
+
time
|
|
2866
|
+
};
|
|
2867
|
+
const types = {
|
|
2868
|
+
"HyperliquidTransaction:Withdraw": [
|
|
2869
|
+
{ name: "hyperliquidChain", type: "string" },
|
|
2870
|
+
{ name: "destination", type: "string" },
|
|
2871
|
+
{ name: "amount", type: "string" },
|
|
2872
|
+
{ name: "time", type: "uint64" }
|
|
2873
|
+
]
|
|
2874
|
+
};
|
|
2875
|
+
const signatureHex = await wallet2.walletClient.signTypedData({
|
|
2876
|
+
account: wallet2.account,
|
|
2877
|
+
domain,
|
|
2878
|
+
types,
|
|
2879
|
+
primaryType: "HyperliquidTransaction:Withdraw",
|
|
2880
|
+
message
|
|
2881
|
+
});
|
|
2882
|
+
const signature = splitSignature(signatureHex);
|
|
2883
|
+
const payload = {
|
|
2884
|
+
action: {
|
|
2885
|
+
type: "withdraw3",
|
|
2886
|
+
signatureChainId,
|
|
2887
|
+
hyperliquidChain,
|
|
2888
|
+
destination: normalizedDestination,
|
|
2889
|
+
amount: parsedAmount.toString(),
|
|
2890
|
+
time: nonce
|
|
2891
|
+
},
|
|
2892
|
+
nonce,
|
|
2893
|
+
signature
|
|
2894
|
+
};
|
|
2895
|
+
const endpoint = `${HL_ENDPOINT[environment]}/exchange`;
|
|
2896
|
+
const response = await fetch(endpoint, {
|
|
2897
|
+
method: "POST",
|
|
2898
|
+
headers: { "content-type": "application/json" },
|
|
2899
|
+
body: JSON.stringify(payload)
|
|
2900
|
+
});
|
|
2901
|
+
const json = await response.json().catch(() => null);
|
|
2902
|
+
if (!response.ok || json?.status !== "ok") {
|
|
2903
|
+
throw new Error(
|
|
2904
|
+
`Hyperliquid withdraw failed: ${json?.response ?? json?.error ?? response.statusText}`
|
|
2905
|
+
);
|
|
2906
|
+
}
|
|
2907
|
+
return {
|
|
2908
|
+
amount: parsedAmount,
|
|
2909
|
+
destination: normalizedDestination,
|
|
2910
|
+
environment,
|
|
2911
|
+
nonce,
|
|
2912
|
+
status: json.status ?? "ok"
|
|
2913
|
+
};
|
|
2914
|
+
}
|
|
2915
|
+
async function fetchHyperliquidClearinghouseState(params) {
|
|
2916
|
+
const { environment, walletAddress } = params;
|
|
2917
|
+
const response = await fetch(`${HL_ENDPOINT[environment]}/info`, {
|
|
2918
|
+
method: "POST",
|
|
2919
|
+
headers: { "content-type": "application/json" },
|
|
2920
|
+
body: JSON.stringify({ type: "clearinghouseState", user: walletAddress })
|
|
2921
|
+
});
|
|
2922
|
+
const data = await response.json().catch(() => null);
|
|
2923
|
+
return {
|
|
2924
|
+
ok: response.ok,
|
|
2925
|
+
data
|
|
2926
|
+
};
|
|
2927
|
+
}
|
|
2928
|
+
async function approveHyperliquidBuilderFee(options) {
|
|
2929
|
+
const { environment, wallet: wallet2, nonce, signatureChainId } = options;
|
|
2930
|
+
if (!wallet2?.account || !wallet2.walletClient) {
|
|
2931
|
+
throw new Error(
|
|
2932
|
+
"Hyperliquid builder approval requires a wallet with signing capabilities."
|
|
2933
|
+
);
|
|
2934
|
+
}
|
|
2935
|
+
const maxFeeRateValue = BUILDER_CODE.fee / 1e3;
|
|
2936
|
+
const formattedPercent = `${maxFeeRateValue}%`;
|
|
2937
|
+
const normalizedBuilder = normalizeAddress(BUILDER_CODE.address);
|
|
2938
|
+
const inferredEnvironment = environment ?? "mainnet";
|
|
2939
|
+
const resolvedBaseUrl = API_BASES[inferredEnvironment];
|
|
2940
|
+
const maxFeeRate = formattedPercent;
|
|
2941
|
+
const effectiveNonce = nonce ?? Date.now();
|
|
2942
|
+
const signatureNonce = BigInt(effectiveNonce);
|
|
2943
|
+
const signatureChainHex = signatureChainId ?? getSignatureChainId(inferredEnvironment);
|
|
2944
|
+
const approvalSignature = await signApproveBuilderFee({
|
|
2945
|
+
wallet: wallet2,
|
|
2946
|
+
maxFeeRate,
|
|
2947
|
+
nonce: signatureNonce,
|
|
2948
|
+
signatureChainId: signatureChainHex,
|
|
2949
|
+
isTestnet: inferredEnvironment === "testnet"
|
|
2950
|
+
});
|
|
2951
|
+
const action = {
|
|
2952
|
+
type: "approveBuilderFee",
|
|
2953
|
+
maxFeeRate,
|
|
2954
|
+
builder: normalizedBuilder,
|
|
2955
|
+
hyperliquidChain: HL_CHAIN_LABEL[inferredEnvironment],
|
|
2956
|
+
signatureChainId: signatureChainHex,
|
|
2957
|
+
nonce: effectiveNonce
|
|
2958
|
+
};
|
|
2959
|
+
const payload = {
|
|
2960
|
+
action,
|
|
2961
|
+
nonce: effectiveNonce,
|
|
2962
|
+
signature: approvalSignature
|
|
2963
|
+
};
|
|
2964
|
+
const response = await fetch(`${resolvedBaseUrl}/exchange`, {
|
|
2965
|
+
method: "POST",
|
|
2966
|
+
headers: { "content-type": "application/json" },
|
|
2967
|
+
body: JSON.stringify(payload)
|
|
2968
|
+
});
|
|
2969
|
+
const rawText = await response.text().catch(() => null);
|
|
2970
|
+
let parsed = null;
|
|
2971
|
+
if (rawText && rawText.length) {
|
|
2972
|
+
try {
|
|
2973
|
+
parsed = JSON.parse(rawText);
|
|
2974
|
+
} catch {
|
|
2975
|
+
parsed = rawText;
|
|
2976
|
+
}
|
|
2977
|
+
}
|
|
2978
|
+
const json = parsed && typeof parsed === "object" && "status" in parsed ? parsed : null;
|
|
2979
|
+
if (!response.ok || !json) {
|
|
2980
|
+
const detail = parsed?.error ?? parsed?.message ?? (typeof parsed === "string" ? parsed : rawText);
|
|
2981
|
+
const suffix = detail ? ` Detail: ${detail}` : "";
|
|
2982
|
+
throw new HyperliquidApiError(
|
|
2983
|
+
`Failed to submit builder approval.${suffix}`,
|
|
2984
|
+
parsed ?? rawText ?? { status: response.status }
|
|
2985
|
+
);
|
|
2986
|
+
}
|
|
2987
|
+
if (json.status !== "ok") {
|
|
2988
|
+
const detail = parsed?.error ?? rawText;
|
|
2989
|
+
throw new HyperliquidApiError(
|
|
2990
|
+
detail ? `Hyperliquid builder approval returned an error: ${detail}` : "Hyperliquid builder approval returned an error.",
|
|
2991
|
+
json
|
|
2992
|
+
);
|
|
2993
|
+
}
|
|
2994
|
+
return json;
|
|
2995
|
+
}
|
|
2996
|
+
async function getHyperliquidMaxBuilderFee(params) {
|
|
2997
|
+
const { environment, user } = params;
|
|
2998
|
+
const resolvedBaseUrl = API_BASES[environment];
|
|
2999
|
+
const response = await fetch(`${resolvedBaseUrl}/info`, {
|
|
3000
|
+
method: "POST",
|
|
3001
|
+
headers: { "content-type": "application/json" },
|
|
3002
|
+
body: JSON.stringify({
|
|
3003
|
+
type: "maxBuilderFee",
|
|
3004
|
+
user: normalizeAddress(user),
|
|
3005
|
+
builder: BUILDER_CODE.address
|
|
3006
|
+
})
|
|
3007
|
+
});
|
|
3008
|
+
const data = await response.json().catch(() => null);
|
|
3009
|
+
if (!response.ok) {
|
|
3010
|
+
throw new HyperliquidApiError(
|
|
3011
|
+
"Failed to query max builder fee.",
|
|
3012
|
+
data ?? { status: response.status }
|
|
3013
|
+
);
|
|
3014
|
+
}
|
|
3015
|
+
return data;
|
|
3016
|
+
}
|
|
3017
|
+
async function recordHyperliquidTermsAcceptance(input) {
|
|
3018
|
+
const { environment, walletAddress, storeOptions } = input;
|
|
3019
|
+
return store(
|
|
3020
|
+
{
|
|
3021
|
+
source: "hyperliquid",
|
|
3022
|
+
ref: `${environment}-terms-${Date.now()}`,
|
|
3023
|
+
status: "info",
|
|
3024
|
+
walletAddress,
|
|
3025
|
+
action: "terms",
|
|
3026
|
+
metadata: {
|
|
3027
|
+
environment,
|
|
3028
|
+
note: "Hyperliquid does not expose a terms endpoint; this records local acknowledgement only."
|
|
3029
|
+
}
|
|
3030
|
+
},
|
|
3031
|
+
storeOptions
|
|
3032
|
+
);
|
|
3033
|
+
}
|
|
3034
|
+
async function recordHyperliquidBuilderApproval(input) {
|
|
3035
|
+
const { environment, walletAddress, storeOptions } = input;
|
|
3036
|
+
const maxFeeRate = `${BUILDER_CODE.fee / 1e3}%`;
|
|
3037
|
+
return store(
|
|
3038
|
+
{
|
|
3039
|
+
source: "hyperliquid",
|
|
3040
|
+
ref: `${environment}-builder-${Date.now()}`,
|
|
3041
|
+
status: "info",
|
|
3042
|
+
walletAddress,
|
|
3043
|
+
action: "builder-approval",
|
|
3044
|
+
metadata: {
|
|
3045
|
+
environment,
|
|
3046
|
+
builder: BUILDER_CODE.address,
|
|
3047
|
+
maxFeeRate
|
|
3048
|
+
}
|
|
3049
|
+
},
|
|
3050
|
+
storeOptions
|
|
3051
|
+
);
|
|
3052
|
+
}
|
|
3053
|
+
var __hyperliquidInternals = {
|
|
3054
|
+
toApiDecimal,
|
|
3055
|
+
createL1ActionHash,
|
|
3056
|
+
splitSignature
|
|
3057
|
+
};
|
|
3058
|
+
|
|
1566
3059
|
// src/ai/errors.ts
|
|
1567
3060
|
var AIError = class extends Error {
|
|
1568
3061
|
constructor(message, options) {
|
|
@@ -1607,7 +3100,7 @@ function assertFetchAvailable(fetchImplementation) {
|
|
|
1607
3100
|
);
|
|
1608
3101
|
}
|
|
1609
3102
|
}
|
|
1610
|
-
function
|
|
3103
|
+
function resolveConfig2(config = {}) {
|
|
1611
3104
|
const fetchImplementation = config.fetchImplementation ?? globalThis.fetch;
|
|
1612
3105
|
assertFetchAvailable(fetchImplementation);
|
|
1613
3106
|
const resolved = {
|
|
@@ -1848,7 +3341,7 @@ function extractTextPart(part, options) {
|
|
|
1848
3341
|
// src/ai/client.ts
|
|
1849
3342
|
var CHAT_COMPLETIONS_PATH = "/v1/chat/completions";
|
|
1850
3343
|
function createAIClient(config = {}) {
|
|
1851
|
-
const resolved =
|
|
3344
|
+
const resolved = resolveConfig2(config);
|
|
1852
3345
|
return {
|
|
1853
3346
|
get config() {
|
|
1854
3347
|
return resolved;
|
|
@@ -1863,7 +3356,7 @@ function createAIClient(config = {}) {
|
|
|
1863
3356
|
};
|
|
1864
3357
|
}
|
|
1865
3358
|
async function generateText(options, clientConfig = {}) {
|
|
1866
|
-
const resolved =
|
|
3359
|
+
const resolved = resolveConfig2(clientConfig);
|
|
1867
3360
|
const model = normalizeModelName(options.model ?? resolved.defaultModel);
|
|
1868
3361
|
const payload = buildRequestPayload(options, model, {
|
|
1869
3362
|
allowTools: isToolCallingSupported(model)
|
|
@@ -1929,7 +3422,7 @@ async function generateText(options, clientConfig = {}) {
|
|
|
1929
3422
|
return result;
|
|
1930
3423
|
}
|
|
1931
3424
|
async function streamText(options, clientConfig = {}) {
|
|
1932
|
-
const resolved =
|
|
3425
|
+
const resolved = resolveConfig2(clientConfig);
|
|
1933
3426
|
const model = normalizeModelName(options.model ?? resolved.defaultModel);
|
|
1934
3427
|
const streamExtras = buildStreamMetadataExtras(options);
|
|
1935
3428
|
const payload = buildRequestPayload(
|
|
@@ -2318,73 +3811,6 @@ function toAbortError(reason) {
|
|
|
2318
3811
|
}
|
|
2319
3812
|
return new AIAbortError(String(reason ?? "AI request aborted"));
|
|
2320
3813
|
}
|
|
2321
|
-
|
|
2322
|
-
// src/store/index.ts
|
|
2323
|
-
var StoreError = class extends Error {
|
|
2324
|
-
constructor(message, status, causeData) {
|
|
2325
|
-
super(message);
|
|
2326
|
-
this.status = status;
|
|
2327
|
-
this.causeData = causeData;
|
|
2328
|
-
this.name = "StoreError";
|
|
2329
|
-
}
|
|
2330
|
-
};
|
|
2331
|
-
function resolveConfig2(options) {
|
|
2332
|
-
const baseUrl = options?.baseUrl ?? process.env.BASE_URL;
|
|
2333
|
-
const apiKey = options?.apiKey ?? process.env.OPENPOND_API_KEY;
|
|
2334
|
-
if (!baseUrl) {
|
|
2335
|
-
throw new StoreError("BASE_URL is required to store activity events");
|
|
2336
|
-
}
|
|
2337
|
-
if (!apiKey) {
|
|
2338
|
-
throw new StoreError(
|
|
2339
|
-
"OPENPOND_API_KEY is required to store activity events"
|
|
2340
|
-
);
|
|
2341
|
-
}
|
|
2342
|
-
const normalizedBaseUrl = baseUrl.replace(/\/$/, "");
|
|
2343
|
-
const fetchFn = options?.fetchFn ?? globalThis.fetch;
|
|
2344
|
-
if (!fetchFn) {
|
|
2345
|
-
throw new StoreError("Fetch is not available in this environment");
|
|
2346
|
-
}
|
|
2347
|
-
return { baseUrl: normalizedBaseUrl, apiKey, fetchFn };
|
|
2348
|
-
}
|
|
2349
|
-
async function store(input, options) {
|
|
2350
|
-
const { baseUrl, apiKey, fetchFn } = resolveConfig2(options);
|
|
2351
|
-
const url = `${baseUrl}/apps/positions/tx`;
|
|
2352
|
-
let response;
|
|
2353
|
-
try {
|
|
2354
|
-
response = await fetchFn(url, {
|
|
2355
|
-
method: "POST",
|
|
2356
|
-
headers: {
|
|
2357
|
-
"content-type": "application/json",
|
|
2358
|
-
"openpond-api-key": apiKey
|
|
2359
|
-
},
|
|
2360
|
-
body: JSON.stringify(input)
|
|
2361
|
-
});
|
|
2362
|
-
} catch (error) {
|
|
2363
|
-
throw new StoreError("Failed to reach store endpoint", void 0, error);
|
|
2364
|
-
}
|
|
2365
|
-
if (!response.ok) {
|
|
2366
|
-
let body;
|
|
2367
|
-
try {
|
|
2368
|
-
body = await response.json();
|
|
2369
|
-
} catch {
|
|
2370
|
-
body = await response.text().catch(() => void 0);
|
|
2371
|
-
}
|
|
2372
|
-
throw new StoreError(
|
|
2373
|
-
`Store request failed with status ${response.status}`,
|
|
2374
|
-
response.status,
|
|
2375
|
-
body
|
|
2376
|
-
);
|
|
2377
|
-
}
|
|
2378
|
-
try {
|
|
2379
|
-
const data = await response.json();
|
|
2380
|
-
return {
|
|
2381
|
-
id: data.id ?? "",
|
|
2382
|
-
status: data.status ?? null
|
|
2383
|
-
};
|
|
2384
|
-
} catch {
|
|
2385
|
-
return { id: "", status: null };
|
|
2386
|
-
}
|
|
2387
|
-
}
|
|
2388
3814
|
var METADATA_SPEC_VERSION = "1.1.0";
|
|
2389
3815
|
var McpAnnotationsSchema = z.object({
|
|
2390
3816
|
title: z.string().optional(),
|
|
@@ -2526,7 +3952,7 @@ async function transpileWithEsbuild(options) {
|
|
|
2526
3952
|
format: options.format,
|
|
2527
3953
|
platform: "node",
|
|
2528
3954
|
target: "node20",
|
|
2529
|
-
logLevel: "warning",
|
|
3955
|
+
logLevel: options.logLevel ?? "warning",
|
|
2530
3956
|
sourcesContent: false,
|
|
2531
3957
|
sourcemap: false,
|
|
2532
3958
|
loader: {
|
|
@@ -2540,13 +3966,16 @@ async function transpileWithEsbuild(options) {
|
|
|
2540
3966
|
".cjs": "js",
|
|
2541
3967
|
".json": "json"
|
|
2542
3968
|
},
|
|
2543
|
-
metafile: false,
|
|
3969
|
+
metafile: options.metafile ?? false,
|
|
2544
3970
|
allowOverwrite: true,
|
|
2545
3971
|
absWorkingDir: projectRoot
|
|
2546
3972
|
};
|
|
2547
3973
|
if (options.external && options.external.length > 0) {
|
|
2548
3974
|
buildOptions.external = options.external;
|
|
2549
3975
|
}
|
|
3976
|
+
if (options.outBase) {
|
|
3977
|
+
buildOptions.outbase = options.outBase;
|
|
3978
|
+
}
|
|
2550
3979
|
if (!buildOptions.bundle) {
|
|
2551
3980
|
buildOptions.packages = "external";
|
|
2552
3981
|
}
|
|
@@ -2928,11 +4357,8 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
2928
4357
|
throw new Error(`${file}: export exactly one of GET or POST`);
|
|
2929
4358
|
}
|
|
2930
4359
|
let normalizedSchedule = null;
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
if (!schedule || typeof schedule?.cron !== "string" || schedule.cron.trim().length === 0) {
|
|
2934
|
-
throw new Error(`${file}: GET tools require profile.schedule { cron }`);
|
|
2935
|
-
}
|
|
4360
|
+
const schedule = toolModule?.profile?.schedule;
|
|
4361
|
+
if (hasGET && schedule && typeof schedule.cron === "string" && schedule.cron.trim().length > 0) {
|
|
2936
4362
|
normalizedSchedule = normalizeScheduleExpression(schedule.cron, file);
|
|
2937
4363
|
if (typeof schedule.enabled === "boolean") {
|
|
2938
4364
|
normalizedSchedule.authoredEnabled = schedule.enabled;
|
|
@@ -2942,6 +4368,9 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
2942
4368
|
if (!schema) {
|
|
2943
4369
|
throw new Error(`${file}: POST tools must export a Zod schema as 'schema'`);
|
|
2944
4370
|
}
|
|
4371
|
+
if (schedule && typeof schedule.cron === "string") {
|
|
4372
|
+
throw new Error(`${file}: POST tools must not define profile.schedule; use GET + cron for scheduled tasks.`);
|
|
4373
|
+
}
|
|
2945
4374
|
}
|
|
2946
4375
|
const httpHandlers = [...httpHandlersRaw];
|
|
2947
4376
|
if (httpHandlers.length === 0) {
|
|
@@ -3227,6 +4656,6 @@ function timestamp() {
|
|
|
3227
4656
|
return (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
|
|
3228
4657
|
}
|
|
3229
4658
|
|
|
3230
|
-
export { AIAbortError, AIError, AIFetchError, AIResponseError, DEFAULT_BASE_URL, DEFAULT_CHAIN, DEFAULT_FACILITATOR, DEFAULT_MODEL, DEFAULT_TIMEOUT_MS, DEFAULT_TOKENS, HTTP_METHODS2 as HTTP_METHODS, PAYMENT_HEADERS, SUPPORTED_CURRENCIES, StoreError, WEBSEARCH_TOOL_DEFINITION, WEBSEARCH_TOOL_NAME, X402BrowserClient, X402Client, X402PaymentRequiredError, chains, createAIClient, createDevServer, createMcpAdapter, createStdioServer, defineX402Payment, ensureTextContent, flattenMessageContent, generateMetadata, generateMetadataCommand, generateText, getModelConfig, getRpcUrl, getX402PaymentContext, isStreamingSupported, isToolCallingSupported, listModels, loadAndValidateTools, normalizeModelName, payX402, payX402WithWallet, registry, requireX402Payment, resolveConfig, resolveRuntimePath, resolveToolset, responseToToolResponse, store, streamText, tokens, validateCommand, wallet, walletToolkit, withX402Payment };
|
|
4659
|
+
export { AIAbortError, AIError, AIFetchError, AIResponseError, DEFAULT_BASE_URL, DEFAULT_CHAIN, DEFAULT_FACILITATOR, DEFAULT_MODEL, DEFAULT_TIMEOUT_MS, DEFAULT_TOKENS, HTTP_METHODS2 as HTTP_METHODS, HyperliquidApiError, HyperliquidBuilderApprovalError, HyperliquidExchangeClient, HyperliquidGuardError, HyperliquidInfoClient, HyperliquidTermsError, PAYMENT_HEADERS, SUPPORTED_CURRENCIES, StoreError, WEBSEARCH_TOOL_DEFINITION, WEBSEARCH_TOOL_NAME, X402BrowserClient, X402Client, X402PaymentRequiredError, __hyperliquidInternals, approveHyperliquidBuilderFee, batchModifyHyperliquidOrders, cancelAllHyperliquidOrders, cancelHyperliquidOrders, cancelHyperliquidOrdersByCloid, cancelHyperliquidTwapOrder, chains, createAIClient, createDevServer, createHyperliquidSubAccount, createMcpAdapter, createMonotonicNonceFactory, createStdioServer, defineX402Payment, depositToHyperliquidBridge, ensureTextContent, fetchHyperliquidAssetCtxs, fetchHyperliquidClearinghouseState, fetchHyperliquidFrontendOpenOrders, fetchHyperliquidHistoricalOrders, fetchHyperliquidMeta, fetchHyperliquidMetaAndAssetCtxs, fetchHyperliquidOpenOrders, fetchHyperliquidOrderStatus, fetchHyperliquidPreTransferCheck, fetchHyperliquidSpotAssetCtxs, fetchHyperliquidSpotClearinghouseState, fetchHyperliquidSpotMeta, fetchHyperliquidSpotMetaAndAssetCtxs, fetchHyperliquidUserFills, fetchHyperliquidUserFillsByTime, fetchHyperliquidUserRateLimit, flattenMessageContent, generateMetadata, generateMetadataCommand, generateText, getHyperliquidMaxBuilderFee, getModelConfig, getRpcUrl, getX402PaymentContext, isStreamingSupported, isToolCallingSupported, listModels, loadAndValidateTools, modifyHyperliquidOrder, normalizeModelName, payX402, payX402WithWallet, placeHyperliquidOrder, placeHyperliquidTwapOrder, recordHyperliquidBuilderApproval, recordHyperliquidTermsAcceptance, registry, requireX402Payment, reserveHyperliquidRequestWeight, resolveConfig2 as resolveConfig, resolveRuntimePath, resolveToolset, responseToToolResponse, retrieve, scheduleHyperliquidCancel, sendHyperliquidSpot, store, streamText, tokens, transferHyperliquidSubAccount, updateHyperliquidIsolatedMargin, updateHyperliquidLeverage, validateCommand, wallet, walletToolkit, withX402Payment, withdrawFromHyperliquid };
|
|
3231
4660
|
//# sourceMappingURL=index.js.map
|
|
3232
4661
|
//# sourceMappingURL=index.js.map
|