@sherwoodagent/cli 0.42.0 → 0.51.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.
Files changed (68) hide show
  1. package/dist/{addresses-DCQMJJFI.js → addresses-DOWLGXGE.js} +4 -4
  2. package/dist/{agent-5YEJ6W6W.js → agent-ZPAZTJG3.js} +2923 -2023
  3. package/dist/agent-ZPAZTJG3.js.map +1 -0
  4. package/dist/autoresearch-IA7HGSNW.js +267 -0
  5. package/dist/autoresearch-IA7HGSNW.js.map +1 -0
  6. package/dist/{chat-UWJ6JBFE.js → chat-MRTPUZ3X.js} +8 -8
  7. package/dist/{chunk-FOOZC4AM.js → chunk-2LRC7I33.js} +2 -2
  8. package/dist/{chunk-4EHI4SKM.js → chunk-2W4KGGPU.js} +11 -1
  9. package/dist/chunk-2W4KGGPU.js.map +1 -0
  10. package/dist/chunk-7HJXZ4NM.js +189 -0
  11. package/dist/chunk-7HJXZ4NM.js.map +1 -0
  12. package/dist/{chunk-JNDEZFXW.js → chunk-E6LH2FJ6.js} +4 -4
  13. package/dist/{chunk-XAUMJZU2.js → chunk-FWC57PT7.js} +2 -2
  14. package/dist/{chunk-4OAZ7TP5.js → chunk-IS2CLLUT.js} +4 -4
  15. package/dist/{chunk-T2IA6CCW.js → chunk-KJ35EF7N.js} +4 -4
  16. package/dist/{chunk-GMVDHSCF.js → chunk-OHQOTSFG.js} +39 -3
  17. package/dist/chunk-OHQOTSFG.js.map +1 -0
  18. package/dist/chunk-OMW47WOO.js +700 -0
  19. package/dist/chunk-OMW47WOO.js.map +1 -0
  20. package/dist/{chunk-5Q3VT6NQ.js → chunk-R7X33D2S.js} +5 -5
  21. package/dist/{chunk-6U3A6ZJ2.js → chunk-WMZEOR5W.js} +6 -127
  22. package/dist/chunk-WMZEOR5W.js.map +1 -0
  23. package/dist/{chunk-SWKHSKDH.js → chunk-XDBRKW7I.js} +3 -3
  24. package/dist/chunk-YTYXBX7B.js +495 -0
  25. package/dist/chunk-YTYXBX7B.js.map +1 -0
  26. package/dist/{client-DRVUILER.js → client-UHHCB6EZ.js} +4 -4
  27. package/dist/{config-YRERDZSL.js → config-REASKDIK.js} +6 -2
  28. package/dist/{eas-KBU2BAOD.js → eas-PEEWGSAO.js} +6 -6
  29. package/dist/{governor-KH7RNH2E.js → governor-MG5VVSU4.js} +6 -6
  30. package/dist/index.js +1424 -270
  31. package/dist/index.js.map +1 -1
  32. package/dist/{network-3HB46JMQ.js → network-3ZU7UBDU.js} +3 -3
  33. package/dist/{price-TTQWI672.js → price-WCCXWPDM.js} +5 -5
  34. package/dist/{research-J3HYU3N6.js → research-QBKISW2M.js} +9 -9
  35. package/dist/research-YJWSQS2A.js +14 -0
  36. package/dist/serve-6MYBOAX6.js +222 -0
  37. package/dist/serve-6MYBOAX6.js.map +1 -0
  38. package/dist/{session-NUPHC6ZN.js → session-FPCPCVQX.js} +10 -10
  39. package/dist/summary-formatter-JIGWN4QS.js +180 -0
  40. package/dist/summary-formatter-JIGWN4QS.js.map +1 -0
  41. package/dist/{trade-VGECC4QZ.js → trade-NO6CNWCA.js} +19 -17
  42. package/dist/{trade-VGECC4QZ.js.map → trade-NO6CNWCA.js.map} +1 -1
  43. package/dist/{xmtp-JO7W6RFK.js → xmtp-ACB2W573.js} +6 -6
  44. package/package.json +5 -2
  45. package/dist/agent-5YEJ6W6W.js.map +0 -1
  46. package/dist/chunk-4EHI4SKM.js.map +0 -1
  47. package/dist/chunk-6U3A6ZJ2.js.map +0 -1
  48. package/dist/chunk-GMVDHSCF.js.map +0 -1
  49. package/dist/research-NR4VC5LN.js +0 -14
  50. /package/dist/{addresses-DCQMJJFI.js.map → addresses-DOWLGXGE.js.map} +0 -0
  51. /package/dist/{chat-UWJ6JBFE.js.map → chat-MRTPUZ3X.js.map} +0 -0
  52. /package/dist/{chunk-FOOZC4AM.js.map → chunk-2LRC7I33.js.map} +0 -0
  53. /package/dist/{chunk-JNDEZFXW.js.map → chunk-E6LH2FJ6.js.map} +0 -0
  54. /package/dist/{chunk-XAUMJZU2.js.map → chunk-FWC57PT7.js.map} +0 -0
  55. /package/dist/{chunk-4OAZ7TP5.js.map → chunk-IS2CLLUT.js.map} +0 -0
  56. /package/dist/{chunk-T2IA6CCW.js.map → chunk-KJ35EF7N.js.map} +0 -0
  57. /package/dist/{chunk-5Q3VT6NQ.js.map → chunk-R7X33D2S.js.map} +0 -0
  58. /package/dist/{chunk-SWKHSKDH.js.map → chunk-XDBRKW7I.js.map} +0 -0
  59. /package/dist/{client-DRVUILER.js.map → client-UHHCB6EZ.js.map} +0 -0
  60. /package/dist/{config-YRERDZSL.js.map → config-REASKDIK.js.map} +0 -0
  61. /package/dist/{eas-KBU2BAOD.js.map → eas-PEEWGSAO.js.map} +0 -0
  62. /package/dist/{governor-KH7RNH2E.js.map → governor-MG5VVSU4.js.map} +0 -0
  63. /package/dist/{network-3HB46JMQ.js.map → network-3ZU7UBDU.js.map} +0 -0
  64. /package/dist/{price-TTQWI672.js.map → price-WCCXWPDM.js.map} +0 -0
  65. /package/dist/{research-J3HYU3N6.js.map → research-QBKISW2M.js.map} +0 -0
  66. /package/dist/{research-NR4VC5LN.js.map → research-YJWSQS2A.js.map} +0 -0
  67. /package/dist/{session-NUPHC6ZN.js.map → session-FPCPCVQX.js.map} +0 -0
  68. /package/dist/{xmtp-JO7W6RFK.js.map → xmtp-ACB2W573.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/agent/technical.ts","../src/providers/data/hyperliquid.ts","../src/lib/hyperliquid-executor.ts"],"sourcesContent":["/**\n * Technical analysis module — pure calculation functions.\n * All functions use standard financial formulas.\n */\n\nexport interface Candle {\n timestamp: number;\n open: number;\n high: number;\n low: number;\n close: number;\n volume: number;\n}\n\nexport interface TechnicalSignals {\n rsi: number;\n macd: { value: number; signal: number; histogram: number };\n bb: { upper: number; middle: number; lower: number; width: number; squeeze: boolean };\n ema: { ema8: number; ema21: number; ema50: number; ema200: number };\n atr: number;\n vwap: number;\n volume: { current: number; avg20: number; ratio: number };\n}\n\n// ── Simple Moving Average ──\n\nexport function calculateSMA(values: number[], period: number): number[] {\n if (values.length === 0) return [];\n\n const result: number[] = [];\n for (let i = 0; i < values.length; i++) {\n if (i < period - 1) {\n result.push(NaN);\n } else {\n let sum = 0;\n for (let j = i - period + 1; j <= i; j++) {\n sum += values[j]!;\n }\n result.push(sum / period);\n }\n }\n return result;\n}\n\n// ── Exponential Moving Average ──\n\nexport function calculateEMA(values: number[], period: number): number[] {\n if (values.length === 0) return [];\n\n const result: number[] = [];\n const k = 2 / (period + 1);\n\n for (let i = 0; i < values.length; i++) {\n if (i < period - 1) {\n result.push(NaN);\n } else if (i === period - 1) {\n // Seed with SMA of first `period` valid values\n let sum = 0;\n let count = 0;\n for (let j = 0; j < period; j++) {\n if (!isNaN(values[j]!)) {\n sum += values[j]!;\n count++;\n }\n }\n if (count > 0) {\n result.push(sum / count);\n } else {\n result.push(NaN);\n }\n } else {\n const prev = result[i - 1]!;\n const current = values[i]!;\n if (!isNaN(current) && !isNaN(prev)) {\n result.push(current * k + prev * (1 - k));\n } else {\n result.push(NaN);\n }\n }\n }\n return result;\n}\n\n// ── RSI (Relative Strength Index) ──\n\nexport function calculateRSI(candles: Candle[], period: number = 14): number[] {\n if (candles.length < 2) return [];\n\n const closes = candles.map((c) => c.close);\n const result: number[] = [];\n\n // Calculate price changes\n const changes: number[] = [];\n for (let i = 0; i < closes.length; i++) {\n if (i === 0) {\n changes.push(0);\n } else {\n changes.push(closes[i]! - closes[i - 1]!);\n }\n }\n\n let avgGain = 0;\n let avgLoss = 0;\n\n for (let i = 0; i < closes.length; i++) {\n if (i < period) {\n result.push(NaN);\n continue;\n }\n\n if (i === period) {\n // Sum gains and losses for changes[1..period]\n let sumGain = 0;\n let sumLoss = 0;\n for (let j = 1; j <= period; j++) {\n const change = changes[j]!;\n sumGain += Math.max(change, 0);\n sumLoss += Math.max(-change, 0);\n }\n avgGain = sumGain / period;\n avgLoss = sumLoss / period;\n } else {\n // Use Wilder's smoothing (exponential smoothing with alpha = 1/period)\n const change = changes[i]!;\n const alpha = 1 / period;\n avgGain = (1 - alpha) * avgGain + alpha * Math.max(change, 0);\n avgLoss = (1 - alpha) * avgLoss + alpha * Math.max(-change, 0);\n }\n\n if (avgLoss === 0) {\n result.push(100);\n } else {\n const rs = avgGain / avgLoss;\n result.push(100 - 100 / (1 + rs));\n }\n }\n\n return result;\n}\n\n// ── MACD ──\n\nexport function calculateMACD(\n candles: Candle[],\n fast: number = 12,\n slow: number = 26,\n signalPeriod: number = 9,\n): { macd: number[]; signal: number[]; histogram: number[] } {\n const closes = candles.map((c) => c.close);\n const emaFast = calculateEMA(closes, fast);\n const emaSlow = calculateEMA(closes, slow);\n\n const macdLine: number[] = [];\n for (let i = 0; i < closes.length; i++) {\n if (isNaN(emaFast[i]!) || isNaN(emaSlow[i]!)) {\n macdLine.push(NaN);\n } else {\n macdLine.push(emaFast[i]! - emaSlow[i]!);\n }\n }\n\n // Signal line = EMA of MACD line\n // Calculate EMA directly on the MACD line, which will handle NaN values internally\n const signalLine = calculateEMA(macdLine, signalPeriod);\n\n const histogram: number[] = [];\n for (let i = 0; i < macdLine.length; i++) {\n if (isNaN(macdLine[i]!) || isNaN(signalLine[i]!)) {\n histogram.push(NaN);\n } else {\n histogram.push(macdLine[i]! - signalLine[i]!);\n }\n }\n\n return { macd: macdLine, signal: signalLine, histogram };\n}\n\n// ── Bollinger Bands ──\n\nexport function calculateBollingerBands(\n candles: Candle[],\n period: number = 20,\n stdDevMult: number = 2.0,\n): { upper: number[]; middle: number[]; lower: number[]; width: number[] } {\n if (candles.length === 0) {\n return { upper: [], middle: [], lower: [], width: [] };\n }\n\n const closes = candles.map((c) => c.close);\n const middle = calculateSMA(closes, period);\n\n const upper: number[] = [];\n const lower: number[] = [];\n const width: number[] = [];\n\n for (let i = 0; i < closes.length; i++) {\n if (isNaN(middle[i]!)) {\n upper.push(NaN);\n lower.push(NaN);\n width.push(NaN);\n } else {\n let sumSq = 0;\n for (let j = i - period + 1; j <= i; j++) {\n sumSq += (closes[j]! - middle[i]!) ** 2;\n }\n const sd = Math.sqrt(sumSq / period);\n upper.push(middle[i]! + stdDevMult * sd);\n lower.push(middle[i]! - stdDevMult * sd);\n width.push(middle[i]! !== 0 ? (stdDevMult * 2 * sd) / middle[i]! : 0);\n }\n }\n\n return { upper, middle, lower, width };\n}\n\n// ── Average True Range ──\n\nexport function calculateATR(candles: Candle[], period: number = 14): number[] {\n if (candles.length === 0) return [];\n\n const trueRanges: number[] = [];\n for (let i = 0; i < candles.length; i++) {\n const c = candles[i]!;\n if (i === 0) {\n trueRanges.push(c.high - c.low);\n } else {\n const prev = candles[i - 1]!;\n const tr = Math.max(c.high - c.low, Math.abs(c.high - prev.close), Math.abs(c.low - prev.close));\n trueRanges.push(tr);\n }\n }\n\n // ATR = smoothed average of true ranges (Wilder's smoothing)\n const result: number[] = [];\n for (let i = 0; i < trueRanges.length; i++) {\n if (i < period - 1) {\n result.push(NaN);\n } else if (i === period - 1) {\n let sum = 0;\n for (let j = 0; j < period; j++) sum += trueRanges[j]!;\n result.push(sum / period);\n } else {\n result.push((result[i - 1]! * (period - 1) + trueRanges[i]!) / period);\n }\n }\n return result;\n}\n\n// ── VWAP (Volume Weighted Average Price) ──\n\nexport function calculateVWAP(candles: Candle[]): number[] {\n const result: number[] = [];\n let cumulativeTPV = 0;\n let cumulativeVolume = 0;\n\n for (const c of candles) {\n const typicalPrice = (c.high + c.low + c.close) / 3;\n cumulativeTPV += typicalPrice * c.volume;\n cumulativeVolume += c.volume;\n result.push(cumulativeVolume > 0 ? cumulativeTPV / cumulativeVolume : typicalPrice);\n }\n return result;\n}\n\n// ── Bollinger Band Squeeze Detection ──\n\nexport function detectBBSqueeze(candles: Candle[]): boolean {\n const bb = calculateBollingerBands(candles, 20, 2.0);\n const validWidths = bb.width.filter((w) => !isNaN(w));\n if (validWidths.length < 20) return false;\n\n const current = validWidths[validWidths.length - 1]!;\n const recent20 = validWidths.slice(-20);\n const minWidth = Math.min(...recent20);\n return current <= minWidth * 1.01; // within 1% of 20-period low\n}\n\n// ── Get Latest Signals (all indicators at current candle) ──\n\nexport function getLatestSignals(candles: Candle[]): TechnicalSignals {\n if (candles.length < 2) {\n throw new Error(\"Need at least 2 candles for technical analysis\");\n }\n\n const last = (arr: number[]): number => {\n for (let i = arr.length - 1; i >= 0; i--) {\n if (!isNaN(arr[i]!)) return arr[i]!;\n }\n return NaN;\n };\n\n // RSI(8) outperforms RSI(14) on hourly crypto — Nunchi autoresearch finding:\n // +4.9 Sharpe from this single change across 103 experiments. Hourly crypto\n // needs faster indicators than the traditional 14-period standard.\n const rsiArr = calculateRSI(candles, 8);\n const macdResult = calculateMACD(candles, 12, 26, 9);\n const bbResult = calculateBollingerBands(candles, 20, 2.0);\n const closes = candles.map((c) => c.close);\n const ema8 = calculateEMA(closes, 8);\n const ema21 = calculateEMA(closes, 21);\n const ema50 = calculateEMA(closes, 50);\n const ema200 = calculateEMA(closes, 200);\n const atrArr = calculateATR(candles, 14);\n const vwapArr = calculateVWAP(candles);\n\n // Volume stats\n const volumes = candles.map((c) => c.volume);\n const currentVol = volumes[volumes.length - 1] ?? 0;\n const recent20Vol = volumes.slice(-20);\n const avg20Vol = recent20Vol.length > 0 ? recent20Vol.reduce((a, b) => a + b, 0) / recent20Vol.length : 0;\n\n return {\n rsi: last(rsiArr),\n macd: {\n value: last(macdResult.macd),\n signal: last(macdResult.signal),\n histogram: last(macdResult.histogram),\n },\n bb: {\n upper: last(bbResult.upper),\n middle: last(bbResult.middle),\n lower: last(bbResult.lower),\n width: last(bbResult.width),\n squeeze: detectBBSqueeze(candles),\n },\n ema: {\n ema8: last(ema8),\n ema21: last(ema21),\n ema50: last(ema50),\n ema200: last(ema200),\n },\n atr: last(atrArr),\n vwap: last(vwapArr),\n volume: {\n current: currentVol,\n avg20: avg20Vol,\n ratio: avg20Vol > 0 ? currentVol / avg20Vol : 0,\n },\n };\n}\n","/**\n * Hyperliquid data provider — fetches native exchange data from Hyperliquid's free REST API.\n * Provides funding rates, open interest, order book, and trade flow data.\n * Base URL: https://api.hyperliquid.xyz/info (POST requests, JSON body)\n * Rate limit: reasonable usage, cached for 2 minutes.\n */\n\nimport { mkdir, readFile, writeFile, rename } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\nconst HYPERLIQUID_BASE = 'https://api.hyperliquid.xyz/info';\n\n/**\n * Parse a numeric value from the Hyperliquid API safely.\n * Returns `null` if the input is undefined, empty, or would parse to a non-finite\n * value (NaN / Infinity). This prevents silent NaN propagation into scoring,\n * which would otherwise corrupt `NaN * weight = NaN` across the decision stack.\n */\nexport function safeNumber(x: string | number | undefined | null): number | null {\n if (x === undefined || x === null) return null;\n const n = typeof x === 'number' ? x : parseFloat(x);\n return Number.isFinite(n) ? n : null;\n}\n\n/** Key: coin symbol (e.g. \"BTC\"). Value: last-seen OI + when we saw it. */\ninterface OiCacheEntry {\n openInterest: number;\n timestamp: number;\n}\n\n/** Stale OI entries (> this many ms old) are treated as absent. */\nconst OI_STALE_MS = 30 * 60 * 1000; // 30 minutes\n\n// Map CoinGecko token IDs to Hyperliquid coin names\nconst TOKEN_TO_COIN: Record<string, string> = {\n bitcoin: 'BTC',\n ethereum: 'ETH',\n solana: 'SOL',\n arbitrum: 'ARB',\n chainlink: 'LINK',\n aave: 'AAVE',\n uniswap: 'UNI',\n dogecoin: 'DOGE',\n avalanche: 'AVAX',\n 'avalanche-2': 'AVAX',\n near: 'NEAR',\n sui: 'SUI',\n aptos: 'APT',\n injective: 'INJ',\n pendle: 'PENDLE',\n pepe: 'PEPE',\n polygon: 'MATIC',\n optimism: 'OP',\n litecoin: 'LTC',\n cosmos: 'ATOM',\n filecoin: 'FIL',\n maker: 'MKR',\n cardano: 'ADA',\n polkadot: 'DOT',\n render: 'RENDER',\n jupiter: 'JUP',\n // Extended for full agent watchlist — all HL perps\n hyperliquid: 'HYPE',\n ethena: 'ENA',\n zcash: 'ZEC',\n ripple: 'XRP',\n bittensor: 'TAO',\n fartcoin: 'FARTCOIN',\n binancecoin: 'BNB',\n blur: 'BLUR',\n 'worldcoin-wld': 'WLD',\n 'pudgy-penguins': 'PENGU',\n 'fetch-ai': 'FET',\n};\n\nexport interface HyperliquidData {\n fundingRate: number; // current hourly funding rate (Hyperliquid funds every hour)\n openInterest: number; // USD value\n oiChangePct: number; // OI change since last fetch (percentage, NOT 24h)\n volume24h: number; // 24h notional volume\n markPrice: number;\n oraclePrice: number;\n prevDayPrice: number;\n orderBookImbalance: number; // (bid_depth - ask_depth) / (bid_depth + ask_depth) for top 10 levels\n largeTradesBias: number; // net direction of trades > $50K in last hour (-1 to +1)\n}\n\ninterface MetaAndAssetCtxs {\n universe: Array<{\n name: string;\n szDecimals: number;\n }>;\n}\n\ninterface AssetCtx {\n funding: string;\n openInterest: string;\n dayNtlVlm: string;\n markPx: string;\n oraclePx: string;\n prevDayPx: string;\n}\n\ninterface L2BookLevel {\n px: string;\n sz: string;\n n: number;\n}\n\ninterface L2Book {\n levels: [L2BookLevel[], L2BookLevel[]]; // [bids, asks]\n}\n\ninterface RecentTrade {\n coin: string;\n side: string;\n px: string;\n sz: string;\n time: number;\n hash: string;\n}\n\nexport class HyperliquidProvider {\n private cacheDir: string;\n private cacheTTL = 2 * 60 * 1000; // 2 minutes\n private oiCache = new Map<string, OiCacheEntry>(); // persisted; see loadOiCache\n private oiCacheFile: string;\n private oiCacheLoaded = false;\n private oiCacheLoadPromise: Promise<void> | null = null;\n private oiCacheSeq = 0; // per-process monotonically-increasing tmp suffix\n\n constructor() {\n this.cacheDir = join(homedir(), '.sherwood', 'agent', 'cache');\n this.oiCacheFile = join(this.cacheDir, 'hl-oi.json');\n // Kick off the load eagerly so the first getHyperliquidData call finds it\n // populated. Consumers can also await ensureOiCacheLoaded() directly.\n this.oiCacheLoadPromise = this.loadOiCache();\n }\n\n /** Load the OI cache from disk. Called once at construction. Never throws. */\n private async loadOiCache(): Promise<void> {\n try {\n const raw = await readFile(this.oiCacheFile, 'utf-8');\n const parsed = JSON.parse(raw) as Record<string, OiCacheEntry>;\n if (parsed && typeof parsed === 'object') {\n for (const [coin, entry] of Object.entries(parsed)) {\n if (\n entry\n && Number.isFinite(entry.openInterest)\n && Number.isFinite(entry.timestamp)\n ) {\n this.oiCache.set(coin, entry);\n }\n }\n }\n } catch {\n // No file, corrupt JSON, or permission error — start with an empty cache.\n } finally {\n this.oiCacheLoaded = true;\n }\n }\n\n private async ensureOiCacheLoaded(): Promise<void> {\n if (this.oiCacheLoaded) return;\n if (this.oiCacheLoadPromise) await this.oiCacheLoadPromise;\n }\n\n /**\n * Persist the OI cache to disk using an atomic tmp-rename write.\n * Fire-and-forget: callers do NOT await this. Errors are logged as warnings\n * so a slow or full disk never blocks the signal hot path.\n */\n private persistOiCache(): void {\n const snapshot: Record<string, OiCacheEntry> = {};\n for (const [coin, entry] of this.oiCache.entries()) {\n snapshot[coin] = entry;\n }\n // Unique per-process tmp suffix avoids a rename-race between back-to-back\n // persist() calls (writeFile of the second collides with rename of the first).\n const tmp = `${this.oiCacheFile}.tmp.${process.pid}.${++this.oiCacheSeq}`;\n void (async () => {\n try {\n await mkdir(this.cacheDir, { recursive: true });\n await writeFile(tmp, JSON.stringify(snapshot), 'utf-8');\n await rename(tmp, this.oiCacheFile);\n } catch (err) {\n console.warn(`[hyperliquid] oi-cache persist failed: ${(err as Error).message}`);\n }\n })();\n }\n\n /** Get comprehensive Hyperliquid data for a token. Returns null if token not supported or API failure. */\n async getHyperliquidData(tokenId: string): Promise<HyperliquidData | null> {\n const coin = TOKEN_TO_COIN[tokenId];\n if (!coin) return null;\n\n // Check cache first\n const cached = await this.readCache(tokenId);\n if (cached) return cached;\n\n // Make sure the persisted OI cache is available before we compute oiChangePct\n await this.ensureOiCacheLoaded();\n\n try {\n // Fetch all data in parallel\n const [metaResult, bookResult, tradesResult] = await Promise.allSettled([\n this.fetchMetaAndAssetCtxs(),\n this.fetchL2Book(coin),\n this.fetchRecentTrades(coin)\n ]);\n\n // Process meta and asset contexts (funding, OI, volume, prices)\n if (metaResult.status !== 'fulfilled' || !metaResult.value) {\n return null;\n }\n\n const [meta, assetCtxs] = metaResult.value;\n const assetIdx = meta.universe.findIndex(asset => asset.name === coin);\n if (assetIdx === -1 || !assetCtxs[assetIdx]) {\n return null;\n }\n\n const assetData = assetCtxs[assetIdx]!;\n const fundingRate = safeNumber(assetData.funding);\n const openInterest = safeNumber(assetData.openInterest);\n const volume24h = safeNumber(assetData.dayNtlVlm);\n const markPrice = safeNumber(assetData.markPx);\n const oraclePrice = safeNumber(assetData.oraclePx);\n const prevDayPrice = safeNumber(assetData.prevDayPx);\n\n // If ANY core field failed to parse, the whole response is tainted —\n // return null rather than let NaN / placeholder zeros reach scoring.\n if (\n fundingRate === null\n || openInterest === null\n || volume24h === null\n || markPrice === null\n || oraclePrice === null\n || prevDayPrice === null\n ) {\n return null;\n }\n\n // OI change since last fetch. Cache is persisted to disk; entries older\n // than OI_STALE_MS are treated as absent (no false signal from hour-old OI).\n const prior = this.oiCache.get(coin);\n const now = Date.now();\n const priorIsFresh = prior !== undefined && now - prior.timestamp < OI_STALE_MS;\n const prevOI = priorIsFresh ? prior!.openInterest : openInterest;\n const oiChangePct = prevOI > 0 ? ((openInterest - prevOI) / prevOI) * 100 : 0;\n this.oiCache.set(coin, { openInterest, timestamp: now });\n this.persistOiCache(); // fire-and-forget — never awaits disk\n\n // Process order book imbalance\n let orderBookImbalance = 0;\n if (bookResult.status === 'fulfilled' && bookResult.value) {\n orderBookImbalance = this.calculateOrderBookImbalance(bookResult.value);\n }\n\n // Process large trades bias\n let largeTradesBias = 0;\n if (tradesResult.status === 'fulfilled' && tradesResult.value) {\n largeTradesBias = this.calculateLargeTradesBias(tradesResult.value);\n }\n\n const data: HyperliquidData = {\n fundingRate,\n openInterest,\n oiChangePct,\n volume24h,\n markPrice,\n oraclePrice,\n prevDayPrice,\n orderBookImbalance,\n largeTradesBias,\n };\n\n // Cache results\n await this.writeCache(tokenId, data);\n\n return data;\n } catch (err) {\n console.error(`Hyperliquid API error for ${tokenId}: ${(err as Error).message}`);\n return null;\n }\n }\n\n /** Fetch metadata and asset contexts (funding, OI, volume, prices). */\n private async fetchMetaAndAssetCtxs(): Promise<[MetaAndAssetCtxs, AssetCtx[]] | null> {\n const response = await fetch(HYPERLIQUID_BASE, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ type: 'metaAndAssetCtxs' }),\n });\n\n if (!response.ok) return null;\n const data = await response.json() as [MetaAndAssetCtxs, AssetCtx[]];\n return data;\n }\n\n /** Fetch L2 order book for a coin. */\n private async fetchL2Book(coin: string): Promise<L2Book | null> {\n const response = await fetch(HYPERLIQUID_BASE, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ type: 'l2Book', coin }),\n });\n\n if (!response.ok) return null;\n return await response.json() as L2Book;\n }\n\n /**\n * Fetch OHLCV candles from Hyperliquid. Free, no rate limit, real-time.\n * Replaces CoinGecko OHLC as the primary candle source so the technical\n * signal stack doesn't go blind when CG's free tier 429s.\n *\n * @param tokenId CoinGecko token ID (resolved via TOKEN_TO_COIN)\n * @param interval HL interval string: '1h', '4h', '1d'\n * @param lookbackMs How far back to fetch (default 30 days)\n * @returns Array of Candle objects, or null if the token isn't mapped\n */\n async getCandles(\n tokenId: string,\n interval: '1h' | '4h' | '1d' = '4h',\n lookbackMs: number = 30 * 24 * 60 * 60 * 1000,\n ): Promise<Array<{ timestamp: number; open: number; high: number; low: number; close: number; volume: number }> | null> {\n const coin = TOKEN_TO_COIN[tokenId];\n if (!coin) return null;\n\n try {\n const now = Date.now();\n const response = await fetch(HYPERLIQUID_BASE, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n type: 'candleSnapshot',\n req: { coin, interval, startTime: now - lookbackMs, endTime: now },\n }),\n });\n\n if (!response.ok) return null;\n\n const raw = await response.json() as Array<{\n t: number; T: number; s: string; i: string;\n o: string; c: string; h: string; l: string; v: string; n: number;\n }>;\n\n if (!Array.isArray(raw) || raw.length === 0) return null;\n\n return raw.map(c => {\n const o = safeNumber(c.o);\n const h = safeNumber(c.h);\n const l = safeNumber(c.l);\n const close = safeNumber(c.c);\n const v = safeNumber(c.v);\n if (o === null || h === null || l === null || close === null) return null;\n return { timestamp: c.t, open: o, high: h, low: l, close, volume: v ?? 0 };\n }).filter((c): c is NonNullable<typeof c> => c !== null);\n } catch {\n return null;\n }\n }\n\n /** Fetch recent trades for a coin. */\n private async fetchRecentTrades(coin: string): Promise<RecentTrade[] | null> {\n const response = await fetch(HYPERLIQUID_BASE, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ type: 'recentTrades', coin }),\n });\n\n if (!response.ok) return null;\n return await response.json() as RecentTrade[];\n }\n\n /** Calculate order book imbalance from L2 book. */\n private calculateOrderBookImbalance(book: L2Book): number {\n const [bids, asks] = book.levels;\n\n // Sum top 10 levels for both sides. Skip any level whose size fails to parse\n // rather than letting NaN infect the depth total.\n const sumDepth = (levels: L2BookLevel[]): number =>\n levels.slice(0, 10).reduce((sum, level) => {\n const sz = safeNumber(level.sz);\n return sz === null ? sum : sum + sz;\n }, 0);\n\n const bidDepth = sumDepth(bids);\n const askDepth = sumDepth(asks);\n\n const totalDepth = bidDepth + askDepth;\n if (totalDepth === 0) return 0;\n\n return (bidDepth - askDepth) / totalDepth;\n }\n\n /** Calculate large trades bias from recent trades (>$50K in last hour). */\n private calculateLargeTradesBias(trades: RecentTrade[]): number {\n const oneHourAgo = Date.now() - 60 * 60 * 1000;\n const recentTrades = trades.filter(t => t.time > oneHourAgo);\n\n let buyVolume = 0;\n let sellVolume = 0;\n\n for (const trade of recentTrades) {\n const size = safeNumber(trade.sz);\n const price = safeNumber(trade.px);\n if (size === null || price === null) continue; // drop unparseable trades\n const notional = size * price;\n\n // Only count trades >$50K\n if (notional > 50000) {\n if (trade.side === 'B') {\n buyVolume += notional;\n } else if (trade.side === 'A') {\n sellVolume += notional;\n }\n }\n }\n\n const totalVolume = buyVolume + sellVolume;\n if (totalVolume === 0) return 0;\n\n return (buyVolume - sellVolume) / totalVolume;\n }\n\n /** Read cached Hyperliquid data. */\n private async readCache(tokenId: string): Promise<HyperliquidData | null> {\n try {\n const cacheFile = join(this.cacheDir, `hl-${tokenId}.json`);\n const raw = await readFile(cacheFile, 'utf-8');\n const cached = JSON.parse(raw) as { ts: number; data: HyperliquidData };\n\n if (Date.now() - cached.ts < this.cacheTTL) {\n return cached.data;\n }\n } catch {\n // No cache or invalid cache\n }\n return null;\n }\n\n /** Write Hyperliquid data to cache. */\n private async writeCache(tokenId: string, data: HyperliquidData): Promise<void> {\n try {\n await mkdir(this.cacheDir, { recursive: true });\n const cacheFile = join(this.cacheDir, `hl-${tokenId}.json`);\n await writeFile(cacheFile, JSON.stringify({ ts: Date.now(), data }), 'utf-8');\n } catch {\n // Cache write failure is non-fatal\n }\n }\n}","/**\n * Thin wrapper around the Hermes HL skill's hyperliquid.mjs script.\n * Shells out to `node ~/.hermes/skills/openclaw-imports/hyperliquid/scripts/hyperliquid.mjs`\n * so the CLI doesn't need the `hyperliquid` npm package as a dependency.\n */\n\nimport { execFile } from 'node:child_process';\nimport { resolve } from 'node:path';\nimport { homedir } from 'node:os';\n\nconst HL_SCRIPT = resolve(\n homedir(),\n '.hermes/skills/openclaw-imports/hyperliquid/scripts/hyperliquid.mjs',\n);\n\n/** CoinGecko token ID → Hyperliquid ticker (used by the HL SDK script). */\nconst TOKEN_TO_HL_COIN: Record<string, string> = {\n bitcoin: 'BTC',\n ethereum: 'ETH',\n solana: 'SOL',\n arbitrum: 'ARB',\n dogecoin: 'DOGE',\n chainlink: 'LINK',\n aave: 'AAVE',\n uniswap: 'UNI',\n ripple: 'XRP',\n polkadot: 'DOT',\n avalanche: 'AVAX',\n hyperliquid: 'HYPE',\n zcash: 'ZEC',\n bittensor: 'TAO',\n 'worldcoin-wld': 'WLD',\n fartcoin: 'FARTCOIN',\n 'fetch-ai': 'FET',\n pepe: 'PEPE',\n pendle: 'PENDLE',\n sui: 'SUI',\n near: 'NEAR',\n aptos: 'APT',\n};\n\nexport interface HLOrderResult {\n success: boolean;\n orderId?: string;\n executedPrice?: number;\n executedSize?: number;\n error?: string;\n}\n\n/** Resolve a CoinGecko token ID to its Hyperliquid ticker symbol. */\nexport function resolveHLCoin(tokenId: string): string | undefined {\n return TOKEN_TO_HL_COIN[tokenId];\n}\n\n/**\n * Execute the HL script with the given command and args.\n * Passes HYPERLIQUID_PRIVATE_KEY and HYPERLIQUID_ADDRESS from process.env.\n */\nfunction runHLScript(command: string, args: string[] = []): Promise<string> {\n return new Promise((resolve, reject) => {\n const env: Record<string, string> = { ...process.env as Record<string, string> };\n\n // Ensure required env vars are forwarded\n if (process.env.HYPERLIQUID_PRIVATE_KEY) {\n env.HYPERLIQUID_PRIVATE_KEY = process.env.HYPERLIQUID_PRIVATE_KEY;\n }\n if (process.env.HYPERLIQUID_ADDRESS) {\n env.HYPERLIQUID_ADDRESS = process.env.HYPERLIQUID_ADDRESS;\n }\n\n execFile(\n 'node',\n [HL_SCRIPT, command, ...args],\n { env, timeout: 30_000 },\n (error, stdout, stderr) => {\n if (error) {\n // The script writes errors to stderr and exits non-zero\n const msg = stderr?.trim() || error.message;\n reject(new Error(`HL script failed: ${msg}`));\n return;\n }\n resolve(stdout.trim());\n },\n );\n });\n}\n\n/** Parse the placeOrder response from the HL SDK into a normalized result. */\nfunction parseOrderResponse(raw: string): HLOrderResult {\n try {\n const data = JSON.parse(raw);\n\n // SDK response shape: { response: { type: \"order\", data: { statuses: [...] } } }\n const statuses = data?.response?.data?.statuses;\n if (!statuses || statuses.length === 0) {\n // Might be a direct error\n if (data?.response?.type === 'error') {\n return { success: false, error: data.response.data || 'Unknown HL error' };\n }\n return { success: false, error: `Unexpected response: ${raw.slice(0, 200)}` };\n }\n\n const status = statuses[0];\n\n // Filled: { filled: { totalSz, avgPx, oid } }\n if (status.filled) {\n return {\n success: true,\n orderId: String(status.filled.oid),\n executedPrice: parseFloat(status.filled.avgPx),\n executedSize: parseFloat(status.filled.totalSz),\n };\n }\n\n // Resting (limit order placed but not filled): { resting: { oid } }\n if (status.resting) {\n return {\n success: true,\n orderId: String(status.resting.oid),\n };\n }\n\n // Error status: { error: \"reason\" }\n if (status.error) {\n return { success: false, error: status.error };\n }\n\n return { success: false, error: `Unrecognized status: ${JSON.stringify(status)}` };\n } catch {\n return { success: false, error: `Failed to parse HL response: ${raw.slice(0, 200)}` };\n }\n}\n\n/** Place a market buy order on Hyperliquid perps. */\nexport async function hlMarketBuy(coin: string, sizeInToken: number): Promise<HLOrderResult> {\n const raw = await runHLScript('market-buy', [coin, String(sizeInToken)]);\n return parseOrderResponse(raw);\n}\n\n/** Place a market sell order on Hyperliquid perps. */\nexport async function hlMarketSell(coin: string, sizeInToken: number): Promise<HLOrderResult> {\n const raw = await runHLScript('market-sell', [coin, String(sizeInToken)]);\n return parseOrderResponse(raw);\n}\n\n/** Get account balance from Hyperliquid. */\nexport async function hlGetBalance(): Promise<{ equity: number; availableBalance: number }> {\n const raw = await runHLScript('balance');\n const data = JSON.parse(raw);\n\n // clearinghouseState shape: { marginSummary: { accountValue, totalMarginUsed, ... }, ... }\n const summary = data?.marginSummary;\n if (!summary) {\n throw new Error(`Unexpected balance response: ${raw.slice(0, 200)}`);\n }\n\n return {\n equity: parseFloat(summary.accountValue),\n availableBalance: parseFloat(summary.accountValue) - parseFloat(summary.totalMarginUsed),\n };\n}\n\n/** Get open positions from Hyperliquid. */\nexport async function hlGetPositions(): Promise<\n Array<{ coin: string; size: number; entryPrice: number; unrealizedPnl: number; side: string }>\n> {\n const raw = await runHLScript('positions');\n const positions = JSON.parse(raw) as Array<{ position: { coin: string; szi: string; entryPx: string; unrealizedPnl: string } }>;\n\n return positions\n .filter((p) => parseFloat(p.position.szi) !== 0)\n .map((p) => {\n const size = parseFloat(p.position.szi);\n return {\n coin: p.position.coin,\n size: Math.abs(size),\n entryPrice: parseFloat(p.position.entryPx),\n unrealizedPnl: parseFloat(p.position.unrealizedPnl),\n side: size > 0 ? 'long' : 'short',\n };\n });\n}\n\n/**\n * Place a GTC limit order on Hyperliquid perps.\n * Returns oid (HyperCore order ID) on success.\n */\nexport async function hlPlaceLimitOrder(\n coin: string,\n isBuy: boolean,\n sizeInToken: number,\n limitPrice: number,\n): Promise<HLOrderResult> {\n const cmd = isBuy ? 'limit-buy' : 'limit-sell';\n const raw = await runHLScript(cmd, [coin, String(sizeInToken), String(limitPrice)]);\n return parseOrderResponse(raw);\n}\n\n/**\n * Cancel all open orders, optionally scoped to a single coin.\n * Returns the raw response.\n */\nexport async function hlCancelAllOrders(coin?: string): Promise<string> {\n const args = coin ? [coin] : [];\n return runHLScript('cancel-all', args);\n}\n\n/** Validate that required env vars are set for live HL trading. */\nexport function validateHLEnv(): void {\n if (!process.env.HYPERLIQUID_PRIVATE_KEY) {\n throw new Error(\n 'HYPERLIQUID_PRIVATE_KEY env var is required for hyperliquid-perp mode. ' +\n 'Export it before running with --mode hyperliquid-perp.',\n );\n }\n}\n\nexport interface HLAssetMeta {\n name: string;\n szDecimals: number;\n /**\n * USD price decimals = 6 - szDecimals (Hyperliquid convention).\n * E.g. BTC szDecimals=5 → pxDecimals=1; SOL szDecimals=2 → pxDecimals=4.\n */\n pxDecimals: number;\n}\n\nconst META_TTL_MS = 60 * 60 * 1000; // 1 hour\nlet _metaCache: Map<string, HLAssetMeta> | null = null;\nlet _metaCachedAt = 0;\n\n/**\n * Fetch HL perp universe metadata, returning per-coin szDecimals + pxDecimals.\n * Caches the result for {@link META_TTL_MS} so long-running daemons refresh\n * after universe additions without needing a restart.\n */\nexport async function hlGetMeta(): Promise<Map<string, HLAssetMeta>> {\n if (_metaCache && Date.now() - _metaCachedAt < META_TTL_MS) return _metaCache;\n const raw = await runHLScript('meta');\n const universe = JSON.parse(raw) as Array<{ name: string; szDecimals: number }>;\n const fresh = new Map<string, HLAssetMeta>();\n for (const u of universe) {\n // Hyperliquid convention: pxDecimals = 6 - szDecimals (so price * 10^pxDecimals fits uint64).\n // Reference: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#perpetuals-metadata\n const pxDecimals = 6 - u.szDecimals;\n fresh.set(u.name, { name: u.name, szDecimals: u.szDecimals, pxDecimals });\n }\n _metaCache = fresh;\n _metaCachedAt = Date.now();\n return _metaCache;\n}\n\n/** Force refetch on next hlGetMeta() call. */\nexport function hlInvalidateMeta(): void {\n _metaCache = null;\n _metaCachedAt = 0;\n}\n"],"mappings":"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","names":["homedir","resolve"]}
@@ -2,23 +2,23 @@ import {
2
2
  ENS,
3
3
  SHERWOOD,
4
4
  TOKENS
5
- } from "./chunk-XAUMJZU2.js";
5
+ } from "./chunk-FWC57PT7.js";
6
6
  import {
7
7
  getAccount,
8
8
  getPublicClient,
9
9
  getWalletClient,
10
10
  waitForReceipt,
11
11
  writeContractWithRetry
12
- } from "./chunk-SWKHSKDH.js";
12
+ } from "./chunk-XDBRKW7I.js";
13
13
  import {
14
14
  CHAIN_REGISTRY,
15
15
  VALID_NETWORKS,
16
16
  getChain,
17
17
  withNetwork
18
- } from "./chunk-FOOZC4AM.js";
18
+ } from "./chunk-2LRC7I33.js";
19
19
  import {
20
20
  getChainContracts
21
- } from "./chunk-4EHI4SKM.js";
21
+ } from "./chunk-2W4KGGPU.js";
22
22
  import {
23
23
  ERC20_ABI,
24
24
  L2_REGISTRY_ABI,
@@ -543,4 +543,4 @@ export {
543
543
  setTextRecord,
544
544
  getTextRecord
545
545
  };
546
- //# sourceMappingURL=chunk-5Q3VT6NQ.js.map
546
+ //# sourceMappingURL=chunk-R7X33D2S.js.map
@@ -1,20 +1,18 @@
1
1
  import {
2
2
  UNISWAP
3
- } from "./chunk-XAUMJZU2.js";
3
+ } from "./chunk-FWC57PT7.js";
4
4
  import {
5
5
  getAccount,
6
6
  getPublicClient,
7
7
  sendTxWithRetry,
8
8
  waitForReceipt
9
- } from "./chunk-SWKHSKDH.js";
9
+ } from "./chunk-XDBRKW7I.js";
10
10
  import {
11
11
  getChain
12
- } from "./chunk-FOOZC4AM.js";
12
+ } from "./chunk-2LRC7I33.js";
13
13
  import {
14
- getUniswapApiKey,
15
- getVeniceApiKey,
16
- setVeniceApiKey
17
- } from "./chunk-4EHI4SKM.js";
14
+ getUniswapApiKey
15
+ } from "./chunk-2W4KGGPU.js";
18
16
  import {
19
17
  UNISWAP_QUOTER_V2_ABI
20
18
  } from "./chunk-D77JGXIV.js";
@@ -248,121 +246,6 @@ var UniswapProvider = class {
248
246
  }
249
247
  };
250
248
 
251
- // src/lib/venice.ts
252
- var VENICE_API_BASE = "https://api.venice.ai/api/v1";
253
- async function provisionApiKey() {
254
- const account = getAccount();
255
- const tokenRes = await fetch(`${VENICE_API_BASE}/api_keys/generate_web3_key`, {
256
- signal: AbortSignal.timeout(15e3)
257
- });
258
- if (!tokenRes.ok) {
259
- throw new Error(`Failed to get validation token: ${tokenRes.status} ${tokenRes.statusText}`);
260
- }
261
- const tokenData = await tokenRes.json();
262
- const token = tokenData?.data?.token;
263
- if (!token) {
264
- throw new Error("Venice API returned no validation token");
265
- }
266
- const signature = await account.signMessage({ message: token });
267
- const keyRes = await fetch(`${VENICE_API_BASE}/api_keys/generate_web3_key`, {
268
- method: "POST",
269
- headers: {
270
- "Content-Type": "application/json"
271
- },
272
- signal: AbortSignal.timeout(15e3),
273
- body: JSON.stringify({
274
- address: account.address,
275
- signature,
276
- token,
277
- apiKeyType: "INFERENCE",
278
- description: "Sherwood syndicate agent"
279
- })
280
- });
281
- if (!keyRes.ok) {
282
- const body = await keyRes.text();
283
- throw new Error(`Failed to generate API key: ${keyRes.status} ${body}`);
284
- }
285
- const keyData = await keyRes.json();
286
- const apiKey = keyData?.data?.apiKey;
287
- if (!apiKey) {
288
- throw new Error("Venice API returned no API key");
289
- }
290
- setVeniceApiKey(apiKey);
291
- return apiKey;
292
- }
293
- async function checkApiKeyValid() {
294
- const apiKey = getVeniceApiKey();
295
- if (!apiKey) return false;
296
- try {
297
- const res = await fetch(`${VENICE_API_BASE}/models`, {
298
- headers: { Authorization: `Bearer ${apiKey}` },
299
- signal: AbortSignal.timeout(15e3)
300
- });
301
- return res.ok;
302
- } catch {
303
- return false;
304
- }
305
- }
306
- async function chatCompletion(opts) {
307
- const apiKey = getVeniceApiKey();
308
- if (!apiKey) {
309
- throw new Error("No Venice API key configured. Run 'sherwood venice provision' first.");
310
- }
311
- const body = {
312
- model: opts.model,
313
- messages: opts.messages
314
- };
315
- if (opts.temperature !== void 0) body.temperature = opts.temperature;
316
- if (opts.maxTokens !== void 0) body.max_tokens = opts.maxTokens;
317
- const veniceParams = {};
318
- if (opts.enableWebSearch) veniceParams.enable_web_search = "on";
319
- if (opts.disableThinking) veniceParams.disable_thinking = true;
320
- if (Object.keys(veniceParams).length > 0) body.venice_parameters = veniceParams;
321
- const res = await fetch(`${VENICE_API_BASE}/chat/completions`, {
322
- method: "POST",
323
- headers: {
324
- "Content-Type": "application/json",
325
- Authorization: `Bearer ${apiKey}`
326
- },
327
- signal: AbortSignal.timeout(12e4),
328
- // inference can be slow
329
- body: JSON.stringify(body)
330
- });
331
- if (!res.ok) {
332
- const errBody = await res.text();
333
- throw new Error(`Venice inference failed: ${res.status} ${errBody}`);
334
- }
335
- const data = await res.json();
336
- const choice = data.choices?.[0];
337
- if (!choice) {
338
- throw new Error("Venice returned no choices");
339
- }
340
- return {
341
- content: choice.message?.content ?? "",
342
- model: data.model ?? opts.model,
343
- usage: {
344
- promptTokens: data.usage?.prompt_tokens ?? 0,
345
- completionTokens: data.usage?.completion_tokens ?? 0,
346
- totalTokens: data.usage?.total_tokens ?? 0
347
- }
348
- };
349
- }
350
- async function listModels() {
351
- const apiKey = getVeniceApiKey();
352
- if (!apiKey) {
353
- throw new Error("No Venice API key configured. Run 'sherwood venice provision' first.");
354
- }
355
- const res = await fetch(`${VENICE_API_BASE}/models`, {
356
- headers: { Authorization: `Bearer ${apiKey}` },
357
- signal: AbortSignal.timeout(15e3)
358
- });
359
- if (!res.ok) {
360
- throw new Error(`Failed to list Venice models: ${res.status} ${res.statusText}`);
361
- }
362
- const data = await res.json();
363
- return (data.data ?? []).map((m) => m.id);
364
- }
365
-
366
249
  // src/lib/quote.ts
367
250
  import { encodeFunctionData, decodeFunctionResult, concat, pad, numberToHex } from "viem";
368
251
  async function getQuote(params) {
@@ -434,13 +317,9 @@ async function getMultiHopQuote(params) {
434
317
 
435
318
  export {
436
319
  UniswapProvider,
437
- provisionApiKey,
438
- checkApiKeyValid,
439
- chatCompletion,
440
- listModels,
441
320
  getQuote,
442
321
  applySlippage,
443
322
  encodeSwapPath,
444
323
  getMultiHopQuote
445
324
  };
446
- //# sourceMappingURL=chunk-6U3A6ZJ2.js.map
325
+ //# sourceMappingURL=chunk-WMZEOR5W.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/uniswap.ts","../src/lib/quote.ts"],"sourcesContent":["/**\n * Uniswap Trading API provider — swaps on Base via the hosted API.\n *\n * Uses the 3-step flow:\n * 1. POST /check_approval → check/submit token approval\n * 2. POST /quote → get optimal route + executable quote\n * 3. POST /swap → get transaction calldata to sign\n *\n * API key required — set via `sherwood config set --uniswap-api-key <key>`\n * or UNISWAP_API_KEY env var.\n *\n * Docs: https://docs.uniswap.org/api/trading-api\n * Key: https://developers.uniswap.org/\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { isAddress, isHex, formatUnits } from \"viem\";\nimport { base, baseSepolia } from \"viem/chains\";\nimport type { TradingProvider, ProviderInfo, SwapParams, SwapQuoteParams, TxResult, SwapQuote } from \"../types.js\";\nimport { getPublicClient, getAccount, writeContractWithRetry, sendTxWithRetry, waitForReceipt } from \"../lib/client.js\";\nimport { getChain } from \"../lib/network.js\";\nimport { getUniswapApiKey } from \"../lib/config.js\";\n\nconst API_BASE = \"https://trade-api.gateway.uniswap.org/v1\";\n\n// ── API Types ──\n\ninterface ApprovalResponse {\n approval: {\n to: Address;\n from: Address;\n data: Hex;\n value: string;\n chainId: number;\n } | null;\n}\n\n// CLASSIC route quote\ninterface ClassicQuote {\n routing: \"CLASSIC\" | \"WRAP\" | \"UNWRAP\";\n quote: {\n input: { token: string; amount: string };\n output: { token: string; amount: string };\n slippage: number;\n route: unknown[];\n gasFee: string;\n gasFeeUSD: string;\n gasUseEstimate: string;\n };\n permitData: Record<string, unknown> | null;\n}\n\n// UniswapX route quote (PRIORITY on Base)\ninterface UniswapXQuote {\n routing: \"DUTCH_V2\" | \"DUTCH_V3\" | \"PRIORITY\";\n quote: {\n orderInfo: {\n outputs: Array<{\n token: string;\n startAmount: string;\n endAmount: string;\n recipient: string;\n }>;\n input: { token: string; startAmount: string; endAmount: string };\n deadline: number;\n nonce: string;\n };\n encodedOrder: string;\n orderHash: string;\n };\n permitData: Record<string, unknown> | null;\n}\n\ntype QuoteResponse = ClassicQuote | UniswapXQuote;\n\ninterface SwapResponse {\n swap: {\n to: Address;\n from: Address;\n data: Hex;\n value: string;\n chainId: number;\n gasLimit?: string;\n };\n}\n\n// ── Helpers ──\n\nfunction getApiKey(): string {\n const key = getUniswapApiKey();\n if (!key) {\n throw new Error(\n \"Uniswap API key not configured. Run 'sherwood config set --uniswap-api-key <key>' \" +\n \"or set UNISWAP_API_KEY env var.\\n\" +\n \"Get your key at https://developers.uniswap.org/\",\n );\n }\n return key;\n}\n\nfunction apiHeaders(): Record<string, string> {\n return {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": getApiKey(),\n \"x-universal-router-version\": \"2.0\",\n };\n}\n\nfunction isUniswapXRouting(routing: string): boolean {\n return routing === \"DUTCH_V2\" || routing === \"DUTCH_V3\" || routing === \"PRIORITY\";\n}\n\nfunction getOutputAmount(q: QuoteResponse): string {\n if (isUniswapXRouting(q.routing)) {\n const ux = q as UniswapXQuote;\n const firstOutput = ux.quote.orderInfo.outputs[0];\n if (!firstOutput) throw new Error(\"UniswapX quote has no outputs\");\n return firstOutput.startAmount; // best-case fill\n }\n return (q as ClassicQuote).quote.output.amount;\n}\n\nasync function fetchWithRetry(\n url: string,\n init: RequestInit,\n maxRetries = 3,\n): Promise<Response> {\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const response = await fetch(url, {\n ...init,\n signal: AbortSignal.timeout(30_000),\n });\n if (response.status !== 429 && response.status < 500) return response;\n if (attempt === maxRetries) return response;\n\n const delay = Math.min(200 * Math.pow(2, attempt) + Math.random() * 100, 10000);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n throw new Error(\"Unreachable\");\n}\n\n// ── Provider ──\n\nexport class UniswapProvider implements TradingProvider {\n info(): ProviderInfo {\n return {\n name: \"uniswap\",\n type: \"trading\",\n capabilities: [\n \"swap.exact-input\",\n \"swap.quote\",\n \"swap.check-approval\",\n ],\n supportedChains: [base, baseSepolia],\n };\n }\n\n /**\n * Get a quote from the Uniswap Trading API.\n * Returns the optimal route (CLASSIC, PRIORITY, or UniswapX).\n */\n async quote(params: SwapQuoteParams): Promise<SwapQuote> {\n const account = getAccount();\n const chainId = getChain().id;\n\n const body = {\n swapper: account.address,\n tokenIn: params.tokenIn,\n tokenOut: params.tokenOut,\n tokenInChainId: String(chainId),\n tokenOutChainId: String(chainId),\n amount: params.amountIn.toString(),\n type: \"EXACT_INPUT\",\n slippageTolerance: 0.5,\n routingPreference: \"BEST_PRICE\",\n };\n\n const res = await fetchWithRetry(`${API_BASE}/quote`, {\n method: \"POST\",\n headers: apiHeaders(),\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`Uniswap quote failed (${res.status}): ${err}`);\n }\n\n const data = (await res.json()) as QuoteResponse;\n const amountOut = BigInt(getOutputAmount(data));\n\n return {\n amountOut,\n priceImpact: 0,\n route: `${data.routing}: ${params.tokenIn.slice(0, 8)}→${params.tokenOut.slice(0, 8)}`,\n };\n }\n\n /**\n * Get a full quote response (preserving the raw API response for swap execution).\n */\n async fullQuote(params: {\n tokenIn: Address;\n tokenOut: Address;\n amountIn: bigint;\n slippageTolerance?: number;\n }): Promise<{ quoteResponse: QuoteResponse; amountOut: bigint; routing: string }> {\n const account = getAccount();\n const chainId = getChain().id;\n\n const body = {\n swapper: account.address,\n tokenIn: params.tokenIn,\n tokenOut: params.tokenOut,\n tokenInChainId: String(chainId),\n tokenOutChainId: String(chainId),\n amount: params.amountIn.toString(),\n type: \"EXACT_INPUT\",\n slippageTolerance: params.slippageTolerance ?? 0.5,\n routingPreference: \"BEST_PRICE\",\n };\n\n const res = await fetchWithRetry(`${API_BASE}/quote`, {\n method: \"POST\",\n headers: apiHeaders(),\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`Uniswap quote failed (${res.status}): ${err}`);\n }\n\n const quoteResponse = (await res.json()) as QuoteResponse;\n const amountOut = BigInt(getOutputAmount(quoteResponse));\n return { quoteResponse, amountOut, routing: quoteResponse.routing };\n }\n\n /**\n * Check and handle token approval for Uniswap.\n * Uses the Trading API's /check_approval endpoint.\n */\n async checkApproval(params: {\n token: Address;\n amount: bigint;\n }): Promise<void> {\n const account = getAccount();\n const chainId = getChain().id;\n const client = getPublicClient();\n\n const res = await fetchWithRetry(`${API_BASE}/check_approval`, {\n method: \"POST\",\n headers: apiHeaders(),\n body: JSON.stringify({\n walletAddress: account.address,\n token: params.token,\n amount: params.amount.toString(),\n chainId,\n }),\n });\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`Approval check failed (${res.status}): ${err}`);\n }\n\n const data = (await res.json()) as ApprovalResponse;\n\n if (data.approval) {\n // API returns a ready-to-send transaction — use sendTxWithRetry for nonce safety\n const approvalHash = await sendTxWithRetry({\n to: data.approval.to,\n data: data.approval.data,\n value: BigInt(data.approval.value || \"0\"),\n account,\n chain: getChain(),\n });\n await waitForReceipt(approvalHash);\n }\n }\n\n /**\n * Execute a swap via the Uniswap Trading API.\n *\n * Full flow: check_approval → quote → swap → sign & broadcast.\n */\n async swap(params: SwapParams): Promise<TxResult> {\n const account = getAccount();\n const client = getPublicClient();\n\n // 1. Check approval (skip for native ETH)\n const ETH_ADDRESS = \"0x0000000000000000000000000000000000000000\" as Address;\n if (params.tokenIn !== ETH_ADDRESS) {\n await this.checkApproval({\n token: params.tokenIn,\n amount: params.amountIn,\n });\n }\n\n // 2. Get quote\n const { quoteResponse } = await this.fullQuote({\n tokenIn: params.tokenIn,\n tokenOut: params.tokenOut,\n amountIn: params.amountIn,\n slippageTolerance: params.slippageTolerance ?? 0.5,\n });\n\n // 3. Prepare swap request — routing-aware permitData handling\n const quoteRaw = quoteResponse as unknown as Record<string, unknown>;\n const { permitData, ...cleanQuote } = quoteRaw;\n const swapRequest: Record<string, unknown> = { ...cleanQuote };\n\n // Sign permitData if present (required for both CLASSIC and UniswapX).\n // For CLASSIC routes using Permit2 (PermitSingle): include BOTH permitData + signature.\n // For UniswapX routes: include signature only (order-level signing, no permitData in body).\n if (permitData && typeof permitData === \"object\") {\n const typedData = permitData as {\n domain: Record<string, unknown>;\n types: Record<string, unknown>;\n values: Record<string, unknown>;\n };\n const primaryType =\n Object.keys(typedData.types).find((k) => k !== \"EIP712Domain\") ?? \"PermitSingle\";\n const signature = await account.signTypedData({\n domain: typedData.domain as Record<string, unknown>,\n types: typedData.types as Record<string, Array<{ name: string; type: string }>>,\n primaryType,\n message: typedData.values,\n });\n swapRequest.signature = signature;\n // CLASSIC routes: /swap requires both permitData and signature\n // UniswapX routes: /swap requires signature only (order is in quote body)\n if (!isUniswapXRouting(quoteResponse.routing)) {\n swapRequest.permitData = permitData;\n }\n }\n\n // 4. Get swap transaction\n const swapRes = await fetchWithRetry(`${API_BASE}/swap`, {\n method: \"POST\",\n headers: apiHeaders(),\n body: JSON.stringify(swapRequest),\n });\n\n if (!swapRes.ok) {\n const err = await swapRes.text();\n throw new Error(`Uniswap swap failed (${swapRes.status}): ${err}`);\n }\n\n const swapData = (await swapRes.json()) as SwapResponse;\n\n // 5. Validate before broadcasting\n if (!swapData.swap?.data || swapData.swap.data === (\"\" as Hex) || swapData.swap.data === \"0x\") {\n throw new Error(\"Empty swap data — quote may have expired. Try again.\");\n }\n if (!isAddress(swapData.swap.to) || !isAddress(swapData.swap.from)) {\n throw new Error(\"Invalid address in swap response\");\n }\n\n // 6. Sign and broadcast with retry-aware sender\n // Apply a 1.5x buffer to the API's gasLimit: the Uniswap API under-estimates for WETH\n // and other non-USDC inputs where PermitSingle+transfer adds overhead.\n const gasLimit = swapData.swap.gasLimit\n ? (BigInt(swapData.swap.gasLimit) * 150n) / 100n\n : undefined;\n const hash = await sendTxWithRetry({\n to: swapData.swap.to,\n data: swapData.swap.data,\n value: BigInt(swapData.swap.value || \"0\"),\n gas: gasLimit,\n account,\n chain: getChain(),\n });\n\n const receipt = await waitForReceipt(hash);\n return {\n hash,\n success: receipt.status === \"success\",\n gasUsed: receipt.gasUsed,\n };\n }\n}\n","/**\n * Uniswap V3 Quoter V2 integration for swap quotes.\n *\n * quoteExactInputSingle is NOT a view function — it reverts internally\n * after computing the quote. Must use eth_call to get the return data.\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeFunctionData, decodeFunctionResult, concat, pad, numberToHex } from \"viem\";\nimport { getPublicClient } from \"./client.js\";\nimport { UNISWAP_QUOTER_V2_ABI } from \"./abis.js\";\nimport { UNISWAP } from \"./addresses.js\";\n\nexport interface QuoteResult {\n amountOut: bigint;\n sqrtPriceX96After: bigint;\n gasEstimate: bigint;\n}\n\n/**\n * Get a swap quote from Uniswap Quoter V2.\n */\nexport async function getQuote(params: {\n tokenIn: Address;\n tokenOut: Address;\n amountIn: bigint;\n fee: number;\n}): Promise<QuoteResult> {\n const client = getPublicClient();\n\n const calldata = encodeFunctionData({\n abi: UNISWAP_QUOTER_V2_ABI,\n functionName: \"quoteExactInputSingle\",\n args: [\n {\n tokenIn: params.tokenIn,\n tokenOut: params.tokenOut,\n amountIn: params.amountIn,\n fee: params.fee,\n sqrtPriceLimitX96: 0n,\n },\n ],\n });\n\n const { data } = await client.call({\n to: UNISWAP().QUOTER_V2,\n data: calldata,\n });\n\n if (!data) {\n throw new Error(\"Quoter returned no data — pool may not exist for this pair/fee\");\n }\n\n const [amountOut, sqrtPriceX96After, , gasEstimate] = decodeFunctionResult({\n abi: UNISWAP_QUOTER_V2_ABI,\n functionName: \"quoteExactInputSingle\",\n data,\n }) as [bigint, bigint, number, bigint];\n\n return { amountOut, sqrtPriceX96After, gasEstimate };\n}\n\n/**\n * Apply slippage tolerance to a quote amount.\n * Returns the minimum acceptable output amount.\n */\nexport function applySlippage(amountOut: bigint, slippageBps: number): bigint {\n return (amountOut * BigInt(10000 - slippageBps)) / 10000n;\n}\n\n/**\n * Encode a Uniswap V3 multi-hop swap path.\n * Format: abi.encodePacked(address, uint24, address, uint24, address, ...)\n */\nexport function encodeSwapPath(tokens: Address[], fees: number[]): Hex {\n if (tokens.length < 2 || fees.length !== tokens.length - 1) {\n throw new Error(\"Invalid path: need at least 2 tokens and (tokens-1) fees\");\n }\n\n const parts: Hex[] = [];\n for (let i = 0; i < tokens.length; i++) {\n // Address: 20 bytes (no padding)\n parts.push(tokens[i].toLowerCase() as Hex);\n if (i < fees.length) {\n // Fee: 3 bytes (uint24), left-padded to 3 bytes\n parts.push(pad(numberToHex(fees[i]), { size: 3 }) as Hex);\n }\n }\n return concat(parts);\n}\n\n/**\n * Get a multi-hop swap quote from Uniswap Quoter V2.\n */\nexport async function getMultiHopQuote(params: {\n path: Hex;\n amountIn: bigint;\n}): Promise<QuoteResult> {\n const client = getPublicClient();\n\n const calldata = encodeFunctionData({\n abi: UNISWAP_QUOTER_V2_ABI,\n functionName: \"quoteExactInput\",\n args: [params.path, params.amountIn],\n });\n\n const { data } = await client.call({\n to: UNISWAP().QUOTER_V2,\n data: calldata,\n });\n\n if (!data) {\n throw new Error(\"Quoter returned no data — pool may not exist for this path\");\n }\n\n const [amountOut, , , gasEstimate] = decodeFunctionResult({\n abi: UNISWAP_QUOTER_V2_ABI,\n functionName: \"quoteExactInput\",\n data,\n }) as [bigint, bigint[], number[], bigint];\n\n return { amountOut, sqrtPriceX96After: 0n, gasEstimate };\n}\n\n/** Token decimals for display purposes. */\nexport const TOKEN_DECIMALS: Record<string, number> = {\n USDC: 6,\n WETH: 18,\n cbETH: 18,\n wstETH: 18,\n cbBTC: 8,\n DAI: 18,\n AERO: 18,\n};\n"],"mappings":"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","names":[]}
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  getChain,
3
3
  getRpcUrls
4
- } from "./chunk-FOOZC4AM.js";
4
+ } from "./chunk-2LRC7I33.js";
5
5
  import {
6
6
  loadConfig
7
- } from "./chunk-4EHI4SKM.js";
7
+ } from "./chunk-2W4KGGPU.js";
8
8
 
9
9
  // src/lib/client.ts
10
10
  import { createPublicClient, createWalletClient, fallback, http } from "viem";
@@ -489,4 +489,4 @@ export {
489
489
  writeContractWithRetry,
490
490
  waitForReceipt
491
491
  };
492
- //# sourceMappingURL=chunk-SWKHSKDH.js.map
492
+ //# sourceMappingURL=chunk-XDBRKW7I.js.map