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.
package/dist/index.js CHANGED
@@ -1843,6 +1843,7 @@ var BUILDER_CODE = {
1843
1843
  fee: 100
1844
1844
  };
1845
1845
  var metaCache = /* @__PURE__ */ new Map();
1846
+ var spotMetaCache = /* @__PURE__ */ new Map();
1846
1847
  var perpDexsCache = /* @__PURE__ */ new Map();
1847
1848
  var UNKNOWN_SYMBOL = "UNKNOWN";
1848
1849
  var extractDexPrefix = (value) => {
@@ -1865,6 +1866,14 @@ var normalizeHyperliquidBase = (value) => {
1865
1866
  if (!normalized || normalized === UNKNOWN_SYMBOL) return null;
1866
1867
  return normalized;
1867
1868
  };
1869
+ var normalizeSpotTokenName = (value) => {
1870
+ const raw = (value ?? "").trim().toUpperCase();
1871
+ if (!raw) return "";
1872
+ if (raw.endsWith("0") && raw.length > 1) {
1873
+ return raw.slice(0, -1);
1874
+ }
1875
+ return raw;
1876
+ };
1868
1877
  var parseHyperliquidPair = (value) => {
1869
1878
  if (!value) return null;
1870
1879
  const trimmed = value.trim();
@@ -2011,6 +2020,29 @@ async function getUniverse(args) {
2011
2020
  metaCache.set(cacheKey, { fetchedAt: Date.now(), universe: json.universe });
2012
2021
  return json.universe;
2013
2022
  }
2023
+ async function getSpotMeta(args) {
2024
+ const cacheKey = `${args.environment}:${args.baseUrl}`;
2025
+ const cached = spotMetaCache.get(cacheKey);
2026
+ if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
2027
+ return { universe: cached.universe, tokens: cached.tokens };
2028
+ }
2029
+ const response = await args.fetcher(`${args.baseUrl}/info`, {
2030
+ method: "POST",
2031
+ headers: { "content-type": "application/json" },
2032
+ body: JSON.stringify({ type: "spotMeta" })
2033
+ });
2034
+ const json = await response.json().catch(() => null);
2035
+ if (!response.ok || !json?.universe) {
2036
+ throw new HyperliquidApiError(
2037
+ "Unable to load Hyperliquid spot metadata.",
2038
+ json ?? { status: response.status }
2039
+ );
2040
+ }
2041
+ const universe = json.universe ?? [];
2042
+ const tokens2 = json.tokens ?? [];
2043
+ spotMetaCache.set(cacheKey, { fetchedAt: Date.now(), universe, tokens: tokens2 });
2044
+ return { universe, tokens: tokens2 };
2045
+ }
2014
2046
  function resolveAssetIndex(symbol, universe) {
2015
2047
  const [raw] = symbol.split("-");
2016
2048
  const target = raw.trim();
@@ -2054,11 +2086,57 @@ async function resolveDexIndex(args) {
2054
2086
  }
2055
2087
  return index;
2056
2088
  }
2089
+ function buildSpotTokenIndexMap(tokens2) {
2090
+ const map = /* @__PURE__ */ new Map();
2091
+ for (const token2 of tokens2) {
2092
+ const name = normalizeSpotTokenName(token2?.name);
2093
+ const index = typeof token2?.index === "number" && Number.isFinite(token2.index) ? token2.index : null;
2094
+ if (!name || index == null) continue;
2095
+ if (!map.has(name) || token2?.isCanonical) {
2096
+ map.set(name, index);
2097
+ }
2098
+ }
2099
+ return map;
2100
+ }
2101
+ function resolveSpotTokenIndex(tokenMap, value) {
2102
+ const normalized = normalizeSpotTokenName(value);
2103
+ if (!normalized) return null;
2104
+ const direct = tokenMap.get(normalized);
2105
+ if (direct != null) return direct;
2106
+ if (!normalized.startsWith("U")) {
2107
+ const prefixed = tokenMap.get(`U${normalized}`);
2108
+ if (prefixed != null) return prefixed;
2109
+ }
2110
+ return null;
2111
+ }
2112
+ function resolveSpotMarketIndex(args) {
2113
+ for (let i = 0; i < args.universe.length; i += 1) {
2114
+ const entry = args.universe[i];
2115
+ const tokens2 = Array.isArray(entry?.tokens) ? entry.tokens : null;
2116
+ const baseToken = tokens2?.[0] ?? entry?.baseToken ?? null;
2117
+ const quoteToken = tokens2?.[1] ?? entry?.quoteToken ?? null;
2118
+ if (baseToken === args.baseToken && quoteToken === args.quoteToken) {
2119
+ if (typeof entry?.index === "number" && Number.isFinite(entry.index)) {
2120
+ return entry.index;
2121
+ }
2122
+ return i;
2123
+ }
2124
+ }
2125
+ return null;
2126
+ }
2057
2127
  async function resolveHyperliquidAssetIndex(args) {
2058
2128
  const trimmed = args.symbol.trim();
2059
2129
  if (!trimmed) {
2060
2130
  throw new Error("Hyperliquid symbol must be a non-empty string.");
2061
2131
  }
2132
+ if (trimmed.startsWith("@")) {
2133
+ const rawIndex = trimmed.slice(1).trim();
2134
+ const index = Number(rawIndex);
2135
+ if (!Number.isFinite(index)) {
2136
+ throw new Error(`Hyperliquid spot market index is invalid: ${trimmed}`);
2137
+ }
2138
+ return 1e4 + index;
2139
+ }
2062
2140
  const separator = trimmed.indexOf(":");
2063
2141
  if (separator > 0) {
2064
2142
  const dex = trimmed.slice(0, separator).trim();
@@ -2085,6 +2163,29 @@ async function resolveHyperliquidAssetIndex(args) {
2085
2163
  }
2086
2164
  return 1e5 + dexIndex * 1e4 + assetIndex;
2087
2165
  }
2166
+ const pair = parseHyperliquidPair(trimmed);
2167
+ if (pair) {
2168
+ const { universe: universe2, tokens: tokens2 } = await getSpotMeta({
2169
+ baseUrl: args.baseUrl,
2170
+ environment: args.environment,
2171
+ fetcher: args.fetcher
2172
+ });
2173
+ const tokenMap = buildSpotTokenIndexMap(tokens2);
2174
+ const baseToken = resolveSpotTokenIndex(tokenMap, pair.base);
2175
+ const quoteToken = resolveSpotTokenIndex(tokenMap, pair.quote);
2176
+ if (baseToken == null || quoteToken == null) {
2177
+ throw new Error(`Unknown Hyperliquid spot symbol: ${trimmed}`);
2178
+ }
2179
+ const marketIndex = resolveSpotMarketIndex({
2180
+ universe: universe2,
2181
+ baseToken,
2182
+ quoteToken
2183
+ });
2184
+ if (marketIndex == null) {
2185
+ throw new Error(`Unknown Hyperliquid spot symbol: ${trimmed}`);
2186
+ }
2187
+ return 1e4 + marketIndex;
2188
+ }
2088
2189
  const universe = await getUniverse({
2089
2190
  baseUrl: args.baseUrl,
2090
2191
  environment: args.environment,