@sherwoodagent/cli 0.82.0 → 0.83.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/{addresses-FGJ4I4IG.js → addresses-MS6BB7AB.js} +3 -3
  2. package/dist/{agent-QUINV725.js → agent-C5XZSK7Z.js} +6 -6
  3. package/dist/{chat-5TUHBSIA.js → chat-FGTYCJ4B.js} +7 -7
  4. package/dist/{chunk-Y6XOH23Y.js → chunk-4GO7I33U.js} +4 -4
  5. package/dist/{chunk-4KJUX5SS.js → chunk-4WAEM2TC.js} +4 -4
  6. package/dist/{chunk-LZEV772I.js → chunk-AJ46XIGY.js} +4 -4
  7. package/dist/chunk-AJ46XIGY.js.map +1 -0
  8. package/dist/{chunk-MC5QEPW3.js → chunk-AOL2DJTK.js} +5 -5
  9. package/dist/{chunk-EPQR6PJ4.js → chunk-AQPTBVEA.js} +20 -4
  10. package/dist/chunk-AQPTBVEA.js.map +1 -0
  11. package/dist/{chunk-6BVA4RIH.js → chunk-CCNOXDZ7.js} +2 -2
  12. package/dist/{chunk-UHGWEJ24.js → chunk-G34TNE53.js} +2 -2
  13. package/dist/{chunk-PMRYC6SF.js → chunk-I7TMY7AS.js} +2 -2
  14. package/dist/{chunk-54CLRBPB.js → chunk-M34JVPJO.js} +4 -4
  15. package/dist/chunk-M34JVPJO.js.map +1 -0
  16. package/dist/{chunk-27XY2HXV.js → chunk-MBWFTXF5.js} +4 -4
  17. package/dist/{chunk-76DLC7CM.js → chunk-NKRMMFQG.js} +3 -3
  18. package/dist/{chunk-3TLKNRZV.js → chunk-ZW2VKCFZ.js} +2 -2
  19. package/dist/chunk-ZW2VKCFZ.js.map +1 -0
  20. package/dist/{client-VNSFNDF4.js → client-OPZ2ORWW.js} +3 -3
  21. package/dist/{cron-QMLRWDJG.js → cron-E3UAZF5B.js} +1 -1
  22. package/dist/cron-E3UAZF5B.js.map +1 -0
  23. package/dist/{eas-PJ3Y4NDB.js → eas-32PEJETG.js} +5 -5
  24. package/dist/{governor-4ASVLOCI.js → governor-GSCXEZWI.js} +5 -5
  25. package/dist/index.js +1041 -944
  26. package/dist/index.js.map +1 -1
  27. package/dist/{network-RI54LT2Y.js → network-HCFCNZUI.js} +2 -2
  28. package/dist/{price-JX2LFKFW.js → price-OUL7WIXQ.js} +5 -5
  29. package/dist/{providers-F6MNPMR4.js → providers-4HQHB7V5.js} +4 -4
  30. package/dist/{research-5ZJTRILJ.js → research-2RWAMWWH.js} +7 -7
  31. package/dist/{session-AXLPYJHX.js → session-SIOJZO6P.js} +10 -10
  32. package/dist/{trade-BZM7K2F4.js → trade-ZEIY3MCL.js} +15 -15
  33. package/dist/trade-ZEIY3MCL.js.map +1 -0
  34. package/dist/{vault-AWQBFD4C.js → vault-VDADZFSV.js} +7 -7
  35. package/dist/{xmtp-M74BRF3G.js → xmtp-2U7CSBXM.js} +5 -5
  36. package/package.json +5 -2
  37. package/scripts/pin-xmtp-bindings.cjs +26 -10
  38. package/dist/chunk-3TLKNRZV.js.map +0 -1
  39. package/dist/chunk-54CLRBPB.js.map +0 -1
  40. package/dist/chunk-EPQR6PJ4.js.map +0 -1
  41. package/dist/chunk-LZEV772I.js.map +0 -1
  42. package/dist/cron-QMLRWDJG.js.map +0 -1
  43. package/dist/trade-BZM7K2F4.js.map +0 -1
  44. /package/dist/{addresses-FGJ4I4IG.js.map → addresses-MS6BB7AB.js.map} +0 -0
  45. /package/dist/{agent-QUINV725.js.map → agent-C5XZSK7Z.js.map} +0 -0
  46. /package/dist/{chat-5TUHBSIA.js.map → chat-FGTYCJ4B.js.map} +0 -0
  47. /package/dist/{chunk-Y6XOH23Y.js.map → chunk-4GO7I33U.js.map} +0 -0
  48. /package/dist/{chunk-4KJUX5SS.js.map → chunk-4WAEM2TC.js.map} +0 -0
  49. /package/dist/{chunk-MC5QEPW3.js.map → chunk-AOL2DJTK.js.map} +0 -0
  50. /package/dist/{chunk-6BVA4RIH.js.map → chunk-CCNOXDZ7.js.map} +0 -0
  51. /package/dist/{chunk-UHGWEJ24.js.map → chunk-G34TNE53.js.map} +0 -0
  52. /package/dist/{chunk-PMRYC6SF.js.map → chunk-I7TMY7AS.js.map} +0 -0
  53. /package/dist/{chunk-27XY2HXV.js.map → chunk-MBWFTXF5.js.map} +0 -0
  54. /package/dist/{chunk-76DLC7CM.js.map → chunk-NKRMMFQG.js.map} +0 -0
  55. /package/dist/{client-VNSFNDF4.js.map → client-OPZ2ORWW.js.map} +0 -0
  56. /package/dist/{eas-PJ3Y4NDB.js.map → eas-32PEJETG.js.map} +0 -0
  57. /package/dist/{governor-4ASVLOCI.js.map → governor-GSCXEZWI.js.map} +0 -0
  58. /package/dist/{network-RI54LT2Y.js.map → network-HCFCNZUI.js.map} +0 -0
  59. /package/dist/{price-JX2LFKFW.js.map → price-OUL7WIXQ.js.map} +0 -0
  60. /package/dist/{providers-F6MNPMR4.js.map → providers-4HQHB7V5.js.map} +0 -0
  61. /package/dist/{research-5ZJTRILJ.js.map → research-2RWAMWWH.js.map} +0 -0
  62. /package/dist/{session-AXLPYJHX.js.map → session-SIOJZO6P.js.map} +0 -0
  63. /package/dist/{vault-AWQBFD4C.js.map → vault-VDADZFSV.js.map} +0 -0
  64. /package/dist/{xmtp-M74BRF3G.js.map → xmtp-2U7CSBXM.js.map} +0 -0
@@ -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 * Current deployment target: Robinhood L2 testnet (chain 46630) only. Sherwood\n * launches on Robinhood first; other chains may be added back later, at which\n * point they re-enter 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\";\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// ── 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};\n\nexport const VALID_NETWORKS = Object.keys(CHAIN_REGISTRY) as Network[];\n\nexport const DEFAULT_NETWORK: Network = \"robinhood-testnet\";\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. Legacy env var (ROBINHOOD_TESTNET_RPC_URL)\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/eas.ts"],"sourcesContent":["/**\n * EAS (Ethereum Attestation Service) wrapper for fund join requests and approvals.\n *\n * Uses viem for on-chain writes and the EAS GraphQL API for queries.\n * No ethers dependency — attestation data is encoded with viem's encodeAbiParameters.\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeAbiParameters, parseAbiParameters, decodeAbiParameters } from \"viem\";\nimport { getPublicClient, getAccount, writeContractWithRetry, waitForReceipt } from \"./client.js\";\nimport { getChain, getNetwork, getChainConfig, withNetwork, isTestnet, CHAIN_REGISTRY, type Network } from \"./network.js\";\nimport { EAS_CONTRACTS, EAS_SCHEMAS } from \"./addresses.js\";\nimport { EAS_ABI } from \"./abis.js\";\n\n// ── Schema definitions ──\n\nconst ZERO_BYTES32 = \"0x0000000000000000000000000000000000000000000000000000000000000000\" as Hex;\n\n// keccak256(\"Attested(address,address,bytes32,bytes32)\")\nconst ATTESTED_TOPIC = \"0x8bf46bf4cfd674fa735a3d63ec1c9ad4153f033c290341f3a588b75685141b35\" as Hex;\n\nconst JOIN_REQUEST_PARAMS = parseAbiParameters(\"uint256, uint256, address, string\");\nconst AGENT_APPROVED_PARAMS = parseAbiParameters(\"uint256, uint256, address\");\nconst X402_RESEARCH_PARAMS = parseAbiParameters(\"string, string, string, string, string\");\nconst VENICE_PROVISION_PARAMS = parseAbiParameters(\"address, string\");\nconst VENICE_INFERENCE_PARAMS = parseAbiParameters(\"string, uint256, uint256, string\");\nconst TRADE_EXECUTED_PARAMS = parseAbiParameters(\"address, address, uint256, string, string, string\");\n\nfunction assertSchemasRegistered() {\n const schemas = EAS_SCHEMAS();\n if (schemas.SYNDICATE_JOIN_REQUEST === ZERO_BYTES32 || schemas.AGENT_APPROVED === ZERO_BYTES32) {\n const flag = isTestnet() ? \" --testnet\" : \"\";\n throw new Error(\n `EAS schemas not registered on ${getNetwork()}. Run: cd cli && npx tsx scripts/register-eas-schemas.ts${flag}`,\n );\n }\n}\n\n/**\n * The chain where fund-coordination attestations live. EAS is not deployed\n * on the current deployment target (robinhood-testnet), so this returns the\n * active network — downstream `getEasGraphqlUrl` / `EAS_CONTRACTS()` then fail\n * with a clear \"EAS not available\" error. When an EAS-bearing chain is added\n * back, route coordination attestations to it here.\n */\nexport function getEasNetwork(): Network {\n return getNetwork();\n}\n\n// ── GraphQL ──\n\nfunction getEasGraphqlUrl(): string {\n const url = getChainConfig().easGraphqlUrl;\n if (!url) {\n throw new Error(\n `EAS is not available on ${getNetwork()}. Attestation operations require a chain with EAS (e.g. base, base-sepolia).`,\n );\n }\n return url;\n}\n\nexport function getEasScanUrl(uid: Hex): string {\n // Always use the EAS chain's scan host — attestations live on Base, even\n // for HyperEVM funds. Read the registry directly rather than mutating\n // the singleton, since this is a pure URL build.\n const host = CHAIN_REGISTRY[getEasNetwork()].easScanHost;\n if (!host) {\n throw new Error(`EAS scan host is not configured on ${getEasNetwork()}.`);\n }\n return `https://${host}/attestation/view/${uid}`;\n}\n\n/**\n * The block-explorer URL for a tx that ran on the EAS chain. Use this for\n * attestation create/revoke txs so the link points to base(-sepolia) scan\n * even when the active --chain is HyperEVM / Robinhood.\n */\nexport function getEasExplorerUrl(txHash: string): string {\n const host = CHAIN_REGISTRY[getEasNetwork()].explorerHost;\n return `https://${host}/tx/${txHash}`;\n}\n\n// ── Attestation Creation ──\n\n/**\n * Extract the attestation UID from a transaction receipt.\n * The EAS contract emits: event Attested(address indexed recipient, address indexed attester, bytes32 uid, bytes32 indexed schemaUID)\n * uid is a non-indexed parameter in the event data.\n */\nfunction extractAttestationUid(receipt: { logs: readonly { topics: readonly Hex[]; data: Hex }[] }): Hex {\n for (const log of receipt.logs) {\n // Match the Attested event signature to avoid false positives from other events\n if (log.topics[0] !== ATTESTED_TOPIC) continue;\n // Attested event has 4 topics (sig + 3 indexed) and data contains the uid (bytes32)\n if (log.topics.length === 4 && log.data.length >= 66) {\n return (\"0x\" + log.data.slice(2, 66)) as Hex;\n }\n }\n throw new Error(\"Could not extract attestation UID from transaction receipt\");\n}\n\n// ── Message Prefix Helpers ──\n//\n// Join-request messages can carry CLI metadata as bracketed prefixes. Order\n// is `[chain:<network>] [ref:<id>] body` — chain outer because the chain\n// disambiguates the fund, ref inner because it's optional and per-user.\n// Both prefixes are stripped before display.\n\nconst CHAIN_PREFIX_RE = /^\\[chain:([a-z0-9-]+)\\]\\s*/;\n// Tolerate an optional leading [chain:...] prefix so parseReferrer keeps\n// working when both metadata fields are encoded.\nconst REF_PREFIX_RE = /^(?:\\[chain:[a-z0-9-]+\\]\\s*)?\\[ref:(\\d+)\\]\\s*/;\n\n/**\n * Format a message with an optional referrer prefix.\n * e.g. formatMessageWithRef(\"Hello\", 42) → \"[ref:42] Hello\"\n */\nexport function formatMessageWithRef(message: string, referrerAgentId?: number): string {\n if (referrerAgentId == null) return message;\n return `[ref:${referrerAgentId}] ${message}`;\n}\n\n/**\n * Parse a referrer agentId from a message, if present.\n * e.g. parseReferrer(\"[ref:42] Hello\") → 42\n * parseReferrer(\"[chain:hyperevm] [ref:42] Hello\") → 42\n */\nexport function parseReferrer(message: string): number | null {\n const match = message.match(REF_PREFIX_RE);\n return match ? parseInt(match[1], 10) : null;\n}\n\n/**\n * Format a message with a `[chain:<network>]` prefix when the fund\n * lives on a chain other than the EAS chain (Base / Base-Sepolia). Skipped\n * when source matches the EAS chain to avoid noise on the common case.\n */\nexport function formatMessageWithChain(\n message: string,\n sourceNetwork: Network,\n easNetwork: Network,\n): string {\n if (sourceNetwork === easNetwork) return message;\n return `[chain:${sourceNetwork}] ${message}`;\n}\n\n/**\n * Parse the source-chain prefix from a message, if present.\n * Returns null when no `[chain:<network>]` prefix is found, which means the\n * attestation was created from the EAS chain itself (e.g. base attestation\n * for a base fund).\n */\nexport function parseChain(message: string): string | null {\n const match = message.match(CHAIN_PREFIX_RE);\n return match ? match[1] : null;\n}\n\n/**\n * Strip both `[chain:...]` and `[ref:...]` prefixes from a message,\n * returning the clean human-facing body. Name kept for backward compat.\n */\nexport function stripReferrerPrefix(message: string): string {\n // REF_PREFIX_RE already swallows an optional leading chain prefix when ref\n // is present; the second replace handles a chain prefix without ref.\n return message.replace(REF_PREFIX_RE, \"\").replace(CHAIN_PREFIX_RE, \"\");\n}\n\n/**\n * Create a SYNDICATE_JOIN_REQUEST attestation.\n * Attester: the calling agent. Recipient: the fund creator.\n * If referrerAgentId is provided, it's embedded in the message as a [ref:N] prefix.\n */\nexport async function createJoinRequest(\n syndicateId: bigint,\n agentId: bigint,\n vault: Address,\n creatorAddress: Address,\n message: string,\n referrerAgentId?: number,\n): Promise<{ uid: Hex; hash: Hex }> {\n // Capture the fund's source chain BEFORE switching to the EAS chain\n // so we can encode it in the message prefix.\n const sourceNetwork = getNetwork();\n const easNetwork = getEasNetwork();\n const messageWithRef = formatMessageWithRef(message, referrerAgentId);\n const encodedMessage = formatMessageWithChain(messageWithRef, sourceNetwork, easNetwork);\n\n return withNetwork(easNetwork, async () => {\n assertSchemasRegistered();\n\n const data = encodeAbiParameters(JOIN_REQUEST_PARAMS, [\n syndicateId, agentId, vault, encodedMessage,\n ]);\n\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: EAS_CONTRACTS().EAS,\n abi: EAS_ABI,\n functionName: \"attest\",\n args: [{\n schema: EAS_SCHEMAS().SYNDICATE_JOIN_REQUEST,\n data: {\n recipient: creatorAddress,\n expirationTime: 0n,\n revocable: true,\n refUID: ZERO_BYTES32,\n data,\n value: 0n,\n },\n }],\n value: 0n,\n });\n\n const receipt = await waitForReceipt(hash);\n const uid = extractAttestationUid(receipt);\n\n return { uid, hash };\n });\n}\n\n/**\n * Create an AGENT_APPROVED attestation.\n * Attester: the fund creator. Recipient: the agent wallet.\n */\nexport async function createApproval(\n syndicateId: bigint,\n agentId: bigint,\n vault: Address,\n agentAddress: Address,\n): Promise<{ uid: Hex; hash: Hex }> {\n return withNetwork(getEasNetwork(), async () => {\n assertSchemasRegistered();\n\n const data = encodeAbiParameters(AGENT_APPROVED_PARAMS, [\n syndicateId, agentId, vault,\n ]);\n\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: EAS_CONTRACTS().EAS,\n abi: EAS_ABI,\n functionName: \"attest\",\n args: [{\n schema: EAS_SCHEMAS().AGENT_APPROVED,\n data: {\n recipient: agentAddress,\n expirationTime: 0n,\n revocable: true,\n refUID: ZERO_BYTES32,\n data,\n value: 0n,\n },\n }],\n value: 0n,\n });\n\n const receipt = await waitForReceipt(hash);\n const uid = extractAttestationUid(receipt);\n\n return { uid, hash };\n });\n}\n\n/**\n * Revoke an attestation. Only the original attester can revoke. Uses the\n * active chain's EAS — call sites that revoke fund-coordination\n * attestations (join requests, approvals) should go through\n * `revokeJoinRequest` / `revokeApproval` so the revoke lands on the same\n * chain as the original attestation (Base / Base-Sepolia).\n */\nexport async function revokeAttestation(\n schemaUid: Hex,\n attestationUid: Hex,\n): Promise<Hex> {\n return writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: EAS_CONTRACTS().EAS,\n abi: EAS_ABI,\n functionName: \"revoke\",\n args: [{\n schema: schemaUid,\n data: {\n uid: attestationUid,\n value: 0n,\n },\n }],\n value: 0n,\n });\n}\n\n/** Revoke a SYNDICATE_JOIN_REQUEST on the EAS chain (Base / Base-Sepolia). */\nexport async function revokeJoinRequest(attestationUid: Hex): Promise<Hex> {\n return withNetwork(getEasNetwork(), () =>\n revokeAttestation(EAS_SCHEMAS().SYNDICATE_JOIN_REQUEST, attestationUid),\n );\n}\n\n/**\n * Create an X402_RESEARCH attestation — records a research query on-chain.\n * Attester: the agent. Recipient: vault address (links to fund) or agent itself.\n * Schema: \"string provider, string queryType, string prompt, string costUsdc, string resultUri\"\n */\nexport async function createResearchAttestation(\n provider: string,\n queryType: string,\n prompt: string,\n costUsdc: string,\n resultUri: string,\n recipient?: Address,\n): Promise<{ uid: Hex; hash: Hex }> {\n const schemas = EAS_SCHEMAS();\n if (schemas.X402_RESEARCH === ZERO_BYTES32) {\n throw new Error(\n \"X402_RESEARCH schema not registered. Run: npx tsx scripts/register-eas-schemas.ts --testnet\",\n );\n }\n\n const client = getPublicClient();\n const account = getAccount();\n\n const data = encodeAbiParameters(X402_RESEARCH_PARAMS, [\n provider, queryType, prompt, costUsdc, resultUri,\n ]);\n\n const hash = await writeContractWithRetry({\n account,\n chain: getChain(),\n address: EAS_CONTRACTS().EAS,\n abi: EAS_ABI,\n functionName: \"attest\",\n args: [{\n schema: schemas.X402_RESEARCH,\n data: {\n recipient: recipient ?? account.address,\n expirationTime: 0n,\n revocable: false,\n refUID: ZERO_BYTES32,\n data,\n value: 0n,\n },\n }],\n value: 0n,\n });\n\n const receipt = await waitForReceipt(hash);\n const uid = extractAttestationUid(receipt);\n\n return { uid, hash };\n}\n\n/**\n * Create a VENICE_PROVISION attestation — records that an agent provisioned a Venice API key.\n * Schema: \"address agent, string status\"\n */\nexport async function createVeniceProvisionAttestation(\n agent: Address,\n): Promise<{ uid: Hex; hash: Hex }> {\n const schemas = EAS_SCHEMAS();\n if (schemas.VENICE_PROVISION === ZERO_BYTES32) return skipAttestation(\"VENICE_PROVISION\");\n\n const client = getPublicClient();\n const account = getAccount();\n\n const data = encodeAbiParameters(VENICE_PROVISION_PARAMS, [agent, \"provisioned\"]);\n\n const hash = await writeContractWithRetry({\n account,\n chain: getChain(),\n address: EAS_CONTRACTS().EAS,\n abi: EAS_ABI,\n functionName: \"attest\",\n args: [{\n schema: schemas.VENICE_PROVISION,\n data: {\n recipient: agent,\n expirationTime: 0n,\n revocable: false,\n refUID: ZERO_BYTES32,\n data,\n value: 0n,\n },\n }],\n value: 0n,\n });\n\n const receipt = await waitForReceipt(hash);\n const uid = extractAttestationUid(receipt);\n return { uid, hash };\n}\n\n/**\n * Create a VENICE_INFERENCE attestation — records an inference call.\n * Attester: the agent. Recipient: vault address (links to fund) or agent itself.\n * Schema: \"string model, uint256 promptTokens, uint256 completionTokens, string promptHash\"\n */\nexport async function createVeniceInferenceAttestation(\n model: string,\n promptTokens: number,\n completionTokens: number,\n promptHash: string,\n recipient?: Address,\n): Promise<{ uid: Hex; hash: Hex }> {\n const schemas = EAS_SCHEMAS();\n if (schemas.VENICE_INFERENCE === ZERO_BYTES32) return skipAttestation(\"VENICE_INFERENCE\");\n\n const client = getPublicClient();\n const account = getAccount();\n\n const data = encodeAbiParameters(VENICE_INFERENCE_PARAMS, [\n model,\n BigInt(promptTokens),\n BigInt(completionTokens),\n promptHash,\n ]);\n\n const hash = await writeContractWithRetry({\n account,\n chain: getChain(),\n address: EAS_CONTRACTS().EAS,\n abi: EAS_ABI,\n functionName: \"attest\",\n args: [{\n schema: schemas.VENICE_INFERENCE,\n data: {\n recipient: recipient ?? account.address,\n expirationTime: 0n,\n revocable: false,\n refUID: ZERO_BYTES32,\n data,\n value: 0n,\n },\n }],\n value: 0n,\n });\n\n const receipt = await waitForReceipt(hash);\n const uid = extractAttestationUid(receipt);\n return { uid, hash };\n}\n\n/**\n * Create a TRADE_EXECUTED attestation — records a swap on-chain.\n * Attester: the agent. Recipient: vault address (links to fund) or agent itself.\n * Schema: \"address tokenIn, address tokenOut, uint256 amountIn, string amountOut, string txHash, string routing\"\n */\nexport async function createTradeAttestation(\n tokenIn: Address,\n tokenOut: Address,\n amountIn: bigint,\n amountOut: string,\n txHash: string,\n routing: string,\n recipient?: Address,\n): Promise<{ uid: Hex; hash: Hex }> {\n const schemas = EAS_SCHEMAS();\n if (schemas.TRADE_EXECUTED === ZERO_BYTES32) return skipAttestation(\"TRADE_EXECUTED\");\n\n const client = getPublicClient();\n const account = getAccount();\n\n const data = encodeAbiParameters(TRADE_EXECUTED_PARAMS, [\n tokenIn, tokenOut, amountIn, amountOut, txHash, routing,\n ]);\n\n const hash = await writeContractWithRetry({\n account,\n chain: getChain(),\n address: EAS_CONTRACTS().EAS,\n abi: EAS_ABI,\n functionName: \"attest\",\n args: [{\n schema: schemas.TRADE_EXECUTED,\n data: {\n recipient: recipient ?? account.address,\n expirationTime: 0n,\n revocable: false,\n refUID: ZERO_BYTES32,\n data,\n value: 0n,\n },\n }],\n value: 0n,\n });\n\n const receipt = await waitForReceipt(hash);\n const uid = extractAttestationUid(receipt);\n return { uid, hash };\n}\n\n/** Skip attestation gracefully when schema isn't registered on this chain. */\nfunction skipAttestation(name: string): { uid: Hex; hash: Hex } {\n return { uid: ZERO_BYTES32, hash: ZERO_BYTES32 };\n}\n\n// ── Attestation Queries ──\n\nexport interface JoinRequestAttestation {\n uid: Hex;\n attester: Address;\n recipient: Address;\n time: number;\n decoded: {\n syndicateId: bigint;\n agentId: bigint;\n vault: Address;\n message: string;\n };\n}\n\n/**\n * Query pending (non-revoked) join requests for a given recipient (creator address).\n * Uses the EAS GraphQL API.\n */\nexport interface ApprovalAttestation {\n uid: Hex;\n attester: Address;\n recipient: Address;\n time: number;\n decoded: {\n syndicateId: bigint;\n agentId: bigint;\n vault: Address;\n };\n}\n\n/**\n * Query existing (non-revoked) AGENT_APPROVED attestations created by a given attester (creator).\n * Used to check for duplicates before creating a new approval and to filter already-approved agents from requests.\n */\nexport async function queryApprovals(\n attester: Address,\n): Promise<ApprovalAttestation[]> {\n return withNetwork(getEasNetwork(), () => queryApprovalsImpl(attester));\n}\n\nasync function queryApprovalsImpl(attester: Address): Promise<ApprovalAttestation[]> {\n assertSchemasRegistered();\n const schemaUid = EAS_SCHEMAS().AGENT_APPROVED;\n const url = getEasGraphqlUrl();\n\n const query = `\n query Approvals($schemaId: String!, $attester: String!) {\n attestations(\n where: {\n schemaId: { equals: $schemaId }\n attester: { equals: $attester }\n revoked: { equals: false }\n }\n orderBy: [{ time: desc }]\n ) {\n id\n attester\n recipient\n time\n data\n }\n }\n `;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n query,\n variables: { schemaId: schemaUid, attester },\n }),\n });\n\n if (!response.ok) {\n throw new Error(`EAS GraphQL query failed: ${response.statusText}`);\n }\n\n const json = await response.json() as {\n data?: {\n attestations: Array<{\n id: string;\n attester: string;\n recipient: string;\n time: number;\n data: string;\n }>;\n };\n };\n\n if (!json.data?.attestations) return [];\n\n return json.data.attestations.map((a) => {\n const decoded = decodeAbiParameters(AGENT_APPROVED_PARAMS, a.data as Hex);\n return {\n uid: a.id as Hex,\n attester: a.attester as Address,\n recipient: a.recipient as Address,\n time: a.time,\n decoded: {\n syndicateId: decoded[0],\n agentId: decoded[1],\n vault: decoded[2],\n },\n };\n });\n}\n\nexport async function queryJoinRequests(\n recipient: Address,\n): Promise<JoinRequestAttestation[]> {\n return withNetwork(getEasNetwork(), () => queryJoinRequestsImpl(recipient));\n}\n\nasync function queryJoinRequestsImpl(recipient: Address): Promise<JoinRequestAttestation[]> {\n assertSchemasRegistered();\n const schemaUid = EAS_SCHEMAS().SYNDICATE_JOIN_REQUEST;\n const url = getEasGraphqlUrl();\n\n const query = `\n query JoinRequests($schemaId: String!, $recipient: String!) {\n attestations(\n where: {\n schemaId: { equals: $schemaId }\n recipient: { equals: $recipient }\n revoked: { equals: false }\n }\n orderBy: [{ time: desc }]\n ) {\n id\n attester\n recipient\n time\n data\n }\n }\n `;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n query,\n variables: { schemaId: schemaUid, recipient },\n }),\n });\n\n if (!response.ok) {\n throw new Error(`EAS GraphQL query failed: ${response.statusText}`);\n }\n\n const json = await response.json() as {\n data?: {\n attestations: Array<{\n id: string;\n attester: string;\n recipient: string;\n time: number;\n data: string;\n }>;\n };\n };\n\n if (!json.data?.attestations) return [];\n\n return json.data.attestations.map((a) => {\n const decoded = decodeAbiParameters(JOIN_REQUEST_PARAMS, a.data as Hex);\n return {\n uid: a.id as Hex,\n attester: a.attester as Address,\n recipient: a.recipient as Address,\n time: a.time,\n decoded: {\n syndicateId: decoded[0],\n agentId: decoded[1],\n vault: decoded[2],\n message: decoded[3],\n },\n };\n });\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\n // ── SyndicateGovernor ──\n { type: \"error\", name: \"VaultNotRegistered\", inputs: [] },\n { type: \"error\", name: \"VaultAlreadyRegistered\", inputs: [] },\n { type: \"error\", name: \"NotRegisteredAgent\", inputs: [] },\n { type: \"error\", name: \"PerformanceFeeTooHigh\", inputs: [] },\n { type: \"error\", name: \"StrategyDurationTooLong\", inputs: [] },\n { type: \"error\", name: \"StrategyDurationTooShort\", inputs: [] },\n { type: \"error\", name: \"EmptyExecuteCalls\", inputs: [] },\n { type: \"error\", name: \"EmptySettlementCalls\", inputs: [] },\n { type: \"error\", name: \"NotWithinVotingPeriod\", inputs: [] },\n { type: \"error\", name: \"NoVotingPower\", inputs: [] },\n { type: \"error\", name: \"AlreadyVoted\", inputs: [] },\n { type: \"error\", name: \"ProposalNotFound\", inputs: [] },\n { type: \"error\", name: \"ProposalNotApproved\", inputs: [] },\n { type: \"error\", name: \"ExecutionWindowExpired\", inputs: [] },\n { type: \"error\", name: \"StrategyAlreadyActive\", inputs: [] },\n { type: \"error\", name: \"CooldownNotElapsed\", inputs: [] },\n { type: \"error\", name: \"ProposalNotExecuted\", inputs: [] },\n { type: \"error\", name: \"ProposalNotCancellable\", inputs: [] },\n { type: \"error\", name: \"NotProposer\", inputs: [] },\n { type: \"error\", name: \"InvalidVotingPeriod\", inputs: [] },\n { type: \"error\", name: \"InvalidExecutionWindow\", inputs: [] },\n { type: \"error\", name: \"InvalidVetoThresholdBps\", inputs: [] },\n { type: \"error\", name: \"InvalidMaxPerformanceFeeBps\", inputs: [] },\n { type: \"error\", name: \"InvalidStrategyDurationBounds\", inputs: [] },\n { type: \"error\", name: \"InvalidCooldownPeriod\", inputs: [] },\n { type: \"error\", name: \"InvalidVault\", inputs: [] },\n { type: \"error\", name: \"NotVaultOwner\", inputs: [] },\n { type: \"error\", name: \"StrategyDurationNotElapsed\", inputs: [] },\n { type: \"error\", name: \"InvalidProtocolFeeBps\", inputs: [] },\n { type: \"error\", name: \"InvalidProtocolFeeRecipient\", inputs: [] },\n { type: \"error\", name: \"NotCoProposer\", inputs: [] },\n { type: \"error\", name: \"CollaborationExpired\", inputs: [] },\n { type: \"error\", name: \"AlreadyApproved\", inputs: [] },\n { type: \"error\", name: \"InvalidSplits\", inputs: [] },\n { type: \"error\", name: \"TooManyCoProposers\", inputs: [] },\n { type: \"error\", name: \"SplitTooLow\", inputs: [] },\n { type: \"error\", name: \"LeadSplitTooLow\", inputs: [] },\n { type: \"error\", name: \"DuplicateCoProposer\", inputs: [] },\n { type: \"error\", name: \"NotDraftState\", inputs: [] },\n { type: \"error\", name: \"InvalidCollaborationWindow\", inputs: [] },\n { type: \"error\", name: \"NotAuthorized\", inputs: [] },\n { type: \"error\", name: \"InvalidMaxCoProposers\", inputs: [] },\n { type: \"error\", name: \"Reentrancy\", inputs: [] },\n\n // ── GovernorParameters (timelock) ──\n { type: \"error\", name: \"ChangeAlreadyPending\", inputs: [] },\n { type: \"error\", name: \"NoChangePending\", inputs: [] },\n { type: \"error\", name: \"ChangeNotReady\", inputs: [] },\n { type: \"error\", name: \"InvalidParameterChangeDelay\", inputs: [] },\n { type: \"error\", name: \"InvalidParameterKey\", inputs: [] },\n\n // ── SyndicateFactory ──\n { type: \"error\", name: \"InvalidVaultImpl\", inputs: [] },\n { type: \"error\", name: \"InvalidENSRegistrar\", inputs: [] },\n { type: \"error\", name: \"SubdomainTooShort\", inputs: [] },\n { type: \"error\", name: \"SubdomainTaken\", inputs: [] },\n { type: \"error\", name: \"NotCreator\", inputs: [] },\n { type: \"error\", name: \"InvalidGovernor\", inputs: [] },\n { type: \"error\", name: \"InsufficientCreationFee\", inputs: [] },\n { type: \"error\", name: \"InvalidFeeToken\", inputs: [] },\n { type: \"error\", name: \"ManagementFeeTooHigh\", inputs: [] },\n { type: \"error\", name: \"UpgradesDisabled\", inputs: [] },\n { type: \"error\", name: \"VaultNotDeployed\", inputs: [] },\n { type: \"error\", name: \"StrategyActive\", inputs: [] },\n\n // ── BaseStrategy ──\n { type: \"error\", name: \"AlreadyInitialized\", inputs: [] },\n { type: \"error\", name: \"NotVault\", inputs: [] },\n { type: \"error\", name: \"NotExecuted\", inputs: [] },\n { type: \"error\", name: \"AlreadyExecuted\", inputs: [] },\n { type: \"error\", name: \"AlreadySettled\", inputs: [] },\n\n // ── MoonwellSupplyStrategy / WstETHMoonwellStrategy ──\n { type: \"error\", name: \"InvalidAmount\", inputs: [] },\n { type: \"error\", name: \"MintFailed\", inputs: [] },\n { type: \"error\", name: \"RedeemFailed\", inputs: [] },\n\n // ── AerodromeLPStrategy ──\n { type: \"error\", name: \"GaugeMismatch\", inputs: [] },\n\n // ── WstETHMoonwellStrategy / VeniceInferenceStrategy ──\n { type: \"error\", name: \"SwapFailed\", inputs: [] },\n { type: \"error\", name: \"AlreadySettledParams\", inputs: [] },\n\n // ── PortfolioStrategy / UniswapSwapAdapter ──\n { type: \"error\", name: \"QuoteUnavailable\", inputs: [] },\n { type: \"error\", name: \"UnsupportedMode\", inputs: [] },\n { type: \"error\", name: \"InvalidWeights\", inputs: [] },\n { type: \"error\", name: \"LengthMismatch\", inputs: [] },\n { type: \"error\", name: \"TooManyTokens\", inputs: [] },\n { type: \"error\", name: \"RebalancingInProgress\", inputs: [] },\n { type: \"error\", name: \"StalePrice\", inputs: [] },\n { type: \"error\", name: \"InvalidSlippage\", inputs: [] },\n { type: \"error\", name: \"InvalidPriceDecimals\", inputs: [] },\n\n // ── VeniceInferenceStrategy ──\n { type: \"error\", name: \"NoAgent\", inputs: [] },\n] as const;\n\n// ── Human-readable error messages ──\n\nconst ERROR_MESSAGES: Record<string, string> = {\n // Vault — permissions / state\n InvalidOwner: \"The caller is not the vault owner.\",\n NotActiveAgent: \"Your wallet is not registered as an active agent on this vault. Ask the creator to run: sherwood fund approve --agent-id <id> --wallet <your-address>\",\n NotApprovedDepositor: \"Your address is not on the depositor whitelist. Ask the vault creator to approve you.\",\n NotGovernor: \"This operation can only be called by the governor contract.\",\n NotFactory: \"This operation can only be called by the factory contract.\",\n RedemptionsLocked: \"Redemptions are locked while a strategy is executing. Wait for the proposal to be settled.\",\n DepositsLocked: \"Deposits are locked while an active proposal exists. Wait for settlement.\",\n InvalidDepositor: \"Invalid depositor address.\",\n DepositorAlreadyApproved: \"This depositor is already on the whitelist.\",\n DepositorNotApproved: \"This depositor is not on the whitelist.\",\n AgentAlreadyRegistered: \"This agent wallet is already registered on the vault.\",\n AgentNotActive: \"This agent is registered but not active.\",\n InvalidAgentRegistry: \"Agent registry address is invalid.\",\n NotAgentOwner: \"You do not own this ERC-8004 agent identity NFT.\",\n InvalidAgentAddress: \"Invalid agent wallet address (cannot be zero).\",\n InvalidExecutorImpl: \"Executor implementation address is invalid.\",\n SimulationFailed: \"Transaction simulation failed — the batch calls would revert onchain.\",\n TransferFailed: \"ERC-20 token transfer failed. Check token balance and approvals.\",\n ZeroAddress: \"A required address parameter is the zero address.\",\n CannotRescueAsset: \"Cannot rescue the vault's underlying asset — use redeem() instead.\",\n\n // Governor — proposal lifecycle\n VaultNotRegistered: \"This vault is not registered with the governor. The factory registers vaults automatically on creation.\",\n VaultAlreadyRegistered: \"This vault is already registered with the governor.\",\n NotRegisteredAgent: \"Your wallet is not a registered agent on this vault. Register first via: sherwood fund approve\",\n PerformanceFeeTooHigh: \"Performance fee exceeds the governor's maxPerformanceFeeBps. Check: sherwood governor info\",\n StrategyDurationTooLong: \"Strategy duration exceeds the governor's maxStrategyDuration. Check: sherwood governor info\",\n StrategyDurationTooShort: \"Strategy duration is below the governor's minStrategyDuration. Check: sherwood governor info\",\n EmptyExecuteCalls: \"Proposal must include at least one execute call.\",\n EmptySettlementCalls: \"Proposal must include at least one settlement call.\",\n NotWithinVotingPeriod: \"Voting period has not started or has already ended. Check: sherwood proposal show <id>\",\n NoVotingPower: \"You have no voting power (zero vault shares at the snapshot time).\",\n AlreadyVoted: \"You have already voted on this proposal.\",\n ProposalNotFound: \"Proposal does not exist. Check the proposal ID.\",\n ProposalNotApproved: \"Proposal is not in Approved state. It may still be in voting or was rejected.\",\n ExecutionWindowExpired: \"The execution window has closed. The proposal is now Expired.\",\n StrategyAlreadyActive: \"Another strategy is currently executing on this vault. Settle it first before executing a new proposal.\",\n CooldownNotElapsed: \"A proposal was recently settled. Wait for the cooldown period to elapse. Check: sherwood governor info\",\n ProposalNotExecuted: \"Proposal has not been executed yet. Execute it first.\",\n ProposalNotCancellable: \"This proposal cannot be cancelled in its current state.\",\n NotProposer: \"Only the original proposer can perform this action.\",\n StrategyDurationNotElapsed: \"Strategy duration has not elapsed yet. Only the proposer can settle early.\",\n\n // Governor — parameter validation\n InvalidVotingPeriod: \"Voting period is outside allowed bounds (check governor constants).\",\n InvalidExecutionWindow: \"Execution window is outside allowed bounds.\",\n InvalidVetoThresholdBps: \"Veto threshold must be between the allowed bounds (in bps).\",\n InvalidMaxPerformanceFeeBps: \"Max performance fee is outside allowed bounds.\",\n InvalidStrategyDurationBounds: \"Strategy duration bounds are invalid (min must be < max).\",\n InvalidCooldownPeriod: \"Cooldown period is outside allowed bounds.\",\n InvalidVault: \"Invalid vault address.\",\n NotVaultOwner: \"Only the vault owner can perform this action.\",\n InvalidProtocolFeeBps: \"Protocol fee exceeds the 10% maximum (1000 bps).\",\n InvalidProtocolFeeRecipient: \"Protocol fee recipient must be set before enabling protocol fees.\",\n\n // Governor — collaborative proposals\n NotCoProposer: \"You are not listed as a co-proposer on this proposal.\",\n CollaborationExpired: \"The collaboration window has expired.\",\n AlreadyApproved: \"This co-proposer has already approved.\",\n InvalidSplits: \"Co-proposer fee splits must sum correctly with the lead proposer split.\",\n TooManyCoProposers: \"Exceeds the maximum number of co-proposers. Check: sherwood governor info\",\n SplitTooLow: \"A co-proposer's fee split is below the minimum.\",\n LeadSplitTooLow: \"The lead proposer's fee split is below the minimum.\",\n DuplicateCoProposer: \"Duplicate co-proposer address in the list.\",\n NotDraftState: \"Proposal must be in Draft state for this operation.\",\n InvalidCollaborationWindow: \"Collaboration window is outside allowed bounds.\",\n NotAuthorized: \"You are not authorized to perform this action.\",\n InvalidMaxCoProposers: \"Max co-proposers value is outside allowed bounds.\",\n Reentrancy: \"Reentrancy detected — this call cannot be made during another call.\",\n\n // Governor — parameter timelock\n ChangeAlreadyPending: \"A parameter change is already pending for this parameter. Finalize or cancel it first.\",\n NoChangePending: \"No parameter change is pending for this key.\",\n ChangeNotReady: \"Parameter change timelock has not elapsed yet. Wait for the delay to pass, then finalize.\",\n InvalidParameterChangeDelay: \"Parameter change delay is outside allowed bounds.\",\n InvalidParameterKey: \"Unknown parameter key.\",\n\n // Factory\n InvalidVaultImpl: \"Vault implementation address is invalid.\",\n InvalidENSRegistrar: \"ENS registrar address is invalid.\",\n SubdomainTooShort: \"Subdomain must be at least 3 characters.\",\n SubdomainTaken: \"This subdomain is already taken. Choose a different name.\",\n NotCreator: \"Only the fund creator can perform this action.\",\n InvalidGovernor: \"Governor address is invalid.\",\n InsufficientCreationFee: \"Insufficient creation fee. Check the required fee amount.\",\n InvalidFeeToken: \"Invalid fee token address.\",\n ManagementFeeTooHigh: \"Management fee exceeds the maximum allowed.\",\n UpgradesDisabled: \"Vault upgrades are currently disabled by the factory owner.\",\n VaultNotDeployed: \"Vault has not been deployed yet.\",\n StrategyActive: \"Cannot perform this action while a strategy is actively executing.\",\n\n // Strategy — base\n AlreadyInitialized: \"This strategy clone was already initialized. Deploy a fresh clone.\",\n NotVault: \"Only the vault can call this strategy function.\",\n NotExecuted: \"Strategy has not been executed yet.\",\n AlreadyExecuted: \"Strategy has already been executed.\",\n AlreadySettled: \"Strategy has already been settled.\",\n\n // Strategy — Moonwell / WstETH\n InvalidAmount: \"Invalid amount — must be greater than zero.\",\n MintFailed: \"Moonwell cToken mint failed. The underlying supply may have hit the market cap.\",\n RedeemFailed: \"Moonwell cToken redeem failed. Check that sufficient liquidity is available.\",\n\n // Strategy — Aerodrome\n GaugeMismatch: \"Aerodrome gauge does not match the expected pool.\",\n\n // Strategy — WstETH / Venice\n SwapFailed: \"Token swap failed. Check slippage tolerance and pool liquidity.\",\n AlreadySettledParams: \"Settlement parameters have already been set.\",\n\n // Strategy — Portfolio / UniswapSwapAdapter\n QuoteUnavailable:\n \"Uniswap quoter returned 0 or reverted for a portfolio allocation. \" +\n \"Usually means: (a) no V3 pool exists at the requested fee tier for one of the tokens, \" +\n \"(b) the strategy clone was initialized against an old/broken UniswapSwapAdapter \" +\n \"(check the clone's swapAdapter() vs the current chains JSON), or \" +\n \"(c) the adapter is calling Quoter with the wrong ABI (pre-PR #317 bug).\",\n UnsupportedMode: \"UniswapSwapAdapter doesn't support that swap mode. Only V3 single-hop (mode 0) and multi-hop (mode 1) are supported.\",\n InvalidWeights: \"Portfolio weights must sum to 10000 bps (100%).\",\n LengthMismatch: \"Portfolio input arrays (tokens / weights / swapExtraData / priceDecimals) must have the same length.\",\n TooManyTokens: \"Portfolio basket exceeds the maximum allocation count (20).\",\n RebalancingInProgress: \"A rebalance is already in flight on this clone. Wait for it to finish.\",\n StalePrice: \"Chainlink Data Streams report has expired. Refresh prices and retry.\",\n InvalidSlippage: \"maxSlippageBps must be > 0 and < 10000.\",\n InvalidPriceDecimals: \"priceDecimals entry exceeds 36. Use 8 for tokenized-stock feeds, 18 for crypto pairs.\",\n\n // Strategy — Venice\n NoAgent: \"No agent is registered on the vault. Register an agent first.\",\n};\n\n// ── Decoding ──\n\n/**\n * Attempt to decode a hex revert selector into a human-readable error message.\n * Returns null if the selector doesn't match any known contract error.\n */\nexport function decodeContractError(data: Hex): { name: string; message: string } | null {\n try {\n const decoded = decodeErrorResult({\n abi: CONTRACT_ERRORS_ABI,\n data,\n });\n const message = ERROR_MESSAGES[decoded.errorName] || `Contract error: ${decoded.errorName}`;\n return { name: decoded.errorName, message };\n } catch {\n return null;\n }\n}\n\n/**\n * Extract a hex error selector from a viem error's walk chain.\n * viem wraps contract call reverts in ContractFunctionRevertedError which\n * contains a `data` field with the raw 4-byte (or longer) revert payload.\n */\nfunction extractRevertData(err: unknown): Hex | null {\n if (!(err instanceof BaseError)) return null;\n\n // Walk the viem error chain to find revert data\n const revertError = err.walk((e) => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (e as any).data !== undefined;\n });\n\n if (revertError) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const data = (revertError as any).data;\n // data can be the hex string directly, or an object with a data field\n if (typeof data === \"string\" && data.startsWith(\"0x\")) {\n return data as Hex;\n }\n if (typeof data === \"object\" && data?.data && typeof data.data === \"string\") {\n return data.data as Hex;\n }\n }\n\n // Fallback: extract 0x + hex from the error message (e.g. \"reverted with 0x62df0545\")\n const msg = err.message || \"\";\n const match = msg.match(/(?:signature|data)\\s*\"?(0x[0-9a-fA-F]+)\"?/);\n if (match) return match[1] as Hex;\n\n return null;\n}\n\n// ── Known common EVM / ERC-20 revert strings ──\n\nconst KNOWN_REVERT_STRINGS: Record<string, string> = {\n \"ERC20: transfer amount exceeds balance\": \"Insufficient token balance for this transfer.\",\n \"ERC20: transfer amount exceeds allowance\": \"Token allowance insufficient. An approval step may have been skipped.\",\n \"ERC20: insufficient allowance\": \"Token allowance insufficient. An approval step may have been skipped.\",\n \"Ownable: caller is not the owner\": \"Only the contract owner can call this function.\",\n \"Pausable: paused\": \"The contract is currently paused.\",\n};\n\n/**\n * Format any caught error into a user-friendly message.\n *\n * Tries (in order):\n * 1. Decode custom error selector from our contract ABIs\n * 2. Match known EVM/ERC-20 revert reason strings\n * 3. Identify nonce / gas issues with actionable advice\n * 4. Fall back to the raw error message\n */\nexport function formatContractError(err: unknown): string {\n // 1. Try to decode custom contract error\n const revertData = extractRevertData(err);\n if (revertData && revertData.length >= 10) {\n const decoded = decodeContractError(revertData);\n if (decoded) return decoded.message;\n }\n\n const rawMsg = err instanceof Error ? err.message : String(err);\n\n // 2. Check for known revert reason strings\n for (const [pattern, message] of Object.entries(KNOWN_REVERT_STRINGS)) {\n if (rawMsg.includes(pattern)) return message;\n }\n\n // 3. Nonce / gas issues — already handled by retry, but surface clearly if they bubble up\n if (rawMsg.includes(\"replacement transaction underpriced\")) {\n return \"A previous transaction is stuck. The CLI retried with higher gas but the error persists. Try again in a moment.\";\n }\n if (rawMsg.includes(\"nonce too low\") || rawMsg.includes(\"NONCE_EXPIRED\")) {\n return \"Transaction nonce conflict — a previous transaction is still pending. Wait a moment and retry.\";\n }\n if (rawMsg.includes(\"insufficient funds for gas\")) {\n return `Insufficient ETH for gas fees. Top up your wallet with ETH on ${getChain().name}.`;\n }\n\n // 4. Clean up common viem wrapper noise\n // Strip \"ContractFunctionRevertedError:\" prefix and \"Docs:\" links\n let cleaned = rawMsg\n .replace(/ContractFunctionRevertedError:\\s*/g, \"\")\n .replace(/Docs:\\s*https:\\/\\/\\S+/g, \"\")\n .replace(/Version:\\s*viem@\\S+/g, \"\")\n .replace(/Request Arguments:[\\s\\S]*$/m, \"\")\n .replace(/Contract Call:[\\s\\S]*?(?=\\n\\n|\\n[A-Z]|$)/m, \"\")\n .trim();\n\n // If we still have \"reverted with the following signature: 0x...\" try one more decode\n const sigMatch = cleaned.match(/signature[:\\s]+\"?(0x[0-9a-fA-F]{8,})\"?/);\n if (sigMatch) {\n const decoded = decodeContractError(sigMatch[1] as Hex);\n if (decoded) return decoded.message;\n // If we can't decode it, at least explain what it is\n const explorer = getChain().blockExplorers?.default?.name ?? \"the block explorer\";\n cleaned = `Contract reverted with unknown error selector ${sigMatch[1]}. Check the transaction on ${explorer} for details.`;\n }\n\n return cleaned;\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/swap-router.ts","../src/lib/template-encoder.ts","../src/strategies/moonwell-supply-template.ts","../src/strategies/venice-inference-template.ts","../src/strategies/aerodrome-lp-template.ts","../src/strategies/wsteth-moonwell-template.ts","../src/strategies/mamo-yield-template.ts","../src/strategies/portfolio-template.ts","../src/strategies/hyperliquid-perp-template.ts","../src/lib/abis-legacy.ts","../src/strategies/hyperliquid-grid-template.ts"],"sourcesContent":["/**\n * SwapRouter — the single owner of \"swap tokenIn→tokenOut on the current chain\".\n *\n * Surface (small, deep):\n * - detectRoute(tokenIn, tokenOut, feeTier?) → Route (wraps template-encoder's\n * detectSwapRoute; pure on the current deployment target)\n * - buildSwapCalldata(route, opts?) → adapter swapExtraData (delegates\n * byte encoding to template-encoder's tested buildSwapExtraData)\n * - quote({tokenIn, tokenOut, amountIn}) → Route + amountOut via the active\n * network's QuoterV2 (Synthra shim on robinhood-testnet)\n *\n * Quoting primitives (getQuote / getMultiHopQuote) moved here from lib/quote.ts,\n * which is now a back-compat re-export shim. QuoterV2's quote functions are NOT\n * view — they revert internally after computing — so we use eth_call and decode\n * the return data. The client is injectable (`deps.client`) so tests never need\n * a live RPC.\n *\n * Path/extraData byte layouts are owned by template-encoder.ts (golden-vector\n * tested) and strategies/portfolio-template.ts (v4 modes) — this module only\n * composes them; it never re-implements an encoding.\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeFunctionData, decodeFunctionResult } from \"viem\";\nimport { getPublicClient } from \"./client.js\";\nimport { getNetwork } from \"./network.js\";\nimport { UNISWAP } from \"./addresses.js\";\nimport { UNISWAP_QUOTER_V2_ABI } from \"./abis.js\";\nimport { buildSwapExtraData, detectSwapRoute, encodeV3Path } from \"./template-encoder.js\";\n\nexport const DEFAULT_FEE_TIER = 3000;\n\nconst ZERO: Address = \"0x0000000000000000000000000000000000000000\";\n\n/**\n * Minimal client surface needed for quoting (eth_call). getPublicClient()\n * satisfies it; tests inject a mock.\n */\nexport interface QuoterClient {\n call(args: { to: Address; data: Hex }): Promise<{ data?: Hex }>;\n}\n\nexport interface QuoteDeps {\n client?: QuoterClient;\n}\n\nexport type Route =\n | {\n kind: \"v3-direct\";\n tokenIn: Address;\n tokenOut: Address;\n feeTier: number;\n routeDesc: string;\n }\n | {\n kind: \"v3-hop\";\n tokenIn: Address;\n tokenOut: Address;\n via: Address;\n feeIn: number;\n feeOut: number;\n routeDesc: string;\n };\n\nexport interface QuoteResult {\n amountOut: bigint;\n sqrtPriceX96After: bigint;\n gasEstimate: bigint;\n}\n\nexport interface Quote extends QuoteResult {\n route: Route;\n}\n\n// ── Route detection ──\n\n/**\n * Detect the swap route for a token pair on the current chain.\n * Wraps template-encoder's detectSwapRoute (which owns the per-chain routing\n * decision); on the current deployment target this is pure — always a direct\n * v3-style route through the Synthra-backed adapter.\n */\nexport async function detectRoute(\n tokenIn: Address,\n tokenOut: Address,\n preferredFeeTier: number = DEFAULT_FEE_TIER,\n): Promise<Route> {\n const detected = await detectSwapRoute(tokenIn, tokenOut, preferredFeeTier);\n if (!detected) {\n throw new Error(`No swap route found for ${tokenIn}→${tokenOut} (fee ${preferredFeeTier})`);\n }\n return {\n kind: \"v3-direct\",\n tokenIn,\n tokenOut,\n feeTier: preferredFeeTier,\n routeDesc: detected.routeDesc,\n };\n}\n\n// ── Calldata building ──\n\n/**\n * Build adapter swapExtraData for a route. Byte encoding is delegated to\n * template-encoder's tested buildSwapExtraData (mode 0 single-hop / mode 1\n * multi-hop with a per-hop slippage budget).\n */\nexport function buildSwapCalldata(\n route: Route,\n opts: { perHopSlippageBps?: number } = {},\n): Hex {\n const network = getNetwork();\n if (route.kind === \"v3-hop\") {\n return buildSwapExtraData(\n network,\n route.tokenIn,\n route.tokenOut,\n route.feeIn,\n { via: route.via, feeIn: route.feeIn, feeOut: route.feeOut },\n opts.perHopSlippageBps ?? 100,\n );\n }\n return buildSwapExtraData(network, route.tokenIn, route.tokenOut, route.feeTier);\n}\n\n// ── Quoting ──\n\nfunction quoterAddress(): Address {\n const quoter = UNISWAP().QUOTER_V2;\n if (quoter === ZERO) {\n throw new Error(\"QuoterV2 not deployed on this network\");\n }\n return quoter;\n}\n\n/**\n * Quote a swap on the current chain: detect the route, then price it through\n * the network's QuoterV2 (Synthra shim on robinhood-testnet).\n */\nexport async function quote(\n params: { tokenIn: Address; tokenOut: Address; amountIn: bigint; feeTier?: number },\n deps: QuoteDeps = {},\n): Promise<Quote> {\n const route = await detectRoute(params.tokenIn, params.tokenOut, params.feeTier);\n if (route.kind === \"v3-hop\") {\n const path = encodeSwapPath(\n [route.tokenIn, route.via, route.tokenOut],\n [route.feeIn, route.feeOut],\n );\n const result = await getMultiHopQuote({ path, amountIn: params.amountIn }, deps);\n return { route, ...result };\n }\n const result = await getQuote(\n {\n tokenIn: route.tokenIn,\n tokenOut: route.tokenOut,\n amountIn: params.amountIn,\n fee: route.feeTier,\n },\n deps,\n );\n return { route, ...result };\n}\n\n/**\n * Get a single-hop swap quote from QuoterV2 (moved from lib/quote.ts).\n */\nexport async function getQuote(\n params: { tokenIn: Address; tokenOut: Address; amountIn: bigint; fee: number },\n deps: QuoteDeps = {},\n): Promise<QuoteResult> {\n const client = deps.client ?? getPublicClient();\n\n const calldata = encodeFunctionData({\n abi: UNISWAP_QUOTER_V2_ABI,\n functionName: \"quoteExactInputSingle\",\n args: [\n {\n tokenIn: params.tokenIn,\n tokenOut: params.tokenOut,\n amountIn: params.amountIn,\n fee: params.fee,\n sqrtPriceLimitX96: 0n,\n },\n ],\n });\n\n const { data } = await client.call({ to: quoterAddress(), data: calldata });\n\n if (!data) {\n throw new Error(\"Quoter returned no data — pool may not exist for this pair/fee\");\n }\n\n const [amountOut, sqrtPriceX96After, , gasEstimate] = decodeFunctionResult({\n abi: UNISWAP_QUOTER_V2_ABI,\n functionName: \"quoteExactInputSingle\",\n data,\n }) as [bigint, bigint, number, bigint];\n\n return { amountOut, sqrtPriceX96After, gasEstimate };\n}\n\n/**\n * Get a multi-hop swap quote from QuoterV2 (moved from lib/quote.ts).\n */\nexport async function getMultiHopQuote(\n params: { path: Hex; amountIn: bigint },\n deps: QuoteDeps = {},\n): Promise<QuoteResult> {\n const client = deps.client ?? getPublicClient();\n\n const calldata = encodeFunctionData({\n abi: UNISWAP_QUOTER_V2_ABI,\n functionName: \"quoteExactInput\",\n args: [params.path, params.amountIn],\n });\n\n const { data } = await client.call({ to: quoterAddress(), data: calldata });\n\n if (!data) {\n throw new Error(\"Quoter returned no data — pool may not exist for this path\");\n }\n\n const [amountOut, , , gasEstimate] = decodeFunctionResult({\n abi: UNISWAP_QUOTER_V2_ABI,\n functionName: \"quoteExactInput\",\n data,\n }) as [bigint, bigint[], number[], bigint];\n\n return { amountOut, sqrtPriceX96After: 0n, gasEstimate };\n}\n\n// ── Pure helpers (moved from lib/quote.ts) ──\n\n/**\n * Apply slippage tolerance to a quote amount.\n * Returns the minimum acceptable output amount.\n */\nexport function applySlippage(amountOut: bigint, slippageBps: number): bigint {\n return (amountOut * BigInt(10000 - slippageBps)) / 10000n;\n}\n\n/**\n * Encode a Uniswap V3 multi-hop swap path (address + uint24 fee + address ...).\n * Validates the shape here (>= 2 tokens), then delegates the byte layout to\n * template-encoder's tested encodeV3Path.\n */\nexport function encodeSwapPath(tokens: Address[], fees: number[]): Hex {\n if (tokens.length < 2 || fees.length !== tokens.length - 1) {\n throw new Error(\"Invalid path: need at least 2 tokens and (tokens-1) fees\");\n }\n return encodeV3Path(tokens, fees);\n}\n\n/** Token decimals for display purposes (moved from lib/quote.ts). */\nexport const TOKEN_DECIMALS: Record<string, number> = {\n USDC: 6,\n WETH: 18,\n cbETH: 18,\n wstETH: 18,\n cbBTC: 8,\n DAI: 18,\n AERO: 18,\n};\n","/**\n * Template encoder — pure params → bytes encoding for strategy templates.\n *\n * Extracted from commands/strategy-template.ts so the calldata-producing logic\n * is testable without a chain. The interface is deliberately small:\n *\n * - buildInitDataForTemplate(templateKey, opts, vault, resolved?) — per-template\n * initialize() payload + the asset/amount the vault must fund.\n * - buildCallsForTemplate(templateKey, clone, asset, amount, extraApprovals?) —\n * the execute/settle BatchCall arrays for a proposal.\n *\n * Secondary exports (parseSwapRouteSpec, buildSwapExtraData, encodeV3Path,\n * parseAlignedOverrides, computeProposalAssetChecks, resolve* helpers) exist for\n * the command layer and for tests.\n *\n * PURITY RULE: nothing in this module performs chain I/O or touches the signer.\n * The two inputs that historically needed RPC (the Venice minVVV auto-quote and\n * the Aerodrome tokenA/tokenB decimals) are supplied by the caller via\n * `ResolvedChainInputs` — see resolveChainInputsForTemplate in\n * commands/strategy-template.ts. Registry lookups (TOKENS(), CHAINLINK(), …) are\n * config reads keyed off the network singleton, not RPC.\n */\n\nimport type { Address, Hex } from \"viem\";\nimport {\n parseUnits,\n isAddress,\n encodeAbiParameters,\n concat,\n numberToHex,\n} from \"viem\";\nimport chalk from \"chalk\";\n\nimport { getNetwork } from \"./network.js\";\nimport {\n TOKENS,\n MOONWELL,\n VENICE,\n AERODROME,\n UNISWAP,\n SYNTHRA,\n CHAINLINK,\n ROBINHOOD_STOCK_ROUTES,\n robinhoodEquityMaxAge,\n} from \"./addresses.js\";\nimport type { BatchCall } from \"./batch.js\";\n\nimport * as moonwellBuilder from \"../strategies/moonwell-supply-template.js\";\nimport * as veniceBuilder from \"../strategies/venice-inference-template.js\";\nimport * as aerodromeBuilder from \"../strategies/aerodrome-lp-template.js\";\nimport * as wstethBuilder from \"../strategies/wsteth-moonwell-template.js\";\nimport * as mamoBuilder from \"../strategies/mamo-yield-template.js\";\nimport * as portfolioBuilder from \"../strategies/portfolio-template.js\";\nimport * as hyperliquidPerpBuilder from \"../strategies/hyperliquid-perp-template.js\";\nimport * as hyperliquidGridBuilder from \"../strategies/hyperliquid-grid-template.js\";\n\nconst ZERO: Address = \"0x0000000000000000000000000000000000000000\";\nconst ZERO_BYTES32 =\n \"0x0000000000000000000000000000000000000000000000000000000000000000\" as Hex;\n\n/**\n * Chain-derived inputs the encoder cannot (and must not) fetch itself.\n * Resolved by the command layer BEFORE encoding (see\n * resolveChainInputsForTemplate in commands/strategy-template.ts).\n */\nexport interface ResolvedChainInputs {\n /** venice-inference: agent wallet — the caller defaults it to the signer. */\n veniceAgent?: Address;\n /**\n * venice-inference: auto-quoted minVVV (18-dec) for a non-direct path when\n * --min-vvv was not passed. Quoted via the Aerodrome router off-module.\n */\n veniceMinVVV?: bigint;\n /** aerodrome-lp: on-chain decimals() of tokenA / tokenB. */\n aerodromeDecimals?: { decimalsA: number; decimalsB: number };\n}\n\n// ── Uniswap V3 swap routing helpers ──\n\n/**\n * Encode Uniswap V3 packed path: token (20 bytes) + fee (3 bytes) + token (20 bytes) [+ fee + token ...]\n */\nexport function encodeV3Path(tokens: Address[], fees: number[]): Hex {\n if (tokens.length !== fees.length + 1) throw new Error(\"tokens.length must be fees.length + 1\");\n const parts: Hex[] = [];\n for (let i = 0; i < tokens.length; i++) {\n parts.push(tokens[i].toLowerCase() as Hex);\n if (i < fees.length) {\n // fee as 3 bytes (uint24)\n parts.push(numberToHex(fees[i], { size: 3 }));\n }\n }\n return concat(parts);\n}\n\n/**\n * Build swapExtraData for the UniswapSwapAdapter.\n *\n * Mode 0 — single-hop: 0x00 + abi.encode(uint24 fee)\n * Mode 1 — multi-hop: 0x01 + abi.encode(bytes path, uint16 perHopSlippageBps)\n *\n * Sherlock run #2 #11: mode-1 extraData now carries a per-hop slippage\n * budget so the adapter's `_chainedSingleHops` can enforce a per-hop\n * `amountOutMinimum` derived from a quoter pre-call at swap time. This\n * closes the cascading-sandwich attack on intermediate hops. Default\n * to 100 bps (1%) per hop unless the caller overrides — conservative\n * for typical V3 routes; mainnet templates with deeper pools can\n * tighten this. The adapter still enforces the top-level `amountOutMin`\n * on the final hop, so cumulative slippage is doubly capped.\n *\n * robinhood-testnet uses the registry UniswapSwapAdapter (Synthra-router-backed,\n * QuoterV2-shim), which consumes the SAME mode-prefixed encoding as the other\n * chains — mode 0 single-hop / mode 1 multi-hop — so no special-case here.\n */\nexport function buildSwapExtraData(\n network: string,\n tokenIn: Address,\n tokenOut: Address,\n feeTier: number,\n hop?: { via: Address; feeIn: number; feeOut: number },\n perHopSlippageBps: number = 100,\n): Hex {\n if (hop) {\n // Multi-hop: tokenIn → hop.via → tokenOut\n const path = encodeV3Path([tokenIn, hop.via, tokenOut], [hop.feeIn, hop.feeOut]);\n const encoded = encodeAbiParameters(\n [{ type: \"bytes\" }, { type: \"uint16\" }],\n [path, perHopSlippageBps],\n );\n return `0x01${encoded.slice(2)}` as Hex;\n }\n\n // Single-hop: mode 0\n const encoded = encodeAbiParameters([{ type: \"uint24\" }], [feeTier]);\n return `0x00${encoded.slice(2)}` as Hex;\n}\n\n// ── Explicit per-token swap-route spec parsing (--swap-routes) ──\n//\n// One entry per allocation, comma-separated at the flag level. Each entry:\n// 'v3:<fee>' → mode 0 (v3 single-hop)\n// 'v4:<fee>:<tickSpacing>' → mode 2 (v4 single-hop hookless)\n// 'v4path:<hop>+<hop>+...' → mode 3 (v4 multi-hop hookless)\n// where hop = '<currency>@<fee>:<tickSpacing>' and\n// currency ∈ { 'eth'|'native' → address(0), 'self' → this allocation's\n// token, or a literal 0x-address }. The last hop's currency MUST resolve\n// to the allocation token (contract-enforced); 'self' is the ergonomic form.\n\nexport function parseSwapRouteSpec(spec: string, token: Address): Hex {\n const s = spec.trim();\n const [kind, ...restParts] = s.split(\":\");\n const rest = restParts.join(\":\");\n switch (kind) {\n case \"v3\": {\n const fee = Number(rest);\n if (!Number.isInteger(fee) || fee <= 0) throw new Error(`bad v3 fee in '${spec}'`);\n return portfolioBuilder.v3SingleHopExtraData(fee);\n }\n case \"v4\": {\n const [feeStr, tsStr] = rest.split(\":\");\n const fee = Number(feeStr);\n const tickSpacing = Number(tsStr);\n if (!Number.isInteger(fee) || fee <= 0) throw new Error(`bad v4 fee in '${spec}'`);\n if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) throw new Error(`bad v4 tickSpacing in '${spec}'`);\n return portfolioBuilder.v4SingleHopExtraData(fee, tickSpacing);\n }\n case \"v4path\": {\n const hops = rest.split(\"+\").map((hopStr) => {\n const [currencyRaw, feeTs] = hopStr.split(\"@\");\n if (!feeTs) throw new Error(`bad v4path hop '${hopStr}' in '${spec}' (expected currency@fee:tickSpacing)`);\n const [feeStr, tsStr] = feeTs.split(\":\");\n const fee = Number(feeStr);\n const tickSpacing = Number(tsStr);\n if (!Number.isInteger(fee) || fee <= 0) throw new Error(`bad v4path fee in '${spec}'`);\n if (!Number.isInteger(tickSpacing) || tickSpacing <= 0) throw new Error(`bad v4path tickSpacing in '${spec}'`);\n const c = currencyRaw.trim().toLowerCase();\n let currency: Address;\n if (c === \"eth\" || c === \"native\") currency = ZERO;\n else if (c === \"self\") currency = token;\n else if (isAddress(currencyRaw.trim())) currency = currencyRaw.trim() as Address;\n else throw new Error(`bad v4path currency '${currencyRaw}' in '${spec}' (use eth/native/self/0x-address)`);\n return { currency, fee, tickSpacing };\n });\n return portfolioBuilder.v4PathExtraData(hops);\n }\n default:\n throw new Error(`unknown swap-route kind '${kind}' in '${spec}' (use v3/v4/v4path)`);\n }\n}\n\n/**\n * Auto-detect swap route for a token pair on Uniswap V3.\n * Returns { direct: true, feeTier } or { direct: false, hop } or null if no route found.\n *\n * NOTE (encoder purity): on the current deployment target this performs NO\n * chain I/O — the multi-chain v3 pool probing was removed with Base/HyperEVM.\n * If per-chain detection comes back, the pool probing belongs in the command\n * layer (resolveChainInputsForTemplate), NOT here.\n */\nexport async function detectSwapRoute(\n asset: Address,\n token: Address,\n preferredFeeTier: number,\n): Promise<{ extraData: Hex; routeDesc: string } | null> {\n const network = getNetwork();\n // Current deployment target (robinhood-testnet) uses a direct v3-style route\n // via the Synthra-backed adapter. Multi-chain v3 auto-detect (Base/HyperEVM)\n // was removed with those chains; re-add per-chain detection here when a chain\n // with distinct routing comes back.\n return {\n extraData: buildSwapExtraData(network, asset, token, preferredFeeTier),\n routeDesc: `direct (fee ${preferredFeeTier})`,\n };\n}\n\n// ── Helpers for building init data per template ──\n\n/**\n * Pure (no-RPC) derivation of the assets a propose call will pull from the\n * vault. Mirrors the asset/amount slice of `buildInitDataForTemplate` so the\n * propose preflight can balance-check the vault BEFORE clone + init burns\n * any gas. Returns one entry per token the vault has to fund — single\n * entry for most templates, two for aerodrome-lp (tokenA + tokenB).\n *\n * Templates whose amount is `0n` (hyperliquid-perp / -grid in dynamic-all\n * mode, wsteth-moonwell without --amount) intentionally return entries\n * with `amount === 0n`; the caller short-circuits on those.\n *\n * Kept in sync with `buildInitDataForTemplate` per-branch logic. The\n * sync-invariant suite in template-encoder.test.ts enforces the mirror for\n * venice-inference, wsteth-moonwell, mamo-yield, portfolio, hyperliquid-perp\n * and hyperliquid-grid. NOT enforced there: moonwell-supply (no Moonwell\n * market on the Robinhood-testnet token registry, so the branch is\n * unreachable in tests) and aerodrome-lp (returns [] — per-leg decimals\n * need RPC). Diverging here only weakens the preflight guard — the real\n * values still come from `buildInitDataForTemplate`, so we'd just miss a\n * warning, never produce an inconsistent on-chain call.\n */\nexport function computeProposalAssetChecks(\n templateKey: string,\n opts: Record<string, string | boolean | undefined>,\n): { asset: Address; amount: bigint; label: string }[] {\n if (templateKey === \"moonwell-supply\" || templateKey === \"mamo-yield\") {\n if (!opts.amount) return [];\n const token = (opts.token as string) || \"USDC\";\n const asset = resolveToken(token);\n const decimals = assetDecimalsForSymbol(token);\n return [{ asset, amount: parseUnits(opts.amount as string, decimals), label: token.toUpperCase() }];\n }\n\n if (templateKey === \"venice-inference\") {\n if (!opts.amount) return [];\n const assetSymbol = (opts.asset as string) || \"USDC\";\n const asset = resolveToken(assetSymbol);\n const decimals = assetDecimalsForSymbol(assetSymbol);\n return [{ asset, amount: parseUnits(opts.amount as string, decimals), label: assetSymbol.toUpperCase() }];\n }\n\n if (templateKey === \"aerodrome-lp\") {\n // Aerodrome needs both legs of the pair funded. We can't compute the\n // per-leg parseUnits without a decimals() RPC, so we fall back to a\n // raw-units balance check (vault must hold at least `amountA` raw of\n // tokenA AND `amountB` raw of tokenB). Worst case: a stricter check\n // than needed, never permissive.\n if (!opts.tokenA || !opts.tokenB || !opts.amountA || !opts.amountB) return [];\n // amountA/amountB are human strings — without decimals we can't normalize.\n // Skip the precise check for aerodrome and let buildInitDataForTemplate\n // handle errors. (Other templates cover the common --amount footgun.)\n return [];\n }\n\n if (templateKey === \"wsteth-moonwell\") {\n if (!opts.amount) return []; // dynamic-all mode\n return [{\n asset: TOKENS().WETH,\n amount: parseUnits(opts.amount as string, 18),\n label: \"WETH\",\n }];\n }\n\n if (templateKey === \"portfolio\") {\n if (!opts.amount) return [];\n // Keep this in lock-step with buildInitDataForTemplate's portfolio branch:\n // default asset is USDG on robinhood mainnet (6 dec, no USDC there), WETH on\n // robinhood-testnet, USDC elsewhere; decimals resolved from token metadata.\n const assetSymbol = (opts.asset as string) || defaultPortfolioAsset();\n const asset = resolveToken(assetSymbol);\n const decimals = assetDecimalsForSymbol(assetSymbol);\n return [{ asset, amount: parseUnits(opts.amount as string, decimals), label: assetSymbol.toUpperCase() }];\n }\n\n if (templateKey === \"hyperliquid-perp\" || templateKey === \"hyperliquid-grid\") {\n if (!opts.amount) return []; // dynamic-all mode — skip check\n const token = (opts.token as string) || \"USDC\";\n const asset = resolveToken(token);\n const decimals = assetDecimalsForSymbol(token);\n return [{ asset, amount: parseUnits(opts.amount as string, decimals), label: token.toUpperCase() }];\n }\n\n return [];\n}\n\n/**\n * Parse a comma-separated per-allocation override flag (--feed-ids,\n * --price-decimals, --swap-routes, --max-price-ages) into a slot-aligned array.\n *\n * Empty entries are PRESERVED (trimmed to \"\"), NOT filtered — so partial\n * overrides work: an empty slot falls through to that flag's per-slot\n * auto-resolve default (e.g. `--price-decimals \"8,,8\"` overrides slots 0 and 2\n * and auto-resolves slot 1). Filtering empties would collapse the length and\n * either misalign the remaining entries or trip the length check.\n *\n * Alignment is validated only when the flag is PRESENT (`raw !== undefined`):\n * an unset flag yields `[]` and `mismatch: false`. A present flag whose entry\n * count ≠ `expectedLen` returns `mismatch: true` for the caller to hard-exit.\n * (An unset flag is `undefined` here; `\"\"` — an explicitly empty flag — is\n * \"present\" and splits to `[\"\"]`, i.e. one empty slot.)\n */\nexport function parseAlignedOverrides(\n raw: string | undefined,\n expectedLen: number,\n): { values: string[]; mismatch: boolean } {\n if (raw === undefined) return { values: [], mismatch: false };\n const values = raw.split(\",\").map((s) => s.trim());\n return { values, mismatch: values.length !== expectedLen };\n}\n\nexport async function buildInitDataForTemplate(\n templateKey: string,\n opts: Record<string, string | boolean | undefined>,\n vault: Address,\n resolved?: ResolvedChainInputs,\n): Promise<{ initData: Hex; asset: Address; assetAmount: bigint; extraApprovals?: { token: Address; amount: bigint }[] }> {\n if (templateKey === \"moonwell-supply\") {\n if (!opts.amount) {\n console.error(chalk.red(\"--amount is required for moonwell-supply template\"));\n process.exit(1);\n }\n const token = (opts.token as string) || \"USDC\";\n const underlying = resolveToken(token);\n const mToken = resolveMToken(token);\n const decimals = assetDecimalsForSymbol(token);\n const supplyAmount = parseUnits(opts.amount as string, decimals);\n const minRedeem = parseUnits((opts.minRedeem as string) || opts.amount as string, decimals);\n // V2: Moonwell's native-ETH (mWETH) market redeems raw ETH the strategy\n // wraps back to WETH — every non-USDC token here is the WETH market.\n const isNativeEthMarket = token.toUpperCase() !== \"USDC\";\n\n return {\n initData: moonwellBuilder.buildInitData(underlying, mToken, supplyAmount, minRedeem, isNativeEthMarket),\n asset: underlying,\n assetAmount: supplyAmount,\n };\n }\n\n if (templateKey === \"venice-inference\") {\n if (!opts.amount) {\n console.error(chalk.red(\"--amount is required for venice-inference template\"));\n process.exit(1);\n }\n const assetSymbol = (opts.asset as string) || \"USDC\";\n const asset = resolveToken(assetSymbol);\n const vvv = VENICE().VVV;\n const isDirect = asset.toLowerCase() === vvv.toLowerCase();\n const decimals = assetDecimalsForSymbol(assetSymbol);\n const assetAmount = parseUnits(opts.amount as string, decimals);\n // The signer-default agent and the Aerodrome getAmountsOut auto-quote are\n // chain/signer concerns — the command layer resolves both (see\n // resolveChainInputsForTemplate) and passes them in.\n const agent = (opts.agent as Address) || resolved?.veniceAgent;\n if (!agent) {\n throw new Error(\n \"venice-inference: missing agent — pass --agent or resolve chain inputs (signer default) before encoding\",\n );\n }\n const isSingleHop = !!opts.singleHop;\n\n // minVVV: explicit flag wins; non-direct paths without it need the\n // caller-resolved auto-quote (5% slippage applied at quote time).\n let minVVV = 0n;\n if (!isDirect) {\n if (opts.minVvv) {\n minVVV = parseUnits(opts.minVvv as string, 18);\n } else if (resolved?.veniceMinVVV !== undefined) {\n minVVV = resolved.veniceMinVVV;\n } else {\n throw new Error(\n \"venice-inference: missing resolved minVVV quote — pass --min-vvv or resolve chain inputs before encoding\",\n );\n }\n }\n\n const params: veniceBuilder.VeniceInferenceInitParams = {\n asset,\n weth: isDirect ? ZERO : TOKENS().WETH,\n vvv,\n sVVV: VENICE().STAKING,\n aeroRouter: isDirect ? ZERO : AERODROME().ROUTER,\n aeroFactory: isDirect ? ZERO : AERODROME().FACTORY,\n agent,\n assetAmount,\n minVVV,\n deadlineOffset: 300n,\n singleHop: isSingleHop,\n };\n\n return {\n initData: veniceBuilder.buildInitData(params),\n asset,\n assetAmount,\n };\n }\n\n if (templateKey === \"aerodrome-lp\") {\n for (const flag of [\"tokenA\", \"tokenB\", \"amountA\", \"amountB\", \"lpToken\"]) {\n if (!opts[flag]) {\n console.error(chalk.red(`--${flag.replace(/([A-Z])/g, \"-$1\").toLowerCase()} is required for aerodrome-lp template`));\n process.exit(1);\n }\n }\n const tokenA = opts.tokenA as Address;\n const tokenB = opts.tokenB as Address;\n // decimals() is a chain read — the command layer resolves it (see\n // resolveChainInputsForTemplate) and passes it in.\n if (!resolved?.aerodromeDecimals) {\n throw new Error(\n \"aerodrome-lp: missing resolved tokenA/tokenB decimals — resolve chain inputs before encoding\",\n );\n }\n const { decimalsA, decimalsB } = resolved.aerodromeDecimals;\n const amountA = parseUnits(opts.amountA as string, decimalsA);\n const amountB = parseUnits(opts.amountB as string, decimalsB);\n const minAOut = parseUnits((opts.minAOut as string) || \"0\", decimalsA);\n const minBOut = parseUnits((opts.minBOut as string) || \"0\", decimalsB);\n\n const params: aerodromeBuilder.AerodromeLPInitParams = {\n tokenA,\n tokenB,\n stable: !!opts.stable,\n factory: AERODROME().FACTORY,\n router: AERODROME().ROUTER,\n gauge: (opts.gauge as Address) || ZERO,\n lpToken: opts.lpToken as Address,\n amountADesired: amountA,\n amountBDesired: amountB,\n amountAMin: amountA, // use desired as min for now\n amountBMin: amountB,\n minAmountAOut: minAOut,\n minAmountBOut: minBOut,\n };\n\n return {\n initData: aerodromeBuilder.buildInitData(params),\n asset: tokenA,\n assetAmount: amountA,\n extraApprovals: [{ token: tokenB, amount: amountB }],\n };\n }\n\n if (templateKey === \"wsteth-moonwell\") {\n const supplyAmount = opts.amount ? parseUnits(opts.amount as string, 18) : 0n; // WETH = 18 decimals; 0 => use full vault balance at execute time\n const slippageBps = BigInt((opts.slippage as string) || \"500\"); // default 5% slippage\n // Per-unit rates (1e18-scaled) — Aerodrome wstETH/WETH stable pool trades\n // near 1:1, so default the expected rate to 1e18. Slippage cuts from that.\n // Rates scale with amountIn at execute time → dynamic-all mode is safe.\n const ONE = 10n ** 18n;\n const minWstethOutPerWeth = (ONE * (10000n - slippageBps)) / 10000n;\n const minWethOutPerWsteth = (ONE * (10000n - slippageBps)) / 10000n;\n\n const params: wstethBuilder.WstETHMoonwellInitParams = {\n weth: TOKENS().WETH,\n wsteth: TOKENS().wstETH,\n mwsteth: MOONWELL().mWstETH,\n aeroRouter: AERODROME().ROUTER,\n aeroFactory: AERODROME().FACTORY,\n chainlinkWstethEthFeed: CHAINLINK().WSTETH_ETH_FEED,\n supplyAmount,\n minWstethOutPerWeth,\n minWethOutPerWsteth,\n deadlineOffset: 300n,\n };\n\n return {\n initData: wstethBuilder.buildInitData(params),\n asset: TOKENS().WETH,\n assetAmount: supplyAmount,\n };\n }\n\n if (templateKey === \"mamo-yield\") {\n if (!opts.amount) {\n console.error(chalk.red(\"--amount is required for mamo-yield template\"));\n process.exit(1);\n }\n if (!opts.mamoFactory) {\n console.error(chalk.red(\"--mamo-factory is required for mamo-yield template\"));\n process.exit(1);\n }\n const token = (opts.token as string) || \"USDC\";\n const underlying = resolveToken(token);\n const decimals = assetDecimalsForSymbol(token);\n const amount = parseUnits(opts.amount as string, decimals);\n const minRedeemAmount = parseUnits((opts.minRedeem as string) || opts.amount as string, decimals);\n\n return {\n initData: mamoBuilder.buildInitData(underlying, opts.mamoFactory as Address, minRedeemAmount),\n asset: underlying,\n assetAmount: amount,\n };\n }\n\n if (templateKey === \"portfolio\") {\n if (!opts.amount) { console.error(chalk.red(\"--amount is required for portfolio template\")); process.exit(1); }\n if (!opts.tokens || !opts.weights) {\n console.error(chalk.red(\"--tokens and --weights are required for portfolio template\"));\n console.error(chalk.dim(\" --tokens: comma-separated token addresses or symbols\"));\n console.error(chalk.dim(\" --weights: comma-separated bps (must sum to 10000)\"));\n process.exit(1);\n }\n const network = getNetwork();\n const tokens = TOKENS();\n const assetSymbol = (opts.asset as string) || defaultPortfolioAsset();\n const asset = resolveToken(assetSymbol);\n const decimals = assetDecimalsForSymbol(assetSymbol);\n const totalAmount = parseUnits(opts.amount as string, decimals);\n const maxSlippageBps = Number((opts.maxSlippage as string) || \"500\");\n const feeTier = (opts.feeTier as string) || \"3000\";\n\n // Parse token specs, keeping the original symbol/spec so we can resolve a\n // Chainlink push feed on chains that use AggregatorV3 push feeds.\n const tokenSpecs = (opts.tokens as string).split(\",\").map((t) => t.trim());\n const tokenAddrs = tokenSpecs.map((trimmed) => {\n if (isAddress(trimmed)) return trimmed as Address;\n const allTokens = tokens as Record<string, Address>;\n const resolvedAddr = allTokens[trimmed.toUpperCase()];\n if (resolvedAddr && resolvedAddr !== ZERO) return resolvedAddr;\n console.error(chalk.red(`Unknown token: ${trimmed}`)); process.exit(1);\n });\n const weightsBps = (opts.weights as string).split(\",\").map((w) => Number(w.trim()));\n if (tokenAddrs.length !== weightsBps.length) { console.error(chalk.red(\"--tokens and --weights must have same length\")); process.exit(1); }\n if (weightsBps.reduce((a, b) => a + b, 0) !== 10000) { console.error(chalk.red(`Weights must sum to 10000`)); process.exit(1); }\n\n const swapAdapter = (opts.swapAdapter as Address) || resolveSwapAdapter();\n const chainlinkVerifier = CHAINLINK().VERIFIER_PROXY;\n // Push-feed mode (chainlinkVerifier == 0, e.g. Robinhood mainnet): each\n // allocation's feedId is an AggregatorV3 proxy left-padded to bytes32, and\n // priceDecimals must equal that feed's decimals() (8 on Robinhood mainnet).\n const pushMode = chainlinkVerifier === ZERO;\n const chainlink = CHAINLINK() as Record<string, Address>;\n\n // Optional explicit per-allocation overrides (comma-separated, aligned to\n // --tokens). All four flags parse identically via parseAlignedOverrides:\n // empty entries are preserved so a partial override (e.g. \"8,,8\") falls\n // through to that slot's auto-resolve default; a PRESENT flag must align\n // 1:1 with --tokens (an unset flag → [] and skips the check).\n // --feed-ids: bytes32 feed ids (Data Streams) or feed addresses (push\n // mode). Empty slot → auto-resolve SYMBOL_USD_FEED below.\n // --price-decimals: raw feed scale per allocation. Empty slot → pushMode 8\n // / else 18 default below.\n const feedIds = parseAlignedOverrides(opts.feedIds as string | undefined, tokenAddrs.length);\n const feedIdOverrides = feedIds.values;\n if (feedIds.mismatch) { console.error(chalk.red(\"--feed-ids must have the same length as --tokens\")); process.exit(1); }\n const priceDecimals = parseAlignedOverrides(opts.priceDecimals as string | undefined, tokenAddrs.length);\n const priceDecimalOverrides = priceDecimals.values;\n if (priceDecimals.mismatch) { console.error(chalk.red(\"--price-decimals must have the same length as --tokens\")); process.exit(1); }\n\n // Explicit per-token swap-route overrides (aligned to --tokens). An empty\n // entry falls through to the robinhood default / auto-detect below.\n const swapRoutes = parseAlignedOverrides(opts.swapRoutes as string | undefined, tokenAddrs.length);\n const swapRouteOverrides = swapRoutes.values;\n if (swapRoutes.mismatch) { console.error(chalk.red(\"--swap-routes must have the same length as --tokens\")); process.exit(1); }\n\n // Optional per-token max-price-age override (seconds), comma-aligned to\n // --tokens. Packs into the push-mode feedId's upper bits. Empty entry → the\n // registry-driven default (96h for equity feeds, 0/contract-default otherwise).\n const maxPriceAges = parseAlignedOverrides(opts.maxPriceAges as string | undefined, tokenAddrs.length);\n const maxPriceAgeOverrides = maxPriceAges.values;\n if (maxPriceAges.mismatch) { console.error(chalk.red(\"--max-price-ages must have the same length as --tokens\")); process.exit(1); }\n\n // Robinhood mainnet default swap routes come from the data-driven\n // ROBINHOOD_STOCK_ROUTES registry (verified on-chain liquidity) plus a WETH\n // v3 fee-500 leg. A robinhood basket token with a feed but NO verified route\n // and NO --swap-routes override fails fast (see below) rather than falling\n // through to a v3 auto-detect that is guaranteed dead on 4663.\n const wethAddr = TOKENS().WETH;\n function robinhoodDefaultRoute(token: Address, symbol: string): { extraData: Hex; routeDesc: string } | null {\n // Robinhood-mainnet-only default route (verified ROBINHOOD_STOCK_ROUTES).\n // Mainnet is not in the current deployment target, so this is inert today;\n // string-compare keeps it forward-compatible for when 4663 is added back.\n if ((network as string) !== \"robinhood\") return null;\n if (wethAddr !== ZERO && token.toLowerCase() === wethAddr.toLowerCase()) {\n return { extraData: portfolioBuilder.v3SingleHopExtraData(500), routeDesc: \"v3 direct (fee 500)\" };\n }\n const r = ROBINHOOD_STOCK_ROUTES[symbol.toUpperCase()];\n if (r) {\n return {\n extraData: portfolioBuilder.v4PathExtraData([\n { currency: ZERO, fee: r.nativeFee, tickSpacing: r.nativeTickSpacing },\n { currency: token, fee: r.stockFee, tickSpacing: r.stockTickSpacing },\n ]),\n routeDesc: `v4 multi-hop (USDG→ETH fee ${r.nativeFee} / ts ${r.nativeTickSpacing} → ${symbol.toUpperCase()} fee ${r.stockFee} / ts ${r.stockTickSpacing})`,\n };\n }\n return null;\n }\n\n // Auto-detect swap routes for each token\n console.log(chalk.dim(\" Detecting swap routes...\"));\n const allocations: portfolioBuilder.BasketAllocation[] = [];\n for (let i = 0; i < tokenAddrs.length; i++) {\n const token = tokenAddrs[i];\n let route: { extraData: Hex; routeDesc: string } | null = null;\n const override = swapRouteOverrides[i];\n if (override) {\n try {\n route = { extraData: parseSwapRouteSpec(override, token), routeDesc: `explicit '${override}'` };\n } catch (e) {\n console.error(chalk.red(`Bad --swap-routes entry for ${tokenSpecs[i]}: ${(e as Error).message}`));\n process.exit(1);\n }\n }\n if (!route) route = robinhoodDefaultRoute(token, tokenSpecs[i]);\n if (!route && (network as string) === \"robinhood\") {\n // No verified default route and no override. v3 auto-detect is dead on\n // 4663 (no v3 stock pools) — fail fast with an actionable message rather\n // than emitting a doomed proposal.\n console.error(\n chalk.red(\n `No verified default swap route for ${tokenSpecs[i]} on robinhood mainnet.`,\n ),\n );\n console.error(\n chalk.yellow(\n ` Pass --swap-routes to set it explicitly for this token, e.g.\\n` +\n ` --swap-routes 'v4path:eth@500:10+self@50000:1000' (USDG→ETH→${tokenSpecs[i].toUpperCase()})`,\n ),\n );\n process.exit(1);\n }\n if (!route) route = await detectSwapRoute(asset, token, Number(feeTier));\n if (!route) {\n console.error(chalk.red(`No swap route found for ${token}. No Uniswap V3 pool (direct or via WETH). Pass --swap-routes to set it explicitly.`));\n process.exit(1);\n }\n console.log(chalk.dim(` ${token.slice(0, 10)}... → ${route.routeDesc}`));\n\n // Resolve the per-allocation Chainlink feed id + priceDecimals.\n let feedId = feedIdOverrides[i] as portfolioBuilder.BasketAllocation[\"feedId\"] | undefined;\n // Default priceDecimals: 8 in push mode (Robinhood mainnet feeds),\n // 18 otherwise (crypto Data Streams pairs); override wins.\n let priceDecimals = priceDecimalOverrides[i]\n ? Number(priceDecimalOverrides[i])\n : pushMode ? 8 : 18;\n\n // Per-slot max price age (seconds), packed into the push-mode feedId.\n // Precedence: explicit --max-price-ages > registry default (96h for\n // Robinhood equity feeds; 0 = contract default for crypto/stable feeds).\n const sym = tokenSpecs[i].toUpperCase();\n let maxPriceAge = 0;\n if (maxPriceAgeOverrides[i]) {\n // Explicit --max-price-ages overrides everything (unchanged precedence).\n maxPriceAge = Number(maxPriceAgeOverrides[i]);\n if (!Number.isInteger(maxPriceAge) || maxPriceAge < 0) {\n console.error(chalk.red(`Bad --max-price-ages entry for ${tokenSpecs[i]}: '${maxPriceAgeOverrides[i]}' (expected a non-negative integer count of seconds)`));\n process.exit(1);\n }\n } else if (pushMode && (network as string) === \"robinhood\") {\n // Registry-driven default: classify the token as equity vs crypto to\n // pack the 96h max-age into the push feedId. Works for tokens given by\n // SYMBOL and (via reverse-lookup) by raw 0x address — otherwise a stock\n // token passed by address silently falls back to the contract's 26h\n // default and trips StalePrice over long weekends.\n const { maxPriceAge: age, unknownAddress } = robinhoodEquityMaxAge(\n tokenSpecs[i],\n tokens as Record<string, Address>,\n portfolioBuilder.EQUITY_MAX_PRICE_AGE_SECONDS,\n );\n maxPriceAge = age;\n if (unknownAddress && feedIdOverrides[i]) {\n // Raw address unknown to the registry + an explicit feed id: we can't\n // classify it, so the slot will use the contract's 26h default. Warn\n // rather than guess — equity feeds need an explicit --max-price-ages.\n console.warn(\n chalk.yellow(\n ` Warning: token ${tokenSpecs[i]} is not in the ${network} registry, so its ` +\n `push feed uses the contract's 26h default max-price-age.\\n` +\n ` If this is a tokenized-equity feed, pass --max-price-ages (e.g. ${portfolioBuilder.EQUITY_MAX_PRICE_AGE_SECONDS}) ` +\n `for this slot or it will trip StalePrice over long weekends.`,\n ),\n );\n }\n }\n\n if (pushMode && !feedId) {\n // Auto-resolve SYMBOL_USD_FEED from the CHAINLINK() registry by symbol.\n // WETH/ETH share the ETH_USD_FEED key (there is no WETH_USD_FEED).\n const feedKey = sym === \"WETH\" || sym === \"ETH\" ? \"ETH_USD_FEED\" : `${sym}_USD_FEED`;\n const feed = isAddress(tokenSpecs[i]) ? undefined : chainlink[feedKey];\n if (!feed || feed === ZERO) {\n console.error(chalk.red(`No Chainlink push feed for ${tokenSpecs[i]} on ${network}. Pass --feed-ids <feedAddr,...> to supply AggregatorV3 addresses.`));\n process.exit(1);\n }\n feedId = portfolioBuilder.pushFeedId(feed, maxPriceAge);\n } else if (pushMode && feedId && isAddress(feedId)) {\n // Push-mode override given as a bare address — pad to bytes32 (+ age).\n feedId = portfolioBuilder.pushFeedId(feedId as Address, maxPriceAge);\n }\n\n if (!feedId || feedId === ZERO_BYTES32) {\n console.error(chalk.red(`Missing Chainlink feedId for allocation ${i} (${tokenSpecs[i]}). The strategy requires a non-zero feedId per token — pass --feed-ids as a comma-separated list.`));\n process.exit(1);\n }\n\n allocations.push({\n token, weightBps: weightsBps[i],\n swapExtraData: route.extraData,\n priceDecimals,\n feedId,\n });\n }\n return {\n initData: portfolioBuilder.buildInitData(asset, swapAdapter, chainlinkVerifier, allocations, totalAmount, maxSlippageBps),\n asset, assetAmount: totalAmount,\n };\n }\n\n if (templateKey === \"hyperliquid-perp\") {\n const token = (opts.token as string) || \"USDC\";\n const asset = resolveToken(token);\n const decimals = assetDecimalsForSymbol(token);\n // Omit --amount to use the vault's full asset balance at execute time (dynamic-all mode).\n const depositAmount = opts.amount ? parseUnits(opts.amount as string, decimals) : 0n;\n const leverage = Number((opts.leverage as string) || \"10\");\n const assetIndex = Number((opts.assetIndex as string) || \"0\");\n const maxPosition = parseUnits((opts.maxPosition as string) || \"100000\", decimals);\n const maxTradesDay = Number((opts.maxTradesPerDay as string) || \"50\");\n return {\n initData: hyperliquidPerpBuilder.buildInitData(asset, depositAmount, assetIndex, leverage, maxPosition, maxTradesDay),\n asset, assetAmount: depositAmount,\n };\n }\n\n if (templateKey === \"hyperliquid-grid\") {\n const token = (opts.token as string) || \"USDC\";\n const asset = resolveToken(token);\n const decimals = assetDecimalsForSymbol(token);\n const depositAmount = opts.amount ? parseUnits(opts.amount as string, decimals) : 0n;\n const leverage = Number((opts.leverage as string) || \"5\");\n const maxOrderSize = parseUnits((opts.maxOrderSize as string) || \"10000\", decimals);\n const maxOrdersPerTick = Number((opts.maxOrdersPerTick as string) || \"20\");\n const assetIndices = ((opts.assetIndices as string) || \"0\")\n .split(\",\")\n .map((s) => Number(s.trim()))\n .filter((n) => !Number.isNaN(n));\n return {\n initData: hyperliquidGridBuilder.buildInitData(asset, depositAmount, leverage, maxOrderSize, maxOrdersPerTick, assetIndices),\n asset, assetAmount: depositAmount,\n };\n }\n\n throw new Error(`No init builder for template: ${templateKey}`);\n}\n\nexport function buildCallsForTemplate(\n templateKey: string,\n clone: Address,\n asset: Address,\n assetAmount: bigint,\n extraApprovals?: { token: Address; amount: bigint }[],\n): { executeCalls: BatchCall[]; settleCalls: BatchCall[] } {\n if (templateKey === \"moonwell-supply\") {\n return {\n executeCalls: moonwellBuilder.buildExecuteCalls(clone, asset, assetAmount),\n settleCalls: moonwellBuilder.buildSettleCalls(clone),\n };\n }\n\n if (templateKey === \"venice-inference\") {\n return {\n executeCalls: veniceBuilder.buildExecuteCalls(clone, asset, assetAmount),\n settleCalls: veniceBuilder.buildSettleCalls(clone),\n };\n }\n\n if (templateKey === \"aerodrome-lp\") {\n const tokenB = extraApprovals?.[0]?.token ?? ZERO;\n const amountB = extraApprovals?.[0]?.amount ?? 0n;\n return {\n executeCalls: aerodromeBuilder.buildExecuteCalls(clone, asset, assetAmount, tokenB, amountB),\n settleCalls: aerodromeBuilder.buildSettleCalls(clone),\n };\n }\n\n if (templateKey === \"wsteth-moonwell\") {\n return {\n executeCalls: wstethBuilder.buildExecuteCalls(clone, asset, assetAmount),\n settleCalls: wstethBuilder.buildSettleCalls(clone),\n };\n }\n\n if (templateKey === \"mamo-yield\") {\n return {\n executeCalls: mamoBuilder.buildExecuteCalls(clone, asset, assetAmount),\n settleCalls: mamoBuilder.buildSettleCalls(clone),\n };\n }\n\n if (templateKey === \"portfolio\") {\n return {\n executeCalls: portfolioBuilder.buildExecuteCalls(clone, asset, assetAmount),\n settleCalls: portfolioBuilder.buildSettleCalls(clone),\n };\n }\n\n if (templateKey === \"hyperliquid-perp\") {\n return {\n executeCalls: hyperliquidPerpBuilder.buildExecuteCalls(clone, asset, assetAmount),\n settleCalls: hyperliquidPerpBuilder.buildSettleCalls(clone),\n };\n }\n\n if (templateKey === \"hyperliquid-grid\") {\n return {\n executeCalls: hyperliquidGridBuilder.buildExecuteCalls(clone, asset, assetAmount),\n settleCalls: hyperliquidGridBuilder.buildSettleCalls(clone),\n };\n }\n\n throw new Error(`No call builder for template: ${templateKey}`);\n}\n\n// ── Token resolution (registry lookups — config reads, not RPC) ──\n\nexport function resolveSwapAdapter(): Address {\n const network = getNetwork();\n if (network === \"robinhood-testnet\" && SYNTHRA().ROUTER === ZERO) {\n console.error(chalk.red(\"Synthra DEX not available\"));\n process.exit(1);\n }\n // The deployed adapter on robinhood-testnet is the registry's UniswapSwapAdapter\n // (UNISWAP_SWAP_ADAPTER), backed by Synthra's router + a QuoterV2 shim\n // (SYNTHRA_QUOTER_V2_SHIM). It consumes MODE-PREFIXED extraData (0x00 single-hop\n // / 0x01 multi-hop — see buildSwapExtraData). An earlier build hardcoded a bare\n // SynthraDirectAdapter address here paired with un-prefixed extraData; that\n // adapter's on-chain `quote()` returns 0 (bricking PortfolioStrategy execute\n // with QuoteUnavailable), so always resolve the registry adapter instead.\n const adapterAddr = UNISWAP().SWAP_ADAPTER;\n if (adapterAddr !== ZERO) return adapterAddr;\n console.error(chalk.red(\"UniswapSwapAdapter not deployed yet. Use --swap-adapter to specify manually.\"));\n process.exit(1);\n}\n\nexport function resolveToken(symbolOrAddress: string): Address {\n if (isAddress(symbolOrAddress)) return symbolOrAddress as Address;\n const upper = symbolOrAddress.toUpperCase();\n // Spread the per-network TOKENS() registry (so USDG / stock tokens on robinhood\n // resolve without a second hand-rolled map — mirrors the basket-token path),\n // then overlay VVV which lives in the Venice registry rather than TOKENS().\n const tokenMap: Record<string, Address> = {\n ...(TOKENS() as Record<string, Address>),\n VVV: VENICE().VVV,\n };\n const addr = tokenMap[upper];\n if (!addr || addr === ZERO) {\n console.error(chalk.red(`Unknown token: ${symbolOrAddress}`));\n process.exit(1);\n }\n return addr;\n}\n\n/**\n * Default vault asset for the portfolio template on the current network:\n * WETH on Robinhood testnet (an ETH-only chain), USDG on the Robinhood mainnet\n * fork, USDC as the forward-compatible default for any other chain added back.\n * Single source of truth shared by buildInitDataForTemplate +\n * computeProposalAssetChecks.\n *\n * THE FORK BRANCH IS NOT COSMETIC. Robinhood mainnet has no USDC — the token\n * resolves to address(0) — so falling through to the USDC default made every\n * portfolio proposal on the fork die in preflight with a bare\n * \"Unknown token: USDC\", naming a token the operator never asked for. The rest\n * of this file already assumed otherwise (\"default asset is USDG on robinhood\n * mainnet (6 dec, no USDC there)\"); this is the line that was left behind.\n */\nexport function defaultPortfolioAsset(): string {\n const network = getNetwork();\n if (network === \"robinhood-testnet\") return \"WETH\";\n if (network === \"robinhood-fork\") return \"USDG\";\n return \"USDC\";\n}\n\n/**\n * Decimals for a vault-asset symbol. USDC and USDG are 6-decimal stables; every\n * other supported vault asset (WETH, stock tokens, …) is 18-decimal. Kept as one\n * helper so the funding math can't drift between the preflight check and the\n * on-chain init data.\n */\nexport function assetDecimalsForSymbol(symbol: string): number {\n const upper = symbol.toUpperCase();\n return upper === \"USDC\" || upper === \"USDG\" ? 6 : 18;\n}\n\nexport function resolveMToken(tokenSymbol: string): Address {\n const upper = tokenSymbol.toUpperCase();\n const moonwell = MOONWELL();\n const mTokenMap: Record<string, Address> = {\n USDC: moonwell.mUSDC,\n WETH: moonwell.mWETH,\n };\n const addr = mTokenMap[upper];\n if (!addr || addr === ZERO) {\n console.error(chalk.red(`No Moonwell market for: ${tokenSymbol}`));\n process.exit(1);\n }\n return addr;\n}\n","/**\n * MoonwellSupplyStrategy call builder.\n *\n * InitParams (Solidity, V2): (address underlying, address mToken, uint256 supplyAmount,\n * uint256 minRedeemAmount, bool isNativeEthMarket)\n *\n * `isNativeEthMarket` — true when the mToken is Moonwell's native-ETH (mWETH)\n * market, whose redeem returns raw ETH the strategy must wrap back to WETH.\n * false for ERC-20 markets (USDC). V2 beta added this field; encoding the old\n * 4-field payload makes the clone's `initialize` abi.decode revert with empty\n * data (vnet e2e finding, issues #411-#414).\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeAbiParameters, encodeFunctionData } from \"viem\";\nimport { ERC20_ABI, BASE_STRATEGY_ABI } from \"../lib/abis.js\";\nimport type { BatchCall } from \"../lib/batch.js\";\n\nexport function buildInitData(\n underlying: Address,\n mToken: Address,\n supplyAmount: bigint,\n minRedeemAmount: bigint,\n isNativeEthMarket: boolean,\n): Hex {\n return encodeAbiParameters(\n [\n { type: \"address\" },\n { type: \"address\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"bool\" },\n ],\n [underlying, mToken, supplyAmount, minRedeemAmount, isNativeEthMarket],\n );\n}\n\nexport function buildExecuteCalls(\n clone: Address,\n underlying: Address,\n supplyAmount: bigint,\n): BatchCall[] {\n return [\n {\n target: underlying,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, supplyAmount],\n }),\n value: 0n,\n },\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"execute\",\n }),\n value: 0n,\n },\n ];\n}\n\nexport function buildSettleCalls(clone: Address): BatchCall[] {\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"settle\",\n }),\n value: 0n,\n },\n ];\n}\n","/**\n * VeniceInferenceStrategy call builder.\n *\n * InitParams (Solidity struct):\n * address asset, address weth, address vvv, address sVVV,\n * address aeroRouter, address aeroFactory, address agent,\n * uint256 assetAmount, uint256 minVVV, uint256 deadlineOffset, bool singleHop\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeAbiParameters, encodeFunctionData } from \"viem\";\nimport { ERC20_ABI, BASE_STRATEGY_ABI } from \"../lib/abis.js\";\nimport type { BatchCall } from \"../lib/batch.js\";\n\nexport interface VeniceInferenceInitParams {\n asset: Address;\n weth: Address;\n vvv: Address;\n sVVV: Address;\n aeroRouter: Address;\n aeroFactory: Address;\n agent: Address;\n assetAmount: bigint;\n minVVV: bigint;\n deadlineOffset: bigint;\n singleHop: boolean;\n}\n\nconst INIT_PARAMS_TYPES = [\n {\n type: \"tuple\" as const,\n components: [\n { name: \"asset\", type: \"address\" as const },\n { name: \"weth\", type: \"address\" as const },\n { name: \"vvv\", type: \"address\" as const },\n { name: \"sVVV\", type: \"address\" as const },\n { name: \"aeroRouter\", type: \"address\" as const },\n { name: \"aeroFactory\", type: \"address\" as const },\n { name: \"agent\", type: \"address\" as const },\n { name: \"assetAmount\", type: \"uint256\" as const },\n { name: \"minVVV\", type: \"uint256\" as const },\n { name: \"deadlineOffset\", type: \"uint256\" as const },\n { name: \"singleHop\", type: \"bool\" as const },\n ],\n },\n] as const;\n\nexport function buildInitData(params: VeniceInferenceInitParams): Hex {\n return encodeAbiParameters(INIT_PARAMS_TYPES, [params]);\n}\n\nexport function buildExecuteCalls(\n clone: Address,\n asset: Address,\n assetAmount: bigint,\n): BatchCall[] {\n return [\n {\n target: asset,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, assetAmount],\n }),\n value: 0n,\n },\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"execute\",\n }),\n value: 0n,\n },\n ];\n}\n\nexport function buildSettleCalls(clone: Address): BatchCall[] {\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"settle\",\n }),\n value: 0n,\n },\n ];\n}\n","/**\n * AerodromeLPStrategy call builder.\n *\n * InitParams (Solidity struct):\n * address tokenA, address tokenB, bool stable,\n * address factory, address router, address gauge, address lpToken,\n * uint256 amountADesired, uint256 amountBDesired,\n * uint256 amountAMin, uint256 amountBMin,\n * uint256 minAmountAOut, uint256 minAmountBOut\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeAbiParameters, encodeFunctionData } from \"viem\";\nimport { ERC20_ABI, BASE_STRATEGY_ABI } from \"../lib/abis.js\";\nimport type { BatchCall } from \"../lib/batch.js\";\n\nexport interface AerodromeLPInitParams {\n tokenA: Address;\n tokenB: Address;\n stable: boolean;\n factory: Address;\n router: Address;\n gauge: Address;\n lpToken: Address;\n amountADesired: bigint;\n amountBDesired: bigint;\n amountAMin: bigint;\n amountBMin: bigint;\n minAmountAOut: bigint;\n minAmountBOut: bigint;\n}\n\nconst INIT_PARAMS_TYPES = [\n {\n type: \"tuple\" as const,\n components: [\n { name: \"tokenA\", type: \"address\" as const },\n { name: \"tokenB\", type: \"address\" as const },\n { name: \"stable\", type: \"bool\" as const },\n { name: \"factory\", type: \"address\" as const },\n { name: \"router\", type: \"address\" as const },\n { name: \"gauge\", type: \"address\" as const },\n { name: \"lpToken\", type: \"address\" as const },\n { name: \"amountADesired\", type: \"uint256\" as const },\n { name: \"amountBDesired\", type: \"uint256\" as const },\n { name: \"amountAMin\", type: \"uint256\" as const },\n { name: \"amountBMin\", type: \"uint256\" as const },\n { name: \"minAmountAOut\", type: \"uint256\" as const },\n { name: \"minAmountBOut\", type: \"uint256\" as const },\n ],\n },\n] as const;\n\nexport function buildInitData(params: AerodromeLPInitParams): Hex {\n return encodeAbiParameters(INIT_PARAMS_TYPES, [params]);\n}\n\nexport function buildExecuteCalls(\n clone: Address,\n tokenA: Address,\n amountA: bigint,\n tokenB: Address,\n amountB: bigint,\n): BatchCall[] {\n return [\n {\n target: tokenA,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, amountA],\n }),\n value: 0n,\n },\n {\n target: tokenB,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, amountB],\n }),\n value: 0n,\n },\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"execute\",\n }),\n value: 0n,\n },\n ];\n}\n\nexport function buildSettleCalls(clone: Address): BatchCall[] {\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"settle\",\n }),\n value: 0n,\n },\n ];\n}\n","/**\n * WstETHMoonwellStrategy call builder.\n *\n * InitParams (Solidity struct):\n * address weth, address wsteth, address mwsteth,\n * address aeroRouter, address aeroFactory, address chainlinkWstethEthFeed,\n * uint256 supplyAmount, uint256 minWstethOutPerWeth, uint256 minWethOutPerWsteth, uint256 deadlineOffset\n * supplyAmount = 0 means use the vault's full WETH balance at execute time\n * min*PerX are 1e18-scaled per-unit rates so slippage protection scales with amountIn.\n * chainlinkWstethEthFeed is the Chainlink WSTETH/ETH price feed used by the\n * strategy's `_positionValue` for live NAV during an active proposal. Base\n * mainnet: 0x43a5C292A453A3bF3606fa856197f09D7B74251a (heartbeat 24h, 18 decimals).\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeAbiParameters, encodeFunctionData, maxUint256 } from \"viem\";\nimport { ERC20_ABI, BASE_STRATEGY_ABI } from \"../lib/abis.js\";\nimport type { BatchCall } from \"../lib/batch.js\";\n\nexport interface WstETHMoonwellInitParams {\n weth: Address;\n wsteth: Address;\n mwsteth: Address;\n aeroRouter: Address;\n aeroFactory: Address;\n chainlinkWstethEthFeed: Address;\n supplyAmount: bigint;\n minWstethOutPerWeth: bigint;\n minWethOutPerWsteth: bigint;\n deadlineOffset: bigint;\n}\n\nconst INIT_PARAMS_TYPES = [\n {\n type: \"tuple\" as const,\n components: [\n { name: \"weth\", type: \"address\" as const },\n { name: \"wsteth\", type: \"address\" as const },\n { name: \"mwsteth\", type: \"address\" as const },\n { name: \"aeroRouter\", type: \"address\" as const },\n { name: \"aeroFactory\", type: \"address\" as const },\n { name: \"chainlinkWstethEthFeed\", type: \"address\" as const },\n { name: \"supplyAmount\", type: \"uint256\" as const },\n { name: \"minWstethOutPerWeth\", type: \"uint256\" as const },\n { name: \"minWethOutPerWsteth\", type: \"uint256\" as const },\n { name: \"deadlineOffset\", type: \"uint256\" as const },\n ],\n },\n] as const;\n\nexport function buildInitData(params: WstETHMoonwellInitParams): Hex {\n return encodeAbiParameters(INIT_PARAMS_TYPES, [params]);\n}\n\nexport function buildExecuteCalls(\n clone: Address,\n weth: Address,\n supplyAmount: bigint,\n): BatchCall[] {\n // In dynamic-all mode (supplyAmount == 0) we can't know the exact amount\n // at proposal-build time, so approve maxUint256 then revoke to 0 after\n // execute() in the same batch. This bounds the residual allowance to a\n // single atomic tx — any leftover approval is cleared before control\n // returns to the governor.\n const approveAmount = supplyAmount === 0n ? maxUint256 : supplyAmount;\n\n return [\n {\n target: weth,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, approveAmount],\n }),\n value: 0n,\n },\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"execute\",\n }),\n value: 0n,\n },\n {\n target: weth,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, 0n],\n }),\n value: 0n,\n },\n ];\n}\n\nexport function buildSettleCalls(clone: Address): BatchCall[] {\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"settle\",\n }),\n value: 0n,\n },\n ];\n}\n","/**\n * MamoYieldStrategy call builder.\n *\n * InitParams (Solidity): (address underlying, address mamoFactory, uint256 minRedeemAmount)\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeAbiParameters, encodeFunctionData } from \"viem\";\nimport { ERC20_ABI, BASE_STRATEGY_ABI } from \"../lib/abis.js\";\nimport type { BatchCall } from \"../lib/batch.js\";\n\nexport function buildInitData(\n underlying: Address,\n mamoFactory: Address,\n minRedeemAmount: bigint,\n): Hex {\n return encodeAbiParameters(\n [\n { type: \"address\" },\n { type: \"address\" },\n { type: \"uint256\" },\n ],\n [underlying, mamoFactory, minRedeemAmount],\n );\n}\n\nexport function buildExecuteCalls(\n clone: Address,\n underlying: Address,\n amount: bigint,\n): BatchCall[] {\n return [\n {\n target: underlying,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, amount],\n }),\n value: 0n,\n },\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"execute\",\n }),\n value: 0n,\n },\n ];\n}\n\nexport function buildSettleCalls(clone: Address): BatchCall[] {\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"settle\",\n }),\n value: 0n,\n },\n ];\n}","/**\n * PortfolioStrategy call builder.\n *\n * InitParams (Solidity): (address asset, address swapAdapter, address chainlinkVerifier,\n * address[] tokens, uint256[] weightsBps, uint256 totalAmount, uint256 maxSlippageBps,\n * bytes[] swapExtraData, uint8[] priceDecimals, bytes32[] feedIds)\n *\n * `priceDecimals[i]` declares the raw Chainlink feed scale for allocation `i`\n * (typically 8 for tokenized stocks, 18 for crypto pairs). It normalizes the\n * position value into the vault asset's decimals.\n *\n * `feedIds[i]` binds each allocation to its expected Chainlink feed (Sherlock\n * #56). Two modes, selected by `chainlinkVerifier`:\n * - Data Streams (chainlinkVerifier != 0): feedIds[i] is the report feed id.\n * - Push feeds (chainlinkVerifier == 0, e.g. Robinhood mainnet): feedIds[i]\n * is an AggregatorV3 proxy address left-padded to bytes32\n * (`bytes32(uint160(feed))`); the contract asserts the feed's live\n * `decimals()` equals `priceDecimals[i]`.\n * feedIds[i] must be non-zero in both modes.\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { concat, encodeAbiParameters, encodeFunctionData, numberToHex, pad } from \"viem\";\nimport { ERC20_ABI, BASE_STRATEGY_ABI } from \"../lib/abis.js\";\nimport type { BatchCall } from \"../lib/batch.js\";\n\n// ── UniswapSwapAdapter swapExtraData builders ──\n//\n// Wire format for every mode: one raw mode byte, then abi-encoded route data\n// (see UniswapSwapAdapter.sol header):\n// Mode 0 — v3 single-hop: 0x00 + abi.encode(uint24 fee)\n// Mode 1 — v3 multi-hop: 0x01 + abi.encode(bytes path, uint16 perHopSlippageBps)\n// Mode 2 — v4 single-hop: 0x02 + abi.encode(uint24 fee, int24 tickSpacing)\n// Mode 3 — v4 multi-hop: 0x03 + abi.encode(PathHop[]) where\n// PathHop = { address currency; uint24 fee; int24 tickSpacing }\n// hop i swaps prev currency → hops[i].currency; native ETH = address(0)\n// allowed as an intermediate; last hop currency MUST equal the token.\n\nconst ZERO_ADDRESS: Address = \"0x0000000000000000000000000000000000000000\";\n\n/** Concatenate a raw 1-byte mode prefix with abi-encoded route data. */\nfunction withMode(mode: number, routeData: Hex): Hex {\n const modeByte = (`0x${mode.toString(16).padStart(2, \"0\")}`) as Hex;\n return concat([modeByte, routeData]);\n}\n\n/** Mode 0 — Uniswap v3 single-hop. */\nexport function v3SingleHopExtraData(fee: number): Hex {\n return withMode(0, encodeAbiParameters([{ type: \"uint24\" }], [fee]));\n}\n\n/** Mode 2 — Uniswap v4 single-hop (hookless). */\nexport function v4SingleHopExtraData(fee: number, tickSpacing: number): Hex {\n return withMode(\n 2,\n encodeAbiParameters(\n [{ type: \"uint24\" }, { type: \"int24\" }],\n [fee, tickSpacing],\n ),\n );\n}\n\nexport interface V4PathHop {\n currency: Address; // address(0) = native ETH; last hop MUST equal the allocation token\n fee: number;\n tickSpacing: number;\n}\n\n/** Mode 3 — Uniswap v4 multi-hop (hookless; native ETH allowed as intermediate). */\nexport function v4PathExtraData(hops: V4PathHop[]): Hex {\n // The adapter's _orientHops reverts InvalidPath for n < 2 (a single hop is\n // mode 2) — reject at build time instead of at first execution.\n if (hops.length < 2) throw new Error(\"v4PathExtraData: mode 3 needs >= 2 hops (use v4SingleHopExtraData for one)\");\n return withMode(\n 3,\n encodeAbiParameters(\n [\n {\n type: \"tuple[]\",\n components: [\n { type: \"address\", name: \"currency\" },\n { type: \"uint24\", name: \"fee\" },\n { type: \"int24\", name: \"tickSpacing\" },\n ],\n },\n ],\n [hops.map((h) => ({ currency: h.currency, fee: h.fee, tickSpacing: h.tickSpacing }))],\n ),\n );\n}\n\nexport { ZERO_ADDRESS as NATIVE_ETH };\n\nexport interface BasketAllocation {\n token: Address;\n weightBps: number; // e.g. 4000 = 40%\n swapExtraData: Hex; // adapter-specific (fee tier, path, etc.)\n priceDecimals: number; // Chainlink feed report decimals (8 or 18)\n feedId: Hex; // bytes32: Data Streams feed id, or bytes32(uint160(pushFeed))\n}\n\n/** Default max price age (seconds) for a tokenized-equity push feed on Robinhood\n * mainnet: 96h. Equity feeds go ~77h stale over holiday weekends, past the\n * contract's 26h default — so we pack a wider staleness window per equity slot.\n * Crypto/FX/stable feeds pass 0 (→ contract default 26h). */\nexport const EQUITY_MAX_PRICE_AGE_SECONDS = 96 * 60 * 60; // 345_600\n\n// Contract-enforced bounds on a packed per-slot max price age (0 = default).\nconst MIN_MAX_PRICE_AGE = 3600; // 1h\nconst MAX_MAX_PRICE_AGE = 2_592_000; // 30d\n\n/**\n * Pack a Chainlink AggregatorV3 proxy address (+ optional per-slot max price age)\n * into a bytes32 feed id for push-feed mode (`chainlinkVerifier == address(0)`):\n *\n * bytes32 = uint256(maxAgeSeconds) << 160 | uint160(feedAddress)\n *\n * `maxAgeSeconds`:\n * - omitted / 0 → lower 160 bits only (contract falls back to its 26h default;\n * byte-identical to the plain left-padded address).\n * - provided → must be within [3600, 2_592_000] seconds.\n *\n * The contract decodes the address via `address(uint160(uint256(feedIds[i])))`\n * and the age via `uint256(feedIds[i]) >> 160`.\n */\nexport function pushFeedId(feed: Address, maxAgeSeconds?: number): Hex {\n if (maxAgeSeconds === undefined || maxAgeSeconds === 0) {\n return pad(feed, { size: 32 });\n }\n if (\n !Number.isInteger(maxAgeSeconds) ||\n maxAgeSeconds < MIN_MAX_PRICE_AGE ||\n maxAgeSeconds > MAX_MAX_PRICE_AGE\n ) {\n throw new Error(\n `pushFeedId: maxAgeSeconds must be an integer in [${MIN_MAX_PRICE_AGE}, ${MAX_MAX_PRICE_AGE}] (or 0 for the contract default), got ${maxAgeSeconds}`,\n );\n }\n // (age << 160) | uint160(addr), as a 32-byte hex string.\n const packed = (BigInt(maxAgeSeconds) << 160n) | BigInt(feed);\n return numberToHex(packed, { size: 32 });\n}\n\nexport function buildInitData(\n asset: Address,\n swapAdapter: Address,\n chainlinkVerifier: Address,\n allocations: BasketAllocation[],\n totalAmount: bigint,\n maxSlippageBps: number,\n): Hex {\n const tokens = allocations.map((a) => a.token);\n const weightsBps = allocations.map((a) => BigInt(a.weightBps));\n const swapExtraData = allocations.map((a) => a.swapExtraData);\n const priceDecimals = allocations.map((a) => a.priceDecimals);\n const feedIds = allocations.map((a) => a.feedId);\n\n return encodeAbiParameters(\n [\n { type: \"address\" },\n { type: \"address\" },\n { type: \"address\" },\n { type: \"address[]\" },\n { type: \"uint256[]\" },\n { type: \"uint256\" },\n { type: \"uint256\" },\n { type: \"bytes[]\" },\n { type: \"uint8[]\" },\n { type: \"bytes32[]\" },\n ],\n [\n asset,\n swapAdapter,\n chainlinkVerifier,\n tokens,\n weightsBps,\n totalAmount,\n BigInt(maxSlippageBps),\n swapExtraData,\n priceDecimals,\n feedIds,\n ],\n );\n}\n\nexport function buildExecuteCalls(\n clone: Address,\n asset: Address,\n totalAmount: bigint,\n): BatchCall[] {\n return [\n {\n target: asset,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, totalAmount],\n }),\n value: 0n,\n },\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"execute\",\n }),\n value: 0n,\n },\n ];\n}\n\nexport function buildSettleCalls(clone: Address): BatchCall[] {\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"settle\",\n }),\n value: 0n,\n },\n ];\n}\n\nexport function buildUpdateParamsCalls(\n clone: Address,\n newWeightsBps: number[],\n newMaxSlippageBps: number,\n newSwapExtraData: Hex[],\n): BatchCall[] {\n const data = encodeAbiParameters(\n [{ type: \"uint256[]\" }, { type: \"uint256\" }, { type: \"bytes[]\" }],\n [\n newWeightsBps.map((w) => BigInt(w)),\n BigInt(newMaxSlippageBps),\n newSwapExtraData,\n ],\n );\n\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: [\n {\n type: \"function\",\n name: \"updateParams\",\n inputs: [{ type: \"bytes\", name: \"data\" }],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n ],\n functionName: \"updateParams\",\n args: [data],\n }),\n value: 0n,\n },\n ];\n}\n\n// ── Rebalancing ──\n\nimport { PORTFOLIO_STRATEGY_ABI } from \"../lib/abis.js\";\n\n/**\n * Encode calldata for the simple `rebalance()` call.\n * This is called directly by the proposer (not via vault batch).\n */\nexport function encodeRebalanceCalldata(): Hex {\n return encodeFunctionData({\n abi: PORTFOLIO_STRATEGY_ABI,\n functionName: \"rebalance\",\n });\n}\n\n/**\n * Encode calldata for `rebalanceDelta(bytes[] priceReports)`.\n *\n * Two modes, keyed off `basketSize` + `pushMode`:\n * - Push-feed mode (Robinhood mainnet, chainlinkVerifier == 0): the strategy\n * reads prices from its bound AggregatorV3 push feeds and IGNORES the report\n * bytes, but the array length must still equal the basket size or the call\n * reverts with `LengthMismatch`. Pass `pushMode: true` and the CLI fills\n * `Array(basketSize).fill(\"0x\")` — N empty entries. (Real Data Streams\n * reports here would revert with `InvalidFeedId`.)\n * - Data Streams mode (chainlinkVerifier != 0): pass the signed report blobs\n * as `reports` (one per allocation).\n */\nexport function encodeRebalanceDeltaCalldata(\n opts: { basketSize: number; pushMode: true } | { reports: Hex[]; pushMode?: false },\n): Hex {\n const priceReports: Hex[] =\n \"pushMode\" in opts && opts.pushMode\n ? (Array(opts.basketSize).fill(\"0x\") as Hex[])\n : (opts.reports as Hex[]);\n return encodeFunctionData({\n abi: PORTFOLIO_STRATEGY_ABI,\n functionName: \"rebalanceDelta\",\n args: [priceReports],\n });\n}\n\n/**\n * Encode calldata for `updateParams()` to change weights before rebalancing.\n */\nexport function encodeUpdateWeightsCalldata(\n newWeightsBps: number[],\n newMaxSlippageBps: number,\n newSwapExtraData: Hex[],\n): Hex {\n const data = encodeAbiParameters(\n [{ type: \"uint256[]\" }, { type: \"uint256\" }, { type: \"bytes[]\" }],\n [\n newWeightsBps.map((w) => BigInt(w)),\n BigInt(newMaxSlippageBps),\n newSwapExtraData,\n ],\n );\n\n return encodeFunctionData({\n abi: PORTFOLIO_STRATEGY_ABI,\n functionName: \"updateParams\",\n args: [data],\n });\n}\n","/**\n * HyperliquidPerpStrategy call builder.\n *\n * InitParams (Solidity): (address asset, uint256 depositAmount, uint32 perpAssetIndex, uint32 leverage, uint256 maxPositionSize, uint32 maxTradesPerDay)\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeAbiParameters, encodeFunctionData, maxUint256 } from \"viem\";\nimport { ERC20_ABI, BASE_STRATEGY_ABI } from \"../lib/abis.js\";\n// Frozen: the contract no longer ships in the protocol. See abis-legacy.ts.\nimport { HYPERLIQUID_PERP_STRATEGY_ABI } from \"../lib/abis-legacy.js\";\nimport type { BatchCall } from \"../lib/batch.js\";\n\nexport function buildInitData(\n asset: Address,\n depositAmount: bigint,\n perpAssetIndex: number,\n leverage: number,\n maxPositionSize: bigint,\n maxTradesPerDay: number,\n): Hex {\n return encodeAbiParameters(\n [\n { type: \"address\" },\n { type: \"uint256\" },\n { type: \"uint32\" },\n { type: \"uint32\" },\n { type: \"uint256\" },\n { type: \"uint32\" },\n ],\n [asset, depositAmount, perpAssetIndex, leverage, maxPositionSize, maxTradesPerDay],\n );\n}\n\nexport function buildExecuteCalls(\n clone: Address,\n asset: Address,\n amount: bigint,\n): BatchCall[] {\n // In dynamic-all mode (amount == 0) we approve maxUint256 up front and\n // revoke to 0 after execute() in the same atomic batch — the residual\n // allowance never persists beyond the tx.\n const approveAmount = amount === 0n ? maxUint256 : amount;\n\n return [\n {\n target: asset,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, approveAmount],\n }),\n value: 0n,\n },\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"execute\",\n }),\n value: 0n,\n },\n {\n target: asset,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, 0n],\n }),\n value: 0n,\n },\n ];\n}\n\nexport function buildSettleCalls(clone: Address): BatchCall[] {\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"settle\",\n }),\n value: 0n,\n },\n ];\n}\n\n/** Phase 2: sweep USDC back to vault after async HyperCore transfer completes. */\nexport function buildSweepToVaultCalls(clone: Address): BatchCall[] {\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: HYPERLIQUID_PERP_STRATEGY_ABI,\n functionName: \"sweepToVault\",\n }),\n value: 0n,\n },\n ];\n}\n","/**\n * FROZEN ABIs for contracts that NO LONGER SHIP IN THE PROTOCOL.\n *\n * `HyperliquidPerpStrategy` was removed from sherwood-protocol — `src/strategies/`\n * now holds only BaseStrategy, ConcentratedLiquidity, MorphoSupply and Portfolio.\n * It therefore has no build artifact, and `cli/src/lib/abis.ts` (which IS\n * generated) cannot carry it: requiring it made `npm run codegen` fail outright\n * against the post-audit protocol, which in turn blocked every ABI update.\n *\n * KEPT RATHER THAN DELETED, deliberately. Strategies already deployed from the\n * old template are still live on chain and still addressable; ripping the ABI\n * out would break the CLI's ability to talk to them, which is a product\n * decision separate from the contract's removal from the repo.\n *\n * FROZEN means frozen: nothing regenerates this file, so it can only be correct\n * for the bytecode that was deployed when the contract still existed. Do not\n * extend it, and do not add new contracts here — a contract that ships belongs\n * in the generated module, pinned to a real artifact.\n *\n * See sherwoodagent/sherwood#535 for the surrounding cleanup: the `grid`\n * commands, `hyperliquid-executor`, and the perp paths in `agent.ts` all still\n * target this contract and need their own decision.\n */\n\nexport const HYPERLIQUID_PERP_STRATEGY_ABI = [\n {\n name: \"asset\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\" }],\n },\n {\n name: \"assetTraded\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [{ name: \"\", type: \"uint32\" }],\n outputs: [{ name: \"\", type: \"bool\" }],\n },\n {\n name: \"cumulativeSwept\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint256\" }],\n },\n {\n name: \"depositAmount\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint256\" }],\n },\n { name: \"execute\", type: \"function\", stateMutability: \"nonpayable\", inputs: [], outputs: [] },\n {\n name: \"executed\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bool\" }],\n },\n {\n name: \"finalizeForHyperCore\",\n type: \"function\",\n stateMutability: \"nonpayable\",\n inputs: [\n { name: \"token\", type: \"uint64\" },\n { name: \"variant\", type: \"uint8\" },\n { name: \"createNonce\", type: \"uint64\" },\n ],\n outputs: [],\n },\n {\n name: \"getMarginSummary\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [\n {\n name: \"summary\",\n type: \"tuple\",\n components: [\n { name: \"accountValue\", type: \"int64\" },\n { name: \"marginUsed\", type: \"uint64\" },\n { name: \"ntlPos\", type: \"uint64\" },\n { name: \"rawUsd\", type: \"int64\" },\n ],\n },\n ],\n },\n {\n name: \"getPosition\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [\n {\n name: \"pos\",\n type: \"tuple\",\n components: [\n { name: \"szi\", type: \"int64\" },\n { name: \"entryNtl\", type: \"uint64\" },\n { name: \"isolatedRawUsd\", type: \"int64\" },\n { name: \"leverage\", type: \"uint32\" },\n { name: \"isIsolated\", type: \"bool\" },\n ],\n },\n ],\n },\n {\n name: \"getSpotBalance\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [\n {\n name: \"balance\",\n type: \"tuple\",\n components: [\n { name: \"total\", type: \"uint64\" },\n { name: \"hold\", type: \"uint64\" },\n { name: \"entryNtl\", type: \"uint64\" },\n ],\n },\n ],\n },\n {\n name: \"hasActiveStopLoss\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bool\" }],\n },\n {\n name: \"hyperCoreFinalized\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bool\" }],\n },\n {\n name: \"inFlightToHc\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint256\" }],\n },\n {\n name: \"initialize\",\n type: \"function\",\n stateMutability: \"nonpayable\",\n inputs: [\n { name: \"vault_\", type: \"address\" },\n { name: \"proposer_\", type: \"address\" },\n { name: \"data\", type: \"bytes\" },\n ],\n outputs: [],\n },\n {\n name: \"initiateReturn\",\n type: \"function\",\n stateMutability: \"nonpayable\",\n inputs: [],\n outputs: [],\n },\n {\n name: \"lastRecoverBlock\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint256\" }],\n },\n {\n name: \"lastTradeReset\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint256\" }],\n },\n {\n name: \"leverage\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint32\" }],\n },\n {\n name: \"maxPositionSize\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint256\" }],\n },\n {\n name: \"maxTradesPerDay\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint32\" }],\n },\n {\n name: \"moveSpotToPerp\",\n type: \"function\",\n stateMutability: \"nonpayable\",\n inputs: [],\n outputs: [],\n },\n {\n name: \"name\",\n type: \"function\",\n stateMutability: \"pure\",\n inputs: [],\n outputs: [{ name: \"\", type: \"string\" }],\n },\n {\n name: \"perpAssetIndex\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint32\" }],\n },\n {\n name: \"positions\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [\n {\n name: \"ps\",\n type: \"tuple[]\",\n components: [\n { name: \"venue\", type: \"address\" },\n { name: \"kind\", type: \"bytes32\" },\n { name: \"ref\", type: \"bytes\" },\n ],\n },\n ],\n },\n {\n name: \"proposer\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\" }],\n },\n {\n name: \"recoverHcResiduals\",\n type: \"function\",\n stateMutability: \"nonpayable\",\n inputs: [],\n outputs: [],\n },\n {\n name: \"returnsInitiated\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bool\" }],\n },\n {\n name: \"returnsInitiatedBlock\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint256\" }],\n },\n {\n name: \"selfManagesFees\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bool\" }],\n },\n { name: \"settle\", type: \"function\", stateMutability: \"nonpayable\", inputs: [], outputs: [] },\n {\n name: \"settled\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bool\" }],\n },\n {\n name: \"state\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint8\" }],\n },\n {\n name: \"sweepToVault\",\n type: \"function\",\n stateMutability: \"nonpayable\",\n inputs: [],\n outputs: [],\n },\n {\n name: \"tradedAssets\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [{ name: \"\", type: \"uint256\" }],\n outputs: [{ name: \"\", type: \"uint32\" }],\n },\n {\n name: \"tradesToday\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"uint32\" }],\n },\n {\n name: \"updateParams\",\n type: \"function\",\n stateMutability: \"nonpayable\",\n inputs: [{ name: \"data\", type: \"bytes\" }],\n outputs: [],\n },\n {\n name: \"vault\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\" }],\n },\n {\n name: \"FundsParked\",\n type: \"event\",\n inputs: [{ name: \"amount\", type: \"uint256\", indexed: false }],\n },\n {\n name: \"FundsSwept\",\n type: \"event\",\n inputs: [{ name: \"amount\", type: \"uint256\", indexed: false }],\n },\n {\n name: \"HyperCoreFinalized\",\n type: \"event\",\n inputs: [\n { name: \"token\", type: \"uint64\", indexed: false },\n { name: \"variant\", type: \"uint8\", indexed: false },\n { name: \"createNonce\", type: \"uint64\", indexed: false },\n ],\n },\n {\n name: \"PositionClosed\",\n type: \"event\",\n inputs: [\n { name: \"asset\", type: \"uint32\", indexed: false },\n { name: \"limitPx\", type: \"uint64\", indexed: false },\n { name: \"sz\", type: \"uint64\", indexed: false },\n ],\n },\n {\n name: \"PositionOpened\",\n type: \"event\",\n inputs: [\n { name: \"asset\", type: \"uint32\", indexed: false },\n { name: \"isBuy\", type: \"bool\", indexed: false },\n { name: \"limitPx\", type: \"uint64\", indexed: false },\n { name: \"sz\", type: \"uint64\", indexed: false },\n { name: \"leverage\", type: \"uint32\", indexed: false },\n ],\n },\n { name: \"ReturnsInitiated\", type: \"event\", inputs: [] },\n { name: \"Settled\", type: \"event\", inputs: [] },\n {\n name: \"StopLossUpdated\",\n type: \"event\",\n inputs: [{ name: \"triggerPx\", type: \"uint64\", indexed: false }],\n },\n { name: \"AccountMarginSummaryPrecompileCallFailed\", type: \"error\", inputs: [] },\n { name: \"AlreadyExecuted\", type: \"error\", inputs: [] },\n { name: \"AlreadyFinalized\", type: \"error\", inputs: [] },\n { name: \"AlreadyInitialized\", type: \"error\", inputs: [] },\n { name: \"AlreadySettled\", type: \"error\", inputs: [] },\n { name: \"DepositAmountTooLarge\", type: \"error\", inputs: [] },\n { name: \"InvalidAction\", type: \"error\", inputs: [] },\n { name: \"InvalidAmount\", type: \"error\", inputs: [] },\n { name: \"MaxTradesExceeded\", type: \"error\", inputs: [] },\n { name: \"NotAuthorized\", type: \"error\", inputs: [] },\n { name: \"NotExecuted\", type: \"error\", inputs: [] },\n { name: \"NotProposer\", type: \"error\", inputs: [] },\n { name: \"NotSweepable\", type: \"error\", inputs: [] },\n { name: \"NotVault\", type: \"error\", inputs: [] },\n { name: \"Position2PrecompileCallFailed\", type: \"error\", inputs: [] },\n {\n name: \"PositionTooLarge\",\n type: \"error\",\n inputs: [{ name: \"actual\", type: \"uint256\" }, { name: \"max\", type: \"uint256\" }],\n },\n { name: \"ReturnsNotInitiated\", type: \"error\", inputs: [] },\n {\n name: \"SafeERC20FailedOperation\",\n type: \"error\",\n inputs: [{ name: \"token\", type: \"address\" }],\n },\n { name: \"SettleTooSoon\", type: \"error\", inputs: [] },\n { name: \"SpotBalancePrecompileCallFailed\", type: \"error\", inputs: [] },\n { name: \"ZeroAddress\", type: \"error\", inputs: [] },\n] as const;\n","/**\n * HyperliquidGridStrategy call builder.\n *\n * InitParams (Solidity): (address asset, uint256 depositAmount, uint32 leverage, uint256 maxOrderSize, uint32 maxOrdersPerTick, uint32[] assetIndices)\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { encodeAbiParameters, encodeFunctionData, maxUint256 } from \"viem\";\nimport { ERC20_ABI, BASE_STRATEGY_ABI } from \"../lib/abis.js\";\nimport type { BatchCall } from \"../lib/batch.js\";\n\nexport function buildInitData(\n asset: Address,\n depositAmount: bigint,\n leverage: number,\n maxOrderSize: bigint,\n maxOrdersPerTick: number,\n assetIndices: number[],\n): Hex {\n return encodeAbiParameters(\n [\n { type: \"address\" },\n { type: \"uint256\" },\n { type: \"uint32\" },\n { type: \"uint256\" },\n { type: \"uint32\" },\n { type: \"uint32[]\" },\n ],\n [asset, depositAmount, leverage, maxOrderSize, maxOrdersPerTick, assetIndices],\n );\n}\n\nexport function buildExecuteCalls(\n clone: Address,\n asset: Address,\n amount: bigint,\n): BatchCall[] {\n const approveAmount = amount === 0n ? maxUint256 : amount;\n\n return [\n {\n target: asset,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, approveAmount],\n }),\n value: 0n,\n },\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"execute\",\n }),\n value: 0n,\n },\n {\n target: asset,\n data: encodeFunctionData({\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [clone, 0n],\n }),\n value: 0n,\n },\n ];\n}\n\nexport function buildSettleCalls(clone: Address): BatchCall[] {\n return [\n {\n target: clone,\n data: encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: \"settle\",\n }),\n value: 0n,\n },\n ];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAS,sBAAAA,qBAAoB,4BAA4B;;;ACCzD;AAAA,EACE;AAAA,EACA;AAAA,EACA,uBAAAC;AAAA,EACA,UAAAC;AAAA,EACA,eAAAC;AAAA,OACK;AACP,OAAO,WAAW;;;ACjBlB,SAAS,qBAAqB,0BAA0B;AAIjD,SAAS,cACd,YACA,QACA,cACA,iBACA,mBACK;AACL,SAAO;AAAA,IACL;AAAA,MACE,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,OAAO;AAAA,IACjB;AAAA,IACA,CAAC,YAAY,QAAQ,cAAc,iBAAiB,iBAAiB;AAAA,EACvE;AACF;AAEO,SAAS,kBACd,OACA,YACA,cACa;AACb,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,MAAM,mBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,QACd,MAAM,CAAC,OAAO,YAAY;AAAA,MAC5B,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM,mBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,MAChB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAAS,iBAAiB,OAA6B;AAC5D,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,MAAM,mBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,MAChB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,EACF;AACF;;;AChEA,SAAS,uBAAAC,sBAAqB,sBAAAC,2BAA0B;AAkBxD,IAAM,oBAAoB;AAAA,EACxB;AAAA,IACE,MAAM;AAAA,IACN,YAAY;AAAA,MACV,EAAE,MAAM,SAAS,MAAM,UAAmB;AAAA,MAC1C,EAAE,MAAM,QAAQ,MAAM,UAAmB;AAAA,MACzC,EAAE,MAAM,OAAO,MAAM,UAAmB;AAAA,MACxC,EAAE,MAAM,QAAQ,MAAM,UAAmB;AAAA,MACzC,EAAE,MAAM,cAAc,MAAM,UAAmB;AAAA,MAC/C,EAAE,MAAM,eAAe,MAAM,UAAmB;AAAA,MAChD,EAAE,MAAM,SAAS,MAAM,UAAmB;AAAA,MAC1C,EAAE,MAAM,eAAe,MAAM,UAAmB;AAAA,MAChD,EAAE,MAAM,UAAU,MAAM,UAAmB;AAAA,MAC3C,EAAE,MAAM,kBAAkB,MAAM,UAAmB;AAAA,MACnD,EAAE,MAAM,aAAa,MAAM,OAAgB;AAAA,IAC7C;AAAA,EACF;AACF;AAEO,SAASC,eAAc,QAAwC;AACpE,SAAOC,qBAAoB,mBAAmB,CAAC,MAAM,CAAC;AACxD;AAEO,SAASC,mBACd,OACA,OACA,aACa;AACb,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,MAAMC,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,QACd,MAAM,CAAC,OAAO,WAAW;AAAA,MAC3B,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAMA,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,MAChB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAASC,kBAAiB,OAA6B;AAC5D,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,MAAMD,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,MAChB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,EACF;AACF;;;AC5EA,SAAS,uBAAAE,sBAAqB,sBAAAC,2BAA0B;AAoBxD,IAAMC,qBAAoB;AAAA,EACxB;AAAA,IACE,MAAM;AAAA,IACN,YAAY;AAAA,MACV,EAAE,MAAM,UAAU,MAAM,UAAmB;AAAA,MAC3C,EAAE,MAAM,UAAU,MAAM,UAAmB;AAAA,MAC3C,EAAE,MAAM,UAAU,MAAM,OAAgB;AAAA,MACxC,EAAE,MAAM,WAAW,MAAM,UAAmB;AAAA,MAC5C,EAAE,MAAM,UAAU,MAAM,UAAmB;AAAA,MAC3C,EAAE,MAAM,SAAS,MAAM,UAAmB;AAAA,MAC1C,EAAE,MAAM,WAAW,MAAM,UAAmB;AAAA,MAC5C,EAAE,MAAM,kBAAkB,MAAM,UAAmB;AAAA,MACnD,EAAE,MAAM,kBAAkB,MAAM,UAAmB;AAAA,MACnD,EAAE,MAAM,cAAc,MAAM,UAAmB;AAAA,MAC/C,EAAE,MAAM,cAAc,MAAM,UAAmB;AAAA,MAC/C,EAAE,MAAM,iBAAiB,MAAM,UAAmB;AAAA,MAClD,EAAE,MAAM,iBAAiB,MAAM,UAAmB;AAAA,IACpD;AAAA,EACF;AACF;AAEO,SAASC,eAAc,QAAoC;AAChE,SAAOC,qBAAoBF,oBAAmB,CAAC,MAAM,CAAC;AACxD;AAEO,SAASG,mBACd,OACA,QACA,SACA,QACA,SACa;AACb,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,MAAMC,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,QACd,MAAM,CAAC,OAAO,OAAO;AAAA,MACvB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAMA,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,QACd,MAAM,CAAC,OAAO,OAAO;AAAA,MACvB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAMA,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,MAChB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAASC,kBAAiB,OAA6B;AAC5D,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,MAAMD,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,MAChB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,EACF;AACF;;;AC1FA,SAAS,uBAAAE,sBAAqB,sBAAAC,qBAAoB,kBAAkB;AAiBpE,IAAMC,qBAAoB;AAAA,EACxB;AAAA,IACE,MAAM;AAAA,IACN,YAAY;AAAA,MACV,EAAE,MAAM,QAAQ,MAAM,UAAmB;AAAA,MACzC,EAAE,MAAM,UAAU,MAAM,UAAmB;AAAA,MAC3C,EAAE,MAAM,WAAW,MAAM,UAAmB;AAAA,MAC5C,EAAE,MAAM,cAAc,MAAM,UAAmB;AAAA,MAC/C,EAAE,MAAM,eAAe,MAAM,UAAmB;AAAA,MAChD,EAAE,MAAM,0BAA0B,MAAM,UAAmB;AAAA,MAC3D,EAAE,MAAM,gBAAgB,MAAM,UAAmB;AAAA,MACjD,EAAE,MAAM,uBAAuB,MAAM,UAAmB;AAAA,MACxD,EAAE,MAAM,uBAAuB,MAAM,UAAmB;AAAA,MACxD,EAAE,MAAM,kBAAkB,MAAM,UAAmB;AAAA,IACrD;AAAA,EACF;AACF;AAEO,SAASC,eAAc,QAAuC;AACnE,SAAOC,qBAAoBF,oBAAmB,CAAC,MAAM,CAAC;AACxD;AAEO,SAASG,mBACd,OACA,MACA,cACa;AAMb,QAAM,gBAAgB,iBAAiB,KAAK,aAAa;AAEzD,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,MAAMC,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,QACd,MAAM,CAAC,OAAO,aAAa;AAAA,MAC7B,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAMA,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,MAChB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAMA,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,QACd,MAAM,CAAC,OAAO,EAAE;AAAA,MAClB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAASC,kBAAiB,OAA6B;AAC5D,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,MAAMD,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,MAChB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,EACF;AACF;;;ACpGA,SAAS,uBAAAE,sBAAqB,sBAAAC,2BAA0B;AAIjD,SAASC,eACd,YACA,aACA,iBACK;AACL,SAAOC;AAAA,IACL;AAAA,MACE,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,UAAU;AAAA,IACpB;AAAA,IACA,CAAC,YAAY,aAAa,eAAe;AAAA,EAC3C;AACF;AAEO,SAASC,mBACd,OACA,YACA,QACa;AACb,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,MAAMC,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,QACd,MAAM,CAAC,OAAO,MAAM;AAAA,MACtB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAMA,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,MAChB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAASC,kBAAiB,OAA6B;AAC5D,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,MAAMD,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,MAChB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,EACF;AACF;;;ACzCA,SAAS,QAAQ,uBAAAE,sBAAqB,sBAAAC,qBAAoB,aAAa,WAAW;AAmBlF,SAAS,SAAS,MAAc,WAAqB;AACnD,QAAM,WAAY,KAAK,KAAK,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC;AACzD,SAAO,OAAO,CAAC,UAAU,SAAS,CAAC;AACrC;AAGO,SAAS,qBAAqB,KAAkB;AACrD,SAAO,SAAS,GAAGC,qBAAoB,CAAC,EAAE,MAAM,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACrE;AAGO,SAAS,qBAAqB,KAAa,aAA0B;AAC1E,SAAO;AAAA,IACL;AAAA,IACAA;AAAA,MACE,CAAC,EAAE,MAAM,SAAS,GAAG,EAAE,MAAM,QAAQ,CAAC;AAAA,MACtC,CAAC,KAAK,WAAW;AAAA,IACnB;AAAA,EACF;AACF;AASO,SAAS,gBAAgB,MAAwB;AAGtD,MAAI,KAAK,SAAS,EAAG,OAAM,IAAI,MAAM,4EAA4E;AACjH,SAAO;AAAA,IACL;AAAA,IACAA;AAAA,MACE;AAAA,QACE;AAAA,UACE,MAAM;AAAA,UACN,YAAY;AAAA,YACV,EAAE,MAAM,WAAW,MAAM,WAAW;AAAA,YACpC,EAAE,MAAM,UAAU,MAAM,MAAM;AAAA,YAC9B,EAAE,MAAM,SAAS,MAAM,cAAc;AAAA,UACvC;AAAA,QACF;AAAA,MACF;AAAA,MACA,CAAC,KAAK,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,KAAK,EAAE,KAAK,aAAa,EAAE,YAAY,EAAE,CAAC;AAAA,IACtF;AAAA,EACF;AACF;AAgBO,IAAM,+BAA+B,KAAK,KAAK;AAGtD,IAAM,oBAAoB;AAC1B,IAAM,oBAAoB;AAgBnB,SAAS,WAAW,MAAe,eAA6B;AACrE,MAAI,kBAAkB,UAAa,kBAAkB,GAAG;AACtD,WAAO,IAAI,MAAM,EAAE,MAAM,GAAG,CAAC;AAAA,EAC/B;AACA,MACE,CAAC,OAAO,UAAU,aAAa,KAC/B,gBAAgB,qBAChB,gBAAgB,mBAChB;AACA,UAAM,IAAI;AAAA,MACR,oDAAoD,iBAAiB,KAAK,iBAAiB,0CAA0C,aAAa;AAAA,IACpJ;AAAA,EACF;AAEA,QAAM,SAAU,OAAO,aAAa,KAAK,OAAQ,OAAO,IAAI;AAC5D,SAAO,YAAY,QAAQ,EAAE,MAAM,GAAG,CAAC;AACzC;AAEO,SAASC,eACd,OACA,aACA,mBACA,aACA,aACA,gBACK;AACL,QAAM,SAAS,YAAY,IAAI,CAAC,MAAM,EAAE,KAAK;AAC7C,QAAM,aAAa,YAAY,IAAI,CAAC,MAAM,OAAO,EAAE,SAAS,CAAC;AAC7D,QAAM,gBAAgB,YAAY,IAAI,CAAC,MAAM,EAAE,aAAa;AAC5D,QAAM,gBAAgB,YAAY,IAAI,CAAC,MAAM,EAAE,aAAa;AAC5D,QAAM,UAAU,YAAY,IAAI,CAAC,MAAM,EAAE,MAAM;AAE/C,SAAOC;AAAA,IACL;AAAA,MACE,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,YAAY;AAAA,MACpB,EAAE,MAAM,YAAY;AAAA,MACpB,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,YAAY;AAAA,IACtB;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,cAAc;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAASC,mBACd,OACA,OACA,aACa;AACb,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,MAAMC,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,QACd,MAAM,CAAC,OAAO,WAAW;AAAA,MAC3B,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAMA,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,MAChB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAASC,kBAAiB,OAA6B;AAC5D,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,MAAMD,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,MAChB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,EACF;AACF;;;ACvNA,SAAS,uBAAAE,sBAAqB,sBAAAC,qBAAoB,cAAAC,mBAAkB;;;ACiB7D,IAAM,gCAAgC;AAAA,EAC3C;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,UAAU,CAAC;AAAA,EACzC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC,EAAE,MAAM,IAAI,MAAM,SAAS,CAAC;AAAA,IACrC,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,OAAO,CAAC;AAAA,EACtC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,UAAU,CAAC;AAAA,EACzC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,UAAU,CAAC;AAAA,EACzC;AAAA,EACA,EAAE,MAAM,WAAW,MAAM,YAAY,iBAAiB,cAAc,QAAQ,CAAC,GAAG,SAAS,CAAC,EAAE;AAAA,EAC5F;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,OAAO,CAAC;AAAA,EACtC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ;AAAA,MACN,EAAE,MAAM,SAAS,MAAM,SAAS;AAAA,MAChC,EAAE,MAAM,WAAW,MAAM,QAAQ;AAAA,MACjC,EAAE,MAAM,eAAe,MAAM,SAAS;AAAA,IACxC;AAAA,IACA,SAAS,CAAC;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,YAAY;AAAA,UACV,EAAE,MAAM,gBAAgB,MAAM,QAAQ;AAAA,UACtC,EAAE,MAAM,cAAc,MAAM,SAAS;AAAA,UACrC,EAAE,MAAM,UAAU,MAAM,SAAS;AAAA,UACjC,EAAE,MAAM,UAAU,MAAM,QAAQ;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,YAAY;AAAA,UACV,EAAE,MAAM,OAAO,MAAM,QAAQ;AAAA,UAC7B,EAAE,MAAM,YAAY,MAAM,SAAS;AAAA,UACnC,EAAE,MAAM,kBAAkB,MAAM,QAAQ;AAAA,UACxC,EAAE,MAAM,YAAY,MAAM,SAAS;AAAA,UACnC,EAAE,MAAM,cAAc,MAAM,OAAO;AAAA,QACrC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,YAAY;AAAA,UACV,EAAE,MAAM,SAAS,MAAM,SAAS;AAAA,UAChC,EAAE,MAAM,QAAQ,MAAM,SAAS;AAAA,UAC/B,EAAE,MAAM,YAAY,MAAM,SAAS;AAAA,QACrC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,OAAO,CAAC;AAAA,EACtC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,OAAO,CAAC;AAAA,EACtC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,UAAU,CAAC;AAAA,EACzC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ;AAAA,MACN,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,MAClC,EAAE,MAAM,aAAa,MAAM,UAAU;AAAA,MACrC,EAAE,MAAM,QAAQ,MAAM,QAAQ;AAAA,IAChC;AAAA,IACA,SAAS,CAAC;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,UAAU,CAAC;AAAA,EACzC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,UAAU,CAAC;AAAA,EACzC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,SAAS,CAAC;AAAA,EACxC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,UAAU,CAAC;AAAA,EACzC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,SAAS,CAAC;AAAA,EACxC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,SAAS,CAAC;AAAA,EACxC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,SAAS,CAAC;AAAA,EACxC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,YAAY;AAAA,UACV,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,UACjC,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,UAChC,EAAE,MAAM,OAAO,MAAM,QAAQ;AAAA,QAC/B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,UAAU,CAAC;AAAA,EACzC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,OAAO,CAAC;AAAA,EACtC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,UAAU,CAAC;AAAA,EACzC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,OAAO,CAAC;AAAA,EACtC;AAAA,EACA,EAAE,MAAM,UAAU,MAAM,YAAY,iBAAiB,cAAc,QAAQ,CAAC,GAAG,SAAS,CAAC,EAAE;AAAA,EAC3F;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,OAAO,CAAC;AAAA,EACtC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,QAAQ,CAAC;AAAA,EACvC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC,EAAE,MAAM,IAAI,MAAM,UAAU,CAAC;AAAA,IACtC,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,SAAS,CAAC;AAAA,EACxC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,SAAS,CAAC;AAAA,EACxC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,CAAC;AAAA,IACxC,SAAS,CAAC;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,UAAU,CAAC;AAAA,EACzC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC,EAAE,MAAM,UAAU,MAAM,WAAW,SAAS,MAAM,CAAC;AAAA,EAC9D;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC,EAAE,MAAM,UAAU,MAAM,WAAW,SAAS,MAAM,CAAC;AAAA,EAC9D;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,EAAE,MAAM,SAAS,MAAM,UAAU,SAAS,MAAM;AAAA,MAChD,EAAE,MAAM,WAAW,MAAM,SAAS,SAAS,MAAM;AAAA,MACjD,EAAE,MAAM,eAAe,MAAM,UAAU,SAAS,MAAM;AAAA,IACxD;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,EAAE,MAAM,SAAS,MAAM,UAAU,SAAS,MAAM;AAAA,MAChD,EAAE,MAAM,WAAW,MAAM,UAAU,SAAS,MAAM;AAAA,MAClD,EAAE,MAAM,MAAM,MAAM,UAAU,SAAS,MAAM;AAAA,IAC/C;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,EAAE,MAAM,SAAS,MAAM,UAAU,SAAS,MAAM;AAAA,MAChD,EAAE,MAAM,SAAS,MAAM,QAAQ,SAAS,MAAM;AAAA,MAC9C,EAAE,MAAM,WAAW,MAAM,UAAU,SAAS,MAAM;AAAA,MAClD,EAAE,MAAM,MAAM,MAAM,UAAU,SAAS,MAAM;AAAA,MAC7C,EAAE,MAAM,YAAY,MAAM,UAAU,SAAS,MAAM;AAAA,IACrD;AAAA,EACF;AAAA,EACA,EAAE,MAAM,oBAAoB,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EACtD,EAAE,MAAM,WAAW,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EAC7C;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC,EAAE,MAAM,aAAa,MAAM,UAAU,SAAS,MAAM,CAAC;AAAA,EAChE;AAAA,EACA,EAAE,MAAM,4CAA4C,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EAC9E,EAAE,MAAM,mBAAmB,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EACrD,EAAE,MAAM,oBAAoB,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EACtD,EAAE,MAAM,sBAAsB,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EACxD,EAAE,MAAM,kBAAkB,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EACpD,EAAE,MAAM,yBAAyB,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EAC3D,EAAE,MAAM,iBAAiB,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EACnD,EAAE,MAAM,iBAAiB,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EACnD,EAAE,MAAM,qBAAqB,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EACvD,EAAE,MAAM,iBAAiB,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EACnD,EAAE,MAAM,eAAe,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EACjD,EAAE,MAAM,eAAe,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EACjD,EAAE,MAAM,gBAAgB,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EAClD,EAAE,MAAM,YAAY,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EAC9C,EAAE,MAAM,iCAAiC,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EACnE;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC,EAAE,MAAM,UAAU,MAAM,UAAU,GAAG,EAAE,MAAM,OAAO,MAAM,UAAU,CAAC;AAAA,EAChF;AAAA,EACA,EAAE,MAAM,uBAAuB,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EACzD;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ,CAAC,EAAE,MAAM,SAAS,MAAM,UAAU,CAAC;AAAA,EAC7C;AAAA,EACA,EAAE,MAAM,iBAAiB,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EACnD,EAAE,MAAM,mCAAmC,MAAM,SAAS,QAAQ,CAAC,EAAE;AAAA,EACrE,EAAE,MAAM,eAAe,MAAM,SAAS,QAAQ,CAAC,EAAE;AACnD;;;ADjYO,SAASC,eACd,OACA,eACA,gBACA,UACA,iBACA,iBACK;AACL,SAAOC;AAAA,IACL;AAAA,MACE,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,SAAS;AAAA,MACjB,EAAE,MAAM,SAAS;AAAA,MACjB,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,SAAS;AAAA,IACnB;AAAA,IACA,CAAC,OAAO,eAAe,gBAAgB,UAAU,iBAAiB,eAAe;AAAA,EACnF;AACF;AAEO,SAASC,mBACd,OACA,OACA,QACa;AAIb,QAAM,gBAAgB,WAAW,KAAKC,cAAa;AAEnD,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,MAAMC,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,QACd,MAAM,CAAC,OAAO,aAAa;AAAA,MAC7B,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAMA,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,MAChB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAMA,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,QACd,MAAM,CAAC,OAAO,EAAE;AAAA,MAClB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAASC,kBAAiB,OAA6B;AAC5D,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,MAAMD,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,MAChB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,EACF;AACF;;;AE9EA,SAAS,uBAAAE,sBAAqB,sBAAAC,qBAAoB,cAAAC,mBAAkB;AAI7D,SAASC,eACd,OACA,eACA,UACA,cACA,kBACA,cACK;AACL,SAAOC;AAAA,IACL;AAAA,MACE,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,SAAS;AAAA,MACjB,EAAE,MAAM,UAAU;AAAA,MAClB,EAAE,MAAM,SAAS;AAAA,MACjB,EAAE,MAAM,WAAW;AAAA,IACrB;AAAA,IACA,CAAC,OAAO,eAAe,UAAU,cAAc,kBAAkB,YAAY;AAAA,EAC/E;AACF;AAEO,SAASC,mBACd,OACA,OACA,QACa;AACb,QAAM,gBAAgB,WAAW,KAAKC,cAAa;AAEnD,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,MAAMC,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,QACd,MAAM,CAAC,OAAO,aAAa;AAAA,MAC7B,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAMA,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,MAChB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAMA,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,QACd,MAAM,CAAC,OAAO,EAAE;AAAA,MAClB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAASC,kBAAiB,OAA6B;AAC5D,SAAO;AAAA,IACL;AAAA,MACE,QAAQ;AAAA,MACR,MAAMD,oBAAmB;AAAA,QACvB,KAAK;AAAA,QACL,cAAc;AAAA,MAChB,CAAC;AAAA,MACD,OAAO;AAAA,IACT;AAAA,EACF;AACF;;;ATxBA,IAAM,OAAgB;AACtB,IAAM,eACJ;AAwBK,SAAS,aAAa,QAAmB,MAAqB;AACnE,MAAI,OAAO,WAAW,KAAK,SAAS,EAAG,OAAM,IAAI,MAAM,uCAAuC;AAC9F,QAAM,QAAe,CAAC;AACtB,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAM,KAAK,OAAO,CAAC,EAAE,YAAY,CAAQ;AACzC,QAAI,IAAI,KAAK,QAAQ;AAEnB,YAAM,KAAKE,aAAY,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;AAAA,IAC9C;AAAA,EACF;AACA,SAAOC,QAAO,KAAK;AACrB;AAqBO,SAAS,mBACd,SACA,SACA,UACA,SACA,KACA,oBAA4B,KACvB;AACL,MAAI,KAAK;AAEP,UAAM,OAAO,aAAa,CAAC,SAAS,IAAI,KAAK,QAAQ,GAAG,CAAC,IAAI,OAAO,IAAI,MAAM,CAAC;AAC/E,UAAMC,WAAUC;AAAA,MACd,CAAC,EAAE,MAAM,QAAQ,GAAG,EAAE,MAAM,SAAS,CAAC;AAAA,MACtC,CAAC,MAAM,iBAAiB;AAAA,IAC1B;AACA,WAAO,OAAOD,SAAQ,MAAM,CAAC,CAAC;AAAA,EAChC;AAGA,QAAM,UAAUC,qBAAoB,CAAC,EAAE,MAAM,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC;AACnE,SAAO,OAAO,QAAQ,MAAM,CAAC,CAAC;AAChC;AAaO,SAAS,mBAAmB,MAAc,OAAqB;AACpE,QAAM,IAAI,KAAK,KAAK;AACpB,QAAM,CAAC,MAAM,GAAG,SAAS,IAAI,EAAE,MAAM,GAAG;AACxC,QAAM,OAAO,UAAU,KAAK,GAAG;AAC/B,UAAQ,MAAM;AAAA,IACZ,KAAK,MAAM;AACT,YAAM,MAAM,OAAO,IAAI;AACvB,UAAI,CAAC,OAAO,UAAU,GAAG,KAAK,OAAO,EAAG,OAAM,IAAI,MAAM,kBAAkB,IAAI,GAAG;AACjF,aAAwB,qBAAqB,GAAG;AAAA,IAClD;AAAA,IACA,KAAK,MAAM;AACT,YAAM,CAAC,QAAQ,KAAK,IAAI,KAAK,MAAM,GAAG;AACtC,YAAM,MAAM,OAAO,MAAM;AACzB,YAAM,cAAc,OAAO,KAAK;AAChC,UAAI,CAAC,OAAO,UAAU,GAAG,KAAK,OAAO,EAAG,OAAM,IAAI,MAAM,kBAAkB,IAAI,GAAG;AACjF,UAAI,CAAC,OAAO,UAAU,WAAW,KAAK,eAAe,EAAG,OAAM,IAAI,MAAM,0BAA0B,IAAI,GAAG;AACzG,aAAwB,qBAAqB,KAAK,WAAW;AAAA,IAC/D;AAAA,IACA,KAAK,UAAU;AACb,YAAM,OAAO,KAAK,MAAM,GAAG,EAAE,IAAI,CAAC,WAAW;AAC3C,cAAM,CAAC,aAAa,KAAK,IAAI,OAAO,MAAM,GAAG;AAC7C,YAAI,CAAC,MAAO,OAAM,IAAI,MAAM,mBAAmB,MAAM,SAAS,IAAI,uCAAuC;AACzG,cAAM,CAAC,QAAQ,KAAK,IAAI,MAAM,MAAM,GAAG;AACvC,cAAM,MAAM,OAAO,MAAM;AACzB,cAAM,cAAc,OAAO,KAAK;AAChC,YAAI,CAAC,OAAO,UAAU,GAAG,KAAK,OAAO,EAAG,OAAM,IAAI,MAAM,sBAAsB,IAAI,GAAG;AACrF,YAAI,CAAC,OAAO,UAAU,WAAW,KAAK,eAAe,EAAG,OAAM,IAAI,MAAM,8BAA8B,IAAI,GAAG;AAC7G,cAAM,IAAI,YAAY,KAAK,EAAE,YAAY;AACzC,YAAI;AACJ,YAAI,MAAM,SAAS,MAAM,SAAU,YAAW;AAAA,iBACrC,MAAM,OAAQ,YAAW;AAAA,iBACzB,UAAU,YAAY,KAAK,CAAC,EAAG,YAAW,YAAY,KAAK;AAAA,YAC/D,OAAM,IAAI,MAAM,wBAAwB,WAAW,SAAS,IAAI,oCAAoC;AACzG,eAAO,EAAE,UAAU,KAAK,YAAY;AAAA,MACtC,CAAC;AACD,aAAwB,gBAAgB,IAAI;AAAA,IAC9C;AAAA,IACA;AACE,YAAM,IAAI,MAAM,4BAA4B,IAAI,SAAS,IAAI,sBAAsB;AAAA,EACvF;AACF;AAWA,eAAsB,gBACpB,OACA,OACA,kBACuD;AACvD,QAAM,UAAU,WAAW;AAK3B,SAAO;AAAA,IACL,WAAW,mBAAmB,SAAS,OAAO,OAAO,gBAAgB;AAAA,IACrE,WAAW,eAAe,gBAAgB;AAAA,EAC5C;AACF;AAyBO,SAAS,2BACd,aACA,MACqD;AACrD,MAAI,gBAAgB,qBAAqB,gBAAgB,cAAc;AACrE,QAAI,CAAC,KAAK,OAAQ,QAAO,CAAC;AAC1B,UAAM,QAAS,KAAK,SAAoB;AACxC,UAAM,QAAQ,aAAa,KAAK;AAChC,UAAM,WAAW,uBAAuB,KAAK;AAC7C,WAAO,CAAC,EAAE,OAAO,QAAQ,WAAW,KAAK,QAAkB,QAAQ,GAAG,OAAO,MAAM,YAAY,EAAE,CAAC;AAAA,EACpG;AAEA,MAAI,gBAAgB,oBAAoB;AACtC,QAAI,CAAC,KAAK,OAAQ,QAAO,CAAC;AAC1B,UAAM,cAAe,KAAK,SAAoB;AAC9C,UAAM,QAAQ,aAAa,WAAW;AACtC,UAAM,WAAW,uBAAuB,WAAW;AACnD,WAAO,CAAC,EAAE,OAAO,QAAQ,WAAW,KAAK,QAAkB,QAAQ,GAAG,OAAO,YAAY,YAAY,EAAE,CAAC;AAAA,EAC1G;AAEA,MAAI,gBAAgB,gBAAgB;AAMlC,QAAI,CAAC,KAAK,UAAU,CAAC,KAAK,UAAU,CAAC,KAAK,WAAW,CAAC,KAAK,QAAS,QAAO,CAAC;AAI5E,WAAO,CAAC;AAAA,EACV;AAEA,MAAI,gBAAgB,mBAAmB;AACrC,QAAI,CAAC,KAAK,OAAQ,QAAO,CAAC;AAC1B,WAAO,CAAC;AAAA,MACN,OAAO,OAAO,EAAE;AAAA,MAChB,QAAQ,WAAW,KAAK,QAAkB,EAAE;AAAA,MAC5C,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,MAAI,gBAAgB,aAAa;AAC/B,QAAI,CAAC,KAAK,OAAQ,QAAO,CAAC;AAI1B,UAAM,cAAe,KAAK,SAAoB,sBAAsB;AACpE,UAAM,QAAQ,aAAa,WAAW;AACtC,UAAM,WAAW,uBAAuB,WAAW;AACnD,WAAO,CAAC,EAAE,OAAO,QAAQ,WAAW,KAAK,QAAkB,QAAQ,GAAG,OAAO,YAAY,YAAY,EAAE,CAAC;AAAA,EAC1G;AAEA,MAAI,gBAAgB,sBAAsB,gBAAgB,oBAAoB;AAC5E,QAAI,CAAC,KAAK,OAAQ,QAAO,CAAC;AAC1B,UAAM,QAAS,KAAK,SAAoB;AACxC,UAAM,QAAQ,aAAa,KAAK;AAChC,UAAM,WAAW,uBAAuB,KAAK;AAC7C,WAAO,CAAC,EAAE,OAAO,QAAQ,WAAW,KAAK,QAAkB,QAAQ,GAAG,OAAO,MAAM,YAAY,EAAE,CAAC;AAAA,EACpG;AAEA,SAAO,CAAC;AACV;AAkBO,SAAS,sBACd,KACA,aACyC;AACzC,MAAI,QAAQ,OAAW,QAAO,EAAE,QAAQ,CAAC,GAAG,UAAU,MAAM;AAC5D,QAAM,SAAS,IAAI,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AACjD,SAAO,EAAE,QAAQ,UAAU,OAAO,WAAW,YAAY;AAC3D;AAEA,eAAsB,yBACpB,aACA,MACA,OACA,UACwH;AACxH,MAAI,gBAAgB,mBAAmB;AACrC,QAAI,CAAC,KAAK,QAAQ;AAChB,cAAQ,MAAM,MAAM,IAAI,mDAAmD,CAAC;AAC5E,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,QAAS,KAAK,SAAoB;AACxC,UAAM,aAAa,aAAa,KAAK;AACrC,UAAM,SAAS,cAAc,KAAK;AAClC,UAAM,WAAW,uBAAuB,KAAK;AAC7C,UAAM,eAAe,WAAW,KAAK,QAAkB,QAAQ;AAC/D,UAAM,YAAY,WAAY,KAAK,aAAwB,KAAK,QAAkB,QAAQ;AAG1F,UAAM,oBAAoB,MAAM,YAAY,MAAM;AAElD,WAAO;AAAA,MACL,UAA0B,cAAc,YAAY,QAAQ,cAAc,WAAW,iBAAiB;AAAA,MACtG,OAAO;AAAA,MACP,aAAa;AAAA,IACf;AAAA,EACF;AAEA,MAAI,gBAAgB,oBAAoB;AACtC,QAAI,CAAC,KAAK,QAAQ;AAChB,cAAQ,MAAM,MAAM,IAAI,oDAAoD,CAAC;AAC7E,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,cAAe,KAAK,SAAoB;AAC9C,UAAM,QAAQ,aAAa,WAAW;AACtC,UAAM,MAAM,OAAO,EAAE;AACrB,UAAM,WAAW,MAAM,YAAY,MAAM,IAAI,YAAY;AACzD,UAAM,WAAW,uBAAuB,WAAW;AACnD,UAAM,cAAc,WAAW,KAAK,QAAkB,QAAQ;AAI9D,UAAM,QAAS,KAAK,SAAqB,UAAU;AACnD,QAAI,CAAC,OAAO;AACV,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,UAAM,cAAc,CAAC,CAAC,KAAK;AAI3B,QAAI,SAAS;AACb,QAAI,CAAC,UAAU;AACb,UAAI,KAAK,QAAQ;AACf,iBAAS,WAAW,KAAK,QAAkB,EAAE;AAAA,MAC/C,WAAW,UAAU,iBAAiB,QAAW;AAC/C,iBAAS,SAAS;AAAA,MACpB,OAAO;AACL,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAkD;AAAA,MACtD;AAAA,MACA,MAAM,WAAW,OAAO,OAAO,EAAE;AAAA,MACjC;AAAA,MACA,MAAM,OAAO,EAAE;AAAA,MACf,YAAY,WAAW,OAAO,UAAU,EAAE;AAAA,MAC1C,aAAa,WAAW,OAAO,UAAU,EAAE;AAAA,MAC3C;AAAA,MACA;AAAA,MACA;AAAA,MACA,gBAAgB;AAAA,MAChB,WAAW;AAAA,IACb;AAEA,WAAO;AAAA,MACL,UAAwBC,eAAc,MAAM;AAAA,MAC5C;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,gBAAgB,gBAAgB;AAClC,eAAW,QAAQ,CAAC,UAAU,UAAU,WAAW,WAAW,SAAS,GAAG;AACxE,UAAI,CAAC,KAAK,IAAI,GAAG;AACf,gBAAQ,MAAM,MAAM,IAAI,KAAK,KAAK,QAAQ,YAAY,KAAK,EAAE,YAAY,CAAC,wCAAwC,CAAC;AACnH,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AACA,UAAM,SAAS,KAAK;AACpB,UAAM,SAAS,KAAK;AAGpB,QAAI,CAAC,UAAU,mBAAmB;AAChC,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,UAAM,EAAE,WAAW,UAAU,IAAI,SAAS;AAC1C,UAAM,UAAU,WAAW,KAAK,SAAmB,SAAS;AAC5D,UAAM,UAAU,WAAW,KAAK,SAAmB,SAAS;AAC5D,UAAM,UAAU,WAAY,KAAK,WAAsB,KAAK,SAAS;AACrE,UAAM,UAAU,WAAY,KAAK,WAAsB,KAAK,SAAS;AAErE,UAAM,SAAiD;AAAA,MACrD;AAAA,MACA;AAAA,MACA,QAAQ,CAAC,CAAC,KAAK;AAAA,MACf,SAAS,UAAU,EAAE;AAAA,MACrB,QAAQ,UAAU,EAAE;AAAA,MACpB,OAAQ,KAAK,SAAqB;AAAA,MAClC,SAAS,KAAK;AAAA,MACd,gBAAgB;AAAA,MAChB,gBAAgB;AAAA,MAChB,YAAY;AAAA;AAAA,MACZ,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,eAAe;AAAA,IACjB;AAEA,WAAO;AAAA,MACL,UAA2BA,eAAc,MAAM;AAAA,MAC/C,OAAO;AAAA,MACP,aAAa;AAAA,MACb,gBAAgB,CAAC,EAAE,OAAO,QAAQ,QAAQ,QAAQ,CAAC;AAAA,IACrD;AAAA,EACF;AAEA,MAAI,gBAAgB,mBAAmB;AACrC,UAAM,eAAe,KAAK,SAAS,WAAW,KAAK,QAAkB,EAAE,IAAI;AAC3E,UAAM,cAAc,OAAQ,KAAK,YAAuB,KAAK;AAI7D,UAAM,MAAM,OAAO;AACnB,UAAM,sBAAuB,OAAO,SAAS,eAAgB;AAC7D,UAAM,sBAAuB,OAAO,SAAS,eAAgB;AAE7D,UAAM,SAAiD;AAAA,MACrD,MAAM,OAAO,EAAE;AAAA,MACf,QAAQ,OAAO,EAAE;AAAA,MACjB,SAAS,SAAS,EAAE;AAAA,MACpB,YAAY,UAAU,EAAE;AAAA,MACxB,aAAa,UAAU,EAAE;AAAA,MACzB,wBAAwB,UAAU,EAAE;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,MACA,gBAAgB;AAAA,IAClB;AAEA,WAAO;AAAA,MACL,UAAwBA,eAAc,MAAM;AAAA,MAC5C,OAAO,OAAO,EAAE;AAAA,MAChB,aAAa;AAAA,IACf;AAAA,EACF;AAEA,MAAI,gBAAgB,cAAc;AAChC,QAAI,CAAC,KAAK,QAAQ;AAChB,cAAQ,MAAM,MAAM,IAAI,8CAA8C,CAAC;AACvE,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,QAAI,CAAC,KAAK,aAAa;AACrB,cAAQ,MAAM,MAAM,IAAI,oDAAoD,CAAC;AAC7E,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,QAAS,KAAK,SAAoB;AACxC,UAAM,aAAa,aAAa,KAAK;AACrC,UAAM,WAAW,uBAAuB,KAAK;AAC7C,UAAM,SAAS,WAAW,KAAK,QAAkB,QAAQ;AACzD,UAAM,kBAAkB,WAAY,KAAK,aAAwB,KAAK,QAAkB,QAAQ;AAEhG,WAAO;AAAA,MACL,UAAsBA,eAAc,YAAY,KAAK,aAAwB,eAAe;AAAA,MAC5F,OAAO;AAAA,MACP,aAAa;AAAA,IACf;AAAA,EACF;AAEA,MAAI,gBAAgB,aAAa;AA0E/B,QAASC,yBAAT,SAA+B,OAAgB,QAA8D;AAI3G,UAAK,YAAuB,YAAa,QAAO;AAChD,UAAI,aAAa,QAAQ,MAAM,YAAY,MAAM,SAAS,YAAY,GAAG;AACvE,eAAO,EAAE,WAA4B,qBAAqB,GAAG,GAAG,WAAW,sBAAsB;AAAA,MACnG;AACA,YAAM,IAAI,uBAAuB,OAAO,YAAY,CAAC;AACrD,UAAI,GAAG;AACL,eAAO;AAAA,UACL,WAA4B,gBAAgB;AAAA,YAC1C,EAAE,UAAU,MAAM,KAAK,EAAE,WAAW,aAAa,EAAE,kBAAkB;AAAA,YACrE,EAAE,UAAU,OAAO,KAAK,EAAE,UAAU,aAAa,EAAE,iBAAiB;AAAA,UACtE,CAAC;AAAA,UACD,WAAW,mCAA8B,EAAE,SAAS,SAAS,EAAE,iBAAiB,WAAM,OAAO,YAAY,CAAC,QAAQ,EAAE,QAAQ,SAAS,EAAE,gBAAgB;AAAA,QACzJ;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAnBS,gCAAAA;AAzET,QAAI,CAAC,KAAK,QAAQ;AAAE,cAAQ,MAAM,MAAM,IAAI,6CAA6C,CAAC;AAAG,cAAQ,KAAK,CAAC;AAAA,IAAG;AAC9G,QAAI,CAAC,KAAK,UAAU,CAAC,KAAK,SAAS;AACjC,cAAQ,MAAM,MAAM,IAAI,4DAA4D,CAAC;AACrF,cAAQ,MAAM,MAAM,IAAI,wDAAwD,CAAC;AACjF,cAAQ,MAAM,MAAM,IAAI,sDAAsD,CAAC;AAC/E,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,UAAU,WAAW;AAC3B,UAAM,SAAS,OAAO;AACtB,UAAM,cAAe,KAAK,SAAoB,sBAAsB;AACpE,UAAM,QAAQ,aAAa,WAAW;AACtC,UAAM,WAAW,uBAAuB,WAAW;AACnD,UAAM,cAAc,WAAW,KAAK,QAAkB,QAAQ;AAC9D,UAAM,iBAAiB,OAAQ,KAAK,eAA0B,KAAK;AACnE,UAAM,UAAW,KAAK,WAAsB;AAI5C,UAAM,aAAc,KAAK,OAAkB,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AACzE,UAAM,aAAa,WAAW,IAAI,CAAC,YAAY;AAC7C,UAAI,UAAU,OAAO,EAAG,QAAO;AAC/B,YAAM,YAAY;AAClB,YAAM,eAAe,UAAU,QAAQ,YAAY,CAAC;AACpD,UAAI,gBAAgB,iBAAiB,KAAM,QAAO;AAClD,cAAQ,MAAM,MAAM,IAAI,kBAAkB,OAAO,EAAE,CAAC;AAAG,cAAQ,KAAK,CAAC;AAAA,IACvE,CAAC;AACD,UAAM,aAAc,KAAK,QAAmB,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,OAAO,EAAE,KAAK,CAAC,CAAC;AAClF,QAAI,WAAW,WAAW,WAAW,QAAQ;AAAE,cAAQ,MAAM,MAAM,IAAI,8CAA8C,CAAC;AAAG,cAAQ,KAAK,CAAC;AAAA,IAAG;AAC1I,QAAI,WAAW,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,MAAM,KAAO;AAAE,cAAQ,MAAM,MAAM,IAAI,2BAA2B,CAAC;AAAG,cAAQ,KAAK,CAAC;AAAA,IAAG;AAE/H,UAAM,cAAe,KAAK,eAA2B,mBAAmB;AACxE,UAAM,oBAAoB,UAAU,EAAE;AAItC,UAAM,WAAW,sBAAsB;AACvC,UAAM,YAAY,UAAU;AAW5B,UAAM,UAAU,sBAAsB,KAAK,SAA+B,WAAW,MAAM;AAC3F,UAAM,kBAAkB,QAAQ;AAChC,QAAI,QAAQ,UAAU;AAAE,cAAQ,MAAM,MAAM,IAAI,kDAAkD,CAAC;AAAG,cAAQ,KAAK,CAAC;AAAA,IAAG;AACvH,UAAM,gBAAgB,sBAAsB,KAAK,eAAqC,WAAW,MAAM;AACvG,UAAM,wBAAwB,cAAc;AAC5C,QAAI,cAAc,UAAU;AAAE,cAAQ,MAAM,MAAM,IAAI,wDAAwD,CAAC;AAAG,cAAQ,KAAK,CAAC;AAAA,IAAG;AAInI,UAAM,aAAa,sBAAsB,KAAK,YAAkC,WAAW,MAAM;AACjG,UAAM,qBAAqB,WAAW;AACtC,QAAI,WAAW,UAAU;AAAE,cAAQ,MAAM,MAAM,IAAI,qDAAqD,CAAC;AAAG,cAAQ,KAAK,CAAC;AAAA,IAAG;AAK7H,UAAM,eAAe,sBAAsB,KAAK,cAAoC,WAAW,MAAM;AACrG,UAAM,uBAAuB,aAAa;AAC1C,QAAI,aAAa,UAAU;AAAE,cAAQ,MAAM,MAAM,IAAI,wDAAwD,CAAC;AAAG,cAAQ,KAAK,CAAC;AAAA,IAAG;AAOlI,UAAM,WAAW,OAAO,EAAE;AAuB1B,YAAQ,IAAI,MAAM,IAAI,4BAA4B,CAAC;AACnD,UAAM,cAAmD,CAAC;AAC1D,aAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;AAC1C,YAAM,QAAQ,WAAW,CAAC;AAC1B,UAAI,QAAsD;AAC1D,YAAM,WAAW,mBAAmB,CAAC;AACrC,UAAI,UAAU;AACZ,YAAI;AACF,kBAAQ,EAAE,WAAW,mBAAmB,UAAU,KAAK,GAAG,WAAW,aAAa,QAAQ,IAAI;AAAA,QAChG,SAAS,GAAG;AACV,kBAAQ,MAAM,MAAM,IAAI,+BAA+B,WAAW,CAAC,CAAC,KAAM,EAAY,OAAO,EAAE,CAAC;AAChG,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAAA,MACF;AACA,UAAI,CAAC,MAAO,SAAQA,uBAAsB,OAAO,WAAW,CAAC,CAAC;AAC9D,UAAI,CAAC,SAAU,YAAuB,aAAa;AAIjD,gBAAQ;AAAA,UACN,MAAM;AAAA,YACJ,sCAAsC,WAAW,CAAC,CAAC;AAAA,UACrD;AAAA,QACF;AACA,gBAAQ;AAAA,UACN,MAAM;AAAA,YACJ;AAAA,6EACsE,WAAW,CAAC,EAAE,YAAY,CAAC;AAAA,UACnG;AAAA,QACF;AACA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,UAAI,CAAC,MAAO,SAAQ,MAAM,gBAAgB,OAAO,OAAO,OAAO,OAAO,CAAC;AACvE,UAAI,CAAC,OAAO;AACV,gBAAQ,MAAM,MAAM,IAAI,2BAA2B,KAAK,qFAAqF,CAAC;AAC9I,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,cAAQ,IAAI,MAAM,IAAI,OAAO,MAAM,MAAM,GAAG,EAAE,CAAC,cAAS,MAAM,SAAS,EAAE,CAAC;AAG1E,UAAI,SAAS,gBAAgB,CAAC;AAG9B,UAAIC,iBAAgB,sBAAsB,CAAC,IACvC,OAAO,sBAAsB,CAAC,CAAC,IAC/B,WAAW,IAAI;AAKnB,YAAM,MAAM,WAAW,CAAC,EAAE,YAAY;AACtC,UAAI,cAAc;AAClB,UAAI,qBAAqB,CAAC,GAAG;AAE3B,sBAAc,OAAO,qBAAqB,CAAC,CAAC;AAC5C,YAAI,CAAC,OAAO,UAAU,WAAW,KAAK,cAAc,GAAG;AACrD,kBAAQ,MAAM,MAAM,IAAI,kCAAkC,WAAW,CAAC,CAAC,MAAM,qBAAqB,CAAC,CAAC,sDAAsD,CAAC;AAC3J,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAAA,MACF,WAAW,YAAa,YAAuB,aAAa;AAM1D,cAAM,EAAE,aAAa,KAAK,eAAe,IAAI;AAAA,UAC3C,WAAW,CAAC;AAAA,UACZ;AAAA,UACiB;AAAA,QACnB;AACA,sBAAc;AACd,YAAI,kBAAkB,gBAAgB,CAAC,GAAG;AAIxC,kBAAQ;AAAA,YACN,MAAM;AAAA,cACJ,oBAAoB,WAAW,CAAC,CAAC,kBAAkB,OAAO;AAAA,oEAE8B,4BAA4B;AAAA,YAEtH;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,UAAI,YAAY,CAAC,QAAQ;AAGvB,cAAM,UAAU,QAAQ,UAAU,QAAQ,QAAQ,iBAAiB,GAAG,GAAG;AACzE,cAAM,OAAO,UAAU,WAAW,CAAC,CAAC,IAAI,SAAY,UAAU,OAAO;AACrE,YAAI,CAAC,QAAQ,SAAS,MAAM;AAC1B,kBAAQ,MAAM,MAAM,IAAI,8BAA8B,WAAW,CAAC,CAAC,OAAO,OAAO,oEAAoE,CAAC;AACtJ,kBAAQ,KAAK,CAAC;AAAA,QAChB;AACA,iBAA0B,WAAW,MAAM,WAAW;AAAA,MACxD,WAAW,YAAY,UAAU,UAAU,MAAM,GAAG;AAElD,iBAA0B,WAAW,QAAmB,WAAW;AAAA,MACrE;AAEA,UAAI,CAAC,UAAU,WAAW,cAAc;AACtC,gBAAQ,MAAM,MAAM,IAAI,2CAA2C,CAAC,KAAK,WAAW,CAAC,CAAC,wGAAmG,CAAC;AAC1L,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,kBAAY,KAAK;AAAA,QACf;AAAA,QAAO,WAAW,WAAW,CAAC;AAAA,QAC9B,eAAe,MAAM;AAAA,QACrB,eAAAA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,MACL,UAA2BF,eAAc,OAAO,aAAa,mBAAmB,aAAa,aAAa,cAAc;AAAA,MACxH;AAAA,MAAO,aAAa;AAAA,IACtB;AAAA,EACF;AAEA,MAAI,gBAAgB,oBAAoB;AACtC,UAAM,QAAS,KAAK,SAAoB;AACxC,UAAM,QAAQ,aAAa,KAAK;AAChC,UAAM,WAAW,uBAAuB,KAAK;AAE7C,UAAM,gBAAgB,KAAK,SAAS,WAAW,KAAK,QAAkB,QAAQ,IAAI;AAClF,UAAM,WAAW,OAAQ,KAAK,YAAuB,IAAI;AACzD,UAAM,aAAa,OAAQ,KAAK,cAAyB,GAAG;AAC5D,UAAM,cAAc,WAAY,KAAK,eAA0B,UAAU,QAAQ;AACjF,UAAM,eAAe,OAAQ,KAAK,mBAA8B,IAAI;AACpE,WAAO;AAAA,MACL,UAAiCA,eAAc,OAAO,eAAe,YAAY,UAAU,aAAa,YAAY;AAAA,MACpH;AAAA,MAAO,aAAa;AAAA,IACtB;AAAA,EACF;AAEA,MAAI,gBAAgB,oBAAoB;AACtC,UAAM,QAAS,KAAK,SAAoB;AACxC,UAAM,QAAQ,aAAa,KAAK;AAChC,UAAM,WAAW,uBAAuB,KAAK;AAC7C,UAAM,gBAAgB,KAAK,SAAS,WAAW,KAAK,QAAkB,QAAQ,IAAI;AAClF,UAAM,WAAW,OAAQ,KAAK,YAAuB,GAAG;AACxD,UAAM,eAAe,WAAY,KAAK,gBAA2B,SAAS,QAAQ;AAClF,UAAM,mBAAmB,OAAQ,KAAK,oBAA+B,IAAI;AACzE,UAAM,gBAAiB,KAAK,gBAA2B,KACpD,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,OAAO,EAAE,KAAK,CAAC,CAAC,EAC3B,OAAO,CAAC,MAAM,CAAC,OAAO,MAAM,CAAC,CAAC;AACjC,WAAO;AAAA,MACL,UAAiCA,eAAc,OAAO,eAAe,UAAU,cAAc,kBAAkB,YAAY;AAAA,MAC3H;AAAA,MAAO,aAAa;AAAA,IACtB;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,iCAAiC,WAAW,EAAE;AAChE;AAEO,SAAS,sBACd,aACA,OACA,OACA,aACA,gBACyD;AACzD,MAAI,gBAAgB,mBAAmB;AACrC,WAAO;AAAA,MACL,cAA8B,kBAAkB,OAAO,OAAO,WAAW;AAAA,MACzE,aAA6B,iBAAiB,KAAK;AAAA,IACrD;AAAA,EACF;AAEA,MAAI,gBAAgB,oBAAoB;AACtC,WAAO;AAAA,MACL,cAA4BG,mBAAkB,OAAO,OAAO,WAAW;AAAA,MACvE,aAA2BC,kBAAiB,KAAK;AAAA,IACnD;AAAA,EACF;AAEA,MAAI,gBAAgB,gBAAgB;AAClC,UAAM,SAAS,iBAAiB,CAAC,GAAG,SAAS;AAC7C,UAAM,UAAU,iBAAiB,CAAC,GAAG,UAAU;AAC/C,WAAO;AAAA,MACL,cAA+BD,mBAAkB,OAAO,OAAO,aAAa,QAAQ,OAAO;AAAA,MAC3F,aAA8BC,kBAAiB,KAAK;AAAA,IACtD;AAAA,EACF;AAEA,MAAI,gBAAgB,mBAAmB;AACrC,WAAO;AAAA,MACL,cAA4BD,mBAAkB,OAAO,OAAO,WAAW;AAAA,MACvE,aAA2BC,kBAAiB,KAAK;AAAA,IACnD;AAAA,EACF;AAEA,MAAI,gBAAgB,cAAc;AAChC,WAAO;AAAA,MACL,cAA0BD,mBAAkB,OAAO,OAAO,WAAW;AAAA,MACrE,aAAyBC,kBAAiB,KAAK;AAAA,IACjD;AAAA,EACF;AAEA,MAAI,gBAAgB,aAAa;AAC/B,WAAO;AAAA,MACL,cAA+BD,mBAAkB,OAAO,OAAO,WAAW;AAAA,MAC1E,aAA8BC,kBAAiB,KAAK;AAAA,IACtD;AAAA,EACF;AAEA,MAAI,gBAAgB,oBAAoB;AACtC,WAAO;AAAA,MACL,cAAqCD,mBAAkB,OAAO,OAAO,WAAW;AAAA,MAChF,aAAoCC,kBAAiB,KAAK;AAAA,IAC5D;AAAA,EACF;AAEA,MAAI,gBAAgB,oBAAoB;AACtC,WAAO;AAAA,MACL,cAAqCD,mBAAkB,OAAO,OAAO,WAAW;AAAA,MAChF,aAAoCC,kBAAiB,KAAK;AAAA,IAC5D;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,iCAAiC,WAAW,EAAE;AAChE;AAIO,SAAS,qBAA8B;AAC5C,QAAM,UAAU,WAAW;AAC3B,MAAI,YAAY,uBAAuB,QAAQ,EAAE,WAAW,MAAM;AAChE,YAAQ,MAAM,MAAM,IAAI,2BAA2B,CAAC;AACpD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAQA,QAAM,cAAc,QAAQ,EAAE;AAC9B,MAAI,gBAAgB,KAAM,QAAO;AACjC,UAAQ,MAAM,MAAM,IAAI,8EAA8E,CAAC;AACvG,UAAQ,KAAK,CAAC;AAChB;AAEO,SAAS,aAAa,iBAAkC;AAC7D,MAAI,UAAU,eAAe,EAAG,QAAO;AACvC,QAAM,QAAQ,gBAAgB,YAAY;AAI1C,QAAM,WAAoC;AAAA,IACxC,GAAI,OAAO;AAAA,IACX,KAAK,OAAO,EAAE;AAAA,EAChB;AACA,QAAM,OAAO,SAAS,KAAK;AAC3B,MAAI,CAAC,QAAQ,SAAS,MAAM;AAC1B,YAAQ,MAAM,MAAM,IAAI,kBAAkB,eAAe,EAAE,CAAC;AAC5D,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO;AACT;AAgBO,SAAS,wBAAgC;AAC9C,QAAM,UAAU,WAAW;AAC3B,MAAI,YAAY,oBAAqB,QAAO;AAC5C,MAAI,YAAY,iBAAkB,QAAO;AACzC,SAAO;AACT;AAQO,SAAS,uBAAuB,QAAwB;AAC7D,QAAM,QAAQ,OAAO,YAAY;AACjC,SAAO,UAAU,UAAU,UAAU,SAAS,IAAI;AACpD;AAEO,SAAS,cAAc,aAA8B;AAC1D,QAAM,QAAQ,YAAY,YAAY;AACtC,QAAM,WAAW,SAAS;AAC1B,QAAM,YAAqC;AAAA,IACzC,MAAM,SAAS;AAAA,IACf,MAAM,SAAS;AAAA,EACjB;AACA,QAAM,OAAO,UAAU,KAAK;AAC5B,MAAI,CAAC,QAAQ,SAAS,MAAM;AAC1B,YAAQ,MAAM,MAAM,IAAI,2BAA2B,WAAW,EAAE,CAAC;AACjE,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO;AACT;;;ADr3BO,IAAM,mBAAmB;AAEhC,IAAMC,QAAgB;AAkDtB,eAAsB,YACpB,SACA,UACA,mBAA2B,kBACX;AAChB,QAAM,WAAW,MAAM,gBAAgB,SAAS,UAAU,gBAAgB;AAC1E,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,2BAA2B,OAAO,SAAI,QAAQ,SAAS,gBAAgB,GAAG;AAAA,EAC5F;AACA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,WAAW,SAAS;AAAA,EACtB;AACF;AA6BA,SAAS,gBAAyB;AAChC,QAAM,SAAS,QAAQ,EAAE;AACzB,MAAI,WAAWC,OAAM;AACnB,UAAM,IAAI,MAAM,uCAAuC;AAAA,EACzD;AACA,SAAO;AACT;AAMA,eAAsB,MACpB,QACA,OAAkB,CAAC,GACH;AAChB,QAAM,QAAQ,MAAM,YAAY,OAAO,SAAS,OAAO,UAAU,OAAO,OAAO;AAC/E,MAAI,MAAM,SAAS,UAAU;AAC3B,UAAM,OAAO;AAAA,MACX,CAAC,MAAM,SAAS,MAAM,KAAK,MAAM,QAAQ;AAAA,MACzC,CAAC,MAAM,OAAO,MAAM,MAAM;AAAA,IAC5B;AACA,UAAMC,UAAS,MAAM,iBAAiB,EAAE,MAAM,UAAU,OAAO,SAAS,GAAG,IAAI;AAC/E,WAAO,EAAE,OAAO,GAAGA,QAAO;AAAA,EAC5B;AACA,QAAM,SAAS,MAAM;AAAA,IACnB;AAAA,MACE,SAAS,MAAM;AAAA,MACf,UAAU,MAAM;AAAA,MAChB,UAAU,OAAO;AAAA,MACjB,KAAK,MAAM;AAAA,IACb;AAAA,IACA;AAAA,EACF;AACA,SAAO,EAAE,OAAO,GAAG,OAAO;AAC5B;AAKA,eAAsB,SACpB,QACA,OAAkB,CAAC,GACG;AACtB,QAAM,SAAS,KAAK,UAAU,gBAAgB;AAE9C,QAAM,WAAWC,oBAAmB;AAAA,IAClC,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM;AAAA,MACJ;AAAA,QACE,SAAS,OAAO;AAAA,QAChB,UAAU,OAAO;AAAA,QACjB,UAAU,OAAO;AAAA,QACjB,KAAK,OAAO;AAAA,QACZ,mBAAmB;AAAA,MACrB;AAAA,IACF;AAAA,EACF,CAAC;AAED,QAAM,EAAE,KAAK,IAAI,MAAM,OAAO,KAAK,EAAE,IAAI,cAAc,GAAG,MAAM,SAAS,CAAC;AAE1E,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,qEAAgE;AAAA,EAClF;AAEA,QAAM,CAAC,WAAW,mBAAmB,EAAE,WAAW,IAAI,qBAAqB;AAAA,IACzE,KAAK;AAAA,IACL,cAAc;AAAA,IACd;AAAA,EACF,CAAC;AAED,SAAO,EAAE,WAAW,mBAAmB,YAAY;AACrD;AAKA,eAAsB,iBACpB,QACA,OAAkB,CAAC,GACG;AACtB,QAAM,SAAS,KAAK,UAAU,gBAAgB;AAE9C,QAAM,WAAWA,oBAAmB;AAAA,IAClC,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC,OAAO,MAAM,OAAO,QAAQ;AAAA,EACrC,CAAC;AAED,QAAM,EAAE,KAAK,IAAI,MAAM,OAAO,KAAK,EAAE,IAAI,cAAc,GAAG,MAAM,SAAS,CAAC;AAE1E,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,iEAA4D;AAAA,EAC9E;AAEA,QAAM,CAAC,WAAW,EAAE,EAAE,WAAW,IAAI,qBAAqB;AAAA,IACxD,KAAK;AAAA,IACL,cAAc;AAAA,IACd;AAAA,EACF,CAAC;AAED,SAAO,EAAE,WAAW,mBAAmB,IAAI,YAAY;AACzD;AAQO,SAAS,cAAc,WAAmB,aAA6B;AAC5E,SAAQ,YAAY,OAAO,MAAQ,WAAW,IAAK;AACrD;AAOO,SAAS,eAAe,QAAmB,MAAqB;AACrE,MAAI,OAAO,SAAS,KAAK,KAAK,WAAW,OAAO,SAAS,GAAG;AAC1D,UAAM,IAAI,MAAM,0DAA0D;AAAA,EAC5E;AACA,SAAO,aAAa,QAAQ,IAAI;AAClC;","names":["encodeFunctionData","encodeAbiParameters","concat","numberToHex","encodeAbiParameters","encodeFunctionData","buildInitData","encodeAbiParameters","buildExecuteCalls","encodeFunctionData","buildSettleCalls","encodeAbiParameters","encodeFunctionData","INIT_PARAMS_TYPES","buildInitData","encodeAbiParameters","buildExecuteCalls","encodeFunctionData","buildSettleCalls","encodeAbiParameters","encodeFunctionData","INIT_PARAMS_TYPES","buildInitData","encodeAbiParameters","buildExecuteCalls","encodeFunctionData","buildSettleCalls","encodeAbiParameters","encodeFunctionData","buildInitData","encodeAbiParameters","buildExecuteCalls","encodeFunctionData","buildSettleCalls","encodeAbiParameters","encodeFunctionData","encodeAbiParameters","buildInitData","encodeAbiParameters","buildExecuteCalls","encodeFunctionData","buildSettleCalls","encodeAbiParameters","encodeFunctionData","maxUint256","buildInitData","encodeAbiParameters","buildExecuteCalls","maxUint256","encodeFunctionData","buildSettleCalls","encodeAbiParameters","encodeFunctionData","maxUint256","buildInitData","encodeAbiParameters","buildExecuteCalls","maxUint256","encodeFunctionData","buildSettleCalls","numberToHex","concat","encoded","encodeAbiParameters","buildInitData","robinhoodDefaultRoute","priceDecimals","buildExecuteCalls","buildSettleCalls","ZERO","ZERO","result","encodeFunctionData"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/cron.ts"],"sourcesContent":["/**\n * OpenClaw cron integration — auto-register participation crons for fund agents.\n *\n * When an agent creates or joins a fund, the CLI registers two cron jobs:\n * 1. Silent check (every 15m) — processes messages/events, responds autonomously\n * 2. Human summary (every 1h) — brief activity report delivered to the human's channel\n *\n * Non-OpenClaw agents skip silently — the caller prints guidance instead.\n */\n\nimport { execFileSync } from \"node:child_process\";\n\n// ── OpenClaw detection (cached per process) ──\n\nlet _isOpenClaw: boolean | null = null;\n\nexport function isOpenClaw(): boolean {\n if (_isOpenClaw !== null) return _isOpenClaw;\n try {\n execFileSync(\"openclaw\", [\"cron\", \"list\"], {\n encoding: \"utf8\",\n timeout: 10_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n _isOpenClaw = true;\n } catch {\n _isOpenClaw = false;\n }\n return _isOpenClaw;\n}\n\n// ── Types ──\n\nexport interface CronResult {\n registered: boolean;\n isOpenClaw: boolean;\n cronNames: string[];\n}\n\nexport interface CronStatus {\n isOpenClaw: boolean;\n crons: { name: string; every: string; lastRun?: string }[];\n}\n\n// ── Cron naming ──\n\nfunction cronName(subdomain: string, testnet: boolean): string {\n return `sherwood-${subdomain}${testnet ? \"-testnet\" : \"\"}`;\n}\n\nfunction summaryCronName(subdomain: string, testnet: boolean): string {\n return `${cronName(subdomain, testnet)}-summary`;\n}\n\n// ── Prompts ──\n\nfunction silentPrompt(subdomain: string, testnet: boolean): string {\n // Current deployment target (robinhood-testnet) is the ungated CLI default,\n // so cron commands need no explicit --chain flag or env gate.\n const chainFlag = \"\";\n const envPrefix = \"\";\n void testnet;\n return [\n `You are a sherwood fund member. Your fund: ${subdomain}.sherwoodagent.eth`,\n \"\",\n `Step 1: Run \\`${envPrefix}sherwood session check ${subdomain}${chainFlag}\\``,\n \"Step 2: Parse the JSON output. The output is a single JSON object with fields: fund, messages[], events[], meta{}.\",\n \" - If the command fails or returns an error, reply HEARTBEAT_ERROR with the error message.\",\n \" - If meta.newMessages === 0 and meta.newEvents === 0, you may still be pending approval.\",\n \" Check: `\" + envPrefix + \"sherwood vault info\" + chainFlag + \"`\",\n \" If your wallet is not listed as a registered agent, you are still pending. Reply HEARTBEAT_OK.\",\n \" If you ARE registered but this is your first time seeing it, alert your human that you've been approved and are now active.\",\n \" - If there are new messages from OTHER agents, respond thoughtfully via:\",\n ` \\`${envPrefix}sherwood chat ${subdomain} send \"<response>\"${chainFlag}\\``,\n \" - If there are on-chain events (proposals, votes, settlements), acknowledge them in chat if relevant.\",\n \"Step 3: If you responded to anything, summarize what you did (for your own session log).\",\n \" If nothing happened, reply HEARTBEAT_OK\",\n \"\",\n \"Rules:\",\n \"- Be a real fund member — discuss strategies, share opinions, ask questions\",\n \"- Keep responses concise and on-topic\",\n \"- Do NOT alert your human unless something requires their approval (or you were just approved)\",\n `- You can use \\`sherwood research\\` commands if you need data to back up your response`,\n ].join(\"\\n\");\n}\n\nfunction summaryPrompt(subdomain: string, testnet: boolean): string {\n // Current deployment target (robinhood-testnet) is the ungated CLI default,\n // so cron commands need no explicit --chain flag or env gate.\n const chainFlag = \"\";\n const envPrefix = \"\";\n void testnet;\n return [\n \"You are reporting fund activity to your human operator.\",\n \"\",\n `Run: \\`${envPrefix}sherwood session check ${subdomain}${chainFlag}\\``,\n \"\",\n \"The output is a single JSON object with fields: fund, messages[], events[], meta{}.\",\n \"If the command fails, report the error to your human.\",\n \"\",\n \"If there was activity (messages, events, proposals) since last check:\",\n \" Send a brief summary — who said what, any decisions made, any actions you took.\",\n \" Keep it to 3-5 lines max.\",\n \"\",\n \"If there was no activity:\",\n \" Reply HEARTBEAT_OK\",\n \"\",\n \"Only escalate (flag as urgent) if:\",\n \"- A proposal needs human sign-off\",\n \"- An agent left the fund\",\n \"- Risk alert or health factor warning\",\n \"- Human was directly asked for input\",\n ].join(\"\\n\");\n}\n\n// ── Helpers ──\n\n/** Parse `openclaw cron list --json` and return job names. */\nfunction listCronNames(): string[] {\n try {\n const raw = execFileSync(\"openclaw\", [\"cron\", \"list\", \"--json\"], {\n encoding: \"utf8\",\n timeout: 10_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n const parsed = JSON.parse(raw);\n const jobs: { name: string }[] = parsed.jobs || parsed || [];\n return jobs.map((j) => j.name);\n } catch {\n return [];\n }\n}\n\n/** Parse `openclaw cron list --json` with full details for status display. */\nfunction listCronDetails(): { name: string; every: string; lastRun?: string }[] {\n try {\n const raw = execFileSync(\"openclaw\", [\"cron\", \"list\", \"--json\"], {\n encoding: \"utf8\",\n timeout: 10_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n const parsed = JSON.parse(raw);\n const jobs: { name: string; every?: string; interval?: string; lastRun?: string }[] =\n parsed.jobs || parsed || [];\n return jobs.map((j) => ({\n name: j.name,\n every: j.every || j.interval || \"unknown\",\n lastRun: j.lastRun,\n }));\n } catch {\n return [];\n }\n}\n\n// ── Public API ──\n\nexport function registerFundCrons(\n subdomain: string,\n testnet: boolean,\n notifyTo?: string,\n): CronResult {\n if (!isOpenClaw()) {\n return { registered: false, isOpenClaw: false, cronNames: [] };\n }\n\n const checkName = cronName(subdomain, testnet);\n const summaryName = summaryCronName(subdomain, testnet);\n const existing = listCronNames();\n const created: string[] = [];\n\n // Cron 1: Silent participation check (every 15m)\n if (!existing.includes(checkName)) {\n try {\n execFileSync(\"openclaw\", [\n \"cron\", \"create\",\n \"--name\", checkName,\n \"--every\", \"15m\",\n \"--session\", \"isolated\",\n \"--timeout-seconds\", \"120\",\n \"--no-deliver\",\n \"--message\", silentPrompt(subdomain, testnet),\n ], {\n encoding: \"utf8\",\n timeout: 30_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n created.push(checkName);\n } catch (err) {\n console.warn(`Could not create silent cron: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n // Cron 2: Human summary (every 1h)\n if (!existing.includes(summaryName)) {\n try {\n const args = [\n \"cron\", \"create\",\n \"--name\", summaryName,\n \"--every\", \"1h\",\n \"--session\", \"isolated\",\n \"--timeout-seconds\", \"90\",\n \"--announce\",\n ];\n\n // Use explicit destination if configured, otherwise auto-route via --channel last\n if (notifyTo) {\n args.push(\"--to\", notifyTo);\n } else {\n args.push(\"--channel\", \"last\");\n }\n\n args.push(\"--message\", summaryPrompt(subdomain, testnet));\n\n execFileSync(\"openclaw\", args, {\n encoding: \"utf8\",\n timeout: 30_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n created.push(summaryName);\n } catch (err) {\n console.warn(`Could not create summary cron: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n return {\n registered: created.length > 0,\n isOpenClaw: true,\n cronNames: created,\n };\n}\n\nexport function unregisterFundCrons(\n subdomain: string,\n testnet: boolean,\n): { removed: boolean; isOpenClaw: boolean } {\n if (!isOpenClaw()) {\n return { removed: false, isOpenClaw: false };\n }\n\n const names = [cronName(subdomain, testnet), summaryCronName(subdomain, testnet)];\n let removed = false;\n\n for (const name of names) {\n try {\n execFileSync(\"openclaw\", [\"cron\", \"remove\", \"--name\", name], {\n encoding: \"utf8\",\n timeout: 10_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n removed = true;\n } catch {\n // Cron may not exist — that's fine\n }\n }\n\n return { removed, isOpenClaw: true };\n}\n\nexport function getFundCronStatus(\n subdomain: string,\n testnet: boolean,\n): CronStatus {\n if (!isOpenClaw()) {\n return { isOpenClaw: false, crons: [] };\n }\n\n const prefix = cronName(subdomain, testnet);\n const all = listCronDetails();\n const matching = all.filter((c) => c.name.startsWith(prefix));\n\n return { isOpenClaw: true, crons: matching };\n}\n"],"mappings":"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","names":[]}