@sherwoodagent/cli 0.73.4 → 0.74.3
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-KP7M4IPM.js → abis-OLIDCWDS.js} +2 -2
- package/dist/{addresses-DGB3D457.js → addresses-OFFTM6NG.js} +4 -4
- package/dist/{agent-UNSW5IPO.js → agent-B7V5L2ZL.js} +8 -8
- package/dist/{chat-KT2WVDT2.js → chat-CXUU4AXK.js} +9 -10
- package/dist/{chat-KT2WVDT2.js.map → chat-CXUU4AXK.js.map} +1 -1
- package/dist/{chunk-ROKE6ZAW.js → chunk-2OHX3O55.js} +6 -20
- package/dist/chunk-2OHX3O55.js.map +1 -0
- package/dist/chunk-3ZOWP3VO.js +173 -0
- package/dist/chunk-3ZOWP3VO.js.map +1 -0
- package/dist/chunk-4LKU7ASB.js +1253 -0
- package/dist/chunk-4LKU7ASB.js.map +1 -0
- package/dist/{chunk-GSC7PVEO.js → chunk-6MV4ESXM.js} +43 -7
- package/dist/chunk-6MV4ESXM.js.map +1 -0
- package/dist/{chunk-CHWBQJLT.js → chunk-6UEQUVTQ.js} +8 -21
- package/dist/chunk-6UEQUVTQ.js.map +1 -0
- package/dist/{chunk-NPWYX6NU.js → chunk-BD4ZV7FQ.js} +3 -3
- package/dist/{chunk-BKJ7HYX7.js → chunk-DGLLSZ2D.js} +10 -10
- package/dist/chunk-DGLLSZ2D.js.map +1 -0
- package/dist/chunk-EGJESQXZ.js +1 -0
- package/dist/{chunk-ZURDCYGU.js → chunk-EW6FTUOL.js} +9 -5
- package/dist/chunk-EW6FTUOL.js.map +1 -0
- package/dist/{chunk-2U4TWPWQ.js → chunk-K3EYEJMT.js} +5 -5
- package/dist/{chunk-DXJJMRBM.js → chunk-LHVSS27T.js} +2 -2
- package/dist/{chunk-GU5VZGXB.js → chunk-O65AC2YS.js} +5 -5
- package/dist/chunk-TU655ZTV.js +3866 -0
- package/dist/chunk-TU655ZTV.js.map +1 -0
- package/dist/{chunk-IFL5SREW.js → chunk-UINMHN6S.js} +2 -2
- package/dist/{chunk-CZRJ5GWE.js → chunk-YADJ5YWY.js} +54 -24
- package/dist/chunk-YADJ5YWY.js.map +1 -0
- package/dist/{client-NAL3HVLK.js → client-C3C6IXAH.js} +4 -4
- package/dist/{config-FAQO37S7.js → config-7HU4X7EK.js} +4 -4
- package/dist/{eas-QAH7XVLK.js → eas-XWQYAUEM.js} +7 -7
- package/dist/{governor-S56M6BV6.js → governor-NHXBIFFB.js} +7 -7
- package/dist/index.js +201 -1286
- package/dist/index.js.map +1 -1
- package/dist/{network-MKMX2NG6.js → network-WU2QC3L4.js} +3 -3
- package/dist/{price-HHDBMKIE.js → price-QSVIM6QY.js} +15 -37
- package/dist/price-QSVIM6QY.js.map +1 -0
- package/dist/providers-YOOQFBN2.js +31 -0
- package/dist/providers-YOOQFBN2.js.map +1 -0
- package/dist/{research-IJBOMYL3.js → research-NQKYGTLY.js} +9 -9
- package/dist/{session-L67AVWBY.js → session-NLI6UFKB.js} +19 -174
- package/dist/session-NLI6UFKB.js.map +1 -0
- package/dist/{trade-LGFQEK3I.js → trade-6VYB6YJZ.js} +277 -43
- package/dist/trade-6VYB6YJZ.js.map +1 -0
- package/dist/{vault-XWFPGHRA.js → vault-45POYGLN.js} +14 -9
- package/dist/{xmtp-6US7GH3Z.js → xmtp-KH5I6GOL.js} +11 -15
- package/dist/xmtp-KH5I6GOL.js.map +1 -0
- package/package.json +2 -1
- package/dist/chunk-BKJ7HYX7.js.map +0 -1
- package/dist/chunk-BQMOE4FJ.js +0 -1629
- package/dist/chunk-BQMOE4FJ.js.map +0 -1
- package/dist/chunk-CHWBQJLT.js.map +0 -1
- package/dist/chunk-CZRJ5GWE.js.map +0 -1
- package/dist/chunk-DIZEB2VV.js +0 -325
- package/dist/chunk-DIZEB2VV.js.map +0 -1
- package/dist/chunk-GSC7PVEO.js.map +0 -1
- package/dist/chunk-ROKE6ZAW.js.map +0 -1
- package/dist/chunk-ZURDCYGU.js.map +0 -1
- package/dist/price-HHDBMKIE.js.map +0 -1
- package/dist/research-4TBGYEVI.js +0 -14
- package/dist/session-L67AVWBY.js.map +0 -1
- package/dist/trade-LGFQEK3I.js.map +0 -1
- package/dist/xmtp-6US7GH3Z.js.map +0 -1
- /package/dist/{abis-KP7M4IPM.js.map → abis-OLIDCWDS.js.map} +0 -0
- /package/dist/{addresses-DGB3D457.js.map → addresses-OFFTM6NG.js.map} +0 -0
- /package/dist/{agent-UNSW5IPO.js.map → agent-B7V5L2ZL.js.map} +0 -0
- /package/dist/{chunk-NPWYX6NU.js.map → chunk-BD4ZV7FQ.js.map} +0 -0
- /package/dist/{client-NAL3HVLK.js.map → chunk-EGJESQXZ.js.map} +0 -0
- /package/dist/{chunk-2U4TWPWQ.js.map → chunk-K3EYEJMT.js.map} +0 -0
- /package/dist/{chunk-DXJJMRBM.js.map → chunk-LHVSS27T.js.map} +0 -0
- /package/dist/{chunk-GU5VZGXB.js.map → chunk-O65AC2YS.js.map} +0 -0
- /package/dist/{chunk-IFL5SREW.js.map → chunk-UINMHN6S.js.map} +0 -0
- /package/dist/{config-FAQO37S7.js.map → client-C3C6IXAH.js.map} +0 -0
- /package/dist/{eas-QAH7XVLK.js.map → config-7HU4X7EK.js.map} +0 -0
- /package/dist/{governor-S56M6BV6.js.map → eas-XWQYAUEM.js.map} +0 -0
- /package/dist/{network-MKMX2NG6.js.map → governor-NHXBIFFB.js.map} +0 -0
- /package/dist/{research-4TBGYEVI.js.map → network-WU2QC3L4.js.map} +0 -0
- /package/dist/{research-IJBOMYL3.js.map → research-NQKYGTLY.js.map} +0 -0
- /package/dist/{vault-XWFPGHRA.js.map → vault-45POYGLN.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/swap-router.ts","../src/lib/template-encoder.ts","../src/strategies/moonwell-supply-template.ts","../src/strategies/venice-inference-template.ts","../src/strategies/aerodrome-lp-template.ts","../src/strategies/wsteth-moonwell-template.ts","../src/strategies/mamo-yield-template.ts","../src/strategies/portfolio-template.ts","../src/strategies/hyperliquid-perp-template.ts","../src/strategies/hyperliquid-grid-template.ts"],"sourcesContent":["/**\n * SwapRouter — the single owner of \"swap tokenIn→tokenOut on the current chain\".\n *\n * Surface (small, deep):\n * - detectRoute(tokenIn, tokenOut, feeTier?) → Route (wraps template-encoder's\n * detectSwapRoute; pure on the current deployment target)\n * - buildSwapCalldata(route, opts?) → adapter swapExtraData (delegates\n * byte encoding to template-encoder's tested buildSwapExtraData)\n * - quote({tokenIn, tokenOut, amountIn}) → Route + amountOut via the active\n * network's QuoterV2 (Synthra shim on robinhood-testnet)\n *\n * Quoting primitives (getQuote / getMultiHopQuote) moved here from lib/quote.ts,\n * which is now a back-compat re-export shim. QuoterV2's quote functions are NOT\n * view — they revert internally after computing — so we use eth_call and decode\n * the return data. The client is injectable (`deps.client`) so tests never need\n * a live RPC.\n *\n * Path/extraData byte layouts are owned by template-encoder.ts (golden-vector\n * tested) and strategies/portfolio-template.ts (v4 modes) — this module only\n * composes them; it never re-implements an encoding.\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeFunctionData, decodeFunctionResult } from \"viem\";\nimport { getPublicClient } from \"./client.js\";\nimport { getNetwork } from \"./network.js\";\nimport { UNISWAP } from \"./addresses.js\";\nimport { UNISWAP_QUOTER_V2_ABI } from \"./abis.js\";\nimport { buildSwapExtraData, detectSwapRoute, encodeV3Path } from \"./template-encoder.js\";\n\nexport const DEFAULT_FEE_TIER = 3000;\n\nconst ZERO: Address = \"0x0000000000000000000000000000000000000000\";\n\n/**\n * Minimal client surface needed for quoting (eth_call). getPublicClient()\n * satisfies it; tests inject a mock.\n */\nexport interface QuoterClient {\n call(args: { to: Address; data: Hex }): Promise<{ data?: Hex }>;\n}\n\nexport interface QuoteDeps {\n client?: QuoterClient;\n}\n\nexport type Route =\n | {\n kind: \"v3-direct\";\n tokenIn: Address;\n tokenOut: Address;\n feeTier: number;\n routeDesc: string;\n }\n | {\n kind: \"v3-hop\";\n tokenIn: Address;\n tokenOut: Address;\n via: Address;\n feeIn: number;\n feeOut: number;\n routeDesc: string;\n };\n\nexport interface QuoteResult {\n amountOut: bigint;\n sqrtPriceX96After: bigint;\n gasEstimate: bigint;\n}\n\nexport interface Quote extends QuoteResult {\n route: Route;\n}\n\n// ── Route detection ──\n\n/**\n * Detect the swap route for a token pair on the current chain.\n * Wraps template-encoder's detectSwapRoute (which owns the per-chain routing\n * decision); on the current deployment target this is pure — always a direct\n * v3-style route through the Synthra-backed adapter.\n */\nexport async function detectRoute(\n tokenIn: Address,\n tokenOut: Address,\n preferredFeeTier: number = DEFAULT_FEE_TIER,\n): Promise<Route> {\n const detected = await detectSwapRoute(tokenIn, tokenOut, preferredFeeTier);\n if (!detected) {\n throw new Error(`No swap route found for ${tokenIn}→${tokenOut} (fee ${preferredFeeTier})`);\n }\n return {\n kind: \"v3-direct\",\n tokenIn,\n tokenOut,\n feeTier: preferredFeeTier,\n routeDesc: detected.routeDesc,\n };\n}\n\n// ── Calldata building ──\n\n/**\n * Build adapter swapExtraData for a route. Byte encoding is delegated to\n * template-encoder's tested buildSwapExtraData (mode 0 single-hop / mode 1\n * multi-hop with a per-hop slippage budget).\n */\nexport function buildSwapCalldata(\n route: Route,\n opts: { perHopSlippageBps?: number } = {},\n): Hex {\n const network = getNetwork();\n if (route.kind === \"v3-hop\") {\n return buildSwapExtraData(\n network,\n route.tokenIn,\n route.tokenOut,\n route.feeIn,\n { via: route.via, feeIn: route.feeIn, feeOut: route.feeOut },\n opts.perHopSlippageBps ?? 100,\n );\n }\n return buildSwapExtraData(network, route.tokenIn, route.tokenOut, route.feeTier);\n}\n\n// ── Quoting ──\n\nfunction quoterAddress(): Address {\n const quoter = UNISWAP().QUOTER_V2;\n if (quoter === ZERO) {\n throw new Error(\"QuoterV2 not deployed on this network\");\n }\n return quoter;\n}\n\n/**\n * Quote a swap on the current chain: detect the route, then price it through\n * the network's QuoterV2 (Synthra shim on robinhood-testnet).\n */\nexport async function quote(\n params: { tokenIn: Address; tokenOut: Address; amountIn: bigint; feeTier?: number },\n deps: QuoteDeps = {},\n): Promise<Quote> {\n const route = await detectRoute(params.tokenIn, params.tokenOut, params.feeTier);\n if (route.kind === \"v3-hop\") {\n const path = encodeSwapPath(\n [route.tokenIn, route.via, route.tokenOut],\n [route.feeIn, route.feeOut],\n );\n const result = await getMultiHopQuote({ path, amountIn: params.amountIn }, deps);\n return { route, ...result };\n }\n const result = await getQuote(\n {\n tokenIn: route.tokenIn,\n tokenOut: route.tokenOut,\n amountIn: params.amountIn,\n fee: route.feeTier,\n },\n deps,\n );\n return { route, ...result };\n}\n\n/**\n * Get a single-hop swap quote from QuoterV2 (moved from lib/quote.ts).\n */\nexport async function getQuote(\n params: { tokenIn: Address; tokenOut: Address; amountIn: bigint; fee: number },\n deps: QuoteDeps = {},\n): Promise<QuoteResult> {\n const client = deps.client ?? getPublicClient();\n\n const calldata = encodeFunctionData({\n abi: UNISWAP_QUOTER_V2_ABI,\n functionName: \"quoteExactInputSingle\",\n args: [\n {\n tokenIn: params.tokenIn,\n tokenOut: params.tokenOut,\n amountIn: params.amountIn,\n fee: params.fee,\n sqrtPriceLimitX96: 0n,\n },\n ],\n });\n\n const { data } = await client.call({ to: quoterAddress(), data: calldata });\n\n if (!data) {\n throw new Error(\"Quoter returned no data — pool may not exist for this pair/fee\");\n }\n\n const [amountOut, sqrtPriceX96After, , gasEstimate] = decodeFunctionResult({\n abi: UNISWAP_QUOTER_V2_ABI,\n functionName: \"quoteExactInputSingle\",\n data,\n }) as [bigint, bigint, number, bigint];\n\n return { amountOut, sqrtPriceX96After, gasEstimate };\n}\n\n/**\n * Get a multi-hop swap quote from QuoterV2 (moved from lib/quote.ts).\n */\nexport async function getMultiHopQuote(\n params: { path: Hex; amountIn: bigint },\n deps: QuoteDeps = {},\n): Promise<QuoteResult> {\n const client = deps.client ?? getPublicClient();\n\n const calldata = encodeFunctionData({\n abi: UNISWAP_QUOTER_V2_ABI,\n functionName: \"quoteExactInput\",\n args: [params.path, params.amountIn],\n });\n\n const { data } = await client.call({ to: quoterAddress(), data: calldata });\n\n if (!data) {\n throw new Error(\"Quoter returned no data — pool may not exist for this path\");\n }\n\n const [amountOut, , , gasEstimate] = decodeFunctionResult({\n abi: UNISWAP_QUOTER_V2_ABI,\n functionName: \"quoteExactInput\",\n data,\n }) as [bigint, bigint[], number[], bigint];\n\n return { amountOut, sqrtPriceX96After: 0n, gasEstimate };\n}\n\n// ── Pure helpers (moved from lib/quote.ts) ──\n\n/**\n * Apply slippage tolerance to a quote amount.\n * Returns the minimum acceptable output amount.\n */\nexport function applySlippage(amountOut: bigint, slippageBps: number): bigint {\n return (amountOut * BigInt(10000 - slippageBps)) / 10000n;\n}\n\n/**\n * Encode a Uniswap V3 multi-hop swap path (address + uint24 fee + address ...).\n * Validates the shape here (>= 2 tokens), then delegates the byte layout to\n * template-encoder's tested encodeV3Path.\n */\nexport function encodeSwapPath(tokens: Address[], fees: number[]): Hex {\n if (tokens.length < 2 || fees.length !== tokens.length - 1) {\n throw new Error(\"Invalid path: need at least 2 tokens and (tokens-1) fees\");\n }\n return encodeV3Path(tokens, fees);\n}\n\n/** Token decimals for display purposes (moved from lib/quote.ts). */\nexport const TOKEN_DECIMALS: Record<string, number> = {\n USDC: 6,\n WETH: 18,\n cbETH: 18,\n wstETH: 18,\n cbBTC: 8,\n DAI: 18,\n AERO: 18,\n};\n","/**\n * Template encoder — pure params → bytes encoding for strategy templates.\n *\n * Extracted from commands/strategy-template.ts so the calldata-producing logic\n * is testable without a chain. The interface is deliberately small:\n *\n * - buildInitDataForTemplate(templateKey, opts, vault, resolved?) — per-template\n * initialize() payload + the asset/amount the vault must fund.\n * - buildCallsForTemplate(templateKey, clone, asset, amount, extraApprovals?) —\n * the execute/settle BatchCall arrays for a proposal.\n *\n * Secondary exports (parseSwapRouteSpec, buildSwapExtraData, encodeV3Path,\n * parseAlignedOverrides, computeProposalAssetChecks, resolve* helpers) exist for\n * the command layer and for tests.\n *\n * PURITY RULE: nothing in this module performs chain I/O or touches the signer.\n * The two inputs that historically needed RPC (the Venice minVVV auto-quote and\n * the Aerodrome tokenA/tokenB decimals) are supplied by the caller via\n * `ResolvedChainInputs` — see resolveChainInputsForTemplate in\n * commands/strategy-template.ts. Registry lookups (TOKENS(), CHAINLINK(), …) are\n * config reads keyed off the network singleton, not RPC.\n */\n\nimport type { Address, Hex } from \"viem\";\nimport {\n parseUnits,\n isAddress,\n encodeAbiParameters,\n concat,\n numberToHex,\n} from \"viem\";\nimport chalk from \"chalk\";\n\nimport { getNetwork } from \"./network.js\";\nimport {\n TOKENS,\n MOONWELL,\n VENICE,\n AERODROME,\n UNISWAP,\n SYNTHRA,\n CHAINLINK,\n ROBINHOOD_STOCK_ROUTES,\n robinhoodEquityMaxAge,\n} from \"./addresses.js\";\nimport type { BatchCall } from \"./batch.js\";\n\nimport * as moonwellBuilder from \"../strategies/moonwell-supply-template.js\";\nimport * as veniceBuilder from \"../strategies/venice-inference-template.js\";\nimport * as aerodromeBuilder from \"../strategies/aerodrome-lp-template.js\";\nimport * as wstethBuilder from \"../strategies/wsteth-moonwell-template.js\";\nimport * as mamoBuilder from \"../strategies/mamo-yield-template.js\";\nimport * as portfolioBuilder from \"../strategies/portfolio-template.js\";\nimport * as hyperliquidPerpBuilder from \"../strategies/hyperliquid-perp-template.js\";\nimport * as hyperliquidGridBuilder from \"../strategies/hyperliquid-grid-template.js\";\n\nconst ZERO: Address = \"0x0000000000000000000000000000000000000000\";\nconst ZERO_BYTES32 =\n \"0x0000000000000000000000000000000000000000000000000000000000000000\" as Hex;\n\n/**\n * Chain-derived inputs the encoder cannot (and must not) fetch itself.\n * Resolved by the command layer BEFORE encoding (see\n * resolveChainInputsForTemplate in commands/strategy-template.ts).\n */\nexport interface ResolvedChainInputs {\n /** venice-inference: agent wallet — the caller defaults it to the signer. */\n veniceAgent?: Address;\n /**\n * venice-inference: auto-quoted minVVV (18-dec) for a non-direct path when\n * --min-vvv was not passed. Quoted via the Aerodrome router off-module.\n */\n veniceMinVVV?: bigint;\n /** aerodrome-lp: on-chain decimals() of tokenA / tokenB. */\n aerodromeDecimals?: { decimalsA: number; decimalsB: number };\n}\n\n// ── Uniswap V3 swap routing helpers ──\n\n/**\n * Encode Uniswap V3 packed path: token (20 bytes) + fee (3 bytes) + token (20 bytes) [+ fee + token ...]\n */\nexport function encodeV3Path(tokens: Address[], fees: number[]): Hex {\n if (tokens.length !== fees.length + 1) throw new Error(\"tokens.length must be fees.length + 1\");\n const parts: Hex[] = [];\n for (let i = 0; i < tokens.length; i++) {\n parts.push(tokens[i].toLowerCase() as Hex);\n if (i < fees.length) {\n // fee as 3 bytes (uint24)\n parts.push(numberToHex(fees[i], { size: 3 }));\n }\n }\n return concat(parts);\n}\n\n/**\n * Build swapExtraData for the UniswapSwapAdapter.\n *\n * Mode 0 — single-hop: 0x00 + abi.encode(uint24 fee)\n * Mode 1 — multi-hop: 0x01 + abi.encode(bytes path, uint16 perHopSlippageBps)\n *\n * Sherlock run #2 #11: mode-1 extraData now carries a per-hop slippage\n * budget so the adapter's `_chainedSingleHops` can enforce a per-hop\n * `amountOutMinimum` derived from a quoter pre-call at swap time. This\n * closes the cascading-sandwich attack on intermediate hops. Default\n * to 100 bps (1%) per hop unless the caller overrides — conservative\n * for typical V3 routes; mainnet templates with deeper pools can\n * tighten this. The adapter still enforces the top-level `amountOutMin`\n * on the final hop, so cumulative slippage is doubly capped.\n *\n * robinhood-testnet uses the registry UniswapSwapAdapter (Synthra-router-backed,\n * QuoterV2-shim), which consumes the SAME mode-prefixed encoding as the other\n * chains — mode 0 single-hop / mode 1 multi-hop — so no special-case here.\n */\nexport function buildSwapExtraData(\n network: string,\n tokenIn: Address,\n tokenOut: Address,\n feeTier: number,\n hop?: { via: Address; feeIn: number; feeOut: number },\n perHopSlippageBps: number = 100,\n): Hex {\n if (hop) {\n // Multi-hop: tokenIn → hop.via → tokenOut\n const path = encodeV3Path([tokenIn, hop.via, tokenOut], [hop.feeIn, hop.feeOut]);\n const encoded = encodeAbiParameters(\n [{ type: \"bytes\" }, { type: \"uint16\" }],\n [path, perHopSlippageBps],\n );\n return `0x01${encoded.slice(2)}` as Hex;\n }\n\n // Single-hop: mode 0\n const encoded = encodeAbiParameters([{ type: \"uint24\" }], [feeTier]);\n return `0x00${encoded.slice(2)}` as Hex;\n}\n\n// ── Explicit per-token swap-route spec parsing (--swap-routes) ──\n//\n// One entry per allocation, comma-separated at the flag level. Each entry:\n// 'v3:<fee>' → mode 0 (v3 single-hop)\n// 'v4:<fee>:<tickSpacing>' → mode 2 (v4 single-hop hookless)\n// 'v4path:<hop>+<hop>+...' → mode 3 (v4 multi-hop hookless)\n// where hop = '<currency>@<fee>:<tickSpacing>' and\n// currency ∈ { 'eth'|'native' → address(0), 'self' → this allocation's\n// token, or a literal 0x-address }. The last hop's currency MUST resolve\n// to the allocation token (contract-enforced); 'self' is the ergonomic form.\n\nexport function parseSwapRouteSpec(spec: string, token: Address): Hex {\n const s = spec.trim();\n const [kind, ...restParts] = s.split(\":\");\n const rest = restParts.join(\":\");\n switch (kind) {\n case \"v3\": {\n const fee = Number(rest);\n if (!Number.isInteger(fee) || fee <= 0) throw new Error(`bad v3 fee in '${spec}'`);\n return portfolioBuilder.v3SingleHopExtraData(fee);\n }\n case \"v4\": {\n const [feeStr, tsStr] = rest.split(\":\");\n const fee = Number(feeStr);\n const tickSpacing = Number(tsStr);\n if (!Number.isInteger(fee) || fee <= 0) throw new Error(`bad v4 fee in '${spec}'`);\n if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) throw new Error(`bad v4 tickSpacing in '${spec}'`);\n return portfolioBuilder.v4SingleHopExtraData(fee, tickSpacing);\n }\n case \"v4path\": {\n const hops = rest.split(\"+\").map((hopStr) => {\n const [currencyRaw, feeTs] = hopStr.split(\"@\");\n if (!feeTs) throw new Error(`bad v4path hop '${hopStr}' in '${spec}' (expected currency@fee:tickSpacing)`);\n const [feeStr, tsStr] = feeTs.split(\":\");\n const fee = Number(feeStr);\n const tickSpacing = Number(tsStr);\n if (!Number.isInteger(fee) || fee <= 0) throw new Error(`bad v4path fee in '${spec}'`);\n if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) throw new Error(`bad v4path tickSpacing in '${spec}'`);\n const c = currencyRaw.trim().toLowerCase();\n let currency: Address;\n if (c === \"eth\" || c === \"native\") currency = ZERO;\n else if (c === \"self\") currency = token;\n else if (isAddress(currencyRaw.trim())) currency = currencyRaw.trim() as Address;\n else throw new Error(`bad v4path currency '${currencyRaw}' in '${spec}' (use eth/native/self/0x-address)`);\n return { currency, fee, tickSpacing };\n });\n return portfolioBuilder.v4PathExtraData(hops);\n }\n default:\n throw new Error(`unknown swap-route kind '${kind}' in '${spec}' (use v3/v4/v4path)`);\n }\n}\n\n/**\n * Auto-detect swap route for a token pair on Uniswap V3.\n * Returns { direct: true, feeTier } or { direct: false, hop } or null if no route found.\n *\n * NOTE (encoder purity): on the current deployment target this performs NO\n * chain I/O — the multi-chain v3 pool probing was removed with Base/HyperEVM.\n * If per-chain detection comes back, the pool probing belongs in the command\n * layer (resolveChainInputsForTemplate), NOT here.\n */\nexport async function detectSwapRoute(\n asset: Address,\n token: Address,\n preferredFeeTier: number,\n): Promise<{ extraData: Hex; routeDesc: string } | null> {\n const network = getNetwork();\n // Current deployment target (robinhood-testnet) uses a direct v3-style route\n // via the Synthra-backed adapter. Multi-chain v3 auto-detect (Base/HyperEVM)\n // was removed with those chains; re-add per-chain detection here when a chain\n // with distinct routing comes back.\n return {\n extraData: buildSwapExtraData(network, asset, token, preferredFeeTier),\n routeDesc: `direct (fee ${preferredFeeTier})`,\n };\n}\n\n// ── Helpers for building init data per template ──\n\n/**\n * Pure (no-RPC) derivation of the assets a propose call will pull from the\n * vault. Mirrors the asset/amount slice of `buildInitDataForTemplate` so the\n * propose preflight can balance-check the vault BEFORE clone + init burns\n * any gas. Returns one entry per token the vault has to fund — single\n * entry for most templates, two for aerodrome-lp (tokenA + tokenB).\n *\n * Templates whose amount is `0n` (hyperliquid-perp / -grid in dynamic-all\n * mode, wsteth-moonwell without --amount) intentionally return entries\n * with `amount === 0n`; the caller short-circuits on those.\n *\n * Kept in sync with `buildInitDataForTemplate` per-branch logic. The\n * sync-invariant suite in template-encoder.test.ts enforces the mirror for\n * venice-inference, wsteth-moonwell, mamo-yield, portfolio, hyperliquid-perp\n * and hyperliquid-grid. NOT enforced there: moonwell-supply (no Moonwell\n * market on the Robinhood-testnet token registry, so the branch is\n * unreachable in tests) and aerodrome-lp (returns [] — per-leg decimals\n * need RPC). Diverging here only weakens the preflight guard — the real\n * values still come from `buildInitDataForTemplate`, so we'd just miss a\n * warning, never produce an inconsistent on-chain call.\n */\nexport function computeProposalAssetChecks(\n templateKey: string,\n opts: Record<string, string | boolean | undefined>,\n): { asset: Address; amount: bigint; label: string }[] {\n if (templateKey === \"moonwell-supply\" || templateKey === \"mamo-yield\") {\n if (!opts.amount) return [];\n const token = (opts.token as string) || \"USDC\";\n const asset = resolveToken(token);\n const decimals = assetDecimalsForSymbol(token);\n return [{ asset, amount: parseUnits(opts.amount as string, decimals), label: token.toUpperCase() }];\n }\n\n if (templateKey === \"venice-inference\") {\n if (!opts.amount) return [];\n const assetSymbol = (opts.asset as string) || \"USDC\";\n const asset = resolveToken(assetSymbol);\n const decimals = assetDecimalsForSymbol(assetSymbol);\n return [{ asset, amount: parseUnits(opts.amount as string, decimals), label: assetSymbol.toUpperCase() }];\n }\n\n if (templateKey === \"aerodrome-lp\") {\n // Aerodrome needs both legs of the pair funded. We can't compute the\n // per-leg parseUnits without a decimals() RPC, so we fall back to a\n // raw-units balance check (vault must hold at least `amountA` raw of\n // tokenA AND `amountB` raw of tokenB). Worst case: a stricter check\n // than needed, never permissive.\n if (!opts.tokenA || !opts.tokenB || !opts.amountA || !opts.amountB) return [];\n // amountA/amountB are human strings — without decimals we can't normalize.\n // Skip the precise check for aerodrome and let buildInitDataForTemplate\n // handle errors. (Other templates cover the common --amount footgun.)\n return [];\n }\n\n if (templateKey === \"wsteth-moonwell\") {\n if (!opts.amount) return []; // dynamic-all mode\n return [{\n asset: TOKENS().WETH,\n amount: parseUnits(opts.amount as string, 18),\n label: \"WETH\",\n }];\n }\n\n if (templateKey === \"portfolio\") {\n if (!opts.amount) return [];\n // Keep this in lock-step with buildInitDataForTemplate's portfolio branch:\n // default asset is USDG on robinhood mainnet (6 dec, no USDC there), WETH on\n // robinhood-testnet, USDC elsewhere; decimals resolved from token metadata.\n const assetSymbol = (opts.asset as string) || defaultPortfolioAsset();\n const asset = resolveToken(assetSymbol);\n const decimals = assetDecimalsForSymbol(assetSymbol);\n return [{ asset, amount: parseUnits(opts.amount as string, decimals), label: assetSymbol.toUpperCase() }];\n }\n\n if (templateKey === \"hyperliquid-perp\" || templateKey === \"hyperliquid-grid\") {\n if (!opts.amount) return []; // dynamic-all mode — skip check\n const token = (opts.token as string) || \"USDC\";\n const asset = resolveToken(token);\n const decimals = assetDecimalsForSymbol(token);\n return [{ asset, amount: parseUnits(opts.amount as string, decimals), label: token.toUpperCase() }];\n }\n\n return [];\n}\n\n/**\n * Parse a comma-separated per-allocation override flag (--feed-ids,\n * --price-decimals, --swap-routes, --max-price-ages) into a slot-aligned array.\n *\n * Empty entries are PRESERVED (trimmed to \"\"), NOT filtered — so partial\n * overrides work: an empty slot falls through to that flag's per-slot\n * auto-resolve default (e.g. `--price-decimals \"8,,8\"` overrides slots 0 and 2\n * and auto-resolves slot 1). Filtering empties would collapse the length and\n * either misalign the remaining entries or trip the length check.\n *\n * Alignment is validated only when the flag is PRESENT (`raw !== undefined`):\n * an unset flag yields `[]` and `mismatch: false`. A present flag whose entry\n * count ≠ `expectedLen` returns `mismatch: true` for the caller to hard-exit.\n * (An unset flag is `undefined` here; `\"\"` — an explicitly empty flag — is\n * \"present\" and splits to `[\"\"]`, i.e. one empty slot.)\n */\nexport function parseAlignedOverrides(\n raw: string | undefined,\n expectedLen: number,\n): { values: string[]; mismatch: boolean } {\n if (raw === undefined) return { values: [], mismatch: false };\n const values = raw.split(\",\").map((s) => s.trim());\n return { values, mismatch: values.length !== expectedLen };\n}\n\nexport async function buildInitDataForTemplate(\n templateKey: string,\n opts: Record<string, string | boolean | undefined>,\n vault: Address,\n resolved?: ResolvedChainInputs,\n): Promise<{ initData: Hex; asset: Address; assetAmount: bigint; extraApprovals?: { token: Address; amount: bigint }[] }> {\n if (templateKey === \"moonwell-supply\") {\n if (!opts.amount) {\n console.error(chalk.red(\"--amount is required for moonwell-supply template\"));\n process.exit(1);\n }\n const token = (opts.token as string) || \"USDC\";\n const underlying = resolveToken(token);\n const mToken = resolveMToken(token);\n const decimals = assetDecimalsForSymbol(token);\n const supplyAmount = parseUnits(opts.amount as string, decimals);\n const minRedeem = parseUnits((opts.minRedeem as string) || opts.amount as string, decimals);\n // V2: Moonwell's native-ETH (mWETH) market redeems raw ETH the strategy\n // wraps back to WETH — every non-USDC token here is the WETH market.\n const isNativeEthMarket = token.toUpperCase() !== \"USDC\";\n\n return {\n initData: moonwellBuilder.buildInitData(underlying, mToken, supplyAmount, minRedeem, isNativeEthMarket),\n asset: underlying,\n assetAmount: supplyAmount,\n };\n }\n\n if (templateKey === \"venice-inference\") {\n if (!opts.amount) {\n console.error(chalk.red(\"--amount is required for venice-inference template\"));\n process.exit(1);\n }\n const assetSymbol = (opts.asset as string) || \"USDC\";\n const asset = resolveToken(assetSymbol);\n const vvv = VENICE().VVV;\n const isDirect = asset.toLowerCase() === vvv.toLowerCase();\n const decimals = assetDecimalsForSymbol(assetSymbol);\n const assetAmount = parseUnits(opts.amount as string, decimals);\n // The signer-default agent and the Aerodrome getAmountsOut auto-quote are\n // chain/signer concerns — the command layer resolves both (see\n // resolveChainInputsForTemplate) and passes them in.\n const agent = (opts.agent as Address) || resolved?.veniceAgent;\n if (!agent) {\n throw new Error(\n \"venice-inference: missing agent — pass --agent or resolve chain inputs (signer default) before encoding\",\n );\n }\n const isSingleHop = !!opts.singleHop;\n\n // minVVV: explicit flag wins; non-direct paths without it need the\n // caller-resolved auto-quote (5% slippage applied at quote time).\n let minVVV = 0n;\n if (!isDirect) {\n if (opts.minVvv) {\n minVVV = parseUnits(opts.minVvv as string, 18);\n } else if (resolved?.veniceMinVVV !== undefined) {\n minVVV = resolved.veniceMinVVV;\n } else {\n throw new Error(\n \"venice-inference: missing resolved minVVV quote — pass --min-vvv or resolve chain inputs before encoding\",\n );\n }\n }\n\n const params: veniceBuilder.VeniceInferenceInitParams = {\n asset,\n weth: isDirect ? ZERO : TOKENS().WETH,\n vvv,\n sVVV: VENICE().STAKING,\n aeroRouter: isDirect ? ZERO : AERODROME().ROUTER,\n aeroFactory: isDirect ? ZERO : AERODROME().FACTORY,\n agent,\n assetAmount,\n minVVV,\n deadlineOffset: 300n,\n singleHop: isSingleHop,\n };\n\n return {\n initData: veniceBuilder.buildInitData(params),\n asset,\n assetAmount,\n };\n }\n\n if (templateKey === \"aerodrome-lp\") {\n for (const flag of [\"tokenA\", \"tokenB\", \"amountA\", \"amountB\", \"lpToken\"]) {\n if (!opts[flag]) {\n console.error(chalk.red(`--${flag.replace(/([A-Z])/g, \"-$1\").toLowerCase()} is required for aerodrome-lp template`));\n process.exit(1);\n }\n }\n const tokenA = opts.tokenA as Address;\n const tokenB = opts.tokenB as Address;\n // decimals() is a chain read — the command layer resolves it (see\n // resolveChainInputsForTemplate) and passes it in.\n if (!resolved?.aerodromeDecimals) {\n throw new Error(\n \"aerodrome-lp: missing resolved tokenA/tokenB decimals — resolve chain inputs before encoding\",\n );\n }\n const { decimalsA, decimalsB } = resolved.aerodromeDecimals;\n const amountA = parseUnits(opts.amountA as string, decimalsA);\n const amountB = parseUnits(opts.amountB as string, decimalsB);\n const minAOut = parseUnits((opts.minAOut as string) || \"0\", decimalsA);\n const minBOut = parseUnits((opts.minBOut as string) || \"0\", decimalsB);\n\n const params: aerodromeBuilder.AerodromeLPInitParams = {\n tokenA,\n tokenB,\n stable: !!opts.stable,\n factory: AERODROME().FACTORY,\n router: AERODROME().ROUTER,\n gauge: (opts.gauge as Address) || ZERO,\n lpToken: opts.lpToken as Address,\n amountADesired: amountA,\n amountBDesired: amountB,\n amountAMin: amountA, // use desired as min for now\n amountBMin: amountB,\n minAmountAOut: minAOut,\n minAmountBOut: minBOut,\n };\n\n return {\n initData: aerodromeBuilder.buildInitData(params),\n asset: tokenA,\n assetAmount: amountA,\n extraApprovals: [{ token: tokenB, amount: amountB }],\n };\n }\n\n if (templateKey === \"wsteth-moonwell\") {\n const supplyAmount = opts.amount ? parseUnits(opts.amount as string, 18) : 0n; // WETH = 18 decimals; 0 => use full vault balance at execute time\n const slippageBps = BigInt((opts.slippage as string) || \"500\"); // default 5% slippage\n // Per-unit rates (1e18-scaled) — Aerodrome wstETH/WETH stable pool trades\n // near 1:1, so default the expected rate to 1e18. Slippage cuts from that.\n // Rates scale with amountIn at execute time → dynamic-all mode is safe.\n const ONE = 10n ** 18n;\n const minWstethOutPerWeth = (ONE * (10000n - slippageBps)) / 10000n;\n const minWethOutPerWsteth = (ONE * (10000n - slippageBps)) / 10000n;\n\n const params: wstethBuilder.WstETHMoonwellInitParams = {\n weth: TOKENS().WETH,\n wsteth: TOKENS().wstETH,\n mwsteth: MOONWELL().mWstETH,\n aeroRouter: AERODROME().ROUTER,\n aeroFactory: AERODROME().FACTORY,\n chainlinkWstethEthFeed: CHAINLINK().WSTETH_ETH_FEED,\n supplyAmount,\n minWstethOutPerWeth,\n minWethOutPerWsteth,\n deadlineOffset: 300n,\n };\n\n return {\n initData: wstethBuilder.buildInitData(params),\n asset: TOKENS().WETH,\n assetAmount: supplyAmount,\n };\n }\n\n if (templateKey === \"mamo-yield\") {\n if (!opts.amount) {\n console.error(chalk.red(\"--amount is required for mamo-yield template\"));\n process.exit(1);\n }\n if (!opts.mamoFactory) {\n console.error(chalk.red(\"--mamo-factory is required for mamo-yield template\"));\n process.exit(1);\n }\n const token = (opts.token as string) || \"USDC\";\n const underlying = resolveToken(token);\n const decimals = assetDecimalsForSymbol(token);\n const amount = parseUnits(opts.amount as string, decimals);\n const minRedeemAmount = parseUnits((opts.minRedeem as string) || opts.amount as string, decimals);\n\n return {\n initData: mamoBuilder.buildInitData(underlying, opts.mamoFactory as Address, minRedeemAmount),\n asset: underlying,\n assetAmount: amount,\n };\n }\n\n if (templateKey === \"portfolio\") {\n if (!opts.amount) { console.error(chalk.red(\"--amount is required for portfolio template\")); process.exit(1); }\n if (!opts.tokens || !opts.weights) {\n console.error(chalk.red(\"--tokens and --weights are required for portfolio template\"));\n console.error(chalk.dim(\" --tokens: comma-separated token addresses or symbols\"));\n console.error(chalk.dim(\" --weights: comma-separated bps (must sum to 10000)\"));\n process.exit(1);\n }\n const network = getNetwork();\n const tokens = TOKENS();\n const assetSymbol = (opts.asset as string) || defaultPortfolioAsset();\n const asset = resolveToken(assetSymbol);\n const decimals = assetDecimalsForSymbol(assetSymbol);\n const totalAmount = parseUnits(opts.amount as string, decimals);\n const maxSlippageBps = Number((opts.maxSlippage as string) || \"500\");\n const feeTier = (opts.feeTier as string) || \"3000\";\n\n // Parse token specs, keeping the original symbol/spec so we can resolve a\n // Chainlink push feed on chains that use AggregatorV3 push feeds.\n const tokenSpecs = (opts.tokens as string).split(\",\").map((t) => t.trim());\n const tokenAddrs = tokenSpecs.map((trimmed) => {\n if (isAddress(trimmed)) return trimmed as Address;\n const allTokens = tokens as Record<string, Address>;\n const resolvedAddr = allTokens[trimmed.toUpperCase()];\n if (resolvedAddr && resolvedAddr !== ZERO) return resolvedAddr;\n console.error(chalk.red(`Unknown token: ${trimmed}`)); process.exit(1);\n });\n const weightsBps = (opts.weights as string).split(\",\").map((w) => Number(w.trim()));\n if (tokenAddrs.length !== weightsBps.length) { console.error(chalk.red(\"--tokens and --weights must have same length\")); process.exit(1); }\n if (weightsBps.reduce((a, b) => a + b, 0) !== 10000) { console.error(chalk.red(`Weights must sum to 10000`)); process.exit(1); }\n\n const swapAdapter = (opts.swapAdapter as Address) || resolveSwapAdapter();\n const chainlinkVerifier = CHAINLINK().VERIFIER_PROXY;\n // Push-feed mode (chainlinkVerifier == 0, e.g. Robinhood mainnet): each\n // allocation's feedId is an AggregatorV3 proxy left-padded to bytes32, and\n // priceDecimals must equal that feed's decimals() (8 on Robinhood mainnet).\n const pushMode = chainlinkVerifier === ZERO;\n const chainlink = CHAINLINK() as Record<string, Address>;\n\n // Optional explicit per-allocation overrides (comma-separated, aligned to\n // --tokens). All four flags parse identically via parseAlignedOverrides:\n // empty entries are preserved so a partial override (e.g. \"8,,8\") falls\n // through to that slot's auto-resolve default; a PRESENT flag must align\n // 1:1 with --tokens (an unset flag → [] and skips the check).\n // --feed-ids: bytes32 feed ids (Data Streams) or feed addresses (push\n // mode). Empty slot → auto-resolve SYMBOL_USD_FEED below.\n // --price-decimals: raw feed scale per allocation. Empty slot → pushMode 8\n // / else 18 default below.\n const feedIds = parseAlignedOverrides(opts.feedIds as string | undefined, tokenAddrs.length);\n const feedIdOverrides = feedIds.values;\n if (feedIds.mismatch) { console.error(chalk.red(\"--feed-ids must have the same length as --tokens\")); process.exit(1); }\n const priceDecimals = parseAlignedOverrides(opts.priceDecimals as string | undefined, tokenAddrs.length);\n const priceDecimalOverrides = priceDecimals.values;\n if (priceDecimals.mismatch) { console.error(chalk.red(\"--price-decimals must have the same length as --tokens\")); process.exit(1); }\n\n // Explicit per-token swap-route overrides (aligned to --tokens). An empty\n // entry falls through to the robinhood default / auto-detect below.\n const swapRoutes = parseAlignedOverrides(opts.swapRoutes as string | undefined, tokenAddrs.length);\n const swapRouteOverrides = swapRoutes.values;\n if (swapRoutes.mismatch) { console.error(chalk.red(\"--swap-routes must have the same length as --tokens\")); process.exit(1); }\n\n // Optional per-token max-price-age override (seconds), comma-aligned to\n // --tokens. Packs into the push-mode feedId's upper bits. Empty entry → the\n // registry-driven default (96h for equity feeds, 0/contract-default otherwise).\n const maxPriceAges = parseAlignedOverrides(opts.maxPriceAges as string | undefined, tokenAddrs.length);\n const maxPriceAgeOverrides = maxPriceAges.values;\n if (maxPriceAges.mismatch) { console.error(chalk.red(\"--max-price-ages must have the same length as --tokens\")); process.exit(1); }\n\n // Robinhood mainnet default swap routes come from the data-driven\n // ROBINHOOD_STOCK_ROUTES registry (verified on-chain liquidity) plus a WETH\n // v3 fee-500 leg. A robinhood basket token with a feed but NO verified route\n // and NO --swap-routes override fails fast (see below) rather than falling\n // through to a v3 auto-detect that is guaranteed dead on 4663.\n const wethAddr = TOKENS().WETH;\n function robinhoodDefaultRoute(token: Address, symbol: string): { extraData: Hex; routeDesc: string } | null {\n // Robinhood-mainnet-only default route (verified ROBINHOOD_STOCK_ROUTES).\n // Mainnet is not in the current deployment target, so this is inert today;\n // string-compare keeps it forward-compatible for when 4663 is added back.\n if ((network as string) !== \"robinhood\") return null;\n if (wethAddr !== ZERO && token.toLowerCase() === wethAddr.toLowerCase()) {\n return { extraData: portfolioBuilder.v3SingleHopExtraData(500), routeDesc: \"v3 direct (fee 500)\" };\n }\n const r = ROBINHOOD_STOCK_ROUTES[symbol.toUpperCase()];\n if (r) {\n return {\n extraData: portfolioBuilder.v4PathExtraData([\n { currency: ZERO, fee: r.nativeFee, tickSpacing: r.nativeTickSpacing },\n { currency: token, fee: r.stockFee, tickSpacing: r.stockTickSpacing },\n ]),\n routeDesc: `v4 multi-hop (USDG→ETH fee ${r.nativeFee} / ts ${r.nativeTickSpacing} → ${symbol.toUpperCase()} fee ${r.stockFee} / ts ${r.stockTickSpacing})`,\n };\n }\n return null;\n }\n\n // Auto-detect swap routes for each token\n console.log(chalk.dim(\" Detecting swap routes...\"));\n const allocations: portfolioBuilder.BasketAllocation[] = [];\n for (let i = 0; i < tokenAddrs.length; i++) {\n const token = tokenAddrs[i];\n let route: { extraData: Hex; routeDesc: string } | null = null;\n const override = swapRouteOverrides[i];\n if (override) {\n try {\n route = { extraData: parseSwapRouteSpec(override, token), routeDesc: `explicit '${override}'` };\n } catch (e) {\n console.error(chalk.red(`Bad --swap-routes entry for ${tokenSpecs[i]}: ${(e as Error).message}`));\n process.exit(1);\n }\n }\n if (!route) route = robinhoodDefaultRoute(token, tokenSpecs[i]);\n if (!route && (network as string) === \"robinhood\") {\n // No verified default route and no override. v3 auto-detect is dead on\n // 4663 (no v3 stock pools) — fail fast with an actionable message rather\n // than emitting a doomed proposal.\n console.error(\n chalk.red(\n `No verified default swap route for ${tokenSpecs[i]} on robinhood mainnet.`,\n ),\n );\n console.error(\n chalk.yellow(\n ` Pass --swap-routes to set it explicitly for this token, e.g.\\n` +\n ` --swap-routes 'v4path:eth@500:10+self@50000:1000' (USDG→ETH→${tokenSpecs[i].toUpperCase()})`,\n ),\n );\n process.exit(1);\n }\n if (!route) route = await detectSwapRoute(asset, token, Number(feeTier));\n if (!route) {\n console.error(chalk.red(`No swap route found for ${token}. No Uniswap V3 pool (direct or via WETH). Pass --swap-routes to set it explicitly.`));\n process.exit(1);\n }\n console.log(chalk.dim(` ${token.slice(0, 10)}... → ${route.routeDesc}`));\n\n // Resolve the per-allocation Chainlink feed id + priceDecimals.\n let feedId = feedIdOverrides[i] as portfolioBuilder.BasketAllocation[\"feedId\"] | undefined;\n // Default priceDecimals: 8 in push mode (Robinhood mainnet feeds),\n // 18 otherwise (crypto Data Streams pairs); override wins.\n let priceDecimals = priceDecimalOverrides[i]\n ? Number(priceDecimalOverrides[i])\n : pushMode ? 8 : 18;\n\n // Per-slot max price age (seconds), packed into the push-mode feedId.\n // Precedence: explicit --max-price-ages > registry default (96h for\n // Robinhood equity feeds; 0 = contract default for crypto/stable feeds).\n const sym = tokenSpecs[i].toUpperCase();\n let maxPriceAge = 0;\n if (maxPriceAgeOverrides[i]) {\n // Explicit --max-price-ages overrides everything (unchanged precedence).\n maxPriceAge = Number(maxPriceAgeOverrides[i]);\n if (!Number.isInteger(maxPriceAge) || maxPriceAge < 0) {\n console.error(chalk.red(`Bad --max-price-ages entry for ${tokenSpecs[i]}: '${maxPriceAgeOverrides[i]}' (expected a non-negative integer count of seconds)`));\n process.exit(1);\n }\n } else if (pushMode && (network as string) === \"robinhood\") {\n // Registry-driven default: classify the token as equity vs crypto to\n // pack the 96h max-age into the push feedId. Works for tokens given by\n // SYMBOL and (via reverse-lookup) by raw 0x address — otherwise a stock\n // token passed by address silently falls back to the contract's 26h\n // default and trips StalePrice over long weekends.\n const { maxPriceAge: age, unknownAddress } = robinhoodEquityMaxAge(\n tokenSpecs[i],\n tokens as Record<string, Address>,\n portfolioBuilder.EQUITY_MAX_PRICE_AGE_SECONDS,\n );\n maxPriceAge = age;\n if (unknownAddress && feedIdOverrides[i]) {\n // Raw address unknown to the registry + an explicit feed id: we can't\n // classify it, so the slot will use the contract's 26h default. Warn\n // rather than guess — equity feeds need an explicit --max-price-ages.\n console.warn(\n chalk.yellow(\n ` Warning: token ${tokenSpecs[i]} is not in the ${network} registry, so its ` +\n `push feed uses the contract's 26h default max-price-age.\\n` +\n ` If this is a tokenized-equity feed, pass --max-price-ages (e.g. ${portfolioBuilder.EQUITY_MAX_PRICE_AGE_SECONDS}) ` +\n `for this slot or it will trip StalePrice over long weekends.`,\n ),\n );\n }\n }\n\n if (pushMode && !feedId) {\n // Auto-resolve SYMBOL_USD_FEED from the CHAINLINK() registry by symbol.\n // WETH/ETH share the ETH_USD_FEED key (there is no WETH_USD_FEED).\n const feedKey = sym === \"WETH\" || sym === \"ETH\" ? \"ETH_USD_FEED\" : `${sym}_USD_FEED`;\n const feed = isAddress(tokenSpecs[i]) ? undefined : chainlink[feedKey];\n if (!feed || feed === ZERO) {\n console.error(chalk.red(`No Chainlink push feed for ${tokenSpecs[i]} on ${network}. Pass --feed-ids <feedAddr,...> to supply AggregatorV3 addresses.`));\n process.exit(1);\n }\n feedId = portfolioBuilder.pushFeedId(feed, maxPriceAge);\n } else if (pushMode && feedId && isAddress(feedId)) {\n // Push-mode override given as a bare address — pad to bytes32 (+ age).\n feedId = portfolioBuilder.pushFeedId(feedId as Address, maxPriceAge);\n }\n\n if (!feedId || feedId === ZERO_BYTES32) {\n console.error(chalk.red(`Missing Chainlink feedId for allocation ${i} (${tokenSpecs[i]}). The strategy requires a non-zero feedId per token — pass --feed-ids as a comma-separated list.`));\n process.exit(1);\n }\n\n allocations.push({\n token, weightBps: weightsBps[i],\n swapExtraData: route.extraData,\n priceDecimals,\n feedId,\n });\n }\n return {\n initData: portfolioBuilder.buildInitData(asset, swapAdapter, chainlinkVerifier, allocations, totalAmount, maxSlippageBps),\n asset, assetAmount: totalAmount,\n };\n }\n\n if (templateKey === \"hyperliquid-perp\") {\n const token = (opts.token as string) || \"USDC\";\n const asset = resolveToken(token);\n const decimals = assetDecimalsForSymbol(token);\n // Omit --amount to use the vault's full asset balance at execute time (dynamic-all mode).\n const depositAmount = opts.amount ? parseUnits(opts.amount as string, decimals) : 0n;\n const leverage = Number((opts.leverage as string) || \"10\");\n const assetIndex = Number((opts.assetIndex as string) || \"0\");\n const maxPosition = parseUnits((opts.maxPosition as string) || \"100000\", decimals);\n const maxTradesDay = Number((opts.maxTradesPerDay as string) || \"50\");\n return {\n initData: hyperliquidPerpBuilder.buildInitData(asset, depositAmount, assetIndex, leverage, maxPosition, maxTradesDay),\n asset, assetAmount: depositAmount,\n };\n }\n\n if (templateKey === \"hyperliquid-grid\") {\n const token = (opts.token as string) || \"USDC\";\n const asset = resolveToken(token);\n const decimals = assetDecimalsForSymbol(token);\n const depositAmount = opts.amount ? parseUnits(opts.amount as string, decimals) : 0n;\n const leverage = Number((opts.leverage as string) || \"5\");\n const maxOrderSize = parseUnits((opts.maxOrderSize as string) || \"10000\", decimals);\n const maxOrdersPerTick = Number((opts.maxOrdersPerTick as string) || \"20\");\n const assetIndices = ((opts.assetIndices as string) || \"0\")\n .split(\",\")\n .map((s) => Number(s.trim()))\n .filter((n) => !Number.isNaN(n));\n return {\n initData: hyperliquidGridBuilder.buildInitData(asset, depositAmount, leverage, maxOrderSize, maxOrdersPerTick, assetIndices),\n asset, assetAmount: depositAmount,\n };\n }\n\n throw new Error(`No init builder for template: ${templateKey}`);\n}\n\nexport function buildCallsForTemplate(\n templateKey: string,\n clone: Address,\n asset: Address,\n assetAmount: bigint,\n extraApprovals?: { token: Address; amount: bigint }[],\n): { executeCalls: BatchCall[]; settleCalls: BatchCall[] } {\n if (templateKey === \"moonwell-supply\") {\n return {\n executeCalls: moonwellBuilder.buildExecuteCalls(clone, asset, assetAmount),\n settleCalls: moonwellBuilder.buildSettleCalls(clone),\n };\n }\n\n if (templateKey === \"venice-inference\") {\n return {\n executeCalls: veniceBuilder.buildExecuteCalls(clone, asset, assetAmount),\n settleCalls: veniceBuilder.buildSettleCalls(clone),\n };\n }\n\n if (templateKey === \"aerodrome-lp\") {\n const tokenB = extraApprovals?.[0]?.token ?? ZERO;\n const amountB = extraApprovals?.[0]?.amount ?? 0n;\n return {\n executeCalls: aerodromeBuilder.buildExecuteCalls(clone, asset, assetAmount, tokenB, amountB),\n settleCalls: aerodromeBuilder.buildSettleCalls(clone),\n };\n }\n\n if (templateKey === \"wsteth-moonwell\") {\n return {\n executeCalls: wstethBuilder.buildExecuteCalls(clone, asset, assetAmount),\n settleCalls: wstethBuilder.buildSettleCalls(clone),\n };\n }\n\n if (templateKey === \"mamo-yield\") {\n return {\n executeCalls: mamoBuilder.buildExecuteCalls(clone, asset, assetAmount),\n settleCalls: mamoBuilder.buildSettleCalls(clone),\n };\n }\n\n if (templateKey === \"portfolio\") {\n return {\n executeCalls: portfolioBuilder.buildExecuteCalls(clone, asset, assetAmount),\n settleCalls: portfolioBuilder.buildSettleCalls(clone),\n };\n }\n\n if (templateKey === \"hyperliquid-perp\") {\n return {\n executeCalls: hyperliquidPerpBuilder.buildExecuteCalls(clone, asset, assetAmount),\n settleCalls: hyperliquidPerpBuilder.buildSettleCalls(clone),\n };\n }\n\n if (templateKey === \"hyperliquid-grid\") {\n return {\n executeCalls: hyperliquidGridBuilder.buildExecuteCalls(clone, asset, assetAmount),\n settleCalls: hyperliquidGridBuilder.buildSettleCalls(clone),\n };\n }\n\n throw new Error(`No call builder for template: ${templateKey}`);\n}\n\n// ── Token resolution (registry lookups — config reads, not RPC) ──\n\nexport function resolveSwapAdapter(): Address {\n const network = getNetwork();\n if (network === \"robinhood-testnet\" && SYNTHRA().ROUTER === ZERO) {\n console.error(chalk.red(\"Synthra DEX not available\"));\n process.exit(1);\n }\n // The deployed adapter on robinhood-testnet is the registry's UniswapSwapAdapter\n // (UNISWAP_SWAP_ADAPTER), backed by Synthra's router + a QuoterV2 shim\n // (SYNTHRA_QUOTER_V2_SHIM). It consumes MODE-PREFIXED extraData (0x00 single-hop\n // / 0x01 multi-hop — see buildSwapExtraData). An earlier build hardcoded a bare\n // SynthraDirectAdapter address here paired with un-prefixed extraData; that\n // adapter's on-chain `quote()` returns 0 (bricking PortfolioStrategy execute\n // with QuoteUnavailable), so always resolve the registry adapter instead.\n const adapterAddr = UNISWAP().SWAP_ADAPTER;\n if (adapterAddr !== ZERO) return adapterAddr;\n console.error(chalk.red(\"UniswapSwapAdapter not deployed yet. Use --swap-adapter to specify manually.\"));\n process.exit(1);\n}\n\nexport function resolveToken(symbolOrAddress: string): Address {\n if (isAddress(symbolOrAddress)) return symbolOrAddress as Address;\n const upper = symbolOrAddress.toUpperCase();\n // Spread the per-network TOKENS() registry (so USDG / stock tokens on robinhood\n // resolve without a second hand-rolled map — mirrors the basket-token path),\n // then overlay VVV which lives in the Venice registry rather than TOKENS().\n const tokenMap: Record<string, Address> = {\n ...(TOKENS() as Record<string, Address>),\n VVV: VENICE().VVV,\n };\n const addr = tokenMap[upper];\n if (!addr || addr === ZERO) {\n console.error(chalk.red(`Unknown token: ${symbolOrAddress}`));\n process.exit(1);\n }\n return addr;\n}\n\n/**\n * Default vault asset for the portfolio template on the current network:\n * WETH on Robinhood testnet (ETH-only chain, the current deployment target),\n * USDC as the forward-compatible default for any other chain added back. Single\n * source of truth shared by buildInitDataForTemplate + computeProposalAssetChecks.\n */\nexport function defaultPortfolioAsset(): string {\n const network = getNetwork();\n if (network === \"robinhood-testnet\") return \"WETH\";\n return \"USDC\";\n}\n\n/**\n * Decimals for a vault-asset symbol. USDC and USDG are 6-decimal stables; every\n * other supported vault asset (WETH, stock tokens, …) is 18-decimal. Kept as one\n * helper so the funding math can't drift between the preflight check and the\n * on-chain init data.\n */\nexport function assetDecimalsForSymbol(symbol: string): number {\n const upper = symbol.toUpperCase();\n return upper === \"USDC\" || upper === \"USDG\" ? 6 : 18;\n}\n\nexport function resolveMToken(tokenSymbol: string): Address {\n const upper = tokenSymbol.toUpperCase();\n const moonwell = MOONWELL();\n const mTokenMap: Record<string, Address> = {\n USDC: moonwell.mUSDC,\n WETH: moonwell.mWETH,\n };\n const addr = mTokenMap[upper];\n if (!addr || addr === ZERO) {\n console.error(chalk.red(`No Moonwell market for: ${tokenSymbol}`));\n process.exit(1);\n }\n return addr;\n}\n","/**\n * MoonwellSupplyStrategy call builder.\n *\n * InitParams (Solidity, V2): (address underlying, address mToken, uint256 supplyAmount,\n * uint256 minRedeemAmount, bool isNativeEthMarket)\n *\n * `isNativeEthMarket` — true when the mToken is Moonwell's native-ETH (mWETH)\n * market, whose redeem returns raw ETH the strategy must wrap back to WETH.\n * false for ERC-20 markets (USDC). V2 beta added this field; encoding the old\n * 4-field payload makes the clone's `initialize` abi.decode revert with empty\n * data (vnet e2e finding, issues #411-#414).\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeAbiParameters, encodeFunctionData } from \"viem\";\nimport { ERC20_ABI, BASE_STRATEGY_ABI } from \"../lib/abis.js\";\nimport type { BatchCall } from \"../lib/batch.js\";\n\nexport function buildInitData(\n underlying: Address,\n mToken: Address,\n supplyAmount: bigint,\n minRedeemAmount: bigint,\n isNativeEthMarket: boolean,\n): Hex {\n return encodeAbiParameters(\n [\n { type: \"address\" },\n { type: \"address\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"bool\" },\n ],\n [underlying, mToken, supplyAmount, minRedeemAmount, isNativeEthMarket],\n );\n}\n\nexport function buildExecuteCalls(\n clone: Address,\n underlying: Address,\n supplyAmount: bigint,\n): BatchCall[] {\n return [\n {\n target: underlying,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, supplyAmount],\n }),\n value: 0n,\n },\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"execute\",\n }),\n value: 0n,\n },\n ];\n}\n\nexport function buildSettleCalls(clone: Address): BatchCall[] {\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"settle\",\n }),\n value: 0n,\n },\n ];\n}\n","/**\n * VeniceInferenceStrategy call builder.\n *\n * InitParams (Solidity struct):\n * address asset, address weth, address vvv, address sVVV,\n * address aeroRouter, address aeroFactory, address agent,\n * uint256 assetAmount, uint256 minVVV, uint256 deadlineOffset, bool singleHop\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeAbiParameters, encodeFunctionData } from \"viem\";\nimport { ERC20_ABI, BASE_STRATEGY_ABI } from \"../lib/abis.js\";\nimport type { BatchCall } from \"../lib/batch.js\";\n\nexport interface VeniceInferenceInitParams {\n asset: Address;\n weth: Address;\n vvv: Address;\n sVVV: Address;\n aeroRouter: Address;\n aeroFactory: Address;\n agent: Address;\n assetAmount: bigint;\n minVVV: bigint;\n deadlineOffset: bigint;\n singleHop: boolean;\n}\n\nconst INIT_PARAMS_TYPES = [\n {\n type: \"tuple\" as const,\n components: [\n { name: \"asset\", type: \"address\" as const },\n { name: \"weth\", type: \"address\" as const },\n { name: \"vvv\", type: \"address\" as const },\n { name: \"sVVV\", type: \"address\" as const },\n { name: \"aeroRouter\", type: \"address\" as const },\n { name: \"aeroFactory\", type: \"address\" as const },\n { name: \"agent\", type: \"address\" as const },\n { name: \"assetAmount\", type: \"uint256\" as const },\n { name: \"minVVV\", type: \"uint256\" as const },\n { name: \"deadlineOffset\", type: \"uint256\" as const },\n { name: \"singleHop\", type: \"bool\" as const },\n ],\n },\n] as const;\n\nexport function buildInitData(params: VeniceInferenceInitParams): Hex {\n return encodeAbiParameters(INIT_PARAMS_TYPES, [params]);\n}\n\nexport function buildExecuteCalls(\n clone: Address,\n asset: Address,\n assetAmount: bigint,\n): BatchCall[] {\n return [\n {\n target: asset,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, assetAmount],\n }),\n value: 0n,\n },\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"execute\",\n }),\n value: 0n,\n },\n ];\n}\n\nexport function buildSettleCalls(clone: Address): BatchCall[] {\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"settle\",\n }),\n value: 0n,\n },\n ];\n}\n","/**\n * AerodromeLPStrategy call builder.\n *\n * InitParams (Solidity struct):\n * address tokenA, address tokenB, bool stable,\n * address factory, address router, address gauge, address lpToken,\n * uint256 amountADesired, uint256 amountBDesired,\n * uint256 amountAMin, uint256 amountBMin,\n * uint256 minAmountAOut, uint256 minAmountBOut\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeAbiParameters, encodeFunctionData } from \"viem\";\nimport { ERC20_ABI, BASE_STRATEGY_ABI } from \"../lib/abis.js\";\nimport type { BatchCall } from \"../lib/batch.js\";\n\nexport interface AerodromeLPInitParams {\n tokenA: Address;\n tokenB: Address;\n stable: boolean;\n factory: Address;\n router: Address;\n gauge: Address;\n lpToken: Address;\n amountADesired: bigint;\n amountBDesired: bigint;\n amountAMin: bigint;\n amountBMin: bigint;\n minAmountAOut: bigint;\n minAmountBOut: bigint;\n}\n\nconst INIT_PARAMS_TYPES = [\n {\n type: \"tuple\" as const,\n components: [\n { name: \"tokenA\", type: \"address\" as const },\n { name: \"tokenB\", type: \"address\" as const },\n { name: \"stable\", type: \"bool\" as const },\n { name: \"factory\", type: \"address\" as const },\n { name: \"router\", type: \"address\" as const },\n { name: \"gauge\", type: \"address\" as const },\n { name: \"lpToken\", type: \"address\" as const },\n { name: \"amountADesired\", type: \"uint256\" as const },\n { name: \"amountBDesired\", type: \"uint256\" as const },\n { name: \"amountAMin\", type: \"uint256\" as const },\n { name: \"amountBMin\", type: \"uint256\" as const },\n { name: \"minAmountAOut\", type: \"uint256\" as const },\n { name: \"minAmountBOut\", type: \"uint256\" as const },\n ],\n },\n] as const;\n\nexport function buildInitData(params: AerodromeLPInitParams): Hex {\n return encodeAbiParameters(INIT_PARAMS_TYPES, [params]);\n}\n\nexport function buildExecuteCalls(\n clone: Address,\n tokenA: Address,\n amountA: bigint,\n tokenB: Address,\n amountB: bigint,\n): BatchCall[] {\n return [\n {\n target: tokenA,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, amountA],\n }),\n value: 0n,\n },\n {\n target: tokenB,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, amountB],\n }),\n value: 0n,\n },\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"execute\",\n }),\n value: 0n,\n },\n ];\n}\n\nexport function buildSettleCalls(clone: Address): BatchCall[] {\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"settle\",\n }),\n value: 0n,\n },\n ];\n}\n","/**\n * WstETHMoonwellStrategy call builder.\n *\n * InitParams (Solidity struct):\n * address weth, address wsteth, address mwsteth,\n * address aeroRouter, address aeroFactory, address chainlinkWstethEthFeed,\n * uint256 supplyAmount, uint256 minWstethOutPerWeth, uint256 minWethOutPerWsteth, uint256 deadlineOffset\n * supplyAmount = 0 means use the vault's full WETH balance at execute time\n * min*PerX are 1e18-scaled per-unit rates so slippage protection scales with amountIn.\n * chainlinkWstethEthFeed is the Chainlink WSTETH/ETH price feed used by the\n * strategy's `_positionValue` for live NAV during an active proposal. Base\n * mainnet: 0x43a5C292A453A3bF3606fa856197f09D7B74251a (heartbeat 24h, 18 decimals).\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeAbiParameters, encodeFunctionData, maxUint256 } from \"viem\";\nimport { ERC20_ABI, BASE_STRATEGY_ABI } from \"../lib/abis.js\";\nimport type { BatchCall } from \"../lib/batch.js\";\n\nexport interface WstETHMoonwellInitParams {\n weth: Address;\n wsteth: Address;\n mwsteth: Address;\n aeroRouter: Address;\n aeroFactory: Address;\n chainlinkWstethEthFeed: Address;\n supplyAmount: bigint;\n minWstethOutPerWeth: bigint;\n minWethOutPerWsteth: bigint;\n deadlineOffset: bigint;\n}\n\nconst INIT_PARAMS_TYPES = [\n {\n type: \"tuple\" as const,\n components: [\n { name: \"weth\", type: \"address\" as const },\n { name: \"wsteth\", type: \"address\" as const },\n { name: \"mwsteth\", type: \"address\" as const },\n { name: \"aeroRouter\", type: \"address\" as const },\n { name: \"aeroFactory\", type: \"address\" as const },\n { name: \"chainlinkWstethEthFeed\", type: \"address\" as const },\n { name: \"supplyAmount\", type: \"uint256\" as const },\n { name: \"minWstethOutPerWeth\", type: \"uint256\" as const },\n { name: \"minWethOutPerWsteth\", type: \"uint256\" as const },\n { name: \"deadlineOffset\", type: \"uint256\" as const },\n ],\n },\n] as const;\n\nexport function buildInitData(params: WstETHMoonwellInitParams): Hex {\n return encodeAbiParameters(INIT_PARAMS_TYPES, [params]);\n}\n\nexport function buildExecuteCalls(\n clone: Address,\n weth: Address,\n supplyAmount: bigint,\n): BatchCall[] {\n // In dynamic-all mode (supplyAmount == 0) we can't know the exact amount\n // at proposal-build time, so approve maxUint256 then revoke to 0 after\n // execute() in the same batch. This bounds the residual allowance to a\n // single atomic tx — any leftover approval is cleared before control\n // returns to the governor.\n const approveAmount = supplyAmount === 0n ? maxUint256 : supplyAmount;\n\n return [\n {\n target: weth,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, approveAmount],\n }),\n value: 0n,\n },\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"execute\",\n }),\n value: 0n,\n },\n {\n target: weth,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, 0n],\n }),\n value: 0n,\n },\n ];\n}\n\nexport function buildSettleCalls(clone: Address): BatchCall[] {\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"settle\",\n }),\n value: 0n,\n },\n ];\n}\n","/**\n * MamoYieldStrategy call builder.\n *\n * InitParams (Solidity): (address underlying, address mamoFactory, uint256 minRedeemAmount)\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeAbiParameters, encodeFunctionData } from \"viem\";\nimport { ERC20_ABI, BASE_STRATEGY_ABI } from \"../lib/abis.js\";\nimport type { BatchCall } from \"../lib/batch.js\";\n\nexport function buildInitData(\n underlying: Address,\n mamoFactory: Address,\n minRedeemAmount: bigint,\n): Hex {\n return encodeAbiParameters(\n [\n { type: \"address\" },\n { type: \"address\" },\n { type: \"uint256\" },\n ],\n [underlying, mamoFactory, minRedeemAmount],\n );\n}\n\nexport function buildExecuteCalls(\n clone: Address,\n underlying: Address,\n amount: bigint,\n): BatchCall[] {\n return [\n {\n target: underlying,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, amount],\n }),\n value: 0n,\n },\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"execute\",\n }),\n value: 0n,\n },\n ];\n}\n\nexport function buildSettleCalls(clone: Address): BatchCall[] {\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"settle\",\n }),\n value: 0n,\n },\n ];\n}","/**\n * PortfolioStrategy call builder.\n *\n * InitParams (Solidity): (address asset, address swapAdapter, address chainlinkVerifier,\n * address[] tokens, uint256[] weightsBps, uint256 totalAmount, uint256 maxSlippageBps,\n * bytes[] swapExtraData, uint8[] priceDecimals, bytes32[] feedIds)\n *\n * `priceDecimals[i]` declares the raw Chainlink feed scale for allocation `i`\n * (typically 8 for tokenized stocks, 18 for crypto pairs). It normalizes the\n * position value into the vault asset's decimals.\n *\n * `feedIds[i]` binds each allocation to its expected Chainlink feed (Sherlock\n * #56). Two modes, selected by `chainlinkVerifier`:\n * - Data Streams (chainlinkVerifier != 0): feedIds[i] is the report feed id.\n * - Push feeds (chainlinkVerifier == 0, e.g. Robinhood mainnet): feedIds[i]\n * is an AggregatorV3 proxy address left-padded to bytes32\n * (`bytes32(uint160(feed))`); the contract asserts the feed's live\n * `decimals()` equals `priceDecimals[i]`.\n * feedIds[i] must be non-zero in both modes.\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { concat, encodeAbiParameters, encodeFunctionData, numberToHex, pad } from \"viem\";\nimport { ERC20_ABI, BASE_STRATEGY_ABI } from \"../lib/abis.js\";\nimport type { BatchCall } from \"../lib/batch.js\";\n\n// ── UniswapSwapAdapter swapExtraData builders ──\n//\n// Wire format for every mode: one raw mode byte, then abi-encoded route data\n// (see UniswapSwapAdapter.sol header):\n// Mode 0 — v3 single-hop: 0x00 + abi.encode(uint24 fee)\n// Mode 1 — v3 multi-hop: 0x01 + abi.encode(bytes path, uint16 perHopSlippageBps)\n// Mode 2 — v4 single-hop: 0x02 + abi.encode(uint24 fee, int24 tickSpacing)\n// Mode 3 — v4 multi-hop: 0x03 + abi.encode(PathHop[]) where\n// PathHop = { address currency; uint24 fee; int24 tickSpacing }\n// hop i swaps prev currency → hops[i].currency; native ETH = address(0)\n// allowed as an intermediate; last hop currency MUST equal the token.\n\nconst ZERO_ADDRESS: Address = \"0x0000000000000000000000000000000000000000\";\n\n/** Concatenate a raw 1-byte mode prefix with abi-encoded route data. */\nfunction withMode(mode: number, routeData: Hex): Hex {\n const modeByte = (`0x${mode.toString(16).padStart(2, \"0\")}`) as Hex;\n return concat([modeByte, routeData]);\n}\n\n/** Mode 0 — Uniswap v3 single-hop. */\nexport function v3SingleHopExtraData(fee: number): Hex {\n return withMode(0, encodeAbiParameters([{ type: \"uint24\" }], [fee]));\n}\n\n/** Mode 2 — Uniswap v4 single-hop (hookless). */\nexport function v4SingleHopExtraData(fee: number, tickSpacing: number): Hex {\n return withMode(\n 2,\n encodeAbiParameters(\n [{ type: \"uint24\" }, { type: \"int24\" }],\n [fee, tickSpacing],\n ),\n );\n}\n\nexport interface V4PathHop {\n currency: Address; // address(0) = native ETH; last hop MUST equal the allocation token\n fee: number;\n tickSpacing: number;\n}\n\n/** Mode 3 — Uniswap v4 multi-hop (hookless; native ETH allowed as intermediate). */\nexport function v4PathExtraData(hops: V4PathHop[]): Hex {\n // The adapter's _orientHops reverts InvalidPath for n < 2 (a single hop is\n // mode 2) — reject at build time instead of at first execution.\n if (hops.length < 2) throw new Error(\"v4PathExtraData: mode 3 needs >= 2 hops (use v4SingleHopExtraData for one)\");\n return withMode(\n 3,\n encodeAbiParameters(\n [\n {\n type: \"tuple[]\",\n components: [\n { type: \"address\", name: \"currency\" },\n { type: \"uint24\", name: \"fee\" },\n { type: \"int24\", name: \"tickSpacing\" },\n ],\n },\n ],\n [hops.map((h) => ({ currency: h.currency, fee: h.fee, tickSpacing: h.tickSpacing }))],\n ),\n );\n}\n\nexport { ZERO_ADDRESS as NATIVE_ETH };\n\nexport interface BasketAllocation {\n token: Address;\n weightBps: number; // e.g. 4000 = 40%\n swapExtraData: Hex; // adapter-specific (fee tier, path, etc.)\n priceDecimals: number; // Chainlink feed report decimals (8 or 18)\n feedId: Hex; // bytes32: Data Streams feed id, or bytes32(uint160(pushFeed))\n}\n\n/** Default max price age (seconds) for a tokenized-equity push feed on Robinhood\n * mainnet: 96h. Equity feeds go ~77h stale over holiday weekends, past the\n * contract's 26h default — so we pack a wider staleness window per equity slot.\n * Crypto/FX/stable feeds pass 0 (→ contract default 26h). */\nexport const EQUITY_MAX_PRICE_AGE_SECONDS = 96 * 60 * 60; // 345_600\n\n// Contract-enforced bounds on a packed per-slot max price age (0 = default).\nconst MIN_MAX_PRICE_AGE = 3600; // 1h\nconst MAX_MAX_PRICE_AGE = 2_592_000; // 30d\n\n/**\n * Pack a Chainlink AggregatorV3 proxy address (+ optional per-slot max price age)\n * into a bytes32 feed id for push-feed mode (`chainlinkVerifier == address(0)`):\n *\n * bytes32 = uint256(maxAgeSeconds) << 160 | uint160(feedAddress)\n *\n * `maxAgeSeconds`:\n * - omitted / 0 → lower 160 bits only (contract falls back to its 26h default;\n * byte-identical to the plain left-padded address).\n * - provided → must be within [3600, 2_592_000] seconds.\n *\n * The contract decodes the address via `address(uint160(uint256(feedIds[i])))`\n * and the age via `uint256(feedIds[i]) >> 160`.\n */\nexport function pushFeedId(feed: Address, maxAgeSeconds?: number): Hex {\n if (maxAgeSeconds === undefined || maxAgeSeconds === 0) {\n return pad(feed, { size: 32 });\n }\n if (\n !Number.isInteger(maxAgeSeconds) ||\n maxAgeSeconds < MIN_MAX_PRICE_AGE ||\n maxAgeSeconds > MAX_MAX_PRICE_AGE\n ) {\n throw new Error(\n `pushFeedId: maxAgeSeconds must be an integer in [${MIN_MAX_PRICE_AGE}, ${MAX_MAX_PRICE_AGE}] (or 0 for the contract default), got ${maxAgeSeconds}`,\n );\n }\n // (age << 160) | uint160(addr), as a 32-byte hex string.\n const packed = (BigInt(maxAgeSeconds) << 160n) | BigInt(feed);\n return numberToHex(packed, { size: 32 });\n}\n\nexport function buildInitData(\n asset: Address,\n swapAdapter: Address,\n chainlinkVerifier: Address,\n allocations: BasketAllocation[],\n totalAmount: bigint,\n maxSlippageBps: number,\n): Hex {\n const tokens = allocations.map((a) => a.token);\n const weightsBps = allocations.map((a) => BigInt(a.weightBps));\n const swapExtraData = allocations.map((a) => a.swapExtraData);\n const priceDecimals = allocations.map((a) => a.priceDecimals);\n const feedIds = allocations.map((a) => a.feedId);\n\n return encodeAbiParameters(\n [\n { type: \"address\" },\n { type: \"address\" },\n { type: \"address\" },\n { type: \"address[]\" },\n { type: \"uint256[]\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"bytes[]\" },\n { type: \"uint8[]\" },\n { type: \"bytes32[]\" },\n ],\n [\n asset,\n swapAdapter,\n chainlinkVerifier,\n tokens,\n weightsBps,\n totalAmount,\n BigInt(maxSlippageBps),\n swapExtraData,\n priceDecimals,\n feedIds,\n ],\n );\n}\n\nexport function buildExecuteCalls(\n clone: Address,\n asset: Address,\n totalAmount: bigint,\n): BatchCall[] {\n return [\n {\n target: asset,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, totalAmount],\n }),\n value: 0n,\n },\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"execute\",\n }),\n value: 0n,\n },\n ];\n}\n\nexport function buildSettleCalls(clone: Address): BatchCall[] {\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"settle\",\n }),\n value: 0n,\n },\n ];\n}\n\nexport function buildUpdateParamsCalls(\n clone: Address,\n newWeightsBps: number[],\n newMaxSlippageBps: number,\n newSwapExtraData: Hex[],\n): BatchCall[] {\n const data = encodeAbiParameters(\n [{ type: \"uint256[]\" }, { type: \"uint256\" }, { type: \"bytes[]\" }],\n [\n newWeightsBps.map((w) => BigInt(w)),\n BigInt(newMaxSlippageBps),\n newSwapExtraData,\n ],\n );\n\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: [\n {\n type: \"function\",\n name: \"updateParams\",\n inputs: [{ type: \"bytes\", name: \"data\" }],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n ],\n functionName: \"updateParams\",\n args: [data],\n }),\n value: 0n,\n },\n ];\n}\n\n// ── Rebalancing ──\n\nimport { PORTFOLIO_STRATEGY_ABI } from \"../lib/abis.js\";\n\n/**\n * Encode calldata for the simple `rebalance()` call.\n * This is called directly by the proposer (not via vault batch).\n */\nexport function encodeRebalanceCalldata(): Hex {\n return encodeFunctionData({\n abi: PORTFOLIO_STRATEGY_ABI,\n functionName: \"rebalance\",\n });\n}\n\n/**\n * Encode calldata for `rebalanceDelta(bytes[] priceReports)`.\n *\n * Two modes, keyed off `basketSize` + `pushMode`:\n * - Push-feed mode (Robinhood mainnet, chainlinkVerifier == 0): the strategy\n * reads prices from its bound AggregatorV3 push feeds and IGNORES the report\n * bytes, but the array length must still equal the basket size or the call\n * reverts with `LengthMismatch`. Pass `pushMode: true` and the CLI fills\n * `Array(basketSize).fill(\"0x\")` — N empty entries. (Real Data Streams\n * reports here would revert with `InvalidFeedId`.)\n * - Data Streams mode (chainlinkVerifier != 0): pass the signed report blobs\n * as `reports` (one per allocation).\n */\nexport function encodeRebalanceDeltaCalldata(\n opts: { basketSize: number; pushMode: true } | { reports: Hex[]; pushMode?: false },\n): Hex {\n const priceReports: Hex[] =\n \"pushMode\" in opts && opts.pushMode\n ? (Array(opts.basketSize).fill(\"0x\") as Hex[])\n : (opts.reports as Hex[]);\n return encodeFunctionData({\n abi: PORTFOLIO_STRATEGY_ABI,\n functionName: \"rebalanceDelta\",\n args: [priceReports],\n });\n}\n\n/**\n * Encode calldata for `updateParams()` to change weights before rebalancing.\n */\nexport function encodeUpdateWeightsCalldata(\n newWeightsBps: number[],\n newMaxSlippageBps: number,\n newSwapExtraData: Hex[],\n): Hex {\n const data = encodeAbiParameters(\n [{ type: \"uint256[]\" }, { type: \"uint256\" }, { type: \"bytes[]\" }],\n [\n newWeightsBps.map((w) => BigInt(w)),\n BigInt(newMaxSlippageBps),\n newSwapExtraData,\n ],\n );\n\n return encodeFunctionData({\n abi: PORTFOLIO_STRATEGY_ABI,\n functionName: \"updateParams\",\n args: [data],\n });\n}\n","/**\n * HyperliquidPerpStrategy call builder.\n *\n * InitParams (Solidity): (address asset, uint256 depositAmount, uint32 perpAssetIndex, uint32 leverage, uint256 maxPositionSize, uint32 maxTradesPerDay)\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeAbiParameters, encodeFunctionData, maxUint256 } from \"viem\";\nimport { ERC20_ABI, BASE_STRATEGY_ABI, HYPERLIQUID_PERP_STRATEGY_ABI } from \"../lib/abis.js\";\nimport type { BatchCall } from \"../lib/batch.js\";\n\nexport function buildInitData(\n asset: Address,\n depositAmount: bigint,\n perpAssetIndex: number,\n leverage: number,\n maxPositionSize: bigint,\n maxTradesPerDay: number,\n): Hex {\n return encodeAbiParameters(\n [\n { type: \"address\" },\n { type: \"uint256\" },\n { type: \"uint32\" },\n { type: \"uint32\" },\n { type: \"uint256\" },\n { type: \"uint32\" },\n ],\n [asset, depositAmount, perpAssetIndex, leverage, maxPositionSize, maxTradesPerDay],\n );\n}\n\nexport function buildExecuteCalls(\n clone: Address,\n asset: Address,\n amount: bigint,\n): BatchCall[] {\n // In dynamic-all mode (amount == 0) we approve maxUint256 up front and\n // revoke to 0 after execute() in the same atomic batch — the residual\n // allowance never persists beyond the tx.\n const approveAmount = amount === 0n ? maxUint256 : amount;\n\n return [\n {\n target: asset,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, approveAmount],\n }),\n value: 0n,\n },\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"execute\",\n }),\n value: 0n,\n },\n {\n target: asset,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, 0n],\n }),\n value: 0n,\n },\n ];\n}\n\nexport function buildSettleCalls(clone: Address): BatchCall[] {\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"settle\",\n }),\n value: 0n,\n },\n ];\n}\n\n/** Phase 2: sweep USDC back to vault after async HyperCore transfer completes. */\nexport function buildSweepToVaultCalls(clone: Address): BatchCall[] {\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: HYPERLIQUID_PERP_STRATEGY_ABI,\n functionName: \"sweepToVault\",\n }),\n value: 0n,\n },\n ];\n}\n","/**\n * HyperliquidGridStrategy call builder.\n *\n * InitParams (Solidity): (address asset, uint256 depositAmount, uint32 leverage, uint256 maxOrderSize, uint32 maxOrdersPerTick, uint32[] assetIndices)\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeAbiParameters, encodeFunctionData, maxUint256 } from \"viem\";\nimport { ERC20_ABI, BASE_STRATEGY_ABI } from \"../lib/abis.js\";\nimport type { BatchCall } from \"../lib/batch.js\";\n\nexport function buildInitData(\n asset: Address,\n depositAmount: bigint,\n leverage: number,\n maxOrderSize: bigint,\n maxOrdersPerTick: number,\n assetIndices: number[],\n): Hex {\n return encodeAbiParameters(\n [\n { type: \"address\" },\n { type: \"uint256\" },\n { type: \"uint32\" },\n { type: \"uint256\" },\n { type: \"uint32\" },\n { type: \"uint32[]\" },\n ],\n [asset, depositAmount, leverage, maxOrderSize, maxOrdersPerTick, assetIndices],\n );\n}\n\nexport function buildExecuteCalls(\n clone: Address,\n asset: Address,\n amount: bigint,\n): BatchCall[] {\n const approveAmount = amount === 0n ? maxUint256 : amount;\n\n return [\n {\n target: asset,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, approveAmount],\n }),\n value: 0n,\n },\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"execute\",\n }),\n value: 0n,\n },\n {\n target: asset,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, 0n],\n }),\n value: 0n,\n },\n ];\n}\n\nexport function buildSettleCalls(clone: Address): BatchCall[] {\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"settle\",\n }),\n value: 0n,\n },\n ];\n}\n"],"mappings":"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","names":["encodeFunctionData","encodeAbiParameters","concat","numberToHex","encodeAbiParameters","encodeFunctionData","buildInitData","encodeAbiParameters","buildExecuteCalls","encodeFunctionData","buildSettleCalls","encodeAbiParameters","encodeFunctionData","INIT_PARAMS_TYPES","buildInitData","encodeAbiParameters","buildExecuteCalls","encodeFunctionData","buildSettleCalls","encodeAbiParameters","encodeFunctionData","INIT_PARAMS_TYPES","buildInitData","encodeAbiParameters","buildExecuteCalls","encodeFunctionData","buildSettleCalls","encodeAbiParameters","encodeFunctionData","buildInitData","encodeAbiParameters","buildExecuteCalls","encodeFunctionData","buildSettleCalls","encodeAbiParameters","encodeFunctionData","encodeAbiParameters","buildInitData","encodeAbiParameters","buildExecuteCalls","encodeFunctionData","buildSettleCalls","encodeAbiParameters","encodeFunctionData","maxUint256","buildInitData","encodeAbiParameters","buildExecuteCalls","maxUint256","encodeFunctionData","buildSettleCalls","encodeAbiParameters","encodeFunctionData","maxUint256","buildInitData","encodeAbiParameters","buildExecuteCalls","maxUint256","encodeFunctionData","buildSettleCalls","numberToHex","concat","encoded","encodeAbiParameters","buildInitData","robinhoodDefaultRoute","priceDecimals","buildExecuteCalls","buildSettleCalls","ZERO","ZERO","result","encodeFunctionData"]}
|
|
@@ -3,6 +3,36 @@ import fs from "fs";
|
|
|
3
3
|
import os from "os";
|
|
4
4
|
import path from "path";
|
|
5
5
|
import { privateKeyToAccount } from "viem/accounts";
|
|
6
|
+
|
|
7
|
+
// src/lib/settings.ts
|
|
8
|
+
var hex0x = (v) => v.startsWith("0x") ? v : `0x${v}`;
|
|
9
|
+
var SETTINGS = {
|
|
10
|
+
privateKey: {
|
|
11
|
+
fromConfig: (c) => c.privateKey,
|
|
12
|
+
envVar: "PRIVATE_KEY",
|
|
13
|
+
normalize: hex0x
|
|
14
|
+
},
|
|
15
|
+
veniceApiKey: {
|
|
16
|
+
fromConfig: (c) => c.veniceApiKey,
|
|
17
|
+
envVar: "VENICE_API_KEY"
|
|
18
|
+
},
|
|
19
|
+
anthropicApiKey: {
|
|
20
|
+
fromConfig: (c) => c.anthropicApiKey,
|
|
21
|
+
envVar: "ANTHROPIC_API_KEY"
|
|
22
|
+
},
|
|
23
|
+
uniswapApiKey: {
|
|
24
|
+
fromConfig: (c) => c.uniswapApiKey,
|
|
25
|
+
envVar: "UNISWAP_API_KEY"
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
function resolveSetting(key, config, env) {
|
|
29
|
+
const spec = SETTINGS[key];
|
|
30
|
+
const raw = spec.fromConfig(config) || (spec.envVar ? env[spec.envVar] : void 0);
|
|
31
|
+
if (!raw) return void 0;
|
|
32
|
+
return spec.normalize ? spec.normalize(raw) : raw;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/lib/config.ts
|
|
6
36
|
var CONFIG_DIR = path.join(os.homedir(), ".sherwood");
|
|
7
37
|
var CONFIG_PATH = path.join(CONFIG_DIR, "config.json");
|
|
8
38
|
var DASHBOARD_BRIDGE_PATH = path.join(CONFIG_DIR, "dashboard.json");
|
|
@@ -62,7 +92,7 @@ function setVeniceApiKey(apiKey) {
|
|
|
62
92
|
saveConfig(config);
|
|
63
93
|
}
|
|
64
94
|
function getVeniceApiKey() {
|
|
65
|
-
return loadConfig()
|
|
95
|
+
return resolveSetting("veniceApiKey", loadConfig(), process.env);
|
|
66
96
|
}
|
|
67
97
|
function setAnthropicApiKey(apiKey) {
|
|
68
98
|
const config = loadConfig();
|
|
@@ -70,7 +100,7 @@ function setAnthropicApiKey(apiKey) {
|
|
|
70
100
|
saveConfig(config);
|
|
71
101
|
}
|
|
72
102
|
function getAnthropicApiKey() {
|
|
73
|
-
return loadConfig()
|
|
103
|
+
return resolveSetting("anthropicApiKey", loadConfig(), process.env);
|
|
74
104
|
}
|
|
75
105
|
function setAgentId(agentId) {
|
|
76
106
|
const config = loadConfig();
|
|
@@ -85,8 +115,14 @@ function setPrivateKey(key) {
|
|
|
85
115
|
config.privateKey = key.startsWith("0x") ? key : `0x${key}`;
|
|
86
116
|
saveConfig(config);
|
|
87
117
|
}
|
|
88
|
-
function
|
|
89
|
-
|
|
118
|
+
function requirePrivateKey() {
|
|
119
|
+
const key = resolveSetting("privateKey", loadConfig(), process.env);
|
|
120
|
+
if (!key) {
|
|
121
|
+
throw new Error(
|
|
122
|
+
"Private key not found. Run 'sherwood config set --private-key <key>' or set PRIVATE_KEY env var."
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
return key;
|
|
90
126
|
}
|
|
91
127
|
function setUniswapApiKey(apiKey) {
|
|
92
128
|
const config = loadConfig();
|
|
@@ -94,7 +130,7 @@ function setUniswapApiKey(apiKey) {
|
|
|
94
130
|
saveConfig(config);
|
|
95
131
|
}
|
|
96
132
|
function getUniswapApiKey() {
|
|
97
|
-
return loadConfig()
|
|
133
|
+
return resolveSetting("uniswapApiKey", loadConfig(), process.env);
|
|
98
134
|
}
|
|
99
135
|
function getConfigRpcUrl(network) {
|
|
100
136
|
return loadConfig().rpc?.[network];
|
|
@@ -207,7 +243,7 @@ export {
|
|
|
207
243
|
setAgentId,
|
|
208
244
|
getAgentId,
|
|
209
245
|
setPrivateKey,
|
|
210
|
-
|
|
246
|
+
requirePrivateKey,
|
|
211
247
|
setUniswapApiKey,
|
|
212
248
|
getUniswapApiKey,
|
|
213
249
|
getConfigRpcUrl,
|
|
@@ -224,4 +260,4 @@ export {
|
|
|
224
260
|
cacheSwapRoute,
|
|
225
261
|
clearSwapRoutes
|
|
226
262
|
};
|
|
227
|
-
//# sourceMappingURL=chunk-
|
|
263
|
+
//# sourceMappingURL=chunk-6MV4ESXM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/config.ts","../src/lib/settings.ts"],"sourcesContent":["/**\n * Local config management — ~/.sherwood/config.json\n *\n * Stores group ID cache, per-chain contract addresses, and wallet config.\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport { resolveSetting } from \"./settings.js\";\n\nconst CONFIG_DIR = path.join(os.homedir(), \".sherwood\");\nconst CONFIG_PATH = path.join(CONFIG_DIR, \"config.json\");\nconst DASHBOARD_BRIDGE_PATH = path.join(CONFIG_DIR, \"dashboard.json\");\n\n/** Per-chain user-specific addresses (stored by chainId). */\nexport interface ChainContracts {\n vault?: string; // user's default vault address\n}\n\n/** A fund the agent belongs to (creator or member). */\nexport interface FundMembership {\n subdomain: string;\n vault: string;\n role: \"creator\" | \"agent\";\n}\n\nexport interface SherwoodConfig {\n dbEncryptionKey?: string; // legacy — no longer used, XMTP CLI manages its own DB\n privateKey?: string; // wallet private key (0x-prefixed)\n xmtpInboxId?: string;\n groupCache: Record<string, string>; // subdomain → XMTP group ID\n veniceApiKey?: string; // Venice AI inference API key\n anthropicApiKey?: string; // Anthropic Claude API key (for LLM judge)\n agentId?: number; // ERC-8004 identity token ID\n contracts?: Record<string, ChainContracts>; // chainId → user addresses\n funds?: Record<string, FundMembership[]>; // chainId → fund memberships\n primaryFund?: Record<string, string>; // chainId → subdomain of the active fund\n rpc?: Record<string, string>; // network name → custom RPC URL\n notifyTo?: string; // destination for cron summaries (Telegram chat ID, phone, etc.)\n uniswapApiKey?: string; // Uniswap Trading API key (from developers.uniswap.org)\n positions?: unknown[]; // open trade positions (typed in positions.ts)\n closedPositions?: unknown[]; // historical closed positions\n _xmtpMigrated?: boolean; // one-time flag: revoked stale installations from ~/.xmtp/ era\n /** Cached swap routes per chain: chainId → { tokenPair → SwapRoute } */\n swapRoutes?: Record<string, Record<string, SwapRoute>>;\n}\n\n/** Persisted swap route detected by the CLI during portfolio strategy proposal. */\nexport interface SwapRoute {\n mode: \"direct\" | \"multi-hop\";\n feeTier: number; // direct pool fee tier\n hop?: { via: string; feeIn: number; feeOut: number }; // multi-hop details\n detectedAt: number; // unix timestamp\n}\n\nexport function loadConfig(): SherwoodConfig {\n if (fs.existsSync(CONFIG_PATH)) {\n const config = JSON.parse(fs.readFileSync(CONFIG_PATH, \"utf-8\"));\n if (!config.groupCache) config.groupCache = {};\n return config;\n }\n\n return { groupCache: {} };\n}\n\nexport function saveConfig(config: SherwoodConfig): void {\n fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });\n fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });\n writeDashboardBridge(config);\n}\n\n/**\n * Public-safe derivation of config.json for Hermes dashboard plugins to read.\n * Excludes privateKey + every other sensitive field. Hermes' sherwood-companion\n * plugin reads ~/.sherwood/dashboard.json to auto-detect the operator's\n * primary fund without prompting.\n *\n * Wrapped in try/catch — bridge-write failure must not break a config save.\n */\nfunction writeDashboardBridge(config: SherwoodConfig): void {\n try {\n let agentWallet: string | null = null;\n if (config.privateKey) {\n const key = config.privateKey.startsWith(\"0x\")\n ? (config.privateKey as `0x${string}`)\n : (`0x${config.privateKey}` as `0x${string}`);\n agentWallet = privateKeyToAccount(key).address;\n }\n const bridge = {\n version: 1,\n agentWallet,\n funds: config.funds ?? {},\n primaryFund: config.primaryFund ?? {},\n };\n fs.writeFileSync(\n DASHBOARD_BRIDGE_PATH,\n JSON.stringify(bridge, null, 2),\n { mode: 0o600 },\n );\n } catch {\n // Non-fatal: plugin will fall back to manual subdomain entry.\n }\n}\n\nexport function cacheGroupId(subdomain: string, groupId: string): void {\n const config = loadConfig();\n config.groupCache[subdomain] = groupId;\n saveConfig(config);\n}\n\nexport function getCachedGroupId(subdomain: string): string | undefined {\n const config = loadConfig();\n return config.groupCache[subdomain];\n}\n\nexport function invalidateCachedGroupId(subdomain: string): void {\n const config = loadConfig();\n if (config.groupCache[subdomain]) {\n delete config.groupCache[subdomain];\n saveConfig(config);\n }\n}\n\nexport function setVeniceApiKey(apiKey: string): void {\n const config = loadConfig();\n config.veniceApiKey = apiKey;\n saveConfig(config);\n}\n\nexport function getVeniceApiKey(): string | undefined {\n return resolveSetting(\"veniceApiKey\", loadConfig(), process.env);\n}\n\n// ── Anthropic API Key ──\n\nexport function setAnthropicApiKey(apiKey: string): void {\n const config = loadConfig();\n config.anthropicApiKey = apiKey;\n saveConfig(config);\n}\n\nexport function getAnthropicApiKey(): string | undefined {\n return resolveSetting(\"anthropicApiKey\", loadConfig(), process.env);\n}\n\nexport function setAgentId(agentId: number): void {\n const config = loadConfig();\n config.agentId = agentId;\n saveConfig(config);\n}\n\nexport function getAgentId(): number | undefined {\n return loadConfig().agentId;\n}\n\nexport function setPrivateKey(key: string): void {\n const config = loadConfig();\n config.privateKey = key.startsWith(\"0x\") ? key : `0x${key}`;\n saveConfig(config);\n}\n\n/**\n * Resolve the signing key (config → PRIVATE_KEY env, 0x-normalized) or\n * throw with the canonical setup hint. Every path that signs or derives\n * identity from the key (viem clients, Agent0 SDK, XMTP) must use this,\n * so they can never resolve different keys.\n */\nexport function requirePrivateKey(): `0x${string}` {\n const key = resolveSetting(\"privateKey\", loadConfig(), process.env);\n if (!key) {\n throw new Error(\n \"Private key not found. Run 'sherwood config set --private-key <key>' or set PRIVATE_KEY env var.\",\n );\n }\n return key as `0x${string}`;\n}\n\n// ── Uniswap Trading API Key ──\n\nexport function setUniswapApiKey(apiKey: string): void {\n const config = loadConfig();\n config.uniswapApiKey = apiKey;\n saveConfig(config);\n}\n\nexport function getUniswapApiKey(): string | undefined {\n return resolveSetting(\"uniswapApiKey\", loadConfig(), process.env);\n}\n\n// ── Per-network RPC URLs ──\n\nexport function getConfigRpcUrl(network: string): string | undefined {\n return loadConfig().rpc?.[network];\n}\n\nexport function setConfigRpcUrl(network: string, url: string): void {\n const config = loadConfig();\n if (!config.rpc) config.rpc = {};\n config.rpc[network] = url;\n saveConfig(config);\n}\n\n// ── Per-chain contract addresses ──\n\nexport function getChainContracts(chainId: number): ChainContracts {\n const config = loadConfig();\n return config.contracts?.[String(chainId)] ?? {};\n}\n\nexport function getNotifyTo(): string | undefined {\n return loadConfig().notifyTo;\n}\n\nexport function setNotifyTo(id: string): void {\n const config = loadConfig();\n config.notifyTo = id;\n saveConfig(config);\n}\n\nexport function setChainContract(\n chainId: number,\n key: keyof ChainContracts,\n value: string,\n): void {\n const config = loadConfig();\n if (!config.contracts) config.contracts = {};\n const cid = String(chainId);\n if (!config.contracts[cid]) config.contracts[cid] = {};\n config.contracts[cid][key] = value;\n saveConfig(config);\n}\n\n// ── Fund Membership ──\n\n/**\n * Add (or update) a fund membership. Deduplicates by subdomain.\n * Automatically sets it as primary if it's the first fund on this chain.\n */\nexport function addFund(\n chainId: number,\n membership: FundMembership,\n): void {\n const config = loadConfig();\n const cid = String(chainId);\n if (!config.funds) config.funds = {};\n if (!config.funds[cid]) config.funds[cid] = [];\n\n // Upsert — replace existing entry with same subdomain\n const idx = config.funds[cid].findIndex(\n (s) => s.subdomain === membership.subdomain,\n );\n if (idx >= 0) {\n config.funds[cid][idx] = membership;\n } else {\n config.funds[cid].push(membership);\n }\n\n // Auto-set as primary if it's the first fund (or no primary set)\n if (!config.primaryFund) config.primaryFund = {};\n if (!config.primaryFund[cid]) {\n config.primaryFund[cid] = membership.subdomain;\n }\n\n saveConfig(config);\n}\n\n/** Get all fund memberships for a chain. */\nexport function getFunds(chainId: number): FundMembership[] {\n const config = loadConfig();\n return config.funds?.[String(chainId)] ?? [];\n}\n\n/** Set which fund is the active/primary one for CLI commands. */\nexport function setPrimaryFund(\n chainId: number,\n subdomain: string,\n): void {\n const config = loadConfig();\n if (!config.primaryFund) config.primaryFund = {};\n config.primaryFund[String(chainId)] = subdomain;\n saveConfig(config);\n}\n\n/**\n * Get the primary fund for this chain.\n * Falls back to ChainContracts.vault for backwards compat with older configs.\n */\nexport function getPrimaryFund(\n chainId: number,\n): FundMembership | undefined {\n const config = loadConfig();\n const cid = String(chainId);\n\n // Check new funds store first\n const primarySubdomain = config.primaryFund?.[cid];\n if (primarySubdomain && config.funds?.[cid]) {\n const found = config.funds[cid].find(\n (s) => s.subdomain === primarySubdomain,\n );\n if (found) return found;\n }\n\n // Backwards compat: if funds list has entries but no primary, use the first one\n if (config.funds?.[cid]?.length) {\n return config.funds[cid][0];\n }\n\n // Legacy fallback: config only has a vault address, no subdomain\n const vault = config.contracts?.[cid]?.vault;\n if (vault) {\n return { subdomain: \"\", vault, role: \"creator\" };\n }\n\n return undefined;\n}\n\n// ── Swap Route Cache ──\n\nfunction swapRouteKey(asset: string, token: string): string {\n return `${asset.toLowerCase()}→${token.toLowerCase()}`;\n}\n\n/** Get a cached swap route for a token pair on a chain. */\nexport function getCachedSwapRoute(chainId: number, asset: string, token: string): SwapRoute | undefined {\n const config = loadConfig();\n return config.swapRoutes?.[String(chainId)]?.[swapRouteKey(asset, token)];\n}\n\n/** Save a detected swap route to the config cache. */\nexport function cacheSwapRoute(chainId: number, asset: string, token: string, route: SwapRoute): void {\n const config = loadConfig();\n const cid = String(chainId);\n if (!config.swapRoutes) config.swapRoutes = {};\n if (!config.swapRoutes[cid]) config.swapRoutes[cid] = {};\n config.swapRoutes[cid][swapRouteKey(asset, token)] = route;\n saveConfig(config);\n}\n\n/** Clear all cached swap routes for a chain (e.g. after pool migration). */\nexport function clearSwapRoutes(chainId: number): void {\n const config = loadConfig();\n delete config.swapRoutes?.[String(chainId)];\n saveConfig(config);\n}\n","/**\n * Single owner of config → env resolution for user settings. Every\n * config-or-env setting resolves through the table below — accessors in\n * config.ts and requirePrivateKey() delegate here.\n */\n\nimport { type SherwoodConfig } from \"./config.js\";\n\ntype Env = Record<string, string | undefined>;\n\nconst hex0x = (v: string): string => (v.startsWith(\"0x\") ? v : `0x${v}`);\n\ninterface SettingSpec {\n fromConfig: (c: Partial<SherwoodConfig>) => string | undefined;\n envVar?: string;\n normalize?: (v: string) => string;\n}\n\nconst SETTINGS = {\n privateKey: {\n fromConfig: (c) => c.privateKey,\n envVar: \"PRIVATE_KEY\",\n normalize: hex0x,\n },\n veniceApiKey: {\n fromConfig: (c) => c.veniceApiKey,\n envVar: \"VENICE_API_KEY\",\n },\n anthropicApiKey: {\n fromConfig: (c) => c.anthropicApiKey,\n envVar: \"ANTHROPIC_API_KEY\",\n },\n uniswapApiKey: {\n fromConfig: (c) => c.uniswapApiKey,\n envVar: \"UNISWAP_API_KEY\",\n },\n} satisfies Record<string, SettingSpec>;\n\nexport type SettingKey = keyof typeof SETTINGS;\n\nexport function resolveSetting(\n key: SettingKey,\n config: Partial<SherwoodConfig>,\n env: Env,\n): string | undefined {\n const spec: SettingSpec = SETTINGS[key];\n // Empty string counts as absent on both sources: an empty config key\n // falls through to the env, and a blank `PRIVATE_KEY=` dotenv line\n // resolves to undefined (so callers show the setup hint) instead of\n // normalizing to a bare \"0x\".\n const raw =\n spec.fromConfig(config) || (spec.envVar ? env[spec.envVar] : undefined);\n if (!raw) return undefined;\n return spec.normalize ? spec.normalize(raw) : raw;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,25 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
executeBatch,
|
|
3
|
-
setVaultAddress
|
|
4
|
-
} from "./chunk-CZRJ5GWE.js";
|
|
5
1
|
import {
|
|
6
2
|
ENS,
|
|
7
3
|
SHERWOOD
|
|
8
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-UINMHN6S.js";
|
|
9
5
|
import {
|
|
10
6
|
getPublicClient
|
|
11
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-2OHX3O55.js";
|
|
12
8
|
import {
|
|
13
9
|
VALID_NETWORKS,
|
|
14
10
|
withNetwork
|
|
15
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-LHVSS27T.js";
|
|
16
12
|
import {
|
|
17
13
|
L2_REGISTRY_ABI,
|
|
18
14
|
SYNDICATE_FACTORY_ABI
|
|
19
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-TU655ZTV.js";
|
|
20
16
|
|
|
21
17
|
// src/lib/ens.ts
|
|
22
|
-
import { encodeFunctionData } from "viem";
|
|
23
18
|
import { namehash } from "viem/ens";
|
|
24
19
|
var ENS_DOMAIN = "sherwoodagent.eth";
|
|
25
20
|
var ZERO = "0x0000000000000000000000000000000000000000";
|
|
@@ -91,17 +86,9 @@ async function resolveVaultFund(vaultAddress) {
|
|
|
91
86
|
function getSubdomainNode(subdomain) {
|
|
92
87
|
return namehash(`${subdomain}.${ENS_DOMAIN}`);
|
|
93
88
|
}
|
|
94
|
-
async function setTextRecord(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
setVaultAddress(vaultAddress);
|
|
98
|
-
const setTextData = encodeFunctionData({
|
|
99
|
-
abi: L2_REGISTRY_ABI,
|
|
100
|
-
functionName: "setText",
|
|
101
|
-
args: [node, key, value]
|
|
102
|
-
});
|
|
103
|
-
return executeBatch(
|
|
104
|
-
[{ target: l2Registry, data: setTextData, value: 0n }]
|
|
89
|
+
async function setTextRecord(_subdomain, _key, _value, _vaultAddress) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
"ENS text-record writes are not available: the vault no longer exposes owner-direct batch execution (executeBatch was removed on-chain, V-C3). Fund metadata on IPFS is the operative store for these records \u2014 use `sherwood chat <name> publish-metadata`."
|
|
105
92
|
);
|
|
106
93
|
}
|
|
107
94
|
async function getTextRecord(subdomain, key) {
|
|
@@ -124,4 +111,4 @@ export {
|
|
|
124
111
|
setTextRecord,
|
|
125
112
|
getTextRecord
|
|
126
113
|
};
|
|
127
|
-
//# sourceMappingURL=chunk-
|
|
114
|
+
//# sourceMappingURL=chunk-6UEQUVTQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/ens.ts"],"sourcesContent":["/**\n * ENS resolution + text records via Durin L2Registry on Base.\n *\n * Two responsibilities:\n * 1. Resolve fund subdomain → on-chain fund data (via factory)\n * 2. Read ENS text records (via L2Registry)\n *\n * The vault owns the ENS subdomain node (registered in the factory via\n * `ensRegistrar.register(subdomain, vault)`), so only the vault can write\n * text records. Writes used to route through the vault's owner-direct\n * `executeBatch` → L2Registry.setText — that function was removed on-chain\n * (V-C3; only the governor-driven `executeGovernorBatch` exists), so\n * `setTextRecord` now fails fast (see below) and IPFS fund metadata is the\n * operative store for these records.\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { namehash } from \"viem/ens\";\nimport { getPublicClient } from \"./client.js\";\nimport {\n withNetwork,\n VALID_NETWORKS,\n type Network,\n} from \"./network.js\";\nimport { SYNDICATE_FACTORY_ABI, L2_REGISTRY_ABI } from \"./abis.js\";\nimport { ENS, SHERWOOD } from \"./addresses.js\";\n\nconst ENS_DOMAIN = \"sherwoodagent.eth\";\n\n/** Sentinel for \"no ENS registry deployed on this chain\" (e.g. Robinhood testnet). */\nconst ZERO: Address = \"0x0000000000000000000000000000000000000000\";\n\nfunction getFactoryAddress(): Address {\n return SHERWOOD().FACTORY;\n}\n\n// ── Fund Resolution (via factory) ──\n\nexport interface FundResolution {\n id: bigint;\n vault: Address;\n creator: Address;\n subdomain: string;\n}\n\n/**\n * Resolve a fund subdomain to its on-chain data.\n * Uses factory.subdomainToSyndicate() → factory.syndicates().\n */\nexport async function resolveFund(subdomain: string): Promise<FundResolution> {\n const client = getPublicClient();\n const factory = getFactoryAddress();\n\n // Get fund ID from subdomain\n const fundId = (await client.readContract({\n address: factory,\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"subdomainToSyndicate\",\n args: [subdomain],\n })) as bigint;\n\n if (fundId === 0n) {\n throw new Error(`Fund \"${subdomain}\" not found`);\n }\n\n // Get full fund record\n const result = (await client.readContract({\n address: factory,\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"syndicates\",\n args: [fundId],\n })) as [bigint, Address, Address, string, bigint, boolean, string];\n\n return {\n id: result[0],\n vault: result[1],\n creator: result[2],\n subdomain: result[6],\n };\n}\n\n/**\n * Probe every supported chain for a subdomain registration. Returns every hit —\n * most queries find zero or one, but post-CREATE3 the same subdomain may exist\n * on multiple chains and the caller needs to disambiguate. RPC errors on\n * individual chains are swallowed so a flaky chain doesn't fail the whole\n * search. The current deployment target is a single (ungated) chain, so this\n * iterates VALID_NETWORKS directly.\n */\nexport async function searchFundAcrossChains(\n subdomain: string,\n): Promise<{ network: Network; result: FundResolution }[]> {\n const candidates = VALID_NETWORKS;\n\n const hits: { network: Network; result: FundResolution }[] = [];\n for (const net of candidates) {\n try {\n const result = await withNetwork(net, () => resolveFund(subdomain));\n hits.push({ network: net, result });\n } catch {\n // Not registered on this chain, or RPC failed — keep searching.\n }\n }\n return hits;\n}\n\n/**\n * Reverse lookup: vault address → fund info.\n * Uses factory.vaultToSyndicate() → factory.syndicates().\n */\nexport async function resolveVaultFund(\n vaultAddress: Address,\n): Promise<FundResolution> {\n const client = getPublicClient();\n const factory = getFactoryAddress();\n\n const fundId = (await client.readContract({\n address: factory,\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"vaultToSyndicate\",\n args: [vaultAddress],\n })) as bigint;\n\n if (fundId === 0n) {\n throw new Error(`No fund found for vault ${vaultAddress}`);\n }\n\n const result = (await client.readContract({\n address: factory,\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"syndicates\",\n args: [fundId],\n })) as [bigint, Address, Address, string, bigint, boolean, string];\n\n return {\n id: result[0],\n vault: result[1],\n creator: result[2],\n subdomain: result[6],\n };\n}\n\n// ── ENS Text Records (via L2Registry) ──\n\n/**\n * Compute the ENS node hash for a subdomain under sherwoodagent.eth.\n */\nfunction getSubdomainNode(subdomain: string): Hex {\n return namehash(`${subdomain}.${ENS_DOMAIN}`);\n}\n\n/**\n * Write a text record to the L2Registry — CURRENTLY IMPOSSIBLE.\n *\n * The vault owns the ENS node, so only the vault can call setText, and the\n * write used to route through the vault's owner-direct `executeBatch`. That\n * function was removed on-chain (V-C3) — the only remaining batch path is\n * the governor-driven `executeGovernorBatch` — so this call reverted\n * opaquely at runtime. Fail fast with an honest error instead; callers\n * already treat the write as best-effort and fall back to IPFS fund\n * metadata (`sherwood chat <name> publish-metadata`), which the dashboard\n * resolves before ENS.\n *\n * Parameters are kept for API stability with the best-effort call sites.\n */\nexport async function setTextRecord(\n _subdomain: string,\n _key: string,\n _value: string,\n _vaultAddress: Address,\n): Promise<Hex> {\n throw new Error(\n \"ENS text-record writes are not available: the vault no longer exposes \" +\n \"owner-direct batch execution (executeBatch was removed on-chain, V-C3). \" +\n \"Fund metadata on IPFS is the operative store for these records — use \" +\n \"`sherwood chat <name> publish-metadata`.\",\n );\n}\n\n/**\n * Read a text record from the L2Registry.\n * Used to look up xmtpGroupId when not cached locally.\n *\n * Chains without a deployed ENS registry (e.g. Robinhood testnet, where\n * `L2_REGISTRY == address(0)`) have no text records — reading `text()` from\n * the zero address makes viem throw `ContractFunctionZeroDataError`. Return\n * \"\" instead so callers (chat init idempotency probe, getGroup ENS fallback)\n * degrade to the cache / name-search paths rather than hard-failing. Every\n * caller already treats \"\" as \"not set\".\n */\nexport async function getTextRecord(\n subdomain: string,\n key: string,\n): Promise<string> {\n const registry = ENS().L2_REGISTRY;\n if (registry.toLowerCase() === ZERO.toLowerCase()) return \"\";\n\n const client = getPublicClient();\n const node = getSubdomainNode(subdomain);\n\n return client.readContract({\n address: registry,\n abi: L2_REGISTRY_ABI,\n functionName: \"text\",\n args: [node, key],\n }) as Promise<string>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,SAAS,gBAAgB;AAUzB,IAAM,aAAa;AAGnB,IAAM,OAAgB;AAEtB,SAAS,oBAA6B;AACpC,SAAO,SAAS,EAAE;AACpB;AAeA,eAAsB,YAAY,WAA4C;AAC5E,QAAM,SAAS,gBAAgB;AAC/B,QAAM,UAAU,kBAAkB;AAGlC,QAAM,SAAU,MAAM,OAAO,aAAa;AAAA,IACxC,SAAS;AAAA,IACT,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC,SAAS;AAAA,EAClB,CAAC;AAED,MAAI,WAAW,IAAI;AACjB,UAAM,IAAI,MAAM,SAAS,SAAS,aAAa;AAAA,EACjD;AAGA,QAAM,SAAU,MAAM,OAAO,aAAa;AAAA,IACxC,SAAS;AAAA,IACT,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC,MAAM;AAAA,EACf,CAAC;AAED,SAAO;AAAA,IACL,IAAI,OAAO,CAAC;AAAA,IACZ,OAAO,OAAO,CAAC;AAAA,IACf,SAAS,OAAO,CAAC;AAAA,IACjB,WAAW,OAAO,CAAC;AAAA,EACrB;AACF;AAUA,eAAsB,uBACpB,WACyD;AACzD,QAAM,aAAa;AAEnB,QAAM,OAAuD,CAAC;AAC9D,aAAW,OAAO,YAAY;AAC5B,QAAI;AACF,YAAM,SAAS,MAAM,YAAY,KAAK,MAAM,YAAY,SAAS,CAAC;AAClE,WAAK,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC;AAAA,IACpC,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AAMA,eAAsB,iBACpB,cACyB;AACzB,QAAM,SAAS,gBAAgB;AAC/B,QAAM,UAAU,kBAAkB;AAElC,QAAM,SAAU,MAAM,OAAO,aAAa;AAAA,IACxC,SAAS;AAAA,IACT,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC,YAAY;AAAA,EACrB,CAAC;AAED,MAAI,WAAW,IAAI;AACjB,UAAM,IAAI,MAAM,2BAA2B,YAAY,EAAE;AAAA,EAC3D;AAEA,QAAM,SAAU,MAAM,OAAO,aAAa;AAAA,IACxC,SAAS;AAAA,IACT,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC,MAAM;AAAA,EACf,CAAC;AAED,SAAO;AAAA,IACL,IAAI,OAAO,CAAC;AAAA,IACZ,OAAO,OAAO,CAAC;AAAA,IACf,SAAS,OAAO,CAAC;AAAA,IACjB,WAAW,OAAO,CAAC;AAAA,EACrB;AACF;AAOA,SAAS,iBAAiB,WAAwB;AAChD,SAAO,SAAS,GAAG,SAAS,IAAI,UAAU,EAAE;AAC9C;AAgBA,eAAsB,cACpB,YACA,MACA,QACA,eACc;AACd,QAAM,IAAI;AAAA,IACR;AAAA,EAIF;AACF;AAaA,eAAsB,cACpB,WACA,KACiB;AACjB,QAAM,WAAW,IAAI,EAAE;AACvB,MAAI,SAAS,YAAY,MAAM,KAAK,YAAY,EAAG,QAAO;AAE1D,QAAM,SAAS,gBAAgB;AAC/B,QAAM,OAAO,iBAAiB,SAAS;AAEvC,SAAO,OAAO,aAAa;AAAA,IACzB,SAAS;AAAA,IACT,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC,MAAM,GAAG;AAAA,EAClB,CAAC;AACH;","names":[]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getAccount
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2OHX3O55.js";
|
|
4
4
|
import {
|
|
5
5
|
getVeniceApiKey,
|
|
6
6
|
setVeniceApiKey
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-6MV4ESXM.js";
|
|
8
8
|
|
|
9
9
|
// src/lib/venice.ts
|
|
10
10
|
import chalk from "chalk";
|
|
@@ -186,4 +186,4 @@ export {
|
|
|
186
186
|
chatCompletion,
|
|
187
187
|
listModels
|
|
188
188
|
};
|
|
189
|
-
//# sourceMappingURL=chunk-
|
|
189
|
+
//# sourceMappingURL=chunk-BD4ZV7FQ.js.map
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getAccount
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
|
|
5
|
-
// src/providers/research/messari.ts
|
|
6
|
-
import { base, baseSepolia } from "viem/chains";
|
|
3
|
+
} from "./chunk-2OHX3O55.js";
|
|
7
4
|
|
|
8
5
|
// src/lib/x402.ts
|
|
9
6
|
var _x402Fetch = null;
|
|
@@ -27,10 +24,10 @@ async function isX402WalletFunded() {
|
|
|
27
24
|
}
|
|
28
25
|
try {
|
|
29
26
|
const { createPublicClient, http } = await import("viem");
|
|
30
|
-
const { base
|
|
27
|
+
const { base } = await import("viem/chains");
|
|
31
28
|
const account = getAccount();
|
|
32
29
|
const client = createPublicClient({
|
|
33
|
-
chain:
|
|
30
|
+
chain: base,
|
|
34
31
|
transport: http("https://base-rpc.publicnode.com")
|
|
35
32
|
});
|
|
36
33
|
const balance = await client.readContract({
|
|
@@ -72,7 +69,9 @@ var MessariProvider = class {
|
|
|
72
69
|
"research.token",
|
|
73
70
|
"research.market"
|
|
74
71
|
],
|
|
75
|
-
|
|
72
|
+
// Chain-agnostic: research queries an off-chain x402 API — no
|
|
73
|
+
// per-chain support claim (mirrors the data providers' convention).
|
|
74
|
+
supportedChains: []
|
|
76
75
|
};
|
|
77
76
|
}
|
|
78
77
|
async query(params) {
|
|
@@ -221,7 +220,6 @@ var MessariProvider = class {
|
|
|
221
220
|
};
|
|
222
221
|
|
|
223
222
|
// src/providers/research/nansen.ts
|
|
224
|
-
import { base as base2, baseSepolia as baseSepolia2 } from "viem/chains";
|
|
225
223
|
var BASE_URL2 = "https://api.nansen.ai";
|
|
226
224
|
var _nansenFetch = null;
|
|
227
225
|
var _nansenFetchKey;
|
|
@@ -262,7 +260,9 @@ var NansenProvider = class {
|
|
|
262
260
|
"research.smart-money",
|
|
263
261
|
"research.wallet"
|
|
264
262
|
],
|
|
265
|
-
|
|
263
|
+
// Chain-agnostic: research queries an off-chain x402 API — no
|
|
264
|
+
// per-chain support claim (mirrors the data providers' convention).
|
|
265
|
+
supportedChains: []
|
|
266
266
|
};
|
|
267
267
|
}
|
|
268
268
|
async query(params) {
|
|
@@ -635,4 +635,4 @@ export {
|
|
|
635
635
|
NansenProvider,
|
|
636
636
|
getResearchProvider
|
|
637
637
|
};
|
|
638
|
-
//# sourceMappingURL=chunk-
|
|
638
|
+
//# sourceMappingURL=chunk-DGLLSZ2D.js.map
|