@sherwoodagent/cli 0.83.0 → 0.84.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.
- package/dist/{abis-ZQ6I3S6L.js → abis-WVW2EBI3.js} +2 -2
- package/dist/{addresses-MS6BB7AB.js → addresses-LFYVOPOH.js} +3 -3
- package/dist/{agent-I6AUSTZG.js → agent-TBLC3WNJ.js} +7 -7
- package/dist/{chat-5SI7K5FA.js → chat-UZ3BBEXV.js} +8 -8
- package/dist/{chunk-MRUTBOMZ.js → chunk-45FELUWY.js} +2 -2
- package/dist/{chunk-UK2G5AZG.js → chunk-56YYNNNQ.js} +5 -5
- package/dist/{chunk-N5RIB6ZZ.js → chunk-6DRNSZ2Z.js} +41 -5
- package/dist/chunk-6DRNSZ2Z.js.map +1 -0
- package/dist/{chunk-ZTR2GPZO.js → chunk-BOC7VB5B.js} +36 -5
- package/dist/chunk-BOC7VB5B.js.map +1 -0
- package/dist/{chunk-I7TMY7AS.js → chunk-DNRIKCJ5.js} +85 -31
- package/dist/chunk-DNRIKCJ5.js.map +1 -0
- package/dist/{chunk-XSP64L7L.js → chunk-F3MDCUGO.js} +4 -368
- package/dist/chunk-F3MDCUGO.js.map +1 -0
- package/dist/{chunk-5O3KO7ZI.js → chunk-JUVXLTL2.js} +56 -5
- package/dist/chunk-JUVXLTL2.js.map +1 -0
- package/dist/{chunk-7ILOT3SI.js → chunk-KVB5P2OE.js} +2 -2
- package/dist/{chunk-I7NXKJCG.js → chunk-MQ55QOGD.js} +5 -5
- package/dist/{chunk-ZEZQM42M.js → chunk-NCFN66ZH.js} +39 -6
- package/dist/chunk-NCFN66ZH.js.map +1 -0
- package/dist/{chunk-ZW2VKCFZ.js → chunk-PVTZMRC6.js} +34 -2
- package/dist/chunk-PVTZMRC6.js.map +1 -0
- package/dist/{chunk-5BYJ3TGZ.js → chunk-QRMZRAMG.js} +20 -4
- package/dist/chunk-QRMZRAMG.js.map +1 -0
- package/dist/{chunk-4BMAFJKO.js → chunk-SNR5R5TO.js} +6 -6
- package/dist/{client-Z7LNEG2F.js → client-3SE632Q2.js} +3 -3
- package/dist/{eas-DWBT332K.js → eas-QPKX6A5A.js} +12 -6
- package/dist/{governor-ZVNTHHML.js → governor-7QKGNHMR.js} +12 -6
- package/dist/index.js +2183 -1305
- package/dist/index.js.map +1 -1
- package/dist/{network-HCFCNZUI.js → network-FEHRFDPJ.js} +6 -2
- package/dist/{price-GEUCSTO4.js → price-SVF25X4O.js} +6 -6
- package/dist/{providers-PWUJ2AR7.js → providers-BMOHHVUN.js} +4 -4
- package/dist/{research-SW6PLO32.js → research-YSNJ5HTM.js} +15 -12
- package/dist/research-YSNJ5HTM.js.map +1 -0
- package/dist/{session-6RSOG5NE.js → session-RMAIFRS6.js} +44 -13
- package/dist/session-RMAIFRS6.js.map +1 -0
- package/dist/{trade-45JPCKGP.js → trade-YPLTIS56.js} +21 -21
- package/dist/trade-YPLTIS56.js.map +1 -0
- package/dist/{vault-GAIOZZPC.js → vault-UCFFOOTS.js} +8 -8
- package/dist/{xmtp-A2KIQWGA.js → xmtp-S7IGTIMZ.js} +6 -6
- package/package.json +6 -3
- package/scripts/pin-xmtp-bindings.cjs +26 -10
- package/dist/chunk-5BYJ3TGZ.js.map +0 -1
- package/dist/chunk-5O3KO7ZI.js.map +0 -1
- package/dist/chunk-I7TMY7AS.js.map +0 -1
- package/dist/chunk-N5RIB6ZZ.js.map +0 -1
- package/dist/chunk-XSP64L7L.js.map +0 -1
- package/dist/chunk-ZEZQM42M.js.map +0 -1
- package/dist/chunk-ZTR2GPZO.js.map +0 -1
- package/dist/chunk-ZW2VKCFZ.js.map +0 -1
- package/dist/research-SW6PLO32.js.map +0 -1
- package/dist/session-6RSOG5NE.js.map +0 -1
- package/dist/trade-45JPCKGP.js.map +0 -1
- /package/dist/{abis-ZQ6I3S6L.js.map → abis-WVW2EBI3.js.map} +0 -0
- /package/dist/{addresses-MS6BB7AB.js.map → addresses-LFYVOPOH.js.map} +0 -0
- /package/dist/{agent-I6AUSTZG.js.map → agent-TBLC3WNJ.js.map} +0 -0
- /package/dist/{chat-5SI7K5FA.js.map → chat-UZ3BBEXV.js.map} +0 -0
- /package/dist/{chunk-MRUTBOMZ.js.map → chunk-45FELUWY.js.map} +0 -0
- /package/dist/{chunk-UK2G5AZG.js.map → chunk-56YYNNNQ.js.map} +0 -0
- /package/dist/{chunk-7ILOT3SI.js.map → chunk-KVB5P2OE.js.map} +0 -0
- /package/dist/{chunk-I7NXKJCG.js.map → chunk-MQ55QOGD.js.map} +0 -0
- /package/dist/{chunk-4BMAFJKO.js.map → chunk-SNR5R5TO.js.map} +0 -0
- /package/dist/{client-Z7LNEG2F.js.map → client-3SE632Q2.js.map} +0 -0
- /package/dist/{eas-DWBT332K.js.map → eas-QPKX6A5A.js.map} +0 -0
- /package/dist/{governor-ZVNTHHML.js.map → governor-7QKGNHMR.js.map} +0 -0
- /package/dist/{network-HCFCNZUI.js.map → network-FEHRFDPJ.js.map} +0 -0
- /package/dist/{price-GEUCSTO4.js.map → price-SVF25X4O.js.map} +0 -0
- /package/dist/{providers-PWUJ2AR7.js.map → providers-BMOHHVUN.js.map} +0 -0
- /package/dist/{vault-GAIOZZPC.js.map → vault-UCFFOOTS.js.map} +0 -0
- /package/dist/{xmtp-A2KIQWGA.js.map → xmtp-S7IGTIMZ.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/trade.ts","../src/providers/uniswap.ts","../src/lib/signals.ts","../src/lib/exit-strategy.ts","../src/lib/positions.ts"],"sourcesContent":["/**\n * Trade commands — sherwood trade <subcommand>\n *\n * Memecoin trading via the Uniswap Trading API on Base, driven by signal-based\n * analysis (on-chain flows, social sentiment, fundamentals).\n *\n * Trades execute from the agent's own EOA wallet using USDC as quote currency.\n * Requires a Uniswap API key: `sherwood config set --uniswap-api-key <key>`\n */\n\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { confirm } from \"@inquirer/prompts\";\nimport type { Address } from \"viem\";\nimport { isAddress, parseUnits, formatUnits } from \"viem\";\n\nimport { getPublicClient, getAccount, formatContractError } from \"../lib/client.js\";\nimport { getExplorerUrl, getNetwork } from \"../lib/network.js\";\nimport { TOKENS } from \"../lib/addresses.js\";\nimport { ERC20_ABI } from \"../lib/abis.js\";\nimport { UniswapProvider } from \"../providers/uniswap.js\";\nimport { analyzeToken } from \"../lib/signals.js\";\nimport type { SignalResult } from \"../lib/signals.js\";\nimport { checkExit, DEFAULT_EXIT_CONFIG } from \"../lib/exit-strategy.js\";\nimport type { ExitConfig } from \"../lib/exit-strategy.js\";\nimport {\n getOpenPositions,\n addPosition,\n closePosition,\n updateHighWater,\n getCurrentPrice,\n} from \"../lib/positions.js\";\nimport type { MessageType } from \"../lib/types.js\";\n\nconst uniswap = new UniswapProvider();\n\n// Lazy-load XMTP to avoid breaking non-chat environments\nasync function loadXmtp() {\n return import(\"../lib/xmtp.js\");\n}\n\n// ── Token resolution ──\n\nconst ETH_ADDRESS = \"0x0000000000000000000000000000000000000000\" as Address;\n\nconst KNOWN_MEMECOINS: Record<string, Address> = {\n DEGEN: \"0x4ed4E862860beD51a9570b96d89aF5E1B0Efefed\" as Address,\n TOSHI: \"0xAC1Bd2486aAf3B5C0fc3Fd868558b082a531B2B4\" as Address,\n BRETT: \"0x532f27101965dd16442E59d40670FaF5eBB142E4\" as Address,\n HIGHER: \"0x0578d8A44db98B23BF096A382e016e29a5Ce0ffe\" as Address,\n};\n\nconst WETH_ABI = [\n {\n name: \"deposit\",\n type: \"function\",\n stateMutability: \"payable\",\n inputs: [],\n outputs: [],\n },\n] as const;\n\nasync function resolveToken(\n symbolOrAddress: string,\n): Promise<{ address: Address; symbol: string; decimals: number }> {\n const upper = symbolOrAddress.toUpperCase();\n\n // ETH is native — not an ERC-20, handle specially\n if (upper === \"ETH\") {\n return { address: ETH_ADDRESS, symbol: \"ETH\", decimals: 18 };\n }\n\n let address: Address;\n let symbol: string;\n\n if (isAddress(symbolOrAddress)) {\n address = symbolOrAddress as Address;\n const client = getPublicClient();\n try {\n symbol = (await client.readContract({\n address,\n abi: ERC20_ABI,\n functionName: \"symbol\",\n })) as string;\n } catch {\n symbol = address.slice(0, 8);\n }\n } else {\n const tokens = TOKENS();\n const tokenMap: Record<string, Address> = {\n USDC: tokens.USDC,\n WETH: tokens.WETH,\n ...KNOWN_MEMECOINS,\n };\n address = tokenMap[upper];\n if (!address) {\n throw new Error(\n `Unknown token: ${symbolOrAddress}. Use a contract address or known symbol (${Object.keys(tokenMap).join(\", \")}).`,\n );\n }\n symbol = upper;\n }\n\n const client = getPublicClient();\n const decimals = (await client.readContract({\n address,\n abi: ERC20_ABI,\n functionName: \"decimals\",\n })) as number;\n\n return { address, symbol, decimals };\n}\n\n// ── Chat posting ──\n\nasync function postToChat(\n fund: string,\n type: MessageType,\n text: string,\n data: Record<string, unknown>,\n): Promise<void> {\n try {\n const xmtp = await loadXmtp();\n const group = await xmtp.getGroup(\"\", fund);\n await xmtp.sendEnvelope(group, {\n type,\n from: getAccount().address,\n text,\n data,\n timestamp: Math.floor(Date.now() / 1000),\n });\n } catch {\n // Chat posting is best-effort\n }\n}\n\n// ── Formatting ──\n\nfunction formatSignalTable(results: { symbol: string; address: Address; result: SignalResult }[]): void {\n console.log();\n console.log(chalk.bold(\" Token Score Action Conf. On-chain Social Fundmtl\"));\n console.log(chalk.dim(\" \" + \"─\".repeat(72)));\n\n for (const { symbol, address, result } of results) {\n const scoreColor = result.compositeScore > 0 ? chalk.green : result.compositeScore < 0 ? chalk.red : chalk.dim;\n const actionColor =\n result.action === \"buy\" ? chalk.green.bold :\n result.action === \"sell\" ? chalk.red.bold :\n chalk.dim;\n\n const onChain = result.signals.find((s) => s.source === \"onchain\");\n const social = result.signals.find((s) => s.source === \"social\");\n const fundamental = result.signals.find((s) => s.source === \"fundamental\");\n\n const shortAddr = `${address.slice(0, 6)}..`;\n const label = `${symbol.padEnd(6)} (${shortAddr})`;\n\n console.log(\n ` ${label.padEnd(16)} ` +\n `${scoreColor(result.compositeScore.toFixed(2).padStart(6))} ` +\n `${actionColor(result.action.toUpperCase().padEnd(6))} ` +\n `${(result.confidence * 100).toFixed(0).padStart(4)}% ` +\n `${formatSignalValue(onChain?.value).padStart(8)} ` +\n `${formatSignalValue(social?.value).padStart(6)} ` +\n `${formatSignalValue(fundamental?.value).padStart(7)}`,\n );\n }\n console.log();\n}\n\nfunction formatSignalValue(v: number | undefined): string {\n if (v === undefined) return chalk.dim(\"n/a\");\n const s = (v >= 0 ? \"+\" : \"\") + v.toFixed(2);\n return v > 0 ? chalk.green(s) : v < 0 ? chalk.red(s) : chalk.dim(s);\n}\n\n// ── Commands ──\n\n// The Uniswap Trading API (and the KNOWN_MEMECOINS universe) covers Base only.\n// No currently registered network qualifies — Sherwood currently deploys on\n// Robinhood testnet (chain 46630) — so every trade subcommand fails fast\n// instead of advertising a capability that would throw mid-flow.\nconst TRADING_API_NETWORKS = new Set<string>([\"base\", \"base-sepolia\"]);\n\nexport function registerTradeCommands(program: Command): void {\n const trade = program\n .command(\"trade\")\n .description(\"Memecoin trading — scan, buy, sell, monitor positions (Uniswap Trading API on Base)\");\n\n trade.hook(\"preAction\", () => {\n const network = getNetwork();\n if (!TRADING_API_NETWORKS.has(network)) {\n console.error(chalk.red(`trade commands are not supported on ${network}.`));\n console.error(\n chalk.dim(\n \"They require the Uniswap Trading API, which covers Base only. \" +\n \"Sherwood deploys on Robinhood Chain — the mainnet fork (chain \" +\n \"9994663, the default) and the L2 testnet (chain 46630).\",\n ),\n );\n process.exit(1);\n }\n });\n\n // ── trade scan ──\n\n trade\n .command(\"scan\")\n .description(\"Analyze token(s) using on-chain, social, and fundamental signals\")\n .option(\"--token <addr|symbol>\", \"Specific token to analyze (otherwise scans known memecoins)\")\n .option(\"--fund <name>\", \"Post results to fund chat\")\n .option(\"--yes\", \"Skip cost confirmation\", false)\n .action(async (opts: { token?: string; fund?: string; yes: boolean }) => {\n const targets: { symbol: string; address: Address }[] = [];\n\n if (opts.token) {\n const resolved = await resolveToken(opts.token);\n targets.push({ symbol: resolved.symbol, address: resolved.address });\n } else {\n for (const [symbol, address] of Object.entries(KNOWN_MEMECOINS)) {\n targets.push({ symbol, address });\n }\n }\n\n const estCost = targets.length * 0.26;\n console.log();\n console.log(chalk.bold(\"Memecoin Alpha Scan\"));\n console.log(chalk.dim(\"─\".repeat(40)));\n console.log(` Tokens: ${targets.map((t) => t.symbol).join(\", \")}`);\n console.log(` Est. cost: ${chalk.yellow(`~$${estCost.toFixed(2)} USDC`)} (x402 research) + Venice inference`);\n console.log();\n\n if (!opts.yes) {\n const ok = await confirm({\n message: `Proceed with signal analysis?`,\n default: true,\n });\n if (!ok) {\n console.log(chalk.dim(\"Cancelled.\"));\n return;\n }\n }\n\n const spinner = ora(\"Analyzing signals...\").start();\n const results: { symbol: string; address: Address; result: SignalResult }[] = [];\n\n for (const target of targets) {\n try {\n spinner.text = `Analyzing ${target.symbol}...`;\n const result = await analyzeToken(target.address, target.symbol);\n results.push({ ...target, result });\n } catch {\n results.push({\n ...target,\n result: {\n action: \"hold\",\n confidence: 0,\n compositeScore: 0,\n signals: [],\n costUsdc: \"0\",\n timestamp: Math.floor(Date.now() / 1000),\n },\n });\n }\n }\n\n spinner.succeed(\"Scan complete\");\n formatSignalTable(results);\n\n const totalCost = results.reduce((sum, r) => sum + Number(r.result.costUsdc), 0);\n console.log(chalk.dim(` Total research cost: $${totalCost.toFixed(4)} USDC`));\n console.log();\n\n if (opts.fund) {\n await postToChat(opts.fund, \"TRADE_SIGNAL\" as MessageType,\n `Scanned ${results.length} tokens: ${results.filter((r) => r.result.action === \"buy\").map((r) => r.symbol).join(\", \") || \"no buys\"}`,\n { results: results.map((r) => ({ symbol: r.symbol, action: r.result.action, score: r.result.compositeScore })) },\n );\n }\n });\n\n // ── trade buy ──\n\n trade\n .command(\"buy\")\n .description(\"Buy a token via Uniswap Trading API\")\n .requiredOption(\"--token <addr|symbol>\", \"Token to buy\")\n .requiredOption(\"--amount <n>\", \"Amount of input token to spend\")\n .option(\"--with <token>\", \"Input token to spend (default: USDC). Use ETH for native ETH (auto-wraps to WETH).\", \"USDC\")\n .option(\"--slippage <pct>\", \"Slippage tolerance % (default: 0.5)\", \"0.5\")\n .option(\"--stop-loss <pct>\", \"Stop loss percentage (default: 10)\", \"10\")\n .option(\"--trailing-stop <pct>\", \"Trailing stop percentage (0 = disabled)\", \"0\")\n .option(\"--deadline <hours>\", \"Force exit after N hours (0 = none)\", \"0\")\n .option(\"--fund <name>\", \"Post trade to fund chat\")\n .action(async (opts) => {\n const { address: tokenAddr, symbol, decimals } = await resolveToken(opts.token as string);\n const slippage = Number(opts.slippage);\n\n // Resolve input token\n const inputSpec = (opts.with as string).toUpperCase();\n const isEthInput = inputSpec === \"ETH\";\n // ETH input: wrap to WETH first, then swap WETH → target\n const {\n address: inputAddr,\n symbol: inputSymbol,\n decimals: inputDecimals,\n } = isEthInput\n ? { address: TOKENS().WETH, symbol: \"ETH\", decimals: 18 }\n : await resolveToken(opts.with as string);\n const inputAmount = parseUnits(opts.amount as string, inputDecimals);\n\n // Check balance\n const client = getPublicClient();\n const account = getAccount();\n\n if (isEthInput) {\n const ethBalance = await client.getBalance({ address: account.address });\n if (ethBalance < inputAmount) {\n console.error(chalk.red(\n `Insufficient ETH. Have ${formatUnits(ethBalance, 18)}, need ${opts.amount}`,\n ));\n process.exit(1);\n }\n\n // Wrap ETH → WETH\n const wrapSpinner = ora(\"Wrapping ETH → WETH...\").start();\n try {\n const { writeContractWithRetry, waitForReceipt: waitForReceiptFn } = await import(\"../lib/client.js\");\n const wethAddr = TOKENS().WETH;\n const wrapHash = await writeContractWithRetry({\n address: wethAddr,\n abi: WETH_ABI,\n functionName: \"deposit\",\n args: [],\n value: inputAmount,\n account,\n chain: (await import(\"../lib/network.js\")).getChain(),\n });\n await waitForReceiptFn(wrapHash);\n wrapSpinner.succeed(`Wrapped ${opts.amount} ETH → WETH`);\n } catch (err) {\n wrapSpinner.fail(\"ETH wrap failed\");\n console.error(chalk.red(err instanceof Error ? err.message : String(err)));\n process.exit(1);\n }\n } else {\n const balance = (await client.readContract({\n address: inputAddr,\n abi: ERC20_ABI,\n functionName: \"balanceOf\",\n args: [account.address],\n })) as bigint;\n\n if (balance < inputAmount) {\n console.error(chalk.red(\n `Insufficient ${inputSymbol}. Have ${formatUnits(balance, inputDecimals)}, need ${opts.amount}`,\n ));\n process.exit(1);\n }\n }\n\n // Get quote via Uniswap Trading API (handles routing automatically)\n const quoteSpinner = ora(\"Getting quote from Uniswap API...\").start();\n let expectedOut: bigint;\n\n try {\n const result = await uniswap.fullQuote({\n tokenIn: inputAddr,\n tokenOut: tokenAddr,\n amountIn: inputAmount,\n slippageTolerance: slippage,\n });\n expectedOut = result.amountOut;\n const routing = result.routing;\n quoteSpinner.succeed(\n `Quote: ${formatUnits(result.amountOut, decimals)} ${symbol} (${routing} route)`,\n );\n } catch (err) {\n quoteSpinner.fail(\"Quote failed\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n\n // Execute swap via Uniswap Trading API (check_approval + quote + swap + sign + broadcast)\n const swapSpinner = ora(\"Executing swap via Uniswap API...\").start();\n let txHash: string;\n try {\n const result = await uniswap.swap({\n tokenIn: inputAddr,\n tokenOut: tokenAddr,\n amountIn: inputAmount,\n amountOutMinimum: 0n, // slippage handled by API\n fee: 3000,\n slippageTolerance: slippage,\n });\n txHash = result.hash;\n\n if (!result.success) {\n swapSpinner.fail(\"Swap reverted\");\n console.error(chalk.dim(` Tx: ${getExplorerUrl(result.hash)}`));\n process.exit(1);\n }\n swapSpinner.succeed(\"Swap executed\");\n } catch (err) {\n swapSpinner.fail(\"Swap failed\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n\n // Read actual token balance received\n const tokenBalance = (await client.readContract({\n address: tokenAddr,\n abi: ERC20_ABI,\n functionName: \"balanceOf\",\n args: [account.address],\n })) as bigint;\n\n const tokensReceived = tokenBalance > 0n ? tokenBalance : expectedOut;\n const entryPrice = Number(opts.amount) / Number(formatUnits(tokensReceived, decimals));\n\n // Build exit config\n const exitConfig: ExitConfig = {\n stopLossPct: Number(opts.stopLoss) || DEFAULT_EXIT_CONFIG.stopLossPct,\n trailingStopPct: Number(opts.trailingStop) || DEFAULT_EXIT_CONFIG.trailingStopPct,\n takeProfitPct: DEFAULT_EXIT_CONFIG.takeProfitPct,\n deadlineUnix: Number(opts.deadline) > 0\n ? Math.floor(Date.now() / 1000) + Number(opts.deadline) * 3600\n : 0,\n signalExitEnabled: true,\n };\n\n // Save position\n addPosition({\n tokenAddress: tokenAddr,\n tokenSymbol: symbol,\n tokenDecimals: decimals,\n amountIn: opts.amount as string,\n amountOut: tokensReceived.toString(),\n entryPrice,\n highWaterPrice: entryPrice,\n feeTier: 3000, // stored for price lookups via QuoterV2\n openedAt: Math.floor(Date.now() / 1000),\n txHash,\n exitConfig,\n inputTokenAddress: inputAddr,\n inputTokenSymbol: inputSymbol,\n inputTokenDecimals: inputDecimals,\n });\n\n console.log();\n console.log(chalk.bold(\"Trade Executed\"));\n console.log(chalk.dim(\"─\".repeat(40)));\n console.log(` Token: ${symbol} (${tokenAddr})`);\n console.log(` Spent: ${opts.amount} ${inputSymbol}`);\n console.log(` Received: ${formatUnits(tokensReceived, decimals)} ${symbol}`);\n console.log(` Entry: ${entryPrice.toFixed(8)} ${inputSymbol}/${symbol}`);\n console.log(` Stop: -${exitConfig.stopLossPct}%`);\n if (exitConfig.trailingStopPct > 0) {\n console.log(` Trailing: ${exitConfig.trailingStopPct}%`);\n }\n if (exitConfig.deadlineUnix > 0) {\n console.log(` Deadline: ${new Date(exitConfig.deadlineUnix * 1000).toISOString()}`);\n }\n console.log(` Tx: ${chalk.dim(getExplorerUrl(txHash as `0x${string}`))}`);\n\n // EAS attestation (best-effort) — recipient is vault so dashboard can display it\n try {\n const { createTradeAttestation, getEasScanUrl } = await import(\"../lib/eas.js\");\n const { getChainContracts } = await import(\"../lib/config.js\");\n const { getChain: getActiveChain } = await import(\"../lib/network.js\");\n const vaultRecipient = getChainContracts(getActiveChain().id).vault as `0x${string}` | undefined;\n const attestation = await createTradeAttestation(\n inputAddr, tokenAddr, inputAmount,\n formatUnits(tokensReceived, decimals),\n txHash, \"BUY\", vaultRecipient,\n );\n if (attestation) {\n console.log(` Attested: ${chalk.dim(getEasScanUrl(attestation.uid))}`);\n }\n } catch {\n // Attestation is best-effort\n }\n\n console.log();\n\n if (opts.fund) {\n await postToChat(opts.fund, \"TRADE_EXECUTED\" as MessageType,\n `Bought ${formatUnits(tokensReceived, decimals)} ${symbol} for ${opts.amount} ${inputSymbol} via Uniswap`,\n { token: symbol, address: tokenAddr, amountIn: opts.amount, inputToken: inputSymbol, txHash },\n );\n }\n });\n\n // ── trade sell ──\n\n trade\n .command(\"sell\")\n .description(\"Sell a token position via Uniswap Trading API\")\n .requiredOption(\"--token <addr|symbol>\", \"Token to sell\")\n .option(\"--amount <n>\", \"Token amount to sell (default: entire position)\")\n .option(\"--for <token>\", \"Output token to receive (default: USDC)\", \"USDC\")\n .option(\"--slippage <pct>\", \"Slippage tolerance % (default: 0.5)\", \"0.5\")\n .option(\"--fund <name>\", \"Post trade to fund chat\")\n .action(async (opts) => {\n const { address: tokenAddr, symbol, decimals } = await resolveToken(opts.token as string);\n const {\n address: outputAddr,\n symbol: outputSymbol,\n decimals: outputDecimals,\n } = await resolveToken(opts.for as string);\n const slippage = Number(opts.slippage);\n\n // Find open position\n const positions = getOpenPositions();\n const pos = positions.find(\n (p) => p.tokenAddress.toLowerCase() === tokenAddr.toLowerCase(),\n );\n\n // Determine sell amount\n const client = getPublicClient();\n const account = getAccount();\n let sellAmount: bigint;\n\n if (opts.amount) {\n sellAmount = parseUnits(opts.amount as string, decimals);\n } else {\n sellAmount = (await client.readContract({\n address: tokenAddr,\n abi: ERC20_ABI,\n functionName: \"balanceOf\",\n args: [account.address],\n })) as bigint;\n }\n\n if (sellAmount === 0n) {\n console.error(chalk.red(\"No tokens to sell.\"));\n process.exit(1);\n }\n\n // Quote via Uniswap Trading API\n const quoteSpinner = ora(\"Getting quote from Uniswap API...\").start();\n let expectedOut: bigint;\n\n try {\n const result = await uniswap.fullQuote({\n tokenIn: tokenAddr,\n tokenOut: outputAddr,\n amountIn: sellAmount,\n slippageTolerance: slippage,\n });\n expectedOut = result.amountOut;\n const routing = result.routing;\n quoteSpinner.succeed(\n `Quote: ${formatUnits(result.amountOut, outputDecimals)} ${outputSymbol} (${routing} route)`,\n );\n } catch (err) {\n quoteSpinner.fail(\"Quote failed\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n\n // Execute sell via Uniswap Trading API\n const swapSpinner = ora(\"Executing sell via Uniswap API...\").start();\n let txHash: string;\n try {\n const result = await uniswap.swap({\n tokenIn: tokenAddr,\n tokenOut: outputAddr,\n amountIn: sellAmount,\n amountOutMinimum: 0n,\n fee: 3000,\n slippageTolerance: slippage,\n });\n txHash = result.hash;\n\n if (!result.success) {\n swapSpinner.fail(\"Sell reverted\");\n process.exit(1);\n }\n swapSpinner.succeed(\"Sell executed\");\n } catch (err) {\n swapSpinner.fail(\"Sell failed\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n\n // Calculate P&L (meaningful when output matches the original input token)\n const outputReceived = Number(formatUnits(expectedOut, outputDecimals));\n const costBasis = pos ? Number(pos.amountIn) : 0;\n const inputMatchesOutput = pos\n ? (pos.inputTokenSymbol ?? \"USDC\").toUpperCase() === outputSymbol.toUpperCase()\n : outputSymbol.toUpperCase() === \"USDC\";\n const pnl = costBasis > 0 && inputMatchesOutput ? outputReceived - costBasis : 0;\n const pnlPct = costBasis > 0 && inputMatchesOutput ? (pnl / costBasis) * 100 : 0;\n const exitPrice = sellAmount > 0n\n ? outputReceived / Number(formatUnits(sellAmount, decimals))\n : 0;\n\n if (pos) {\n closePosition(tokenAddr, {\n exitPrice,\n closedAt: Math.floor(Date.now() / 1000),\n exitTxHash: txHash,\n exitReason: \"manual\",\n pnlUsdc: pnl,\n pnlPct,\n });\n }\n\n const pnlColor = pnl >= 0 ? chalk.green : chalk.red;\n\n console.log();\n console.log(chalk.bold(\"Position Closed\"));\n console.log(chalk.dim(\"─\".repeat(40)));\n console.log(` Token: ${symbol}`);\n console.log(` Sold: ${formatUnits(sellAmount, decimals)} ${symbol}`);\n console.log(` Received: ~${outputReceived.toFixed(outputDecimals <= 6 ? 2 : 6)} ${outputSymbol}`);\n if (costBasis > 0 && inputMatchesOutput) {\n const posInputSymbol = pos?.inputTokenSymbol ?? \"USDC\";\n console.log(` Cost: ${costBasis.toFixed(2)} ${posInputSymbol}`);\n console.log(` P&L: ${pnlColor(`${pnl >= 0 ? \"+\" : \"\"}${pnl.toFixed(2)} ${outputSymbol} (${pnlPct >= 0 ? \"+\" : \"\"}${pnlPct.toFixed(1)}%)`)}`);\n }\n console.log(` Tx: ${chalk.dim(getExplorerUrl(txHash as `0x${string}`))}`);\n\n // EAS attestation (best-effort) — recipient is vault so dashboard can display it\n try {\n const { createTradeAttestation, getEasScanUrl } = await import(\"../lib/eas.js\");\n const { getChainContracts } = await import(\"../lib/config.js\");\n const { getChain: getActiveChain } = await import(\"../lib/network.js\");\n const vaultRecipient = getChainContracts(getActiveChain().id).vault as `0x${string}` | undefined;\n const attestation = await createTradeAttestation(\n tokenAddr, outputAddr, sellAmount,\n formatUnits(expectedOut, outputDecimals),\n txHash, \"SELL\", vaultRecipient,\n );\n if (attestation) {\n console.log(` Attested: ${chalk.dim(getEasScanUrl(attestation.uid))}`);\n }\n } catch {\n // Attestation is best-effort\n }\n\n console.log();\n\n if (opts.fund) {\n await postToChat(opts.fund, \"TRADE_EXECUTED\" as MessageType,\n `Sold ${formatUnits(sellAmount, decimals)} ${symbol} for ~${outputReceived.toFixed(2)} ${outputSymbol}${inputMatchesOutput && costBasis > 0 ? ` (P&L: ${pnl >= 0 ? \"+\" : \"\"}${pnl.toFixed(2)})` : \"\"}`,\n { token: symbol, address: tokenAddr, outputReceived, outputToken: outputSymbol, pnl, pnlPct, txHash },\n );\n }\n });\n\n // ── trade positions ──\n\n trade\n .command(\"positions\")\n .description(\"Show open positions with current prices and unrealized P&L\")\n .action(async () => {\n const positions = getOpenPositions();\n if (positions.length === 0) {\n console.log(chalk.dim(\"\\n No open positions.\\n\"));\n return;\n }\n\n console.log();\n console.log(chalk.bold(\"Open Positions\"));\n console.log(chalk.dim(\"─\".repeat(80)));\n console.log(chalk.dim(\n \" Token Entry Current Qty Cost Value P&L\",\n ));\n\n for (const pos of positions) {\n try {\n const current = await getCurrentPrice(pos.tokenAddress, pos.tokenDecimals, pos.feeTier);\n const qty = Number(formatUnits(BigInt(pos.amountOut), pos.tokenDecimals));\n const cost = Number(pos.amountIn);\n const value = qty * current;\n const pnl = value - cost;\n const pnlPct = cost > 0 ? (pnl / cost) * 100 : 0;\n const pnlColor = pnl >= 0 ? chalk.green : chalk.red;\n\n console.log(\n ` ${pos.tokenSymbol.padEnd(14)} ` +\n `$${pos.entryPrice.toFixed(6).padStart(10)} ` +\n `$${current.toFixed(6).padStart(10)} ` +\n `${qty.toFixed(2).padStart(15)} ` +\n `$${cost.toFixed(2).padStart(8)} ` +\n `$${value.toFixed(2).padStart(8)} ` +\n pnlColor(`${pnl >= 0 ? \"+\" : \"\"}${pnl.toFixed(2)} (${pnlPct >= 0 ? \"+\" : \"\"}${pnlPct.toFixed(1)}%)`),\n );\n\n if (current > pos.highWaterPrice) {\n updateHighWater(pos.tokenAddress, current);\n }\n } catch {\n console.log(\n ` ${pos.tokenSymbol.padEnd(14)} ` +\n `$${pos.entryPrice.toFixed(6).padStart(10)} ` +\n `${chalk.dim(\"price unavailable\")}`,\n );\n }\n }\n console.log();\n });\n\n // ── trade monitor ──\n\n trade\n .command(\"monitor\")\n .description(\"Monitor positions and auto-exit on signal triggers\")\n .option(\"--interval <seconds>\", \"Check interval in seconds (default: 300)\", \"300\")\n .option(\"--fund <name>\", \"Post updates to fund chat\")\n .action(async (opts) => {\n const interval = Number(opts.interval) * 1000;\n\n console.log();\n console.log(chalk.bold(\"Position Monitor\"));\n console.log(chalk.dim(`Checking every ${opts.interval}s. Press Ctrl-C to stop.`));\n console.log();\n\n const running = { value: true };\n process.on(\"SIGINT\", () => {\n running.value = false;\n console.log(chalk.dim(\"\\nStopping monitor...\"));\n });\n\n while (running.value) {\n const positions = getOpenPositions();\n if (positions.length === 0) {\n console.log(chalk.dim(\" No open positions. Waiting...\"));\n await sleep(interval);\n continue;\n }\n\n for (const pos of positions) {\n if (!running.value) break;\n\n try {\n const current = await getCurrentPrice(pos.tokenAddress, pos.tokenDecimals, pos.feeTier);\n const hwPrice = Math.max(current, pos.highWaterPrice);\n if (current > pos.highWaterPrice) {\n updateHighWater(pos.tokenAddress, current);\n }\n\n // Run signal analysis for exit check\n let signalResult: SignalResult | undefined;\n if (pos.exitConfig.signalExitEnabled) {\n try {\n signalResult = await analyzeToken(pos.tokenAddress, pos.tokenSymbol);\n } catch {\n // Signal analysis can fail — continue with price-only checks\n }\n }\n\n const exit = checkExit(pos.entryPrice, current, hwPrice, pos.exitConfig, signalResult);\n const pnlPct = exit.currentPnlPct;\n const pnlColor = pnlPct >= 0 ? chalk.green : chalk.red;\n const ts = new Date().toLocaleTimeString();\n\n console.log(\n ` [${ts}] ${pos.tokenSymbol}: ` +\n `$${current.toFixed(6)} ` +\n pnlColor(`(${pnlPct >= 0 ? \"+\" : \"\"}${pnlPct.toFixed(1)}%)`) +\n (exit.shouldExit ? chalk.red.bold(` → EXIT (${exit.reason})`) : \"\"),\n );\n\n if (exit.shouldExit) {\n console.log(chalk.yellow(` Executing exit for ${pos.tokenSymbol}: ${exit.reason}`));\n\n if (opts.fund) {\n await postToChat(opts.fund, \"RISK_ALERT\" as MessageType,\n `Exit triggered for ${pos.tokenSymbol}: ${exit.reason} (${pnlPct >= 0 ? \"+\" : \"\"}${pnlPct.toFixed(1)}%)`,\n { token: pos.tokenSymbol, reason: exit.reason, pnlPct },\n );\n }\n\n try {\n const sellAmount = BigInt(pos.amountOut);\n const usdc = TOKENS().USDC;\n\n // Get quote for P&L calculation\n const { amountOut: sellQuote } = await uniswap.fullQuote({\n tokenIn: pos.tokenAddress,\n tokenOut: usdc,\n amountIn: sellAmount,\n slippageTolerance: 0.5,\n });\n\n // Execute sell via Trading API\n const result = await uniswap.swap({\n tokenIn: pos.tokenAddress,\n tokenOut: usdc,\n amountIn: sellAmount,\n amountOutMinimum: 0n,\n fee: 3000,\n slippageTolerance: 1.0, // 1% for auto-sell\n });\n\n const usdcReceived = Number(formatUnits(sellQuote, 6));\n const costBasis = Number(pos.amountIn);\n const pnlUsdc = usdcReceived - costBasis;\n\n closePosition(pos.tokenAddress, {\n exitPrice: current,\n closedAt: Math.floor(Date.now() / 1000),\n exitTxHash: result.hash,\n exitReason: exit.reason,\n pnlUsdc,\n pnlPct,\n });\n\n const pnlStr = `${pnlUsdc >= 0 ? \"+\" : \"\"}${pnlUsdc.toFixed(2)} USDC`;\n console.log(chalk.green(` Sold ${pos.tokenSymbol}: ${pnlStr}`));\n\n if (opts.fund) {\n await postToChat(opts.fund, \"TRADE_EXECUTED\" as MessageType,\n `Auto-sold ${pos.tokenSymbol}: ${pnlStr} (${exit.reason})`,\n { token: pos.tokenSymbol, reason: exit.reason, pnlUsdc, pnlPct, txHash: result.hash },\n );\n }\n } catch (err) {\n console.error(chalk.red(\n ` Failed to sell ${pos.tokenSymbol}: ${formatContractError(err)}`,\n ));\n }\n }\n } catch {\n console.error(chalk.dim(\n ` [${new Date().toLocaleTimeString()}] ${pos.tokenSymbol}: price check failed`,\n ));\n }\n }\n\n if (running.value) {\n await sleep(interval);\n }\n }\n\n console.log(chalk.dim(\"Monitor stopped.\"));\n });\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * PARKED — Base-only Uniswap Trading API adapter (inactive on the current\n * deployment target).\n *\n * The hosted Trading API covers Base / Base Sepolia only; the CLI's sole\n * registered chain is Robinhood testnet (chain 46630), so this adapter cannot\n * execute there and is NOT advertised by `sherwood providers` (see\n * providers/index.ts). Its only consumer is `sherwood trade`, which fails fast\n * on unsupported networks (commands/trade.ts). Swaps on the live chain go\n * through lib/swap-router.ts (Synthra). Retained for a future Base deployment.\n *\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 type { 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 {\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 * Signal engine — aggregates on-chain, social, and fundamental data\n * into a composite buy/sell/hold recommendation.\n *\n * Sources:\n * On-chain: Nansen smart-money net flow (x402, ~$0.06)\n * Social: Venice inference with web search (X/Twitter sentiment)\n * Fundamental: Messari market data (x402, ~$0.20)\n *\n * No technical analysis — purely signal-driven.\n */\n\nimport type { Address } from \"viem\";\nimport { getResearchProvider } from \"../providers/research/index.js\";\nimport type { ResearchResult } from \"../providers/research/index.js\";\nimport { chatCompletion } from \"./venice.js\";\n\n// ── Types ──\n\nexport type SignalAction = \"buy\" | \"sell\" | \"hold\";\nexport type SignalSource = \"onchain\" | \"social\" | \"fundamental\";\n\nexport interface Signal {\n source: SignalSource;\n name: string;\n value: number; // -1.0 (bearish) to +1.0 (bullish)\n weight: number; // contribution to composite score\n raw: Record<string, unknown>;\n}\n\nexport interface SignalResult {\n action: SignalAction;\n confidence: number; // 0.0 to 1.0\n compositeScore: number; // -1.0 to +1.0\n signals: Signal[];\n costUsdc: string; // total x402 cost\n timestamp: number;\n}\n\nexport interface SignalConfig {\n buyThreshold: number; // composite score above this → buy (default 0.3)\n sellThreshold: number; // composite score below this → sell (default -0.2)\n}\n\nconst DEFAULT_CONFIG: SignalConfig = {\n buyThreshold: 0.3,\n sellThreshold: -0.2,\n};\n\n// ── Main Entry Point ──\n\n/**\n * Analyze a token using on-chain, social, and fundamental signals.\n * Runs all three data sources in parallel for speed.\n */\nexport async function analyzeToken(\n tokenAddress: Address,\n tokenSymbol: string,\n config?: Partial<SignalConfig>,\n): Promise<SignalResult> {\n const cfg = { ...DEFAULT_CONFIG, ...config };\n let totalCostUsdc = 0;\n\n // Run all three signals in parallel — each returns a Signal + cost\n const [onChain, social, fundamental] = await Promise.allSettled([\n getOnChainSignal(tokenSymbol),\n getSocialSignal(tokenAddress, tokenSymbol),\n getFundamentalSignal(tokenSymbol),\n ]);\n\n const signals: Signal[] = [];\n\n if (onChain.status === \"fulfilled\") {\n signals.push(onChain.value.signal);\n totalCostUsdc += onChain.value.costUsdc;\n }\n\n if (social.status === \"fulfilled\") {\n signals.push(social.value.signal);\n totalCostUsdc += social.value.costUsdc;\n }\n\n if (fundamental.status === \"fulfilled\") {\n signals.push(fundamental.value.signal);\n totalCostUsdc += fundamental.value.costUsdc;\n }\n\n // Compute composite score\n let weightedSum = 0;\n let totalWeight = 0;\n for (const s of signals) {\n weightedSum += s.value * s.weight;\n totalWeight += s.weight;\n }\n const compositeScore = totalWeight > 0 ? weightedSum / totalWeight : 0;\n\n // Confidence = average absolute signal strength\n const confidence =\n signals.length > 0\n ? signals.reduce((sum, s) => sum + Math.abs(s.value), 0) / signals.length\n : 0;\n\n // Decision\n let action: SignalAction = \"hold\";\n if (compositeScore >= cfg.buyThreshold && confidence >= 0.5) {\n action = \"buy\";\n } else if (compositeScore <= cfg.sellThreshold) {\n action = \"sell\";\n }\n\n return {\n action,\n confidence: Math.min(confidence, 1),\n compositeScore,\n signals,\n costUsdc: totalCostUsdc.toFixed(4),\n timestamp: Math.floor(Date.now() / 1000),\n };\n}\n\n// ── Individual Signal Sources ──\n\ninterface SignalWithCost {\n signal: Signal;\n costUsdc: number;\n}\n\n/**\n * On-chain signal: Nansen smart-money net flow.\n * Positive net flow (whales buying) → bullish.\n */\nasync function getOnChainSignal(tokenSymbol: string): Promise<SignalWithCost> {\n const nansen = getResearchProvider(\"nansen\");\n let result: ResearchResult;\n try {\n result = await nansen.query({ type: \"smart-money\", target: tokenSymbol });\n } catch {\n return {\n signal: {\n source: \"onchain\",\n name: \"smart_money_net_flow\",\n value: 0,\n weight: 0.40,\n raw: { error: \"nansen query failed\" },\n },\n costUsdc: 0,\n };\n }\n\n const data = result.data as Record<string, unknown>;\n\n // Extract net flow value — Nansen returns flow data in various formats\n const netFlow = extractNetFlow(data);\n // Normalize to -1..+1 range (clamp large values)\n const value = Math.max(-1, Math.min(1, netFlow));\n\n return {\n signal: {\n source: \"onchain\",\n name: \"smart_money_net_flow\",\n value,\n weight: 0.40,\n raw: data,\n },\n costUsdc: Number(result.costUsdc) || 0.06,\n };\n}\n\n/**\n * Social signal: Venice inference with web search for X/Twitter sentiment.\n */\nasync function getSocialSignal(\n tokenAddress: Address,\n tokenSymbol: string,\n): Promise<SignalWithCost> {\n try {\n const result = await chatCompletion({\n model: \"llama-3.3-70b\",\n messages: [\n {\n role: \"system\",\n content: `You are a crypto market sentiment analyst. Analyze current Twitter/X discourse about the given token. Return ONLY valid JSON with no markdown: {\"sentiment\": <number from -1.0 to 1.0>, \"reasoning\": \"<brief explanation>\", \"tweetCount\": <estimated tweets in last 24h>, \"keyTopics\": [\"topic1\", \"topic2\"]}. Positive sentiment means bullish discussion, influencer endorsements, positive news. Negative means FUD, rug pull warnings, community exodus. If you cannot find data, return {\"sentiment\": 0, \"reasoning\": \"insufficient data\", \"tweetCount\": 0, \"keyTopics\": []}.`,\n },\n {\n role: \"user\",\n content: `Analyze current X/Twitter sentiment for token ${tokenSymbol} (contract: ${tokenAddress} on Base chain). What is the social consensus in the last 24 hours?`,\n },\n ],\n temperature: 0.3,\n maxTokens: 500,\n enableWebSearch: true,\n });\n\n // Parse JSON from response\n const parsed = parseJsonResponse(result.content);\n const sentiment = typeof parsed.sentiment === \"number\"\n ? Math.max(-1, Math.min(1, parsed.sentiment))\n : 0;\n\n return {\n signal: {\n source: \"social\",\n name: \"x_sentiment\",\n value: sentiment,\n weight: 0.30,\n raw: parsed as Record<string, unknown>,\n },\n costUsdc: 0, // Venice inference is prepaid via sVVV, no per-call cost\n };\n } catch {\n return {\n signal: {\n source: \"social\",\n name: \"x_sentiment\",\n value: 0,\n weight: 0.30,\n raw: { error: \"venice inference failed\" },\n },\n costUsdc: 0,\n };\n }\n}\n\n/**\n * Fundamental signal: Messari market data — volume spike, market cap, ATH distance.\n */\nasync function getFundamentalSignal(\n tokenSymbol: string,\n): Promise<SignalWithCost> {\n const messari = getResearchProvider(\"messari\");\n let result: ResearchResult;\n try {\n result = await messari.query({ type: \"market\", target: tokenSymbol });\n } catch {\n return {\n signal: {\n source: \"fundamental\",\n name: \"market_fundamentals\",\n value: 0,\n weight: 0.30,\n raw: { error: \"messari query failed\" },\n },\n costUsdc: 0,\n };\n }\n\n const data = result.data as Record<string, unknown>;\n const value = scoreFundamentals(data);\n\n return {\n signal: {\n source: \"fundamental\",\n name: \"market_fundamentals\",\n value,\n weight: 0.30,\n raw: data,\n },\n costUsdc: Number(result.costUsdc) || 0.20,\n };\n}\n\n// ── Scoring Helpers ──\n\n/**\n * Extract net flow from Nansen smart-money response.\n * Normalizes to -1..+1 range.\n */\nfunction extractNetFlow(data: Record<string, unknown>): number {\n // Nansen returns various formats — try common paths\n const netFlow =\n (data.netFlow as number) ??\n (data.net_flow as number) ??\n ((data.inflow as number ?? 0) - (data.outflow as number ?? 0));\n\n if (typeof netFlow !== \"number\" || isNaN(netFlow)) return 0;\n\n // Normalize: scale by rough heuristic (> $1M net flow = strong signal)\n const normalized = netFlow / 1_000_000;\n return Math.max(-1, Math.min(1, normalized));\n}\n\n/**\n * Score fundamental data from Messari.\n *\n * Factors:\n * - Volume spike (24h vs 7d avg): > 3x = +0.5, > 2x = +0.25\n * - Market cap: < $10M with volume = +0.3 (high upside)\n * - ATH distance: > 80% down = +0.2 (recovery play), < 10% = -0.3 (possible top)\n */\nfunction scoreFundamentals(data: Record<string, unknown>): number {\n let score = 0;\n\n // Try to extract market data from nested Messari response\n const marketData = (data.marketData ?? data.market_data ?? data) as Record<string, unknown>;\n const athData = (data.allTimeHigh ?? data.ath ?? {}) as Record<string, unknown>;\n\n // Volume spike\n const vol24h = toNumber(marketData.volume_last_24_hours ?? marketData.volume24h);\n const vol7d = toNumber(marketData.volume_last_7_days ?? marketData.volume7d);\n if (vol24h > 0 && vol7d > 0) {\n const dailyAvg7d = vol7d / 7;\n const ratio = vol24h / dailyAvg7d;\n if (ratio > 3) score += 0.5;\n else if (ratio > 2) score += 0.25;\n else if (ratio < 0.5) score -= 0.25;\n }\n\n // Market cap\n const mcap = toNumber(marketData.current_marketcap_usd ?? marketData.marketCap);\n if (mcap > 0 && mcap < 10_000_000 && vol24h > 0) {\n score += 0.3; // small cap with volume = high upside potential\n } else if (mcap > 1_000_000_000) {\n score -= 0.15; // large cap = less upside for memecoins\n }\n\n // ATH distance\n const currentPrice = toNumber(marketData.price_usd ?? marketData.currentPrice);\n const athPrice = toNumber(athData.price ?? athData.athPrice);\n if (currentPrice > 0 && athPrice > 0) {\n const athDistance = ((athPrice - currentPrice) / athPrice) * 100;\n if (athDistance > 80) score += 0.2; // deep discount recovery play\n else if (athDistance < 10) score -= 0.3; // near ATH, potential top\n }\n\n return Math.max(-1, Math.min(1, score));\n}\n\nfunction toNumber(v: unknown): number {\n if (typeof v === \"number\") return v;\n if (typeof v === \"string\") return Number(v) || 0;\n return 0;\n}\n\n/**\n * Parse a JSON response from Venice, handling markdown fences and extra text.\n */\nfunction parseJsonResponse(content: string): Record<string, unknown> {\n // Strip markdown code fences if present\n let cleaned = content.trim();\n if (cleaned.startsWith(\"```\")) {\n cleaned = cleaned.replace(/^```(?:json)?\\n?/, \"\").replace(/\\n?```$/, \"\");\n }\n // Find the first { ... } block\n const start = cleaned.indexOf(\"{\");\n const end = cleaned.lastIndexOf(\"}\");\n if (start >= 0 && end > start) {\n try {\n return JSON.parse(cleaned.slice(start, end + 1));\n } catch {\n // Fall through\n }\n }\n return { sentiment: 0, reasoning: \"failed to parse response\", raw: content };\n}\n","/**\n * Signal-based exit strategy for memecoin trades.\n *\n * Pure computation — no network calls. Evaluates a priority-ordered\n * set of exit conditions against the current position state.\n */\n\nimport type { SignalResult } from \"./signals.js\";\n\nexport interface ExitConfig {\n stopLossPct: number; // exit if PnL drops below this % (default 10)\n trailingStopPct: number; // exit if drawdown from high-water exceeds this % (0 = disabled)\n takeProfitPct: number; // exit if PnL reaches this % (0 = disabled, use signal exit)\n deadlineUnix: number; // force exit before this unix timestamp (0 = none)\n signalExitEnabled: boolean; // exit when signals flip bearish (default true)\n}\n\nexport type ExitReason =\n | \"stop_loss\"\n | \"trailing_stop\"\n | \"take_profit\"\n | \"deadline\"\n | \"signal_bearish\"\n | \"hold\";\n\nexport interface ExitCheck {\n shouldExit: boolean;\n reason: ExitReason;\n currentPnlPct: number;\n highWaterPnlPct: number;\n}\n\nexport const DEFAULT_EXIT_CONFIG: ExitConfig = {\n stopLossPct: 10,\n trailingStopPct: 0,\n takeProfitPct: 0,\n deadlineUnix: 0,\n signalExitEnabled: true,\n};\n\n/**\n * Check whether a position should be exited.\n *\n * Priority order (first match wins):\n * 1. Deadline passed\n * 2. Stop loss\n * 3. Trailing stop (drawdown from high-water mark)\n * 4. Take profit\n * 5. Signal-based (bearish signals with sufficient confidence)\n * 6. Hold\n */\nexport function checkExit(\n entryPrice: number,\n currentPrice: number,\n highWaterPrice: number,\n config: ExitConfig,\n signalResult?: SignalResult,\n): ExitCheck {\n if (entryPrice <= 0) {\n return { shouldExit: false, reason: \"hold\", currentPnlPct: 0, highWaterPnlPct: 0 };\n }\n\n const currentPnlPct = ((currentPrice - entryPrice) / entryPrice) * 100;\n const highWaterPnlPct = ((highWaterPrice - entryPrice) / entryPrice) * 100;\n\n // 1. Deadline\n if (config.deadlineUnix > 0 && Date.now() / 1000 > config.deadlineUnix) {\n return { shouldExit: true, reason: \"deadline\", currentPnlPct, highWaterPnlPct };\n }\n\n // 2. Stop loss\n if (currentPnlPct <= -config.stopLossPct) {\n return { shouldExit: true, reason: \"stop_loss\", currentPnlPct, highWaterPnlPct };\n }\n\n // 3. Trailing stop\n if (config.trailingStopPct > 0 && highWaterPrice > 0) {\n const drawdownPct = ((highWaterPrice - currentPrice) / highWaterPrice) * 100;\n if (drawdownPct >= config.trailingStopPct) {\n return { shouldExit: true, reason: \"trailing_stop\", currentPnlPct, highWaterPnlPct };\n }\n }\n\n // 4. Take profit\n if (config.takeProfitPct > 0 && currentPnlPct >= config.takeProfitPct) {\n return { shouldExit: true, reason: \"take_profit\", currentPnlPct, highWaterPnlPct };\n }\n\n // 5. Signal-based exit\n if (\n config.signalExitEnabled &&\n signalResult &&\n signalResult.action === \"sell\" &&\n signalResult.confidence > 0.4\n ) {\n return { shouldExit: true, reason: \"signal_bearish\", currentPnlPct, highWaterPnlPct };\n }\n\n // 6. Hold\n return { shouldExit: false, reason: \"hold\", currentPnlPct, highWaterPnlPct };\n}\n","/**\n * Position tracking for memecoin trades.\n *\n * Persists open and closed positions to ~/.sherwood/config.json.\n * Uses Uniswap QuoterV2 for current price lookups.\n */\n\nimport type { Address } from \"viem\";\nimport { formatUnits, parseUnits } from \"viem\";\nimport { loadConfig, saveConfig } from \"./config.js\";\nimport { getQuote } from \"./quote.js\";\nimport { TOKENS } from \"./addresses.js\";\nimport type { ExitConfig } from \"./exit-strategy.js\";\n\nexport interface Position {\n tokenAddress: Address;\n tokenSymbol: string;\n tokenDecimals: number;\n amountIn: string; // amount spent (human-readable, e.g. \"500\")\n amountOut: string; // tokens received (raw bigint as string)\n entryPrice: number; // input token per target token at entry\n highWaterPrice: number; // highest observed price since entry\n feeTier: number; // Uniswap fee tier used\n openedAt: number; // unix timestamp\n txHash: string; // buy tx hash\n exitConfig: ExitConfig; // per-position exit parameters\n inputTokenAddress?: Address; // token used to buy (default: USDC for backwards compat)\n inputTokenSymbol?: string; // symbol of input token (default: \"USDC\")\n inputTokenDecimals?: number; // decimals of input token (default: 6)\n}\n\nexport interface ClosedPosition extends Position {\n exitPrice: number;\n closedAt: number;\n exitTxHash: string;\n exitReason: string;\n pnlUsdc: number;\n pnlPct: number;\n}\n\n// ── Reads ──\n\nexport function getOpenPositions(): Position[] {\n const config = loadConfig();\n return (config.positions as Position[] | undefined) ?? [];\n}\n\nexport function getClosedPositions(): ClosedPosition[] {\n const config = loadConfig();\n return (config.closedPositions as ClosedPosition[] | undefined) ?? [];\n}\n\n// ── Writes ──\n\nexport function addPosition(pos: Position): void {\n const config = loadConfig();\n const positions = (config.positions as Position[] | undefined) ?? [];\n positions.push(pos);\n config.positions = positions;\n saveConfig(config);\n}\n\nexport function closePosition(\n tokenAddress: Address,\n exitData: {\n exitPrice: number;\n closedAt: number;\n exitTxHash: string;\n exitReason: string;\n pnlUsdc: number;\n pnlPct: number;\n },\n): void {\n const config = loadConfig();\n const positions = (config.positions as Position[] | undefined) ?? [];\n const idx = positions.findIndex(\n (p) => p.tokenAddress.toLowerCase() === tokenAddress.toLowerCase(),\n );\n if (idx === -1) {\n throw new Error(`No open position for ${tokenAddress}`);\n }\n\n const [pos] = positions.splice(idx, 1);\n const closed: ClosedPosition = { ...pos, ...exitData };\n\n const closedPositions = (config.closedPositions as ClosedPosition[] | undefined) ?? [];\n closedPositions.push(closed);\n\n config.positions = positions;\n config.closedPositions = closedPositions;\n saveConfig(config);\n}\n\nexport function updateHighWater(tokenAddress: Address, price: number): void {\n const config = loadConfig();\n const positions = (config.positions as Position[] | undefined) ?? [];\n const pos = positions.find(\n (p) => p.tokenAddress.toLowerCase() === tokenAddress.toLowerCase(),\n );\n if (pos && price > pos.highWaterPrice) {\n pos.highWaterPrice = price;\n config.positions = positions;\n saveConfig(config);\n }\n}\n\n// ── Price Lookup ──\n\n/**\n * Get the current USDC price of one token via Uniswap QuoterV2.\n * Quotes 1 full token unit against USDC.\n */\nexport async function getCurrentPrice(\n tokenAddress: Address,\n tokenDecimals: number,\n feeTier: number,\n): Promise<number> {\n const oneToken = parseUnits(\"1\", tokenDecimals);\n const usdc = TOKENS().USDC;\n\n const { amountOut } = await getQuote({\n tokenIn: tokenAddress,\n tokenOut: usdc,\n amountIn: oneToken,\n fee: feeTier,\n });\n\n // USDC has 6 decimals\n return Number(formatUnits(amountOut, 6));\n}\n"],"mappings":"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","names":["isAddress","parseUnits","formatUnits","ETH_ADDRESS","formatUnits","formatUnits","isAddress","client","parseUnits","formatUnits","writeContractWithRetry"]}
|
|
@@ -22,14 +22,14 @@ import {
|
|
|
22
22
|
removeDepositor,
|
|
23
23
|
setAgentFeeBps,
|
|
24
24
|
setVaultAddress
|
|
25
|
-
} from "./chunk-
|
|
26
|
-
import "./chunk-
|
|
27
|
-
import "./chunk-
|
|
28
|
-
import "./chunk-
|
|
29
|
-
import "./chunk-
|
|
30
|
-
import "./chunk-
|
|
25
|
+
} from "./chunk-SNR5R5TO.js";
|
|
26
|
+
import "./chunk-JUVXLTL2.js";
|
|
27
|
+
import "./chunk-BOC7VB5B.js";
|
|
28
|
+
import "./chunk-DNRIKCJ5.js";
|
|
29
|
+
import "./chunk-QRMZRAMG.js";
|
|
30
|
+
import "./chunk-PVTZMRC6.js";
|
|
31
31
|
import "./chunk-3TZIOAPH.js";
|
|
32
|
-
import "./chunk-
|
|
32
|
+
import "./chunk-F3MDCUGO.js";
|
|
33
33
|
import "./chunk-VR4VHX4D.js";
|
|
34
34
|
export {
|
|
35
35
|
approveDepositor,
|
|
@@ -56,4 +56,4 @@ export {
|
|
|
56
56
|
setAgentFeeBps,
|
|
57
57
|
setVaultAddress
|
|
58
58
|
};
|
|
59
|
-
//# sourceMappingURL=vault-
|
|
59
|
+
//# sourceMappingURL=vault-UCFFOOTS.js.map
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getTextRecord
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-MQ55QOGD.js";
|
|
4
|
+
import "./chunk-DNRIKCJ5.js";
|
|
5
5
|
import {
|
|
6
6
|
getAccount
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-QRMZRAMG.js";
|
|
8
8
|
import {
|
|
9
9
|
getChainConfig
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-PVTZMRC6.js";
|
|
11
11
|
import {
|
|
12
12
|
cacheGroupId,
|
|
13
13
|
getCachedGroupId,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
requirePrivateKey,
|
|
17
17
|
saveConfig
|
|
18
18
|
} from "./chunk-3TZIOAPH.js";
|
|
19
|
-
import "./chunk-
|
|
19
|
+
import "./chunk-F3MDCUGO.js";
|
|
20
20
|
|
|
21
21
|
// src/lib/xmtp.ts
|
|
22
22
|
import fs from "fs";
|
|
@@ -315,4 +315,4 @@ export {
|
|
|
315
315
|
sendReaction,
|
|
316
316
|
streamMessages
|
|
317
317
|
};
|
|
318
|
-
//# sourceMappingURL=xmtp-
|
|
318
|
+
//# sourceMappingURL=xmtp-S7IGTIMZ.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sherwoodagent/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "CLI for agent-managed investment funds
|
|
3
|
+
"version": "0.84.0",
|
|
4
|
+
"description": "CLI for agent-managed investment funds \u2014 onchain DeFi funds with XMTP chat",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"sherwood": "./dist/index.js"
|
|
@@ -19,6 +19,9 @@
|
|
|
19
19
|
"directory": "cli"
|
|
20
20
|
},
|
|
21
21
|
"license": "MIT",
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=20"
|
|
24
|
+
},
|
|
22
25
|
"scripts": {
|
|
23
26
|
"prepublishOnly": "npm run build",
|
|
24
27
|
"build": "tsup",
|
|
@@ -35,7 +38,6 @@
|
|
|
35
38
|
"dependencies": {
|
|
36
39
|
"@anthropic-ai/sdk": "^0.90.0",
|
|
37
40
|
"@inquirer/prompts": "^8.3.2",
|
|
38
|
-
"@sherwoodagent/sdk": "file:../sdk",
|
|
39
41
|
"@x402/evm": "^2.7.0",
|
|
40
42
|
"@x402/fetch": "^2.7.0",
|
|
41
43
|
"@xmtp/node-sdk": "^6.0.0",
|
|
@@ -52,6 +54,7 @@
|
|
|
52
54
|
"@xmtp/node-bindings": "1.10.0-dev.97e86c6"
|
|
53
55
|
},
|
|
54
56
|
"devDependencies": {
|
|
57
|
+
"@sherwoodagent/sdk": "file:../sdk",
|
|
55
58
|
"@scure/bip32": "^1.6.2",
|
|
56
59
|
"@scure/bip39": "^1.5.4",
|
|
57
60
|
"@types/node": "^22.0.0",
|
|
@@ -15,13 +15,14 @@
|
|
|
15
15
|
* Hosts on glibc 2.36 (e.g. Debian 12 containers Hermes often runs in)
|
|
16
16
|
* then see `GLIBC_2.38 not found` on any XMTP call.
|
|
17
17
|
*
|
|
18
|
-
* This postinstall forcibly replaces the installed binding with the
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
18
|
+
* This postinstall forcibly replaces the installed binding with the pin
|
|
19
|
+
* by packing the tarball into a temp dir and extracting it over
|
|
20
|
+
* node_modules/@xmtp/node-bindings. We do NOT run `npm install` against
|
|
21
|
+
* the CLI tree here: a nested reify during `npm i -g` leaves Arborist
|
|
22
|
+
* link nodes with a null target on npm 11 / Node 24, and the outer
|
|
23
|
+
* rebuild then fails.
|
|
23
24
|
*
|
|
24
|
-
* The
|
|
25
|
+
* The extract hoists the dev binding to <cli>/node_modules/@xmtp/
|
|
25
26
|
* node-bindings, but @xmtp/node-sdk's own nested copy at <cli>/
|
|
26
27
|
* node_modules/@xmtp/node-sdk/node_modules/@xmtp/node-bindings persists
|
|
27
28
|
* — `npm dedupe` won't collapse it because the pre-release fails the
|
|
@@ -81,10 +82,25 @@ try {
|
|
|
81
82
|
process.stderr.write(
|
|
82
83
|
`[sherwood-cli] postinstall: forcing ${PINNED} to work around npm global-install override limitation\n`,
|
|
83
84
|
);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
// Pack into a temp dir so we never reify the parent install tree.
|
|
86
|
+
const os = require("node:os");
|
|
87
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "sherwood-xmtp-pin-"));
|
|
88
|
+
try {
|
|
89
|
+
execSync(`npm pack ${PINNED} --pack-destination "${tmp}"`, {
|
|
90
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
91
|
+
cwd: tmp,
|
|
92
|
+
});
|
|
93
|
+
const tgz = fs.readdirSync(tmp).find((f) => f.endsWith(".tgz"));
|
|
94
|
+
if (!tgz) throw new Error("npm pack produced no tarball");
|
|
95
|
+
const dest = path.join(cliRoot, "node_modules", "@xmtp", "node-bindings");
|
|
96
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
97
|
+
execSync(
|
|
98
|
+
`tar -xzf "${path.join(tmp, tgz)}" --strip-components=1 -C "${dest}"`,
|
|
99
|
+
{ stdio: ["ignore", "pipe", "pipe"] },
|
|
100
|
+
);
|
|
101
|
+
} finally {
|
|
102
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
103
|
+
}
|
|
88
104
|
|
|
89
105
|
const rootNodeModules = path.join(cliRoot, "node_modules");
|
|
90
106
|
const hoistedBinding = path.join(rootNodeModules, "@xmtp", "node-bindings");
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/client.ts","../src/lib/errors.ts"],"sourcesContent":["/**\n * viem client factory — resolves chain and RPC from the network module.\n * Private key is read from ~/.sherwood/config.json (set via `sherwood config set --private-key`),\n * with PRIVATE_KEY env var as fallback.\n */\n\n// dotenv loaded at entrypoint\nimport type { Hex, TransactionReceipt } from \"viem\";\nimport { createPublicClient, createWalletClient, fallback, http } from \"viem\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport { getChain, getRpcUrls, getMinGasReserve } from \"./network.js\";\nimport { requirePrivateKey } from \"./config.js\";\nimport { formatContractError } from \"./errors.js\";\nexport { formatContractError } from \"./errors.js\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _publicClient: any = null;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _walletClient: any = null;\n\n/**\n * Build a viem fallback transport over the chain's RPC URL list.\n * Transparently advances to the next URL on rate-limit / network errors\n * (issue #182). `retryCount: 0` on the inner `http` avoids wasting 10+s\n * spinning on a dead RPC before the fallback layer advances.\n */\nfunction buildTransport() {\n const urls = getRpcUrls();\n return fallback(\n urls.map((url) => http(url, { retryCount: 0, timeout: 8_000 })),\n { rank: false, retryCount: 0 },\n );\n}\n\nexport function getPublicClient() {\n const chain = getChain();\n // Auto-invalidate if network changed since last creation\n if (_publicClient && _publicClient.chain?.id !== chain.id) {\n _publicClient = null;\n }\n if (!_publicClient) {\n _publicClient = createPublicClient({\n chain,\n transport: buildTransport(),\n });\n }\n return _publicClient as ReturnType<typeof createPublicClient>;\n}\n\nexport function getWalletClient() {\n const chain = getChain();\n // Auto-invalidate if network changed since last creation\n if (_walletClient && _walletClient.chain?.id !== chain.id) {\n _walletClient = null;\n }\n if (!_walletClient) {\n const account = privateKeyToAccount(requirePrivateKey());\n _walletClient = createWalletClient({\n account,\n chain,\n transport: buildTransport(),\n });\n }\n return _walletClient as ReturnType<typeof createWalletClient>;\n}\n\n/**\n * Reset cached clients. Required for tests that call setNetwork()\n * after a client was already created.\n */\nexport function resetClients() {\n _publicClient = null;\n _walletClient = null;\n}\n\nexport function getAccount() {\n return privateKeyToAccount(requirePrivateKey());\n}\n\n/**\n * Estimate EIP-1559 fees with a 20% buffer to avoid stuck txs on Base gas spikes.\n */\nexport async function estimateFeesWithBuffer() {\n const client = getPublicClient();\n const { maxFeePerGas, maxPriorityFeePerGas } =\n await client.estimateFeesPerGas();\n let fee = (maxFeePerGas * 120n) / 100n;\n let tip = (maxPriorityFeePerGas * 120n) / 100n;\n // #462: some RPCs (Robinhood testnet after activity bursts) suggest fees\n // orders of magnitude above the live base fee; viem's worst-case prefund\n // check (gas × maxFeePerGas) then rejects large txs from small wallets even\n // though real cost is negligible. Clamp to 10× live base, but ONLY when the\n // suggestion exceeds 1000× base (never true on healthy chains — Base gas\n // spikes stay untouched). Best-effort: a failed getBlock skips the clamp.\n let base: bigint | null | undefined;\n try {\n base = (await client.getBlock()).baseFeePerGas;\n } catch {\n base = undefined;\n }\n if (base !== null && base !== undefined && base > 0n && fee > base * 1000n) {\n fee = base * 10n;\n if (tip > fee) tip = fee;\n }\n return { maxFeePerGas: fee, maxPriorityFeePerGas: tip };\n}\n\n/**\n * Conservative per-op gas-unit budgets for the native-ETH-wrap deposit/redeem\n * sequences. Multiplied by the live buffered `maxFeePerGas` (× a safety factor)\n * to derive the ETH gas cushion — replacing the old hardcoded 0.0005-ETH,\n * Base-calibrated constant that rejected valid deposits on low-fee chains\n * (Robinhood testnet, ~14-wei base fee). Deliberately generous; the realized\n * cost is a fraction of these on any chain.\n */\nexport const GAS_UNITS = {\n wrap: 55_000n,\n approve: 60_000n,\n deposit: 250_000n,\n redeem: 250_000n,\n} as const;\n\n/**\n * Derive the ETH gas cushion from live chain gas instead of a fixed constant:\n *\n * cushion = gasUnits × bufferedMaxFeePerGas × safetyFactor, floored at the\n * active chain's `minGasReserve`.\n *\n * `gasUnits` is the summed budget for the tx sequence (e.g. wrap+approve+deposit\n * via `GAS_UNITS`). Falls back to the per-chain floor when the live fee estimate\n * is unavailable (RPC error). On a ~14-wei-base-fee chain the derived term is\n * negligible, so the tiny per-chain floor dominates; on Base the live term\n * scales with the gas market and the Base-scale floor is the lower bound.\n */\nexport async function estimateGasCushion(\n gasUnits: bigint,\n safetyFactor = 2n,\n): Promise<bigint> {\n const floor = getMinGasReserve();\n try {\n const { maxFeePerGas } = await estimateFeesWithBuffer();\n const derived = gasUnits * maxFeePerGas * safetyFactor;\n return derived > floor ? derived : floor;\n } catch {\n return floor;\n }\n}\n\n// ── Nonce management + retry helpers ──\n//\n// Handles: nonce collisions, underpriced replacements, stuck pending txs.\n// Gas bump ceiling: base * 1.2 (buffer) * 1.1^3 (max retries) ≈ 1.6x base fee.\n\nconst MAX_RETRIES = 3;\nconst RETRY_DELAY_MS = 1500; // backoff between retries\nconst STUCK_NONCE_CONFIRM_DELAY_MS = 2500; // staleness check delay\nconst GAS_BUMP_NUMERATOR = 110n;\nconst GAS_BUMP_DENOMINATOR = 100n;\n\nfunction isUnderpricedError(msg: string): boolean {\n return msg.includes(\"replacement transaction underpriced\");\n}\n\nfunction isNonceStaleError(msg: string): boolean {\n return msg.includes(\"nonce too low\") || msg.includes(\"NONCE_EXPIRED\");\n}\n\nfunction isRetryableError(err: unknown): boolean {\n const msg = err instanceof Error ? err.message : String(err);\n return isUnderpricedError(msg) || isNonceStaleError(msg);\n}\n\nfunction bumpFees(fees: { maxFeePerGas: bigint; maxPriorityFeePerGas: bigint }) {\n return {\n maxFeePerGas: (fees.maxFeePerGas * GAS_BUMP_NUMERATOR) / GAS_BUMP_DENOMINATOR,\n maxPriorityFeePerGas: (fees.maxPriorityFeePerGas * GAS_BUMP_NUMERATOR) / GAS_BUMP_DENOMINATOR,\n };\n}\n\n// ── Stuck nonce detection ──\n\n/**\n * Check if the wallet has a stuck nonce (pending tx count > confirmed tx count).\n * Returns the stuck nonce number, or null if the wallet is clean.\n *\n * Includes a staleness guard: if pending > confirmed, waits ~2.5s and re-checks\n * to avoid false positives from propagation delays.\n */\nexport async function detectStuckNonce(): Promise<number | null> {\n const client = getPublicClient();\n const address = getAccount().address;\n const [confirmed, pending] = await Promise.all([\n client.getTransactionCount({ address, blockTag: \"latest\" }),\n client.getTransactionCount({ address, blockTag: \"pending\" }),\n ]);\n if (pending <= confirmed) return null;\n\n // Staleness guard: re-check after a short delay to avoid false positives\n await new Promise((r) => setTimeout(r, STUCK_NONCE_CONFIRM_DELAY_MS));\n const [confirmed2, pending2] = await Promise.all([\n client.getTransactionCount({ address, blockTag: \"latest\" }),\n client.getTransactionCount({ address, blockTag: \"pending\" }),\n ]);\n return pending2 > confirmed2 ? confirmed2 : null;\n}\n\n/**\n * Clear a single stuck nonce by sending a 0-value self-transfer with aggressively bumped gas.\n * Uses 5x the buffered fee estimate to guarantee replacement even if the original tx\n * was sent during a gas spike (EIP-1559 requires >= 110% of original maxPriorityFeePerGas).\n */\nasync function unstickWalletSingle(): Promise<Hex> {\n const stuckNonce = await detectStuckNonce();\n if (stuckNonce === null) {\n throw new Error(\"No stuck nonce detected — wallet is clean.\");\n }\n\n console.warn(` Unsticking wallet: replacing stuck tx at nonce ${stuckNonce}...`);\n const wallet = getWalletClient();\n const account = getAccount();\n\n // Use 5x gas buffer to guarantee replacement even for txs sent during gas spikes\n const { maxFeePerGas, maxPriorityFeePerGas } = await estimateFeesWithBuffer();\n const hash = await wallet.sendTransaction({\n account,\n chain: wallet.chain,\n to: account.address,\n value: 0n,\n nonce: stuckNonce,\n maxFeePerGas: maxFeePerGas * 5n,\n maxPriorityFeePerGas: maxPriorityFeePerGas * 5n,\n });\n\n const client = getPublicClient();\n await client.waitForTransactionReceipt({ hash });\n console.warn(` Wallet unstuck (nonce ${stuckNonce} replaced).`);\n return hash;\n}\n\n/**\n * Unstick a wallet by clearing ALL stuck nonces, not just the first one.\n * Loops until pending == confirmed nonce count.\n */\nexport async function unstickWallet(): Promise<Hex[]> {\n const hashes: Hex[] = [];\n while ((await detectStuckNonce()) !== null) {\n hashes.push(await unstickWalletSingle());\n }\n if (hashes.length === 0) {\n throw new Error(\"No stuck nonce detected — wallet is clean.\");\n }\n return hashes;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype TxSender = (params: any) => Promise<Hex>;\n\n/**\n * Shared retry loop: explicit nonce + EIP-1559 fee buffer + gas-bump on underpriced errors.\n * On \"nonce too low\" / \"NONCE_EXPIRED\", re-fetches nonce from pending state before retrying.\n * Also detects stuck nonces before sending and auto-unsticks the wallet.\n */\nasync function withRetry(send: TxSender, txParams: Record<string, unknown>): Promise<Hex> {\n const client = getPublicClient();\n const account = getAccount();\n let fees = await estimateFeesWithBuffer();\n\n // Auto-detect and clear ALL stuck nonces before attempting the tx\n while ((await detectStuckNonce()) !== null) {\n await unstickWalletSingle();\n }\n\n let nonce = await client.getTransactionCount({ address: account.address, blockTag: \"pending\" });\n\n for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {\n try {\n return await send({ ...txParams, ...fees, nonce });\n } catch (err) {\n if (attempt >= MAX_RETRIES || !isRetryableError(err)) {\n // Decode contract revert into a human-readable message before throwing\n throw new Error(formatContractError(err));\n }\n\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(` Retry ${attempt + 1}/${MAX_RETRIES}: ${isNonceStaleError(msg) ? \"refreshing nonce\" : \"bumping gas\"}...`);\n\n // Backoff between retries to let mempool settle\n await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));\n\n if (isNonceStaleError(msg)) {\n // Fresh nonce = fresh tx, no replacement needed — only bump fees for underpriced errors\n nonce = await client.getTransactionCount({ address: account.address, blockTag: \"pending\" });\n } else {\n fees = bumpFees(fees);\n }\n }\n }\n throw new Error(\"withRetry: exhausted retries\");\n}\n\n/**\n * Send a raw transaction with automatic gas-bump retry on nonce/underpriced errors.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function sendTxWithRetry(txParams: Record<string, any>): Promise<Hex> {\n const wallet = getWalletClient();\n return withRetry((p) => wallet.sendTransaction(p), txParams);\n}\n\n/**\n * Call writeContract with automatic gas-bump retry on nonce/underpriced errors.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function writeContractWithRetry(txParams: Record<string, any>): Promise<Hex> {\n const wallet = getWalletClient();\n return withRetry((p) => wallet.writeContract(p), txParams);\n}\n\n/**\n * Wait for a tx receipt. On timeout, checks for stuck nonce and auto-unsticks.\n *\n * **Important**: After unsticking, the error is still re-thrown because the original\n * tx is lost. Callers should use `writeContractWithRetry` / `sendTxWithRetry` which\n * re-fetch nonces automatically. Do NOT manually retry after this throws — use the\n * retry-aware wrappers instead.\n */\nexport async function waitForReceipt(hash: Hex): Promise<TransactionReceipt> {\n const client = getPublicClient();\n try {\n return await client.waitForTransactionReceipt({ hash });\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (err: any) {\n // If receipt wait times out, check for stuck nonce\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes(\"timeout\") || msg.includes(\"Timed out\")) {\n if ((await detectStuckNonce()) !== null) {\n console.warn(` Tx ${hash} appears stuck — attempting to unstick wallet...`);\n while ((await detectStuckNonce()) !== null) {\n await unstickWalletSingle();\n }\n }\n }\n throw err;\n }\n}\n","/**\n * Contract error decoding — turns raw reverts into human-readable messages.\n *\n * Uses viem's decodeErrorResult() against a combined ABI of all custom errors\n * from SyndicateVault, SyndicateGovernor, GovernorParameters, SyndicateFactory,\n * and strategy contracts.\n */\n\nimport { type Hex, decodeErrorResult, BaseError } from \"viem\";\nimport { getChain } from \"./network.js\";\n\n// ── Combined error-only ABI for decoding ──\n\nexport const CONTRACT_ERRORS_ABI = [\n // ── SyndicateVault ──\n { type: \"error\", name: \"InvalidOwner\", inputs: [] },\n { type: \"error\", name: \"InvalidExecutorImpl\", inputs: [] },\n { type: \"error\", name: \"NotActiveAgent\", inputs: [] },\n { type: \"error\", name: \"SimulationFailed\", inputs: [] },\n { type: \"error\", name: \"InvalidDepositor\", inputs: [] },\n { type: \"error\", name: \"DepositorAlreadyApproved\", inputs: [] },\n { type: \"error\", name: \"DepositorNotApproved\", inputs: [] },\n { type: \"error\", name: \"NotApprovedDepositor\", inputs: [] },\n { type: \"error\", name: \"AgentAlreadyRegistered\", inputs: [] },\n { type: \"error\", name: \"AgentNotActive\", inputs: [] },\n { type: \"error\", name: \"InvalidAgentRegistry\", inputs: [] },\n { type: \"error\", name: \"NotAgentOwner\", inputs: [] },\n { type: \"error\", name: \"NotGovernor\", inputs: [] },\n { type: \"error\", name: \"RedemptionsLocked\", inputs: [] },\n { type: \"error\", name: \"DepositsLocked\", inputs: [] },\n { type: \"error\", name: \"InvalidAgentAddress\", inputs: [] },\n { type: \"error\", name: \"TransferFailed\", inputs: [] },\n { type: \"error\", name: \"ZeroAddress\", inputs: [] },\n { type: \"error\", name: \"CannotRescueAsset\", inputs: [] },\n { type: \"error\", name: \"NotFactory\", inputs: [] },\n\n // ── SyndicateGovernor ──\n { type: \"error\", name: \"VaultNotRegistered\", inputs: [] },\n { type: \"error\", name: \"VaultAlreadyRegistered\", inputs: [] },\n { type: \"error\", name: \"NotRegisteredAgent\", inputs: [] },\n { type: \"error\", name: \"PerformanceFeeTooHigh\", inputs: [] },\n { type: \"error\", name: \"StrategyDurationTooLong\", inputs: [] },\n { type: \"error\", name: \"StrategyDurationTooShort\", inputs: [] },\n { type: \"error\", name: \"EmptyExecuteCalls\", inputs: [] },\n { type: \"error\", name: \"EmptySettlementCalls\", inputs: [] },\n { type: \"error\", name: \"NotWithinVotingPeriod\", inputs: [] },\n { type: \"error\", name: \"NoVotingPower\", inputs: [] },\n { type: \"error\", name: \"AlreadyVoted\", inputs: [] },\n { type: \"error\", name: \"ProposalNotFound\", inputs: [] },\n { type: \"error\", name: \"ProposalNotApproved\", inputs: [] },\n { type: \"error\", name: \"ExecutionWindowExpired\", inputs: [] },\n { type: \"error\", name: \"StrategyAlreadyActive\", inputs: [] },\n { type: \"error\", name: \"CooldownNotElapsed\", inputs: [] },\n { type: \"error\", name: \"ProposalNotExecuted\", inputs: [] },\n { type: \"error\", name: \"ProposalNotCancellable\", inputs: [] },\n { type: \"error\", name: \"NotProposer\", inputs: [] },\n { type: \"error\", name: \"InvalidVotingPeriod\", inputs: [] },\n { type: \"error\", name: \"InvalidExecutionWindow\", inputs: [] },\n { type: \"error\", name: \"InvalidVetoThresholdBps\", inputs: [] },\n { type: \"error\", name: \"InvalidMaxPerformanceFeeBps\", inputs: [] },\n { type: \"error\", name: \"InvalidStrategyDurationBounds\", inputs: [] },\n { type: \"error\", name: \"InvalidCooldownPeriod\", inputs: [] },\n { type: \"error\", name: \"InvalidVault\", inputs: [] },\n { type: \"error\", name: \"NotVaultOwner\", inputs: [] },\n { type: \"error\", name: \"StrategyDurationNotElapsed\", inputs: [] },\n { type: \"error\", name: \"InvalidProtocolFeeBps\", inputs: [] },\n { type: \"error\", name: \"InvalidProtocolFeeRecipient\", inputs: [] },\n { type: \"error\", name: \"NotCoProposer\", inputs: [] },\n { type: \"error\", name: \"CollaborationExpired\", inputs: [] },\n { type: \"error\", name: \"AlreadyApproved\", inputs: [] },\n { type: \"error\", name: \"InvalidSplits\", inputs: [] },\n { type: \"error\", name: \"TooManyCoProposers\", inputs: [] },\n { type: \"error\", name: \"SplitTooLow\", inputs: [] },\n { type: \"error\", name: \"LeadSplitTooLow\", inputs: [] },\n { type: \"error\", name: \"DuplicateCoProposer\", inputs: [] },\n { type: \"error\", name: \"NotDraftState\", inputs: [] },\n { type: \"error\", name: \"InvalidCollaborationWindow\", inputs: [] },\n { type: \"error\", name: \"NotAuthorized\", inputs: [] },\n { type: \"error\", name: \"InvalidMaxCoProposers\", inputs: [] },\n { type: \"error\", name: \"Reentrancy\", inputs: [] },\n\n // ── GovernorParameters (timelock) ──\n { type: \"error\", name: \"ChangeAlreadyPending\", inputs: [] },\n { type: \"error\", name: \"NoChangePending\", inputs: [] },\n { type: \"error\", name: \"ChangeNotReady\", inputs: [] },\n { type: \"error\", name: \"InvalidParameterChangeDelay\", inputs: [] },\n { type: \"error\", name: \"InvalidParameterKey\", inputs: [] },\n\n // ── SyndicateFactory ──\n { type: \"error\", name: \"InvalidVaultImpl\", inputs: [] },\n { type: \"error\", name: \"InvalidENSRegistrar\", inputs: [] },\n { type: \"error\", name: \"SubdomainTooShort\", inputs: [] },\n { type: \"error\", name: \"SubdomainTaken\", inputs: [] },\n { type: \"error\", name: \"NotCreator\", inputs: [] },\n { type: \"error\", name: \"InvalidGovernor\", inputs: [] },\n { type: \"error\", name: \"InsufficientCreationFee\", inputs: [] },\n { type: \"error\", name: \"InvalidFeeToken\", inputs: [] },\n { type: \"error\", name: \"ManagementFeeTooHigh\", inputs: [] },\n { type: \"error\", name: \"UpgradesDisabled\", inputs: [] },\n { type: \"error\", name: \"VaultNotDeployed\", inputs: [] },\n { type: \"error\", name: \"StrategyActive\", inputs: [] },\n\n // ── BaseStrategy ──\n { type: \"error\", name: \"AlreadyInitialized\", inputs: [] },\n { type: \"error\", name: \"NotVault\", inputs: [] },\n { type: \"error\", name: \"NotExecuted\", inputs: [] },\n { type: \"error\", name: \"AlreadyExecuted\", inputs: [] },\n { type: \"error\", name: \"AlreadySettled\", inputs: [] },\n\n // ── MoonwellSupplyStrategy / WstETHMoonwellStrategy ──\n { type: \"error\", name: \"InvalidAmount\", inputs: [] },\n { type: \"error\", name: \"MintFailed\", inputs: [] },\n { type: \"error\", name: \"RedeemFailed\", inputs: [] },\n\n // ── AerodromeLPStrategy ──\n { type: \"error\", name: \"GaugeMismatch\", inputs: [] },\n\n // ── WstETHMoonwellStrategy / VeniceInferenceStrategy ──\n { type: \"error\", name: \"SwapFailed\", inputs: [] },\n { type: \"error\", name: \"AlreadySettledParams\", inputs: [] },\n\n // ── PortfolioStrategy / UniswapSwapAdapter ──\n { type: \"error\", name: \"QuoteUnavailable\", inputs: [] },\n { type: \"error\", name: \"UnsupportedMode\", inputs: [] },\n { type: \"error\", name: \"InvalidWeights\", inputs: [] },\n { type: \"error\", name: \"LengthMismatch\", inputs: [] },\n { type: \"error\", name: \"TooManyTokens\", inputs: [] },\n { type: \"error\", name: \"RebalancingInProgress\", inputs: [] },\n { type: \"error\", name: \"StalePrice\", inputs: [] },\n { type: \"error\", name: \"InvalidSlippage\", inputs: [] },\n { type: \"error\", name: \"InvalidPriceDecimals\", inputs: [] },\n\n // ── VeniceInferenceStrategy ──\n { type: \"error\", name: \"NoAgent\", inputs: [] },\n] as const;\n\n// ── Human-readable error messages ──\n\nconst ERROR_MESSAGES: Record<string, string> = {\n // Vault — permissions / state\n InvalidOwner: \"The caller is not the vault owner.\",\n NotActiveAgent: \"Your wallet is not registered as an active agent on this vault. Ask the creator to run: sherwood fund approve --agent-id <id> --wallet <your-address>\",\n NotApprovedDepositor: \"Your address is not on the depositor whitelist. Ask the vault creator to approve you.\",\n NotGovernor: \"This operation can only be called by the governor contract.\",\n NotFactory: \"This operation can only be called by the factory contract.\",\n RedemptionsLocked: \"Redemptions are locked while a strategy is executing. Wait for the proposal to be settled.\",\n DepositsLocked: \"Deposits are locked while an active proposal exists. Wait for settlement.\",\n InvalidDepositor: \"Invalid depositor address.\",\n DepositorAlreadyApproved: \"This depositor is already on the whitelist.\",\n DepositorNotApproved: \"This depositor is not on the whitelist.\",\n AgentAlreadyRegistered: \"This agent wallet is already registered on the vault.\",\n AgentNotActive: \"This agent is registered but not active.\",\n InvalidAgentRegistry: \"Agent registry address is invalid.\",\n NotAgentOwner: \"You do not own this ERC-8004 agent identity NFT.\",\n InvalidAgentAddress: \"Invalid agent wallet address (cannot be zero).\",\n InvalidExecutorImpl: \"Executor implementation address is invalid.\",\n SimulationFailed: \"Transaction simulation failed — the batch calls would revert onchain.\",\n TransferFailed: \"ERC-20 token transfer failed. Check token balance and approvals.\",\n ZeroAddress: \"A required address parameter is the zero address.\",\n CannotRescueAsset: \"Cannot rescue the vault's underlying asset — use redeem() instead.\",\n\n // Governor — proposal lifecycle\n VaultNotRegistered: \"This vault is not registered with the governor. The factory registers vaults automatically on creation.\",\n VaultAlreadyRegistered: \"This vault is already registered with the governor.\",\n NotRegisteredAgent: \"Your wallet is not a registered agent on this vault. Register first via: sherwood fund approve\",\n PerformanceFeeTooHigh: \"Performance fee exceeds the governor's maxPerformanceFeeBps. Check: sherwood governor info\",\n StrategyDurationTooLong: \"Strategy duration exceeds the governor's maxStrategyDuration. Check: sherwood governor info\",\n StrategyDurationTooShort: \"Strategy duration is below the governor's minStrategyDuration. Check: sherwood governor info\",\n EmptyExecuteCalls: \"Proposal must include at least one execute call.\",\n EmptySettlementCalls: \"Proposal must include at least one settlement call.\",\n NotWithinVotingPeriod: \"Voting period has not started or has already ended. Check: sherwood proposal show <id>\",\n NoVotingPower: \"You have no voting power (zero vault shares at the snapshot time).\",\n AlreadyVoted: \"You have already voted on this proposal.\",\n ProposalNotFound: \"Proposal does not exist. Check the proposal ID.\",\n ProposalNotApproved: \"Proposal is not in Approved state. It may still be in voting or was rejected.\",\n ExecutionWindowExpired: \"The execution window has closed. The proposal is now Expired.\",\n StrategyAlreadyActive: \"Another strategy is currently executing on this vault. Settle it first before executing a new proposal.\",\n CooldownNotElapsed: \"A proposal was recently settled. Wait for the cooldown period to elapse. Check: sherwood governor info\",\n ProposalNotExecuted: \"Proposal has not been executed yet. Execute it first.\",\n ProposalNotCancellable: \"This proposal cannot be cancelled in its current state.\",\n NotProposer: \"Only the original proposer can perform this action.\",\n StrategyDurationNotElapsed: \"Strategy duration has not elapsed yet. Only the proposer can settle early.\",\n\n // Governor — parameter validation\n InvalidVotingPeriod: \"Voting period is outside allowed bounds (check governor constants).\",\n InvalidExecutionWindow: \"Execution window is outside allowed bounds.\",\n InvalidVetoThresholdBps: \"Veto threshold must be between the allowed bounds (in bps).\",\n InvalidMaxPerformanceFeeBps: \"Max performance fee is outside allowed bounds.\",\n InvalidStrategyDurationBounds: \"Strategy duration bounds are invalid (min must be < max).\",\n InvalidCooldownPeriod: \"Cooldown period is outside allowed bounds.\",\n InvalidVault: \"Invalid vault address.\",\n NotVaultOwner: \"Only the vault owner can perform this action.\",\n InvalidProtocolFeeBps: \"Protocol fee exceeds the 10% maximum (1000 bps).\",\n InvalidProtocolFeeRecipient: \"Protocol fee recipient must be set before enabling protocol fees.\",\n\n // Governor — collaborative proposals\n NotCoProposer: \"You are not listed as a co-proposer on this proposal.\",\n CollaborationExpired: \"The collaboration window has expired.\",\n AlreadyApproved: \"This co-proposer has already approved.\",\n InvalidSplits: \"Co-proposer fee splits must sum correctly with the lead proposer split.\",\n TooManyCoProposers: \"Exceeds the maximum number of co-proposers. Check: sherwood governor info\",\n SplitTooLow: \"A co-proposer's fee split is below the minimum.\",\n LeadSplitTooLow: \"The lead proposer's fee split is below the minimum.\",\n DuplicateCoProposer: \"Duplicate co-proposer address in the list.\",\n NotDraftState: \"Proposal must be in Draft state for this operation.\",\n InvalidCollaborationWindow: \"Collaboration window is outside allowed bounds.\",\n NotAuthorized: \"You are not authorized to perform this action.\",\n InvalidMaxCoProposers: \"Max co-proposers value is outside allowed bounds.\",\n Reentrancy: \"Reentrancy detected — this call cannot be made during another call.\",\n\n // Governor — parameter timelock\n ChangeAlreadyPending: \"A parameter change is already pending for this parameter. Finalize or cancel it first.\",\n NoChangePending: \"No parameter change is pending for this key.\",\n ChangeNotReady: \"Parameter change timelock has not elapsed yet. Wait for the delay to pass, then finalize.\",\n InvalidParameterChangeDelay: \"Parameter change delay is outside allowed bounds.\",\n InvalidParameterKey: \"Unknown parameter key.\",\n\n // Factory\n InvalidVaultImpl: \"Vault implementation address is invalid.\",\n InvalidENSRegistrar: \"ENS registrar address is invalid.\",\n SubdomainTooShort: \"Subdomain must be at least 3 characters.\",\n SubdomainTaken: \"This subdomain is already taken. Choose a different name.\",\n NotCreator: \"Only the fund creator can perform this action.\",\n InvalidGovernor: \"Governor address is invalid.\",\n InsufficientCreationFee: \"Insufficient creation fee. Check the required fee amount.\",\n InvalidFeeToken: \"Invalid fee token address.\",\n ManagementFeeTooHigh: \"Management fee exceeds the maximum allowed.\",\n UpgradesDisabled: \"Vault upgrades are currently disabled by the factory owner.\",\n VaultNotDeployed: \"Vault has not been deployed yet.\",\n StrategyActive: \"Cannot perform this action while a strategy is actively executing.\",\n\n // Strategy — base\n AlreadyInitialized: \"This strategy clone was already initialized. Deploy a fresh clone.\",\n NotVault: \"Only the vault can call this strategy function.\",\n NotExecuted: \"Strategy has not been executed yet.\",\n AlreadyExecuted: \"Strategy has already been executed.\",\n AlreadySettled: \"Strategy has already been settled.\",\n\n // Strategy — Moonwell / WstETH\n InvalidAmount: \"Invalid amount — must be greater than zero.\",\n MintFailed: \"Moonwell cToken mint failed. The underlying supply may have hit the market cap.\",\n RedeemFailed: \"Moonwell cToken redeem failed. Check that sufficient liquidity is available.\",\n\n // Strategy — Aerodrome\n GaugeMismatch: \"Aerodrome gauge does not match the expected pool.\",\n\n // Strategy — WstETH / Venice\n SwapFailed: \"Token swap failed. Check slippage tolerance and pool liquidity.\",\n AlreadySettledParams: \"Settlement parameters have already been set.\",\n\n // Strategy — Portfolio / UniswapSwapAdapter\n QuoteUnavailable:\n \"Uniswap quoter returned 0 or reverted for a portfolio allocation. \" +\n \"Usually means: (a) no V3 pool exists at the requested fee tier for one of the tokens, \" +\n \"(b) the strategy clone was initialized against an old/broken UniswapSwapAdapter \" +\n \"(check the clone's swapAdapter() vs the current chains JSON), or \" +\n \"(c) the adapter is calling Quoter with the wrong ABI (pre-PR #317 bug).\",\n UnsupportedMode: \"UniswapSwapAdapter doesn't support that swap mode. Only V3 single-hop (mode 0) and multi-hop (mode 1) are supported.\",\n InvalidWeights: \"Portfolio weights must sum to 10000 bps (100%).\",\n LengthMismatch: \"Portfolio input arrays (tokens / weights / swapExtraData / priceDecimals) must have the same length.\",\n TooManyTokens: \"Portfolio basket exceeds the maximum allocation count (20).\",\n RebalancingInProgress: \"A rebalance is already in flight on this clone. Wait for it to finish.\",\n StalePrice: \"Chainlink Data Streams report has expired. Refresh prices and retry.\",\n InvalidSlippage: \"maxSlippageBps must be > 0 and < 10000.\",\n InvalidPriceDecimals: \"priceDecimals entry exceeds 36. Use 8 for tokenized-stock feeds, 18 for crypto pairs.\",\n\n // Strategy — Venice\n NoAgent: \"No agent is registered on the vault. Register an agent first.\",\n};\n\n// ── Decoding ──\n\n/**\n * Attempt to decode a hex revert selector into a human-readable error message.\n * Returns null if the selector doesn't match any known contract error.\n */\nexport function decodeContractError(data: Hex): { name: string; message: string } | null {\n try {\n const decoded = decodeErrorResult({\n abi: CONTRACT_ERRORS_ABI,\n data,\n });\n const message = ERROR_MESSAGES[decoded.errorName] || `Contract error: ${decoded.errorName}`;\n return { name: decoded.errorName, message };\n } catch {\n return null;\n }\n}\n\n/**\n * Extract a hex error selector from a viem error's walk chain.\n * viem wraps contract call reverts in ContractFunctionRevertedError which\n * contains a `data` field with the raw 4-byte (or longer) revert payload.\n */\nfunction extractRevertData(err: unknown): Hex | null {\n if (!(err instanceof BaseError)) return null;\n\n // Walk the viem error chain to find revert data\n const revertError = err.walk((e) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (e as any).data !== undefined;\n });\n\n if (revertError) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const data = (revertError as any).data;\n // data can be the hex string directly, or an object with a data field\n if (typeof data === \"string\" && data.startsWith(\"0x\")) {\n return data as Hex;\n }\n if (typeof data === \"object\" && data?.data && typeof data.data === \"string\") {\n return data.data as Hex;\n }\n }\n\n // Fallback: extract 0x + hex from the error message (e.g. \"reverted with 0x62df0545\")\n const msg = err.message || \"\";\n const match = msg.match(/(?:signature|data)\\s*\"?(0x[0-9a-fA-F]+)\"?/);\n if (match) return match[1] as Hex;\n\n return null;\n}\n\n// ── Known common EVM / ERC-20 revert strings ──\n\nconst KNOWN_REVERT_STRINGS: Record<string, string> = {\n \"ERC20: transfer amount exceeds balance\": \"Insufficient token balance for this transfer.\",\n \"ERC20: transfer amount exceeds allowance\": \"Token allowance insufficient. An approval step may have been skipped.\",\n \"ERC20: insufficient allowance\": \"Token allowance insufficient. An approval step may have been skipped.\",\n \"Ownable: caller is not the owner\": \"Only the contract owner can call this function.\",\n \"Pausable: paused\": \"The contract is currently paused.\",\n};\n\n/**\n * Format any caught error into a user-friendly message.\n *\n * Tries (in order):\n * 1. Decode custom error selector from our contract ABIs\n * 2. Match known EVM/ERC-20 revert reason strings\n * 3. Identify nonce / gas issues with actionable advice\n * 4. Fall back to the raw error message\n */\nexport function formatContractError(err: unknown): string {\n // 1. Try to decode custom contract error\n const revertData = extractRevertData(err);\n if (revertData && revertData.length >= 10) {\n const decoded = decodeContractError(revertData);\n if (decoded) return decoded.message;\n }\n\n const rawMsg = err instanceof Error ? err.message : String(err);\n\n // 2. Check for known revert reason strings\n for (const [pattern, message] of Object.entries(KNOWN_REVERT_STRINGS)) {\n if (rawMsg.includes(pattern)) return message;\n }\n\n // 3. Nonce / gas issues — already handled by retry, but surface clearly if they bubble up\n if (rawMsg.includes(\"replacement transaction underpriced\")) {\n return \"A previous transaction is stuck. The CLI retried with higher gas but the error persists. Try again in a moment.\";\n }\n if (rawMsg.includes(\"nonce too low\") || rawMsg.includes(\"NONCE_EXPIRED\")) {\n return \"Transaction nonce conflict — a previous transaction is still pending. Wait a moment and retry.\";\n }\n if (rawMsg.includes(\"insufficient funds for gas\")) {\n return `Insufficient ETH for gas fees. Top up your wallet with ETH on ${getChain().name}.`;\n }\n\n // 4. Clean up common viem wrapper noise\n // Strip \"ContractFunctionRevertedError:\" prefix and \"Docs:\" links\n let cleaned = rawMsg\n .replace(/ContractFunctionRevertedError:\\s*/g, \"\")\n .replace(/Docs:\\s*https:\\/\\/\\S+/g, \"\")\n .replace(/Version:\\s*viem@\\S+/g, \"\")\n .replace(/Request Arguments:[\\s\\S]*$/m, \"\")\n .replace(/Contract Call:[\\s\\S]*?(?=\\n\\n|\\n[A-Z]|$)/m, \"\")\n .trim();\n\n // If we still have \"reverted with the following signature: 0x...\" try one more decode\n const sigMatch = cleaned.match(/signature[:\\s]+\"?(0x[0-9a-fA-F]{8,})\"?/);\n if (sigMatch) {\n const decoded = decodeContractError(sigMatch[1] as Hex);\n if (decoded) return decoded.message;\n // If we can't decode it, at least explain what it is\n const explorer = getChain().blockExplorers?.default?.name ?? \"the block explorer\";\n cleaned = `Contract reverted with unknown error selector ${sigMatch[1]}. Check the transaction on ${explorer} for details.`;\n }\n\n return cleaned;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/events.ts"],"sourcesContent":["/**\n * On-chain event reader — fetches vault and governor events via viem getLogs.\n *\n * Uses HTTP RPC (no WebSocket needed). Block ranges are capped at 10,000\n * per call to avoid RPC timeouts (~83 minutes on Base at 2 blocks/sec).\n */\n\nimport type { Address, Log } from \"viem\";\nimport { parseAbiItem } from \"viem\";\nimport { getPublicClient } from \"./client.js\";\nimport { getProposal, PROPOSAL_STATES } from \"./governor.js\";\nimport { resolveMetadataSummary } from \"./ipfs.js\";\n\nconst MAX_BLOCK_RANGE = 10_000n;\n\n// ── Event signatures (parseAbiItem format for getLogs) ──\n\nconst VAULT_EVENTS = [\n parseAbiItem(\"event AgentRegistered(uint256 indexed agentId, address indexed agentAddress)\"),\n parseAbiItem(\"event AgentRemoved(address indexed agentAddress)\"),\n parseAbiItem(\"event DepositorApproved(address indexed depositor)\"),\n parseAbiItem(\"event DepositorRemoved(address indexed depositor)\"),\n parseAbiItem(\"event RedemptionsLockedEvent()\"),\n parseAbiItem(\"event RedemptionsUnlockedEvent()\"),\n] as const;\n\nconst GOVERNOR_EVENTS = [\n parseAbiItem(\"event ProposalCreated(uint256 indexed proposalId, address indexed proposer, address indexed vault, uint256 performanceFeeBps, uint256 strategyDuration, uint256 executeCallCount, uint256 settlementCallCount, string metadataURI)\"),\n parseAbiItem(\"event VoteCast(uint256 indexed proposalId, address indexed voter, uint8 support, uint256 weight)\"),\n parseAbiItem(\"event ProposalExecuted(uint256 indexed proposalId, address indexed vault, uint256 capitalSnapshot)\"),\n parseAbiItem(\"event ProposalSettled(uint256 indexed proposalId, address indexed vault, int256 pnl, uint256 performanceFee, uint256 duration)\"),\n parseAbiItem(\"event ProposalCancelled(uint256 indexed proposalId, address indexed cancelledBy)\"),\n] as const;\n\n/** Normalized event returned by the session check. */\nexport interface ChainEvent {\n source: \"chain\";\n type: string;\n block: number;\n tx: string;\n args: Record<string, string>;\n}\n\nfunction logToChainEvent(log: Log, eventName: string): ChainEvent {\n const args: Record<string, string> = {};\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const decoded = (log as any).args;\n if (decoded) {\n for (const [key, value] of Object.entries(decoded)) {\n args[key] = String(value);\n }\n }\n\n return {\n source: \"chain\",\n type: eventName,\n block: Number(log.blockNumber),\n tx: log.transactionHash || \"\",\n args,\n };\n}\n\n/**\n * Fetch events in chunks to stay within RPC limits.\n * Returns all logs from `fromBlock` to `toBlock` inclusive.\n * Exported for reuse (e.g. vault.ts getNetDeposited's 0→latest scan).\n */\nexport async function getLogsChunked(params: {\n address: Address;\n events: readonly ReturnType<typeof parseAbiItem>[];\n fromBlock: bigint;\n toBlock: bigint;\n}): Promise<Log[]> {\n const client = getPublicClient();\n const { address, events, fromBlock, toBlock } = params;\n\n const allLogs: Log[] = [];\n let cursor = fromBlock;\n\n while (cursor <= toBlock) {\n const end =\n cursor + MAX_BLOCK_RANGE - 1n > toBlock\n ? toBlock\n : cursor + MAX_BLOCK_RANGE - 1n;\n\n const logs = await client.getLogs({\n address,\n events: events as never,\n fromBlock: cursor,\n toBlock: end,\n });\n\n allLogs.push(...logs);\n cursor = end + 1n;\n }\n\n return allLogs;\n}\n\n/** Fetch vault events (AgentRegistered, Ragequit, etc.) */\nexport async function getVaultEvents(\n vaultAddress: Address,\n fromBlock: bigint,\n toBlock: bigint,\n): Promise<ChainEvent[]> {\n const logs = await getLogsChunked({\n address: vaultAddress,\n events: VAULT_EVENTS,\n fromBlock,\n toBlock,\n });\n\n return logs.map((log) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const eventName = (log as any).eventName || \"UnknownVaultEvent\";\n return logToChainEvent(log, eventName);\n });\n}\n\n/** Fetch governor events filtered to a specific vault. */\nexport async function getGovernorEvents(\n governorAddress: Address,\n vaultAddress: Address,\n fromBlock: bigint,\n toBlock: bigint,\n): Promise<ChainEvent[]> {\n if (governorAddress === \"0x0000000000000000000000000000000000000000\") {\n return []; // Governor not deployed yet\n }\n\n const logs = await getLogsChunked({\n address: governorAddress,\n events: GOVERNOR_EVENTS,\n fromBlock,\n toBlock,\n });\n\n // Filter governor events to only those involving our vault\n return logs\n .filter((log) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const args = (log as any).args;\n if (!args) return true;\n // ProposalCreated, ProposalExecuted, ProposalSettled have `vault` in args\n if (args.vault) {\n return (args.vault as string).toLowerCase() === vaultAddress.toLowerCase();\n }\n // VoteCast, ProposalCancelled don't have vault — include them\n // (agents care about all votes/cancellations on their governor)\n return true;\n })\n .map((log) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const eventName = (log as any).eventName || \"UnknownGovernorEvent\";\n return logToChainEvent(log, eventName);\n });\n}\n\n/** Get current block number from the RPC. */\nexport async function getCurrentBlock(): Promise<bigint> {\n const client = getPublicClient();\n return client.getBlockNumber();\n}\n\n// ── Proposal event enrichment ──\n\nconst PROPOSAL_EVENT_TYPES = new Set([\n \"ProposalCreated\",\n \"VoteCast\",\n \"ProposalExecuted\",\n \"ProposalSettled\",\n \"ProposalCancelled\",\n]);\n\n/**\n * Enrich proposal-related events with IPFS metadata (name, description)\n * and current on-chain state. Best-effort — events are returned un-enriched\n * if RPC or IPFS calls fail.\n *\n * `vault` identifies which per-vault governor to read proposal state from\n * (proposal IDs are scoped to a vault's governor in the per-vault design).\n *\n * An optional metadataCache avoids redundant IPFS fetches across poll cycles\n * in streaming mode (proposal metadata is immutable once pinned).\n */\nexport async function enrichProposalEvents(\n vault: Address,\n events: ChainEvent[],\n metadataCache?: Map<string, { name: string; description: string }>,\n): Promise<ChainEvent[]> {\n const cache = metadataCache ?? new Map<string, { name: string; description: string }>();\n\n const proposalEvents = events.filter((e) => PROPOSAL_EVENT_TYPES.has(e.type));\n if (proposalEvents.length === 0) return events;\n\n // Collect unique proposalIds and their metadata sources\n const idsNeedingLookup = new Set<string>();\n const createdURIs = new Map<string, string>(); // proposalId → metadataURI from event args\n\n for (const event of proposalEvents) {\n const pid = event.args.proposalId;\n if (!pid) continue;\n\n if (event.type === \"ProposalCreated\" && event.args.metadataURI) {\n createdURIs.set(pid, event.args.metadataURI);\n } else if (!cache.has(pid)) {\n idsNeedingLookup.add(pid);\n }\n }\n\n // Fetch on-chain proposal data for non-Created events (parallel, deduplicated)\n const proposalData = new Map<string, { metadataURI: string; state: number }>();\n\n await Promise.all(\n Array.from(idsNeedingLookup).map(async (pid) => {\n try {\n const p = await getProposal(vault, BigInt(pid));\n proposalData.set(pid, { metadataURI: p.metadataURI, state: p.state });\n } catch {\n // RPC failure — skip enrichment for this proposalId\n }\n }),\n );\n\n // Resolve IPFS metadata (parallel, deduplicated, uses cache)\n const allURIs = new Map<string, string>();\n for (const [pid, uri] of createdURIs) allURIs.set(pid, uri);\n for (const [pid, data] of proposalData) {\n if (!allURIs.has(pid)) allURIs.set(pid, data.metadataURI);\n }\n\n await Promise.all(\n Array.from(allURIs.entries()).map(async ([pid, uri]) => {\n if (cache.has(pid) || !uri) return;\n const summary = await resolveMetadataSummary(uri);\n if (summary) cache.set(pid, summary);\n }),\n );\n\n // Inject enrichment fields into event args\n return events.map((event) => {\n if (!PROPOSAL_EVENT_TYPES.has(event.type)) return event;\n const pid = event.args.proposalId;\n if (!pid) return event;\n\n const meta = cache.get(pid);\n const pData = proposalData.get(pid);\n const enrichedArgs = { ...event.args };\n\n if (meta) {\n enrichedArgs.proposalName = meta.name;\n enrichedArgs.proposalDescription = meta.description;\n }\n\n if (event.type === \"ProposalCreated\") {\n enrichedArgs.proposalState = \"Pending\";\n } else if (pData) {\n enrichedArgs.proposalState = PROPOSAL_STATES[pData.state] || \"Unknown\";\n }\n\n return { ...event, args: enrichedArgs };\n });\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/addresses.ts","../src/lib/address-overrides.ts"],"sourcesContent":["/**\n * Contract addresses by network.\n *\n * All exports are functions — they resolve at call time based on the\n * current network set via setNetwork(). This ensures --chain works\n * even when modules are imported before the flag is parsed.\n *\n * Current deployment target: Robinhood L2 testnet (chain 46630) only. Other\n * chains may be added back later; when they are, their address blocks + registry\n * entries re-enter here alongside the robinhood-testnet ones.\n *\n * Zero addresses = protocol not deployed on that chain. Strategies that\n * need them will fail at execution time with a clear allowlist error.\n */\n\nimport type { Address } from \"viem\";\nimport { isAddress } from \"viem\";\nimport { type Network, getNetwork } from \"./network.js\";\nimport { overridesFor } from \"./address-overrides.js\";\n\nconst ZERO: Address = \"0x0000000000000000000000000000000000000000\";\nconst ZERO_BYTES32 =\n \"0x0000000000000000000000000000000000000000000000000000000000000000\" as `0x${string}`;\n\n// ── Robinhood L2 Testnet (Arbitrum Orbit, chain 46630) ──\n// Synthra DEX for swaps. Stock tokens available.\n\nconst ROBINHOOD_TESTNET_TOKENS = {\n USDC: ZERO,\n // USDG (Robinhood-chain stablecoin, 6-dec). Zero on testnet (Synthra WETH-quoted);\n // real on the mainnet fork. Keyed so `--asset USDG` resolves + decimals=6.\n USDG: ZERO,\n // WETH resolves to Synthra's WETH9 (SYNTHRA_WETH): ALL stock DEX liquidity is\n // denominated in it (e.g. the TSLA fee-3000 pool holds ~37.8 WETH here vs\n // ~0.0003 in the canonical WETH pool). It is WETH9-style (payable deposit()),\n // so --use-eth wrapping works against it. Canonical WETH kept as WETH_CANONICAL\n // so the reference isn't lost.\n WETH: \"0x33e4191705c386532ba27cBF171Db86919200B94\" as Address,\n WETH_CANONICAL: \"0x7943e237c7F95DA44E0301572D358911207852Fa\" as Address,\n cbETH: ZERO,\n wstETH: ZERO,\n cbBTC: ZERO,\n DAI: ZERO,\n AERO: ZERO,\n TSLA: \"0xC9f9c86933092BbbfFF3CCb4b105A4A94bf3Bd4E\" as Address,\n AMZN: \"0x5884aD2f920c162CFBbACc88C9C51AA75eC09E02\" as Address,\n PLTR: \"0x1FBE1a0e43594b3455993B5dE5Fd0A7A266298d0\" as Address,\n NFLX: \"0x3b8262A63d25f0477c4DDE23F83cfe22Cb768C93\" as Address,\n AMD: \"0x71178BAc73cBeb415514eB542a8995b82669778d\" as Address,\n} as const;\n\nconst ROBINHOOD_TESTNET_MOONWELL = {\n COMPTROLLER: ZERO,\n mUSDC: ZERO,\n mWETH: ZERO,\n mCbETH: ZERO,\n mWstETH: ZERO,\n mCbBTC: ZERO,\n mDAI: ZERO,\n mAERO: ZERO,\n} as const;\n\n// Synthra is Uniswap-V3-compatible; the deployed UniswapSwapAdapter is backed by\n// Synthra's router + a QuoterV2 shim (SYNTHRA_QUOTER_V2_SHIM). SWAP_ROUTER /\n// QUOTER_V2 mirror the Synthra addresses so a direct v3 quote path also resolves.\nconst ROBINHOOD_TESTNET_UNISWAP = {\n SWAP_ROUTER: \"0x3Ce954107b1A675826B33bF23060Dd655e3758fE\" as Address,\n QUOTER_V2: \"0xb3C009aECAeDd5ccC62Ec12eDAAA55F19C4A1eFb\" as Address,\n SWAP_ADAPTER: \"0x4fc3492117cC3bbcE0b210D22a8DC244f9d86490\" as Address,\n} as const;\n\n// ── Synthra DEX (Robinhood L2 — Uniswap V3-compatible concentrated liquidity) ──\n\nconst ROBINHOOD_TESTNET_SYNTHRA = {\n ROUTER: \"0x3Ce954107b1A675826B33bF23060Dd655e3758fE\" as Address,\n QUOTER: \"0x231606c321A99DE81e28fE48B07a93F1ba49e713\" as Address,\n FACTORY: \"0x911b4000D3422F482F4062a913885f7b035382Df\" as Address,\n} as const;\n\n// ── Chainlink (Data Streams verifier proxy + AggregatorV3 feeds) ──\n\nconst ROBINHOOD_TESTNET_CHAINLINK = {\n VERIFIER_PROXY: \"0x72790f9eB82db492a7DDb6d2af22A270Dcc3Db64\" as Address,\n WSTETH_ETH_FEED: ZERO,\n} as const;\n\n// ── Robinhood portfolio-basket route + feed metadata ──\n//\n// Data-driven replacement for the hand-drifting \"known stock\" Set that used to\n// live in strategy-template.ts. Every entry is a VERIFIED-liquidity default\n// swap route for a basket token. Absence from this map means \"no verified\n// default route\" — the CLI fails fast and demands an explicit --swap-routes\n// rather than falling through to a v3 auto-detect that would be dead.\n//\n// `kind: \"v4-native\"` = a Uniswap v4 mode-3 multi-hop USDG → native ETH → stock,\n// consumed by portfolio-template.ts as\n// v4PathExtraData([{currency: ETH, ...native}, {currency: <token>, ...stock}]).\nexport interface RobinhoodStockRoute {\n kind: \"v4-native\";\n nativeFee: number;\n nativeTickSpacing: number;\n stockFee: number;\n stockTickSpacing: number;\n}\n\n// No verified default stock swap routes on the Robinhood testnet — the machinery\n// is retained (see robinhoodEquityMaxAge / portfolio-template.ts) but the map is\n// empty, so every basket token falls to the existing fail-fast route error until\n// a verified route is added.\n// LOCKSTEP: the app's quote-probe geometry (app/src/lib/price-quote.ts\n// V4_DIRECT_TIERS + via-native path) must stay consistent with any route added\n// here, or the dashboard displays a tier the strategy won't execute.\nexport const ROBINHOOD_STOCK_ROUTES: Record<string, RobinhoodStockRoute> = {};\n\n// Chainlink push-feed classification. Every `*_USD_FEED` is an EQUITY feed\n// (needs the extended 96h max-price-age over holiday weekends) EXCEPT these —\n// crypto/FX/stable feeds keep the contract default (26h). Encoded here (not an\n// inline list in the command) so route/feed metadata lives in one registry.\n//\n// WETH is listed alongside ETH because feed auto-resolve normalizes WETH →\n// ETH_USD_FEED (there is no WETH_USD_FEED — the two share the 24h crypto feed).\n// The classification helper below MUST agree with that normalization for every\n// symbol the feed-resolution path accepts, or a WETH allocation packs the 96h\n// equity max-age onto a 24h crypto feed and accepts ~4-day-stale ETH prices.\nexport const ROBINHOOD_NON_EQUITY_FEEDS = new Set([\"ETH\", \"WETH\", \"BTC\", \"LINK\", \"USDG\", \"USDC\"]);\n\n/** True if `symbol`'s Robinhood push feed is a tokenized-equity feed. */\nexport function isRobinhoodEquityFeed(symbol: string): boolean {\n return !ROBINHOOD_NON_EQUITY_FEEDS.has(symbol.toUpperCase());\n}\n\n/**\n * Reverse-lookup a token address against a `TOKENS()` registry to recover its\n * symbol (case-insensitive). Returns undefined for the zero address or an\n * address that isn't registered. Used so a raw-address token spec can still be\n * classified as an equity feed (→ 96h max-price-age) the same way a symbol spec\n * is — otherwise a stock token passed by address silently falls back to the\n * contract's 26h default and trips `StalePrice` over long weekends.\n */\nexport function symbolForTokenAddress(\n address: string,\n tokens: Record<string, Address>,\n): string | undefined {\n if (!address || address.toLowerCase() === ZERO.toLowerCase()) return undefined;\n const want = address.toLowerCase();\n for (const [symbol, addr] of Object.entries(tokens)) {\n if (addr && addr !== ZERO && addr.toLowerCase() === want) return symbol;\n }\n return undefined;\n}\n\n/**\n * Resolve the equity max-price-age (seconds) for a Robinhood push-feed token\n * spec, which may be a SYMBOL or a raw 0x address. Returns the 96h equity\n * default for equity feeds, 0 (contract default) for crypto/stable feeds, and\n * `{ maxPriceAge: 0, unknownAddress: true }` when a raw address isn't in the\n * registry (caller should warn — we can't classify what we can't identify).\n *\n * `equityMaxAgeSeconds` is injected (from the portfolio builder's\n * EQUITY_MAX_PRICE_AGE_SECONDS) to avoid a cross-module import cycle.\n */\nexport function robinhoodEquityMaxAge(\n tokenSpec: string,\n tokens: Record<string, Address>,\n equityMaxAgeSeconds: number,\n): { maxPriceAge: number; unknownAddress: boolean } {\n let symbol: string | undefined;\n if (isAddress(tokenSpec)) {\n symbol = symbolForTokenAddress(tokenSpec, tokens);\n if (!symbol) return { maxPriceAge: 0, unknownAddress: true };\n } else {\n symbol = tokenSpec;\n }\n return {\n maxPriceAge: isRobinhoodEquityFeed(symbol) ? equityMaxAgeSeconds : 0,\n unknownAddress: false,\n };\n}\n\nconst ROBINHOOD_TESTNET_INFRA = {\n MULTICALL3: \"0xcA11bde05977b3631167028862bE2a173976CA11\" as Address, // Deterministic, same everywhere\n} as const;\n\n// ── ENS / Durin ──\n\nconst ROBINHOOD_TESTNET_ENS = {\n L2_REGISTRAR: ZERO,\n L2_REGISTRY: ZERO,\n} as const;\n\n// ── ERC-8004 Agent Identity ──\n\nconst ROBINHOOD_TESTNET_AGENT_REGISTRY = {\n IDENTITY_REGISTRY: ZERO,\n REPUTATION_REGISTRY: ZERO,\n} as const;\n\n// ── Sherwood Protocol (our deployed contracts) ──\n//\n// V2 redeploy (chain 46630): fresh factory/governor/vault-impl/executor plus a\n// full guardian layer (registry + sWOOD + WOOD fixture token) and the V2\n// live-NAV surface (PriceRouter, UniswapSwapAdapter via the Synthra QuoterV2\n// shim, Portfolio template, StrategyFactory). WOOD_TOKEN here is a testnet\n// fixture, not the mainnet OFT.\n//\n// GOVERNOR is the deploy-time bootstrap governor. Governors are per-vault since\n// PR #421 — resolve one at runtime via `factory.governorOf(vault)`\n// (lib/governor.ts `getGovernorOf`), never from this table.\nconst ROBINHOOD_TESTNET_SHERWOOD = {\n FACTORY: \"0xa91AA45AFF32f52b6357044B02a16EBA775feC0b\" as Address,\n GOVERNOR: ZERO, // zeroed since the post-#421 redeploy — always factory.governorOf(vault)\n GUARDIAN_REGISTRY: \"0xA400eFcfFc820C6f812203C58ee00423AeCC0903\" as Address,\n STAKED_WOOD: \"0x21A69A6c9814c0d339C57fDdafed3B283702a739\" as Address,\n WOOD_TOKEN: \"0xCCb4fB59cf40de1E23083037ee81Da1DD747D8d7\" as Address,\n STRATEGY_FACTORY: \"0xb683Bb8EEcBc2419BC3801df6FeA88f96657e670\" as Address,\n MERKL_DISTRIBUTOR: ZERO,\n} as const;\n\n// ── Venice (VVV governance + sVVV staking + DIEM compute) ──\n\nconst ROBINHOOD_TESTNET_VENICE = {\n VVV: ZERO,\n STAKING: ZERO,\n DIEM: ZERO,\n} as const;\n\n// ── Aerodrome (Base ve(3,3) DEX) ──\n\nconst ROBINHOOD_TESTNET_AERODROME = {\n ROUTER: ZERO,\n FACTORY: ZERO,\n} as const;\n\n// ── Strategy Templates (ERC-1167 clonable singletons) ──\n// Populated after running script/DeployTemplates.s.sol\n\nconst ROBINHOOD_TESTNET_STRATEGY_TEMPLATES = {\n MOONWELL_SUPPLY: ZERO as Address,\n AERODROME_LP: ZERO as Address,\n VENICE_INFERENCE: ZERO as Address,\n WSTETH_MOONWELL: ZERO as Address,\n MAMO_YIELD: ZERO as Address,\n HYPERLIQUID_PERP: ZERO as Address,\n HYPERLIQUID_GRID: ZERO as Address,\n // V2 redeploy PORTFOLIO_TEMPLATE (chain 46630).\n PORTFOLIO: \"0x67420Cc504d70a42Adfd8867d878afe0978C7d10\" as Address,\n} as const;\n\n// ── EAS (Ethereum Attestation Service) ──\n\nconst ROBINHOOD_TESTNET_EAS = {\n EAS: ZERO,\n SCHEMA_REGISTRY: ZERO,\n} as const;\n\n// ── EAS Schema UIDs (populated after running scripts/register-eas-schemas.ts) ──\n\nconst ROBINHOOD_TESTNET_EAS_SCHEMAS = {\n SYNDICATE_JOIN_REQUEST: ZERO_BYTES32,\n AGENT_APPROVED: ZERO_BYTES32,\n X402_RESEARCH: ZERO_BYTES32,\n VENICE_PROVISION: ZERO_BYTES32,\n VENICE_INFERENCE: ZERO_BYTES32,\n TRADE_EXECUTED: ZERO_BYTES32,\n} as const;\n\n// ── Robinhood Chain mainnet fork (Tenderly vnet, chain 9994663) ──\n//\n// Fork of Robinhood *mainnet*: USDG stablecoin (6-dec), official Uniswap v3+v4,\n// Chainlink PUSH feeds. VERIFIER_PROXY = 0 makes PortfolioStrategy run in\n// push-feed mode (feedIds are AggregatorV3 proxy addresses). Core addresses\n// come from sherwood-protocol/chains/9994663.json (fresh deploy). USDG is passed\n// as a raw --asset address (not a token-shape key); stock baskets use raw token\n// addresses + explicit --feed-ids/--swap-routes until the symbol registry lands.\n\nconst ROBINHOOD_FORK_TOKENS: typeof ROBINHOOD_TESTNET_TOKENS = {\n USDC: ZERO,\n USDG: \"0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168\" as Address,\n WETH: \"0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73\" as Address,\n WETH_CANONICAL: \"0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73\" as Address,\n cbETH: ZERO,\n wstETH: ZERO,\n cbBTC: ZERO,\n DAI: ZERO,\n AERO: ZERO,\n TSLA: \"0x322F0929c4625eD5bAd873c95208D54E1c003b2d\" as Address,\n AMZN: \"0x12f190a9F9d7D37a250758b26824B97CE941bF54\" as Address,\n PLTR: ZERO,\n NFLX: ZERO,\n AMD: \"0x86923f96303D656E4aa86D9d42D1e57ad2023fdC\" as Address,\n};\n\nconst ROBINHOOD_FORK_UNISWAP: typeof ROBINHOOD_TESTNET_UNISWAP = {\n SWAP_ROUTER: \"0xcaf681a66d020601342297493863e78c959e5cb2\" as Address,\n QUOTER_V2: \"0x33e885ed0ec9bf04ecfb19341582aadcb4c8a9e7\" as Address,\n SWAP_ADAPTER: \"0xdBf12248c68d1FCb6083f431A1d6ab6d0ef84E49\" as Address,\n};\n\n// VERIFIER_PROXY = 0 ⇒ PortfolioStrategy push-feed mode (Robinhood-mainnet-style).\nconst ROBINHOOD_FORK_CHAINLINK: typeof ROBINHOOD_TESTNET_CHAINLINK = {\n VERIFIER_PROXY: ZERO,\n WSTETH_ETH_FEED: ZERO,\n};\n\nconst ROBINHOOD_FORK_SHERWOOD: typeof ROBINHOOD_TESTNET_SHERWOOD = {\n FACTORY: \"0x02bc9B9C1A4322D5A5df86DadA0a2a02e45108B9\" as Address,\n GOVERNOR: ZERO, // per-vault — always factory.governorOf(vault)\n GUARDIAN_REGISTRY: \"0xdfEe38C4D7595c9c04AdBcaFE01E4Fd6FD6117f4\" as Address,\n STAKED_WOOD: \"0xD3037D28693cc7BB3DbF1E17B6e01C4ce628f6DF\" as Address,\n WOOD_TOKEN: \"0xF8BC08092C06dB6148114DCf82AF881F1085f92b\" as Address,\n STRATEGY_FACTORY: \"0xb3C009aECAeDd5ccC62Ec12eDAAA55F19C4A1eFb\" as Address,\n MERKL_DISTRIBUTOR: ZERO,\n};\n\nconst ROBINHOOD_FORK_STRATEGY_TEMPLATES: typeof ROBINHOOD_TESTNET_STRATEGY_TEMPLATES = {\n MOONWELL_SUPPLY: ZERO,\n AERODROME_LP: ZERO,\n VENICE_INFERENCE: ZERO,\n WSTETH_MOONWELL: ZERO,\n MAMO_YIELD: ZERO,\n HYPERLIQUID_PERP: ZERO,\n HYPERLIQUID_GRID: ZERO,\n PORTFOLIO: \"0x0e768a93B814282776022c3EBfc4e3f22Fa1605E\" as Address,\n};\n\n// ── Registries (map-based lookup) ──\n\nconst TOKEN_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_TOKENS> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_TOKENS,\n \"robinhood-fork\": ROBINHOOD_FORK_TOKENS,\n};\n\nconst MOONWELL_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_MOONWELL> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_MOONWELL,\n \"robinhood-fork\": ROBINHOOD_TESTNET_MOONWELL,\n};\n\nconst UNISWAP_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_UNISWAP> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_UNISWAP,\n \"robinhood-fork\": ROBINHOOD_FORK_UNISWAP,\n};\n\nconst INFRA_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_INFRA> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_INFRA,\n \"robinhood-fork\": ROBINHOOD_TESTNET_INFRA,\n};\n\nconst ENS_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_ENS> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_ENS,\n \"robinhood-fork\": ROBINHOOD_TESTNET_ENS,\n};\n\nconst AGENT_REGISTRY_MAP: Record<Network, typeof ROBINHOOD_TESTNET_AGENT_REGISTRY> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_AGENT_REGISTRY,\n \"robinhood-fork\": ROBINHOOD_TESTNET_AGENT_REGISTRY,\n};\n\nconst SHERWOOD_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_SHERWOOD> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_SHERWOOD,\n \"robinhood-fork\": ROBINHOOD_FORK_SHERWOOD,\n};\n\nconst VENICE_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_VENICE> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_VENICE,\n \"robinhood-fork\": ROBINHOOD_TESTNET_VENICE,\n};\n\nconst AERODROME_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_AERODROME> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_AERODROME,\n \"robinhood-fork\": ROBINHOOD_TESTNET_AERODROME,\n};\n\nconst STRATEGY_TEMPLATE_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_STRATEGY_TEMPLATES> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_STRATEGY_TEMPLATES,\n \"robinhood-fork\": ROBINHOOD_FORK_STRATEGY_TEMPLATES,\n};\n\nconst SYNTHRA_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_SYNTHRA> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_SYNTHRA,\n \"robinhood-fork\": ROBINHOOD_TESTNET_SYNTHRA, // unused on the fork (Uniswap, not Synthra)\n};\n\nconst CHAINLINK_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_CHAINLINK> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_CHAINLINK,\n \"robinhood-fork\": ROBINHOOD_FORK_CHAINLINK,\n};\n\nconst EAS_CONTRACT_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_EAS> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_EAS,\n \"robinhood-fork\": ROBINHOOD_TESTNET_EAS,\n};\n\nconst EAS_SCHEMA_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_EAS_SCHEMAS> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_EAS_SCHEMAS,\n \"robinhood-fork\": ROBINHOOD_TESTNET_EAS_SCHEMAS,\n};\n\n// ── Exports (functions, resolved at call time) ──\n\nexport function TOKENS() {\n return TOKEN_REGISTRY[getNetwork()];\n}\n\nexport function MOONWELL() {\n return MOONWELL_REGISTRY[getNetwork()];\n}\n\nexport function UNISWAP() {\n return { ...UNISWAP_REGISTRY[getNetwork()], ...overridesFor(\"UNISWAP\") };\n}\n\nexport function INFRA() {\n return INFRA_REGISTRY[getNetwork()];\n}\n\nexport function ENS() {\n return { ...ENS_REGISTRY[getNetwork()], ...overridesFor(\"ENS\") };\n}\n\nexport function AGENT_REGISTRY() {\n return AGENT_REGISTRY_MAP[getNetwork()];\n}\n\nexport function VENICE() {\n return VENICE_REGISTRY[getNetwork()];\n}\n\nexport function SHERWOOD() {\n return { ...SHERWOOD_REGISTRY[getNetwork()], ...overridesFor(\"SHERWOOD\") };\n}\n\nexport function AERODROME() {\n return AERODROME_REGISTRY[getNetwork()];\n}\n\nexport function STRATEGY_TEMPLATES() {\n return {\n ...STRATEGY_TEMPLATE_REGISTRY[getNetwork()],\n ...overridesFor(\"STRATEGY_TEMPLATES\"),\n };\n}\n\nexport function EAS_CONTRACTS() {\n return EAS_CONTRACT_REGISTRY[getNetwork()];\n}\n\nexport function EAS_SCHEMAS() {\n return EAS_SCHEMA_REGISTRY[getNetwork()];\n}\n\nexport function SYNTHRA() {\n return SYNTHRA_REGISTRY[getNetwork()];\n}\n\nexport function CHAINLINK() {\n return CHAINLINK_REGISTRY[getNetwork()];\n}\n","/**\n * SIM_ADDRESSES_FILE override layer (spec G1).\n *\n * Points the CLI at a vnet deployment: a chains/{chainId}.json-shaped file\n * (CAPS_SNAKE_CASE keys, written by contracts deploy scripts) is mapped onto\n * the CLI's per-registry key names and merged over the base network registry\n * at call time. Only 0x-string values are considered. Fail-closed: a set-but-\n * unreadable file throws rather than silently using mainnet addresses.\n */\nimport { readFileSync } from \"node:fs\";\nimport type { Address } from \"viem\";\n\ntype RegistryName = \"SHERWOOD\" | \"STRATEGY_TEMPLATES\" | \"ENS\" | \"UNISWAP\";\n\n// chains-json key → CLI registry key, grouped by target registry.\n// Extend when deploy scripts gain keys the CLI reads (Task 1 Step 2).\n//\n// STRATEGY_TEMPLATES note (Task 1 Step 2 finding): the deploy scripts\n// (DeployTemplates.s.sol / DeployStrategyFactory.s.sol) write chains.json\n// keys with a `_TEMPLATE` suffix (e.g. `MOONWELL_SUPPLY_TEMPLATE`), but the\n// CLI-side STRATEGY_TEMPLATES() registry (cli/src/lib/addresses.ts\n// `BASE_STRATEGY_TEMPLATES`) and its consumers (e.g.\n// cli/src/commands/strategy-template.ts `addressKey: \"MOONWELL_SUPPLY\"`) key\n// off the UNSUFFIXED name. The map below strips the suffix so overrides\n// actually reach the keys the CLI reads.\nconst CHAINS_TO_CLI: Record<RegistryName, Record<string, string>> = {\n SHERWOOD: {\n SYNDICATE_FACTORY: \"FACTORY\",\n SYNDICATE_GOVERNOR: \"GOVERNOR\",\n GUARDIAN_REGISTRY: \"GUARDIAN_REGISTRY\",\n STAKED_WOOD: \"STAKED_WOOD\",\n WOOD: \"WOOD_TOKEN\",\n WOOD_TOKEN: \"WOOD_TOKEN\",\n STRATEGY_FACTORY: \"STRATEGY_FACTORY\",\n },\n STRATEGY_TEMPLATES: {\n MOONWELL_SUPPLY_TEMPLATE: \"MOONWELL_SUPPLY\",\n AERODROME_LP_TEMPLATE: \"AERODROME_LP\",\n VENICE_INFERENCE_TEMPLATE: \"VENICE_INFERENCE\",\n WSTETH_MOONWELL_TEMPLATE: \"WSTETH_MOONWELL\",\n MAMO_YIELD_TEMPLATE: \"MAMO_YIELD\",\n PORTFOLIO_TEMPLATE: \"PORTFOLIO\",\n HYPERLIQUID_PERP_TEMPLATE: \"HYPERLIQUID_PERP\",\n HYPERLIQUID_GRID_TEMPLATE: \"HYPERLIQUID_GRID\",\n },\n ENS: {\n L2_REGISTRAR: \"L2_REGISTRAR\",\n L2_REGISTRY: \"L2_REGISTRY\",\n },\n UNISWAP: {\n UNISWAP_SWAP_ADAPTER: \"SWAP_ADAPTER\",\n },\n};\n\nlet cached: Record<string, Address> | null | undefined;\n\nfunction loadFile(): Record<string, Address> | null {\n if (cached !== undefined) return cached;\n const file = process.env.SIM_ADDRESSES_FILE;\n if (!file) {\n cached = null;\n return cached;\n }\n let raw: Record<string, unknown>;\n try {\n raw = JSON.parse(readFileSync(file, \"utf8\")) as Record<string, unknown>;\n } catch (err) {\n throw new Error(\n `SIM_ADDRESSES_FILE is set (${file}) but unreadable: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n const out: Record<string, Address> = {};\n for (const [k, v] of Object.entries(raw)) {\n if (typeof v === \"string\" && v.startsWith(\"0x\")) out[k] = v as Address;\n }\n cached = out;\n return cached;\n}\n\n/** Mapped overrides for one CLI registry; {} when SIM_ADDRESSES_FILE unset. */\nexport function overridesFor(registry: RegistryName): Record<string, Address> {\n const file = loadFile();\n if (!file) return {};\n const map = CHAINS_TO_CLI[registry];\n const out: Record<string, Address> = {};\n for (const [chainsKey, cliKey] of Object.entries(map)) {\n if (file[chainsKey]) out[cliKey] = file[chainsKey];\n }\n return out;\n}\n\nexport function __resetOverridesCacheForTests(): void {\n cached = undefined;\n}\n"],"mappings":"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","names":[]}
|