opentool 0.8.23 → 0.8.25
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 +161 -3
- package/dist/adapters/hyperliquid/index.js +1036 -24
- package/dist/adapters/hyperliquid/index.js.map +1 -1
- package/dist/cli/index.js +31 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1067 -26
- package/dist/index.js.map +1 -1
- package/dist/store/index.d.ts +6 -2
- package/dist/store/index.js +92 -7
- package/dist/store/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/base/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1626,6 +1626,29 @@ var walletToolkit = {
|
|
|
1626
1626
|
};
|
|
1627
1627
|
|
|
1628
1628
|
// src/store/index.ts
|
|
1629
|
+
var STORE_EVENT_LEVELS = [
|
|
1630
|
+
"decision",
|
|
1631
|
+
"execution",
|
|
1632
|
+
"lifecycle"
|
|
1633
|
+
];
|
|
1634
|
+
var STORE_EVENT_LEVEL_SET = new Set(STORE_EVENT_LEVELS);
|
|
1635
|
+
var MARKET_REQUIRED_ACTIONS = [
|
|
1636
|
+
"swap",
|
|
1637
|
+
"bridge",
|
|
1638
|
+
"order",
|
|
1639
|
+
"trade",
|
|
1640
|
+
"lend",
|
|
1641
|
+
"borrow",
|
|
1642
|
+
"repay",
|
|
1643
|
+
"stake",
|
|
1644
|
+
"unstake",
|
|
1645
|
+
"withdraw",
|
|
1646
|
+
"provide_liquidity",
|
|
1647
|
+
"remove_liquidity",
|
|
1648
|
+
"claim"
|
|
1649
|
+
];
|
|
1650
|
+
var MARKET_REQUIRED_ACTIONS_SET = new Set(MARKET_REQUIRED_ACTIONS);
|
|
1651
|
+
var EXECUTION_ACTIONS_SET = new Set(MARKET_REQUIRED_ACTIONS);
|
|
1629
1652
|
var StoreError = class extends Error {
|
|
1630
1653
|
constructor(message, status, causeData) {
|
|
1631
1654
|
super(message);
|
|
@@ -1634,13 +1657,57 @@ var StoreError = class extends Error {
|
|
|
1634
1657
|
this.name = "StoreError";
|
|
1635
1658
|
}
|
|
1636
1659
|
};
|
|
1660
|
+
var normalizeAction = (action) => {
|
|
1661
|
+
const normalized = action?.trim().toLowerCase();
|
|
1662
|
+
return normalized ? normalized : null;
|
|
1663
|
+
};
|
|
1664
|
+
var coerceEventLevel = (value) => {
|
|
1665
|
+
if (typeof value !== "string") return null;
|
|
1666
|
+
const normalized = value.trim().toLowerCase();
|
|
1667
|
+
if (!normalized || !STORE_EVENT_LEVEL_SET.has(normalized)) return null;
|
|
1668
|
+
return normalized;
|
|
1669
|
+
};
|
|
1637
1670
|
var requiresMarketIdentity = (input) => {
|
|
1638
|
-
const action = (input.action
|
|
1639
|
-
if (action
|
|
1640
|
-
return
|
|
1671
|
+
const action = normalizeAction(input.action);
|
|
1672
|
+
if (!action) return false;
|
|
1673
|
+
return MARKET_REQUIRED_ACTIONS_SET.has(action);
|
|
1641
1674
|
};
|
|
1642
1675
|
var hasMarketIdentity = (value) => {
|
|
1643
|
-
|
|
1676
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
1677
|
+
const record = value;
|
|
1678
|
+
const requiredKeys = ["market_type", "venue", "environment", "canonical_symbol"];
|
|
1679
|
+
return requiredKeys.every((key) => {
|
|
1680
|
+
const field = record[key];
|
|
1681
|
+
return typeof field === "string" && field.trim().length > 0;
|
|
1682
|
+
});
|
|
1683
|
+
};
|
|
1684
|
+
var resolveEventLevel = (input) => {
|
|
1685
|
+
const direct = coerceEventLevel(input.eventLevel);
|
|
1686
|
+
if (direct) return direct;
|
|
1687
|
+
const metadataLevel = coerceEventLevel(input.metadata?.eventLevel);
|
|
1688
|
+
if (metadataLevel) return metadataLevel;
|
|
1689
|
+
const action = normalizeAction(input.action);
|
|
1690
|
+
if (action && EXECUTION_ACTIONS_SET.has(action) && (input.metadata?.lifecycle === true || typeof input.metadata?.executionRef === "string" || typeof input.metadata?.parentExecutionRef === "string")) {
|
|
1691
|
+
return "lifecycle";
|
|
1692
|
+
}
|
|
1693
|
+
if (action && EXECUTION_ACTIONS_SET.has(action) || hasMarketIdentity(input.market)) {
|
|
1694
|
+
return "execution";
|
|
1695
|
+
}
|
|
1696
|
+
if (action) return "decision";
|
|
1697
|
+
return null;
|
|
1698
|
+
};
|
|
1699
|
+
var normalizeStoreInput = (input) => {
|
|
1700
|
+
const metadata = { ...input.metadata ?? {} };
|
|
1701
|
+
const eventLevel = resolveEventLevel({ ...input, metadata });
|
|
1702
|
+
if (eventLevel) {
|
|
1703
|
+
metadata.eventLevel = eventLevel;
|
|
1704
|
+
}
|
|
1705
|
+
const hasMetadata = Object.keys(metadata).length > 0;
|
|
1706
|
+
return {
|
|
1707
|
+
...input,
|
|
1708
|
+
...eventLevel ? { eventLevel } : {},
|
|
1709
|
+
...hasMetadata ? { metadata } : {}
|
|
1710
|
+
};
|
|
1644
1711
|
};
|
|
1645
1712
|
function resolveConfig(options) {
|
|
1646
1713
|
const baseUrl = options?.baseUrl ?? process.env.BASE_URL ?? "https://api.openpond.ai";
|
|
@@ -1693,8 +1760,26 @@ async function requestJson(url, options, init) {
|
|
|
1693
1760
|
}
|
|
1694
1761
|
}
|
|
1695
1762
|
async function store(input, options) {
|
|
1696
|
-
|
|
1697
|
-
|
|
1763
|
+
const normalizedInput = normalizeStoreInput(input);
|
|
1764
|
+
const eventLevel = normalizedInput.eventLevel;
|
|
1765
|
+
const normalizedAction = normalizeAction(normalizedInput.action);
|
|
1766
|
+
if (eventLevel === "execution" || eventLevel === "lifecycle") {
|
|
1767
|
+
if (!normalizedAction || !EXECUTION_ACTIONS_SET.has(normalizedAction)) {
|
|
1768
|
+
throw new StoreError(
|
|
1769
|
+
`eventLevel "${eventLevel}" requires an execution action`
|
|
1770
|
+
);
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
if (eventLevel === "execution" && !hasMarketIdentity(normalizedInput.market)) {
|
|
1774
|
+
throw new StoreError(
|
|
1775
|
+
`market is required for execution events. market must include market_type, venue, environment, canonical_symbol`
|
|
1776
|
+
);
|
|
1777
|
+
}
|
|
1778
|
+
const shouldApplyLegacyMarketRule = eventLevel == null || eventLevel === "execution";
|
|
1779
|
+
if (shouldApplyLegacyMarketRule && requiresMarketIdentity(normalizedInput) && !hasMarketIdentity(normalizedInput.market)) {
|
|
1780
|
+
throw new StoreError(
|
|
1781
|
+
`market is required for action "${normalizedInput.action}". market must include market_type, venue, environment, canonical_symbol`
|
|
1782
|
+
);
|
|
1698
1783
|
}
|
|
1699
1784
|
const { baseUrl, apiKey, fetchFn } = resolveConfig(options);
|
|
1700
1785
|
const url = `${baseUrl}/apps/positions/tx`;
|
|
@@ -1706,7 +1791,7 @@ async function store(input, options) {
|
|
|
1706
1791
|
"content-type": "application/json",
|
|
1707
1792
|
"openpond-api-key": apiKey
|
|
1708
1793
|
},
|
|
1709
|
-
body: JSON.stringify(
|
|
1794
|
+
body: JSON.stringify(normalizedInput)
|
|
1710
1795
|
});
|
|
1711
1796
|
} catch (error) {
|
|
1712
1797
|
throw new StoreError("Failed to reach store endpoint", void 0, error);
|
|
@@ -2216,12 +2301,29 @@ function toApiDecimal(value) {
|
|
|
2216
2301
|
}
|
|
2217
2302
|
return asString;
|
|
2218
2303
|
}
|
|
2304
|
+
var NORMALIZED_HEX_PATTERN = /^0x[0-9a-f]+$/;
|
|
2305
|
+
var ADDRESS_HEX_LENGTH = 42;
|
|
2306
|
+
var CLOID_HEX_LENGTH = 34;
|
|
2219
2307
|
function normalizeHex(value) {
|
|
2220
|
-
const lower = value.toLowerCase();
|
|
2221
|
-
|
|
2308
|
+
const lower = value.trim().toLowerCase();
|
|
2309
|
+
if (!NORMALIZED_HEX_PATTERN.test(lower)) {
|
|
2310
|
+
throw new Error(`Invalid hex value: ${value}`);
|
|
2311
|
+
}
|
|
2312
|
+
return lower;
|
|
2222
2313
|
}
|
|
2223
2314
|
function normalizeAddress(value) {
|
|
2224
|
-
|
|
2315
|
+
const normalized = normalizeHex(value);
|
|
2316
|
+
if (normalized.length !== ADDRESS_HEX_LENGTH) {
|
|
2317
|
+
throw new Error(`Invalid address length: ${normalized}`);
|
|
2318
|
+
}
|
|
2319
|
+
return normalized;
|
|
2320
|
+
}
|
|
2321
|
+
function normalizeCloid(value) {
|
|
2322
|
+
const normalized = normalizeHex(value);
|
|
2323
|
+
if (normalized.length !== CLOID_HEX_LENGTH) {
|
|
2324
|
+
throw new Error(`Invalid cloid length: ${normalized}`);
|
|
2325
|
+
}
|
|
2326
|
+
return normalized;
|
|
2225
2327
|
}
|
|
2226
2328
|
async function signL1Action(args) {
|
|
2227
2329
|
const { wallet: wallet2, action, nonce, vaultAddress, expiresAfter, isTestnet } = args;
|
|
@@ -2964,8 +3066,8 @@ async function cancelHyperliquidOrdersByCloid(options) {
|
|
|
2964
3066
|
options,
|
|
2965
3067
|
options.cancels,
|
|
2966
3068
|
(idx, entry) => ({
|
|
2967
|
-
|
|
2968
|
-
|
|
3069
|
+
asset: idx,
|
|
3070
|
+
cloid: normalizeCloid(entry.cloid)
|
|
2969
3071
|
})
|
|
2970
3072
|
)
|
|
2971
3073
|
};
|
|
@@ -2976,10 +3078,10 @@ async function cancelAllHyperliquidOrders(options) {
|
|
|
2976
3078
|
return submitExchangeAction(options, action);
|
|
2977
3079
|
}
|
|
2978
3080
|
async function scheduleHyperliquidCancel(options) {
|
|
2979
|
-
if (options.time
|
|
3081
|
+
if (options.time != null) {
|
|
2980
3082
|
assertPositiveNumber(options.time, "time");
|
|
2981
3083
|
}
|
|
2982
|
-
const action = { type: "scheduleCancel", time: options.time };
|
|
3084
|
+
const action = options.time == null ? { type: "scheduleCancel" } : { type: "scheduleCancel", time: options.time };
|
|
2983
3085
|
return submitExchangeAction(options, action);
|
|
2984
3086
|
}
|
|
2985
3087
|
async function modifyHyperliquidOrder(options) {
|
|
@@ -3213,7 +3315,7 @@ async function buildOrder(intent, options) {
|
|
|
3213
3315
|
r: intent.reduceOnly ?? false,
|
|
3214
3316
|
t: limitOrTrigger,
|
|
3215
3317
|
...intent.clientId ? {
|
|
3216
|
-
c:
|
|
3318
|
+
c: normalizeCloid(intent.clientId)
|
|
3217
3319
|
} : {}
|
|
3218
3320
|
};
|
|
3219
3321
|
}
|
|
@@ -3260,6 +3362,32 @@ function assertPositiveDecimal(value, label) {
|
|
|
3260
3362
|
return;
|
|
3261
3363
|
}
|
|
3262
3364
|
assertString(value, label);
|
|
3365
|
+
if (!/^(?:\d+\.?\d*|\.\d+)$/.test(value.trim())) {
|
|
3366
|
+
throw new Error(`${label} must be a positive decimal string.`);
|
|
3367
|
+
}
|
|
3368
|
+
const numeric = Number(value);
|
|
3369
|
+
if (!Number.isFinite(numeric) || numeric <= 0) {
|
|
3370
|
+
throw new Error(`${label} must be positive.`);
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
function collectExchangeErrorMessages(payload) {
|
|
3374
|
+
if (!payload || typeof payload !== "object") return [];
|
|
3375
|
+
const root = payload;
|
|
3376
|
+
const messages = [];
|
|
3377
|
+
const statuses = root.response?.data?.statuses;
|
|
3378
|
+
if (Array.isArray(statuses)) {
|
|
3379
|
+
statuses.forEach((status, index) => {
|
|
3380
|
+
if (status && typeof status === "object" && "error" in status && typeof status.error === "string") {
|
|
3381
|
+
const errorText = status.error;
|
|
3382
|
+
messages.push(`status[${index}]: ${errorText}`);
|
|
3383
|
+
}
|
|
3384
|
+
});
|
|
3385
|
+
}
|
|
3386
|
+
const singleStatus = root.response?.data?.status;
|
|
3387
|
+
if (singleStatus && typeof singleStatus === "object" && "error" in singleStatus && typeof singleStatus.error === "string") {
|
|
3388
|
+
messages.push(singleStatus.error);
|
|
3389
|
+
}
|
|
3390
|
+
return messages;
|
|
3263
3391
|
}
|
|
3264
3392
|
async function postExchange(env, body) {
|
|
3265
3393
|
const response = await fetch(`${API_BASES[env]}/exchange`, {
|
|
@@ -3297,10 +3425,886 @@ async function postExchange(env, body) {
|
|
|
3297
3425
|
body: json
|
|
3298
3426
|
});
|
|
3299
3427
|
}
|
|
3428
|
+
const nestedErrors = collectExchangeErrorMessages(json);
|
|
3429
|
+
if (nestedErrors.length > 0) {
|
|
3430
|
+
throw new HyperliquidApiError("Hyperliquid exchange returned action errors.", {
|
|
3431
|
+
status: response.status,
|
|
3432
|
+
statusText: response.statusText,
|
|
3433
|
+
body: json,
|
|
3434
|
+
errors: nestedErrors
|
|
3435
|
+
});
|
|
3436
|
+
}
|
|
3437
|
+
return json;
|
|
3438
|
+
}
|
|
3439
|
+
|
|
3440
|
+
// src/adapters/hyperliquid/env.ts
|
|
3441
|
+
function resolveHyperliquidChain(environment) {
|
|
3442
|
+
return environment === "mainnet" ? "arbitrum" : "arbitrum-sepolia";
|
|
3443
|
+
}
|
|
3444
|
+
function resolveHyperliquidRpcEnvVar(environment) {
|
|
3445
|
+
return environment === "mainnet" ? "ARBITRUM_RPC_URL" : "ARBITRUM_SEPOLIA_RPC_URL";
|
|
3446
|
+
}
|
|
3447
|
+
function resolveHyperliquidChainConfig(environment, env = process.env) {
|
|
3448
|
+
const rpcVar = resolveHyperliquidRpcEnvVar(environment);
|
|
3449
|
+
const rpcUrl = env[rpcVar];
|
|
3450
|
+
return {
|
|
3451
|
+
chain: resolveHyperliquidChain(environment),
|
|
3452
|
+
...rpcUrl ? { rpcUrl } : {}
|
|
3453
|
+
};
|
|
3454
|
+
}
|
|
3455
|
+
function resolveHyperliquidStoreNetwork(environment) {
|
|
3456
|
+
return environment === "mainnet" ? "hyperliquid" : "hyperliquid-testnet";
|
|
3457
|
+
}
|
|
3458
|
+
|
|
3459
|
+
// src/adapters/hyperliquid/symbols.ts
|
|
3460
|
+
var UNKNOWN_SYMBOL2 = "UNKNOWN";
|
|
3461
|
+
function extractHyperliquidDex(symbol) {
|
|
3462
|
+
const idx = symbol.indexOf(":");
|
|
3463
|
+
if (idx <= 0) return null;
|
|
3464
|
+
const dex = symbol.slice(0, idx).trim().toLowerCase();
|
|
3465
|
+
return dex || null;
|
|
3466
|
+
}
|
|
3467
|
+
function normalizeSpotTokenName2(value) {
|
|
3468
|
+
const raw = (value ?? "").trim();
|
|
3469
|
+
if (!raw) return "";
|
|
3470
|
+
if (raw.endsWith("0") && raw.length > 1) {
|
|
3471
|
+
return raw.slice(0, -1);
|
|
3472
|
+
}
|
|
3473
|
+
return raw;
|
|
3474
|
+
}
|
|
3475
|
+
function normalizeHyperliquidBaseSymbol(value) {
|
|
3476
|
+
if (!value) return null;
|
|
3477
|
+
const trimmed = value.trim();
|
|
3478
|
+
if (!trimmed) return null;
|
|
3479
|
+
const withoutDex = trimmed.includes(":") ? trimmed.split(":").slice(1).join(":") : trimmed;
|
|
3480
|
+
const base2 = withoutDex.split("-")[0] ?? withoutDex;
|
|
3481
|
+
const baseNoPair = base2.split("/")[0] ?? base2;
|
|
3482
|
+
const normalized = baseNoPair.trim().toUpperCase();
|
|
3483
|
+
if (!normalized || normalized === UNKNOWN_SYMBOL2) return null;
|
|
3484
|
+
return normalized;
|
|
3485
|
+
}
|
|
3486
|
+
function normalizeHyperliquidMetaSymbol(symbol) {
|
|
3487
|
+
const trimmed = symbol.trim();
|
|
3488
|
+
const noDex = trimmed.includes(":") ? trimmed.split(":").slice(1).join(":") : trimmed;
|
|
3489
|
+
const noPair = noDex.split("-")[0] ?? noDex;
|
|
3490
|
+
return (noPair.split("/")[0] ?? noPair).trim();
|
|
3491
|
+
}
|
|
3492
|
+
function resolveHyperliquidPair(value) {
|
|
3493
|
+
if (!value) return null;
|
|
3494
|
+
const trimmed = value.trim();
|
|
3495
|
+
if (!trimmed) return null;
|
|
3496
|
+
const withoutDex = trimmed.includes(":") ? trimmed.split(":").slice(1).join(":") : trimmed;
|
|
3497
|
+
if (withoutDex.includes("/")) {
|
|
3498
|
+
return withoutDex.toUpperCase();
|
|
3499
|
+
}
|
|
3500
|
+
if (withoutDex.includes("-")) {
|
|
3501
|
+
const [base2, ...rest] = withoutDex.split("-");
|
|
3502
|
+
const quote = rest.join("-").trim();
|
|
3503
|
+
if (!base2 || !quote) return null;
|
|
3504
|
+
return `${base2.toUpperCase()}/${quote.toUpperCase()}`;
|
|
3505
|
+
}
|
|
3506
|
+
return null;
|
|
3507
|
+
}
|
|
3508
|
+
function parseSpotPairSymbol(symbol) {
|
|
3509
|
+
const trimmed = symbol.trim();
|
|
3510
|
+
if (!trimmed.includes("/")) return null;
|
|
3511
|
+
const [rawBase, rawQuote] = trimmed.split("/");
|
|
3512
|
+
const base2 = rawBase?.trim().toUpperCase() ?? "";
|
|
3513
|
+
const quote = rawQuote?.trim().toUpperCase() ?? "";
|
|
3514
|
+
if (!base2 || !quote) return null;
|
|
3515
|
+
return { base: base2, quote };
|
|
3516
|
+
}
|
|
3517
|
+
function isHyperliquidSpotSymbol(symbol) {
|
|
3518
|
+
return symbol.startsWith("@") || symbol.includes("/");
|
|
3519
|
+
}
|
|
3520
|
+
function resolveSpotMidCandidates(baseSymbol) {
|
|
3521
|
+
const base2 = baseSymbol.trim().toUpperCase();
|
|
3522
|
+
if (!base2) return [];
|
|
3523
|
+
const candidates = [base2];
|
|
3524
|
+
if (base2.startsWith("U") && base2.length > 1) {
|
|
3525
|
+
candidates.push(base2.slice(1));
|
|
3526
|
+
}
|
|
3527
|
+
return Array.from(new Set(candidates));
|
|
3528
|
+
}
|
|
3529
|
+
function resolveSpotTokenCandidates(value) {
|
|
3530
|
+
const normalized = normalizeSpotTokenName2(value).toUpperCase();
|
|
3531
|
+
if (!normalized) return [];
|
|
3532
|
+
const candidates = [normalized];
|
|
3533
|
+
if (normalized.startsWith("U") && normalized.length > 1) {
|
|
3534
|
+
candidates.push(normalized.slice(1));
|
|
3535
|
+
}
|
|
3536
|
+
return Array.from(new Set(candidates));
|
|
3537
|
+
}
|
|
3538
|
+
function resolveHyperliquidOrderSymbol(value) {
|
|
3539
|
+
if (!value) return null;
|
|
3540
|
+
const trimmed = value.trim();
|
|
3541
|
+
if (!trimmed) return null;
|
|
3542
|
+
if (trimmed.startsWith("@")) return trimmed;
|
|
3543
|
+
if (trimmed.includes(":")) {
|
|
3544
|
+
const [rawDex, ...restParts] = trimmed.split(":");
|
|
3545
|
+
const dex = rawDex.trim().toLowerCase();
|
|
3546
|
+
const rest = restParts.join(":");
|
|
3547
|
+
const base2 = rest.split("/")[0]?.split("-")[0] ?? rest;
|
|
3548
|
+
const normalizedBase = base2.trim().toUpperCase();
|
|
3549
|
+
if (!dex || !normalizedBase || normalizedBase === UNKNOWN_SYMBOL2) {
|
|
3550
|
+
return null;
|
|
3551
|
+
}
|
|
3552
|
+
return `${dex}:${normalizedBase}`;
|
|
3553
|
+
}
|
|
3554
|
+
const pair = resolveHyperliquidPair(trimmed);
|
|
3555
|
+
if (pair) return pair;
|
|
3556
|
+
return normalizeHyperliquidBaseSymbol(trimmed);
|
|
3557
|
+
}
|
|
3558
|
+
function resolveHyperliquidSymbol(asset, override) {
|
|
3559
|
+
const raw = override && override.trim().length > 0 ? override.trim() : asset.trim();
|
|
3560
|
+
if (!raw) return raw;
|
|
3561
|
+
if (raw.startsWith("@")) return raw;
|
|
3562
|
+
if (raw.includes(":")) {
|
|
3563
|
+
const [dexRaw, ...restParts] = raw.split(":");
|
|
3564
|
+
const dex = dexRaw.trim().toLowerCase();
|
|
3565
|
+
const rest = restParts.join(":");
|
|
3566
|
+
const base3 = rest.split("/")[0]?.split("-")[0] ?? rest;
|
|
3567
|
+
const normalizedBase = base3.trim().toUpperCase();
|
|
3568
|
+
if (!dex) return normalizedBase;
|
|
3569
|
+
return `${dex}:${normalizedBase}`;
|
|
3570
|
+
}
|
|
3571
|
+
if (raw.includes("/")) {
|
|
3572
|
+
return raw.toUpperCase();
|
|
3573
|
+
}
|
|
3574
|
+
if (raw.includes("-")) {
|
|
3575
|
+
const [base3, ...rest] = raw.split("-");
|
|
3576
|
+
const quote = rest.join("-").trim();
|
|
3577
|
+
if (base3 && quote) {
|
|
3578
|
+
return `${base3.toUpperCase()}/${quote.toUpperCase()}`;
|
|
3579
|
+
}
|
|
3580
|
+
}
|
|
3581
|
+
const base2 = raw.split("-")[0] ?? raw;
|
|
3582
|
+
const baseNoPair = base2.split("/")[0] ?? base2;
|
|
3583
|
+
return baseNoPair.trim().toUpperCase();
|
|
3584
|
+
}
|
|
3585
|
+
|
|
3586
|
+
// src/adapters/hyperliquid/order-utils.ts
|
|
3587
|
+
var MAX_HYPERLIQUID_PRICE_DECIMALS = 8;
|
|
3588
|
+
function countDecimals(value) {
|
|
3589
|
+
if (!Number.isFinite(value)) return 0;
|
|
3590
|
+
const s = value.toString();
|
|
3591
|
+
const [, dec = ""] = s.split(".");
|
|
3592
|
+
return dec.length;
|
|
3593
|
+
}
|
|
3594
|
+
function clampPriceDecimals(value) {
|
|
3595
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
3596
|
+
throw new Error("Price must be positive.");
|
|
3597
|
+
}
|
|
3598
|
+
const fixed = value.toFixed(MAX_HYPERLIQUID_PRICE_DECIMALS);
|
|
3599
|
+
return fixed.replace(/\.?0+$/, "");
|
|
3600
|
+
}
|
|
3601
|
+
function assertNumberString(value) {
|
|
3602
|
+
if (!/^-?(?:\d+\.?\d*|\.\d+)$/.test(value)) {
|
|
3603
|
+
throw new TypeError("Invalid decimal number string.");
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3606
|
+
function normalizeDecimalString(value) {
|
|
3607
|
+
return value.trim().replace(/^(-?)0+(?=\d)/, "$1").replace(/\.0*$|(\.\d+?)0+$/, "$1").replace(/^(-?)\./, "$10.").replace(/^-?$/, "0").replace(/^-0$/, "0");
|
|
3608
|
+
}
|
|
3609
|
+
var StringMath = {
|
|
3610
|
+
log10Floor(value) {
|
|
3611
|
+
const abs = value.startsWith("-") ? value.slice(1) : value;
|
|
3612
|
+
const num = Number(abs);
|
|
3613
|
+
if (!Number.isFinite(num) || num === 0) return -Infinity;
|
|
3614
|
+
const [intPart, fracPart = ""] = abs.split(".");
|
|
3615
|
+
if (Number(intPart) !== 0) {
|
|
3616
|
+
return intPart.replace(/^0+/, "").length - 1;
|
|
3617
|
+
}
|
|
3618
|
+
const leadingZeros = fracPart.match(/^0*/)?.[0]?.length ?? 0;
|
|
3619
|
+
return -(leadingZeros + 1);
|
|
3620
|
+
},
|
|
3621
|
+
multiplyByPow10(value, exp) {
|
|
3622
|
+
if (!Number.isInteger(exp)) {
|
|
3623
|
+
throw new RangeError("Exponent must be an integer.");
|
|
3624
|
+
}
|
|
3625
|
+
if (exp === 0) return normalizeDecimalString(value);
|
|
3626
|
+
const negative = value.startsWith("-");
|
|
3627
|
+
const abs = negative ? value.slice(1) : value;
|
|
3628
|
+
const [intRaw, fracRaw = ""] = abs.split(".");
|
|
3629
|
+
const intPart = intRaw || "0";
|
|
3630
|
+
let output;
|
|
3631
|
+
if (exp > 0) {
|
|
3632
|
+
if (exp >= fracRaw.length) {
|
|
3633
|
+
output = intPart + fracRaw + "0".repeat(exp - fracRaw.length);
|
|
3634
|
+
} else {
|
|
3635
|
+
output = `${intPart}${fracRaw.slice(0, exp)}.${fracRaw.slice(exp)}`;
|
|
3636
|
+
}
|
|
3637
|
+
} else {
|
|
3638
|
+
const absExp = -exp;
|
|
3639
|
+
if (absExp >= intPart.length) {
|
|
3640
|
+
output = `0.${"0".repeat(absExp - intPart.length)}${intPart}${fracRaw}`;
|
|
3641
|
+
} else {
|
|
3642
|
+
output = `${intPart.slice(0, -absExp)}.${intPart.slice(-absExp)}${fracRaw}`;
|
|
3643
|
+
}
|
|
3644
|
+
}
|
|
3645
|
+
return normalizeDecimalString((negative ? "-" : "") + output);
|
|
3646
|
+
},
|
|
3647
|
+
trunc(value) {
|
|
3648
|
+
const index = value.indexOf(".");
|
|
3649
|
+
return index === -1 ? value : value.slice(0, index) || "0";
|
|
3650
|
+
},
|
|
3651
|
+
toPrecisionTruncate(value, precision) {
|
|
3652
|
+
if (!Number.isInteger(precision) || precision < 1) {
|
|
3653
|
+
throw new RangeError("Precision must be a positive integer.");
|
|
3654
|
+
}
|
|
3655
|
+
if (/^-?0+(\.0*)?$/.test(value)) return "0";
|
|
3656
|
+
const negative = value.startsWith("-");
|
|
3657
|
+
const abs = negative ? value.slice(1) : value;
|
|
3658
|
+
const magnitude = StringMath.log10Floor(abs);
|
|
3659
|
+
const shiftAmount = precision - magnitude - 1;
|
|
3660
|
+
const shifted = StringMath.multiplyByPow10(abs, shiftAmount);
|
|
3661
|
+
const truncated = StringMath.trunc(shifted);
|
|
3662
|
+
const shiftedBack = StringMath.multiplyByPow10(truncated, -shiftAmount);
|
|
3663
|
+
return normalizeDecimalString(negative ? `-${shiftedBack}` : shiftedBack);
|
|
3664
|
+
},
|
|
3665
|
+
toFixedTruncate(value, decimals) {
|
|
3666
|
+
if (!Number.isInteger(decimals) || decimals < 0) {
|
|
3667
|
+
throw new RangeError("Decimals must be a non-negative integer.");
|
|
3668
|
+
}
|
|
3669
|
+
const matcher = new RegExp(`^-?(?:\\d+)?(?:\\.\\d{0,${decimals}})?`);
|
|
3670
|
+
const result = value.match(matcher)?.[0];
|
|
3671
|
+
if (!result) {
|
|
3672
|
+
throw new TypeError("Invalid number format.");
|
|
3673
|
+
}
|
|
3674
|
+
return normalizeDecimalString(result);
|
|
3675
|
+
}
|
|
3676
|
+
};
|
|
3677
|
+
function formatHyperliquidPrice(price, szDecimals, marketType = "perp") {
|
|
3678
|
+
const normalized = price.toString().trim();
|
|
3679
|
+
assertNumberString(normalized);
|
|
3680
|
+
if (/^-?\d+$/.test(normalized)) {
|
|
3681
|
+
return normalizeDecimalString(normalized);
|
|
3682
|
+
}
|
|
3683
|
+
const maxDecimals2 = Math.max((marketType === "perp" ? 6 : 8) - szDecimals, 0);
|
|
3684
|
+
const decimalsTrimmed = StringMath.toFixedTruncate(normalized, maxDecimals2);
|
|
3685
|
+
const sigFigTrimmed = StringMath.toPrecisionTruncate(decimalsTrimmed, 5);
|
|
3686
|
+
if (sigFigTrimmed === "0") {
|
|
3687
|
+
throw new RangeError("Price is too small and was truncated to 0.");
|
|
3688
|
+
}
|
|
3689
|
+
return sigFigTrimmed;
|
|
3690
|
+
}
|
|
3691
|
+
function formatHyperliquidSize(size, szDecimals) {
|
|
3692
|
+
const normalized = size.toString().trim();
|
|
3693
|
+
assertNumberString(normalized);
|
|
3694
|
+
const truncated = StringMath.toFixedTruncate(normalized, szDecimals);
|
|
3695
|
+
if (truncated === "0") {
|
|
3696
|
+
throw new RangeError("Size is too small and was truncated to 0.");
|
|
3697
|
+
}
|
|
3698
|
+
return truncated;
|
|
3699
|
+
}
|
|
3700
|
+
function formatHyperliquidOrderSize(value, szDecimals) {
|
|
3701
|
+
if (!Number.isFinite(value) || value <= 0) return "0";
|
|
3702
|
+
try {
|
|
3703
|
+
return formatHyperliquidSize(value, szDecimals);
|
|
3704
|
+
} catch {
|
|
3705
|
+
return "0";
|
|
3706
|
+
}
|
|
3707
|
+
}
|
|
3708
|
+
function roundHyperliquidPriceToTick(price, tick, side) {
|
|
3709
|
+
if (!Number.isFinite(price) || price <= 0) {
|
|
3710
|
+
throw new Error("Price must be positive.");
|
|
3711
|
+
}
|
|
3712
|
+
if (!Number.isFinite(tick.tickDecimals) || tick.tickDecimals < 0) {
|
|
3713
|
+
throw new Error("tick.tickDecimals must be a non-negative number.");
|
|
3714
|
+
}
|
|
3715
|
+
if (tick.tickSizeInt <= 0n) {
|
|
3716
|
+
throw new Error("tick.tickSizeInt must be positive.");
|
|
3717
|
+
}
|
|
3718
|
+
const scale = 10 ** tick.tickDecimals;
|
|
3719
|
+
const scaled = BigInt(Math.round(price * scale));
|
|
3720
|
+
const tickSize = tick.tickSizeInt;
|
|
3721
|
+
const rounded = side === "sell" ? scaled / tickSize * tickSize : (scaled + tickSize - 1n) / tickSize * tickSize;
|
|
3722
|
+
const integer = Number(rounded) / scale;
|
|
3723
|
+
return clampPriceDecimals(integer);
|
|
3724
|
+
}
|
|
3725
|
+
function formatHyperliquidMarketablePrice(params) {
|
|
3726
|
+
const { mid, side, slippageBps, tick } = params;
|
|
3727
|
+
const decimals = countDecimals(mid);
|
|
3728
|
+
const factor = 10 ** decimals;
|
|
3729
|
+
const adjusted = mid * (side === "buy" ? 1 + slippageBps / 1e4 : 1 - slippageBps / 1e4);
|
|
3730
|
+
if (tick) {
|
|
3731
|
+
return roundHyperliquidPriceToTick(adjusted, tick, side);
|
|
3732
|
+
}
|
|
3733
|
+
const scaled = adjusted * factor;
|
|
3734
|
+
const rounded = side === "buy" ? Math.ceil(scaled) / factor : Math.floor(scaled) / factor;
|
|
3735
|
+
return clampPriceDecimals(rounded);
|
|
3736
|
+
}
|
|
3737
|
+
function extractHyperliquidOrderIds(responses) {
|
|
3738
|
+
const cloids = /* @__PURE__ */ new Set();
|
|
3739
|
+
const oids = /* @__PURE__ */ new Set();
|
|
3740
|
+
const push = (val, target) => {
|
|
3741
|
+
if (val === null || val === void 0) return;
|
|
3742
|
+
const str = String(val);
|
|
3743
|
+
if (str.length) target.add(str);
|
|
3744
|
+
};
|
|
3745
|
+
for (const res of responses) {
|
|
3746
|
+
const statuses = res?.response?.data?.statuses;
|
|
3747
|
+
if (!Array.isArray(statuses)) continue;
|
|
3748
|
+
for (const status of statuses) {
|
|
3749
|
+
const resting = status.resting;
|
|
3750
|
+
const filled = status.filled;
|
|
3751
|
+
push(resting?.cloid, cloids);
|
|
3752
|
+
push(resting?.oid, oids);
|
|
3753
|
+
push(filled?.cloid, cloids);
|
|
3754
|
+
push(filled?.oid, oids);
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3757
|
+
return {
|
|
3758
|
+
cloids: Array.from(cloids),
|
|
3759
|
+
oids: Array.from(oids)
|
|
3760
|
+
};
|
|
3761
|
+
}
|
|
3762
|
+
function resolveHyperliquidOrderRef(params) {
|
|
3763
|
+
const { response, fallbackCloid, fallbackOid, prefix = "hl-order", index = 0 } = params;
|
|
3764
|
+
const statuses = response?.response?.data?.statuses ?? [];
|
|
3765
|
+
if (Array.isArray(statuses)) {
|
|
3766
|
+
for (const status of statuses) {
|
|
3767
|
+
const filled = status && typeof status.filled === "object" ? status.filled : null;
|
|
3768
|
+
if (filled) {
|
|
3769
|
+
if (typeof filled.cloid === "string" && filled.cloid.trim().length > 0) {
|
|
3770
|
+
return filled.cloid;
|
|
3771
|
+
}
|
|
3772
|
+
if (typeof filled.oid === "number" || typeof filled.oid === "string" && filled.oid.trim().length > 0) {
|
|
3773
|
+
return String(filled.oid);
|
|
3774
|
+
}
|
|
3775
|
+
}
|
|
3776
|
+
const resting = status && typeof status.resting === "object" ? status.resting : null;
|
|
3777
|
+
if (resting) {
|
|
3778
|
+
if (typeof resting.cloid === "string" && resting.cloid.trim().length > 0) {
|
|
3779
|
+
return resting.cloid;
|
|
3780
|
+
}
|
|
3781
|
+
if (typeof resting.oid === "number" || typeof resting.oid === "string" && resting.oid.trim().length > 0) {
|
|
3782
|
+
return String(resting.oid);
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3787
|
+
if (fallbackCloid && fallbackCloid.trim().length > 0) {
|
|
3788
|
+
return fallbackCloid;
|
|
3789
|
+
}
|
|
3790
|
+
if (fallbackOid && fallbackOid.trim().length > 0) {
|
|
3791
|
+
return fallbackOid;
|
|
3792
|
+
}
|
|
3793
|
+
return `${prefix}-${Date.now()}-${index}`;
|
|
3794
|
+
}
|
|
3795
|
+
function resolveHyperliquidErrorDetail(error) {
|
|
3796
|
+
if (error instanceof HyperliquidApiError) {
|
|
3797
|
+
return error.response ?? null;
|
|
3798
|
+
}
|
|
3799
|
+
if (error && typeof error === "object" && "response" in error) {
|
|
3800
|
+
return error.response ?? null;
|
|
3801
|
+
}
|
|
3802
|
+
return null;
|
|
3803
|
+
}
|
|
3804
|
+
|
|
3805
|
+
// src/adapters/hyperliquid/state-readers.ts
|
|
3806
|
+
function unwrapData(payload) {
|
|
3807
|
+
if (!payload || typeof payload !== "object") return null;
|
|
3808
|
+
if ("data" in payload) {
|
|
3809
|
+
const data = payload.data;
|
|
3810
|
+
if (data && typeof data === "object") {
|
|
3811
|
+
return data;
|
|
3812
|
+
}
|
|
3813
|
+
}
|
|
3814
|
+
return payload;
|
|
3815
|
+
}
|
|
3816
|
+
function readHyperliquidNumber(value) {
|
|
3817
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
3818
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
3819
|
+
const parsed = Number(value);
|
|
3820
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
3821
|
+
}
|
|
3822
|
+
return null;
|
|
3823
|
+
}
|
|
3824
|
+
function readHyperliquidAccountValue(payload) {
|
|
3825
|
+
const data = unwrapData(payload);
|
|
3826
|
+
if (!data) return null;
|
|
3827
|
+
const candidates = [
|
|
3828
|
+
data?.marginSummary?.accountValue,
|
|
3829
|
+
data?.crossMarginSummary?.accountValue,
|
|
3830
|
+
data?.accountValue,
|
|
3831
|
+
data?.equity,
|
|
3832
|
+
data?.totalAccountValue,
|
|
3833
|
+
data?.marginSummary?.totalAccountValue
|
|
3834
|
+
];
|
|
3835
|
+
for (const value of candidates) {
|
|
3836
|
+
const parsed = readHyperliquidNumber(value);
|
|
3837
|
+
if (parsed !== null) return parsed;
|
|
3838
|
+
}
|
|
3839
|
+
return null;
|
|
3840
|
+
}
|
|
3841
|
+
function matchPerpCoin(params) {
|
|
3842
|
+
const coin = params.coin.toUpperCase();
|
|
3843
|
+
const target = params.target.toUpperCase();
|
|
3844
|
+
if (params.prefixMatch) return coin.startsWith(target);
|
|
3845
|
+
return coin === target;
|
|
3846
|
+
}
|
|
3847
|
+
function readHyperliquidPerpPositionSize(payload, symbol, options) {
|
|
3848
|
+
const data = unwrapData(payload);
|
|
3849
|
+
const rows = Array.isArray(data?.assetPositions) ? data.assetPositions : [];
|
|
3850
|
+
const base2 = symbol.split("-")[0]?.toUpperCase() ?? symbol.toUpperCase();
|
|
3851
|
+
const prefixMatch = options?.prefixMatch ?? false;
|
|
3852
|
+
for (const row of rows) {
|
|
3853
|
+
const position = row.position ?? row;
|
|
3854
|
+
const coin = typeof position?.coin === "string" ? position.coin : typeof row.coin === "string" ? row.coin : "";
|
|
3855
|
+
if (!matchPerpCoin({ coin, target: base2, prefixMatch })) continue;
|
|
3856
|
+
const size = position.szi ?? row.szi;
|
|
3857
|
+
const parsed = readHyperliquidNumber(size);
|
|
3858
|
+
return parsed ?? 0;
|
|
3859
|
+
}
|
|
3860
|
+
return 0;
|
|
3861
|
+
}
|
|
3862
|
+
function readHyperliquidPerpPosition(payload, symbol, options) {
|
|
3863
|
+
const data = unwrapData(payload);
|
|
3864
|
+
const rows = Array.isArray(data?.assetPositions) ? data.assetPositions : [];
|
|
3865
|
+
const target = symbol.split("-")[0]?.toUpperCase() ?? symbol.toUpperCase();
|
|
3866
|
+
const prefixMatch = options?.prefixMatch ?? false;
|
|
3867
|
+
for (const row of rows) {
|
|
3868
|
+
const position = row?.position ?? row;
|
|
3869
|
+
const coin = typeof position?.coin === "string" ? position.coin : typeof row?.coin === "string" ? row.coin : "";
|
|
3870
|
+
if (!matchPerpCoin({ coin, target, prefixMatch })) continue;
|
|
3871
|
+
const size = readHyperliquidNumber(position?.szi ?? row.szi) ?? 0;
|
|
3872
|
+
const positionValue = Math.abs(
|
|
3873
|
+
readHyperliquidNumber(position?.positionValue ?? row.positionValue) ?? 0
|
|
3874
|
+
);
|
|
3875
|
+
const unrealizedPnl = readHyperliquidNumber(
|
|
3876
|
+
position?.unrealizedPnl ?? row.unrealizedPnl
|
|
3877
|
+
);
|
|
3878
|
+
return { size, positionValue, unrealizedPnl };
|
|
3879
|
+
}
|
|
3880
|
+
return { size: 0, positionValue: 0, unrealizedPnl: null };
|
|
3881
|
+
}
|
|
3882
|
+
function readHyperliquidSpotBalanceSize(payload, symbol) {
|
|
3883
|
+
const data = unwrapData(payload);
|
|
3884
|
+
const rows = Array.isArray(data?.balances) ? data.balances : [];
|
|
3885
|
+
const base2 = symbol.split("/")[0]?.split("-")[0]?.toUpperCase() ?? symbol.toUpperCase();
|
|
3886
|
+
for (const row of rows) {
|
|
3887
|
+
const coin = typeof row?.coin === "string" ? row.coin : typeof row?.asset === "string" ? row.asset : "";
|
|
3888
|
+
if (coin.toUpperCase() !== base2) continue;
|
|
3889
|
+
const total = row.total ?? row.balance ?? row.szi;
|
|
3890
|
+
const parsed = readHyperliquidNumber(total);
|
|
3891
|
+
return parsed ?? 0;
|
|
3892
|
+
}
|
|
3893
|
+
return 0;
|
|
3894
|
+
}
|
|
3895
|
+
function readHyperliquidSpotBalance(payload, base2) {
|
|
3896
|
+
const data = unwrapData(payload);
|
|
3897
|
+
const balances = Array.isArray(data?.balances) ? data.balances : [];
|
|
3898
|
+
const target = base2.toUpperCase();
|
|
3899
|
+
for (const row of balances) {
|
|
3900
|
+
const coin = typeof row?.coin === "string" ? row.coin : "";
|
|
3901
|
+
if (coin.toUpperCase() !== target) continue;
|
|
3902
|
+
const total = readHyperliquidNumber(row?.total) ?? 0;
|
|
3903
|
+
const entryNtl = readHyperliquidNumber(row?.entryNtl);
|
|
3904
|
+
return { total, entryNtl };
|
|
3905
|
+
}
|
|
3906
|
+
return { total: 0, entryNtl: null };
|
|
3907
|
+
}
|
|
3908
|
+
function readHyperliquidSpotAccountValue(params) {
|
|
3909
|
+
const rows = Array.isArray(params.balances) ? params.balances : [];
|
|
3910
|
+
if (rows.length === 0) return null;
|
|
3911
|
+
let total = 0;
|
|
3912
|
+
let hasValue = false;
|
|
3913
|
+
for (const row of rows) {
|
|
3914
|
+
const coin = typeof row?.coin === "string" ? row.coin : typeof row?.asset === "string" ? row.asset : "";
|
|
3915
|
+
if (!coin) continue;
|
|
3916
|
+
const amount = readHyperliquidNumber(
|
|
3917
|
+
row.total ?? row.balance ?? row.szi
|
|
3918
|
+
);
|
|
3919
|
+
if (amount == null || amount === 0) continue;
|
|
3920
|
+
const price = params.pricesUsd.get(coin.toUpperCase());
|
|
3921
|
+
if (price == null || !Number.isFinite(price) || price <= 0) continue;
|
|
3922
|
+
total += amount * price;
|
|
3923
|
+
hasValue = true;
|
|
3924
|
+
}
|
|
3925
|
+
return hasValue ? total : null;
|
|
3926
|
+
}
|
|
3927
|
+
|
|
3928
|
+
// src/adapters/hyperliquid/market-data.ts
|
|
3929
|
+
var META_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
3930
|
+
var allMidsCache = /* @__PURE__ */ new Map();
|
|
3931
|
+
function gcd(a, b) {
|
|
3932
|
+
let left = a < 0n ? -a : a;
|
|
3933
|
+
let right = b < 0n ? -b : b;
|
|
3934
|
+
while (right !== 0n) {
|
|
3935
|
+
const next = left % right;
|
|
3936
|
+
left = right;
|
|
3937
|
+
right = next;
|
|
3938
|
+
}
|
|
3939
|
+
return left;
|
|
3940
|
+
}
|
|
3941
|
+
function pow10(decimals) {
|
|
3942
|
+
let result = 1n;
|
|
3943
|
+
for (let i = 0; i < decimals; i += 1) {
|
|
3944
|
+
result *= 10n;
|
|
3945
|
+
}
|
|
3946
|
+
return result;
|
|
3947
|
+
}
|
|
3948
|
+
function maxDecimals(values) {
|
|
3949
|
+
let max = 0;
|
|
3950
|
+
for (const value of values) {
|
|
3951
|
+
const dot = value.indexOf(".");
|
|
3952
|
+
if (dot === -1) continue;
|
|
3953
|
+
const decimals = value.length - dot - 1;
|
|
3954
|
+
if (decimals > max) max = decimals;
|
|
3955
|
+
}
|
|
3956
|
+
return max;
|
|
3957
|
+
}
|
|
3958
|
+
function toScaledInt(value, decimals) {
|
|
3959
|
+
const trimmed = value.trim();
|
|
3960
|
+
const negative = trimmed.startsWith("-");
|
|
3961
|
+
const unsigned = negative ? trimmed.slice(1) : trimmed;
|
|
3962
|
+
const [intPart, fracPart = ""] = unsigned.split(".");
|
|
3963
|
+
const padded = fracPart.padEnd(decimals, "0").slice(0, decimals);
|
|
3964
|
+
const combined = `${intPart || "0"}${padded}`;
|
|
3965
|
+
const asInt = BigInt(combined || "0");
|
|
3966
|
+
return negative ? -asInt : asInt;
|
|
3967
|
+
}
|
|
3968
|
+
function formatScaledInt(value, decimals) {
|
|
3969
|
+
const negative = value < 0n;
|
|
3970
|
+
const absValue = negative ? -value : value;
|
|
3971
|
+
const scale = pow10(decimals);
|
|
3972
|
+
const integer = absValue / scale;
|
|
3973
|
+
const fraction = absValue % scale;
|
|
3974
|
+
if (decimals === 0) {
|
|
3975
|
+
return `${negative ? "-" : ""}${integer.toString()}`;
|
|
3976
|
+
}
|
|
3977
|
+
const fractionStr = fraction.toString().padStart(decimals, "0");
|
|
3978
|
+
return `${negative ? "-" : ""}${integer.toString()}.${fractionStr}`.replace(
|
|
3979
|
+
/\.?0+$/,
|
|
3980
|
+
""
|
|
3981
|
+
);
|
|
3982
|
+
}
|
|
3983
|
+
function resolveSpotSizeDecimals(meta, symbol) {
|
|
3984
|
+
const universe = meta.universe ?? [];
|
|
3985
|
+
const tokens2 = meta.tokens ?? [];
|
|
3986
|
+
if (!universe.length || !tokens2.length) {
|
|
3987
|
+
throw new Error(`Spot metadata unavailable for ${symbol}.`);
|
|
3988
|
+
}
|
|
3989
|
+
const tokenMap = /* @__PURE__ */ new Map();
|
|
3990
|
+
for (const token2 of tokens2) {
|
|
3991
|
+
const index = token2?.index;
|
|
3992
|
+
const szDecimals = typeof token2?.szDecimals === "number" ? token2.szDecimals : null;
|
|
3993
|
+
if (typeof index !== "number" || szDecimals == null) continue;
|
|
3994
|
+
tokenMap.set(index, {
|
|
3995
|
+
name: normalizeSpotTokenName2(token2?.name),
|
|
3996
|
+
szDecimals
|
|
3997
|
+
});
|
|
3998
|
+
}
|
|
3999
|
+
if (symbol.startsWith("@")) {
|
|
4000
|
+
const targetIndex = Number.parseInt(symbol.slice(1), 10);
|
|
4001
|
+
if (!Number.isFinite(targetIndex)) {
|
|
4002
|
+
throw new Error(`Invalid spot pair id: ${symbol}`);
|
|
4003
|
+
}
|
|
4004
|
+
for (let idx = 0; idx < universe.length; idx += 1) {
|
|
4005
|
+
const market = universe[idx];
|
|
4006
|
+
const marketIndex = typeof market?.index === "number" ? market.index : idx;
|
|
4007
|
+
if (marketIndex !== targetIndex) continue;
|
|
4008
|
+
const [baseIndex] = Array.isArray(market?.tokens) ? market.tokens : [];
|
|
4009
|
+
const baseToken = tokenMap.get(baseIndex ?? -1);
|
|
4010
|
+
if (!baseToken) break;
|
|
4011
|
+
return baseToken.szDecimals;
|
|
4012
|
+
}
|
|
4013
|
+
throw new Error(`Unknown spot pair id: ${symbol}`);
|
|
4014
|
+
}
|
|
4015
|
+
const pair = parseSpotPairSymbol(symbol);
|
|
4016
|
+
if (!pair) {
|
|
4017
|
+
throw new Error(`Invalid spot symbol: ${symbol}`);
|
|
4018
|
+
}
|
|
4019
|
+
const normalizedBase = normalizeSpotTokenName2(pair.base).toUpperCase();
|
|
4020
|
+
const normalizedQuote = normalizeSpotTokenName2(pair.quote).toUpperCase();
|
|
4021
|
+
for (const market of universe) {
|
|
4022
|
+
const [baseIndex, quoteIndex] = Array.isArray(market?.tokens) ? market.tokens : [];
|
|
4023
|
+
const baseToken = tokenMap.get(baseIndex ?? -1);
|
|
4024
|
+
const quoteToken = tokenMap.get(quoteIndex ?? -1);
|
|
4025
|
+
if (!baseToken || !quoteToken) continue;
|
|
4026
|
+
if (baseToken.name.toUpperCase() === normalizedBase && quoteToken.name.toUpperCase() === normalizedQuote) {
|
|
4027
|
+
return baseToken.szDecimals;
|
|
4028
|
+
}
|
|
4029
|
+
}
|
|
4030
|
+
throw new Error(`No size decimals found for ${symbol}.`);
|
|
4031
|
+
}
|
|
4032
|
+
async function fetchHyperliquidAllMids(environment) {
|
|
4033
|
+
const cacheKey = environment;
|
|
4034
|
+
const cached = allMidsCache.get(cacheKey);
|
|
4035
|
+
if (cached && Date.now() - cached.fetchedAt < META_CACHE_TTL_MS) {
|
|
4036
|
+
return cached.mids;
|
|
4037
|
+
}
|
|
4038
|
+
const baseUrl = API_BASES[environment];
|
|
4039
|
+
const res = await fetch(`${baseUrl}/info`, {
|
|
4040
|
+
method: "POST",
|
|
4041
|
+
headers: { "content-type": "application/json" },
|
|
4042
|
+
body: JSON.stringify({ type: "allMids" })
|
|
4043
|
+
});
|
|
4044
|
+
const json = await res.json().catch(() => null);
|
|
4045
|
+
if (!res.ok || !json || typeof json !== "object") {
|
|
4046
|
+
throw new Error(`Failed to load Hyperliquid mid prices (${res.status}).`);
|
|
4047
|
+
}
|
|
4048
|
+
allMidsCache.set(cacheKey, { fetchedAt: Date.now(), mids: json });
|
|
3300
4049
|
return json;
|
|
3301
4050
|
}
|
|
4051
|
+
async function fetchHyperliquidTickSize(params) {
|
|
4052
|
+
return fetchHyperliquidTickSizeForCoin(params.environment, params.symbol);
|
|
4053
|
+
}
|
|
4054
|
+
async function fetchHyperliquidSpotTickSize(params) {
|
|
4055
|
+
if (!Number.isFinite(params.marketIndex)) {
|
|
4056
|
+
throw new Error("Hyperliquid spot market index is invalid.");
|
|
4057
|
+
}
|
|
4058
|
+
return fetchHyperliquidTickSizeForCoin(
|
|
4059
|
+
params.environment,
|
|
4060
|
+
`@${params.marketIndex}`
|
|
4061
|
+
);
|
|
4062
|
+
}
|
|
4063
|
+
async function fetchHyperliquidTickSizeForCoin(environment, coin) {
|
|
4064
|
+
const base2 = API_BASES[environment];
|
|
4065
|
+
const res = await fetch(`${base2}/info`, {
|
|
4066
|
+
method: "POST",
|
|
4067
|
+
headers: { "content-type": "application/json" },
|
|
4068
|
+
body: JSON.stringify({ type: "l2Book", coin })
|
|
4069
|
+
});
|
|
4070
|
+
if (!res.ok) {
|
|
4071
|
+
throw new Error(`Hyperliquid l2Book failed for ${coin}`);
|
|
4072
|
+
}
|
|
4073
|
+
const data = await res.json().catch(() => null);
|
|
4074
|
+
const levels = Array.isArray(data?.levels) ? data?.levels ?? [] : [];
|
|
4075
|
+
const prices = levels.flatMap(
|
|
4076
|
+
(side) => Array.isArray(side) ? side.map((entry) => String(entry?.px ?? "")) : []
|
|
4077
|
+
).filter((px) => px.length > 0);
|
|
4078
|
+
if (prices.length < 2) {
|
|
4079
|
+
throw new Error(`Hyperliquid l2Book missing price levels for ${coin}`);
|
|
4080
|
+
}
|
|
4081
|
+
const decimals = maxDecimals(prices);
|
|
4082
|
+
const scaled = prices.map((px) => toScaledInt(px, decimals));
|
|
4083
|
+
const unique = Array.from(new Set(scaled.map((v) => v.toString()))).map((v) => BigInt(v)).sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
4084
|
+
let tick = 0n;
|
|
4085
|
+
for (let i = 1; i < unique.length; i += 1) {
|
|
4086
|
+
const diff = unique[i] - unique[i - 1];
|
|
4087
|
+
if (diff <= 0n) continue;
|
|
4088
|
+
tick = tick === 0n ? diff : gcd(tick, diff);
|
|
4089
|
+
}
|
|
4090
|
+
if (tick === 0n) {
|
|
4091
|
+
tick = 1n;
|
|
4092
|
+
}
|
|
4093
|
+
return { tickSizeInt: tick, tickDecimals: decimals };
|
|
4094
|
+
}
|
|
4095
|
+
async function fetchHyperliquidPerpMarketInfo(params) {
|
|
4096
|
+
const data = await fetchHyperliquidMetaAndAssetCtxs(params.environment);
|
|
4097
|
+
const universe = data?.[0]?.universe ?? [];
|
|
4098
|
+
const contexts = data?.[1] ?? [];
|
|
4099
|
+
const target = normalizeHyperliquidMetaSymbol(params.symbol).toUpperCase();
|
|
4100
|
+
const idx = universe.findIndex(
|
|
4101
|
+
(entry) => normalizeHyperliquidMetaSymbol(entry?.name ?? "").toUpperCase() === target
|
|
4102
|
+
);
|
|
4103
|
+
if (idx < 0) {
|
|
4104
|
+
throw new Error(`Unknown Hyperliquid perp asset: ${params.symbol}`);
|
|
4105
|
+
}
|
|
4106
|
+
const ctx = contexts[idx] ?? null;
|
|
4107
|
+
const price = readHyperliquidNumber(ctx?.markPx ?? ctx?.midPx ?? ctx?.oraclePx);
|
|
4108
|
+
if (!price || price <= 0) {
|
|
4109
|
+
throw new Error(`No perp price available for ${params.symbol}`);
|
|
4110
|
+
}
|
|
4111
|
+
const fundingRate = readHyperliquidNumber(ctx?.funding);
|
|
4112
|
+
const szDecimals = readHyperliquidNumber(universe[idx]?.szDecimals);
|
|
4113
|
+
if (szDecimals == null) {
|
|
4114
|
+
throw new Error(`No size decimals available for ${params.symbol}`);
|
|
4115
|
+
}
|
|
4116
|
+
return {
|
|
4117
|
+
symbol: params.symbol,
|
|
4118
|
+
price,
|
|
4119
|
+
fundingRate,
|
|
4120
|
+
szDecimals
|
|
4121
|
+
};
|
|
4122
|
+
}
|
|
4123
|
+
async function fetchHyperliquidSpotMarketInfo(params) {
|
|
4124
|
+
const mids = params.mids === void 0 ? await fetchHyperliquidAllMids(params.environment).catch(() => null) : params.mids;
|
|
4125
|
+
const data = await fetchHyperliquidSpotMetaAndAssetCtxs(params.environment);
|
|
4126
|
+
const universe = data?.[0]?.universe ?? [];
|
|
4127
|
+
const tokens2 = data?.[0]?.tokens ?? [];
|
|
4128
|
+
const contexts = data?.[1] ?? [];
|
|
4129
|
+
const tokenMap = /* @__PURE__ */ new Map();
|
|
4130
|
+
for (const token2 of tokens2) {
|
|
4131
|
+
const index = token2?.index;
|
|
4132
|
+
const szDecimals = readHyperliquidNumber(token2?.szDecimals);
|
|
4133
|
+
if (typeof index !== "number" || szDecimals == null) continue;
|
|
4134
|
+
tokenMap.set(index, {
|
|
4135
|
+
name: normalizeSpotTokenName2(token2?.name),
|
|
4136
|
+
szDecimals
|
|
4137
|
+
});
|
|
4138
|
+
}
|
|
4139
|
+
const baseCandidates = resolveSpotTokenCandidates(params.base);
|
|
4140
|
+
const quoteCandidates = resolveSpotTokenCandidates(params.quote);
|
|
4141
|
+
const normalizedBase = normalizeSpotTokenName2(params.base).toUpperCase();
|
|
4142
|
+
const normalizedQuote = normalizeSpotTokenName2(params.quote).toUpperCase();
|
|
4143
|
+
for (let idx = 0; idx < universe.length; idx += 1) {
|
|
4144
|
+
const market = universe[idx];
|
|
4145
|
+
const [baseIndex, quoteIndex] = Array.isArray(market?.tokens) ? market.tokens : [];
|
|
4146
|
+
const baseToken = tokenMap.get(baseIndex ?? -1);
|
|
4147
|
+
const quoteToken = tokenMap.get(quoteIndex ?? -1);
|
|
4148
|
+
if (!baseToken || !quoteToken) continue;
|
|
4149
|
+
const marketBaseCandidates = resolveSpotTokenCandidates(baseToken.name);
|
|
4150
|
+
const marketQuoteCandidates = resolveSpotTokenCandidates(quoteToken.name);
|
|
4151
|
+
if (baseCandidates.some((candidate) => marketBaseCandidates.includes(candidate)) && quoteCandidates.some((candidate) => marketQuoteCandidates.includes(candidate))) {
|
|
4152
|
+
const contextIndex = typeof market?.index === "number" ? market.index : idx;
|
|
4153
|
+
const ctx = (contextIndex >= 0 && contextIndex < contexts.length ? contexts[contextIndex] : null) ?? contexts[idx] ?? null;
|
|
4154
|
+
let price = null;
|
|
4155
|
+
if (mids) {
|
|
4156
|
+
for (const candidate of resolveSpotMidCandidates(baseToken.name)) {
|
|
4157
|
+
const mid = readHyperliquidNumber(mids[candidate]);
|
|
4158
|
+
if (mid != null && mid > 0) {
|
|
4159
|
+
price = mid;
|
|
4160
|
+
break;
|
|
4161
|
+
}
|
|
4162
|
+
}
|
|
4163
|
+
}
|
|
4164
|
+
if (!price || price <= 0) {
|
|
4165
|
+
price = readHyperliquidNumber(ctx?.markPx ?? ctx?.midPx ?? ctx?.oraclePx);
|
|
4166
|
+
}
|
|
4167
|
+
if (!price || price <= 0) {
|
|
4168
|
+
throw new Error(
|
|
4169
|
+
`No spot price available for ${normalizedBase}/${normalizedQuote}`
|
|
4170
|
+
);
|
|
4171
|
+
}
|
|
4172
|
+
const marketIndex = typeof market?.index === "number" ? market.index : idx;
|
|
4173
|
+
return {
|
|
4174
|
+
symbol: `${baseToken.name.toUpperCase()}/${quoteToken.name.toUpperCase()}`,
|
|
4175
|
+
base: baseToken.name.toUpperCase(),
|
|
4176
|
+
quote: quoteToken.name.toUpperCase(),
|
|
4177
|
+
assetId: 1e4 + marketIndex,
|
|
4178
|
+
marketIndex,
|
|
4179
|
+
price,
|
|
4180
|
+
szDecimals: baseToken.szDecimals
|
|
4181
|
+
};
|
|
4182
|
+
}
|
|
4183
|
+
}
|
|
4184
|
+
throw new Error(`Unknown Hyperliquid spot market: ${normalizedBase}/${normalizedQuote}`);
|
|
4185
|
+
}
|
|
4186
|
+
async function fetchHyperliquidSizeDecimals(params) {
|
|
4187
|
+
const { symbol, environment } = params;
|
|
4188
|
+
if (isHyperliquidSpotSymbol(symbol)) {
|
|
4189
|
+
const meta2 = await fetchHyperliquidSpotMeta(environment);
|
|
4190
|
+
return resolveSpotSizeDecimals(meta2, symbol);
|
|
4191
|
+
}
|
|
4192
|
+
const meta = await fetchHyperliquidMeta(environment);
|
|
4193
|
+
const universe = Array.isArray(meta?.universe) ? meta.universe : [];
|
|
4194
|
+
const normalized = normalizeHyperliquidMetaSymbol(symbol).toUpperCase();
|
|
4195
|
+
const match = universe.find(
|
|
4196
|
+
(entry) => normalizeHyperliquidMetaSymbol(entry?.name ?? "").toUpperCase() === normalized
|
|
4197
|
+
);
|
|
4198
|
+
if (!match || typeof match.szDecimals !== "number") {
|
|
4199
|
+
throw new Error(`No size decimals found for ${symbol}.`);
|
|
4200
|
+
}
|
|
4201
|
+
return match.szDecimals;
|
|
4202
|
+
}
|
|
4203
|
+
function buildHyperliquidSpotUsdPriceMap(params) {
|
|
4204
|
+
const universe = params.meta.universe ?? [];
|
|
4205
|
+
const tokens2 = params.meta.tokens ?? [];
|
|
4206
|
+
const tokenMap = /* @__PURE__ */ new Map();
|
|
4207
|
+
for (const token2 of tokens2) {
|
|
4208
|
+
const index = token2?.index;
|
|
4209
|
+
if (typeof index !== "number") continue;
|
|
4210
|
+
tokenMap.set(index, normalizeSpotTokenName2(token2?.name).toUpperCase());
|
|
4211
|
+
}
|
|
4212
|
+
const prices = /* @__PURE__ */ new Map();
|
|
4213
|
+
prices.set("USDC", 1);
|
|
4214
|
+
for (let idx = 0; idx < universe.length; idx += 1) {
|
|
4215
|
+
const market = universe[idx];
|
|
4216
|
+
const [baseIndex, quoteIndex] = Array.isArray(market?.tokens) ? market.tokens : [];
|
|
4217
|
+
const base2 = tokenMap.get(baseIndex ?? -1);
|
|
4218
|
+
const quote = tokenMap.get(quoteIndex ?? -1);
|
|
4219
|
+
if (!base2 || !quote) continue;
|
|
4220
|
+
if (quote !== "USDC") continue;
|
|
4221
|
+
const contextIndex = typeof market?.index === "number" ? market.index : idx;
|
|
4222
|
+
const ctx = (contextIndex >= 0 && contextIndex < params.ctxs.length ? params.ctxs[contextIndex] : null) ?? params.ctxs[idx] ?? null;
|
|
4223
|
+
let price = null;
|
|
4224
|
+
if (params.mids) {
|
|
4225
|
+
for (const candidate of resolveSpotMidCandidates(base2)) {
|
|
4226
|
+
const mid = readHyperliquidNumber(params.mids[candidate]);
|
|
4227
|
+
if (mid != null && mid > 0) {
|
|
4228
|
+
price = mid;
|
|
4229
|
+
break;
|
|
4230
|
+
}
|
|
4231
|
+
}
|
|
4232
|
+
}
|
|
4233
|
+
if (!price || price <= 0) {
|
|
4234
|
+
price = readHyperliquidNumber(ctx?.markPx ?? ctx?.midPx ?? ctx?.oraclePx);
|
|
4235
|
+
}
|
|
4236
|
+
if (!price || price <= 0) continue;
|
|
4237
|
+
prices.set(base2, price);
|
|
4238
|
+
}
|
|
4239
|
+
return prices;
|
|
4240
|
+
}
|
|
4241
|
+
async function fetchHyperliquidSpotUsdPriceMap(environment) {
|
|
4242
|
+
const [spotMetaAndCtxs, mids] = await Promise.all([
|
|
4243
|
+
fetchHyperliquidSpotMetaAndAssetCtxs(environment),
|
|
4244
|
+
fetchHyperliquidAllMids(environment).catch(() => null)
|
|
4245
|
+
]);
|
|
4246
|
+
const [metaRaw, ctxsRaw] = spotMetaAndCtxs;
|
|
4247
|
+
const meta = {
|
|
4248
|
+
universe: Array.isArray(metaRaw?.universe) ? metaRaw.universe : [],
|
|
4249
|
+
tokens: Array.isArray(metaRaw?.tokens) ? metaRaw.tokens : []
|
|
4250
|
+
};
|
|
4251
|
+
const ctxs = Array.isArray(ctxsRaw) ? ctxsRaw : [];
|
|
4252
|
+
return buildHyperliquidSpotUsdPriceMap({ meta, ctxs, mids });
|
|
4253
|
+
}
|
|
4254
|
+
async function fetchHyperliquidSpotAccountValue(params) {
|
|
4255
|
+
const pricesUsd = await fetchHyperliquidSpotUsdPriceMap(params.environment);
|
|
4256
|
+
return readHyperliquidSpotAccountValue({
|
|
4257
|
+
balances: params.balances,
|
|
4258
|
+
pricesUsd
|
|
4259
|
+
});
|
|
4260
|
+
}
|
|
4261
|
+
var __hyperliquidMarketDataInternals = {
|
|
4262
|
+
maxDecimals,
|
|
4263
|
+
toScaledInt,
|
|
4264
|
+
formatScaledInt
|
|
4265
|
+
};
|
|
3302
4266
|
|
|
3303
4267
|
// src/adapters/hyperliquid/index.ts
|
|
4268
|
+
function assertPositiveDecimalInput(value, label) {
|
|
4269
|
+
if (typeof value === "number") {
|
|
4270
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
4271
|
+
throw new Error(`${label} must be a positive number.`);
|
|
4272
|
+
}
|
|
4273
|
+
return;
|
|
4274
|
+
}
|
|
4275
|
+
if (typeof value === "bigint") {
|
|
4276
|
+
if (value <= 0n) {
|
|
4277
|
+
throw new Error(`${label} must be positive.`);
|
|
4278
|
+
}
|
|
4279
|
+
return;
|
|
4280
|
+
}
|
|
4281
|
+
const trimmed = value.trim();
|
|
4282
|
+
if (!trimmed.length) {
|
|
4283
|
+
throw new Error(`${label} must be a non-empty string.`);
|
|
4284
|
+
}
|
|
4285
|
+
if (!/^(?:\d+\.?\d*|\.\d+)$/.test(trimmed)) {
|
|
4286
|
+
throw new Error(`${label} must be a positive decimal string.`);
|
|
4287
|
+
}
|
|
4288
|
+
const numeric = Number(trimmed);
|
|
4289
|
+
if (!Number.isFinite(numeric) || numeric <= 0) {
|
|
4290
|
+
throw new Error(`${label} must be positive.`);
|
|
4291
|
+
}
|
|
4292
|
+
}
|
|
4293
|
+
function normalizePositiveDecimalString(raw, label) {
|
|
4294
|
+
const trimmed = raw.trim();
|
|
4295
|
+
if (!trimmed.length) {
|
|
4296
|
+
throw new Error(`${label} must be a non-empty decimal string.`);
|
|
4297
|
+
}
|
|
4298
|
+
if (!/^(?:\d+\.?\d*|\.\d+)$/.test(trimmed)) {
|
|
4299
|
+
throw new Error(`${label} must be a positive decimal string.`);
|
|
4300
|
+
}
|
|
4301
|
+
const normalized = trimmed.replace(/^0+(?=\d)/, "").replace(/(\.\d*?)0+$/, "$1").replace(/\.$/, "");
|
|
4302
|
+
const numeric = Number(normalized);
|
|
4303
|
+
if (!Number.isFinite(numeric) || numeric <= 0) {
|
|
4304
|
+
throw new Error(`${label} must be positive.`);
|
|
4305
|
+
}
|
|
4306
|
+
return normalized;
|
|
4307
|
+
}
|
|
3304
4308
|
async function placeHyperliquidOrder(options) {
|
|
3305
4309
|
const {
|
|
3306
4310
|
wallet: wallet2,
|
|
@@ -3324,6 +4328,11 @@ async function placeHyperliquidOrder(options) {
|
|
|
3324
4328
|
const resolvedBaseUrl = API_BASES[inferredEnvironment];
|
|
3325
4329
|
const preparedOrders = await Promise.all(
|
|
3326
4330
|
orders.map(async (intent) => {
|
|
4331
|
+
assertPositiveDecimalInput(intent.price, "price");
|
|
4332
|
+
assertPositiveDecimalInput(intent.size, "size");
|
|
4333
|
+
if (intent.trigger) {
|
|
4334
|
+
assertPositiveDecimalInput(intent.trigger.triggerPx, "triggerPx");
|
|
4335
|
+
}
|
|
3327
4336
|
const assetIndex = await resolveHyperliquidAssetIndex({
|
|
3328
4337
|
symbol: intent.symbol,
|
|
3329
4338
|
baseUrl: resolvedBaseUrl,
|
|
@@ -3349,7 +4358,7 @@ async function placeHyperliquidOrder(options) {
|
|
|
3349
4358
|
r: intent.reduceOnly ?? false,
|
|
3350
4359
|
t: limitOrTrigger,
|
|
3351
4360
|
...intent.clientId ? {
|
|
3352
|
-
c:
|
|
4361
|
+
c: normalizeCloid(intent.clientId)
|
|
3353
4362
|
} : {}
|
|
3354
4363
|
};
|
|
3355
4364
|
return order;
|
|
@@ -3418,7 +4427,9 @@ async function placeHyperliquidOrder(options) {
|
|
|
3418
4427
|
}
|
|
3419
4428
|
const statuses = json.response?.data?.statuses ?? [];
|
|
3420
4429
|
const errorStatuses = statuses.filter(
|
|
3421
|
-
(entry) =>
|
|
4430
|
+
(entry) => Boolean(
|
|
4431
|
+
entry && typeof entry === "object" && "error" in entry && typeof entry.error === "string"
|
|
4432
|
+
)
|
|
3422
4433
|
);
|
|
3423
4434
|
if (errorStatuses.length) {
|
|
3424
4435
|
const message = errorStatuses.map((entry) => entry.error).join(", ");
|
|
@@ -3472,10 +4483,11 @@ async function depositToHyperliquidBridge(options) {
|
|
|
3472
4483
|
}
|
|
3473
4484
|
async function withdrawFromHyperliquid(options) {
|
|
3474
4485
|
const { environment, amount, destination, wallet: wallet2 } = options;
|
|
3475
|
-
const
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
4486
|
+
const normalizedAmount = normalizePositiveDecimalString(
|
|
4487
|
+
amount,
|
|
4488
|
+
"Withdraw amount"
|
|
4489
|
+
);
|
|
4490
|
+
const parsedAmount = Number.parseFloat(normalizedAmount);
|
|
3479
4491
|
if (!wallet2.account || !wallet2.walletClient || !wallet2.publicClient) {
|
|
3480
4492
|
throw new Error(
|
|
3481
4493
|
"Wallet client and public client are required for withdraw."
|
|
@@ -3495,7 +4507,7 @@ async function withdrawFromHyperliquid(options) {
|
|
|
3495
4507
|
const message = {
|
|
3496
4508
|
hyperliquidChain,
|
|
3497
4509
|
destination: normalizedDestination,
|
|
3498
|
-
amount:
|
|
4510
|
+
amount: normalizedAmount,
|
|
3499
4511
|
time
|
|
3500
4512
|
};
|
|
3501
4513
|
const types = {
|
|
@@ -3520,7 +4532,7 @@ async function withdrawFromHyperliquid(options) {
|
|
|
3520
4532
|
signatureChainId,
|
|
3521
4533
|
hyperliquidChain,
|
|
3522
4534
|
destination: normalizedDestination,
|
|
3523
|
-
amount:
|
|
4535
|
+
amount: normalizedAmount,
|
|
3524
4536
|
time: nonce
|
|
3525
4537
|
},
|
|
3526
4538
|
nonce,
|
|
@@ -5767,6 +6779,29 @@ var SUPPORTED_EXTENSIONS = [
|
|
|
5767
6779
|
".mjs",
|
|
5768
6780
|
".cjs"
|
|
5769
6781
|
];
|
|
6782
|
+
var MIN_TEMPLATE_CONFIG_VERSION = 2;
|
|
6783
|
+
function normalizeTemplateConfigVersion(value) {
|
|
6784
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
6785
|
+
return value;
|
|
6786
|
+
}
|
|
6787
|
+
if (typeof value !== "string") {
|
|
6788
|
+
return null;
|
|
6789
|
+
}
|
|
6790
|
+
const trimmed = value.trim();
|
|
6791
|
+
if (!trimmed) {
|
|
6792
|
+
return null;
|
|
6793
|
+
}
|
|
6794
|
+
if (/^\d+(?:\.\d+)?$/.test(trimmed)) {
|
|
6795
|
+
const numeric = Number.parseFloat(trimmed);
|
|
6796
|
+
return Number.isFinite(numeric) ? numeric : null;
|
|
6797
|
+
}
|
|
6798
|
+
const majorMatch = /^v?(\d+)(?:\..*)?$/i.exec(trimmed);
|
|
6799
|
+
if (!majorMatch) {
|
|
6800
|
+
return null;
|
|
6801
|
+
}
|
|
6802
|
+
const major = Number.parseInt(majorMatch[1], 10);
|
|
6803
|
+
return Number.isFinite(major) ? major : null;
|
|
6804
|
+
}
|
|
5770
6805
|
async function validateCommand(options) {
|
|
5771
6806
|
console.log("\u{1F50D} Validating OpenTool metadata...");
|
|
5772
6807
|
try {
|
|
@@ -5918,9 +6953,15 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
5918
6953
|
}
|
|
5919
6954
|
const record = templateConfigRaw;
|
|
5920
6955
|
const version = record.version;
|
|
5921
|
-
|
|
6956
|
+
const normalizedTemplateConfigVersion = normalizeTemplateConfigVersion(version);
|
|
6957
|
+
if (normalizedTemplateConfigVersion === null) {
|
|
6958
|
+
throw new Error(
|
|
6959
|
+
`${file}: profile.templateConfig.version must be a numeric string or number.`
|
|
6960
|
+
);
|
|
6961
|
+
}
|
|
6962
|
+
if (normalizedTemplateConfigVersion < MIN_TEMPLATE_CONFIG_VERSION) {
|
|
5922
6963
|
throw new Error(
|
|
5923
|
-
`${file}: profile.templateConfig.version must be
|
|
6964
|
+
`${file}: profile.templateConfig.version must be >= ${MIN_TEMPLATE_CONFIG_VERSION}.`
|
|
5924
6965
|
);
|
|
5925
6966
|
}
|
|
5926
6967
|
const schema2 = record.schema;
|
|
@@ -6246,6 +7287,6 @@ function timestamp() {
|
|
|
6246
7287
|
return (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
|
|
6247
7288
|
}
|
|
6248
7289
|
|
|
6249
|
-
export { AIAbortError, AIError, AIFetchError, AIResponseError, DEFAULT_BASE_URL, DEFAULT_CHAIN, DEFAULT_FACILITATOR, DEFAULT_HYPERLIQUID_MARKET_SLIPPAGE_BPS, DEFAULT_MODEL, DEFAULT_TIMEOUT_MS, DEFAULT_TOKENS, HTTP_METHODS2 as HTTP_METHODS, HyperliquidApiError, HyperliquidBuilderApprovalError, HyperliquidExchangeClient, HyperliquidGuardError, HyperliquidInfoClient, HyperliquidTermsError, PAYMENT_HEADERS, POLYMARKET_CHAIN_ID, POLYMARKET_CLOB_AUTH_DOMAIN, POLYMARKET_CLOB_DOMAIN, POLYMARKET_ENDPOINTS, POLYMARKET_EXCHANGE_ADDRESSES, PolymarketApiError, PolymarketAuthError, PolymarketExchangeClient, PolymarketInfoClient, SUPPORTED_CURRENCIES, StoreError, WEBSEARCH_TOOL_DEFINITION, WEBSEARCH_TOOL_NAME, X402BrowserClient, X402Client, X402PaymentRequiredError, __hyperliquidInternals, approveHyperliquidBuilderFee, batchModifyHyperliquidOrders, buildHmacSignature, buildHyperliquidMarketIdentity, buildL1Headers, buildL2Headers, buildPolymarketOrderAmounts, buildSignedOrderPayload, cancelAllHyperliquidOrders, cancelAllPolymarketOrders, cancelHyperliquidOrders, cancelHyperliquidOrdersByCloid, cancelHyperliquidTwapOrder, cancelMarketPolymarketOrders, cancelPolymarketOrder, cancelPolymarketOrders, chains, computeHyperliquidMarketIocLimitPrice, createAIClient, createDevServer, createHyperliquidSubAccount, createMcpAdapter, createMonotonicNonceFactory, createPolymarketApiKey, createStdioServer, defineX402Payment, depositToHyperliquidBridge, derivePolymarketApiKey, ensureTextContent, executeTool, fetchHyperliquidAssetCtxs, fetchHyperliquidClearinghouseState, fetchHyperliquidFrontendOpenOrders, fetchHyperliquidHistoricalOrders, fetchHyperliquidMeta, fetchHyperliquidMetaAndAssetCtxs, fetchHyperliquidOpenOrders, fetchHyperliquidOrderStatus, fetchHyperliquidPreTransferCheck, fetchHyperliquidSpotAssetCtxs, fetchHyperliquidSpotClearinghouseState, fetchHyperliquidSpotMeta, fetchHyperliquidSpotMetaAndAssetCtxs, fetchHyperliquidUserFills, fetchHyperliquidUserFillsByTime, fetchHyperliquidUserRateLimit, fetchPolymarketMarket, fetchPolymarketMarkets, fetchPolymarketMidpoint, fetchPolymarketOrderbook, fetchPolymarketPrice, fetchPolymarketPriceHistory, flattenMessageContent, generateMetadata, generateMetadataCommand, generateText, getHyperliquidMaxBuilderFee, getModelConfig, getMyPerformance, getMyTools, getRpcUrl, getX402PaymentContext, isStreamingSupported, isToolCallingSupported, listModels, loadAndValidateTools, modifyHyperliquidOrder, normalizeModelName, normalizeNumberArrayish, normalizeStringArrayish, payX402, payX402WithWallet, placeHyperliquidOrder, placeHyperliquidTwapOrder, placePolymarketOrder, postAgentDigest, recordHyperliquidBuilderApproval, recordHyperliquidTermsAcceptance, registry, requireX402Payment, reserveHyperliquidRequestWeight, resolveConfig2 as resolveConfig, resolveExchangeAddress, resolveHyperliquidAbstractionFromMode, resolvePolymarketBaseUrl, resolveRuntimePath, resolveToolset, responseToToolResponse, retrieve, scheduleHyperliquidCancel, sendHyperliquidSpot, setHyperliquidAccountAbstractionMode, setHyperliquidDexAbstraction, setHyperliquidPortfolioMargin, store, streamText, tokens, transferHyperliquidSubAccount, updateHyperliquidIsolatedMargin, updateHyperliquidLeverage, validateCommand, wallet, walletToolkit, withX402Payment, withdrawFromHyperliquid };
|
|
7290
|
+
export { AIAbortError, AIError, AIFetchError, AIResponseError, DEFAULT_BASE_URL, DEFAULT_CHAIN, DEFAULT_FACILITATOR, DEFAULT_HYPERLIQUID_MARKET_SLIPPAGE_BPS, DEFAULT_MODEL, DEFAULT_TIMEOUT_MS, DEFAULT_TOKENS, HTTP_METHODS2 as HTTP_METHODS, HyperliquidApiError, HyperliquidBuilderApprovalError, HyperliquidExchangeClient, HyperliquidGuardError, HyperliquidInfoClient, HyperliquidTermsError, PAYMENT_HEADERS, POLYMARKET_CHAIN_ID, POLYMARKET_CLOB_AUTH_DOMAIN, POLYMARKET_CLOB_DOMAIN, POLYMARKET_ENDPOINTS, POLYMARKET_EXCHANGE_ADDRESSES, PolymarketApiError, PolymarketAuthError, PolymarketExchangeClient, PolymarketInfoClient, SUPPORTED_CURRENCIES, StoreError, WEBSEARCH_TOOL_DEFINITION, WEBSEARCH_TOOL_NAME, X402BrowserClient, X402Client, X402PaymentRequiredError, __hyperliquidInternals, __hyperliquidMarketDataInternals, approveHyperliquidBuilderFee, batchModifyHyperliquidOrders, buildHmacSignature, buildHyperliquidMarketIdentity, buildHyperliquidSpotUsdPriceMap, buildL1Headers, buildL2Headers, buildPolymarketOrderAmounts, buildSignedOrderPayload, cancelAllHyperliquidOrders, cancelAllPolymarketOrders, cancelHyperliquidOrders, cancelHyperliquidOrdersByCloid, cancelHyperliquidTwapOrder, cancelMarketPolymarketOrders, cancelPolymarketOrder, cancelPolymarketOrders, chains, computeHyperliquidMarketIocLimitPrice, createAIClient, createDevServer, createHyperliquidSubAccount, createMcpAdapter, createMonotonicNonceFactory, createPolymarketApiKey, createStdioServer, defineX402Payment, depositToHyperliquidBridge, derivePolymarketApiKey, ensureTextContent, executeTool, extractHyperliquidDex, extractHyperliquidOrderIds, fetchHyperliquidAllMids, fetchHyperliquidAssetCtxs, fetchHyperliquidClearinghouseState, fetchHyperliquidFrontendOpenOrders, fetchHyperliquidHistoricalOrders, fetchHyperliquidMeta, fetchHyperliquidMetaAndAssetCtxs, fetchHyperliquidOpenOrders, fetchHyperliquidOrderStatus, fetchHyperliquidPerpMarketInfo, fetchHyperliquidPreTransferCheck, fetchHyperliquidSizeDecimals, fetchHyperliquidSpotAccountValue, fetchHyperliquidSpotAssetCtxs, fetchHyperliquidSpotClearinghouseState, fetchHyperliquidSpotMarketInfo, fetchHyperliquidSpotMeta, fetchHyperliquidSpotMetaAndAssetCtxs, fetchHyperliquidSpotTickSize, fetchHyperliquidSpotUsdPriceMap, fetchHyperliquidTickSize, fetchHyperliquidUserFills, fetchHyperliquidUserFillsByTime, fetchHyperliquidUserRateLimit, fetchPolymarketMarket, fetchPolymarketMarkets, fetchPolymarketMidpoint, fetchPolymarketOrderbook, fetchPolymarketPrice, fetchPolymarketPriceHistory, flattenMessageContent, formatHyperliquidMarketablePrice, formatHyperliquidOrderSize, formatHyperliquidPrice, formatHyperliquidSize, generateMetadata, generateMetadataCommand, generateText, getHyperliquidMaxBuilderFee, getModelConfig, getMyPerformance, getMyTools, getRpcUrl, getX402PaymentContext, isHyperliquidSpotSymbol, isStreamingSupported, isToolCallingSupported, listModels, loadAndValidateTools, modifyHyperliquidOrder, normalizeHyperliquidBaseSymbol, normalizeHyperliquidMetaSymbol, normalizeModelName, normalizeNumberArrayish, normalizeSpotTokenName2 as normalizeSpotTokenName, normalizeStringArrayish, parseSpotPairSymbol, payX402, payX402WithWallet, placeHyperliquidOrder, placeHyperliquidTwapOrder, placePolymarketOrder, postAgentDigest, readHyperliquidAccountValue, readHyperliquidNumber, readHyperliquidPerpPosition, readHyperliquidPerpPositionSize, readHyperliquidSpotAccountValue, readHyperliquidSpotBalance, readHyperliquidSpotBalanceSize, recordHyperliquidBuilderApproval, recordHyperliquidTermsAcceptance, registry, requireX402Payment, reserveHyperliquidRequestWeight, resolveConfig2 as resolveConfig, resolveExchangeAddress, resolveHyperliquidAbstractionFromMode, resolveHyperliquidChain, resolveHyperliquidChainConfig, resolveHyperliquidErrorDetail, resolveHyperliquidOrderRef, resolveHyperliquidOrderSymbol, resolveHyperliquidPair, resolveHyperliquidRpcEnvVar, resolveHyperliquidStoreNetwork, resolveHyperliquidSymbol, resolvePolymarketBaseUrl, resolveRuntimePath, resolveSpotMidCandidates, resolveSpotTokenCandidates, resolveToolset, responseToToolResponse, retrieve, roundHyperliquidPriceToTick, scheduleHyperliquidCancel, sendHyperliquidSpot, setHyperliquidAccountAbstractionMode, setHyperliquidDexAbstraction, setHyperliquidPortfolioMargin, store, streamText, tokens, transferHyperliquidSubAccount, updateHyperliquidIsolatedMargin, updateHyperliquidLeverage, validateCommand, wallet, walletToolkit, withX402Payment, withdrawFromHyperliquid };
|
|
6250
7291
|
//# sourceMappingURL=index.js.map
|
|
6251
7292
|
//# sourceMappingURL=index.js.map
|