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,