opentool 0.8.22 → 0.8.23
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.
|
@@ -120,6 +120,7 @@ var BUILDER_CODE = {
|
|
|
120
120
|
fee: 100
|
|
121
121
|
};
|
|
122
122
|
var metaCache = /* @__PURE__ */ new Map();
|
|
123
|
+
var spotMetaCache = /* @__PURE__ */ new Map();
|
|
123
124
|
var perpDexsCache = /* @__PURE__ */ new Map();
|
|
124
125
|
var UNKNOWN_SYMBOL = "UNKNOWN";
|
|
125
126
|
var extractDexPrefix = (value) => {
|
|
@@ -142,6 +143,14 @@ var normalizeHyperliquidBase = (value) => {
|
|
|
142
143
|
if (!normalized || normalized === UNKNOWN_SYMBOL) return null;
|
|
143
144
|
return normalized;
|
|
144
145
|
};
|
|
146
|
+
var normalizeSpotTokenName = (value) => {
|
|
147
|
+
const raw = (value ?? "").trim().toUpperCase();
|
|
148
|
+
if (!raw) return "";
|
|
149
|
+
if (raw.endsWith("0") && raw.length > 1) {
|
|
150
|
+
return raw.slice(0, -1);
|
|
151
|
+
}
|
|
152
|
+
return raw;
|
|
153
|
+
};
|
|
145
154
|
var parseHyperliquidPair = (value) => {
|
|
146
155
|
if (!value) return null;
|
|
147
156
|
const trimmed = value.trim();
|
|
@@ -288,6 +297,29 @@ async function getUniverse(args) {
|
|
|
288
297
|
metaCache.set(cacheKey, { fetchedAt: Date.now(), universe: json.universe });
|
|
289
298
|
return json.universe;
|
|
290
299
|
}
|
|
300
|
+
async function getSpotMeta(args) {
|
|
301
|
+
const cacheKey = `${args.environment}:${args.baseUrl}`;
|
|
302
|
+
const cached = spotMetaCache.get(cacheKey);
|
|
303
|
+
if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
|
|
304
|
+
return { universe: cached.universe, tokens: cached.tokens };
|
|
305
|
+
}
|
|
306
|
+
const response = await args.fetcher(`${args.baseUrl}/info`, {
|
|
307
|
+
method: "POST",
|
|
308
|
+
headers: { "content-type": "application/json" },
|
|
309
|
+
body: JSON.stringify({ type: "spotMeta" })
|
|
310
|
+
});
|
|
311
|
+
const json = await response.json().catch(() => null);
|
|
312
|
+
if (!response.ok || !json?.universe) {
|
|
313
|
+
throw new HyperliquidApiError(
|
|
314
|
+
"Unable to load Hyperliquid spot metadata.",
|
|
315
|
+
json ?? { status: response.status }
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
const universe = json.universe ?? [];
|
|
319
|
+
const tokens = json.tokens ?? [];
|
|
320
|
+
spotMetaCache.set(cacheKey, { fetchedAt: Date.now(), universe, tokens });
|
|
321
|
+
return { universe, tokens };
|
|
322
|
+
}
|
|
291
323
|
function resolveAssetIndex(symbol, universe) {
|
|
292
324
|
const [raw] = symbol.split("-");
|
|
293
325
|
const target = raw.trim();
|
|
@@ -331,11 +363,57 @@ async function resolveDexIndex(args) {
|
|
|
331
363
|
}
|
|
332
364
|
return index;
|
|
333
365
|
}
|
|
366
|
+
function buildSpotTokenIndexMap(tokens) {
|
|
367
|
+
const map = /* @__PURE__ */ new Map();
|
|
368
|
+
for (const token of tokens) {
|
|
369
|
+
const name = normalizeSpotTokenName(token?.name);
|
|
370
|
+
const index = typeof token?.index === "number" && Number.isFinite(token.index) ? token.index : null;
|
|
371
|
+
if (!name || index == null) continue;
|
|
372
|
+
if (!map.has(name) || token?.isCanonical) {
|
|
373
|
+
map.set(name, index);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return map;
|
|
377
|
+
}
|
|
378
|
+
function resolveSpotTokenIndex(tokenMap, value) {
|
|
379
|
+
const normalized = normalizeSpotTokenName(value);
|
|
380
|
+
if (!normalized) return null;
|
|
381
|
+
const direct = tokenMap.get(normalized);
|
|
382
|
+
if (direct != null) return direct;
|
|
383
|
+
if (!normalized.startsWith("U")) {
|
|
384
|
+
const prefixed = tokenMap.get(`U${normalized}`);
|
|
385
|
+
if (prefixed != null) return prefixed;
|
|
386
|
+
}
|
|
387
|
+
return null;
|
|
388
|
+
}
|
|
389
|
+
function resolveSpotMarketIndex(args) {
|
|
390
|
+
for (let i = 0; i < args.universe.length; i += 1) {
|
|
391
|
+
const entry = args.universe[i];
|
|
392
|
+
const tokens = Array.isArray(entry?.tokens) ? entry.tokens : null;
|
|
393
|
+
const baseToken = tokens?.[0] ?? entry?.baseToken ?? null;
|
|
394
|
+
const quoteToken = tokens?.[1] ?? entry?.quoteToken ?? null;
|
|
395
|
+
if (baseToken === args.baseToken && quoteToken === args.quoteToken) {
|
|
396
|
+
if (typeof entry?.index === "number" && Number.isFinite(entry.index)) {
|
|
397
|
+
return entry.index;
|
|
398
|
+
}
|
|
399
|
+
return i;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
334
404
|
async function resolveHyperliquidAssetIndex(args) {
|
|
335
405
|
const trimmed = args.symbol.trim();
|
|
336
406
|
if (!trimmed) {
|
|
337
407
|
throw new Error("Hyperliquid symbol must be a non-empty string.");
|
|
338
408
|
}
|
|
409
|
+
if (trimmed.startsWith("@")) {
|
|
410
|
+
const rawIndex = trimmed.slice(1).trim();
|
|
411
|
+
const index = Number(rawIndex);
|
|
412
|
+
if (!Number.isFinite(index)) {
|
|
413
|
+
throw new Error(`Hyperliquid spot market index is invalid: ${trimmed}`);
|
|
414
|
+
}
|
|
415
|
+
return 1e4 + index;
|
|
416
|
+
}
|
|
339
417
|
const separator = trimmed.indexOf(":");
|
|
340
418
|
if (separator > 0) {
|
|
341
419
|
const dex = trimmed.slice(0, separator).trim();
|
|
@@ -362,6 +440,29 @@ async function resolveHyperliquidAssetIndex(args) {
|
|
|
362
440
|
}
|
|
363
441
|
return 1e5 + dexIndex * 1e4 + assetIndex;
|
|
364
442
|
}
|
|
443
|
+
const pair = parseHyperliquidPair(trimmed);
|
|
444
|
+
if (pair) {
|
|
445
|
+
const { universe: universe2, tokens } = await getSpotMeta({
|
|
446
|
+
baseUrl: args.baseUrl,
|
|
447
|
+
environment: args.environment,
|
|
448
|
+
fetcher: args.fetcher
|
|
449
|
+
});
|
|
450
|
+
const tokenMap = buildSpotTokenIndexMap(tokens);
|
|
451
|
+
const baseToken = resolveSpotTokenIndex(tokenMap, pair.base);
|
|
452
|
+
const quoteToken = resolveSpotTokenIndex(tokenMap, pair.quote);
|
|
453
|
+
if (baseToken == null || quoteToken == null) {
|
|
454
|
+
throw new Error(`Unknown Hyperliquid spot symbol: ${trimmed}`);
|
|
455
|
+
}
|
|
456
|
+
const marketIndex = resolveSpotMarketIndex({
|
|
457
|
+
universe: universe2,
|
|
458
|
+
baseToken,
|
|
459
|
+
quoteToken
|
|
460
|
+
});
|
|
461
|
+
if (marketIndex == null) {
|
|
462
|
+
throw new Error(`Unknown Hyperliquid spot symbol: ${trimmed}`);
|
|
463
|
+
}
|
|
464
|
+
return 1e4 + marketIndex;
|
|
465
|
+
}
|
|
365
466
|
const universe = await getUniverse({
|
|
366
467
|
baseUrl: args.baseUrl,
|
|
367
468
|
environment: args.environment,
|