@sherwoodagent/cli 0.86.1 → 0.87.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{abis-WVW2EBI3.js → abis-WJQ6IVYV.js} +2 -2
- package/dist/{agent-TBLC3WNJ.js → agent-A2JEYGQS.js} +7 -7
- package/dist/{chat-ETZSKQDI.js → chat-OZAAN5LT.js} +8 -8
- package/dist/{chunk-ZN2MHIB7.js → chunk-37GT3TJX.js} +5 -5
- package/dist/{chunk-45FELUWY.js → chunk-3UYGXGMF.js} +2 -2
- package/dist/{chunk-YAS52NEF.js → chunk-CU42ZD4K.js} +5 -5
- package/dist/chunk-CU42ZD4K.js.map +1 -0
- package/dist/{chunk-PVTZMRC6.js → chunk-G3FUEM5N.js} +2 -2
- package/dist/chunk-G3FUEM5N.js.map +1 -0
- package/dist/{chunk-XPVXNG2K.js → chunk-GR3GSU3I.js} +6 -6
- package/dist/{chunk-KVB5P2OE.js → chunk-IINWI3LD.js} +2 -2
- package/dist/{chunk-F3MDCUGO.js → chunk-J2IZWAEW.js} +75 -227
- package/dist/chunk-J2IZWAEW.js.map +1 -0
- package/dist/{chunk-3IAZQMAW.js → chunk-JGD6A2Q4.js} +29 -82
- package/dist/chunk-JGD6A2Q4.js.map +1 -0
- package/dist/{chunk-QRMZRAMG.js → chunk-MIAMGVZ4.js} +8 -8
- package/dist/chunk-MIAMGVZ4.js.map +1 -0
- package/dist/{chunk-EA65CDQH.js → chunk-R6F57QQF.js} +14 -23
- package/dist/chunk-R6F57QQF.js.map +1 -0
- package/dist/{chunk-EVUKJ7CJ.js → chunk-TTF5TDRV.js} +5 -5
- package/dist/{chunk-IAM4VIU2.js → chunk-UOIAY6ZG.js} +6 -39
- package/dist/chunk-UOIAY6ZG.js.map +1 -0
- package/dist/{chunk-6QBGTX2Q.js → chunk-V7TNYHIK.js} +257 -484
- package/dist/chunk-V7TNYHIK.js.map +1 -0
- package/dist/{chunk-OUYMZ5ZC.js → chunk-W3XWRWML.js} +5 -5
- package/dist/{client-3SE632Q2.js → client-C6N2ASTH.js} +3 -3
- package/dist/{eas-KMDAMLXW.js → eas-VFTWEI4K.js} +6 -6
- package/dist/{governor-JNSWPJVQ.js → governor-HVBSI6Z2.js} +6 -6
- package/dist/identity-OLD25QEP.js +18 -0
- package/dist/index.js +91 -305
- package/dist/index.js.map +1 -1
- package/dist/{network-FEHRFDPJ.js → network-7445KSCF.js} +2 -2
- package/dist/{price-YNPYE2EO.js → price-O3THX2HL.js} +6 -6
- package/dist/{providers-BMOHHVUN.js → providers-KZNCCUKT.js} +4 -4
- package/dist/{research-W74PNYPO.js → research-ARFBFXIT.js} +7 -7
- package/dist/{session-HVRZ6AJM.js → session-A7CYZSSA.js} +14 -12
- package/dist/session-A7CYZSSA.js.map +1 -0
- package/dist/{trade-EOQY72L7.js → trade-ZCK332E4.js} +15 -15
- package/dist/{vault-HWJQJW5U.js → vault-CDI7BELZ.js} +8 -8
- package/dist/{xmtp-KW73BGVO.js → xmtp-7LAWDKJT.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-3IAZQMAW.js.map +0 -1
- package/dist/chunk-6QBGTX2Q.js.map +0 -1
- package/dist/chunk-EA65CDQH.js.map +0 -1
- package/dist/chunk-F3MDCUGO.js.map +0 -1
- package/dist/chunk-IAM4VIU2.js.map +0 -1
- package/dist/chunk-PVTZMRC6.js.map +0 -1
- package/dist/chunk-QRMZRAMG.js.map +0 -1
- package/dist/chunk-YAS52NEF.js.map +0 -1
- package/dist/identity-ATWV2O7Y.js +0 -15
- package/dist/session-HVRZ6AJM.js.map +0 -1
- /package/dist/{abis-WVW2EBI3.js.map → abis-WJQ6IVYV.js.map} +0 -0
- /package/dist/{agent-TBLC3WNJ.js.map → agent-A2JEYGQS.js.map} +0 -0
- /package/dist/{chat-ETZSKQDI.js.map → chat-OZAAN5LT.js.map} +0 -0
- /package/dist/{chunk-ZN2MHIB7.js.map → chunk-37GT3TJX.js.map} +0 -0
- /package/dist/{chunk-45FELUWY.js.map → chunk-3UYGXGMF.js.map} +0 -0
- /package/dist/{chunk-XPVXNG2K.js.map → chunk-GR3GSU3I.js.map} +0 -0
- /package/dist/{chunk-KVB5P2OE.js.map → chunk-IINWI3LD.js.map} +0 -0
- /package/dist/{chunk-EVUKJ7CJ.js.map → chunk-TTF5TDRV.js.map} +0 -0
- /package/dist/{chunk-OUYMZ5ZC.js.map → chunk-W3XWRWML.js.map} +0 -0
- /package/dist/{client-3SE632Q2.js.map → client-C6N2ASTH.js.map} +0 -0
- /package/dist/{eas-KMDAMLXW.js.map → eas-VFTWEI4K.js.map} +0 -0
- /package/dist/{governor-JNSWPJVQ.js.map → governor-HVBSI6Z2.js.map} +0 -0
- /package/dist/{identity-ATWV2O7Y.js.map → identity-OLD25QEP.js.map} +0 -0
- /package/dist/{network-FEHRFDPJ.js.map → network-7445KSCF.js.map} +0 -0
- /package/dist/{price-YNPYE2EO.js.map → price-O3THX2HL.js.map} +0 -0
- /package/dist/{providers-BMOHHVUN.js.map → providers-KZNCCUKT.js.map} +0 -0
- /package/dist/{research-W74PNYPO.js.map → research-ARFBFXIT.js.map} +0 -0
- /package/dist/{trade-EOQY72L7.js.map → trade-ZCK332E4.js.map} +0 -0
- /package/dist/{vault-HWJQJW5U.js.map → vault-CDI7BELZ.js.map} +0 -0
- /package/dist/{xmtp-KW73BGVO.js.map → xmtp-7LAWDKJT.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/addresses.ts","../src/lib/address-overrides.ts","../src/lib/fork-tokens.ts"],"sourcesContent":["/**\n * Contract addresses by network.\n *\n * All exports are functions — they resolve at call time based on the\n * current network set via setNetwork(). This ensures --chain works\n * even when modules are imported before the flag is parsed.\n *\n * Current deployment target: Robinhood L2 testnet (chain 46630) only. Other\n * chains may be added back later; when they are, their address blocks + registry\n * entries re-enter here alongside the robinhood-testnet ones.\n *\n * Zero addresses = protocol not deployed on that chain. Strategies that\n * need them will fail at execution time with a clear allowlist error.\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { isAddress } from \"viem\";\nimport { type Network, getNetwork } from \"./network.js\";\nimport { overridesFor } from \"./address-overrides.js\";\nimport { forkStockAddresses, forkStockFeeds } from \"./fork-tokens.js\";\n\nconst ZERO: Address = \"0x0000000000000000000000000000000000000000\";\nconst ZERO_BYTES32 =\n \"0x0000000000000000000000000000000000000000000000000000000000000000\" as `0x${string}`;\n\n// ── Robinhood L2 Testnet (Arbitrum Orbit, chain 46630) ──\n// Synthra DEX for swaps. Stock tokens available.\n\nconst ROBINHOOD_TESTNET_TOKENS = {\n USDC: ZERO,\n // USDG (Robinhood-chain stablecoin, 6-dec). Zero on testnet (Synthra WETH-quoted);\n // real on the mainnet fork. Keyed so `--asset USDG` resolves + decimals=6.\n USDG: ZERO,\n // WETH resolves to Synthra's WETH9 (SYNTHRA_WETH): ALL stock DEX liquidity is\n // denominated in it (e.g. the TSLA fee-3000 pool holds ~37.8 WETH here vs\n // ~0.0003 in the canonical WETH pool). It is WETH9-style (payable deposit()),\n // so --use-eth wrapping works against it. Canonical WETH kept as WETH_CANONICAL\n // so the reference isn't lost.\n WETH: \"0x33e4191705c386532ba27cBF171Db86919200B94\" as Address,\n WETH_CANONICAL: \"0x7943e237c7F95DA44E0301572D358911207852Fa\" as Address,\n cbETH: ZERO,\n wstETH: ZERO,\n cbBTC: ZERO,\n DAI: ZERO,\n AERO: ZERO,\n TSLA: \"0xC9f9c86933092BbbfFF3CCb4b105A4A94bf3Bd4E\" as Address,\n AMZN: \"0x5884aD2f920c162CFBbACc88C9C51AA75eC09E02\" as Address,\n PLTR: \"0x1FBE1a0e43594b3455993B5dE5Fd0A7A266298d0\" as Address,\n NFLX: \"0x3b8262A63d25f0477c4DDE23F83cfe22Cb768C93\" as Address,\n AMD: \"0x71178BAc73cBeb415514eB542a8995b82669778d\" as Address,\n // Stocks the mainnet fork carries and the testnet does not (lib/fork-tokens.ts).\n // Keyed here as ZERO so the token-shape type covers both chains.\n AAPL: ZERO,\n NVDA: ZERO,\n MSFT: ZERO,\n META: ZERO,\n SPY: ZERO,\n QQQ: ZERO,\n SLV: ZERO,\n GOOGL: ZERO,\n} as const;\n\nconst ROBINHOOD_TESTNET_MOONWELL = {\n COMPTROLLER: ZERO,\n mUSDC: ZERO,\n mWETH: ZERO,\n mCbETH: ZERO,\n mWstETH: ZERO,\n mCbBTC: ZERO,\n mDAI: ZERO,\n mAERO: ZERO,\n} as const;\n\n// Synthra is Uniswap-V3-compatible; the deployed UniswapSwapAdapter is backed by\n// Synthra's router + a QuoterV2 shim (SYNTHRA_QUOTER_V2_SHIM). SWAP_ROUTER /\n// QUOTER_V2 mirror the Synthra addresses so a direct v3 quote path also resolves.\nconst ROBINHOOD_TESTNET_UNISWAP = {\n SWAP_ROUTER: \"0x3Ce954107b1A675826B33bF23060Dd655e3758fE\" as Address,\n QUOTER_V2: \"0xb06788F027268a9A06c3AD41a88559530D2E54b1\" as Address,\n SWAP_ADAPTER: \"0x4fc3492117cC3bbcE0b210D22a8DC244f9d86490\" as Address,\n} as const;\n\n// ── Synthra DEX (Robinhood L2 — Uniswap V3-compatible concentrated liquidity) ──\n\nconst ROBINHOOD_TESTNET_SYNTHRA = {\n ROUTER: \"0x3Ce954107b1A675826B33bF23060Dd655e3758fE\" as Address,\n QUOTER: \"0x231606c321A99DE81e28fE48B07a93F1ba49e713\" as Address,\n FACTORY: \"0x911b4000D3422F482F4062a913885f7b035382Df\" as Address,\n} as const;\n\n// ── Chainlink (Data Streams verifier proxy + AggregatorV3 feeds) ──\n\nconst ROBINHOOD_TESTNET_CHAINLINK = {\n VERIFIER_PROXY: \"0x72790f9eB82db492a7DDb6d2af22A270Dcc3Db64\" as Address,\n WSTETH_ETH_FEED: ZERO,\n // Tokenized-equity push feeds exist only on the mainnet fork (Data-Streams\n // mode here). Keyed as ZERO so the registry shape covers both chains and the\n // fork's `<SYM>_USD_FEED` auto-resolve (template-encoder.ts) has a slot.\n ...noneOf(forkStockFeeds()),\n} as const;\n\n// ── Robinhood portfolio-basket route + feed metadata ──\n//\n// Data-driven replacement for the hand-drifting \"known stock\" Set that used to\n// live in strategy-template.ts. Every entry is a VERIFIED-liquidity default\n// swap route for a basket token. Absence from this map means \"no verified\n// default route\" — the CLI fails fast and demands an explicit --swap-routes\n// rather than falling through to a v3 auto-detect that would be dead.\n//\n// `kind: \"v4-native\"` = a Uniswap v4 mode-3 multi-hop USDG → native ETH → stock,\n// consumed by portfolio-template.ts as\n// v4PathExtraData([{currency: ETH, ...native}, {currency: <token>, ...stock}]).\nexport interface RobinhoodStockRoute {\n kind: \"v4-native\";\n nativeFee: number;\n nativeTickSpacing: number;\n stockFee: number;\n stockTickSpacing: number;\n}\n\n// No verified default stock swap routes on the Robinhood testnet — the machinery\n// is retained (see robinhoodEquityMaxAge / portfolio-template.ts) but the map is\n// empty, so every basket token falls to the existing fail-fast route error until\n// a verified route is added.\n// LOCKSTEP: the app's quote-probe geometry (app/src/lib/price-quote.ts\n// V4_DIRECT_TIERS + via-native path) must stay consistent with any route added\n// here, or the dashboard displays a tier the strategy won't execute.\nexport const ROBINHOOD_STOCK_ROUTES: Record<string, RobinhoodStockRoute> = {};\n\n// Chainlink push-feed classification. Every `*_USD_FEED` is an EQUITY feed\n// (needs the extended 96h max-price-age over holiday weekends) EXCEPT these —\n// crypto/FX/stable feeds keep the contract default (26h). Encoded here (not an\n// inline list in the command) so route/feed metadata lives in one registry.\n//\n// WETH is listed alongside ETH because feed auto-resolve normalizes WETH →\n// ETH_USD_FEED (there is no WETH_USD_FEED — the two share the 24h crypto feed).\n// The classification helper below MUST agree with that normalization for every\n// symbol the feed-resolution path accepts, or a WETH allocation packs the 96h\n// equity max-age onto a 24h crypto feed and accepts ~4-day-stale ETH prices.\nexport const ROBINHOOD_NON_EQUITY_FEEDS = new Set([\"ETH\", \"WETH\", \"BTC\", \"LINK\", \"USDG\", \"USDC\"]);\n\n/** True if `symbol`'s Robinhood push feed is a tokenized-equity feed. */\nexport function isRobinhoodEquityFeed(symbol: string): boolean {\n return !ROBINHOOD_NON_EQUITY_FEEDS.has(symbol.toUpperCase());\n}\n\n/**\n * Reverse-lookup a token address against a `TOKENS()` registry to recover its\n * symbol (case-insensitive). Returns undefined for the zero address or an\n * address that isn't registered. Used so a raw-address token spec can still be\n * classified as an equity feed (→ 96h max-price-age) the same way a symbol spec\n * is — otherwise a stock token passed by address silently falls back to the\n * contract's 26h default and trips `StalePrice` over long weekends.\n */\nexport function symbolForTokenAddress(\n address: string,\n tokens: Record<string, Address>,\n): string | undefined {\n if (!address || address.toLowerCase() === ZERO.toLowerCase()) return undefined;\n const want = address.toLowerCase();\n for (const [symbol, addr] of Object.entries(tokens)) {\n if (addr && addr !== ZERO && addr.toLowerCase() === want) return symbol;\n }\n return undefined;\n}\n\n/**\n * Resolve the equity max-price-age (seconds) for a Robinhood push-feed token\n * spec, which may be a SYMBOL or a raw 0x address. Returns the 96h equity\n * default for equity feeds, 0 (contract default) for crypto/stable feeds, and\n * `{ maxPriceAge: 0, unknownAddress: true }` when a raw address isn't in the\n * registry (caller should warn — we can't classify what we can't identify).\n *\n * `equityMaxAgeSeconds` is injected (from the portfolio builder's\n * EQUITY_MAX_PRICE_AGE_SECONDS) to avoid a cross-module import cycle.\n */\nexport function robinhoodEquityMaxAge(\n tokenSpec: string,\n tokens: Record<string, Address>,\n equityMaxAgeSeconds: number,\n): { maxPriceAge: number; unknownAddress: boolean } {\n let symbol: string | undefined;\n if (isAddress(tokenSpec)) {\n symbol = symbolForTokenAddress(tokenSpec, tokens);\n if (!symbol) return { maxPriceAge: 0, unknownAddress: true };\n } else {\n symbol = tokenSpec;\n }\n return {\n maxPriceAge: isRobinhoodEquityFeed(symbol) ? equityMaxAgeSeconds : 0,\n unknownAddress: false,\n };\n}\n\nconst ROBINHOOD_TESTNET_INFRA = {\n MULTICALL3: \"0xcA11bde05977b3631167028862bE2a173976CA11\" as Address, // Deterministic, same everywhere\n} as const;\n\n// ── ENS / Durin ──\n\nconst ROBINHOOD_TESTNET_ENS = {\n L2_REGISTRAR: ZERO,\n L2_REGISTRY: ZERO,\n} as const;\n\n// ── ERC-8004 Agent Identity ──\n\nconst ROBINHOOD_TESTNET_AGENT_REGISTRY = {\n IDENTITY_REGISTRY: ZERO,\n REPUTATION_REGISTRY: ZERO,\n} as const;\n\n// ── Sherwood Protocol (our deployed contracts) ──\n//\n// V2 redeploy (chain 46630): fresh factory/governor/vault-impl/executor plus a\n// full guardian layer (registry + sWOOD + WOOD fixture token) and the V2\n// live-NAV surface (PriceRouter, UniswapSwapAdapter via the Synthra QuoterV2\n// shim, Portfolio template, StrategyFactory). WOOD_TOKEN here is a testnet\n// fixture, not the mainnet OFT.\n//\n// GOVERNOR is the deploy-time bootstrap governor. Governors are per-vault since\n// PR #421 — resolve one at runtime via `factory.governorOf(vault)`\n// (lib/governor.ts `getGovernorOf`), never from this table.\n// Key parity with the SDK book (sdk/src/addresses.ts SherwoodDeployment) is\n// pinned by lib/address-parity.test.ts — add new keys to BOTH books.\nconst ROBINHOOD_TESTNET_SHERWOOD = {\n FACTORY: \"0xa91AA45AFF32f52b6357044B02a16EBA775feC0b\" as Address,\n GOVERNOR: ZERO, // zeroed since the post-#421 redeploy — always factory.governorOf(vault)\n GUARDIAN_REGISTRY: \"0xA400eFcfFc820C6f812203C58ee00423AeCC0903\" as Address,\n STAKED_WOOD: \"0x21A69A6c9814c0d339C57fDdafed3B283702a739\" as Address,\n WOOD_TOKEN: \"0xCCb4fB59cf40de1E23083037ee81Da1DD747D8d7\" as Address,\n STRATEGY_FACTORY: \"0xb683Bb8EEcBc2419BC3801df6FeA88f96657e670\" as Address,\n MERKL_DISTRIBUTOR: ZERO,\n // Guardian-era contracts from contracts/chains/46630.json (SHE-93).\n VAULT_IMPL: \"0xC57e12d6e2d8Ed49316F0b69c51893CcA44151F7\" as Address,\n BATCH_EXECUTOR_LIB: \"0xF3b8db5aa41c7Ce92478A0Fa9C55a6460533eb86\" as Address,\n GOVERNOR_BEACON: \"0x3D46Ec018cd5893b685b4dfdc3921A4Eb64E11d1\" as Address,\n PROTOCOL_CONFIG: \"0xC104Eb6a522d6718cA28F344B2373B29d57FF2E0\" as Address,\n PRICE_ROUTER: \"0xDd302ffcfA08071780eC1A2f12BccFB9ba6b6731\" as Address,\n TIER_REGISTRY: \"0x99b8068Dc0F6093466964D581f72d947e3e380DB\" as Address,\n CALL_SANDBOX_IMPL: \"0xf09f6AF7DeBB964eD731376C9Af389F2Ce3d872A\" as Address,\n // Not in chains/46630.json (econ-security stack not deployed there yet).\n EXPOSURE_LEDGER: ZERO,\n PROPOSER_BOND_ESCROW: ZERO,\n CHALLENGE_GAME: ZERO,\n TOKEN_COURT: ZERO,\n} as const;\n\n// ── Venice (VVV governance + sVVV staking + DIEM compute) ──\n\nconst ROBINHOOD_TESTNET_VENICE = {\n VVV: ZERO,\n STAKING: ZERO,\n DIEM: ZERO,\n} as const;\n\n// ── Aerodrome (Base ve(3,3) DEX) ──\n\nconst ROBINHOOD_TESTNET_AERODROME = {\n ROUTER: ZERO,\n FACTORY: ZERO,\n} as const;\n\n// ── Strategy Templates (ERC-1167 clonable singletons) ──\n// Populated after running script/DeployTemplates.s.sol\n\nconst ROBINHOOD_TESTNET_STRATEGY_TEMPLATES = {\n MOONWELL_SUPPLY: ZERO as Address,\n AERODROME_LP: ZERO as Address,\n VENICE_INFERENCE: ZERO as Address,\n WSTETH_MOONWELL: ZERO as Address,\n MAMO_YIELD: ZERO as Address,\n HYPERLIQUID_PERP: ZERO as Address,\n HYPERLIQUID_GRID: ZERO as Address,\n // V2 redeploy PORTFOLIO_TEMPLATE (chain 46630).\n PORTFOLIO: \"0x67420Cc504d70a42Adfd8867d878afe0978C7d10\" as Address,\n} as const;\n\n// ── EAS (Ethereum Attestation Service) ──\n\nconst ROBINHOOD_TESTNET_EAS = {\n EAS: ZERO,\n SCHEMA_REGISTRY: ZERO,\n} as const;\n\n// EAS on Robinhood Chain mainnet (4663). Deployed by Sherwood — EAS is not a\n// predeploy on an Arbitrum Orbit chain. sherwoodagent/sherwood-protocol#278.\nconst ROBINHOOD_MAINNET_EAS = {\n EAS: \"0x7d70441Bb10AcE5d9771dc0b6205D89ddf63205B\" as Address,\n SCHEMA_REGISTRY: \"0xdd7521Ba10773e556Defa6D6c133cB2F663b5c26\" as Address,\n} as const;\n\n/**\n * Schema UIDs are chain-INDEPENDENT: uid = keccak256(schema, resolver,\n * revocable) carries no chainId. With resolver = address(0) these are the same\n * UIDs already registered on Base, and re-registering the same definitions on\n * any chain reproduces them. Verified against Base's live SchemaRegistry.\n */\nconst SHERWOOD_EAS_SCHEMAS = {\n SYNDICATE_JOIN_REQUEST: \"0x1e7ce17b16233977ba913b156033e98f52029f4bee273a4abefe6c15ce11d5ef\" as Hex,\n AGENT_APPROVED: \"0x1013f7b38f433b2a93fc5ac162482813081c64edd67cea9b5a90698531ddb607\" as Hex,\n X402_RESEARCH: \"0x86c67f0a59acb3093ecbeb6c4d1d4352e4a48143672e92ef9dd2fdfc8a9ca708\" as Hex,\n VENICE_PROVISION: \"0x76d4d6baa72307826cd2fd4ce069bb42ee54cdda6ed6ab208c8d233c893fb7f1\" as Hex,\n VENICE_INFERENCE: \"0xf9b4e530f3016c19439b67372a1c213c9339857627fb817032614b97433a2a14\" as Hex,\n TRADE_EXECUTED: \"0x06bb488363a468f7f857ddc8cfffe918d048b8746a0d59eca9cd7f58dbdb4af6\" as Hex,\n} as const;\n\n/**\n * Every non-EAS address book, for the coordination chain. Sherwood core is not\n * deployed on 4663, so these are all zero BY CONSTRUCTION rather than by\n * omission — mapping them to the testnet book would silently hand out 46630\n * addresses during the brief `withNetwork` window an EAS write opens.\n */\nfunction noneOf<T extends Record<string, unknown>>(shape: T): T {\n return Object.fromEntries(Object.keys(shape).map((k) => [k, ZERO])) as T;\n}\n\n// ── EAS Schema UIDs (populated after running scripts/register-eas-schemas.ts) ──\n\nconst ROBINHOOD_TESTNET_EAS_SCHEMAS = {\n SYNDICATE_JOIN_REQUEST: ZERO_BYTES32,\n AGENT_APPROVED: ZERO_BYTES32,\n X402_RESEARCH: ZERO_BYTES32,\n VENICE_PROVISION: ZERO_BYTES32,\n VENICE_INFERENCE: ZERO_BYTES32,\n TRADE_EXECUTED: ZERO_BYTES32,\n} as const;\n\n// ── Robinhood Chain mainnet fork (Tenderly vnet, chain 9994663) ──\n//\n// Fork of Robinhood *mainnet*: USDG stablecoin (6-dec), official Uniswap v3+v4,\n// Chainlink PUSH feeds. VERIFIER_PROXY = 0 makes PortfolioStrategy run in\n// push-feed mode (feedIds are AggregatorV3 proxy addresses). Core addresses\n// come from sherwood-protocol/chains/9994663.json (fresh deploy). All 11\n// tokenized stocks + their feeds come from lib/fork-tokens.ts (one table, with\n// the measured swap route per token); the feeds are keyed here as\n// `<SYM>_USD_FEED` so a symbol basket auto-resolves its push feed on the fork.\n// Swap routes still need an explicit --swap-routes (ROBINHOOD_STOCK_ROUTES is\n// a different shape and lockstepped with the app's quote probe).\n\nconst ROBINHOOD_FORK_TOKENS: typeof ROBINHOOD_TESTNET_TOKENS = {\n USDC: ZERO,\n USDG: \"0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168\" as Address,\n WETH: \"0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73\" as Address,\n WETH_CANONICAL: \"0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73\" as Address,\n cbETH: ZERO,\n wstETH: ZERO,\n cbBTC: ZERO,\n DAI: ZERO,\n AERO: ZERO,\n PLTR: ZERO,\n NFLX: ZERO,\n ...forkStockAddresses(),\n};\n\nconst ROBINHOOD_FORK_UNISWAP: typeof ROBINHOOD_TESTNET_UNISWAP = {\n SWAP_ROUTER: \"0xcaf681a66d020601342297493863e78c959e5cb2\" as Address,\n QUOTER_V2: \"0x33e885ed0ec9bf04ecfb19341582aadcb4c8a9e7\" as Address,\n SWAP_ADAPTER: \"0x54E6A7af53143556973493fDeC9d7837A77c67eF\" as Address,\n};\n\n// VERIFIER_PROXY = 0 ⇒ PortfolioStrategy push-feed mode (Robinhood-mainnet-style).\n// `<SYM>_USD_FEED` for all 11 stocks so `strategy propose portfolio --tokens\n// AAPL,…` resolves feeds without --feed-ids (template-encoder.ts push mode).\nconst ROBINHOOD_FORK_CHAINLINK: typeof ROBINHOOD_TESTNET_CHAINLINK = {\n VERIFIER_PROXY: ZERO,\n WSTETH_ETH_FEED: ZERO,\n ...forkStockFeeds(),\n};\n\nconst ROBINHOOD_FORK_SHERWOOD: typeof ROBINHOOD_TESTNET_SHERWOOD = {\n FACTORY: \"0x619af1488F32B4797f6faDa3C3a8De72a5B693E0\" as Address,\n GOVERNOR: ZERO, // per-vault — always factory.governorOf(vault)\n GUARDIAN_REGISTRY: \"0xD8F9E7446E6d6c02198AAaF674A0C5e3d5D1BF72\" as Address,\n STAKED_WOOD: \"0xdDf2B4C52B9575e0e6D03a3A57D75D06a4a9e203\" as Address,\n WOOD_TOKEN: \"0xF8BC08092C06dB6148114DCf82AF881F1085f92b\" as Address,\n STRATEGY_FACTORY: \"0xb06788F027268a9A06c3AD41a88559530D2E54b1\" as Address,\n MERKL_DISTRIBUTOR: ZERO,\n // Guardian-era contracts from sherwood-protocol/chains/9994663.json (SHE-93).\n VAULT_IMPL: \"0xdaB4707c9997a84e931FE98F4688adaFc70b6B95\" as Address,\n BATCH_EXECUTOR_LIB: \"0x899FC2Cac572F64A233344115b488E71E0044f34\" as Address,\n GOVERNOR_BEACON: \"0x3CF45eFE9fBDdd6cB749384Bf5c1bA5Ec96af05d\" as Address,\n PROTOCOL_CONFIG: \"0x8aDb5810B5bF8B9149BE3Ca45Cb441818a9679bB\" as Address,\n // Not in chains/9994663.json (no PriceRouter / CallSandbox on the fork).\n PRICE_ROUTER: ZERO,\n TIER_REGISTRY: \"0x4614f058920941A0a9a852e62485fbDE692D75E1\" as Address,\n CALL_SANDBOX_IMPL: ZERO,\n EXPOSURE_LEDGER: \"0x99D789E7C8E65dB5597dCa692F082B47BE30AB33\" as Address,\n PROPOSER_BOND_ESCROW: \"0x7d25058c891d3AC5C8bc8Da6aA937DFeE648B5cF\" as Address,\n CHALLENGE_GAME: \"0x7046FececcA6c0f5E66Cc998099593ae71A1bbee\" as Address,\n TOKEN_COURT: \"0xC30bA62727be65fd867385Ce27Ff7C78bd66A897\" as Address,\n};\n\nconst ROBINHOOD_FORK_STRATEGY_TEMPLATES: typeof ROBINHOOD_TESTNET_STRATEGY_TEMPLATES = {\n MOONWELL_SUPPLY: ZERO,\n AERODROME_LP: ZERO,\n VENICE_INFERENCE: ZERO,\n WSTETH_MOONWELL: ZERO,\n MAMO_YIELD: ZERO,\n HYPERLIQUID_PERP: ZERO,\n HYPERLIQUID_GRID: ZERO,\n PORTFOLIO: \"0xAA5872009c527cCb80343E41C52840CEdb095eb0\" as Address,\n};\n\n// ── Registries (map-based lookup) ──\n\nconst TOKEN_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_TOKENS> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_TOKENS,\n \"robinhood-fork\": ROBINHOOD_FORK_TOKENS,\n \"robinhood-mainnet\": noneOf(ROBINHOOD_TESTNET_TOKENS), // coordination chain — no Sherwood contracts\n};\n\nconst MOONWELL_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_MOONWELL> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_MOONWELL,\n \"robinhood-fork\": ROBINHOOD_TESTNET_MOONWELL,\n \"robinhood-mainnet\": noneOf(ROBINHOOD_TESTNET_MOONWELL), // coordination chain — no Sherwood contracts\n};\n\nconst UNISWAP_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_UNISWAP> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_UNISWAP,\n \"robinhood-fork\": ROBINHOOD_FORK_UNISWAP,\n \"robinhood-mainnet\": noneOf(ROBINHOOD_TESTNET_UNISWAP), // coordination chain — no Sherwood contracts\n};\n\nconst INFRA_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_INFRA> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_INFRA,\n \"robinhood-fork\": ROBINHOOD_TESTNET_INFRA,\n \"robinhood-mainnet\": noneOf(ROBINHOOD_TESTNET_INFRA), // coordination chain — no Sherwood contracts\n};\n\nconst ENS_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_ENS> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_ENS,\n \"robinhood-fork\": ROBINHOOD_TESTNET_ENS,\n \"robinhood-mainnet\": noneOf(ROBINHOOD_TESTNET_ENS), // coordination chain — no Sherwood contracts\n};\n\n// Canonical ERC-8004 registries ARE live on 4663 (verified on-chain). Like\n// EAS, identity coordinates there: mint/load/lookup run against the\n// coordination chain regardless of the fund chain, so testnet/fork stay zero.\nconst ROBINHOOD_MAINNET_AGENT_REGISTRY = {\n IDENTITY_REGISTRY: \"0x8004A169FB4a3325136EB29fA0ceB6D2e539a432\" as Address,\n REPUTATION_REGISTRY: \"0x8004BAa17C55a88189AE136b182e5fdA19dE9b63\" as Address,\n} as const;\n\nconst AGENT_REGISTRY_MAP: Record<Network, typeof ROBINHOOD_TESTNET_AGENT_REGISTRY> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_AGENT_REGISTRY,\n \"robinhood-fork\": ROBINHOOD_TESTNET_AGENT_REGISTRY,\n \"robinhood-mainnet\": ROBINHOOD_MAINNET_AGENT_REGISTRY,\n};\n\nconst SHERWOOD_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_SHERWOOD> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_SHERWOOD,\n \"robinhood-fork\": ROBINHOOD_FORK_SHERWOOD,\n \"robinhood-mainnet\": noneOf(ROBINHOOD_TESTNET_SHERWOOD), // coordination chain — no Sherwood contracts\n};\n\nconst VENICE_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_VENICE> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_VENICE,\n \"robinhood-fork\": ROBINHOOD_TESTNET_VENICE,\n \"robinhood-mainnet\": noneOf(ROBINHOOD_TESTNET_VENICE), // coordination chain — no Sherwood contracts\n};\n\nconst AERODROME_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_AERODROME> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_AERODROME,\n \"robinhood-fork\": ROBINHOOD_TESTNET_AERODROME,\n \"robinhood-mainnet\": noneOf(ROBINHOOD_TESTNET_AERODROME), // coordination chain — no Sherwood contracts\n};\n\nconst STRATEGY_TEMPLATE_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_STRATEGY_TEMPLATES> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_STRATEGY_TEMPLATES,\n \"robinhood-fork\": ROBINHOOD_FORK_STRATEGY_TEMPLATES,\n \"robinhood-mainnet\": noneOf(ROBINHOOD_TESTNET_STRATEGY_TEMPLATES), // coordination chain — no Sherwood contracts\n};\n\nconst SYNTHRA_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_SYNTHRA> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_SYNTHRA,\n \"robinhood-fork\": ROBINHOOD_TESTNET_SYNTHRA, // unused on the fork (Uniswap, not Synthra)\n \"robinhood-mainnet\": noneOf(ROBINHOOD_TESTNET_SYNTHRA), // coordination chain — no Sherwood contracts\n};\n\nconst CHAINLINK_REGISTRY: Record<Network, typeof ROBINHOOD_TESTNET_CHAINLINK> = {\n \"robinhood-testnet\": ROBINHOOD_TESTNET_CHAINLINK,\n \"robinhood-fork\": ROBINHOOD_FORK_CHAINLINK,\n \"robinhood-mainnet\": noneOf(ROBINHOOD_TESTNET_CHAINLINK), // coordination chain — no Sherwood contracts\n};\n\n// Attestations live on chain 4663 no matter which chain the fund is on,\n// so every network resolves to the same book (spec §5.1).\nconst EAS_CONTRACT_REGISTRY: Record<Network, typeof ROBINHOOD_MAINNET_EAS> = {\n \"robinhood-testnet\": ROBINHOOD_MAINNET_EAS,\n \"robinhood-fork\": ROBINHOOD_MAINNET_EAS,\n \"robinhood-mainnet\": ROBINHOOD_MAINNET_EAS,\n};\n\n// Attestations live on chain 4663 no matter which chain the fund is on,\n// so every network resolves to the same book (spec §5.1).\nconst EAS_SCHEMA_REGISTRY: Record<Network, typeof SHERWOOD_EAS_SCHEMAS> = {\n \"robinhood-testnet\": SHERWOOD_EAS_SCHEMAS,\n \"robinhood-fork\": SHERWOOD_EAS_SCHEMAS,\n \"robinhood-mainnet\": SHERWOOD_EAS_SCHEMAS,\n};\n\n// ── Exports (functions, resolved at call time) ──\n\nexport function TOKENS() {\n return TOKEN_REGISTRY[getNetwork()];\n}\n\nexport function MOONWELL() {\n return MOONWELL_REGISTRY[getNetwork()];\n}\n\nexport function UNISWAP() {\n return { ...UNISWAP_REGISTRY[getNetwork()], ...overridesFor(\"UNISWAP\") };\n}\n\nexport function INFRA() {\n return INFRA_REGISTRY[getNetwork()];\n}\n\nexport function ENS() {\n return { ...ENS_REGISTRY[getNetwork()], ...overridesFor(\"ENS\") };\n}\n\nexport function AGENT_REGISTRY() {\n return AGENT_REGISTRY_MAP[getNetwork()];\n}\n\nexport function VENICE() {\n return VENICE_REGISTRY[getNetwork()];\n}\n\nexport function SHERWOOD() {\n return { ...SHERWOOD_REGISTRY[getNetwork()], ...overridesFor(\"SHERWOOD\") };\n}\n\nexport function AERODROME() {\n return AERODROME_REGISTRY[getNetwork()];\n}\n\nexport function STRATEGY_TEMPLATES() {\n return {\n ...STRATEGY_TEMPLATE_REGISTRY[getNetwork()],\n ...overridesFor(\"STRATEGY_TEMPLATES\"),\n };\n}\n\nexport function EAS_CONTRACTS() {\n return EAS_CONTRACT_REGISTRY[getNetwork()];\n}\n\nexport function EAS_SCHEMAS() {\n return EAS_SCHEMA_REGISTRY[getNetwork()];\n}\n\nexport function SYNTHRA() {\n return SYNTHRA_REGISTRY[getNetwork()];\n}\n\nexport function CHAINLINK() {\n return CHAINLINK_REGISTRY[getNetwork()];\n}\n","/**\n * SIM_ADDRESSES_FILE override layer (spec G1).\n *\n * Points the CLI at a vnet deployment: a chains/{chainId}.json-shaped file\n * (CAPS_SNAKE_CASE keys, written by contracts deploy scripts) is mapped onto\n * the CLI's per-registry key names and merged over the base network registry\n * at call time. Only 0x-string values are considered. Fail-closed: a set-but-\n * unreadable file throws rather than silently using mainnet addresses.\n */\nimport { readFileSync } from \"node:fs\";\nimport type { Address } from \"viem\";\n\ntype RegistryName = \"SHERWOOD\" | \"STRATEGY_TEMPLATES\" | \"ENS\" | \"UNISWAP\";\n\n// chains-json key → CLI registry key, grouped by target registry.\n// Extend when deploy scripts gain keys the CLI reads (Task 1 Step 2).\n//\n// STRATEGY_TEMPLATES note (Task 1 Step 2 finding): the deploy scripts\n// (DeployTemplates.s.sol / DeployStrategyFactory.s.sol) write chains.json\n// keys with a `_TEMPLATE` suffix (e.g. `MOONWELL_SUPPLY_TEMPLATE`), but the\n// CLI-side STRATEGY_TEMPLATES() registry (cli/src/lib/addresses.ts\n// `BASE_STRATEGY_TEMPLATES`) and its consumers (e.g.\n// cli/src/commands/strategy-template.ts `addressKey: \"MOONWELL_SUPPLY\"`) key\n// off the UNSUFFIXED name. The map below strips the suffix so overrides\n// actually reach the keys the CLI reads.\nconst CHAINS_TO_CLI: Record<RegistryName, Record<string, string>> = {\n SHERWOOD: {\n SYNDICATE_FACTORY: \"FACTORY\",\n SYNDICATE_GOVERNOR: \"GOVERNOR\",\n GUARDIAN_REGISTRY: \"GUARDIAN_REGISTRY\",\n STAKED_WOOD: \"STAKED_WOOD\",\n WOOD: \"WOOD_TOKEN\",\n WOOD_TOKEN: \"WOOD_TOKEN\",\n STRATEGY_FACTORY: \"STRATEGY_FACTORY\",\n },\n STRATEGY_TEMPLATES: {\n MOONWELL_SUPPLY_TEMPLATE: \"MOONWELL_SUPPLY\",\n AERODROME_LP_TEMPLATE: \"AERODROME_LP\",\n VENICE_INFERENCE_TEMPLATE: \"VENICE_INFERENCE\",\n WSTETH_MOONWELL_TEMPLATE: \"WSTETH_MOONWELL\",\n MAMO_YIELD_TEMPLATE: \"MAMO_YIELD\",\n PORTFOLIO_TEMPLATE: \"PORTFOLIO\",\n HYPERLIQUID_PERP_TEMPLATE: \"HYPERLIQUID_PERP\",\n HYPERLIQUID_GRID_TEMPLATE: \"HYPERLIQUID_GRID\",\n },\n ENS: {\n L2_REGISTRAR: \"L2_REGISTRAR\",\n L2_REGISTRY: \"L2_REGISTRY\",\n },\n UNISWAP: {\n UNISWAP_SWAP_ADAPTER: \"SWAP_ADAPTER\",\n },\n};\n\nlet cached: Record<string, Address> | null | undefined;\n\nfunction loadFile(): Record<string, Address> | null {\n if (cached !== undefined) return cached;\n const file = process.env.SIM_ADDRESSES_FILE;\n if (!file) {\n cached = null;\n return cached;\n }\n let raw: Record<string, unknown>;\n try {\n raw = JSON.parse(readFileSync(file, \"utf8\")) as Record<string, unknown>;\n } catch (err) {\n throw new Error(\n `SIM_ADDRESSES_FILE is set (${file}) but unreadable: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n const out: Record<string, Address> = {};\n for (const [k, v] of Object.entries(raw)) {\n if (typeof v === \"string\" && v.startsWith(\"0x\")) out[k] = v as Address;\n }\n cached = out;\n return cached;\n}\n\n/** Mapped overrides for one CLI registry; {} when SIM_ADDRESSES_FILE unset. */\nexport function overridesFor(registry: RegistryName): Record<string, Address> {\n const file = loadFile();\n if (!file) return {};\n const map = CHAINS_TO_CLI[registry];\n const out: Record<string, Address> = {};\n for (const [chainsKey, cliKey] of Object.entries(map)) {\n if (file[chainsKey]) out[cliKey] = file[chainsKey];\n }\n return out;\n}\n\nexport function __resetOverridesCacheForTests(): void {\n cached = undefined;\n}\n","/**\n * Robinhood mainnet fork (Tenderly vnet, chain 9994663) — tokenized-stock map.\n *\n * ONE table for every stock the fork address book carries\n * (sherwood-protocol/chains/9994663.json): token address, its Chainlink USD\n * push feed, and the swap route the fork's Uniswap deployment ACTUALLY quotes\n * for USDG -> stock. `addresses.ts` derives `ROBINHOOD_FORK_TOKENS` and the\n * fork's `<SYM>_USD_FEED` registry from here; the sim's basket builder\n * (`simulation/proposal-specs.ts`) reads feed + route from here.\n *\n * THE ROUTES ARE MEASURED, NOT GUESSED. Every entry below was quoted\n * read-only against the fork's V4Quoter (0x8dc178ef…) and, where v4 had no\n * pool, the v3 QuoterV2 (0x33e885ed…), at 100 USDG on 2026-09-05 (vnet block\n * 21,179,183), and cross-checked against the token's own Chainlink feed. The\n * per-entry `quotedOut` / `feedDeviationBps` fields are that measurement.\n * Tiers probed: v4 3000/60, 10000/200, 500/10, 100/1; v3 500, 3000, 10000.\n *\n * `eligible` is the sim's basket-generation gate, and it is stricter than\n * \"quotes\": PortfolioStrategy floors every buy at the ORACLE-implied amount\n * discounted by maxSlippageBps (`_buyFloor`, push-feed mode), so a pool whose\n * price sits further above the frozen feed than the sim's 5% tolerance\n * executes to a revert no matter how well it quotes. That is META today\n * (+8.3%). SLV is the other exclusion: it has NO v4 pool on any tier and only\n * quotes on v3, and this vnet's v3 position manager is known-corrupted\n * (state-injected token ids), so the v3 leg is unverified end to end. Both\n * stay in the map with their measured route so an explicit\n * `--tokens META --swap-routes v4:3000:60 --max-slippage 1000` still works;\n * they are just not handed to the sim by default.\n *\n * Re-quote before trusting any of this on a fresh fork — the vnet's pools are\n * traded by every sim run and the feeds are frozen at fork time.\n */\n\nimport type { Address } from \"viem\";\n\nexport interface ForkStock {\n /** Tokenized-stock ERC-20 on the fork (18-dec). */\n address: Address;\n /** Chainlink AggregatorV3 USD feed (8-dec) for the same stock. */\n feed: Address;\n /**\n * Swap-route spec in `--swap-routes` syntax (`v4:<fee>:<tickSpacing>` or\n * `v3:<fee>`), or null when no USDG pool quoted on any probed tier.\n */\n route: string | null;\n /** True when the only quoting pool is Uniswap v3 (no v4 pool on any tier). */\n v3Only?: boolean;\n /** Include in sim basket generation. False = keep out of default baskets. */\n eligible: boolean;\n /** Stock received for 100 USDG on the recorded route (human units). */\n quotedOut?: string;\n /** (pool-implied price / Chainlink feed − 1) in bps at the time of the quote. */\n feedDeviationBps?: number;\n /** Why a token is ineligible / unroutable, or anything the next re-quote should know. */\n note?: string;\n}\n\n/** Symbol order mirrors chains/9994663.json. */\nexport const ROBINHOOD_FORK_STOCKS = {\n AAPL: {\n address: \"0xaF3D76f1834A1d425780943C99Ea8A608f8a93f9\" as Address,\n feed: \"0x6B22A786bAa607d76728168703a39Ea9C99f2cD0\" as Address,\n route: \"v4:3000:60\",\n eligible: true,\n quotedOut: \"0.30994905\",\n feedDeviationBps: 252,\n },\n TSLA: {\n address: \"0x322F0929c4625eD5bAd873c95208D54E1c003b2d\" as Address,\n feed: \"0x4A1166a659A55625345e9515b32adECea5547C38\" as Address,\n route: \"v4:3000:60\",\n eligible: true,\n quotedOut: \"0.27501216\",\n feedDeviationBps: 265,\n },\n NVDA: {\n address: \"0xd0601CE157Db5bdC3162BbaC2a2C8aF5320D9EEC\" as Address,\n feed: \"0x379EC4f7C378F34a1B47E4F3cbeBCbAC3E8E9F15\" as Address,\n route: \"v4:3000:60\",\n eligible: true,\n quotedOut: \"0.43142676\",\n feedDeviationBps: 199,\n },\n MSFT: {\n address: \"0xe93237C50D904957Cf27E7B1133b510C669c2e74\" as Address,\n feed: \"0x45C3C877C15E6BA2EBB19eA114Ea508d14C1Af2E\" as Address,\n route: \"v4:3000:60\",\n eligible: true,\n quotedOut: \"0.19882872\",\n feedDeviationBps: -18,\n },\n AMZN: {\n address: \"0x12f190a9F9d7D37a250758b26824B97CE941bF54\" as Address,\n feed: \"0xD5a1508ceD74c084eBf3cBe853e2C968fB2a651C\" as Address,\n route: \"v4:3000:60\",\n eligible: true,\n quotedOut: \"0.37998363\",\n feedDeviationBps: 264,\n },\n META: {\n address: \"0xc0D6457C16Cc70d6790Dd43521C899C87ce02f35\" as Address,\n feed: \"0x7C38C00C30BEe9378381E7B6135d7283356D71b1\" as Address,\n route: \"v4:3000:60\",\n eligible: false,\n quotedOut: \"0.16185932\",\n feedDeviationBps: 829,\n note:\n \"Quotes, but the pool sits 8.3% above the frozen META/USD feed (v3 agrees: +8.2%), \" +\n \"past the sim's 5% buy floor and near the contract's 10% ceiling. Excluded from \" +\n \"generated baskets until the pool or feed is re-based.\",\n },\n AMD: {\n address: \"0x86923f96303D656E4aa86D9d42D1e57ad2023fdC\" as Address,\n feed: \"0x943A29E7ae51A4798823ca9eEd2ed533B2A22C72\" as Address,\n // The fee-3000 pool does NOT exist — only the 10000/200 tier quotes. This\n // is the case that makes guessing a fee tier a bug.\n route: \"v4:10000:200\",\n eligible: true,\n quotedOut: \"0.20887416\",\n feedDeviationBps: 53,\n },\n SPY: {\n address: \"0x117cc2133c37B721F49dE2A7a74833232B3B4C0C\" as Address,\n feed: \"0x319724394D3A0e3669269846abE664Cd621f9f6A\" as Address,\n route: \"v4:3000:60\",\n eligible: true,\n quotedOut: \"0.12913164\",\n feedDeviationBps: 63,\n },\n QQQ: {\n address: \"0xD5f3879160bc7c32ebb4dC785F8a4F505888de68\" as Address,\n feed: \"0x80901d846d5D7B030F26B480776EE3b29374C2ae\" as Address,\n // A 10000/200 pool also exists but quoted +48.8% vs feed (near-empty) —\n // never route QQQ through it.\n route: \"v4:3000:60\",\n eligible: true,\n quotedOut: \"0.13873445\",\n feedDeviationBps: 23,\n },\n SLV: {\n address: \"0x411eFb0E7f985935DAec3D4C3ebaEa0d0AD7D89f\" as Address,\n feed: \"0x209b73908e92Ae021826eD79609845451Ecba2ce\" as Address,\n route: \"v3:500\",\n v3Only: true,\n eligible: false,\n quotedOut: \"1.66443692\",\n feedDeviationBps: -389,\n note:\n \"No v4 USDG pool on any probed tier; only Uniswap v3 quotes (500/3000/10000 all \" +\n \"do, 500 best). This vnet's v3 position manager is corrupted, so the v3 swap leg \" +\n \"is unverified end to end — excluded from generated baskets.\",\n },\n GOOGL: {\n address: \"0x2e0847E8910a9732eB3fb1bb4b70a580ADAD4FE3\" as Address,\n feed: \"0xF6f373a037c30F0e5010d854385cA89185AE638b\" as Address,\n route: \"v4:3000:60\",\n eligible: true,\n quotedOut: \"0.29346562\",\n feedDeviationBps: 11,\n },\n} as const satisfies Record<string, ForkStock>;\n\nexport type ForkStockSymbol = keyof typeof ROBINHOOD_FORK_STOCKS;\n\nexport const ROBINHOOD_FORK_STOCK_SYMBOLS = Object.keys(ROBINHOOD_FORK_STOCKS) as ForkStockSymbol[];\n\n/** Symbols the sim may put in a generated basket (routable AND inside the slippage floor). */\nexport function forkBasketSymbols(): ForkStockSymbol[] {\n return ROBINHOOD_FORK_STOCK_SYMBOLS.filter((s) => ROBINHOOD_FORK_STOCKS[s].eligible);\n}\n\n/**\n * Feed + route for a basket token, or undefined when the symbol is unknown,\n * unroutable, or gated out of basket generation. Callers own the error text.\n */\nexport function forkBasketMeta(symbol: string): { feed: Address; route: string } | undefined {\n const entry = (ROBINHOOD_FORK_STOCKS as Record<string, ForkStock>)[symbol.toUpperCase()];\n if (!entry || !entry.eligible || !entry.route) return undefined;\n return { feed: entry.feed, route: entry.route };\n}\n\n/** `{ SYM: address }` for the token registry. */\nexport function forkStockAddresses(): Record<ForkStockSymbol, Address> {\n return Object.fromEntries(\n ROBINHOOD_FORK_STOCK_SYMBOLS.map((s) => [s, ROBINHOOD_FORK_STOCKS[s].address]),\n ) as Record<ForkStockSymbol, Address>;\n}\n\n/** `{ SYM_USD_FEED: feed }` for the Chainlink registry (push-feed auto-resolve). */\nexport function forkStockFeeds(): Record<`${ForkStockSymbol}_USD_FEED`, Address> {\n return Object.fromEntries(\n ROBINHOOD_FORK_STOCK_SYMBOLS.map((s) => [`${s}_USD_FEED`, ROBINHOOD_FORK_STOCKS[s].feed]),\n ) as Record<`${ForkStockSymbol}_USD_FEED`, Address>;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/network.ts"],"sourcesContent":["/**\n * Network state singleton.\n *\n * Called once at CLI startup via the --chain flag's preAction hook.\n * Every other module reads from here — never hardcodes a chain.\n *\n * Deployment targets: the Robinhood Chain mainnet fork (chain 9994663) — the\n * DEFAULT, and what the product ships against (app.sherwood.sh and the docs\n * both point there) — plus the Robinhood L2 testnet (chain 46630), still\n * reachable via `--chain robinhood-testnet`. Sherwood launches on Robinhood\n * first; other chains may be added back later, at which point they re-enter\n * the Network union + CHAIN_REGISTRY below.\n */\n\nimport { type Chain, defineChain, parseEther } from \"viem\";\nimport { getConfigRpcUrl } from \"./config.js\";\n\n// ── Robinhood L2 Testnet (Arbitrum Orbit, chain ID 46630) ──\n\nexport const robinhoodTestnet = defineChain({\n id: 46630,\n name: \"Robinhood Chain Testnet\",\n nativeCurrency: { name: \"Ethereum\", symbol: \"ETH\", decimals: 18 },\n rpcUrls: {\n default: { http: [\"https://rpc.testnet.chain.robinhood.com\"] },\n },\n blockExplorers: {\n default: {\n name: \"Blockscout\",\n url: \"https://explorer.testnet.chain.robinhood.com\",\n },\n },\n testnet: true,\n});\n\n// ── Robinhood Chain mainnet fork (Tenderly Virtual TestNet, chain ID 9994663) ──\n//\n// A fork of Robinhood Chain *mainnet* (USDG stablecoin, official Uniswap v3+v4,\n// Chainlink push feeds, tokenized-stock liquidity). Used for mainnet-faithful\n// e2e + guardian-network simulations. Ephemeral: Tenderly vnets expire — the RPC\n// is overridable via ROBINHOOD_FORK_RPC_URL when a new vnet is minted.\n\n/**\n * The PUBLIC RPC endpoint of vnet `a3fb16`\n * (id 6ad5961e-fbca-452f-939f-ca9a8c020933) — safe to bundle and to hand to\n * users: it serves reads and accepts broadcast txs, but exposes no\n * state-cheat surface.\n *\n * Admin/cheat calls (`tenderly_setBalance`, `tenderly_setStorageAt`,\n * `evm_increaseTime`, …) need that vnet's *admin* RPC, which is private —\n * pull it from the Tenderly dashboard and pass it via ROBINHOOD_FORK_RPC_URL.\n *\n * Two vnets answer to chain id 9994663; block height is the tell — the live\n * one is past block 21,170,000, the stale one forked at ~4.4M.\n */\nconst ROBINHOOD_FORK_PUBLIC_RPC =\n \"https://virtual.robinhood-chain.eu.rpc.tenderly.co/moonwell/wormhole-bridge/231af1\";\n\n/**\n * Tenderly scopes a vnet explorer under its vnet id — the bare\n * `dashboard.tenderly.co` host resolves to the user's own dashboard, not to\n * this fork's blocks, so tx/address links must carry the full prefix.\n */\nconst ROBINHOOD_FORK_EXPLORER =\n \"https://dashboard.tenderly.co/explorer/vnet/6ad5961e-fbca-452f-939f-ca9a8c020933\";\n\nexport const robinhoodFork = defineChain({\n id: 9994663,\n name: \"Robinhood Chain (fork)\",\n nativeCurrency: { name: \"Ethereum\", symbol: \"ETH\", decimals: 18 },\n rpcUrls: {\n default: {\n http: [ROBINHOOD_FORK_PUBLIC_RPC],\n },\n },\n blockExplorers: {\n default: {\n name: \"Tenderly\",\n url: ROBINHOOD_FORK_EXPLORER,\n },\n },\n testnet: true,\n});\n\n// ── Types ──\n\nexport type Network = \"robinhood-testnet\" | \"robinhood-fork\" | \"robinhood-mainnet\";\n\nexport interface ChainConfig {\n chain: Chain;\n /**\n * Ordered list of public RPC URLs tried in sequence when no user RPC is set.\n * First entry is the primary; the rest are fallbacks used transparently via\n * viem's `fallback` transport on rate-limit / network errors.\n */\n rpcFallbacks: string[];\n /** Legacy env var for backwards compat (optional per chain) */\n rpcEnvVar?: string;\n explorerHost: string;\n /**\n * Full URL prefix for explorer links, when the explorer is not rooted at\n * `https://${explorerHost}` — a Tenderly vnet scopes its blocks under\n * `/explorer/vnet/<id>`. Defaults to `https://${explorerHost}`.\n */\n explorerBaseUrl?: string;\n /** EAS GraphQL endpoint — null if EAS is not available on this chain */\n easGraphqlUrl: string | null;\n /** EAS scan host — null if unavailable */\n easScanHost: string | null;\n xmtpEnv: \"production\" | \"dev\";\n isTestnet: boolean;\n /**\n * ETH held back for gas in the native-ETH-wrap deposit path — the floor and\n * fallback for the live per-tx cushion estimate (`estimateGasCushion` in\n * client.ts), NOT a fixed requirement. High-fee chains (Base) want a\n * Base-scale reserve; near-zero-fee chains (Robinhood testnet, ~14-wei base\n * fee) want a tiny one so a valid deposit isn't rejected client-side. Unset →\n * `DEFAULT_MIN_GAS_RESERVE`.\n */\n minGasReserve?: bigint;\n}\n\n/**\n * Base-scale default reserve, used when a chain omits `minGasReserve`. Matches\n * the old hardcoded 0.0005-ETH cushion so higher-fee chains keep prior behavior.\n */\nexport const DEFAULT_MIN_GAS_RESERVE = parseEther(\"0.0005\");\n\n/**\n * Robinhood Chain mainnet (4663) — the EAS **coordination chain**.\n *\n * Sherwood core is NOT deployed here. This entry exists so attestations have a\n * single permanent home regardless of which chain a fund lives on, and it is\n * deliberately excluded from VALID_NETWORKS so it can never be picked as one.\n *\n * See docs/superpowers/specs/2026-08-26-eas-robinhood-mainnet-design.md §5.1.\n */\nexport const robinhoodMainnet = defineChain({\n id: 4663,\n name: \"Robinhood Chain\",\n nativeCurrency: {name: \"Ethereum\", symbol: \"ETH\", decimals: 18},\n rpcUrls: {default: {http: [\"https://rpc.mainnet.chain.robinhood.com\"]}},\n blockExplorers: {\n default: {name: \"Blockscout\", url: \"https://robinhoodchain.blockscout.com\"},\n },\n});\n\n// ── Chain Registry ──\n\nexport const CHAIN_REGISTRY: Record<Network, ChainConfig> = {\n \"robinhood-testnet\": {\n chain: robinhoodTestnet,\n rpcFallbacks: [\"https://rpc.testnet.chain.robinhood.com\"],\n rpcEnvVar: \"ROBINHOOD_TESTNET_RPC_URL\",\n explorerHost: \"explorer.testnet.chain.robinhood.com\",\n easGraphqlUrl: null,\n easScanHost: null,\n xmtpEnv: \"production\",\n isTestnet: true,\n // ~14-wei base fee: a full wrap+approve+deposit sequence costs a few\n // million wei (~1e-11 ETH). 0.00002 ETH is a generous floor that still\n // leaves a 0.00058-ETH wallet room to wrap 0.0005 and deposit.\n minGasReserve: parseEther(\"0.00002\"),\n },\n \"robinhood-fork\": {\n chain: robinhoodFork,\n rpcFallbacks: [ROBINHOOD_FORK_PUBLIC_RPC],\n rpcEnvVar: \"ROBINHOOD_FORK_RPC_URL\",\n explorerHost: \"dashboard.tenderly.co\",\n explorerBaseUrl: ROBINHOOD_FORK_EXPLORER,\n easGraphqlUrl: null,\n easScanHost: null,\n xmtpEnv: \"production\",\n isTestnet: true,\n // Robinhood-mainnet-fork gas (~0.17 gwei) is higher than testnet's ~14 wei —\n // keep a modest reserve so the ETH-wrap deposit path isn't rejected.\n minGasReserve: parseEther(\"0.0005\"),\n },\n \"robinhood-mainnet\": {\n chain: robinhoodMainnet,\n // Public endpoint kept only as a last-resort fallback: it sits behind\n // Cloudflare and challenges non-browser clients under load, and Robinhood's\n // own docs call it unsuitable for production. ROBINHOOD_RPC_URL (Alchemy)\n // is what actually gets used.\n rpcFallbacks: [\"https://rpc.mainnet.chain.robinhood.com\"],\n rpcEnvVar: \"ROBINHOOD_RPC_URL\",\n explorerHost: \"robinhoodchain.blockscout.com\",\n // Self-hosted EAS indexer — easscan does not index 4663. Serves GraphQL at\n // the root, so no /graphql suffix.\n easGraphqlUrl: \"https://sherwood-indexer-production.up.railway.app\",\n // No easscan-equivalent UI for this chain yet; attestation permalinks are\n // pending the app's own /attestation route (spec §10.2).\n easScanHost: null,\n xmtpEnv: \"production\",\n isTestnet: false,\n },\n};\n\n/**\n * Networks a user may select with `--chain`.\n *\n * NOT simply the CHAIN_REGISTRY keys: `robinhood-mainnet` is a coordination\n * chain for attestations only (no Sherwood contracts deployed there), so\n * selecting it as a fund's home chain would resolve every address to zero.\n */\nexport const COORDINATION_ONLY_NETWORKS: readonly Network[] = [\"robinhood-mainnet\"];\n\nexport const VALID_NETWORKS = (Object.keys(CHAIN_REGISTRY) as Network[]).filter(\n (n) => !COORDINATION_ONLY_NETWORKS.includes(n),\n);\n\n/**\n * The network a bare CLI invocation (no `--chain`) targets.\n *\n * The fork is where the product actually lives: app.sherwood.sh defaults to\n * chain 9994663, the docs banner declares it, and the redeployed 46630 factory\n * holds zero syndicates — so a default of `robinhood-testnet` landed a fresh\n * agent on an empty chain. `--chain robinhood-testnet` still selects 46630.\n */\nexport const DEFAULT_NETWORK: Network = \"robinhood-fork\";\n\n// ── Singleton state ──\n\nlet _network: Network = DEFAULT_NETWORK;\n\nexport function setNetwork(n: Network) {\n const config = CHAIN_REGISTRY[n];\n if (!config) {\n throw new Error(\n `Unknown network: ${n}. Valid: ${VALID_NETWORKS.join(\", \")}`,\n );\n }\n _network = n;\n}\n\nexport function getNetwork(): Network {\n return _network;\n}\n\n/**\n * Run `fn` with the network singleton temporarily switched to `network`,\n * restoring the previous network in `finally`.\n *\n * The viem clients (`getPublicClient`, `getWalletClient`) auto-invalidate on\n * chain change, so callers get fresh per-chain RPC + chain context inside the\n * block. Used for cross-chain fund resolution.\n */\nexport async function withNetwork<T>(\n network: Network,\n fn: () => Promise<T>,\n): Promise<T> {\n const previous = _network;\n _network = network;\n try {\n return await fn();\n } finally {\n _network = previous;\n }\n}\n\nexport function getChainConfig(): ChainConfig {\n return CHAIN_REGISTRY[_network];\n}\n\n/**\n * Per-chain ETH gas reserve floor/fallback for the ETH-wrap deposit path.\n * Falls back to the Base-scale default when the active chain doesn't set one.\n */\nexport function getMinGasReserve(): bigint {\n return CHAIN_REGISTRY[_network].minGasReserve ?? DEFAULT_MIN_GAS_RESERVE;\n}\n\n/**\n * Dev/CI-only chain-id override (`SIM_CHAIN_ID`) for custom-chainId vnet forks.\n * viem asserts the node's chainId matches the chain definition on every write,\n * so signing for such a fork requires the id to be swapped at the source.\n *\n * Interlock: honored ONLY while `SIM_ADDRESSES_FILE` is also set (the vnet\n * e2e harness's address override). A bare SIM_CHAIN_ID does nothing, so this\n * can never redirect signing on a real network run.\n */\nexport function applyChainIdOverride(chain: Chain): Chain {\n const raw = process.env.SIM_CHAIN_ID;\n if (!raw || !process.env.SIM_ADDRESSES_FILE) return chain;\n const id = Number(raw);\n if (!Number.isInteger(id) || id <= 0) return chain;\n return { ...chain, id };\n}\n\nexport function getChain(): Chain {\n return applyChainIdOverride(CHAIN_REGISTRY[_network].chain);\n}\n\n/**\n * Ordered list of RPC URLs to try, deduped:\n * 1. User config (~/.sherwood/config.json) — honored first\n * 2. The active chain's legacy env var (`rpcEnvVar` — ROBINHOOD_FORK_RPC_URL\n * on the default fork, ROBINHOOD_TESTNET_RPC_URL on 46630)\n * 3. Public fallback list from CHAIN_REGISTRY\n *\n * Fed to viem's `fallback()` transport so rate-limited RPCs transparently\n * advance to the next entry. See issue #182.\n */\nexport function getRpcUrls(): string[] {\n const cfg = CHAIN_REGISTRY[_network];\n const urls: string[] = [];\n\n const fromConfig = getConfigRpcUrl(_network);\n if (fromConfig) urls.push(fromConfig);\n\n if (cfg.rpcEnvVar && process.env[cfg.rpcEnvVar]) {\n urls.push(process.env[cfg.rpcEnvVar]!);\n }\n\n // Vnet harness (SIM_CHAIN_ID + SIM_ADDRESSES_FILE interlock): the fork RPC\n // is the ONLY valid endpoint — the public fallbacks point at the real\n // network. viem's fallback() otherwise rotates there on a vnet hiccup and\n // silently estimates gas/fees against MAINNET state (live finding: an\n // approve estimated at 21.9k gas on mainnet — no code at that address —\n // reverted out-of-gas on the vnet where it needs ~46k). A vnet call must\n // fail loudly, never retarget the real chain.\n if (process.env.SIM_CHAIN_ID && process.env.SIM_ADDRESSES_FILE && urls.length > 0) {\n return Array.from(new Set(urls));\n }\n\n urls.push(...cfg.rpcFallbacks);\n\n return Array.from(new Set(urls));\n}\n\nexport function getRpcUrl(): string {\n return getRpcUrls()[0];\n}\n\nexport function getExplorerUrl(txHash: string): string {\n const cfg = CHAIN_REGISTRY[_network];\n const base = cfg.explorerBaseUrl ?? `https://${cfg.explorerHost}`;\n return `${base}/tx/${txHash}`;\n}\n\nexport function isTestnet(): boolean {\n return CHAIN_REGISTRY[_network].isTestnet;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/client.ts","../src/lib/errors.ts"],"sourcesContent":["/**\n * viem client factory — resolves chain and RPC from the network module.\n * Private key is read from ~/.sherwood/config.json (set via `sherwood config set --private-key`),\n * with PRIVATE_KEY env var as fallback.\n */\n\n// dotenv loaded at entrypoint\nimport type { Hex, TransactionReceipt } from \"viem\";\nimport { createPublicClient, createWalletClient, fallback, http } from \"viem\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport { getChain, getRpcUrls, getMinGasReserve } from \"./network.js\";\nimport { requirePrivateKey } from \"./config.js\";\nimport { formatContractError } from \"./errors.js\";\nexport { formatContractError } from \"./errors.js\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _publicClient: any = null;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _walletClient: any = null;\n\n/**\n * Build a viem fallback transport over the chain's RPC URL list.\n * Transparently advances to the next URL on rate-limit / network errors\n * (issue #182). `retryCount: 0` on the inner `http` avoids wasting 10+s\n * spinning on a dead RPC before the fallback layer advances.\n */\nfunction buildTransport() {\n const urls = getRpcUrls();\n return fallback(\n urls.map((url) => http(url, { retryCount: 0, timeout: 8_000 })),\n { rank: false, retryCount: 0 },\n );\n}\n\nexport function getPublicClient() {\n const chain = getChain();\n // Auto-invalidate if network changed since last creation\n if (_publicClient && _publicClient.chain?.id !== chain.id) {\n _publicClient = null;\n }\n if (!_publicClient) {\n _publicClient = createPublicClient({\n chain,\n transport: buildTransport(),\n });\n }\n return _publicClient as ReturnType<typeof createPublicClient>;\n}\n\nexport function getWalletClient() {\n const chain = getChain();\n // Auto-invalidate if network changed since last creation\n if (_walletClient && _walletClient.chain?.id !== chain.id) {\n _walletClient = null;\n }\n if (!_walletClient) {\n const account = privateKeyToAccount(requirePrivateKey());\n _walletClient = createWalletClient({\n account,\n chain,\n transport: buildTransport(),\n });\n }\n return _walletClient as ReturnType<typeof createWalletClient>;\n}\n\n/**\n * Reset cached clients. Required for tests that call setNetwork()\n * after a client was already created.\n */\nexport function resetClients() {\n _publicClient = null;\n _walletClient = null;\n}\n\nexport function getAccount() {\n return privateKeyToAccount(requirePrivateKey());\n}\n\n/**\n * Estimate EIP-1559 fees with a 20% buffer to avoid stuck txs on Base gas spikes.\n */\nexport async function estimateFeesWithBuffer() {\n const client = getPublicClient();\n const { maxFeePerGas, maxPriorityFeePerGas } =\n await client.estimateFeesPerGas();\n let fee = (maxFeePerGas * 120n) / 100n;\n let tip = (maxPriorityFeePerGas * 120n) / 100n;\n // #462: some RPCs (Robinhood testnet after activity bursts) suggest fees\n // orders of magnitude above the live base fee; viem's worst-case prefund\n // check (gas × maxFeePerGas) then rejects large txs from small wallets even\n // though real cost is negligible. Clamp to 10× live base, but ONLY when the\n // suggestion exceeds 1000× base (never true on healthy chains — Base gas\n // spikes stay untouched). Best-effort: a failed getBlock skips the clamp.\n let base: bigint | null | undefined;\n try {\n base = (await client.getBlock()).baseFeePerGas;\n } catch {\n base = undefined;\n }\n if (base !== null && base !== undefined && base > 0n && fee > base * 1000n) {\n fee = base * 10n;\n if (tip > fee) tip = fee;\n }\n return { maxFeePerGas: fee, maxPriorityFeePerGas: tip };\n}\n\n/**\n * Conservative per-op gas-unit budgets for the native-ETH-wrap deposit/redeem\n * sequences. Multiplied by the live buffered `maxFeePerGas` (× a safety factor)\n * to derive the ETH gas cushion — replacing the old hardcoded 0.0005-ETH,\n * Base-calibrated constant that rejected valid deposits on low-fee chains\n * (Robinhood testnet, ~14-wei base fee). Deliberately generous; the realized\n * cost is a fraction of these on any chain.\n */\nexport const GAS_UNITS = {\n wrap: 55_000n,\n approve: 60_000n,\n deposit: 250_000n,\n redeem: 250_000n,\n} as const;\n\n/**\n * Derive the ETH gas cushion from live chain gas instead of a fixed constant:\n *\n * cushion = gasUnits × bufferedMaxFeePerGas × safetyFactor, floored at the\n * active chain's `minGasReserve`.\n *\n * `gasUnits` is the summed budget for the tx sequence (e.g. wrap+approve+deposit\n * via `GAS_UNITS`). Falls back to the per-chain floor when the live fee estimate\n * is unavailable (RPC error). On a ~14-wei-base-fee chain the derived term is\n * negligible, so the tiny per-chain floor dominates; on Base the live term\n * scales with the gas market and the Base-scale floor is the lower bound.\n */\nexport async function estimateGasCushion(\n gasUnits: bigint,\n safetyFactor = 2n,\n): Promise<bigint> {\n const floor = getMinGasReserve();\n try {\n const { maxFeePerGas } = await estimateFeesWithBuffer();\n const derived = gasUnits * maxFeePerGas * safetyFactor;\n return derived > floor ? derived : floor;\n } catch {\n return floor;\n }\n}\n\n// ── Nonce management + retry helpers ──\n//\n// Handles: nonce collisions, underpriced replacements, stuck pending txs.\n// Gas bump ceiling: base * 1.2 (buffer) * 1.1^3 (max retries) ≈ 1.6x base fee.\n\nconst MAX_RETRIES = 3;\nconst RETRY_DELAY_MS = 1500; // backoff between retries\nconst STUCK_NONCE_CONFIRM_DELAY_MS = 2500; // staleness check delay\nconst GAS_BUMP_NUMERATOR = 110n;\nconst GAS_BUMP_DENOMINATOR = 100n;\n\nfunction isUnderpricedError(msg: string): boolean {\n return msg.includes(\"replacement transaction underpriced\");\n}\n\nfunction isNonceStaleError(msg: string): boolean {\n return msg.includes(\"nonce too low\") || msg.includes(\"NONCE_EXPIRED\");\n}\n\nfunction isRetryableError(err: unknown): boolean {\n const msg = err instanceof Error ? err.message : String(err);\n return isUnderpricedError(msg) || isNonceStaleError(msg);\n}\n\nfunction bumpFees(fees: { maxFeePerGas: bigint; maxPriorityFeePerGas: bigint }) {\n return {\n maxFeePerGas: (fees.maxFeePerGas * GAS_BUMP_NUMERATOR) / GAS_BUMP_DENOMINATOR,\n maxPriorityFeePerGas: (fees.maxPriorityFeePerGas * GAS_BUMP_NUMERATOR) / GAS_BUMP_DENOMINATOR,\n };\n}\n\n// ── Stuck nonce detection ──\n\n/**\n * Check if the wallet has a stuck nonce (pending tx count > confirmed tx count).\n * Returns the stuck nonce number, or null if the wallet is clean.\n *\n * Includes a staleness guard: if pending > confirmed, waits ~2.5s and re-checks\n * to avoid false positives from propagation delays.\n */\nexport async function detectStuckNonce(): Promise<number | null> {\n const client = getPublicClient();\n const address = getAccount().address;\n const [confirmed, pending] = await Promise.all([\n client.getTransactionCount({ address, blockTag: \"latest\" }),\n client.getTransactionCount({ address, blockTag: \"pending\" }),\n ]);\n if (pending <= confirmed) return null;\n\n // Staleness guard: re-check after a short delay to avoid false positives\n await new Promise((r) => setTimeout(r, STUCK_NONCE_CONFIRM_DELAY_MS));\n const [confirmed2, pending2] = await Promise.all([\n client.getTransactionCount({ address, blockTag: \"latest\" }),\n client.getTransactionCount({ address, blockTag: \"pending\" }),\n ]);\n return pending2 > confirmed2 ? confirmed2 : null;\n}\n\n/**\n * Clear a single stuck nonce by sending a 0-value self-transfer with aggressively bumped gas.\n * Uses 5x the buffered fee estimate to guarantee replacement even if the original tx\n * was sent during a gas spike (EIP-1559 requires >= 110% of original maxPriorityFeePerGas).\n */\nasync function unstickWalletSingle(): Promise<Hex> {\n const stuckNonce = await detectStuckNonce();\n if (stuckNonce === null) {\n throw new Error(\"No stuck nonce detected — wallet is clean.\");\n }\n\n console.warn(` Unsticking wallet: replacing stuck tx at nonce ${stuckNonce}...`);\n const wallet = getWalletClient();\n const account = getAccount();\n\n // Use 5x gas buffer to guarantee replacement even for txs sent during gas spikes\n const { maxFeePerGas, maxPriorityFeePerGas } = await estimateFeesWithBuffer();\n const hash = await wallet.sendTransaction({\n account,\n chain: wallet.chain,\n to: account.address,\n value: 0n,\n nonce: stuckNonce,\n maxFeePerGas: maxFeePerGas * 5n,\n maxPriorityFeePerGas: maxPriorityFeePerGas * 5n,\n });\n\n const client = getPublicClient();\n await client.waitForTransactionReceipt({ hash });\n console.warn(` Wallet unstuck (nonce ${stuckNonce} replaced).`);\n return hash;\n}\n\n/**\n * Unstick a wallet by clearing ALL stuck nonces, not just the first one.\n * Loops until pending == confirmed nonce count.\n */\nexport async function unstickWallet(): Promise<Hex[]> {\n const hashes: Hex[] = [];\n while ((await detectStuckNonce()) !== null) {\n hashes.push(await unstickWalletSingle());\n }\n if (hashes.length === 0) {\n throw new Error(\"No stuck nonce detected — wallet is clean.\");\n }\n return hashes;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype TxSender = (params: any) => Promise<Hex>;\n\n/**\n * Shared retry loop: explicit nonce + EIP-1559 fee buffer + gas-bump on underpriced errors.\n * On \"nonce too low\" / \"NONCE_EXPIRED\", re-fetches nonce from pending state before retrying.\n * Also detects stuck nonces before sending and auto-unsticks the wallet.\n */\nasync function withRetry(send: TxSender, txParams: Record<string, unknown>): Promise<Hex> {\n const client = getPublicClient();\n const account = getAccount();\n let fees = await estimateFeesWithBuffer();\n\n // Auto-detect and clear ALL stuck nonces before attempting the tx\n while ((await detectStuckNonce()) !== null) {\n await unstickWalletSingle();\n }\n\n let nonce = await client.getTransactionCount({ address: account.address, blockTag: \"pending\" });\n\n for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {\n try {\n return await send({ ...txParams, ...fees, nonce });\n } catch (err) {\n if (attempt >= MAX_RETRIES || !isRetryableError(err)) {\n // Decode contract revert into a human-readable message before throwing\n throw new Error(formatContractError(err));\n }\n\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(` Retry ${attempt + 1}/${MAX_RETRIES}: ${isNonceStaleError(msg) ? \"refreshing nonce\" : \"bumping gas\"}...`);\n\n // Backoff between retries to let mempool settle\n await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));\n\n if (isNonceStaleError(msg)) {\n // Fresh nonce = fresh tx, no replacement needed — only bump fees for underpriced errors\n nonce = await client.getTransactionCount({ address: account.address, blockTag: \"pending\" });\n } else {\n fees = bumpFees(fees);\n }\n }\n }\n throw new Error(\"withRetry: exhausted retries\");\n}\n\n/**\n * Send a raw transaction with automatic gas-bump retry on nonce/underpriced errors.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function sendTxWithRetry(txParams: Record<string, any>): Promise<Hex> {\n const wallet = getWalletClient();\n return withRetry((p) => wallet.sendTransaction(p), txParams);\n}\n\n/**\n * Call writeContract with automatic gas-bump retry on nonce/underpriced errors.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function writeContractWithRetry(txParams: Record<string, any>): Promise<Hex> {\n const wallet = getWalletClient();\n return withRetry((p) => wallet.writeContract(p), txParams);\n}\n\n/**\n * Wait for a tx receipt. On timeout, checks for stuck nonce and auto-unsticks.\n *\n * **Important**: After unsticking, the error is still re-thrown because the original\n * tx is lost. Callers should use `writeContractWithRetry` / `sendTxWithRetry` which\n * re-fetch nonces automatically. Do NOT manually retry after this throws — use the\n * retry-aware wrappers instead.\n */\nexport async function waitForReceipt(hash: Hex): Promise<TransactionReceipt> {\n const client = getPublicClient();\n try {\n return await client.waitForTransactionReceipt({ hash });\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (err: any) {\n // If receipt wait times out, check for stuck nonce\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes(\"timeout\") || msg.includes(\"Timed out\")) {\n if ((await detectStuckNonce()) !== null) {\n console.warn(` Tx ${hash} appears stuck — attempting to unstick wallet...`);\n while ((await detectStuckNonce()) !== null) {\n await unstickWalletSingle();\n }\n }\n }\n throw err;\n }\n}\n","/**\n * Contract error decoding — turns raw reverts into human-readable messages.\n *\n * Uses viem's decodeErrorResult() against a combined ABI of all custom errors\n * from SyndicateVault, SyndicateGovernor, GovernorParameters, SyndicateFactory,\n * and strategy contracts.\n */\n\nimport { type Hex, decodeErrorResult, BaseError } from \"viem\";\nimport { getChain } from \"./network.js\";\n\n// ── Combined error-only ABI for decoding ──\n\nexport const CONTRACT_ERRORS_ABI = [\n // ── SyndicateVault ──\n { type: \"error\", name: \"InvalidOwner\", inputs: [] },\n { type: \"error\", name: \"InvalidExecutorImpl\", inputs: [] },\n { type: \"error\", name: \"NotActiveAgent\", inputs: [] },\n { type: \"error\", name: \"SimulationFailed\", inputs: [] },\n { type: \"error\", name: \"InvalidDepositor\", inputs: [] },\n { type: \"error\", name: \"DepositorAlreadyApproved\", inputs: [] },\n { type: \"error\", name: \"DepositorNotApproved\", inputs: [] },\n { type: \"error\", name: \"NotApprovedDepositor\", inputs: [] },\n { type: \"error\", name: \"AgentAlreadyRegistered\", inputs: [] },\n { type: \"error\", name: \"AgentNotActive\", inputs: [] },\n { type: \"error\", name: \"InvalidAgentRegistry\", inputs: [] },\n { type: \"error\", name: \"NotAgentOwner\", inputs: [] },\n { type: \"error\", name: \"NotGovernor\", inputs: [] },\n { type: \"error\", name: \"RedemptionsLocked\", inputs: [] },\n { type: \"error\", name: \"DepositsLocked\", inputs: [] },\n { type: \"error\", name: \"InvalidAgentAddress\", inputs: [] },\n { type: \"error\", name: \"TransferFailed\", inputs: [] },\n { type: \"error\", name: \"ZeroAddress\", inputs: [] },\n { type: \"error\", name: \"CannotRescueAsset\", inputs: [] },\n { type: \"error\", name: \"NotFactory\", inputs: [] },\n { type: \"error\", name: \"SandboxFundingExceedsCeiling\", inputs: [{ name: \"funding\", type: \"uint256\" }, { name: \"ceiling\", type: \"uint256\" }] },\n { type: \"error\", name: \"DisallowedBatchCallee\", inputs: [{ name: \"target\", type: \"address\" }] },\n\n // ── SyndicateGovernor ──\n { type: \"error\", name: \"VaultNotRegistered\", inputs: [] },\n { type: \"error\", name: \"VaultAlreadyRegistered\", inputs: [] },\n { type: \"error\", name: \"NotRegisteredAgent\", inputs: [] },\n { type: \"error\", name: \"PerformanceFeeTooHigh\", inputs: [] },\n { type: \"error\", name: \"StrategyDurationTooLong\", inputs: [] },\n { type: \"error\", name: \"StrategyDurationTooShort\", inputs: [] },\n { type: \"error\", name: \"EmptyExecuteCalls\", inputs: [] },\n { type: \"error\", name: \"EmptySettlementCalls\", inputs: [] },\n { type: \"error\", name: \"NotWithinVotingPeriod\", inputs: [] },\n { type: \"error\", name: \"NoVotingPower\", inputs: [] },\n { type: \"error\", name: \"AlreadyVoted\", inputs: [] },\n { type: \"error\", name: \"ProposalNotFound\", inputs: [] },\n { type: \"error\", name: \"ProposalNotApproved\", inputs: [] },\n { type: \"error\", name: \"ExecutionWindowExpired\", inputs: [] },\n { type: \"error\", name: \"StrategyAlreadyActive\", inputs: [] },\n { type: \"error\", name: \"CooldownNotElapsed\", inputs: [] },\n { type: \"error\", name: \"ProposalNotExecuted\", inputs: [] },\n { type: \"error\", name: \"ProposalNotCancellable\", inputs: [] },\n { type: \"error\", name: \"NotProposer\", inputs: [] },\n { type: \"error\", name: \"InvalidVotingPeriod\", inputs: [] },\n { type: \"error\", name: \"InvalidExecutionWindow\", inputs: [] },\n { type: \"error\", name: \"InvalidVetoThresholdBps\", inputs: [] },\n { type: \"error\", name: \"InvalidMaxPerformanceFeeBps\", inputs: [] },\n { type: \"error\", name: \"InvalidStrategyDurationBounds\", inputs: [] },\n { type: \"error\", name: \"InvalidCooldownPeriod\", inputs: [] },\n { type: \"error\", name: \"InvalidVault\", inputs: [] },\n { type: \"error\", name: \"NotVaultOwner\", inputs: [] },\n { type: \"error\", name: \"StrategyDurationNotElapsed\", inputs: [] },\n { type: \"error\", name: \"InvalidProtocolFeeBps\", inputs: [] },\n { type: \"error\", name: \"InvalidProtocolFeeRecipient\", inputs: [] },\n { type: \"error\", name: \"NotCoProposer\", inputs: [] },\n { type: \"error\", name: \"CollaborationExpired\", inputs: [] },\n { type: \"error\", name: \"AlreadyApproved\", inputs: [] },\n { type: \"error\", name: \"InvalidSplits\", inputs: [] },\n { type: \"error\", name: \"TooManyCoProposers\", inputs: [] },\n { type: \"error\", name: \"SplitTooLow\", inputs: [] },\n { type: \"error\", name: \"LeadSplitTooLow\", inputs: [] },\n { type: \"error\", name: \"DuplicateCoProposer\", inputs: [] },\n { type: \"error\", name: \"NotDraftState\", inputs: [] },\n { type: \"error\", name: \"InvalidCollaborationWindow\", inputs: [] },\n { type: \"error\", name: \"NotAuthorized\", inputs: [] },\n { type: \"error\", name: \"InvalidMaxCoProposers\", inputs: [] },\n { type: \"error\", name: \"Reentrancy\", inputs: [] },\n { type: \"error\", name: \"SandboxNotAvailable\", inputs: [{ name: \"vault\", type: \"address\" }] },\n { type: \"error\", name: \"Tier2CallCapExceedsCeiling\", inputs: [{ name: \"index\", type: \"uint256\" }] },\n\n // ── GovernorParameters (timelock) ──\n { type: \"error\", name: \"ChangeAlreadyPending\", inputs: [] },\n { type: \"error\", name: \"NoChangePending\", inputs: [] },\n { type: \"error\", name: \"ChangeNotReady\", inputs: [] },\n { type: \"error\", name: \"InvalidParameterChangeDelay\", inputs: [] },\n { type: \"error\", name: \"InvalidParameterKey\", inputs: [] },\n\n // ── SyndicateFactory ──\n { type: \"error\", name: \"InvalidVaultImpl\", inputs: [] },\n { type: \"error\", name: \"InvalidENSRegistrar\", inputs: [] },\n { type: \"error\", name: \"SubdomainTooShort\", inputs: [] },\n { type: \"error\", name: \"SubdomainTaken\", inputs: [] },\n { type: \"error\", name: \"NotCreator\", inputs: [] },\n { type: \"error\", name: \"InvalidGovernor\", inputs: [] },\n { type: \"error\", name: \"InsufficientCreationFee\", inputs: [] },\n { type: \"error\", name: \"InvalidFeeToken\", inputs: [] },\n { type: \"error\", name: \"ManagementFeeTooHigh\", inputs: [] },\n { type: \"error\", name: \"UpgradesDisabled\", inputs: [] },\n { type: \"error\", name: \"VaultNotDeployed\", inputs: [] },\n { type: \"error\", name: \"StrategyActive\", inputs: [] },\n\n // ── BaseStrategy ──\n { type: \"error\", name: \"AlreadyInitialized\", inputs: [] },\n { type: \"error\", name: \"NotVault\", inputs: [] },\n { type: \"error\", name: \"NotExecuted\", inputs: [] },\n { type: \"error\", name: \"AlreadyExecuted\", inputs: [] },\n { type: \"error\", name: \"AlreadySettled\", inputs: [] },\n\n // ── MoonwellSupplyStrategy / WstETHMoonwellStrategy ──\n { type: \"error\", name: \"InvalidAmount\", inputs: [] },\n { type: \"error\", name: \"MintFailed\", inputs: [] },\n { type: \"error\", name: \"RedeemFailed\", inputs: [] },\n\n // ── AerodromeLPStrategy ──\n { type: \"error\", name: \"GaugeMismatch\", inputs: [] },\n\n // ── WstETHMoonwellStrategy / VeniceInferenceStrategy ──\n { type: \"error\", name: \"SwapFailed\", inputs: [] },\n { type: \"error\", name: \"AlreadySettledParams\", inputs: [] },\n\n // ── PortfolioStrategy / UniswapSwapAdapter ──\n { type: \"error\", name: \"QuoteUnavailable\", inputs: [] },\n { type: \"error\", name: \"UnsupportedMode\", inputs: [] },\n { type: \"error\", name: \"InvalidWeights\", inputs: [] },\n { type: \"error\", name: \"LengthMismatch\", inputs: [] },\n { type: \"error\", name: \"TooManyTokens\", inputs: [] },\n { type: \"error\", name: \"RebalancingInProgress\", inputs: [] },\n { type: \"error\", name: \"StalePrice\", inputs: [] },\n { type: \"error\", name: \"InvalidSlippage\", inputs: [] },\n { type: \"error\", name: \"InvalidPriceDecimals\", inputs: [] },\n\n // ── VeniceInferenceStrategy ──\n { type: \"error\", name: \"NoAgent\", inputs: [] },\n\n // ── ExposureLedger ──\n { type: \"error\", name: \"InsufficientApproveCoverage\", inputs: [] },\n\n // ── StakedWood ──\n { type: \"error\", name: \"CoverageStillOpen\", inputs: [] },\n] as const;\n\n// ── Human-readable error messages ──\n\nconst ERROR_MESSAGES: Record<string, string> = {\n // Vault — permissions / state\n InvalidOwner: \"The caller is not the vault owner.\",\n NotActiveAgent: \"Your wallet is not registered as an active agent on this vault. Ask the creator to run: sherwood fund approve --agent-id <id> --wallet <your-address>\",\n NotApprovedDepositor: \"Your address is not on the depositor whitelist. Ask the vault creator to approve you.\",\n NotGovernor: \"This operation can only be called by the governor contract.\",\n NotFactory: \"This operation can only be called by the factory contract.\",\n RedemptionsLocked: \"Redemptions are locked while a strategy is executing. Wait for the proposal to be settled.\",\n DepositsLocked: \"Deposits are locked while an active proposal exists. Wait for settlement.\",\n InvalidDepositor: \"Invalid depositor address.\",\n DepositorAlreadyApproved: \"This depositor is already on the whitelist.\",\n DepositorNotApproved: \"This depositor is not on the whitelist.\",\n AgentAlreadyRegistered: \"This agent wallet is already registered on the vault.\",\n AgentNotActive: \"This agent is registered but not active.\",\n InvalidAgentRegistry: \"Agent registry address is invalid.\",\n NotAgentOwner: \"You do not own this ERC-8004 agent identity NFT.\",\n InvalidAgentAddress: \"Invalid agent wallet address (cannot be zero).\",\n InvalidExecutorImpl: \"Executor implementation address is invalid.\",\n SimulationFailed: \"Transaction simulation failed — the batch calls would revert onchain.\",\n TransferFailed: \"ERC-20 token transfer failed. Check token balance and approvals.\",\n ZeroAddress: \"A required address parameter is the zero address.\",\n CannotRescueAsset: \"Cannot rescue the vault's underlying asset — use redeem() instead.\",\n SandboxFundingExceedsCeiling: \"Sandbox funding exceeds the live tier-2 per-call capital ceiling. Reduce funding to fit under the ceiling.\",\n DisallowedBatchCallee: \"A governor-batch call targeted an address that is neither the vault's underlying asset nor a TierRegistry-allowlisted adapter.\",\n\n // Governor — proposal lifecycle\n VaultNotRegistered: \"This vault is not registered with the governor. The factory registers vaults automatically on creation.\",\n VaultAlreadyRegistered: \"This vault is already registered with the governor.\",\n NotRegisteredAgent: \"Your wallet is not a registered agent on this vault. Register first via: sherwood fund approve\",\n PerformanceFeeTooHigh: \"Performance fee exceeds the governor's maxPerformanceFeeBps. Check: sherwood governor info\",\n StrategyDurationTooLong: \"Strategy duration exceeds the governor's maxStrategyDuration. Check: sherwood governor info\",\n StrategyDurationTooShort: \"Strategy duration is below the governor's minStrategyDuration. Check: sherwood governor info\",\n EmptyExecuteCalls: \"Proposal must include at least one execute call.\",\n EmptySettlementCalls: \"Proposal must include at least one settlement call.\",\n NotWithinVotingPeriod: \"Voting period has not started or has already ended. Check: sherwood proposal show <id>\",\n NoVotingPower: \"You have no voting power (zero vault shares at the snapshot time).\",\n AlreadyVoted: \"You have already voted on this proposal.\",\n ProposalNotFound: \"Proposal does not exist. Check the proposal ID.\",\n ProposalNotApproved: \"Proposal is not in Approved state. It may still be in voting or was rejected.\",\n ExecutionWindowExpired: \"The execution window has closed. The proposal is now Expired.\",\n StrategyAlreadyActive: \"Another strategy is currently executing on this vault. Settle it first before executing a new proposal.\",\n CooldownNotElapsed: \"A proposal was recently settled. Wait for the cooldown period to elapse. Check: sherwood governor info\",\n ProposalNotExecuted: \"Proposal has not been executed yet. Execute it first.\",\n ProposalNotCancellable: \"This proposal cannot be cancelled in its current state.\",\n NotProposer: \"Only the original proposer can perform this action.\",\n StrategyDurationNotElapsed: \"Strategy duration has not elapsed yet. Only the proposer can settle early.\",\n\n // Governor — parameter validation\n InvalidVotingPeriod: \"Voting period is outside allowed bounds (check governor constants).\",\n InvalidExecutionWindow: \"Execution window is outside allowed bounds.\",\n InvalidVetoThresholdBps: \"Veto threshold must be between the allowed bounds (in bps).\",\n InvalidMaxPerformanceFeeBps: \"Max performance fee is outside allowed bounds.\",\n InvalidStrategyDurationBounds: \"Strategy duration bounds are invalid (min must be < max).\",\n InvalidCooldownPeriod: \"Cooldown period is outside allowed bounds.\",\n InvalidVault: \"Invalid vault address.\",\n NotVaultOwner: \"Only the vault owner can perform this action.\",\n InvalidProtocolFeeBps: \"Protocol fee exceeds the 10% maximum (1000 bps).\",\n InvalidProtocolFeeRecipient: \"Protocol fee recipient must be set before enabling protocol fees.\",\n\n // Governor — collaborative proposals\n NotCoProposer: \"You are not listed as a co-proposer on this proposal.\",\n CollaborationExpired: \"The collaboration window has expired.\",\n AlreadyApproved: \"This co-proposer has already approved.\",\n InvalidSplits: \"Co-proposer fee splits must sum correctly with the lead proposer split.\",\n TooManyCoProposers: \"Exceeds the maximum number of co-proposers. Check: sherwood governor info\",\n SplitTooLow: \"A co-proposer's fee split is below the minimum.\",\n LeadSplitTooLow: \"The lead proposer's fee split is below the minimum.\",\n DuplicateCoProposer: \"Duplicate co-proposer address in the list.\",\n NotDraftState: \"Proposal must be in Draft state for this operation.\",\n InvalidCollaborationWindow: \"Collaboration window is outside allowed bounds.\",\n NotAuthorized: \"You are not authorized to perform this action.\",\n InvalidMaxCoProposers: \"Max co-proposers value is outside allowed bounds.\",\n Reentrancy: \"Reentrancy detected — this call cannot be made during another call.\",\n SandboxNotAvailable: \"This vault has no CallSandbox implementation, so sandbox proposals cannot run. Use a vault created after sandbox wiring, or propose without a sandbox.\",\n Tier2CallCapExceedsCeiling: \"A tier-2 call cap exceeds the vault's tier-2 per-call ceiling (totalAssets × tier2CallCapBps / 10_000). Lower that call's cap.\",\n\n // Governor — parameter timelock\n ChangeAlreadyPending: \"A parameter change is already pending for this parameter. Finalize or cancel it first.\",\n NoChangePending: \"No parameter change is pending for this key.\",\n ChangeNotReady: \"Parameter change timelock has not elapsed yet. Wait for the delay to pass, then finalize.\",\n InvalidParameterChangeDelay: \"Parameter change delay is outside allowed bounds.\",\n InvalidParameterKey: \"Unknown parameter key.\",\n\n // Factory\n InvalidVaultImpl: \"Vault implementation address is invalid.\",\n InvalidENSRegistrar: \"ENS registrar address is invalid.\",\n SubdomainTooShort: \"Subdomain must be at least 3 characters.\",\n SubdomainTaken: \"This subdomain is already taken. Choose a different name.\",\n NotCreator: \"Only the fund creator can perform this action.\",\n InvalidGovernor: \"Governor address is invalid.\",\n InsufficientCreationFee: \"Insufficient creation fee. Check the required fee amount.\",\n InvalidFeeToken: \"Invalid fee token address.\",\n ManagementFeeTooHigh: \"Management fee exceeds the maximum allowed.\",\n UpgradesDisabled: \"Vault upgrades are currently disabled by the factory owner.\",\n VaultNotDeployed: \"Vault has not been deployed yet.\",\n StrategyActive: \"Cannot perform this action while a strategy is actively executing.\",\n\n // Strategy — base\n AlreadyInitialized: \"This strategy clone was already initialized. Deploy a fresh clone.\",\n NotVault: \"Only the vault can call this strategy function.\",\n NotExecuted: \"Strategy has not been executed yet.\",\n AlreadyExecuted: \"Strategy has already been executed.\",\n AlreadySettled: \"Strategy has already been settled.\",\n\n // Strategy — Moonwell / WstETH\n InvalidAmount: \"Invalid amount — must be greater than zero.\",\n MintFailed: \"Moonwell cToken mint failed. The underlying supply may have hit the market cap.\",\n RedeemFailed: \"Moonwell cToken redeem failed. Check that sufficient liquidity is available.\",\n\n // Strategy — Aerodrome\n GaugeMismatch: \"Aerodrome gauge does not match the expected pool.\",\n\n // Strategy — WstETH / Venice\n SwapFailed: \"Token swap failed. Check slippage tolerance and pool liquidity.\",\n AlreadySettledParams: \"Settlement parameters have already been set.\",\n\n // Strategy — Portfolio / UniswapSwapAdapter\n QuoteUnavailable:\n \"Uniswap quoter returned 0 or reverted for a portfolio allocation. \" +\n \"Usually means: (a) no V3 pool exists at the requested fee tier for one of the tokens, \" +\n \"(b) the strategy clone was initialized against an old/broken UniswapSwapAdapter \" +\n \"(check the clone's swapAdapter() vs the current chains JSON), or \" +\n \"(c) the adapter is calling Quoter with the wrong ABI (pre-PR #317 bug).\",\n UnsupportedMode: \"UniswapSwapAdapter doesn't support that swap mode. Only V3 single-hop (mode 0) and multi-hop (mode 1) are supported.\",\n InvalidWeights: \"Portfolio weights must sum to 10000 bps (100%).\",\n LengthMismatch: \"Portfolio input arrays (tokens / weights / swapExtraData / priceDecimals) must have the same length.\",\n TooManyTokens: \"Portfolio basket exceeds the maximum allocation count (20).\",\n RebalancingInProgress: \"A rebalance is already in flight on this clone. Wait for it to finish.\",\n StalePrice: \"Chainlink Data Streams report has expired. Refresh prices and retry.\",\n InvalidSlippage: \"maxSlippageBps must be > 0 and < 10000.\",\n InvalidPriceDecimals: \"priceDecimals entry exceeds 36. Use 8 for tokenized-stock feeds, 18 for crypto pairs.\",\n\n // Strategy — Venice\n NoAgent: \"No agent is registered on the vault. Register an agent first.\",\n\n // ExposureLedger\n InsufficientApproveCoverage: \"No bonded guardian coverage was raised for this proposal. Execution requires at least one identified, bonded approver with slashable coverage.\",\n\n // StakedWood\n CoverageStillOpen: \"Cannot release the unstake yet — this guardian still backs a proposal that could be challenged. The unstake request stays open; retry after coverage closes.\",\n};\n\n// ── Decoding ──\n\n/**\n * Attempt to decode a hex revert selector into a human-readable error message.\n * Returns null if the selector doesn't match any known contract error.\n */\nexport function decodeContractError(data: Hex): { name: string; message: string } | null {\n try {\n const decoded = decodeErrorResult({\n abi: CONTRACT_ERRORS_ABI,\n data,\n });\n const message = ERROR_MESSAGES[decoded.errorName] || `Contract error: ${decoded.errorName}`;\n return { name: decoded.errorName, message };\n } catch {\n return null;\n }\n}\n\n/**\n * Extract a hex error selector from a viem error's walk chain.\n * viem wraps contract call reverts in ContractFunctionRevertedError which\n * contains a `data` field with the raw 4-byte (or longer) revert payload.\n */\nfunction extractRevertData(err: unknown): Hex | null {\n if (!(err instanceof BaseError)) return null;\n\n // Walk the viem error chain to find revert data\n const revertError = err.walk((e) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (e as any).data !== undefined;\n });\n\n if (revertError) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const data = (revertError as any).data;\n // data can be the hex string directly, or an object with a data field\n if (typeof data === \"string\" && data.startsWith(\"0x\")) {\n return data as Hex;\n }\n if (typeof data === \"object\" && data?.data && typeof data.data === \"string\") {\n return data.data as Hex;\n }\n }\n\n // Fallback: extract 0x + hex from the error message (e.g. \"reverted with 0x62df0545\")\n const msg = err.message || \"\";\n const match = msg.match(/(?:signature|data)\\s*\"?(0x[0-9a-fA-F]+)\"?/);\n if (match) return match[1] as Hex;\n\n return null;\n}\n\n// ── Known common EVM / ERC-20 revert strings ──\n\nconst KNOWN_REVERT_STRINGS: Record<string, string> = {\n \"ERC20: transfer amount exceeds balance\": \"Insufficient token balance for this transfer.\",\n \"ERC20: transfer amount exceeds allowance\": \"Token allowance insufficient. An approval step may have been skipped.\",\n \"ERC20: insufficient allowance\": \"Token allowance insufficient. An approval step may have been skipped.\",\n \"Ownable: caller is not the owner\": \"Only the contract owner can call this function.\",\n \"Pausable: paused\": \"The contract is currently paused.\",\n};\n\n/**\n * Format any caught error into a user-friendly message.\n *\n * Tries (in order):\n * 1. Decode custom error selector from our contract ABIs\n * 2. Match known EVM/ERC-20 revert reason strings\n * 3. Identify nonce / gas issues with actionable advice\n * 4. Fall back to the raw error message\n */\nexport function formatContractError(err: unknown): string {\n // 1. Try to decode custom contract error\n const revertData = extractRevertData(err);\n if (revertData && revertData.length >= 10) {\n const decoded = decodeContractError(revertData);\n if (decoded) return decoded.message;\n }\n\n const rawMsg = err instanceof Error ? err.message : String(err);\n\n // 2. Check for known revert reason strings\n for (const [pattern, message] of Object.entries(KNOWN_REVERT_STRINGS)) {\n if (rawMsg.includes(pattern)) return message;\n }\n\n // 3. Nonce / gas issues — already handled by retry, but surface clearly if they bubble up\n if (rawMsg.includes(\"replacement transaction underpriced\")) {\n return \"A previous transaction is stuck. The CLI retried with higher gas but the error persists. Try again in a moment.\";\n }\n if (rawMsg.includes(\"nonce too low\") || rawMsg.includes(\"NONCE_EXPIRED\")) {\n return \"Transaction nonce conflict — a previous transaction is still pending. Wait a moment and retry.\";\n }\n if (rawMsg.includes(\"insufficient funds for gas\")) {\n return `Insufficient ETH for gas fees. Top up your wallet with ETH on ${getChain().name}.`;\n }\n\n // 4. Clean up common viem wrapper noise\n // Strip \"ContractFunctionRevertedError:\" prefix and \"Docs:\" links\n let cleaned = rawMsg\n .replace(/ContractFunctionRevertedError:\\s*/g, \"\")\n .replace(/Docs:\\s*https:\\/\\/\\S+/g, \"\")\n .replace(/Version:\\s*viem@\\S+/g, \"\")\n .replace(/Request Arguments:[\\s\\S]*$/m, \"\")\n .replace(/Contract Call:[\\s\\S]*?(?=\\n\\n|\\n[A-Z]|$)/m, \"\")\n .trim();\n\n // If we still have \"reverted with the following signature: 0x...\" try one more decode\n const sigMatch = cleaned.match(/signature[:\\s]+\"?(0x[0-9a-fA-F]{8,})\"?/);\n if (sigMatch) {\n const decoded = decodeContractError(sigMatch[1] as Hex);\n if (decoded) return decoded.message;\n // If we can't decode it, at least explain what it is\n const explorer = getChain().blockExplorers?.default?.name ?? \"the block explorer\";\n cleaned = `Contract reverted with unknown error selector ${sigMatch[1]}. Check the transaction on ${explorer} for details.`;\n }\n\n return cleaned;\n}\n"],"mappings":";;;;;;;;;;AAQA,SAAS,oBAAoB,oBAAoB,UAAU,YAAY;AACvE,SAAS,2BAA2B;;;ACDpC,SAAmB,mBAAmB,iBAAiB;AAKhD,IAAM,sBAAsB;AAAA;AAAA,EAEjC,EAAE,MAAM,SAAS,MAAM,gBAAgB,QAAQ,CAAC,EAAE;AAAA,EAClD,EAAE,MAAM,SAAS,MAAM,uBAAuB,QAAQ,CAAC,EAAE;AAAA,EACzD,EAAE,MAAM,SAAS,MAAM,kBAAkB,QAAQ,CAAC,EAAE;AAAA,EACpD,EAAE,MAAM,SAAS,MAAM,oBAAoB,QAAQ,CAAC,EAAE;AAAA,EACtD,EAAE,MAAM,SAAS,MAAM,oBAAoB,QAAQ,CAAC,EAAE;AAAA,EACtD,EAAE,MAAM,SAAS,MAAM,4BAA4B,QAAQ,CAAC,EAAE;AAAA,EAC9D,EAAE,MAAM,SAAS,MAAM,wBAAwB,QAAQ,CAAC,EAAE;AAAA,EAC1D,EAAE,MAAM,SAAS,MAAM,wBAAwB,QAAQ,CAAC,EAAE;AAAA,EAC1D,EAAE,MAAM,SAAS,MAAM,0BAA0B,QAAQ,CAAC,EAAE;AAAA,EAC5D,EAAE,MAAM,SAAS,MAAM,kBAAkB,QAAQ,CAAC,EAAE;AAAA,EACpD,EAAE,MAAM,SAAS,MAAM,wBAAwB,QAAQ,CAAC,EAAE;AAAA,EAC1D,EAAE,MAAM,SAAS,MAAM,iBAAiB,QAAQ,CAAC,EAAE;AAAA,EACnD,EAAE,MAAM,SAAS,MAAM,eAAe,QAAQ,CAAC,EAAE;AAAA,EACjD,EAAE,MAAM,SAAS,MAAM,qBAAqB,QAAQ,CAAC,EAAE;AAAA,EACvD,EAAE,MAAM,SAAS,MAAM,kBAAkB,QAAQ,CAAC,EAAE;AAAA,EACpD,EAAE,MAAM,SAAS,MAAM,uBAAuB,QAAQ,CAAC,EAAE;AAAA,EACzD,EAAE,MAAM,SAAS,MAAM,kBAAkB,QAAQ,CAAC,EAAE;AAAA,EACpD,EAAE,MAAM,SAAS,MAAM,eAAe,QAAQ,CAAC,EAAE;AAAA,EACjD,EAAE,MAAM,SAAS,MAAM,qBAAqB,QAAQ,CAAC,EAAE;AAAA,EACvD,EAAE,MAAM,SAAS,MAAM,cAAc,QAAQ,CAAC,EAAE;AAAA,EAChD,EAAE,MAAM,SAAS,MAAM,gCAAgC,QAAQ,CAAC,EAAE,MAAM,WAAW,MAAM,UAAU,GAAG,EAAE,MAAM,WAAW,MAAM,UAAU,CAAC,EAAE;AAAA,EAC5I,EAAE,MAAM,SAAS,MAAM,yBAAyB,QAAQ,CAAC,EAAE,MAAM,UAAU,MAAM,UAAU,CAAC,EAAE;AAAA;AAAA,EAG9F,EAAE,MAAM,SAAS,MAAM,sBAAsB,QAAQ,CAAC,EAAE;AAAA,EACxD,EAAE,MAAM,SAAS,MAAM,0BAA0B,QAAQ,CAAC,EAAE;AAAA,EAC5D,EAAE,MAAM,SAAS,MAAM,sBAAsB,QAAQ,CAAC,EAAE;AAAA,EACxD,EAAE,MAAM,SAAS,MAAM,yBAAyB,QAAQ,CAAC,EAAE;AAAA,EAC3D,EAAE,MAAM,SAAS,MAAM,2BAA2B,QAAQ,CAAC,EAAE;AAAA,EAC7D,EAAE,MAAM,SAAS,MAAM,4BAA4B,QAAQ,CAAC,EAAE;AAAA,EAC9D,EAAE,MAAM,SAAS,MAAM,qBAAqB,QAAQ,CAAC,EAAE;AAAA,EACvD,EAAE,MAAM,SAAS,MAAM,wBAAwB,QAAQ,CAAC,EAAE;AAAA,EAC1D,EAAE,MAAM,SAAS,MAAM,yBAAyB,QAAQ,CAAC,EAAE;AAAA,EAC3D,EAAE,MAAM,SAAS,MAAM,iBAAiB,QAAQ,CAAC,EAAE;AAAA,EACnD,EAAE,MAAM,SAAS,MAAM,gBAAgB,QAAQ,CAAC,EAAE;AAAA,EAClD,EAAE,MAAM,SAAS,MAAM,oBAAoB,QAAQ,CAAC,EAAE;AAAA,EACtD,EAAE,MAAM,SAAS,MAAM,uBAAuB,QAAQ,CAAC,EAAE;AAAA,EACzD,EAAE,MAAM,SAAS,MAAM,0BAA0B,QAAQ,CAAC,EAAE;AAAA,EAC5D,EAAE,MAAM,SAAS,MAAM,yBAAyB,QAAQ,CAAC,EAAE;AAAA,EAC3D,EAAE,MAAM,SAAS,MAAM,sBAAsB,QAAQ,CAAC,EAAE;AAAA,EACxD,EAAE,MAAM,SAAS,MAAM,uBAAuB,QAAQ,CAAC,EAAE;AAAA,EACzD,EAAE,MAAM,SAAS,MAAM,0BAA0B,QAAQ,CAAC,EAAE;AAAA,EAC5D,EAAE,MAAM,SAAS,MAAM,eAAe,QAAQ,CAAC,EAAE;AAAA,EACjD,EAAE,MAAM,SAAS,MAAM,uBAAuB,QAAQ,CAAC,EAAE;AAAA,EACzD,EAAE,MAAM,SAAS,MAAM,0BAA0B,QAAQ,CAAC,EAAE;AAAA,EAC5D,EAAE,MAAM,SAAS,MAAM,2BAA2B,QAAQ,CAAC,EAAE;AAAA,EAC7D,EAAE,MAAM,SAAS,MAAM,+BAA+B,QAAQ,CAAC,EAAE;AAAA,EACjE,EAAE,MAAM,SAAS,MAAM,iCAAiC,QAAQ,CAAC,EAAE;AAAA,EACnE,EAAE,MAAM,SAAS,MAAM,yBAAyB,QAAQ,CAAC,EAAE;AAAA,EAC3D,EAAE,MAAM,SAAS,MAAM,gBAAgB,QAAQ,CAAC,EAAE;AAAA,EAClD,EAAE,MAAM,SAAS,MAAM,iBAAiB,QAAQ,CAAC,EAAE;AAAA,EACnD,EAAE,MAAM,SAAS,MAAM,8BAA8B,QAAQ,CAAC,EAAE;AAAA,EAChE,EAAE,MAAM,SAAS,MAAM,yBAAyB,QAAQ,CAAC,EAAE;AAAA,EAC3D,EAAE,MAAM,SAAS,MAAM,+BAA+B,QAAQ,CAAC,EAAE;AAAA,EACjE,EAAE,MAAM,SAAS,MAAM,iBAAiB,QAAQ,CAAC,EAAE;AAAA,EACnD,EAAE,MAAM,SAAS,MAAM,wBAAwB,QAAQ,CAAC,EAAE;AAAA,EAC1D,EAAE,MAAM,SAAS,MAAM,mBAAmB,QAAQ,CAAC,EAAE;AAAA,EACrD,EAAE,MAAM,SAAS,MAAM,iBAAiB,QAAQ,CAAC,EAAE;AAAA,EACnD,EAAE,MAAM,SAAS,MAAM,sBAAsB,QAAQ,CAAC,EAAE;AAAA,EACxD,EAAE,MAAM,SAAS,MAAM,eAAe,QAAQ,CAAC,EAAE;AAAA,EACjD,EAAE,MAAM,SAAS,MAAM,mBAAmB,QAAQ,CAAC,EAAE;AAAA,EACrD,EAAE,MAAM,SAAS,MAAM,uBAAuB,QAAQ,CAAC,EAAE;AAAA,EACzD,EAAE,MAAM,SAAS,MAAM,iBAAiB,QAAQ,CAAC,EAAE;AAAA,EACnD,EAAE,MAAM,SAAS,MAAM,8BAA8B,QAAQ,CAAC,EAAE;AAAA,EAChE,EAAE,MAAM,SAAS,MAAM,iBAAiB,QAAQ,CAAC,EAAE;AAAA,EACnD,EAAE,MAAM,SAAS,MAAM,yBAAyB,QAAQ,CAAC,EAAE;AAAA,EAC3D,EAAE,MAAM,SAAS,MAAM,cAAc,QAAQ,CAAC,EAAE;AAAA,EAChD,EAAE,MAAM,SAAS,MAAM,uBAAuB,QAAQ,CAAC,EAAE,MAAM,SAAS,MAAM,UAAU,CAAC,EAAE;AAAA,EAC3F,EAAE,MAAM,SAAS,MAAM,8BAA8B,QAAQ,CAAC,EAAE,MAAM,SAAS,MAAM,UAAU,CAAC,EAAE;AAAA;AAAA,EAGlG,EAAE,MAAM,SAAS,MAAM,wBAAwB,QAAQ,CAAC,EAAE;AAAA,EAC1D,EAAE,MAAM,SAAS,MAAM,mBAAmB,QAAQ,CAAC,EAAE;AAAA,EACrD,EAAE,MAAM,SAAS,MAAM,kBAAkB,QAAQ,CAAC,EAAE;AAAA,EACpD,EAAE,MAAM,SAAS,MAAM,+BAA+B,QAAQ,CAAC,EAAE;AAAA,EACjE,EAAE,MAAM,SAAS,MAAM,uBAAuB,QAAQ,CAAC,EAAE;AAAA;AAAA,EAGzD,EAAE,MAAM,SAAS,MAAM,oBAAoB,QAAQ,CAAC,EAAE;AAAA,EACtD,EAAE,MAAM,SAAS,MAAM,uBAAuB,QAAQ,CAAC,EAAE;AAAA,EACzD,EAAE,MAAM,SAAS,MAAM,qBAAqB,QAAQ,CAAC,EAAE;AAAA,EACvD,EAAE,MAAM,SAAS,MAAM,kBAAkB,QAAQ,CAAC,EAAE;AAAA,EACpD,EAAE,MAAM,SAAS,MAAM,cAAc,QAAQ,CAAC,EAAE;AAAA,EAChD,EAAE,MAAM,SAAS,MAAM,mBAAmB,QAAQ,CAAC,EAAE;AAAA,EACrD,EAAE,MAAM,SAAS,MAAM,2BAA2B,QAAQ,CAAC,EAAE;AAAA,EAC7D,EAAE,MAAM,SAAS,MAAM,mBAAmB,QAAQ,CAAC,EAAE;AAAA,EACrD,EAAE,MAAM,SAAS,MAAM,wBAAwB,QAAQ,CAAC,EAAE;AAAA,EAC1D,EAAE,MAAM,SAAS,MAAM,oBAAoB,QAAQ,CAAC,EAAE;AAAA,EACtD,EAAE,MAAM,SAAS,MAAM,oBAAoB,QAAQ,CAAC,EAAE;AAAA,EACtD,EAAE,MAAM,SAAS,MAAM,kBAAkB,QAAQ,CAAC,EAAE;AAAA;AAAA,EAGpD,EAAE,MAAM,SAAS,MAAM,sBAAsB,QAAQ,CAAC,EAAE;AAAA,EACxD,EAAE,MAAM,SAAS,MAAM,YAAY,QAAQ,CAAC,EAAE;AAAA,EAC9C,EAAE,MAAM,SAAS,MAAM,eAAe,QAAQ,CAAC,EAAE;AAAA,EACjD,EAAE,MAAM,SAAS,MAAM,mBAAmB,QAAQ,CAAC,EAAE;AAAA,EACrD,EAAE,MAAM,SAAS,MAAM,kBAAkB,QAAQ,CAAC,EAAE;AAAA;AAAA,EAGpD,EAAE,MAAM,SAAS,MAAM,iBAAiB,QAAQ,CAAC,EAAE;AAAA,EACnD,EAAE,MAAM,SAAS,MAAM,cAAc,QAAQ,CAAC,EAAE;AAAA,EAChD,EAAE,MAAM,SAAS,MAAM,gBAAgB,QAAQ,CAAC,EAAE;AAAA;AAAA,EAGlD,EAAE,MAAM,SAAS,MAAM,iBAAiB,QAAQ,CAAC,EAAE;AAAA;AAAA,EAGnD,EAAE,MAAM,SAAS,MAAM,cAAc,QAAQ,CAAC,EAAE;AAAA,EAChD,EAAE,MAAM,SAAS,MAAM,wBAAwB,QAAQ,CAAC,EAAE;AAAA;AAAA,EAG1D,EAAE,MAAM,SAAS,MAAM,oBAAoB,QAAQ,CAAC,EAAE;AAAA,EACtD,EAAE,MAAM,SAAS,MAAM,mBAAmB,QAAQ,CAAC,EAAE;AAAA,EACrD,EAAE,MAAM,SAAS,MAAM,kBAAkB,QAAQ,CAAC,EAAE;AAAA,EACpD,EAAE,MAAM,SAAS,MAAM,kBAAkB,QAAQ,CAAC,EAAE;AAAA,EACpD,EAAE,MAAM,SAAS,MAAM,iBAAiB,QAAQ,CAAC,EAAE;AAAA,EACnD,EAAE,MAAM,SAAS,MAAM,yBAAyB,QAAQ,CAAC,EAAE;AAAA,EAC3D,EAAE,MAAM,SAAS,MAAM,cAAc,QAAQ,CAAC,EAAE;AAAA,EAChD,EAAE,MAAM,SAAS,MAAM,mBAAmB,QAAQ,CAAC,EAAE;AAAA,EACrD,EAAE,MAAM,SAAS,MAAM,wBAAwB,QAAQ,CAAC,EAAE;AAAA;AAAA,EAG1D,EAAE,MAAM,SAAS,MAAM,WAAW,QAAQ,CAAC,EAAE;AAAA;AAAA,EAG7C,EAAE,MAAM,SAAS,MAAM,+BAA+B,QAAQ,CAAC,EAAE;AAAA;AAAA,EAGjE,EAAE,MAAM,SAAS,MAAM,qBAAqB,QAAQ,CAAC,EAAE;AACzD;AAIA,IAAM,iBAAyC;AAAA;AAAA,EAE7C,cAAc;AAAA,EACd,gBAAgB;AAAA,EAChB,sBAAsB;AAAA,EACtB,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,mBAAmB;AAAA,EACnB,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,0BAA0B;AAAA,EAC1B,sBAAsB;AAAA,EACtB,wBAAwB;AAAA,EACxB,gBAAgB;AAAA,EAChB,sBAAsB;AAAA,EACtB,eAAe;AAAA,EACf,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,8BAA8B;AAAA,EAC9B,uBAAuB;AAAA;AAAA,EAGvB,oBAAoB;AAAA,EACpB,wBAAwB;AAAA,EACxB,oBAAoB;AAAA,EACpB,uBAAuB;AAAA,EACvB,yBAAyB;AAAA,EACzB,0BAA0B;AAAA,EAC1B,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,uBAAuB;AAAA,EACvB,eAAe;AAAA,EACf,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EACrB,wBAAwB;AAAA,EACxB,uBAAuB;AAAA,EACvB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,wBAAwB;AAAA,EACxB,aAAa;AAAA,EACb,4BAA4B;AAAA;AAAA,EAG5B,qBAAqB;AAAA,EACrB,wBAAwB;AAAA,EACxB,yBAAyB;AAAA,EACzB,6BAA6B;AAAA,EAC7B,+BAA+B;AAAA,EAC/B,uBAAuB;AAAA,EACvB,cAAc;AAAA,EACd,eAAe;AAAA,EACf,uBAAuB;AAAA,EACvB,6BAA6B;AAAA;AAAA,EAG7B,eAAe;AAAA,EACf,sBAAsB;AAAA,EACtB,iBAAiB;AAAA,EACjB,eAAe;AAAA,EACf,oBAAoB;AAAA,EACpB,aAAa;AAAA,EACb,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,eAAe;AAAA,EACf,4BAA4B;AAAA,EAC5B,eAAe;AAAA,EACf,uBAAuB;AAAA,EACvB,YAAY;AAAA,EACZ,qBAAqB;AAAA,EACrB,4BAA4B;AAAA;AAAA,EAG5B,sBAAsB;AAAA,EACtB,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,6BAA6B;AAAA,EAC7B,qBAAqB;AAAA;AAAA,EAGrB,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EACrB,mBAAmB;AAAA,EACnB,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,yBAAyB;AAAA,EACzB,iBAAiB;AAAA,EACjB,sBAAsB;AAAA,EACtB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA;AAAA,EAGhB,oBAAoB;AAAA,EACpB,UAAU;AAAA,EACV,aAAa;AAAA,EACb,iBAAiB;AAAA,EACjB,gBAAgB;AAAA;AAAA,EAGhB,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,cAAc;AAAA;AAAA,EAGd,eAAe;AAAA;AAAA,EAGf,YAAY;AAAA,EACZ,sBAAsB;AAAA;AAAA,EAGtB,kBACE;AAAA,EAKF,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,uBAAuB;AAAA,EACvB,YAAY;AAAA,EACZ,iBAAiB;AAAA,EACjB,sBAAsB;AAAA;AAAA,EAGtB,SAAS;AAAA;AAAA,EAGT,6BAA6B;AAAA;AAAA,EAG7B,mBAAmB;AACrB;AAQO,SAAS,oBAAoB,MAAqD;AACvF,MAAI;AACF,UAAM,UAAU,kBAAkB;AAAA,MAChC,KAAK;AAAA,MACL;AAAA,IACF,CAAC;AACD,UAAM,UAAU,eAAe,QAAQ,SAAS,KAAK,mBAAmB,QAAQ,SAAS;AACzF,WAAO,EAAE,MAAM,QAAQ,WAAW,QAAQ;AAAA,EAC5C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAOA,SAAS,kBAAkB,KAA0B;AACnD,MAAI,EAAE,eAAe,WAAY,QAAO;AAGxC,QAAM,cAAc,IAAI,KAAK,CAAC,MAAM;AAElC,WAAQ,EAAU,SAAS;AAAA,EAC7B,CAAC;AAED,MAAI,aAAa;AAEf,UAAM,OAAQ,YAAoB;AAElC,QAAI,OAAO,SAAS,YAAY,KAAK,WAAW,IAAI,GAAG;AACrD,aAAO;AAAA,IACT;AACA,QAAI,OAAO,SAAS,YAAY,MAAM,QAAQ,OAAO,KAAK,SAAS,UAAU;AAC3E,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AAGA,QAAM,MAAM,IAAI,WAAW;AAC3B,QAAM,QAAQ,IAAI,MAAM,2CAA2C;AACnE,MAAI,MAAO,QAAO,MAAM,CAAC;AAEzB,SAAO;AACT;AAIA,IAAM,uBAA+C;AAAA,EACnD,0CAA0C;AAAA,EAC1C,4CAA4C;AAAA,EAC5C,iCAAiC;AAAA,EACjC,oCAAoC;AAAA,EACpC,oBAAoB;AACtB;AAWO,SAAS,oBAAoB,KAAsB;AAExD,QAAM,aAAa,kBAAkB,GAAG;AACxC,MAAI,cAAc,WAAW,UAAU,IAAI;AACzC,UAAM,UAAU,oBAAoB,UAAU;AAC9C,QAAI,QAAS,QAAO,QAAQ;AAAA,EAC9B;AAEA,QAAM,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAG9D,aAAW,CAAC,SAAS,OAAO,KAAK,OAAO,QAAQ,oBAAoB,GAAG;AACrE,QAAI,OAAO,SAAS,OAAO,EAAG,QAAO;AAAA,EACvC;AAGA,MAAI,OAAO,SAAS,qCAAqC,GAAG;AAC1D,WAAO;AAAA,EACT;AACA,MAAI,OAAO,SAAS,eAAe,KAAK,OAAO,SAAS,eAAe,GAAG;AACxE,WAAO;AAAA,EACT;AACA,MAAI,OAAO,SAAS,4BAA4B,GAAG;AACjD,WAAO,iEAAiE,SAAS,EAAE,IAAI;AAAA,EACzF;AAIA,MAAI,UAAU,OACX,QAAQ,sCAAsC,EAAE,EAChD,QAAQ,0BAA0B,EAAE,EACpC,QAAQ,wBAAwB,EAAE,EAClC,QAAQ,+BAA+B,EAAE,EACzC,QAAQ,6CAA6C,EAAE,EACvD,KAAK;AAGR,QAAM,WAAW,QAAQ,MAAM,wCAAwC;AACvE,MAAI,UAAU;AACZ,UAAM,UAAU,oBAAoB,SAAS,CAAC,CAAQ;AACtD,QAAI,QAAS,QAAO,QAAQ;AAE5B,UAAM,WAAW,SAAS,EAAE,gBAAgB,SAAS,QAAQ;AAC7D,cAAU,iDAAiD,SAAS,CAAC,CAAC,8BAA8B,QAAQ;AAAA,EAC9G;AAEA,SAAO;AACT;;;ADzYA,IAAI,gBAAqB;AAEzB,IAAI,gBAAqB;AAQzB,SAAS,iBAAiB;AACxB,QAAM,OAAO,WAAW;AACxB,SAAO;AAAA,IACL,KAAK,IAAI,CAAC,QAAQ,KAAK,KAAK,EAAE,YAAY,GAAG,SAAS,IAAM,CAAC,CAAC;AAAA,IAC9D,EAAE,MAAM,OAAO,YAAY,EAAE;AAAA,EAC/B;AACF;AAEO,SAAS,kBAAkB;AAChC,QAAM,QAAQ,SAAS;AAEvB,MAAI,iBAAiB,cAAc,OAAO,OAAO,MAAM,IAAI;AACzD,oBAAgB;AAAA,EAClB;AACA,MAAI,CAAC,eAAe;AAClB,oBAAgB,mBAAmB;AAAA,MACjC;AAAA,MACA,WAAW,eAAe;AAAA,IAC5B,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEO,SAAS,kBAAkB;AAChC,QAAM,QAAQ,SAAS;AAEvB,MAAI,iBAAiB,cAAc,OAAO,OAAO,MAAM,IAAI;AACzD,oBAAgB;AAAA,EAClB;AACA,MAAI,CAAC,eAAe;AAClB,UAAM,UAAU,oBAAoB,kBAAkB,CAAC;AACvD,oBAAgB,mBAAmB;AAAA,MACjC;AAAA,MACA;AAAA,MACA,WAAW,eAAe;AAAA,IAC5B,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAMO,SAAS,eAAe;AAC7B,kBAAgB;AAChB,kBAAgB;AAClB;AAEO,SAAS,aAAa;AAC3B,SAAO,oBAAoB,kBAAkB,CAAC;AAChD;AAKA,eAAsB,yBAAyB;AAC7C,QAAM,SAAS,gBAAgB;AAC/B,QAAM,EAAE,cAAc,qBAAqB,IACzC,MAAM,OAAO,mBAAmB;AAClC,MAAI,MAAO,eAAe,OAAQ;AAClC,MAAI,MAAO,uBAAuB,OAAQ;AAO1C,MAAI;AACJ,MAAI;AACF,YAAQ,MAAM,OAAO,SAAS,GAAG;AAAA,EACnC,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,SAAS,QAAQ,SAAS,UAAa,OAAO,MAAM,MAAM,OAAO,OAAO;AAC1E,UAAM,OAAO;AACb,QAAI,MAAM,IAAK,OAAM;AAAA,EACvB;AACA,SAAO,EAAE,cAAc,KAAK,sBAAsB,IAAI;AACxD;AAUO,IAAM,YAAY;AAAA,EACvB,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AACV;AAcA,eAAsB,mBACpB,UACA,eAAe,IACE;AACjB,QAAM,QAAQ,iBAAiB;AAC/B,MAAI;AACF,UAAM,EAAE,aAAa,IAAI,MAAM,uBAAuB;AACtD,UAAM,UAAU,WAAW,eAAe;AAC1C,WAAO,UAAU,QAAQ,UAAU;AAAA,EACrC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAOA,IAAM,cAAc;AACpB,IAAM,iBAAiB;AACvB,IAAM,+BAA+B;AACrC,IAAM,qBAAqB;AAC3B,IAAM,uBAAuB;AAE7B,SAAS,mBAAmB,KAAsB;AAChD,SAAO,IAAI,SAAS,qCAAqC;AAC3D;AAEA,SAAS,kBAAkB,KAAsB;AAC/C,SAAO,IAAI,SAAS,eAAe,KAAK,IAAI,SAAS,eAAe;AACtE;AAEA,SAAS,iBAAiB,KAAuB;AAC/C,QAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,SAAO,mBAAmB,GAAG,KAAK,kBAAkB,GAAG;AACzD;AAEA,SAAS,SAAS,MAA8D;AAC9E,SAAO;AAAA,IACL,cAAe,KAAK,eAAe,qBAAsB;AAAA,IACzD,sBAAuB,KAAK,uBAAuB,qBAAsB;AAAA,EAC3E;AACF;AAWA,eAAsB,mBAA2C;AAC/D,QAAM,SAAS,gBAAgB;AAC/B,QAAM,UAAU,WAAW,EAAE;AAC7B,QAAM,CAAC,WAAW,OAAO,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC7C,OAAO,oBAAoB,EAAE,SAAS,UAAU,SAAS,CAAC;AAAA,IAC1D,OAAO,oBAAoB,EAAE,SAAS,UAAU,UAAU,CAAC;AAAA,EAC7D,CAAC;AACD,MAAI,WAAW,UAAW,QAAO;AAGjC,QAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,4BAA4B,CAAC;AACpE,QAAM,CAAC,YAAY,QAAQ,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC/C,OAAO,oBAAoB,EAAE,SAAS,UAAU,SAAS,CAAC;AAAA,IAC1D,OAAO,oBAAoB,EAAE,SAAS,UAAU,UAAU,CAAC;AAAA,EAC7D,CAAC;AACD,SAAO,WAAW,aAAa,aAAa;AAC9C;AAOA,eAAe,sBAAoC;AACjD,QAAM,aAAa,MAAM,iBAAiB;AAC1C,MAAI,eAAe,MAAM;AACvB,UAAM,IAAI,MAAM,iDAA4C;AAAA,EAC9D;AAEA,UAAQ,KAAK,oDAAoD,UAAU,KAAK;AAChF,QAAM,SAAS,gBAAgB;AAC/B,QAAM,UAAU,WAAW;AAG3B,QAAM,EAAE,cAAc,qBAAqB,IAAI,MAAM,uBAAuB;AAC5E,QAAM,OAAO,MAAM,OAAO,gBAAgB;AAAA,IACxC;AAAA,IACA,OAAO,OAAO;AAAA,IACd,IAAI,QAAQ;AAAA,IACZ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,cAAc,eAAe;AAAA,IAC7B,sBAAsB,uBAAuB;AAAA,EAC/C,CAAC;AAED,QAAM,SAAS,gBAAgB;AAC/B,QAAM,OAAO,0BAA0B,EAAE,KAAK,CAAC;AAC/C,UAAQ,KAAK,2BAA2B,UAAU,aAAa;AAC/D,SAAO;AACT;AAMA,eAAsB,gBAAgC;AACpD,QAAM,SAAgB,CAAC;AACvB,SAAQ,MAAM,iBAAiB,MAAO,MAAM;AAC1C,WAAO,KAAK,MAAM,oBAAoB,CAAC;AAAA,EACzC;AACA,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,IAAI,MAAM,iDAA4C;AAAA,EAC9D;AACA,SAAO;AACT;AAUA,eAAe,UAAU,MAAgB,UAAiD;AACxF,QAAM,SAAS,gBAAgB;AAC/B,QAAM,UAAU,WAAW;AAC3B,MAAI,OAAO,MAAM,uBAAuB;AAGxC,SAAQ,MAAM,iBAAiB,MAAO,MAAM;AAC1C,UAAM,oBAAoB;AAAA,EAC5B;AAEA,MAAI,QAAQ,MAAM,OAAO,oBAAoB,EAAE,SAAS,QAAQ,SAAS,UAAU,UAAU,CAAC;AAE9F,WAAS,UAAU,GAAG,WAAW,aAAa,WAAW;AACvD,QAAI;AACF,aAAO,MAAM,KAAK,EAAE,GAAG,UAAU,GAAG,MAAM,MAAM,CAAC;AAAA,IACnD,SAAS,KAAK;AACZ,UAAI,WAAW,eAAe,CAAC,iBAAiB,GAAG,GAAG;AAEpD,cAAM,IAAI,MAAM,oBAAoB,GAAG,CAAC;AAAA,MAC1C;AAEA,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,cAAQ,KAAK,WAAW,UAAU,CAAC,IAAI,WAAW,KAAK,kBAAkB,GAAG,IAAI,qBAAqB,aAAa,KAAK;AAGvH,YAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,cAAc,CAAC;AAEtD,UAAI,kBAAkB,GAAG,GAAG;AAE1B,gBAAQ,MAAM,OAAO,oBAAoB,EAAE,SAAS,QAAQ,SAAS,UAAU,UAAU,CAAC;AAAA,MAC5F,OAAO;AACL,eAAO,SAAS,IAAI;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AACA,QAAM,IAAI,MAAM,8BAA8B;AAChD;AAMA,eAAsB,gBAAgB,UAA6C;AACjF,QAAM,SAAS,gBAAgB;AAC/B,SAAO,UAAU,CAAC,MAAM,OAAO,gBAAgB,CAAC,GAAG,QAAQ;AAC7D;AAMA,eAAsB,uBAAuB,UAA6C;AACxF,QAAM,SAAS,gBAAgB;AAC/B,SAAO,UAAU,CAAC,MAAM,OAAO,cAAc,CAAC,GAAG,QAAQ;AAC3D;AAUA,eAAsB,eAAe,MAAwC;AAC3E,QAAM,SAAS,gBAAgB;AAC/B,MAAI;AACF,WAAO,MAAM,OAAO,0BAA0B,EAAE,KAAK,CAAC;AAAA,EAExD,SAAS,KAAU;AAEjB,UAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,QAAI,IAAI,SAAS,SAAS,KAAK,IAAI,SAAS,WAAW,GAAG;AACxD,UAAK,MAAM,iBAAiB,MAAO,MAAM;AACvC,gBAAQ,KAAK,QAAQ,IAAI,uDAAkD;AAC3E,eAAQ,MAAM,iBAAiB,MAAO,MAAM;AAC1C,gBAAM,oBAAoB;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/governor.ts","../src/lib/generated/proposal-state.ts"],"sourcesContent":["/**\n * Governor contract wrapper — reads/writes to SyndicateGovernor.\n *\n * Per-vault governor design: the factory deploys ONE governor per vault\n * (BeaconProxy). Every helper takes the vault address and resolves its\n * governor via `factory.governorOf(vault)` (memoized per chain+vault —\n * the binding is set once at createSyndicate and never changes).\n *\n * Protocol-wide fee parameters (protocol/guardian fee bps + recipients)\n * live on the separate ProtocolConfig contract, resolved via\n * `factory.protocolConfig()`.\n */\n\nimport type { Address, Hex, Log } from \"viem\";\nimport { parseEventLogs } from \"viem\";\nimport { getPublicClient, getAccount, writeContractWithRetry, waitForReceipt } from \"./client.js\";\nimport { getChain } from \"./network.js\";\nimport { SHERWOOD } from \"./addresses.js\";\nimport { SYNDICATE_GOVERNOR_ABI, SYNDICATE_FACTORY_ABI, PROTOCOL_CONFIG_ABI } from \"./abis.js\";\nimport { PROPOSAL_STATE, PROPOSAL_STATES } from \"./generated/proposal-state.js\";\n\n// ── Types ──\n\nexport interface GovernorParams {\n votingPeriod: bigint;\n executionWindow: bigint;\n vetoThresholdBps: bigint;\n maxPerformanceFeeBps: bigint;\n cooldownPeriod: bigint;\n collaborationWindow: bigint;\n maxCoProposers: bigint;\n minStrategyDuration: bigint;\n maxStrategyDuration: bigint;\n}\n\nexport interface StrategyProposal {\n id: bigint;\n proposer: Address;\n vault: Address;\n /** Strategy contract address whose `positionValue()` the vault polls\n * for live NAV. Set at propose time, immutable thereafter. address(0)\n * for queue-only proposals (no live NAV). */\n strategy: Address;\n metadataURI: string;\n /** Agent fee (bps) snapshotted from the vault's `agentFeeBps` at propose. */\n performanceFeeBps: bigint;\n strategyDuration: bigint;\n votesFor: bigint;\n votesAgainst: bigint;\n votesAbstain: bigint;\n snapshotTimestamp: bigint;\n voteEnd: bigint;\n reviewEnd: bigint;\n executeBy: bigint;\n executedAt: bigint;\n state: number;\n vetoThresholdBps: bigint;\n /** Fee-recipient snapshot taken from ProtocolConfig at propose time.\n *\n * THE FLAT `snapshot*FeeBps` SCALARS AND `selfManagesFees` ARE GONE: the\n * splits became structs (`snapshotMgmtSplit`/`snapshotPerfSplit` below) and\n * self-managed fees were removed outright. Every field below is positional\n * in the on-chain tuple — omitting or reordering one corrupts the decode of\n * everything after it. */\n snapshotProtocolFeeRecipient: Address;\n snapshotGuardiansFeeRecipient: Address;\n /** Risk envelope declared at propose: the net-outflow ceiling the execute\n * batch is metered against. */\n maxCapital: bigint;\n /** Declared drawdown bound, bps of `effectiveMaxCapital`. */\n maxDrawdownBps: number;\n /** Tier the envelope resolved to; drives how much coverage is required. */\n envelopeTier: number;\n requiredCoverage: bigint;\n /** WOOD bond pulled from the proposer at propose, held by the escrow. */\n proposerBondWood: bigint;\n proposerBondEscrow: Address;\n /** Management-fee split snapshotted from ProtocolConfig at propose. */\n snapshotMgmtSplit: { agentBps: number; protocolBps: number; guardianBps: number };\n /** Performance-fee split snapshotted from ProtocolConfig at propose. */\n snapshotPerfSplit: { agentBps: number; protocolBps: number; guardianBps: number; ownerBps: number };\n /** The ledger the bond's reclaim gates read — bound alongside the escrow so\n * re-pointing either slot later cannot strand the bond. */\n proposerBondLedger: Address;\n /** `maxCapital` after any scaling applied at execute. */\n effectiveMaxCapital: bigint;\n}\n\nexport interface CoProposer {\n agent: Address;\n splitBps: bigint;\n}\n\nexport interface BatchCall {\n target: Address;\n data: Hex;\n value: bigint;\n}\n\n// ProposalState ordering is code-generated from the Solidity enum\n// (contracts/src/interfaces/ISyndicateGovernor.sol) — `npm run codegen`.\n// History: PR #229 inserted GuardianReview at index 2 and this hand-kept\n// mirror drifted for ~2 months, mislabeling Approved (3) as Rejected and\n// making `proposal execute` reject valid approved proposals. The generated\n// module (checked by codegen-drift.test.ts + CI) makes that impossible.\nexport { PROPOSAL_STATE, PROPOSAL_STATES };\n\nexport const VOTE_TYPE = {\n For: 0,\n Against: 1,\n Abstain: 2,\n} as const;\n\n// ── Client-side action gates (mirror SyndicateGovernor) ──\n//\n// The governor's mutating entrypoints resolve state INLINE and can act on a\n// state the read-only `getProposalState` view is still reporting as\n// GuardianReview. The client gates below reproduce that divergence so the CLI\n// stops refusing txs the contract would accept (issue #452).\n\n/** Result of the `proposal execute` client gate. */\nexport type ExecuteGate =\n | { kind: \"send\" } // state == Approved — straightforward execute.\n | { kind: \"send-self-resolve\" } // GuardianReview, window elapsed, still within\n // the execution window — executeProposal\n // self-resolves the (cold-start) review inline.\n | { kind: \"refuse-review-open\" } // GuardianReview, review window still open — the\n // tx WOULD revert (ProposalNotApproved).\n | { kind: \"refuse-expired\" } // GuardianReview past executeBy — the inline\n // self-resolve maps to Expired, tx WOULD revert.\n | { kind: \"refuse-state\" }; // any other non-executable state.\n\n/**\n * Decide whether `executeProposal(id)` should be broadcast.\n *\n * Mirrors `SyndicateGovernor.executeProposal` (contracts/src/SyndicateGovernor.sol:342)\n * vs. the `getProposalState` view:\n * - The view (`_resolveStateView` @824 / `_resolveAfterVote` @865) keeps\n * reporting `GuardianReview` once the review window elapses but the registry\n * has not cached a resolution — a zero-guardian / never-opened cold-start\n * review NEVER auto-opens, so the view is stuck there indefinitely.\n * - `executeProposal` runs the MUTATING `_resolveState` (@789) which, when the\n * window elapsed (`now > reviewEnd`), calls `registry.resolveReview` inline\n * (cold-start ⇒ blocked=false) and maps to Approved when `now <= executeBy`\n * (else Expired) — then executes in the same tx.\n * Invariant `voteEnd < reviewEnd < executeBy` (@528-530) holds for any past-vote\n * proposal, so `reviewEnd`/`executeBy` are always populated in the GuardianReview\n * branch.\n *\n * `now` MUST be chain time (latest block timestamp), not wall-clock — on a\n * time-warped vnet the two diverge and the contract compares against chain time.\n */\nexport function evaluateExecuteGate(args: {\n state: number;\n reviewEnd: bigint;\n executeBy: bigint;\n now: bigint;\n}): ExecuteGate {\n const { state, reviewEnd, executeBy, now } = args;\n if (state === PROPOSAL_STATE.Approved) return { kind: \"send\" };\n if (state === PROPOSAL_STATE.GuardianReview) {\n if (now <= reviewEnd) return { kind: \"refuse-review-open\" };\n if (now > executeBy) return { kind: \"refuse-expired\" };\n return { kind: \"send-self-resolve\" };\n }\n return { kind: \"refuse-state\" };\n}\n\n/**\n * Classification for the `resolve-reviews` keeper.\n * - `resolvable`: an OPENED, unresolved review past its window — needs a real\n * `resolveReview` tx (computes block quorum, may slash approvers).\n * - `cold-start`: an UNOPENED, unresolved review past its window — the\n * zero-guardian case. `resolveReview` would only mark it resolved/not-blocked\n * (GuardianRegistry.resolveReview @639-643), which `executeProposal`\n * already does inline, so the keeper should report it (pointing at\n * `proposal execute`) rather than spend a redundant tx.\n * - `none`: not past window yet, or already resolved.\n */\nexport type ReviewResolveClass = \"resolvable\" | \"cold-start\" | \"none\";\n\nexport function classifyReview(args: {\n opened: boolean;\n resolved: boolean;\n reviewEnd: bigint;\n now: bigint;\n}): ReviewResolveClass {\n const { opened, resolved, reviewEnd, now } = args;\n const pastWindow = reviewEnd > 0n && now >= reviewEnd;\n if (!pastWindow || resolved) return \"none\";\n return opened ? \"resolvable\" : \"cold-start\";\n}\n\n/**\n * Classification for the `open-reviews` keeper (SHE-162), the other leg of\n * `classifyReview`: `GuardianRegistry.openReview(governor, proposalId)` is\n * permissionless, and an unopened review clears by default (`outcomeOf`:\n * `if (!r.opened) return ReviewOutcome.Cleared;`) — nobody opening it means\n * proposals execute unreviewed.\n * - `openable`: a registered, unopened, unresolved review inside the open\n * window `[voteEnd, reviewEnd)` — needs an `openReview` keeper tx.\n * - `none`: never registered (collapsed window, `reviewEnd <= voteEnd`),\n * already opened or resolved, or outside the window. Past `reviewEnd`\n * opening is pointless — that is `classifyReview`'s territory.\n */\nexport type ReviewOpenClass = \"openable\" | \"none\";\n\nexport function classifyReviewOpen(args: {\n opened: boolean;\n resolved: boolean;\n voteEnd: bigint;\n reviewEnd: bigint;\n now: bigint;\n}): ReviewOpenClass {\n const { opened, resolved, voteEnd, reviewEnd, now } = args;\n // Collapsed window ⇒ the review was never registered with the registry;\n // openReview would revert ReviewNotOpen (r.voteEnd == 0).\n const registered = voteEnd > 0n && reviewEnd > voteEnd;\n // Contract gate is `now >= voteEnd` (inclusive); past reviewEnd the open\n // is moot — the review resolves/clears without it.\n const inWindow = now >= voteEnd && now < reviewEnd;\n if (!registered || !inWindow || opened || resolved) return \"none\";\n return \"openable\";\n}\n\n/**\n * Per-proposal scan step shared by the `open-reviews` / `resolve-reviews`\n * keepers. Runs `load` for every id concurrently; an id whose load throws is\n * RECORDED in `failures` (id + error), never silently swallowed — a systemic\n * failure (e.g. an ABI mismatch, the SHE-88/SHE-49 class) must surface as\n * \"N of M failed to load\", not as a clean \"nothing to do\". The loadable ids\n * are still returned so the keeper can process every candidate it CAN see.\n */\nexport interface ReviewScanFailure {\n id: bigint;\n error: unknown;\n}\n\nexport async function scanReviewCandidates<T>(\n ids: readonly bigint[],\n load: (id: bigint) => Promise<T>,\n): Promise<{ candidates: T[]; failures: ReviewScanFailure[] }> {\n const failures: ReviewScanFailure[] = [];\n const settled = await Promise.all(\n ids.map(async (id): Promise<{ ok: true; value: T } | { ok: false }> => {\n try {\n return { ok: true, value: await load(id) };\n } catch (error) {\n failures.push({ id, error });\n return { ok: false };\n }\n }),\n );\n const candidates: T[] = [];\n for (const s of settled) if (s.ok) candidates.push(s.value);\n return { candidates, failures };\n}\n\n/**\n * A mined-but-REVERTED tx still yields a receipt — `waitForReceipt` resolves\n * with `status: \"reverted\"` and does not throw. A keeper counting that as a\n * success would report \"opened/resolved\" for a tx that changed nothing. Call\n * this on every keeper receipt: it throws (like a send failure) unless the\n * tx actually succeeded, so the caller's catch path drives the exit code.\n */\nexport function assertReceiptSuccess(receipt: { status: string }): void {\n if (receipt.status !== \"success\") {\n throw new Error(`transaction mined but reverted on-chain (status=${receipt.status})`);\n }\n}\n\n// ── Duration parser ──\n\nexport function parseDuration(input: string): bigint {\n const match = input.match(/^(\\d+)(d|h|m|s)?$/);\n if (!match) throw new Error(`Invalid duration: ${input}`);\n const value = BigInt(match[1]);\n switch (match[2]) {\n case \"d\":\n return value * 86400n;\n case \"h\":\n return value * 3600n;\n case \"m\":\n return value * 60n;\n case \"s\":\n case undefined:\n return value;\n default:\n throw new Error(`Unknown duration unit: ${match[2]}`);\n }\n}\n\n// ── Address helpers ──\n\n// governorOf(vault) is set once at createSyndicate and never rebinds, so\n// it is safe to memoize per chain+vault for the lifetime of the process.\nconst governorCache = new Map<string, Address>();\n\n/** Resolve the per-vault governor via `factory.governorOf(vault)`. */\nexport async function getGovernorOf(vault: Address): Promise<Address> {\n const key = `${getChain().id}:${vault.toLowerCase()}`;\n const cached = governorCache.get(key);\n if (cached) return cached;\n\n const client = getPublicClient();\n const governor = await client.readContract({\n address: SHERWOOD().FACTORY,\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"governorOf\",\n args: [vault],\n }) as Address;\n\n if (governor === \"0x0000000000000000000000000000000000000000\") {\n throw new Error(`No governor registered for vault ${vault} — is it a factory-created vault?`);\n }\n\n governorCache.set(key, governor);\n return governor;\n}\n\n// ProtocolConfig is a protocol-wide singleton behind the factory — same\n// set-once semantics as governorOf, memoized per chain.\nconst protocolConfigCache = new Map<number, Address>();\n\n/** Resolve the ProtocolConfig address via `factory.protocolConfig()`. */\nexport async function getProtocolConfigAddress(): Promise<Address> {\n const chainId = getChain().id;\n const cached = protocolConfigCache.get(chainId);\n if (cached) return cached;\n\n const client = getPublicClient();\n const config = await client.readContract({\n address: SHERWOOD().FACTORY,\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"protocolConfig\",\n }) as Address;\n\n protocolConfigCache.set(chainId, config);\n return config;\n}\n\n// ── Read helpers ──\n\nexport async function getGovernorParams(vault: Address): Promise<GovernorParams> {\n const client = getPublicClient();\n const result = await client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getGovernorParams\",\n }) as {\n votingPeriod: bigint;\n executionWindow: bigint;\n vetoThresholdBps: bigint;\n maxPerformanceFeeBps: bigint;\n cooldownPeriod: bigint;\n collaborationWindow: bigint;\n maxCoProposers: bigint;\n minStrategyDuration: bigint;\n maxStrategyDuration: bigint;\n };\n return result;\n}\n\nexport async function getProposal(vault: Address, id: bigint): Promise<StrategyProposal> {\n const client = getPublicClient();\n const result = await client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getProposal\",\n args: [id],\n }) as StrategyProposal;\n return result;\n}\n\nexport async function getProposalState(vault: Address, id: bigint): Promise<number> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getProposalState\",\n args: [id],\n }) as Promise<number>;\n}\n\nexport async function proposalCount(vault: Address): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"proposalCount\",\n }) as Promise<bigint>;\n}\n\nexport async function getVoteWeight(vault: Address, proposalId: bigint, voter: Address): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getVoteWeight\",\n args: [proposalId, voter],\n }) as Promise<bigint>;\n}\n\nexport async function hasVoted(vault: Address, proposalId: bigint, voter: Address): Promise<boolean> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"hasVoted\",\n args: [proposalId, voter],\n }) as Promise<boolean>;\n}\n\n// `getProposalCalls` (concat of execute + settle) was dropped in V1.5\n// to reclaim governor bytecode under EIP-170. Use `getExecuteCalls`\n// + `getSettlementCalls` instead — same data, no on-chain copy loop.\n\nexport async function getExecuteCalls(vault: Address, proposalId: bigint): Promise<BatchCall[]> {\n const client = getPublicClient();\n const result = await client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getExecuteCalls\",\n args: [proposalId],\n }) as { target: Address; data: Hex; value: bigint }[];\n return result.map((c) => ({ target: c.target, data: c.data, value: c.value }));\n}\n\nexport async function getSettlementCalls(vault: Address, proposalId: bigint): Promise<BatchCall[]> {\n const client = getPublicClient();\n const result = await client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getSettlementCalls\",\n args: [proposalId],\n }) as { target: Address; data: Hex; value: bigint }[];\n return result.map((c) => ({ target: c.target, data: c.data, value: c.value }));\n}\n\n// Per-vault governor: `getRegisteredVaults` / `isRegisteredVault` were\n// removed on-chain — a governor serves exactly one vault (`governor.vault()`).\n// Enumerate vaults via the factory (`getAllActiveSyndicates`) instead.\n\nexport async function getActiveProposal(vault: Address): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getActiveProposal\",\n }) as Promise<bigint>;\n}\n\nexport async function getCooldownEnd(vault: Address): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getCooldownEnd\",\n }) as Promise<bigint>;\n}\n\nexport async function openProposalCount(vault: Address): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"openProposalCount\",\n }) as Promise<bigint>;\n}\n\nexport async function getCapitalSnapshot(vault: Address, proposalId: bigint): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"getCapitalSnapshot\",\n args: [proposalId],\n }) as Promise<bigint>;\n}\n\n/**\n * Extract proposalId from ProposalCreated event logs.\n * Returns undefined if the event is not found or parsing fails.\n */\nexport function parseProposalIdFromLogs(logs: Log[]): bigint | undefined {\n try {\n const parsed = parseEventLogs({\n abi: SYNDICATE_GOVERNOR_ABI,\n logs,\n eventName: \"ProposalCreated\",\n });\n return parsed[0]?.args.proposalId;\n } catch {\n return undefined;\n }\n}\n\n// ── Write helpers ──\n\n/**\n * The risk envelope a proposal commits to.\n *\n * `maxCapital` is in ASSET UNITS (the vault's own asset, at its decimals), not\n * a share. `maxDrawdownBps` is the declared loss allowance in basis points,\n * 0..10_000, and is what the settle-price guard sizes its tolerance from — so\n * it is a real declaration to voters and guardians, not a formality.\n */\nexport interface RiskEnvelope {\n maxCapital: bigint;\n maxDrawdownBps: number;\n}\n\n/**\n * @param executeCallCaps one entry per execute call, in ASSET UNITS: the\n * maximum GROSS OUTFLOW of the vault asset measured around that call. A call\n * that moves nothing out (an `approve`, or a settlement that only returns\n * assets) takes 0. Summed per batch and required to be <= `maxCapital`;\n * the execute and settlement batches are bounded independently because they\n * run in separate transactions.\n */\nexport async function propose(\n vault: Address,\n strategy: Address,\n metadataURI: string,\n strategyDuration: bigint,\n envelope: RiskEnvelope,\n executeCalls: BatchCall[],\n executeCallCaps: bigint[],\n settlementCalls: BatchCall[],\n settlementCallCaps: bigint[],\n coProposers: CoProposer[] = [],\n): Promise<{ hash: Hex; proposalId: bigint }> {\n // Fail here rather than as an on-chain `CallCapsLengthMismatch` — the\n // governor's revert names the mismatch but not which batch, and a caller that\n // built the arrays in different places will not know.\n if (executeCallCaps.length !== executeCalls.length) {\n throw new Error(\n `executeCallCaps has ${executeCallCaps.length} entries for ${executeCalls.length} execute calls — every call must declare exactly one cap`,\n );\n }\n if (settlementCallCaps.length !== settlementCalls.length) {\n throw new Error(\n `settlementCallCaps has ${settlementCallCaps.length} entries for ${settlementCalls.length} settlement calls — every call must declare exactly one cap`,\n );\n }\n\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"propose\",\n args: [\n vault,\n strategy,\n metadataURI,\n strategyDuration,\n { maxCapital: envelope.maxCapital, maxDrawdownBps: envelope.maxDrawdownBps },\n executeCalls,\n executeCallCaps,\n settlementCalls,\n settlementCallCaps,\n coProposers,\n ],\n });\n\n const receipt = await waitForReceipt(hash);\n\n // Parse proposalId from the ProposalCreated event in the receipt logs.\n // Falls back to proposalCount() if event parsing fails.\n let proposalId = parseProposalIdFromLogs(receipt.logs);\n if (proposalId === undefined) {\n try {\n proposalId = await proposalCount(vault);\n } catch {\n proposalId = 0n;\n }\n }\n\n return { hash: receipt.transactionHash, proposalId };\n}\n\nexport async function vote(vault: Address, proposalId: bigint, support: number): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"vote\",\n args: [proposalId, support],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\nexport async function executeProposal(vault: Address, proposalId: bigint): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"executeProposal\",\n args: [proposalId],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\n/**\n * Walk a proposal's executeCalls and pick the strategy clone — the\n * target of the call whose selector matches `BaseStrategy.execute()`\n * (0x61461954). This is the canonical entry point that every Sherwood\n * strategy template inherits from BaseStrategy, so it's a reliable\n * marker even across template families (Moonwell / Aerodrome /\n * Hyperliquid / Mamo / Venice / Portfolio).\n *\n * Returns null when no execute() call is present (e.g. proposals that\n * only do approves and direct ERC-20 transfers without a strategy).\n */\nexport function detectStrategyAdapter(\n calls: { target: Address; data: Hex; value: bigint }[],\n): Address | null {\n const STRATEGY_EXECUTE_SELECTOR = \"0x61461954\";\n for (const call of calls) {\n if (call.data.slice(0, 10).toLowerCase() === STRATEGY_EXECUTE_SELECTOR) {\n return call.target;\n }\n }\n return null;\n}\n\nexport async function settleProposal(vault: Address, proposalId: bigint): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"settleProposal\",\n args: [proposalId],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\nexport async function emergencySettle(vault: Address, proposalId: bigint, calls: BatchCall[]): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"emergencySettleWithCalls\",\n args: [proposalId, calls],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\nexport async function cancelProposal(vault: Address, proposalId: bigint): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"cancelProposal\",\n args: [proposalId],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\nexport async function emergencyCancel(vault: Address, proposalId: bigint): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"emergencyCancel\",\n args: [proposalId],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\n// ── Parameter setters ──\n//\n// Per-vault governor: governance parameters are per-vault now, set by the\n// VAULT OWNER on that vault's governor. Setters revert with\n// `ParamsFrozenDuringProposal` while any proposal is open on the vault.\n\ntype GovernorParamSetter =\n | \"setVotingPeriod\"\n | \"setExecutionWindow\"\n | \"setVetoThresholdBps\"\n | \"setMaxPerformanceFeeBps\"\n | \"setMaxStrategyDuration\"\n | \"setCooldownPeriod\";\n\nasync function setGovernorParam(\n vault: Address,\n functionName: GovernorParamSetter,\n value: bigint,\n): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName,\n args: [value],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\nexport async function setVotingPeriod(vault: Address, seconds: bigint): Promise<Hex> {\n return setGovernorParam(vault, \"setVotingPeriod\", seconds);\n}\n\nexport async function setExecutionWindow(vault: Address, seconds: bigint): Promise<Hex> {\n return setGovernorParam(vault, \"setExecutionWindow\", seconds);\n}\n\nexport async function setVetoThresholdBps(vault: Address, bps: bigint): Promise<Hex> {\n return setGovernorParam(vault, \"setVetoThresholdBps\", bps);\n}\n\nexport async function setMaxPerformanceFeeBps(vault: Address, bps: bigint): Promise<Hex> {\n return setGovernorParam(vault, \"setMaxPerformanceFeeBps\", bps);\n}\n\nexport async function setMaxStrategyDuration(vault: Address, seconds: bigint): Promise<Hex> {\n return setGovernorParam(vault, \"setMaxStrategyDuration\", seconds);\n}\n\nexport async function setCooldownPeriod(vault: Address, seconds: bigint): Promise<Hex> {\n return setGovernorParam(vault, \"setCooldownPeriod\", seconds);\n}\n\nexport async function vetoProposal(vault: Address, proposalId: bigint): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getGovernorOf(vault),\n abi: SYNDICATE_GOVERNOR_ABI,\n functionName: \"vetoProposal\",\n args: [proposalId],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\n// ── ProtocolConfig fee-split setters (protocol-owner only) ──\n//\n// Post-audit ProtocolConfig holds no per-rate protocol fee — the two-number\n// model exposes the SPLITS of the management and performance fees instead,\n// on the protocol-wide config (resolved via `factory.protocolConfig()`).\n\nexport interface MgmtSplit {\n agentBps: number;\n protocolBps: number;\n guardianBps: number;\n}\n\nexport interface PerfSplit extends MgmtSplit {\n ownerBps: number;\n}\n\nexport async function setMgmtSplit(s: MgmtSplit): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getProtocolConfigAddress(),\n abi: PROTOCOL_CONFIG_ABI,\n functionName: \"setMgmtSplit\",\n args: [s],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n\nexport async function setPerfSplit(s: PerfSplit): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: await getProtocolConfigAddress(),\n abi: PROTOCOL_CONFIG_ABI,\n functionName: \"setPerfSplit\",\n args: [s],\n });\n const receipt = await waitForReceipt(hash);\n return receipt.transactionHash;\n}\n","/**\n * AUTO-GENERATED by cli/scripts/codegen-contracts.ts — do not edit.\n * Regenerate: npm run codegen (in cli/)\n *\n * Source of truth: sherwood-protocol src/interfaces/ISyndicateGovernor.sol (enum ProposalState)\n */\n\n/** On-chain `ProposalState` member names, index === Solidity enum value. */\nexport const PROPOSAL_STATES = [\n \"Draft\",\n \"Pending\",\n \"GuardianReview\",\n \"Approved\",\n \"Rejected\",\n \"Expired\",\n \"Executed\",\n \"Settled\",\n \"Cancelled\",\n] as const;\n\nexport type ProposalStateName = (typeof PROPOSAL_STATES)[number];\n\n/** Name → Solidity enum value. */\nexport const PROPOSAL_STATE = {\n Draft: 0,\n Pending: 1,\n GuardianReview: 2,\n Approved: 3,\n Rejected: 4,\n Expired: 5,\n Executed: 6,\n Settled: 7,\n Cancelled: 8,\n} as const;\n"],"mappings":"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","names":[]}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
lookupAgentIdByWallet,
|
|
3
|
-
registerIdentityCommands
|
|
4
|
-
} from "./chunk-6QBGTX2Q.js";
|
|
5
|
-
import "./chunk-OUYMZ5ZC.js";
|
|
6
|
-
import "./chunk-IAM4VIU2.js";
|
|
7
|
-
import "./chunk-QRMZRAMG.js";
|
|
8
|
-
import "./chunk-PVTZMRC6.js";
|
|
9
|
-
import "./chunk-3TZIOAPH.js";
|
|
10
|
-
import "./chunk-F3MDCUGO.js";
|
|
11
|
-
export {
|
|
12
|
-
lookupAgentIdByWallet,
|
|
13
|
-
registerIdentityCommands
|
|
14
|
-
};
|
|
15
|
-
//# sourceMappingURL=identity-ATWV2O7Y.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/session.ts"],"sourcesContent":["/**\n * Session commands — sherwood session check|status|reset\n *\n * Provides agent awareness: catch up on XMTP messages and on-chain events\n * since the last session. Supports one-shot polling (default) and persistent\n * streaming (--stream).\n *\n * Usage:\n * sherwood session check <name> — one-shot catch-up (JSON to stdout)\n * sherwood session check <name> --stream — persistent stream (JSON lines to stdout)\n * sherwood session check <name> --no-xmtp — skip XMTP entirely (on-chain events only)\n * sherwood session status [name] — show session cursor positions\n * sherwood session reset <name> [--full] — reset session cursors\n *\n * Env: SHERWOOD_SKIP_XMTP=1 is equivalent to --no-xmtp.\n */\n\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport type { Address } from \"viem\";\nimport { resolveFund } from \"../lib/ens.js\";\nimport { getPublicClient } from \"../lib/client.js\";\nimport { getGovernorOf } from \"../lib/governor.js\";\nimport { SYNDICATE_VAULT_ABI } from \"../lib/abis.js\";\nimport {\n getSession,\n updateSession,\n resetSession,\n getAllSessions,\n} from \"../lib/session.js\";\nimport {\n getVaultEvents,\n getGovernorEvents,\n getGuardianRegistryEvents,\n getStakedWoodEvents,\n getCurrentBlock,\n enrichProposalEvents,\n type ChainEvent,\n} from \"../lib/events.js\";\nimport { SHERWOOD } from \"../lib/addresses.js\";\nimport type { ChatEnvelope } from \"../lib/types.js\";\nimport { loadConfig } from \"../lib/config.js\";\n\n// Lazy-load XMTP to avoid breaking session commands when @xmtp/cli is missing\nasync function loadXmtp() {\n return import(\"../lib/xmtp.js\");\n}\n\n// ── Output types ──\n\ninterface SessionMessage {\n source: \"xmtp\";\n id: string;\n from: string;\n type: string;\n text: string;\n sentAt: string; // ISO 8601\n}\n\ninterface SessionCheckResult {\n fund: string;\n messages: SessionMessage[];\n events: ChainEvent[];\n meta: {\n newMessages: number;\n newEvents: number;\n blocksScanned: number;\n lastCheckAt: string; // ISO 8601\n };\n}\n\n// ── Helpers ──\n\n/** Resolve the per-vault governor address from the vault contract. */\nasync function resolveGovernor(vaultAddress: Address): Promise<Address> {\n const client = getPublicClient();\n try {\n const governor = await client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"governor\",\n });\n return governor as Address;\n } catch {\n // Vault didn't answer — fall back to the factory's per-vault mapping.\n return getGovernorOf(vaultAddress);\n }\n}\n\n/** Convert an XMTP message to session output format. */\nfunction toSessionMessage(msg: {\n id: string;\n senderInboxId: string;\n content: string;\n sentAt: Date;\n}): SessionMessage {\n let type = \"MESSAGE\";\n let text = msg.content;\n let from = msg.senderInboxId;\n\n try {\n const envelope: ChatEnvelope = JSON.parse(msg.content);\n type = envelope.type;\n text = envelope.text || envelope.type;\n from = envelope.from || msg.senderInboxId;\n } catch {\n // Plain text message\n }\n\n return {\n source: \"xmtp\",\n id: msg.id,\n from,\n type,\n text,\n sentAt: msg.sentAt.toISOString(),\n };\n}\n\n// ── Command handlers ──\n\nasync function handleCheck(\n name: string,\n stream: boolean,\n noXmtp: boolean,\n): Promise<void> {\n // Resolve fund\n const fund = await resolveFund(name);\n const vaultAddress = fund.vault;\n const governorAddress = await resolveGovernor(vaultAddress);\n\n // Load or initialize session\n const session = getSession(name);\n const currentBlock = await getCurrentBlock();\n\n // On first run: look back ~1000 blocks (~8 min on Base)\n const fromBlock = session?.lastBlockNumber\n ? BigInt(session.lastBlockNumber) + 1n\n : currentBlock > 1000n\n ? currentBlock - 1000n\n : 0n;\n\n const lastMessageTimestamp = session?.lastMessageTimestamp || 0;\n\n // ── Fetch XMTP messages ──\n // Skipped entirely when noXmtp is true — used by callers that own XMTP\n // themselves (e.g. the sherwood-monitor Hermes plugin via its bundled\n // sidecar) or when the local @xmtp/node-bindings load would fail.\n let messages: SessionMessage[] = [];\n if (!noXmtp) {\n try {\n const xmtp = await loadXmtp();\n const groupId = await xmtp.getGroup(\"\", name);\n const recent = await xmtp.getRecentMessages(groupId, 100);\n\n // Filter to messages after our cursor, excluding our own messages\n const cursorMs = lastMessageTimestamp * 1000;\n const ownInboxId = loadConfig().xmtpInboxId;\n const newMessages = recent.filter(\n (m) =>\n m.sentAt.getTime() > cursorMs &&\n (!ownInboxId || m.senderInboxId !== ownInboxId),\n );\n messages = newMessages.map(toSessionMessage);\n } catch {\n // XMTP not available or group not found — skip messages\n }\n }\n\n // ── Fetch on-chain events ──\n let events: ChainEvent[] = [];\n if (fromBlock <= currentBlock) {\n const vaultEvents = await getVaultEvents(\n vaultAddress,\n fromBlock,\n currentBlock,\n );\n const govEvents = await getGovernorEvents(\n governorAddress,\n vaultAddress,\n fromBlock,\n currentBlock,\n );\n // Guardian layer — resolved from the address book (zero addresses on\n // chains without the guardian stack yield no events).\n const { GUARDIAN_REGISTRY, STAKED_WOOD } = SHERWOOD();\n const guardianEvents = await getGuardianRegistryEvents(\n GUARDIAN_REGISTRY,\n fromBlock,\n currentBlock,\n );\n const slashEvents = await getStakedWoodEvents(\n STAKED_WOOD,\n fromBlock,\n currentBlock,\n );\n events = [...vaultEvents, ...govEvents, ...guardianEvents, ...slashEvents].sort(\n (a, b) => a.block - b.block,\n );\n\n // Enrich proposal events with IPFS metadata (name, description, state)\n try {\n events = await enrichProposalEvents(vaultAddress, events);\n } catch {\n // IPFS/RPC unreachable — continue with raw events\n }\n }\n\n // ── Output initial catch-up result ──\n const result: SessionCheckResult = {\n fund: name,\n messages,\n events,\n meta: {\n newMessages: messages.length,\n newEvents: events.length,\n blocksScanned: Number(currentBlock - fromBlock),\n lastCheckAt: session?.lastCheckAt\n ? new Date(session.lastCheckAt * 1000).toISOString()\n : \"never\",\n },\n };\n\n process.stdout.write(JSON.stringify(result) + \"\\n\");\n\n // ── Update session state ──\n // Find the newest message timestamp (messages may not be sorted)\n // Use ceil to ensure we don't re-fetch the same message due to sub-second precision\n let newestTimestamp = lastMessageTimestamp;\n let newestMessageId = session?.lastMessageId || \"\";\n for (const msg of messages) {\n const ts = Math.ceil(new Date(msg.sentAt).getTime() / 1000);\n if (ts > newestTimestamp) {\n newestTimestamp = ts;\n newestMessageId = msg.id;\n }\n }\n\n updateSession(name, {\n vault: vaultAddress,\n governor: governorAddress,\n lastBlockNumber: Number(currentBlock),\n lastCheckAt: Math.floor(Date.now() / 1000),\n lastMessageId: newestMessageId,\n lastMessageTimestamp: newestTimestamp,\n totalMessagesProcessed:\n (session?.totalMessagesProcessed || 0) + messages.length,\n totalEventsProcessed:\n (session?.totalEventsProcessed || 0) + events.length,\n });\n\n // ── If --stream, stay alive ──\n if (stream) {\n await startStream(name, vaultAddress, governorAddress, noXmtp);\n }\n}\n\nasync function startStream(\n name: string,\n vaultAddress: Address,\n governorAddress: Address,\n noXmtp: boolean,\n): Promise<void> {\n // Cache for proposal metadata — immutable once pinned, safe to reuse across polls\n const metadataCache = new Map<string, { name: string; description: string }>();\n\n // Start XMTP message stream\n // Skipped entirely when noXmtp is true — see handleCheck for the rationale.\n // xmtpCleanup stays undefined in that case; the on-exit cleanup does\n // `xmtpCleanup?.()` which is a no-op on undefined, so teardown is unaffected.\n let xmtpCleanup: (() => void) | undefined;\n if (!noXmtp) {\n try {\n const xmtp = await loadXmtp();\n const groupId = await xmtp.getGroup(\"\", name);\n\n const streamOwnInboxId = loadConfig().xmtpInboxId;\n xmtpCleanup = await xmtp.streamMessages(groupId, (msg) => {\n // Skip own messages to prevent self-replies\n if (streamOwnInboxId && msg.senderInboxId === streamOwnInboxId) return;\n\n const sessionMsg = toSessionMessage(msg);\n process.stdout.write(JSON.stringify(sessionMsg) + \"\\n\");\n\n // Update session state incrementally\n updateSession(name, {\n lastMessageId: msg.id,\n lastMessageTimestamp: Math.floor(msg.sentAt.getTime() / 1000),\n lastCheckAt: Math.floor(Date.now() / 1000),\n totalMessagesProcessed:\n (getSession(name)?.totalMessagesProcessed || 0) + 1,\n });\n });\n } catch {\n // XMTP not available — continue with event polling only\n }\n }\n\n // Start on-chain event polling (~30s interval)\n const pollInterval = setInterval(async () => {\n try {\n const session = getSession(name);\n const fromBlock = BigInt(session?.lastBlockNumber || 0) + 1n;\n const toBlock = await getCurrentBlock();\n\n if (fromBlock > toBlock) return; // No new blocks\n\n const vaultEvents = await getVaultEvents(\n vaultAddress,\n fromBlock,\n toBlock,\n );\n const govEvents = await getGovernorEvents(\n governorAddress,\n vaultAddress,\n fromBlock,\n toBlock,\n );\n const { GUARDIAN_REGISTRY, STAKED_WOOD } = SHERWOOD();\n const guardianEvents = await getGuardianRegistryEvents(\n GUARDIAN_REGISTRY,\n fromBlock,\n toBlock,\n );\n const slashEvents = await getStakedWoodEvents(\n STAKED_WOOD,\n fromBlock,\n toBlock,\n );\n\n let events = [\n ...vaultEvents,\n ...govEvents,\n ...guardianEvents,\n ...slashEvents,\n ].sort((a, b) => a.block - b.block);\n\n // Enrich proposal events with IPFS metadata (reuse cache across polls)\n try {\n events = await enrichProposalEvents(vaultAddress, events, metadataCache);\n } catch {\n // IPFS/RPC unreachable — continue with raw events\n }\n\n for (const event of events) {\n process.stdout.write(JSON.stringify(event) + \"\\n\");\n }\n\n updateSession(name, {\n lastBlockNumber: Number(toBlock),\n lastCheckAt: Math.floor(Date.now() / 1000),\n totalEventsProcessed:\n (getSession(name)?.totalEventsProcessed || 0) + events.length,\n });\n } catch {\n // RPC error — skip this poll cycle\n }\n }, 30_000);\n\n // Clean up on exit\n const cleanup = () => {\n clearInterval(pollInterval);\n xmtpCleanup?.();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", cleanup);\n process.on(\"SIGTERM\", cleanup);\n\n // Keep alive\n await new Promise(() => {});\n}\n\nasync function handleStatus(name?: string): Promise<void> {\n const sessions = getAllSessions();\n\n if (name) {\n const session = sessions[name];\n if (!session) {\n console.log(\n chalk.dim(`No session found for \"${name}\". Run \"sherwood session check ${name}\" first.`),\n );\n return;\n }\n console.log(JSON.stringify({ [name]: formatSessionStatus(session) }, null, 2));\n return;\n }\n\n // Show all sessions\n if (Object.keys(sessions).length === 0) {\n console.log(chalk.dim(\"No sessions found. Run \\\"sherwood session check <name>\\\" to start.\"));\n return;\n }\n\n const output: Record<string, ReturnType<typeof formatSessionStatus>> = {};\n for (const [subdomain, session] of Object.entries(sessions)) {\n output[subdomain] = formatSessionStatus(session);\n }\n console.log(JSON.stringify(output, null, 2));\n}\n\nfunction formatSessionStatus(session: {\n lastCheckAt: number;\n lastBlockNumber: number;\n totalMessagesProcessed: number;\n totalEventsProcessed: number;\n}) {\n return {\n lastCheckAt: session.lastCheckAt\n ? new Date(session.lastCheckAt * 1000).toISOString()\n : \"never\",\n lastBlockNumber: session.lastBlockNumber,\n totalMessagesProcessed: session.totalMessagesProcessed,\n totalEventsProcessed: session.totalEventsProcessed,\n };\n}\n\nasync function handleReset(\n name: string,\n sinceBlock?: string,\n full?: boolean,\n): Promise<void> {\n if (full || !sinceBlock) {\n resetSession(name);\n console.log(chalk.green(`Session for \"${name}\" has been reset.`));\n } else {\n const block = parseInt(sinceBlock, 10);\n if (isNaN(block)) {\n console.error(chalk.red(\"--since-block must be a number\"));\n process.exit(1);\n }\n resetSession(name, block);\n console.log(\n chalk.green(`Block cursor for \"${name}\" reset to ${block}.`),\n );\n }\n}\n\n// ── Command Registration ──\n\nexport function registerSessionCommands(program: Command): void {\n const session = program\n .command(\"session\")\n .description(\"Agent session — catch up on messages + on-chain events\");\n\n session\n .command(\"check <name>\")\n .description(\"Fetch new XMTP messages and on-chain events since last check\")\n .option(\"--stream\", \"Stay alive streaming messages and polling events\", false)\n .option(\n \"--no-xmtp\",\n \"Skip XMTP catch-up and streaming. Use when XMTP bindings are unavailable or when an external process owns XMTP (e.g. the sherwood-monitor Hermes plugin's bundled sidecar). Also honors SHERWOOD_SKIP_XMTP=1.\",\n false,\n )\n .action(\n async (name: string, opts: { stream: boolean; noXmtp: boolean }) => {\n const skipXmtp =\n opts.noXmtp || process.env.SHERWOOD_SKIP_XMTP === \"1\";\n await handleCheck(name, opts.stream, skipXmtp);\n },\n );\n\n session\n .command(\"status [name]\")\n .description(\"Show session cursor positions\")\n .action(async (name?: string) => {\n await handleStatus(name);\n });\n\n session\n .command(\"reset <name>\")\n .description(\"Reset session cursors\")\n .option(\"--since-block <n>\", \"Reset block cursor to a specific block\")\n .option(\"--full\", \"Reset everything (messages + events)\", false)\n .action(\n async (\n name: string,\n opts: { sinceBlock?: string; full: boolean },\n ) => {\n await handleReset(name, opts.sinceBlock, opts.full);\n },\n );\n\n session\n .command(\"cron <name>\")\n .description(\"Manage participation crons (OpenClaw agents)\")\n .option(\"--remove\", \"Remove participation crons\", false)\n .option(\"--status\", \"Show cron status\", false)\n .action(async (name: string, opts: { remove: boolean; status: boolean }) => {\n const { isOpenClaw, registerFundCrons, unregisterFundCrons, getFundCronStatus } =\n await import(\"../lib/cron.js\");\n const { isTestnet } = await import(\"../lib/network.js\");\n const { getNotifyTo } = await import(\"../lib/config.js\");\n\n if (!isOpenClaw()) {\n console.log(chalk.yellow(\"Not running on OpenClaw — cron commands unavailable\"));\n console.log(chalk.dim(` Set up your own scheduler: sherwood session check ${name} --stream`));\n return;\n }\n\n if (opts.status) {\n const status = getFundCronStatus(name, isTestnet());\n if (status.crons.length === 0) {\n console.log(chalk.dim(\"No participation crons found for \" + name));\n return;\n }\n console.log();\n console.log(chalk.bold(`Participation Crons — ${name}`));\n console.log(chalk.dim(\"─\".repeat(50)));\n for (const cron of status.crons) {\n console.log(` ${chalk.green(cron.name)} every ${cron.every}${cron.lastRun ? ` last: ${cron.lastRun}` : \"\"}`);\n }\n console.log();\n return;\n }\n\n if (opts.remove) {\n const result = unregisterFundCrons(name, isTestnet());\n if (result.removed) {\n console.log(chalk.green(\"Participation crons removed\"));\n } else {\n console.log(chalk.dim(\"No crons found to remove\"));\n }\n return;\n }\n\n // Register/update\n const result = registerFundCrons(name, isTestnet(), getNotifyTo());\n if (result.registered) {\n console.log(chalk.green(\"Participation crons registered: \" + result.cronNames.join(\", \")));\n } else {\n console.log(chalk.dim(\"Crons already registered\"));\n }\n });\n}\n"],"mappings":"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","names":["result"]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|