@oydual31/more-vaults-sdk 0.2.4 → 0.2.5

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/viem/chains.ts","../../src/viem/abis.ts","../../src/viem/types.ts","../../src/viem/errors.ts","../../src/viem/utils.ts","../../src/viem/spokeRoutes.ts","../../src/viem/topology.ts","../../src/viem/preflight.ts","../../src/viem/chainValidation.ts","../../src/viem/depositFlows.ts","../../src/viem/redeemFlows.ts","../../src/viem/userHelpers.ts","../../src/viem/distribution.ts","../../src/viem/wagmiCompat.ts","../../src/react/useVaultStatus.ts","../../src/react/useVaultMetadata.ts","../../src/react/useUserPosition.ts","../../src/react/useUserPositionMultiChain.ts","../../src/react/useLzFee.ts","../../src/react/useAsyncRequestStatus.ts","../../src/react/useVaultTopology.ts","../../src/react/useOmniDeposit.ts","../../src/react/useOmniRedeem.ts","../../src/react/useDepositSimple.ts","../../src/react/useRedeemShares.ts","../../src/react/useVaultDistribution.ts","../../src/react/useSmartDeposit.ts","../../src/react/useSmartRedeem.ts","../../src/react/useInboundRoutes.ts"],"names":["getAddress","zeroAddress","createPublicClient","http","fallback","localChainId","encodeAbiParameters","usePublicClient","useQuery","useChainId","useWalletClient","useState","useCallback","useMemo"],"mappings":"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","file":"index.cjs","sourcesContent":["/** EVM Chain IDs for chains supported by MoreVaults */\nexport const CHAIN_IDS = {\n flowEVMMainnet: 747,\n flowEVMTestnet: 545,\n arbitrum: 42161,\n base: 8453,\n ethereum: 1,\n optimism: 10,\n sonic: 146,\n bsc: 56,\n} as const\n\n/**\n * LayerZero Endpoint IDs (EID) for chains supported by MoreVaults.\n * Verified on-chain via MoreVaults OmniFactory.localEid() on each chain.\n * - flowMainnet: 30336 (0x7680) — confirmed from factory + LZ endpoint on Flow EVM mainnet\n * - base: 30184 (0x75e8) — confirmed from factory on Base\n * - arbitrum: 30110 (0x75b6) — confirmed from factory on Arbitrum\n * - ethereum: 30101 (0x75b5) — confirmed from factory on Ethereum\n * - optimism: 30111 — verified via LZ docs and on-chain quoteSend\n */\nexport const LZ_EIDS = {\n flowMainnet: 30336,\n flowTestnet: 30333,\n arbitrum: 30110,\n base: 30184,\n ethereum: 30101,\n optimism: 30111,\n sonic: 30332,\n bsc: 30102,\n} as const\n\n/** LayerZero EID → EVM Chain ID */\nexport const EID_TO_CHAIN_ID: Record<number, number> = {\n [LZ_EIDS.flowMainnet]: CHAIN_IDS.flowEVMMainnet,\n [LZ_EIDS.flowTestnet]: CHAIN_IDS.flowEVMTestnet,\n [LZ_EIDS.arbitrum]: CHAIN_IDS.arbitrum,\n [LZ_EIDS.base]: CHAIN_IDS.base,\n [LZ_EIDS.ethereum]: CHAIN_IDS.ethereum,\n [LZ_EIDS.optimism]: CHAIN_IDS.optimism,\n [LZ_EIDS.sonic]: CHAIN_IDS.sonic,\n [LZ_EIDS.bsc]: CHAIN_IDS.bsc,\n}\n\n/** EVM Chain ID → LayerZero EID */\nexport const CHAIN_ID_TO_EID: Record<number, number> = {\n [CHAIN_IDS.flowEVMMainnet]: LZ_EIDS.flowMainnet,\n [CHAIN_IDS.flowEVMTestnet]: LZ_EIDS.flowTestnet,\n [CHAIN_IDS.arbitrum]: LZ_EIDS.arbitrum,\n [CHAIN_IDS.base]: LZ_EIDS.base,\n [CHAIN_IDS.ethereum]: LZ_EIDS.ethereum,\n [CHAIN_IDS.optimism]: LZ_EIDS.optimism,\n [CHAIN_IDS.sonic]: LZ_EIDS.sonic,\n [CHAIN_IDS.bsc]: LZ_EIDS.bsc,\n}\n\n/**\n * LayerZero v2 OFT route config per asset symbol.\n *\n * Each entry maps chainId → { oft, token } where:\n * - `oft` = OFT contract to call send() on (pass as `spokeOFT` to depositFromSpoke)\n * - `token` = underlying ERC-20 the user approves before bridging\n * (zero address = native ETH, no approval needed)\n *\n * All routes verified on-chain via quoteSend() or peers(). Issuers vary per asset.\n */\nexport const OFT_ROUTES = {\n /**\n * stgUSDC — USDC bridged via Stargate v2.\n * Underlying on Eth/Arb/Base/Op: native USDC. On Flow: stgUSDC (Stargate's wrapped USDC).\n * Routes verified: Eth→Flow ✓ Arb→Flow ✓ Base→Flow ✓ Op→Flow ✓ Op→Base ✓ Op→Arb ✓\n */\n stgUSDC: {\n [747 /* flowEVMMainnet */]: { oft: '0xAF54BE5B6eEc24d6BFACf1cce4eaF680A8239398' as `0x${string}`, token: '0xF1815bd50389c46847f0Bda824eC8da914045D14' as `0x${string}` },\n [1 /* ethereum */]: { oft: '0xc026395860Db2d07ee33e05fE50ed7bD583189C7' as `0x${string}`, token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0xe8CDF27AcD73a434D661C84887215F7598e7d0d3' as `0x${string}`, token: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831' as `0x${string}` },\n [8453 /* base */]: { oft: '0x27a16dc786820B16E5c9028b75B99F6f604b5d26' as `0x${string}`, token: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' as `0x${string}` },\n [10 /* optimism */]: { oft: '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0' as `0x${string}`, token: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85' as `0x${string}` },\n [146 /* sonic */]: { oft: '0xA272fFe20cFfe769CdFc4b63088DCD2C82a2D8F9' as `0x${string}`, token: '0x29219dd400f2Bf60E5a23d13Be72B486D4038894' as `0x${string}` },\n },\n /**\n * USDT — USDT bridged via Stargate v2.\n * Routes verified: Arb→Flow ✓ Eth→Flow ✓ Op→Flow ✓ Op→Base ✓ Op→Arb ✓\n */\n USDT: {\n [747 /* flowEVMMainnet */]: { oft: '0xAf5191B0De278C7286d6C7CC6ab6BB8A73bA2Cd6' as `0x${string}`, token: '0x674843C06FF83502ddb4D37c2E09C01cdA38cbc8' as `0x${string}` },\n [1 /* ethereum */]: { oft: '0x933597a323Eb81cAe705C5bC29985172fd5A3973' as `0x${string}`, token: '0xdAC17F958D2ee523a2206206994597C13D831ec7' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0' as `0x${string}`, token: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9' as `0x${string}` },\n [10 /* optimism */]: { oft: '0x19cFCE47eD54a88614648DC3f19A5980097007dD' as `0x${string}`, token: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58' as `0x${string}` },\n },\n /**\n * PYUSD — PayPal USD OFT (issued by PayPal/Flow).\n * Routes verified: Eth→Flow ✓\n */\n PYUSD: {\n [747 /* flowEVMMainnet */]: { oft: '0x2aabea2058b5ac2d339b163c6ab6f2b6d53aabed' as `0x${string}`, token: '0x2aabea2058b5ac2d339b163c6ab6f2b6d53aabed' as `0x${string}` },\n [1 /* ethereum */]: { oft: '0xfa0e06b54986ad96de87a8c56fea76fbd8d493f8' as `0x${string}`, token: '0x6c3ea9036406852006290770BEdFcAbA0e23A0e8' as `0x${string}` },\n },\n /**\n * WFLOW — Wrapped FLOW NativeOFTAdapter (issued by Flow Foundation).\n * Routes verified: Eth→Flow ✓\n */\n WFLOW: {\n [747 /* flowEVMMainnet */]: { oft: '0xd296588850bee2770136464ffdddd78c32f2a07c' as `0x${string}`, token: '0xd296588850bee2770136464ffdddd78c32f2a07c' as `0x${string}` },\n [1 /* ethereum */]: { oft: '0xc1b45896b5fc9422a8f779653808297bb4f546f9' as `0x${string}`, token: '0x5c147e74D63B1D31AA3Fd78Eb229B65161983B2b' as `0x${string}` },\n },\n /**\n * WETH — ETH OFT via Stargate v2. underlying = native ETH (no approval needed).\n * Warning: Flow and Optimism routes error on quoteSend — do not use with those chains.\n */\n WETH: {\n [747 /* flowEVMMainnet */]: { oft: '0x45f1A95A4D3f3836523F5c83673c797f4d4d263B' as `0x${string}`, token: '0x2F6F07CDcf3588944Bf4C42aC74ff24bF56e7590' as `0x${string}` },\n [1 /* ethereum */]: { oft: '0x77b2043768d28E9C9aB44E1aBfC95944bcE57931' as `0x${string}`, token: '0x0000000000000000000000000000000000000000' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0xA45B5130f36CDcA45667738e2a258AB09f4A5f7F' as `0x${string}`, token: '0x0000000000000000000000000000000000000000' as `0x${string}` },\n [8453 /* base */]: { oft: '0xdc181Bd607330aeeBEF6ea62e03e5e1Fb4B6F7C7' as `0x${string}`, token: '0x0000000000000000000000000000000000000000' as `0x${string}` },\n },\n /**\n * sUSDe — Ethena staked USDe (yield-bearing stablecoin).\n * Pure OFT on Op/Arb/Base, OFTAdapter on Eth (wraps real sUSDe ERC4626).\n * Routes verified via peers(): Op↔Arb ✓ Op↔Eth ✓ Op↔Base ✓\n * No Flow peer.\n */\n sUSDe: {\n [1 /* ethereum */]: { oft: '0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2' as `0x${string}`, token: '0x9D39A5DE30e57443BfF2A8307A4256c8797A3497' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2' as `0x${string}`, token: '0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2' as `0x${string}` },\n [8453 /* base */]: { oft: '0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2' as `0x${string}`, token: '0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2' as `0x${string}` },\n [10 /* optimism */]: { oft: '0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2' as `0x${string}`, token: '0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2' as `0x${string}` },\n [56 /* bsc */]: { oft: '0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2' as `0x${string}`, token: '0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2' as `0x${string}` },\n },\n /**\n * USDe — Ethena USD stablecoin.\n * Pure OFT on Arb/Base/Op/BSC, OFTAdapter on Eth (wraps real USDe).\n * Routes verified via peers(): Arb↔Eth ✓ Arb↔Base ✓ BSC↔Op ✓ BSC↔Eth ✓ BSC↔Arb ✓\n * No Flow peer.\n */\n USDe: {\n [1 /* ethereum */]: { oft: '0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34' as `0x${string}`, token: '0x4c9EDD5852cd905f086C759E8383e09bff1E68B3' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34' as `0x${string}`, token: '0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34' as `0x${string}` },\n [8453 /* base */]: { oft: '0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34' as `0x${string}`, token: '0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34' as `0x${string}` },\n [10 /* optimism */]: { oft: '0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34' as `0x${string}`, token: '0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34' as `0x${string}` },\n [56 /* bsc */]: { oft: '0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34' as `0x${string}`, token: '0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34' as `0x${string}` },\n },\n /**\n * weETH — Ether.Fi liquid restaking token.\n * Pure OFT on Op/Base, OFTAdapter on Eth (wraps real weETH).\n * Routes verified via peers(): Op↔Eth ✓ Op↔Base ✓\n * No Flow or Arbitrum peer from Optimism.\n */\n weETH: {\n [1 /* ethereum */]: { oft: '0xcd2eb13d6831d4602d80e5db9230a57596cdca63' as `0x${string}`, token: '0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee' as `0x${string}` },\n [8453 /* base */]: { oft: '0x04c0599ae5a44757c0af6f9ec3b93da8976c150a' as `0x${string}`, token: '0x04c0599ae5a44757c0af6f9ec3b93da8976c150a' as `0x${string}` },\n [10 /* optimism */]: { oft: '0x5a7facb970d094b6c7ff1df0ea68d99e6e73cbff' as `0x${string}`, token: '0x5a7facb970d094b6c7ff1df0ea68d99e6e73cbff' as `0x${string}` },\n [56 /* bsc */]: { oft: '0x04c0599ae5a44757c0af6f9ec3b93da8976c150a' as `0x${string}`, token: '0x04c0599ae5a44757c0af6f9ec3b93da8976c150a' as `0x${string}` },\n [146 /* sonic */]: { oft: '0xa3d68b74bf0528fdd07263c60d6488749044914b' as `0x${string}`, token: '0xa3d68b74bf0528fdd07263c60d6488749044914b' as `0x${string}` },\n },\n /**\n * rsETH — Kelp DAO liquid restaking token.\n * Pure OFT on Op/Arb/Base, OFTAdapter on Eth (wraps real rsETH).\n * Routes verified via peers(): Op↔Eth ✓ Op↔Arb ✓ Op↔Base ✓\n * No Flow peer.\n */\n rsETH: {\n [1 /* ethereum */]: { oft: '0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3' as `0x${string}`, token: '0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0x4186bfc76e2e237523cbc30fd220fe055156b41f' as `0x${string}`, token: '0x4186bfc76e2e237523cbc30fd220fe055156b41f' as `0x${string}` },\n [8453 /* base */]: { oft: '0x1bc71130a0e39942a7658878169764bbd8a45993' as `0x${string}`, token: '0x1bc71130a0e39942a7658878169764bbd8a45993' as `0x${string}` },\n [10 /* optimism */]: { oft: '0x4186bfc76e2e237523cbc30fd220fe055156b41f' as `0x${string}`, token: '0x4186bfc76e2e237523cbc30fd220fe055156b41f' as `0x${string}` },\n [146 /* sonic */]: { oft: '0xd75787ba9aba324420d522bda84c08c87e5099b1' as `0x${string}`, token: '0xd75787ba9aba324420d522bda84c08c87e5099b1' as `0x${string}` },\n },\n /**\n * rswETH — Swell Network liquid restaking token.\n * Pure OFT on Arb/Base, OFTAdapter on Eth (wraps real rswETH).\n * Routes verified via peers(): Arb↔Eth ✓ Arb↔Base ✓\n * No Flow or Optimism peer.\n */\n rswETH: {\n [1 /* ethereum */]: { oft: '0x1486d39646cdee84619bd05997319545a8575079' as `0x${string}`, token: '0xFAe103DC9cf190eD75350761e95403b7b8aFa6c0' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0xb1fe27b32ffb5ce54e272c096547f1e86c19e72f' as `0x${string}`, token: '0xb1fe27b32ffb5ce54e272c096547f1e86c19e72f' as `0x${string}` },\n [8453 /* base */]: { oft: '0x850cdf416668210ed0c36bfff5d21921c7ada3b8' as `0x${string}`, token: '0x850cdf416668210ed0c36bfff5d21921c7ada3b8' as `0x${string}` },\n },\n /**\n * USR — Resolv Labs USD stablecoin.\n * Pure OFT on Arb/Base, OFTAdapter on Eth.\n * Routes verified via peers(): Arb↔Eth ✓ Arb↔Base ✓\n * No Flow or Optimism peer.\n */\n USR: {\n [1 /* ethereum */]: { oft: '0xd2ee2776f34ef4e7325745b06e6d464b08d4be0e' as `0x${string}`, token: '0x66a1E37c9b0eAddca17d3662D6c05F4DECf3e110' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0x2492d0006411af6c8bbb1c8afc1b0197350a79e9' as `0x${string}`, token: '0x2492d0006411af6c8bbb1c8afc1b0197350a79e9' as `0x${string}` },\n [8453 /* base */]: { oft: '0x35e5db674d8e93a03d814fa0ada70731efe8a4b9' as `0x${string}`, token: '0x35e5db674d8e93a03d814fa0ada70731efe8a4b9' as `0x${string}` },\n [56 /* bsc */]: { oft: '0x2492d0006411af6c8bbb1c8afc1b0197350a79e9' as `0x${string}`, token: '0x2492d0006411af6c8bbb1c8afc1b0197350a79e9' as `0x${string}` },\n },\n /**\n * wstUSR — Resolv Labs wrapped staked USR (yield-bearing).\n * Pure OFT on Arb/Base, OFTAdapter on Eth.\n * Routes verified via peers(): Arb↔Eth ✓ Arb↔Base ✓\n * No Flow or Optimism peer.\n */\n wstUSR: {\n [1 /* ethereum */]: { oft: '0xab17c1fe647c37ceb9b96d1c27dd189bf8451978' as `0x${string}`, token: '0x1202F5C7b4B9E47a1A484E8B270be34dbbC75055' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0x66cfbd79257dc5217903a36293120282548e2254' as `0x${string}`, token: '0x66cfbd79257dc5217903a36293120282548e2254' as `0x${string}` },\n [8453 /* base */]: { oft: '0xb67675158b412d53fe6b68946483ba920b135ba1' as `0x${string}`, token: '0xb67675158b412d53fe6b68946483ba920b135ba1' as `0x${string}` },\n [56 /* bsc */]: { oft: '0x4254813524695def4163a169e901f3d7a1a55429' as `0x${string}`, token: '0x4254813524695def4163a169e901f3d7a1a55429' as `0x${string}` },\n },\n /**\n * USDtb — Ethena treasury-backed stablecoin.\n * Pure OFT on Arb/Base, OFTAdapter on Eth.\n * Routes verified via peers(): Arb↔Eth ✓ Arb↔Base ✓\n * No Flow or Optimism peer.\n */\n USDtb: {\n [1 /* ethereum */]: { oft: '0xc708b6887db46005da033501f8aebee72d191a5d' as `0x${string}`, token: '0xC139190F447e929f090Edeb554D95AbB8b18aC1C' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0xc708b6887db46005da033501f8aebee72d191a5d' as `0x${string}`, token: '0xc708b6887db46005da033501f8aebee72d191a5d' as `0x${string}` },\n [8453 /* base */]: { oft: '0xc708b6887db46005da033501f8aebee72d191a5d' as `0x${string}`, token: '0xc708b6887db46005da033501f8aebee72d191a5d' as `0x${string}` },\n },\n} as const\n\n/**\n * oftCmd for Stargate v2 taxi mode (immediate per-message delivery).\n * Pass as `oftCmd` in SendParam when using stgUSDC, USDT, or WETH OFT_ROUTES entries.\n * Non-Stargate OFTs (PYUSD, WFLOW, sUSDe, USDe, weETH, rsETH) use empty bytes — pass `'0x'` instead.\n */\nexport const STARGATE_TAXI_CMD = '0x01' as const\n\n/**\n * Recommended timeouts for cross-chain operations (milliseconds).\n *\n * Based on real E2E tests:\n * - Standard OFT bridge (non-Stargate): ~5-10 min\n * - Stargate bridge: ~10-15 min, can reach 20 min under load\n * - LZ Read callback (async deposit/redeem): ~5-10 min\n * - Full spoke deposit (compose + oracle + share bridge): ~10-15 min\n * - Full spoke redeem (share bridge + async redeem + asset bridge): ~25-30 min\n *\n * UIs should show a progress indicator and NOT timeout before these values.\n */\nexport const LZ_TIMEOUTS = {\n /** Poll interval between balance/event checks */\n POLL_INTERVAL: 30_000,\n /** Standard OFT bridge (shares or assets, non-Stargate) */\n OFT_BRIDGE: 900_000, // 15 min\n /** Stargate bridge (USDC, USDT, WETH) — slower due to pool mechanics */\n STARGATE_BRIDGE: 1_800_000, // 30 min\n /** LZ Read callback (async vault actions) */\n LZ_READ_CALLBACK: 900_000, // 15 min\n /** Compose delivery to hub (deposit from spoke) */\n COMPOSE_DELIVERY: 2_700_000, // 45 min\n /** Full spoke→hub→spoke redeem (all steps combined) */\n FULL_SPOKE_REDEEM: 3_600_000, // 60 min\n} as const\n\n// ---------------------------------------------------------------------------\n// Legacy flat exports — kept for backwards compat, prefer OFT_ROUTES\n// ---------------------------------------------------------------------------\n\n/** @deprecated Use OFT_ROUTES.stgUSDC instead */\nexport const USDC_STARGATE_OFT: Partial<Record<number, `0x${string}`>> = Object.fromEntries(\n Object.entries(OFT_ROUTES.stgUSDC).map(([k, v]) => [k, v.oft])\n)\n/** @deprecated Use OFT_ROUTES.stgUSDC[chainId].token instead */\nexport const USDC_TOKEN: Partial<Record<number, `0x${string}`>> = Object.fromEntries(\n Object.entries(OFT_ROUTES.stgUSDC).map(([k, v]) => [k, v.token])\n)\n","/**\n * ABI fragments for MoreVaults SDK.\n * Extracted from compiled contract artifacts — only the selectors used by SDK flows.\n */\n\nexport const VAULT_ABI = [\n {\n type: 'function',\n name: 'deposit',\n inputs: [\n { name: 'assets', type: 'uint256' },\n { name: 'receiver', type: 'address' },\n ],\n outputs: [{ name: 'shares', type: 'uint256' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'deposit',\n inputs: [\n { name: 'tokens', type: 'address[]' },\n { name: 'assets', type: 'uint256[]' },\n { name: 'receiver', type: 'address' },\n { name: 'minAmountOut', type: 'uint256' },\n ],\n outputs: [{ name: 'shares', type: 'uint256' }],\n stateMutability: 'payable',\n },\n {\n type: 'function',\n name: 'mint',\n inputs: [\n { name: 'shares', type: 'uint256' },\n { name: 'receiver', type: 'address' },\n ],\n outputs: [{ name: 'assets', type: 'uint256' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'withdraw',\n inputs: [\n { name: 'assets', type: 'uint256' },\n { name: 'receiver', type: 'address' },\n { name: 'owner', type: 'address' },\n ],\n outputs: [{ name: 'shares', type: 'uint256' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'redeem',\n inputs: [\n { name: 'shares', type: 'uint256' },\n { name: 'receiver', type: 'address' },\n { name: 'owner', type: 'address' },\n ],\n outputs: [{ name: 'assets', type: 'uint256' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'requestRedeem',\n inputs: [\n { name: '_shares', type: 'uint256' },\n { name: '_onBehalfOf', type: 'address' },\n ],\n outputs: [],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'requestWithdraw',\n inputs: [\n { name: '_assets', type: 'uint256' },\n { name: '_onBehalfOf', type: 'address' },\n ],\n outputs: [],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'getWithdrawalRequest',\n inputs: [{ name: '_owner', type: 'address' }],\n outputs: [\n { name: 'shares', type: 'uint256' },\n { name: 'timelockEndsAt', type: 'uint256' },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'totalAssets',\n inputs: [],\n outputs: [{ name: '_totalAssets', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'totalSupply',\n inputs: [],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'balanceOf',\n inputs: [{ name: 'account', type: 'address' }],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'asset',\n inputs: [],\n outputs: [{ name: '', type: 'address' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'convertToShares',\n inputs: [{ name: 'assets', type: 'uint256' }],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'convertToAssets',\n inputs: [{ name: 'shares', type: 'uint256' }],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'previewDeposit',\n inputs: [{ name: 'assets', type: 'uint256' }],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'previewRedeem',\n inputs: [{ name: 'shares', type: 'uint256' }],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n] as const\n\nexport const BRIDGE_ABI = [\n {\n type: 'function',\n name: 'initVaultActionRequest',\n inputs: [\n { name: 'actionType', type: 'uint8' },\n { name: 'actionCallData', type: 'bytes' },\n { name: 'amountLimit', type: 'uint256' },\n { name: 'extraOptions', type: 'bytes' },\n ],\n outputs: [{ name: 'guid', type: 'bytes32' }],\n stateMutability: 'payable',\n },\n {\n type: 'function',\n name: 'getRequestInfo',\n inputs: [{ name: 'guid', type: 'bytes32' }],\n outputs: [\n {\n name: '',\n type: 'tuple',\n components: [\n { name: 'initiator', type: 'address' },\n { name: 'timestamp', type: 'uint64' },\n { name: 'actionType', type: 'uint8' },\n { name: 'actionCallData', type: 'bytes' },\n { name: 'fulfilled', type: 'bool' },\n { name: 'finalized', type: 'bool' },\n { name: 'refunded', type: 'bool' },\n { name: 'totalAssets', type: 'uint256' },\n { name: 'finalizationResult', type: 'uint256' },\n { name: 'amountLimit', type: 'uint256' },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'getFinalizationResult',\n inputs: [{ name: 'guid', type: 'bytes32' }],\n outputs: [{ name: 'result', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'quoteAccountingFee',\n inputs: [{ name: 'extraOptions', type: 'bytes' }],\n outputs: [{ name: 'nativeFee', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'oraclesCrossChainAccounting',\n inputs: [],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'view',\n },\n] as const\n\nexport const CONFIG_ABI = [\n {\n type: 'function',\n name: 'getEscrow',\n inputs: [],\n outputs: [{ name: 'escrow', type: 'address' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'getCrossChainAccountingManager',\n inputs: [],\n outputs: [{ name: '', type: 'address' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'isHub',\n inputs: [],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'getWithdrawalQueueStatus',\n inputs: [],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'getWithdrawalTimelock',\n inputs: [],\n outputs: [{ name: '', type: 'uint64' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'paused',\n inputs: [],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'maxDeposit',\n inputs: [{ name: 'receiver', type: 'address' }],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n] as const\n\nexport const ERC20_ABI = [\n {\n type: 'function',\n name: 'approve',\n inputs: [\n { name: 'spender', type: 'address' },\n { name: 'value', type: 'uint256' },\n ],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'allowance',\n inputs: [\n { name: 'owner', type: 'address' },\n { name: 'spender', type: 'address' },\n ],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'balanceOf',\n inputs: [{ name: 'account', type: 'address' }],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n] as const\n\n/**\n * Minimal ABI for reading ERC-20 / ERC-4626 token metadata.\n * Used to read name, symbol, and decimals from any token or vault.\n */\nexport const METADATA_ABI = [\n { type: 'function', name: 'name', inputs: [], outputs: [{ name: '', type: 'string' }], stateMutability: 'view' },\n { type: 'function', name: 'symbol', inputs: [], outputs: [{ name: '', type: 'string' }], stateMutability: 'view' },\n { type: 'function', name: 'decimals', inputs: [], outputs: [{ name: '', type: 'uint8' }], stateMutability: 'view' },\n] as const\n\n/**\n * Minimal OFT ABI for cross-chain bridging (LayerZero OFT standard).\n * Used by D6/D7 spoke-to-hub flows and R6 share bridging.\n */\nexport const OFT_ABI = [\n {\n type: 'function',\n name: 'send',\n inputs: [\n {\n name: '_sendParam',\n type: 'tuple',\n components: [\n { name: 'dstEid', type: 'uint32' },\n { name: 'to', type: 'bytes32' },\n { name: 'amountLD', type: 'uint256' },\n { name: 'minAmountLD', type: 'uint256' },\n { name: 'extraOptions', type: 'bytes' },\n { name: 'composeMsg', type: 'bytes' },\n { name: 'oftCmd', type: 'bytes' },\n ],\n },\n {\n name: '_fee',\n type: 'tuple',\n components: [\n { name: 'nativeFee', type: 'uint256' },\n { name: 'lzTokenFee', type: 'uint256' },\n ],\n },\n { name: '_refundAddress', type: 'address' },\n ],\n outputs: [\n {\n name: 'msgReceipt',\n type: 'tuple',\n components: [\n { name: 'guid', type: 'bytes32' },\n { name: 'nonce', type: 'uint64' },\n {\n name: 'fee',\n type: 'tuple',\n components: [\n { name: 'nativeFee', type: 'uint256' },\n { name: 'lzTokenFee', type: 'uint256' },\n ],\n },\n ],\n },\n {\n name: 'oftReceipt',\n type: 'tuple',\n components: [\n { name: 'amountSentLD', type: 'uint256' },\n { name: 'amountReceivedLD', type: 'uint256' },\n ],\n },\n ],\n stateMutability: 'payable',\n },\n {\n type: 'function',\n name: 'quoteSend',\n inputs: [\n {\n name: '_sendParam',\n type: 'tuple',\n components: [\n { name: 'dstEid', type: 'uint32' },\n { name: 'to', type: 'bytes32' },\n { name: 'amountLD', type: 'uint256' },\n { name: 'minAmountLD', type: 'uint256' },\n { name: 'extraOptions', type: 'bytes' },\n { name: 'composeMsg', type: 'bytes' },\n { name: 'oftCmd', type: 'bytes' },\n ],\n },\n { name: '_payInLzToken', type: 'bool' },\n ],\n outputs: [\n {\n name: 'msgFee',\n type: 'tuple',\n components: [\n { name: 'nativeFee', type: 'uint256' },\n { name: 'lzTokenFee', type: 'uint256' },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'token',\n inputs: [],\n outputs: [{ name: '', type: 'address' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'peers',\n inputs: [{ name: '_eid', type: 'uint32' }],\n outputs: [{ name: '', type: 'bytes32' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'quoteOFT',\n inputs: [\n {\n name: '_sendParam',\n type: 'tuple',\n components: [\n { name: 'dstEid', type: 'uint32' },\n { name: 'to', type: 'bytes32' },\n { name: 'amountLD', type: 'uint256' },\n { name: 'minAmountLD', type: 'uint256' },\n { name: 'extraOptions', type: 'bytes' },\n { name: 'composeMsg', type: 'bytes' },\n { name: 'oftCmd', type: 'bytes' },\n ],\n },\n ],\n outputs: [\n {\n name: 'oftLimit',\n type: 'tuple',\n components: [\n { name: 'minAmountLD', type: 'uint256' },\n { name: 'maxAmountLD', type: 'uint256' },\n ],\n },\n {\n name: 'oftFeeDetails',\n type: 'tuple[]',\n components: [\n { name: 'feeAmountLD', type: 'int256' },\n { name: 'description', type: 'string' },\n ],\n },\n {\n name: 'oftReceipt',\n type: 'tuple',\n components: [\n { name: 'amountSentLD', type: 'uint256' },\n { name: 'amountReceivedLD', type: 'uint256' },\n ],\n },\n ],\n stateMutability: 'view',\n },\n] as const\n\n/**\n * Minimal LZ Endpoint V2 ABI for compose queue management.\n * Used by the Stargate 2-TX flow to check compose status and execute pending composes.\n */\nexport const LZ_ENDPOINT_ABI = [\n {\n type: 'function',\n name: 'composeQueue',\n inputs: [\n { name: 'from', type: 'address' },\n { name: 'to', type: 'address' },\n { name: 'guid', type: 'bytes32' },\n { name: 'index', type: 'uint16' },\n ],\n outputs: [{ name: 'messageHash', type: 'bytes32' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'lzCompose',\n inputs: [\n { name: '_from', type: 'address' },\n { name: '_to', type: 'address' },\n { name: '_guid', type: 'bytes32' },\n { name: '_index', type: 'uint16' },\n { name: '_message', type: 'bytes' },\n { name: '_extraData', type: 'bytes' },\n ],\n outputs: [],\n stateMutability: 'payable',\n },\n] as const","import type { Address, Hash, PublicClient, WalletClient } from 'viem'\n\nexport interface VaultAddresses {\n /** Hub vault address (diamond proxy) */\n vault: Address\n /** MoreVaultsEscrow — holds locked tokens during async cross-chain flows */\n escrow?: Address\n /** OFTAdapter for vault shares (cross-chain redeem only) */\n shareOFT?: Address\n /** OFT for USDC bridging (cross-chain deposits from spoke) */\n usdcOFT?: Address\n /**\n * Expected EVM chain ID of the hub. When provided, SDK functions will\n * throw a clear WrongChainError if the walletClient is on a different chain.\n * Prevents silent failures when MetaMask is connected to the wrong network.\n */\n hubChainId?: number\n}\n\nexport interface DepositResult {\n txHash: Hash\n shares: bigint\n}\n\nexport interface RedeemResult {\n txHash: Hash\n assets: bigint\n}\n\nexport interface AsyncRequestResult {\n txHash: Hash\n /** Cross-chain request GUID to track via getRequestInfo / getFinalizationResult */\n guid: `0x${string}`\n}\n\n/**\n * ActionType enum values matching MoreVaultsLib.ActionType on-chain.\n * DEPOSIT=0, MINT=1, WITHDRAW=2, REDEEM=3, MULTI_ASSETS_DEPOSIT=4, ACCRUE_FEES=5\n */\nexport const ActionType = {\n DEPOSIT: 0,\n MINT: 1,\n WITHDRAW: 2,\n REDEEM: 3,\n MULTI_ASSETS_DEPOSIT: 4,\n ACCRUE_FEES: 5,\n} as const\n\nexport type ActionTypeValue = (typeof ActionType)[keyof typeof ActionType]\n\n/**\n * Data needed to execute a pending LZ compose on the hub chain.\n * Returned by `depositFromSpoke` when the OFT is a Stargate V2 pool,\n * because Stargate cannot forward ETH to the compose executor.\n * The SDK user must call `executeCompose()` with this data as a second TX on the hub.\n */\nexport interface ComposeData {\n /** LZ Endpoint address on the hub chain */\n endpoint: Address\n /** The OFT/pool address that sent the compose (Stargate pool on hub) */\n from: Address\n /** MoreVaultsComposer address on the hub */\n to: Address\n /** LayerZero GUID from the original OFT.send() */\n guid: `0x${string}`\n /** Compose index (always 0 for single-compose messages) */\n index: number\n /** The full compose message bytes (reconstructed from composeMsg + OFT header) */\n message: `0x${string}`\n /** Whether this is a Stargate OFT that requires a 2-TX flow */\n isStargate: boolean\n /** Hub chain ID for creating the hub wallet/public client */\n hubChainId: number\n /** Hub block number just before TX1 was sent — used as search start for ComposeSent events */\n hubBlockStart: bigint\n}\n\n/**\n * Result from `depositFromSpoke`.\n * When `composeData` is present, the user must call `executeCompose()` on the hub chain.\n */\nexport interface SpokeDepositResult {\n txHash: Hash\n guid: `0x${string}`\n /** Present when OFT is Stargate V2 — user must execute compose on hub as TX2 */\n composeData?: ComposeData\n}\n\nexport interface CrossChainRequestInfo {\n initiator: Address\n timestamp: bigint\n actionType: number\n actionCallData: `0x${string}`\n fulfilled: boolean\n finalized: boolean\n refunded: boolean\n totalAssets: bigint\n finalizationResult: bigint\n amountLimit: bigint\n}\n","/**\n * Typed error classes for the MoreVaults SDK.\n *\n * Frontend code can use instanceof checks to handle errors programmatically:\n * catch (e) {\n * if (e instanceof InsufficientLiquidityError) { ... }\n * }\n */\n\nexport class MoreVaultsError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'MoreVaultsError'\n }\n}\n\nexport class VaultPausedError extends MoreVaultsError {\n constructor(vault: string) {\n super(`[MoreVaults] Vault ${vault} is paused. Cannot perform any actions.`)\n this.name = 'VaultPausedError'\n }\n}\n\nexport class CapacityFullError extends MoreVaultsError {\n constructor(vault: string) {\n super(`[MoreVaults] Vault ${vault} has reached deposit capacity. No more deposits accepted.`)\n this.name = 'CapacityFullError'\n }\n}\n\nexport class NotWhitelistedError extends MoreVaultsError {\n constructor(vault: string, user: string) {\n super(`[MoreVaults] Address ${user} is not whitelisted to deposit in vault ${vault}.`)\n this.name = 'NotWhitelistedError'\n }\n}\n\nexport class InsufficientLiquidityError extends MoreVaultsError {\n hubLiquid: bigint\n required: bigint\n constructor(vault: string, hubLiquid: bigint, required: bigint) {\n super(\n `[MoreVaults] Insufficient hub liquidity for redeem.\\n` +\n ` Hub liquid balance : ${hubLiquid}\\n` +\n ` Estimated required : ${required}\\n` +\n `Submitting this redeem will waste the LayerZero fee — the request will be auto-refunded.\\n` +\n `Ask the vault curator to repatriate liquidity from spoke chains first.`\n )\n this.name = 'InsufficientLiquidityError'\n this.hubLiquid = hubLiquid\n this.required = required\n }\n}\n\nexport class CCManagerNotConfiguredError extends MoreVaultsError {\n constructor(vault: string) {\n super(`[MoreVaults] CCManager not configured on vault ${vault}. Call setCrossChainAccountingManager(ccManagerAddress) as vault owner first.`)\n this.name = 'CCManagerNotConfiguredError'\n }\n}\n\nexport class EscrowNotConfiguredError extends MoreVaultsError {\n constructor(vault: string) {\n super(`[MoreVaults] Escrow not configured for vault ${vault}. The registry must have an escrow set for this vault.`)\n this.name = 'EscrowNotConfiguredError'\n }\n}\n\nexport class NotHubVaultError extends MoreVaultsError {\n constructor(vault: string) {\n super(`[MoreVaults] Vault ${vault} is not a hub vault. Async flows (D4/D5/R5) only work on hub vaults.`)\n this.name = 'NotHubVaultError'\n }\n}\n\nexport class MissingEscrowAddressError extends MoreVaultsError {\n constructor() {\n super(`[MoreVaults] This flow requires an escrow address. Set VaultAddresses.escrow before calling async deposit/redeem flows.`)\n this.name = 'MissingEscrowAddressError'\n }\n}\n\nexport class WrongChainError extends MoreVaultsError {\n constructor(currentChainId: number, expectedChainId: number) {\n super(\n `Wrong network: wallet is on chain ${currentChainId}, but the vault hub requires chain ${expectedChainId}. Switch networks before proceeding.`,\n )\n this.name = 'WrongChainError'\n }\n}\n","import {\n type Address,\n type Hash,\n type PublicClient,\n type WalletClient,\n getAddress,\n zeroAddress,\n} from 'viem'\nimport { BRIDGE_ABI, CONFIG_ABI, ERC20_ABI, VAULT_ABI, METADATA_ABI } from './abis'\nimport type { CrossChainRequestInfo } from './types'\n\n// ─────────────────────────────────────────────────────────────────────────────\n// TX receipt helper with retry — public RPCs can be slow, especially on Ethereum mainnet.\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Wait for a transaction receipt with generous timeout and retry logic.\n *\n * Public RPCs often timeout before the TX is mined. This helper retries\n * `waitForTransactionReceipt` up to 3 times with increasing timeouts,\n * so the SDK doesn't crash on slow RPCs.\n */\nexport async function waitForTx(\n publicClient: PublicClient,\n hash: Hash,\n maxRetries = 3,\n): Promise<void> {\n const timeouts = [60_000, 120_000, 180_000] // 1min, 2min, 3min\n for (let i = 0; i < maxRetries; i++) {\n try {\n await publicClient.waitForTransactionReceipt({\n hash,\n timeout: timeouts[i] ?? 180_000,\n })\n return\n } catch (e: any) {\n // If it's a timeout error, retry with longer timeout\n if (e.name === 'WaitForTransactionReceiptTimeoutError' && i < maxRetries - 1) {\n continue\n }\n throw e\n }\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type VaultMode =\n | 'local' // single-chain vault, no cross-chain\n | 'cross-chain-oracle' // hub with oracle-based accounting (sync)\n | 'cross-chain-async' // hub with off-chain accounting (async, D4/D5/R5)\n | 'paused' // vault is paused\n | 'full' // deposit capacity reached\n\nexport interface VaultStatus {\n /** Vault operating mode — determines which SDK flow to use */\n mode: VaultMode\n /** Which deposit function to call given the current configuration */\n recommendedDepositFlow: 'depositSimple' | 'depositAsync' | 'mintAsync' | 'none'\n /** Which redeem function to call given the current configuration */\n recommendedRedeemFlow: 'redeemShares' | 'redeemAsync' | 'none'\n\n // ── Configuration ────────────────────────────────────────────────────────\n isHub: boolean\n isPaused: boolean\n oracleAccountingEnabled: boolean\n\n /** address(0) means CCManager is not set — async flows will fail */\n ccManager: Address\n /** address(0) means escrow is not configured in the registry */\n escrow: Address\n\n // ── Withdrawal queue ─────────────────────────────────────────────────────\n withdrawalQueueEnabled: boolean\n /** Timelock duration in seconds (0 = no timelock) */\n withdrawalTimelockSeconds: bigint\n\n // ── Capacity ─────────────────────────────────────────────────────────────\n /**\n * Remaining deposit capacity in underlying token decimals.\n * `type(uint256).max` = no cap configured (unlimited).\n * `0n` = vault is full — no more deposits accepted.\n * If `depositAccessRestricted = true`, this value is `type(uint256).max` but\n * deposits are still gated by whitelist or other access control.\n */\n remainingDepositCapacity: bigint\n /**\n * True when `maxDeposit(address(0))` reverted, indicating the vault uses\n * whitelist or other access control to restrict who can deposit.\n * Deposit flows will succeed only for addresses the vault operator has approved.\n */\n depositAccessRestricted: boolean\n\n // ── Vault metrics ────────────────────────────────────────────────────────\n underlying: Address\n totalAssets: bigint\n totalSupply: bigint\n /** Vault share token decimals. Use this for display — never hardcode 18. */\n decimals: number\n /**\n * Price of 1 full share expressed in underlying token units.\n * = convertToAssets(10^decimals). Grows over time as the vault earns yield.\n */\n sharePrice: bigint\n /**\n * Underlying token balance held directly on the hub chain.\n * This is the only portion that can be paid out to redeeming users immediately.\n * (= ERC-20.balanceOf(vault) on the hub)\n */\n hubLiquidBalance: bigint\n /**\n * Approximate value deployed to spoke chains (totalAssets − hubLiquidBalance).\n * These funds are NOT immediately redeemable — the vault curator must\n * call executeBridging to repatriate them before large redeems can succeed.\n */\n spokesDeployedBalance: bigint\n /**\n * Maximum assets that can be redeemed right now without curator intervention.\n * - For hub vaults: equals `hubLiquidBalance` (only what the hub holds).\n * - For local/oracle vaults: equals `totalAssets` (all assets are local).\n * Attempting to redeem more than this will revert (R1) or be auto-refunded (R5).\n */\n maxImmediateRedeemAssets: bigint\n\n // ── Issues — empty when everything is correctly configured ───────────────\n /**\n * Human-readable list of configuration problems that would cause transactions\n * to fail. Empty array = vault is ready to use.\n */\n issues: string[]\n}\n\n/**\n * Read the full configuration and operational status of a vault in a single\n * multicall-friendly batch.\n *\n * Use this to:\n * - Determine which SDK flow to use (`recommendedDepositFlow`)\n * - Show a configuration checklist in an admin dashboard\n * - Surface `issues` to the developer before any transaction\n *\n * @param publicClient Public client for reads\n * @param vault Vault address (diamond proxy)\n * @returns Full vault status snapshot\n *\n * @example\n * ```ts\n * const status = await getVaultStatus(publicClient, VAULT)\n * if (status.issues.length) {\n * console.warn('Vault misconfigured:', status.issues)\n * }\n * // Use recommended flow:\n * if (status.recommendedDepositFlow === 'depositAsync') {\n * await depositAsync(walletClient, publicClient, { vault: VAULT, escrow: status.escrow }, ...)\n * }\n * ```\n */\nexport async function getVaultStatus(\n publicClient: PublicClient,\n vault: Address,\n): Promise<VaultStatus> {\n const v = getAddress(vault)\n\n // ── Batch 1: single multicall — 12 reads, 1 HTTP request ─────────────────\n // maxDeposit(address(0)) may revert on whitelisted vaults — allowFailure handles it.\n const b1 = await publicClient.multicall({\n contracts: [\n { address: v, abi: CONFIG_ABI, functionName: 'isHub' },\n { address: v, abi: CONFIG_ABI, functionName: 'paused' },\n { address: v, abi: BRIDGE_ABI, functionName: 'oraclesCrossChainAccounting' },\n { address: v, abi: CONFIG_ABI, functionName: 'getCrossChainAccountingManager' },\n { address: v, abi: CONFIG_ABI, functionName: 'getEscrow' },\n { address: v, abi: CONFIG_ABI, functionName: 'getWithdrawalQueueStatus' },\n { address: v, abi: CONFIG_ABI, functionName: 'getWithdrawalTimelock' },\n { address: v, abi: CONFIG_ABI, functionName: 'maxDeposit', args: [zeroAddress] },\n { address: v, abi: VAULT_ABI, functionName: 'asset' },\n { address: v, abi: VAULT_ABI, functionName: 'totalAssets' },\n { address: v, abi: VAULT_ABI, functionName: 'totalSupply' },\n { address: v, abi: METADATA_ABI, functionName: 'decimals' },\n ] as const,\n allowFailure: true,\n })\n\n const isHub = b1[0].status === 'success' ? b1[0].result as boolean : false\n const isPaused = b1[1].status === 'success' ? b1[1].result as boolean : false\n const oraclesEnabled = b1[2].status === 'success' ? b1[2].result as boolean : false\n const ccManager = b1[3].status === 'success' ? b1[3].result as Address : zeroAddress\n const escrow = b1[4].status === 'success' ? b1[4].result as Address : zeroAddress\n const withdrawalQueueEnabled = b1[5].status === 'success' ? b1[5].result as boolean : false\n const withdrawalTimelockSeconds = b1[6].status === 'success' ? b1[6].result as bigint : 0n\n // null = reverted (whitelist/ACL), bigint = normal return\n const maxDepositRaw = b1[7].status === 'success' ? b1[7].result as bigint : null\n const underlying = b1[8].status === 'success' ? b1[8].result as Address : zeroAddress\n const totalAssets = b1[9].status === 'success' ? b1[9].result as bigint : 0n\n const totalSupply = b1[10].status === 'success' ? b1[10].result as bigint : 0n\n const decimals = b1[11].status === 'success' ? Number(b1[11].result) : 18\n\n // ── Batch 2: depends on underlying + decimals from batch 1 ────────────────\n const oneShare = 10n ** BigInt(decimals)\n const b2 = await publicClient.multicall({\n contracts: [\n { address: getAddress(underlying), abi: ERC20_ABI, functionName: 'balanceOf', args: [v] },\n { address: v, abi: VAULT_ABI, functionName: 'convertToAssets', args: [oneShare] },\n ] as const,\n allowFailure: true,\n })\n\n const hubLiquidBalance = b2[0].status === 'success' ? b2[0].result as bigint : 0n\n const sharePrice = b2[1].status === 'success' ? b2[1].result as bigint : 0n\n\n const spokesDeployedBalance = totalAssets > hubLiquidBalance ? totalAssets - hubLiquidBalance : 0n\n\n // null = maxDeposit reverted.\n // For cross-chain-async hubs this is expected — the contract reverts with\n // NotAnERC4626CompatibleVault because maxDeposit is not meaningful in async mode.\n // Only treat the revert as \"whitelist/ACL\" when the vault is NOT a hub.\n const MAX_UINT256 = BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')\n const isCrossChainAsync = isHub && !oraclesEnabled\n const depositAccessRestricted = maxDepositRaw === null && !isCrossChainAsync\n const effectiveCapacity: bigint = (maxDepositRaw === null) ? MAX_UINT256 : maxDepositRaw\n\n // ── Derive mode ────────────────────────────────────────────────────────────\n let mode: VaultMode\n if (isPaused) {\n mode = 'paused'\n } else if (effectiveCapacity === 0n) {\n mode = 'full'\n } else if (!isHub) {\n mode = 'local'\n } else if (oraclesEnabled) {\n mode = 'cross-chain-oracle'\n } else {\n mode = 'cross-chain-async'\n }\n\n // ── Recommended flows ──────────────────────────────────────────────────────\n let recommendedDepositFlow: VaultStatus['recommendedDepositFlow']\n let recommendedRedeemFlow: VaultStatus['recommendedRedeemFlow']\n\n if (mode === 'paused' || mode === 'full') {\n recommendedDepositFlow = 'none'\n recommendedRedeemFlow = mode === 'paused' ? 'none' : 'redeemShares'\n } else if (mode === 'cross-chain-async') {\n recommendedDepositFlow = 'depositAsync'\n recommendedRedeemFlow = 'redeemAsync'\n } else {\n // local or cross-chain-oracle\n recommendedDepositFlow = 'depositSimple'\n recommendedRedeemFlow = 'redeemShares'\n }\n\n // ── maxImmediateRedeemAssets ───────────────────────────────────────────────\n const maxImmediateRedeemAssets = isHub && !oraclesEnabled ? hubLiquidBalance : totalAssets\n\n // ── Issues ─────────────────────────────────────────────────────────────────\n const issues: string[] = []\n\n if (isPaused) {\n issues.push('Vault is paused — no deposits or redeems are possible.')\n }\n if (effectiveCapacity === 0n && !isPaused) {\n issues.push('Deposit capacity is full — increase depositCapacity via setDepositCapacity().')\n }\n if (depositAccessRestricted) {\n issues.push('Deposit access is restricted (whitelist or other access control). Only approved addresses can deposit.')\n }\n if (isHub && !oraclesEnabled && ccManager === zeroAddress) {\n issues.push(\n 'CCManager not configured — async flows will revert. Call setCrossChainAccountingManager(address) as vault owner.',\n )\n }\n if (isHub && !oraclesEnabled && escrow === zeroAddress) {\n issues.push(\n 'Escrow not configured in registry — async flows will revert. Set the escrow via the MoreVaultsRegistry.',\n )\n }\n if (isHub) {\n if (hubLiquidBalance === 0n) {\n issues.push(\n `Hub has no liquid assets (hubLiquidBalance = 0). All redeems will be auto-refunded until the curator repatriates funds from spokes via executeBridging().`,\n )\n } else if (totalAssets > 0n && hubLiquidBalance * 10n < totalAssets) {\n const pct = Number((hubLiquidBalance * 10000n) / totalAssets) / 100\n issues.push(\n `Low hub liquidity: ${hubLiquidBalance} units liquid on hub (${pct.toFixed(1)}% of TVL). ` +\n `Redeems above ${hubLiquidBalance} underlying units will be auto-refunded. ` +\n `Curator must call executeBridging() to repatriate from spokes.`,\n )\n }\n if (spokesDeployedBalance > 0n) {\n const pct = ((Number(spokesDeployedBalance) / Number(totalAssets || 1n)) * 100).toFixed(1)\n issues.push(\n `${spokesDeployedBalance} units (~${pct}% of TVL) are deployed on spoke chains earning yield. ` +\n `These are NOT immediately redeemable — they require a curator repatriation (executeBridging) before users can withdraw them.`,\n )\n }\n }\n\n return {\n mode,\n recommendedDepositFlow,\n recommendedRedeemFlow,\n isHub,\n isPaused,\n oracleAccountingEnabled: oraclesEnabled,\n ccManager,\n escrow,\n withdrawalQueueEnabled,\n withdrawalTimelockSeconds: BigInt(withdrawalTimelockSeconds),\n remainingDepositCapacity: effectiveCapacity,\n depositAccessRestricted,\n underlying,\n totalAssets,\n totalSupply,\n decimals,\n sharePrice,\n hubLiquidBalance,\n spokesDeployedBalance,\n maxImmediateRedeemAssets,\n issues,\n }\n}\n\n/**\n * Ensure the spender has sufficient ERC-20 allowance; approve if not.\n *\n * Checks the current allowance and only sends an approve transaction if\n * the existing allowance is less than the required amount.\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads\n * @param token ERC-20 token address\n * @param spender Address to approve\n * @param amount Minimum required allowance\n */\nexport async function ensureAllowance(\n walletClient: WalletClient,\n publicClient: PublicClient,\n token: Address,\n spender: Address,\n amount: bigint,\n): Promise<void> {\n const account = walletClient.account!\n\n const allowance = await publicClient.readContract({\n address: getAddress(token),\n abi: ERC20_ABI,\n functionName: 'allowance',\n args: [account.address, getAddress(spender)],\n })\n\n if (allowance < amount) {\n const hash = await walletClient.writeContract({\n address: getAddress(token),\n abi: ERC20_ABI,\n functionName: 'approve',\n args: [getAddress(spender), amount],\n account,\n chain: walletClient.chain,\n })\n await waitForTx(publicClient, hash)\n }\n}\n\n/**\n * Quote the LayerZero native fee required for async vault actions.\n *\n * Call this before `depositAsync`, `mintAsync`, or `redeemAsync` to get the\n * exact `lzFee` (msg.value) needed.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address (diamond proxy)\n * @param extraOptions Optional LZ extra options bytes (default 0x)\n * @returns Required native fee in wei\n */\nexport async function quoteLzFee(\n publicClient: PublicClient,\n vault: Address,\n extraOptions: `0x${string}` = '0x',\n): Promise<bigint> {\n return publicClient.readContract({\n address: getAddress(vault),\n abi: BRIDGE_ABI,\n functionName: 'quoteAccountingFee',\n args: [extraOptions],\n })\n}\n\n/**\n * Check if a vault is operating in async mode (cross-chain hub with oracle OFF).\n *\n * When this returns `true`, deposits and redeems must use the async flows\n * (D4/D5/R5) which go through `initVaultActionRequest`.\n * When `false`, the vault either uses oracle-based accounting (sync) or is\n * a single-chain vault.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @returns `true` if the vault requires async cross-chain flows\n */\nexport async function isAsyncMode(\n publicClient: PublicClient,\n vault: Address,\n): Promise<boolean> {\n const v = getAddress(vault)\n\n // A vault is async if it's a hub AND oracle accounting is OFF\n const isHub = await publicClient.readContract({\n address: v,\n abi: CONFIG_ABI,\n functionName: 'isHub',\n })\n\n if (!isHub) return false\n\n const oraclesEnabled = await publicClient.readContract({\n address: v,\n abi: BRIDGE_ABI,\n functionName: 'oraclesCrossChainAccounting',\n })\n\n return !oraclesEnabled\n}\n\n/**\n * Poll for async request completion status.\n *\n * After calling an async flow (D4/D5/R5), use this to check whether the\n * LZ callback has resolved and `executeRequest` has been called.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @param guid Request GUID returned by the async flow\n * @returns Whether the request is fulfilled and the finalization result\n */\nexport async function getAsyncRequestStatus(\n publicClient: PublicClient,\n vault: Address,\n guid: `0x${string}`,\n): Promise<{ fulfilled: boolean; finalized: boolean; result: bigint }> {\n const info = (await publicClient.readContract({\n address: getAddress(vault),\n abi: BRIDGE_ABI,\n functionName: 'getRequestInfo',\n args: [guid],\n })) as unknown as CrossChainRequestInfo\n\n const finalizationResult = await publicClient.readContract({\n address: getAddress(vault),\n abi: BRIDGE_ABI,\n functionName: 'getFinalizationResult',\n args: [guid],\n })\n\n return {\n fulfilled: info.fulfilled,\n finalized: info.finalized,\n result: finalizationResult,\n }\n}\n","import { type Address, createPublicClient, http, fallback, getAddress, zeroAddress } from 'viem'\nimport { OFT_ROUTES, CHAIN_ID_TO_EID } from './chains'\nimport { OFT_ABI, ERC20_ABI } from './abis'\nimport { getVaultTopology } from './topology'\nimport { isAsyncMode, quoteLzFee } from './utils'\n\nexport interface OutboundRoute {\n /** Chain ID where user can receive shares/assets */\n chainId: number\n /** Whether this chain is the hub (direct redeem) or a spoke (shares bridged back) */\n routeType: 'hub' | 'spoke'\n /** LZ EID for this chain */\n eid: number\n /** Native gas symbol */\n nativeSymbol: string\n}\n\n/**\n * Multiple public RPC endpoints per chain — tried in order via viem fallback transport.\n * First entry is preferred; subsequent entries are used if the first fails or times out.\n */\nconst PUBLIC_RPCS: Partial<Record<number, string[]>> = {\n 1: [\n 'https://ethereum-rpc.publicnode.com',\n 'https://ethereum.publicnode.com',\n 'https://eth.drpc.org',\n 'https://eth-mainnet.public.blastapi.io',\n 'https://0xrpc.io/eth',\n 'https://eth.llamarpc.com',\n ],\n 10: [\n 'https://mainnet.optimism.io',\n 'https://optimism-rpc.publicnode.com',\n 'https://op.drpc.org',\n ],\n 42161: [\n 'https://arbitrum-one-rpc.publicnode.com',\n 'https://arbitrum.publicnode.com',\n 'https://arbitrum.public.blockpi.network/v1/rpc/public',\n 'https://public-arb-mainnet.fastnode.io',\n ],\n 8453: [\n 'https://base-rpc.publicnode.com',\n 'https://base.llamarpc.com',\n 'https://base.drpc.org',\n 'https://mainnet.base.org',\n 'https://1rpc.io/base',\n 'https://base.rpc.subquery.network/public',\n ],\n 747: [\n 'https://mainnet.evm.nodes.onflow.org',\n ],\n 146: [\n 'https://rpc.soniclabs.com',\n 'https://sonic.drpc.org',\n ],\n 56: [\n 'https://bsc-dataseed1.binance.org',\n 'https://bsc-dataseed2.binance.org',\n 'https://bsc-rpc.publicnode.com',\n ],\n}\n\n// multicall3 is deployed at the same deterministic address on all supported chains\nconst MULTICALL3_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11' as const\n\n/** Returns a viem transport (factory) for a given chain ID, or null if not supported */\nexport function createChainTransport(chainId: number) {\n const rpcs = PUBLIC_RPCS[chainId]\n if (!rpcs?.length) return null\n return rpcs.length === 1 ? http(rpcs[0]) : fallback(rpcs.map(url => http(url)))\n}\n\n/** Create a public client with fallback transport for a given chain ID */\nexport function createChainClient(chainId: number) {\n const rpcs = PUBLIC_RPCS[chainId]\n if (!rpcs?.length) return null\n return createPublicClient({\n chain: {\n id: chainId,\n name: `chain-${chainId}`,\n nativeCurrency: { name: 'ETH', symbol: 'ETH', decimals: 18 },\n rpcUrls: { default: { http: rpcs as [string, ...string[]] } },\n contracts: { multicall3: { address: MULTICALL3_ADDRESS } },\n },\n transport: rpcs.length === 1 ? http(rpcs[0]) : fallback(rpcs.map(url => http(url))),\n })\n}\n\nconst SYMBOL_ABI = [{ name: 'symbol', type: 'function', stateMutability: 'view', inputs: [], outputs: [{ type: 'string' }] }] as const\n\n/** Read ERC20 symbol() on-chain. Falls back to `fallback` if the call fails. */\nasync function readTokenSymbol(client: ReturnType<typeof createChainClient>, token: Address, fallbackSymbol: string): Promise<string> {\n if (!client) return fallbackSymbol\n try {\n return await client.readContract({ address: token, abi: SYMBOL_ABI, functionName: 'symbol' })\n } catch {\n return fallbackSymbol\n }\n}\n\n/** @deprecated use PUBLIC_RPCS — kept for backwards compat in internal checks */\nconst PUBLIC_RPC: Partial<Record<number, string>> = Object.fromEntries(\n Object.entries(PUBLIC_RPCS).map(([k, v]) => [k, v![0]])\n)\n\n/** Native gas token symbol per chain ID — lzFeeEstimate is denominated in this token */\nexport const NATIVE_SYMBOL: Partial<Record<number, string>> = {\n 1: 'ETH',\n 10: 'ETH',\n 42161: 'ETH',\n 8453: 'ETH',\n 747: 'FLOW',\n 146: 'S',\n 56: 'BNB',\n}\n\nexport interface InboundRoute {\n /** Internal route identifier from OFT_ROUTES (e.g. 'stgUSDC') — do NOT show to users */\n symbol: string\n /** Chain ID where user sends from */\n spokeChainId: number\n /**\n * How the deposit is executed:\n * - 'direct' → user is on the hub chain, vault uses standard ERC-4626 (depositSimple). No LZ fee.\n * - 'direct-async' → user is on the hub chain, vault uses async accounting (depositAsync). LZ fee required.\n * - 'oft-compose' → user is on a spoke chain, use depositFromSpoke via OFT compose. LZ fee required.\n */\n depositType: 'direct' | 'direct-async' | 'oft-compose'\n /** OFT contract on spoke chain — pass as `spokeOFT` to depositFromSpoke. Null for direct deposits. */\n spokeOft: Address | null\n /** Token user must approve on spoke chain (zeroAddress = native ETH) */\n spokeToken: Address\n /**\n * Human-readable symbol of the token the user needs to hold on the spoke chain.\n * For OFTAdapters this is the underlying token symbol (e.g. 'USDC', 'weETH').\n * For pure OFTs this is the OFT's own symbol (e.g. 'sUSDe', 'USDe').\n * Use this — not `symbol` — when displaying the token name to users.\n */\n sourceTokenSymbol: string\n /** OFT contract on hub chain — receives tokens for the composer. Null for direct deposits. */\n hubOft: Address | null\n /** oftCmd to use in SendParam (0x01 for Stargate taxi, 0x for standard OFT) */\n oftCmd: `0x${string}`\n /** LZ fee estimate in native wei of the SPOKE chain (not always ETH — e.g. FLOW on Flow EVM) */\n lzFeeEstimate: bigint\n /** Native gas token symbol for the spoke chain — use this when displaying the fee */\n nativeSymbol: string\n}\n\nexport interface InboundRouteWithBalance extends InboundRoute {\n /** User's token balance on the spoke chain */\n userBalance: bigint\n}\n\n/**\n * Find all valid OFT inbound routes for a vault.\n *\n * Only returns routes for chains where the vault has a registered spoke —\n * this is required so the composer can send shares back to the user's chain.\n * The hub chain is always included as a 'direct' deposit option.\n *\n * Routes that revert on quoteSend() (no liquidity, no peer) are excluded.\n *\n * @param hubChainId Chain ID of the vault hub (e.g. 8453 for Base)\n * @param vault Vault address (to resolve registered spoke chains)\n * @param vaultAsset vault.asset() address on the hub chain\n * @param userAddress User address (used as receiver for fee quote)\n */\nexport async function getInboundRoutes(\n hubChainId: number,\n vault: Address,\n vaultAsset: Address,\n userAddress: Address,\n): Promise<InboundRoute[]> {\n const hubEid = CHAIN_ID_TO_EID[hubChainId]\n if (!hubEid) throw new Error(`No LZ EID for hub chainId ${hubChainId}`)\n\n // Fetch vault topology to get registered spoke chains\n const hubClient = createChainClient(hubChainId)\n if (!hubClient) throw new Error(`No public RPC for hub chainId ${hubChainId}`)\n const topology = await getVaultTopology(hubClient, vault)\n const registeredSpokes = new Set(topology.spokeChainIds)\n\n const results: InboundRoute[] = []\n\n for (const [symbol, chainMap] of Object.entries(OFT_ROUTES)) {\n const hubEntry = (chainMap as Record<number, { oft: string; token: string }>)[hubChainId]\n if (!hubEntry) continue\n\n // Does this OFT deliver the right asset to the hub?\n if (getAddress(hubEntry.token) !== getAddress(vaultAsset)) continue\n\n // oftCmd for OFT compose deposits: always '0x' (TAXI mode = immediate delivery with composeMsg).\n // Stargate V2 semantics: '0x' = TAXI (supports composeMsg), '0x01' = BUS (no composeMsg).\n // depositFromSpoke internally uses resolveOftCmd() which returns '0x' — match that here.\n const oftCmd: `0x${string}` = '0x'\n\n // Only check chains where the vault has a registered spoke\n // (composer needs to send shares back — requires a spoke vault on that chain)\n const spokesToCheck = Object.keys(chainMap)\n .map(Number)\n .filter(id => id !== hubChainId && registeredSpokes.has(id))\n\n await Promise.allSettled(\n spokesToCheck.map(async (spokeChainId) => {\n const spokeEntry = (chainMap as Record<number, { oft: string; token: string }>)[spokeChainId]\n if (!spokeEntry) return\n\n const client = createChainClient(spokeChainId)\n if (!client) return\n\n // Validate route via quoteSend — if it reverts, skip\n try {\n const receiverBytes32 = `0x${getAddress(userAddress).slice(2).padStart(64, '0')}` as `0x${string}`\n const spokeTokenAddr = getAddress(spokeEntry.token) as Address\n const [fee, sourceTokenSymbol] = await Promise.all([\n client.readContract({\n address: getAddress(spokeEntry.oft) as Address,\n abi: OFT_ABI,\n functionName: 'quoteSend',\n args: [{\n dstEid: hubEid,\n to: receiverBytes32,\n amountLD: 1_000_000n,\n minAmountLD: 0n,\n extraOptions: '0x',\n composeMsg: '0x',\n oftCmd,\n }, false],\n }),\n readTokenSymbol(client, spokeTokenAddr, symbol),\n ])\n\n results.push({\n symbol,\n spokeChainId,\n depositType: 'oft-compose',\n spokeOft: getAddress(spokeEntry.oft) as Address,\n spokeToken: spokeTokenAddr,\n sourceTokenSymbol,\n hubOft: getAddress(hubEntry.oft) as Address,\n oftCmd,\n lzFeeEstimate: fee.nativeFee,\n nativeSymbol: NATIVE_SYMBOL[spokeChainId] ?? 'ETH',\n })\n } catch {\n // Route not available — skip silently\n }\n })\n )\n }\n\n // Add the hub chain itself as a deposit option.\n // For async vaults the vault uses depositAsync which requires a LZ fee even on the hub chain.\n const [asyncMode, ...hubOftEntries] = await Promise.all([\n isAsyncMode(hubClient, vault),\n ...Object.entries(OFT_ROUTES).map(async ([symbol, chainMap]) => {\n const hubEntry = (chainMap as Record<number, { oft: string; token: string }>)[hubChainId]\n if (!hubEntry || getAddress(hubEntry.token) !== getAddress(vaultAsset)) return null\n return { symbol, hubEntry }\n }),\n ])\n\n const hubOftEntry = hubOftEntries.find((e) => e !== null) ?? null\n\n if (hubOftEntry) {\n const { symbol, hubEntry } = hubOftEntry\n const hubTokenAddr = getAddress(hubEntry.token) as Address\n const [sourceTokenSymbol, lzFeeEstimate] = await Promise.all([\n readTokenSymbol(hubClient, hubTokenAddr, symbol),\n asyncMode ? quoteLzFee(hubClient, vault) : Promise.resolve(0n),\n ])\n results.unshift({\n symbol,\n spokeChainId: hubChainId,\n depositType: asyncMode ? 'direct-async' : 'direct',\n spokeOft: null,\n spokeToken: hubTokenAddr,\n sourceTokenSymbol,\n hubOft: null,\n oftCmd: '0x',\n lzFeeEstimate,\n nativeSymbol: NATIVE_SYMBOL[hubChainId] ?? 'ETH',\n })\n }\n\n return results\n}\n\n/**\n * Fetch user token balances for each inbound route in parallel.\n * Routes with native ETH as token (zeroAddress) return the chain's ETH balance.\n */\nexport async function getUserBalancesForRoutes(\n routes: InboundRoute[],\n userAddress: Address,\n): Promise<InboundRouteWithBalance[]> {\n return Promise.all(\n routes.map(async (route) => {\n const client = createChainClient(route.spokeChainId)\n if (!client) return { ...route, userBalance: 0n }\n\n try {\n let userBalance: bigint\n\n if (route.spokeToken === zeroAddress) {\n userBalance = await client.getBalance({ address: getAddress(userAddress) as Address })\n } else {\n userBalance = await client.readContract({\n address: route.spokeToken,\n abi: ERC20_ABI,\n functionName: 'balanceOf',\n args: [getAddress(userAddress) as Address],\n })\n }\n\n return { ...route, userBalance }\n } catch {\n return { ...route, userBalance: 0n }\n }\n })\n )\n}\n\n/**\n * Find all outbound routes for a vault — chains where a user can receive\n * shares/assets when redeeming.\n *\n * The hub chain is always first (direct redeem). Spoke chains follow\n * (shares are bridged back via the composer).\n *\n * @param hubChainId Chain ID of the vault hub (e.g. 8453 for Base)\n * @param vault Vault address (to resolve registered spoke chains)\n */\nexport async function getOutboundRoutes(\n hubChainId: number,\n vault: Address,\n): Promise<OutboundRoute[]> {\n const hubEid = CHAIN_ID_TO_EID[hubChainId]\n if (!hubEid) throw new Error(`No LZ EID for hub chainId ${hubChainId}`)\n\n const hubClient = createChainClient(hubChainId)\n if (!hubClient) throw new Error(`No public RPC for hub chainId ${hubChainId}`)\n\n const topology = await getVaultTopology(hubClient, vault)\n\n const routes: OutboundRoute[] = [\n {\n chainId: hubChainId,\n routeType: 'hub',\n eid: hubEid,\n nativeSymbol: NATIVE_SYMBOL[hubChainId] ?? 'ETH',\n },\n ]\n\n for (const spokeChainId of topology.spokeChainIds) {\n const eid = CHAIN_ID_TO_EID[spokeChainId]\n if (!eid) continue\n\n routes.push({\n chainId: spokeChainId,\n routeType: 'spoke',\n eid,\n nativeSymbol: NATIVE_SYMBOL[spokeChainId] ?? 'ETH',\n })\n }\n\n return routes\n}\n\n/**\n * Quote the LayerZero native fee for a cross-chain deposit with a real amount.\n *\n * More precise than the `lzFeeEstimate` field on `InboundRoute`, which uses\n * a dummy 1 USDC amount.\n *\n * @param route An InboundRoute from `getInboundRoutes()`\n * @param hubChainId Chain ID of the vault hub (needed for LZ destination EID)\n * @param amount Real deposit amount in token decimals\n * @param userAddress User address (used as receiver for fee quote)\n * @returns Native fee in wei of the spoke chain's gas token, or 0n for direct deposits\n */\nexport async function quoteRouteDepositFee(\n route: InboundRoute,\n hubChainId: number,\n amount: bigint,\n userAddress: Address,\n): Promise<bigint> {\n if (route.depositType === 'direct') return 0n\n\n const hubEid = CHAIN_ID_TO_EID[hubChainId]\n if (!hubEid) throw new Error(`No LZ EID for hub chainId ${hubChainId}`)\n\n if (!route.spokeOft) throw new Error('Route is oft-compose but spokeOft is null')\n\n const client = createChainClient(route.spokeChainId)\n if (!client) throw new Error(`No public RPC for spoke chainId ${route.spokeChainId}`)\n\n const receiverBytes32 = `0x${getAddress(userAddress).slice(2).padStart(64, '0')}` as `0x${string}`\n const fee = await client.readContract({\n address: route.spokeOft,\n abi: OFT_ABI,\n functionName: 'quoteSend',\n args: [{\n dstEid: hubEid,\n to: receiverBytes32,\n amountLD: amount,\n minAmountLD: 0n,\n extraOptions: '0x',\n composeMsg: '0x',\n oftCmd: route.oftCmd,\n }, false],\n })\n\n return fee.nativeFee\n}\n","import { type Address, type PublicClient, getAddress } from 'viem'\nimport { EID_TO_CHAIN_ID, CHAIN_ID_TO_EID, CHAIN_IDS } from './chains'\nimport { createChainClient } from './spokeRoutes'\n\n// MoreVaults OMNI factory — same address on every supported chain (CREATE3)\nexport const OMNI_FACTORY_ADDRESS: Address = '0x7bDB8B17604b03125eFAED33cA0c55FBf856BB0C'\n\nconst FACTORY_ABI = [\n {\n name: 'localEid',\n type: 'function',\n inputs: [],\n outputs: [{ type: 'uint32' }],\n stateMutability: 'view',\n },\n {\n name: 'isCrossChainVault',\n type: 'function',\n inputs: [{ name: '__eid', type: 'uint32' }, { name: '_vault', type: 'address' }],\n outputs: [{ type: 'bool' }],\n stateMutability: 'view',\n },\n {\n name: 'hubToSpokes',\n type: 'function',\n inputs: [{ name: '__eid', type: 'uint32' }, { name: '_hubVault', type: 'address' }],\n outputs: [{ name: 'eids', type: 'uint32[]' }, { name: 'vaults', type: 'address[]' }],\n stateMutability: 'view',\n },\n {\n name: 'spokeToHub',\n type: 'function',\n inputs: [{ name: '__eid', type: 'uint32' }, { name: '_spokeVault', type: 'address' }],\n outputs: [{ name: 'eid', type: 'uint32' }, { name: 'vault', type: 'address' }],\n stateMutability: 'view',\n },\n] as const\n\nexport interface VaultTopology {\n /**\n * Role of this vault on the chain you queried:\n * - 'hub' → this chain holds the TVL, users deposit here\n * - 'spoke' → this chain is a yield deployment; deposits go to the hub\n * - 'local' → single-chain vault, no cross-chain setup\n */\n role: 'hub' | 'spoke' | 'local'\n\n /** Chain ID where the hub lives. Same as the queried chain when role='hub'. */\n hubChainId: number\n\n /**\n * All spoke chain IDs registered under this hub.\n * Empty when role='local'.\n * Since vaults are CREATE3-deployed, the vault address is the same on all chains.\n */\n spokeChainIds: number[]\n}\n\n/**\n * Resolve the cross-chain topology of a vault: hub chain + all spoke chains.\n *\n * Works for hub vaults, spoke vaults, and local (single-chain) vaults.\n * Because MoreVaults uses CREATE3, the vault address is identical on every chain —\n * only the chain IDs differ.\n *\n * @param publicClient Connected to the chain you want to inspect\n * @param vault Vault address (same on all chains)\n * @param factoryAddress MoreVaults factory (defaults to the known OMNI_FACTORY_ADDRESS)\n *\n * @example\n * // Querying from Base — will detect hub + Ethereum/Arbitrum spokes\n * const topo = await getVaultTopology(baseClient, '0x8f740...')\n * // { role: 'hub', hubChainId: 8453, spokeChainIds: [1, 42161] }\n *\n * // Querying from Ethereum — same vault is a spoke there\n * const topo = await getVaultTopology(ethClient, '0x8f740...')\n * // { role: 'spoke', hubChainId: 8453, spokeChainIds: [1, 42161] }\n */\nexport async function getVaultTopology(\n publicClient: PublicClient,\n vault: Address,\n factoryAddress: Address = OMNI_FACTORY_ADDRESS,\n): Promise<VaultTopology> {\n const v = getAddress(vault)\n const f = getAddress(factoryAddress)\n\n // Get local EID from the factory on the queried chain\n const localEid = await publicClient.readContract({\n address: f,\n abi: FACTORY_ABI,\n functionName: 'localEid',\n })\n\n // Check if this vault is a hub on the current chain\n const isHub = await publicClient.readContract({\n address: f,\n abi: FACTORY_ABI,\n functionName: 'isCrossChainVault',\n args: [localEid, v],\n })\n\n if (isHub) {\n // Hub: get all registered spokes\n const [spokeEids] = await publicClient.readContract({\n address: f,\n abi: FACTORY_ABI,\n functionName: 'hubToSpokes',\n args: [localEid, v],\n })\n\n const localChainId = EID_TO_CHAIN_ID[localEid] ?? Number(publicClient.chain?.id ?? 0)\n const spokeChainIds = (spokeEids as readonly number[])\n .map(eid => EID_TO_CHAIN_ID[eid])\n .filter((id): id is number => id !== undefined)\n\n return { role: 'hub', hubChainId: localChainId, spokeChainIds }\n }\n\n // Check if this vault is a spoke on the current chain\n const [hubEid, hubVault] = await publicClient.readContract({\n address: f,\n abi: FACTORY_ABI,\n functionName: 'spokeToHub',\n args: [localEid, v],\n })\n\n if (hubEid !== 0 && hubVault !== '0x0000000000000000000000000000000000000000') {\n // Spoke: resolve hub chain + get all siblings from hub's factory\n const hubChainId = EID_TO_CHAIN_ID[hubEid] ?? 0\n\n // We only have the current chain's client — return what we know\n // The hub's full spoke list requires a separate client for the hub chain\n // (callers can pass a hub-chain client to get the full picture)\n const spokeChainIds: number[] = []\n\n // If we happen to know the hub EID mapping, include local chain as a spoke\n const localChainId = EID_TO_CHAIN_ID[localEid]\n if (localChainId !== undefined) spokeChainIds.push(localChainId)\n\n return { role: 'spoke', hubChainId, spokeChainIds }\n }\n\n // Local vault — no cross-chain setup\n const localChainId = EID_TO_CHAIN_ID[localEid] ?? Number(publicClient.chain?.id ?? 0)\n return { role: 'local', hubChainId: localChainId, spokeChainIds: [] }\n}\n\n/**\n * Resolve the FULL topology of a vault by querying the hub chain directly.\n *\n * Provide a publicClient connected to the hub chain for complete spoke data.\n * If you don't know which chain is the hub, call `getVaultTopology` first\n * from any chain and use the returned `hubChainId` to create the hub client.\n *\n * @param hubChainClient Public client connected to the hub chain\n * @param vault Vault address\n * @param factoryAddress MoreVaults factory (defaults to OMNI_FACTORY_ADDRESS)\n */\nexport async function getFullVaultTopology(\n hubChainClient: PublicClient,\n vault: Address,\n factoryAddress: Address = OMNI_FACTORY_ADDRESS,\n): Promise<VaultTopology> {\n const topo = await getVaultTopology(hubChainClient, vault, factoryAddress)\n if (topo.role !== 'hub') {\n throw new Error(\n `getFullVaultTopology: client must be connected to the hub chain (${topo.hubChainId}), ` +\n `but got role=\"${topo.role}\". Connect to chainId ${topo.hubChainId} instead.`,\n )\n }\n return topo\n}\n\n/** All mainnet chain IDs where the OMNI_FACTORY is deployed */\nconst DISCOVERY_CHAIN_IDS = Object.values(CHAIN_IDS).filter(\n id => id !== 545, // exclude testnet\n) as number[]\n\n/**\n * Discover a vault's topology across all supported chains.\n *\n * Unlike `getVaultTopology` (which queries a single chain), this function\n * automatically iterates all supported chains when the initial query returns\n * `role: \"local\"`. This handles the case where the caller doesn't know which\n * chain the vault is deployed on, or when no wallet is connected.\n *\n * If a `publicClient` is provided, it's tried first. If that returns \"local\",\n * every other supported chain is probed via `createChainClient` (public RPCs).\n * If no `publicClient` is provided, all chains are probed.\n *\n * Once a hub is found, `getFullVaultTopology` is called to get the complete\n * spoke list.\n *\n * @param vault Vault address (same on all chains via CREATE3)\n * @param publicClient Optional — client for the \"preferred\" chain to try first\n * @param factoryAddress MoreVaults factory (defaults to OMNI_FACTORY_ADDRESS)\n *\n * @example\n * // No wallet connected — discovers that 0x8f74... is hub on Base\n * const topo = await discoverVaultTopology('0x8f740...')\n * // { role: 'hub', hubChainId: 8453, spokeChainIds: [1, 42161] }\n */\nexport async function discoverVaultTopology(\n vault: Address,\n publicClient?: PublicClient | null,\n factoryAddress: Address = OMNI_FACTORY_ADDRESS,\n): Promise<VaultTopology> {\n const v = getAddress(vault)\n\n // 1. Try the provided client first (fast path — avoids extra RPC calls)\n let triedChainId: number | undefined\n if (publicClient) {\n try {\n const topo = await getVaultTopology(publicClient, v, factoryAddress)\n if (topo.role !== 'local') {\n // Found hub or spoke — if spoke, resolve full topology from hub\n if (topo.role === 'spoke') {\n const hubClient = createChainClient(topo.hubChainId)\n if (hubClient) {\n try {\n return await getFullVaultTopology(hubClient, v, factoryAddress)\n } catch { /* fall through to return partial */ }\n }\n }\n return topo\n }\n triedChainId = publicClient.chain?.id\n } catch { /* client failed — continue with discovery */ }\n }\n\n // 2. Iterate all supported chains\n for (const chainId of DISCOVERY_CHAIN_IDS) {\n if (chainId === triedChainId) continue\n const client = createChainClient(chainId)\n if (!client) continue\n\n try {\n const topo = await getVaultTopology(client, v, factoryAddress)\n if (topo.role === 'hub') return topo\n if (topo.role === 'spoke') {\n // Found spoke — get full topology from hub\n const hubClient = createChainClient(topo.hubChainId)\n if (hubClient) {\n try {\n return await getFullVaultTopology(hubClient, v, factoryAddress)\n } catch { return topo }\n }\n return topo\n }\n } catch { /* this chain doesn't have the factory or vault — skip */ }\n }\n\n // 3. Not found on any chain — return local with chainId 0\n return { role: 'local', hubChainId: 0, spokeChainIds: [] }\n}\n\n/**\n * Check if a wallet is connected to the hub chain for a given vault.\n * Useful for showing a \"Switch to Base\" prompt before deposit.\n *\n * @param currentChainId Chain ID the wallet is currently connected to\n * @param topology Result of getVaultTopology\n */\nexport function isOnHubChain(currentChainId: number, topology: VaultTopology): boolean {\n return currentChainId === topology.hubChainId\n}\n\n/**\n * Get all chain IDs where this vault is deployed (hub + all spokes).\n */\nexport function getAllVaultChainIds(topology: VaultTopology): number[] {\n return [topology.hubChainId, ...topology.spokeChainIds]\n}\n","/**\n * Pre-flight validation helpers for MoreVaults SDK flows.\n *\n * Each function reads on-chain state and throws a descriptive error BEFORE\n * the actual contract call, so developers see a clear, actionable message\n * instead of a raw VM revert.\n */\n\nimport { type Address, type PublicClient, getAddress, zeroAddress } from 'viem'\nimport { CONFIG_ABI, BRIDGE_ABI, VAULT_ABI, ERC20_ABI, OFT_ABI } from './abis'\nimport { InsufficientLiquidityError } from './errors'\nimport { quoteComposeFee } from './crossChainFlows'\nimport { createChainClient } from './spokeRoutes'\nimport { EID_TO_CHAIN_ID, OFT_ROUTES } from './chains'\n\n/**\n * Pre-flight checks for async cross-chain flows (D4 / D5 / R5).\n *\n * Validates that:\n * 1. The CCManager is configured on the vault.\n * 2. An escrow is registered in the vault's registry.\n * 3. The vault is a hub (required for async flows).\n * 4. The vault does NOT have oracle-based cross-chain accounting enabled\n * (oracle-on vaults should use depositSimple / depositCrossChainOracleOn).\n * 5. The vault is not paused.\n *\n * All reads that are independent of each other are executed in parallel via\n * Promise.all to minimise latency.\n *\n * @param publicClient Public client for contract reads\n * @param vault Vault address (diamond proxy)\n * @param escrow Escrow address from VaultAddresses\n */\nexport async function preflightAsync(\n publicClient: PublicClient,\n vault: Address,\n escrow: Address,\n): Promise<void> {\n const v = getAddress(vault)\n\n // Parallel read: ccManager, escrow, isHub, oraclesCrossChainAccounting, paused\n const [ccManager, registeredEscrow, isHub, oraclesEnabled, isPaused] =\n await Promise.all([\n publicClient.readContract({\n address: v,\n abi: CONFIG_ABI,\n functionName: 'getCrossChainAccountingManager',\n }),\n publicClient.readContract({\n address: v,\n abi: CONFIG_ABI,\n functionName: 'getEscrow',\n }),\n publicClient.readContract({\n address: v,\n abi: CONFIG_ABI,\n functionName: 'isHub',\n }),\n publicClient.readContract({\n address: v,\n abi: BRIDGE_ABI,\n functionName: 'oraclesCrossChainAccounting',\n }),\n publicClient.readContract({\n address: v,\n abi: CONFIG_ABI,\n functionName: 'paused',\n }),\n ])\n\n if (ccManager === zeroAddress) {\n throw new Error(\n `[MoreVaults] CCManager not configured on vault ${vault}. Call setCrossChainAccountingManager(ccManagerAddress) as vault owner first.`,\n )\n }\n\n if (registeredEscrow === zeroAddress) {\n throw new Error(\n `[MoreVaults] Escrow not configured for vault ${vault}. The registry must have an escrow set for this vault.`,\n )\n }\n\n if (!isHub) {\n throw new Error(\n `[MoreVaults] Vault ${vault} is not a hub vault. Async flows (D4/D5/R5) only work on hub vaults.`,\n )\n }\n\n if (oraclesEnabled) {\n throw new Error(\n `[MoreVaults] Vault ${vault} has oracle-based cross-chain accounting enabled. Use depositSimple/depositCrossChainOracleOn instead of async flows.`,\n )\n }\n\n if (isPaused) {\n throw new Error(\n `[MoreVaults] Vault ${vault} is paused. Cannot perform any actions.`,\n )\n }\n}\n\n/**\n * Pre-flight liquidity check for async redeem (R5).\n *\n * Reads the hub's liquid balance of the underlying token and compares it\n * against the assets the user expects to receive. If the hub does not hold\n * enough liquid assets the redeem will be auto-refunded after the LZ round-trip,\n * wasting the LayerZero fee.\n *\n * Uses `convertToAssets` (not `previewRedeem`) because async cross-chain vaults\n * disable direct redeem and revert on `previewRedeem` by design.\n *\n * This check is best-effort: liquidity could change in the 1-5 minutes between\n * submission and execution. But it catches the common case where the hub is\n * already under-funded at the time of submission.\n *\n * @param publicClient Public client for contract reads\n * @param vault Vault address (diamond proxy)\n * @param shares Shares the user intends to redeem\n */\nexport async function preflightRedeemLiquidity(\n publicClient: PublicClient,\n vault: Address,\n shares: bigint,\n): Promise<void> {\n const v = getAddress(vault)\n\n // Batch 1: check if this is a hub vault without oracle accounting.\n // Only those vaults can have liquidity stranded on spoke chains.\n const [isHub, oraclesEnabled] = await Promise.all([\n publicClient.readContract({\n address: v,\n abi: CONFIG_ABI,\n functionName: 'isHub',\n }),\n publicClient.readContract({\n address: v,\n abi: BRIDGE_ABI,\n functionName: 'oraclesCrossChainAccounting',\n }),\n ])\n\n // Non-hub vaults and oracle-on hubs hold all redeemable assets locally —\n // no liquidity gap is possible, so skip the check.\n if (!isHub || oraclesEnabled) return\n\n // Batch 2: underlying address (needed for ERC-20 balanceOf)\n const underlying = await publicClient.readContract({\n address: v,\n abi: VAULT_ABI,\n functionName: 'asset',\n })\n\n // Batch 3: hub liquid balance + convertToAssets\n // NOTE: previewRedeem reverts on async cross-chain vaults (disabled by design).\n // convertToAssets is always safe and gives a correct lower-bound estimate.\n const [hubLiquid, assetsNeeded] = await Promise.all([\n publicClient.readContract({\n address: getAddress(underlying as Address),\n abi: ERC20_ABI,\n functionName: 'balanceOf',\n args: [v],\n }),\n publicClient.readContract({\n address: v,\n abi: VAULT_ABI,\n functionName: 'convertToAssets',\n args: [shares],\n }),\n ])\n\n const hubLiquidBig = hubLiquid as bigint\n const assetsNeededBig = assetsNeeded as bigint\n\n if (hubLiquidBig < assetsNeededBig) {\n throw new InsufficientLiquidityError(vault, hubLiquidBig, assetsNeededBig)\n }\n}\n\n/**\n * Pre-flight checks for synchronous deposit flows (D1 / D3).\n *\n * Validates that:\n * 1. The vault is not paused.\n * 2. The vault still has deposit capacity (maxDeposit > 0).\n *\n * Both reads are executed in parallel.\n *\n * @param publicClient Public client for contract reads\n * @param vault Vault address (diamond proxy)\n */\nexport async function preflightSync(\n publicClient: PublicClient,\n vault: Address,\n): Promise<void> {\n const v = getAddress(vault)\n\n // Run paused and maxDeposit in parallel.\n // maxDeposit(address(0)) may REVERT on whitelisted vaults — catch separately.\n const [isPaused, depositCapResult] = await Promise.all([\n publicClient.readContract({\n address: v,\n abi: CONFIG_ABI,\n functionName: 'paused',\n }),\n publicClient\n .readContract({\n address: v,\n abi: CONFIG_ABI,\n functionName: 'maxDeposit',\n args: [zeroAddress],\n })\n .catch(() => null as null),\n ])\n\n if (isPaused) {\n throw new Error(\n `[MoreVaults] Vault ${vault} is paused. Cannot perform any actions.`,\n )\n }\n\n // null means maxDeposit reverted → whitelist vault — skip capacity check\n // (the user may still be whitelisted; canDeposit will do user-specific check)\n if (depositCapResult !== null && depositCapResult === 0n) {\n throw new Error(\n `[MoreVaults] Vault ${vault} has reached deposit capacity. No more deposits accepted.`,\n )\n }\n}\n\n/**\n * Pre-flight checks for spoke-to-hub deposits (D6 / D7 via OFT Compose).\n *\n * Validates that:\n * 1. User has enough tokens on the spoke chain to deposit.\n * 2. User has enough native gas on the spoke chain for TX1 (OFT.send).\n * 3. For Stargate OFTs (2-TX flow): user has enough ETH on the hub chain\n * for TX2 (compose retry). This prevents sending TX1 only to get stuck\n * because there's no ETH on the hub for TX2.\n *\n * @param spokePublicClient Public client on the SPOKE chain\n * @param vault Vault address\n * @param spokeOFT OFT contract address on the spoke chain\n * @param hubEid LZ EID for the hub chain\n * @param spokeEid LZ EID for the spoke chain\n * @param amount Amount of tokens to deposit\n * @param userAddress User's wallet address\n * @param lzFee LZ fee for TX1 (from quoteDepositFromSpokeFee)\n * @returns Object with validated balances for UI display\n */\nexport async function preflightSpokeDeposit(\n spokePublicClient: PublicClient,\n vault: Address,\n spokeOFT: Address,\n hubEid: number,\n spokeEid: number,\n amount: bigint,\n userAddress: Address,\n lzFee: bigint,\n): Promise<{\n spokeTokenBalance: bigint\n spokeNativeBalance: bigint\n hubNativeBalance: bigint\n estimatedComposeFee: bigint\n isStargate: boolean\n}> {\n const oft = getAddress(spokeOFT)\n\n // Read the underlying token address from the OFT\n const spokeToken = await spokePublicClient.readContract({\n address: oft,\n abi: OFT_ABI,\n functionName: 'token',\n })\n\n // Check token balance + native balance on spoke in parallel\n const [spokeTokenBalance, spokeNativeBalance] = await Promise.all([\n spokePublicClient.readContract({\n address: spokeToken,\n abi: ERC20_ABI,\n functionName: 'balanceOf',\n args: [getAddress(userAddress)],\n }),\n spokePublicClient.getBalance({ address: getAddress(userAddress) }),\n ])\n\n // 1. Check token balance\n if (spokeTokenBalance < amount) {\n throw new Error(\n `[MoreVaults] Insufficient token balance on spoke chain.\\n` +\n ` Need: ${amount}\\n` +\n ` Have: ${spokeTokenBalance}\\n` +\n ` Token: ${spokeToken}`,\n )\n }\n\n // 2. Check native gas for TX1 (lzFee + gas buffer)\n const gasBuffer = 500_000_000_000_000n // 0.0005 ETH for gas\n if (spokeNativeBalance < lzFee + gasBuffer) {\n throw new Error(\n `[MoreVaults] Insufficient native gas on spoke chain for TX1.\\n` +\n ` Need: ~${lzFee + gasBuffer} wei (LZ fee + gas)\\n` +\n ` Have: ${spokeNativeBalance} wei`,\n )\n }\n\n // 3. For Stargate OFTs: check ETH on hub for TX2 (compose retry)\n const STARGATE_ASSETS = new Set(['stgUSDC', 'USDT', 'WETH'])\n let isStargate = false\n for (const [symbol, chainMap] of Object.entries(OFT_ROUTES)) {\n if (!STARGATE_ASSETS.has(symbol)) continue\n for (const entry of Object.values(chainMap as Record<number, { oft: string; token: string }>)) {\n if (getAddress(entry.oft) === oft) isStargate = true\n }\n }\n\n let hubNativeBalance = 0n\n let estimatedComposeFee = 0n\n\n if (isStargate) {\n const hubChainId = EID_TO_CHAIN_ID[hubEid]\n const hubClient = createChainClient(hubChainId)\n if (hubClient) {\n [hubNativeBalance, estimatedComposeFee] = await Promise.all([\n hubClient.getBalance({ address: getAddress(userAddress) }),\n quoteComposeFee(hubClient, vault, spokeEid, userAddress),\n ])\n\n const hubGasBuffer = 300_000_000_000_000n // 0.0003 ETH for gas\n const totalNeeded = estimatedComposeFee + hubGasBuffer\n\n if (hubNativeBalance < totalNeeded) {\n throw new Error(\n `[MoreVaults] Insufficient ETH on hub chain for TX2 (compose retry).\\n` +\n ` This is a Stargate 2-TX flow — TX2 requires ETH on the hub chain.\\n` +\n ` Need: ~${totalNeeded} wei (compose fee ${estimatedComposeFee} + gas)\\n` +\n ` Have: ${hubNativeBalance} wei\\n` +\n ` Short: ${totalNeeded - hubNativeBalance} wei\\n` +\n ` Send ETH to ${userAddress} on chainId ${hubChainId} before depositing.`,\n )\n }\n }\n }\n\n return {\n spokeTokenBalance,\n spokeNativeBalance,\n hubNativeBalance,\n estimatedComposeFee,\n isStargate,\n }\n}\n\n/**\n * Pre-flight checks for spoke→hub→spoke redeem (R6 + R1 + R7).\n *\n * Validates that:\n * 1. User has shares on the spoke chain.\n * 2. User has enough native gas on the spoke for TX1 (share bridge LZ fee + gas).\n * 3. User has enough native gas on the hub for TX2 (redeem gas) + TX3 (asset bridge LZ fee + gas).\n * 4. The vault has enough liquid assets on the hub to redeem.\n *\n * @param route SpokeRedeemRoute from resolveRedeemAddresses\n * @param shares Shares the user intends to redeem\n * @param userAddress User's wallet address\n * @param shareBridgeFee LZ fee for share bridge (TX1) — from quoteSend on spoke SHARE_OFT\n * @returns Validated balances for UI display\n */\nexport async function preflightSpokeRedeem(\n route: {\n hubChainId: number\n spokeChainId: number\n hubEid: number\n spokeEid: number\n hubAsset: `0x${string}`\n spokeShareOft: `0x${string}`\n hubAssetOft: `0x${string}`\n spokeAsset: `0x${string}`\n isStargate: boolean\n },\n shares: bigint,\n userAddress: `0x${string}`,\n shareBridgeFee: bigint,\n): Promise<{\n sharesOnSpoke: bigint\n spokeNativeBalance: bigint\n hubNativeBalance: bigint\n estimatedAssetBridgeFee: bigint\n estimatedAssetsOut: bigint\n hubLiquidBalance: bigint\n}> {\n const spokeClient = createChainClient(route.spokeChainId)\n const hubClient = createChainClient(route.hubChainId)\n if (!spokeClient) throw new Error(`No public RPC for spoke chainId ${route.spokeChainId}`)\n if (!hubClient) throw new Error(`No public RPC for hub chainId ${route.hubChainId}`)\n\n const user = getAddress(userAddress)\n const vault = getAddress(route.hubAsset) // vault address is same on all chains\n\n // Parallel reads: shares on spoke, native balances, vault data on hub\n const [sharesOnSpoke, spokeNativeBalance, hubNativeBalance] = await Promise.all([\n spokeClient.readContract({\n address: route.spokeShareOft,\n abi: ERC20_ABI,\n functionName: 'balanceOf',\n args: [user],\n }),\n spokeClient.getBalance({ address: user }),\n hubClient.getBalance({ address: user }),\n ])\n\n // 1. Check shares\n if (sharesOnSpoke < shares) {\n throw new Error(\n `[MoreVaults] Insufficient shares on spoke chain.\\n` +\n ` Need: ${shares}\\n` +\n ` Have: ${sharesOnSpoke}\\n` +\n ` Token: ${route.spokeShareOft}`,\n )\n }\n\n // 2. Check spoke gas for TX1\n const spokeGasBuffer = 500_000_000_000_000n // 0.0005 ETH\n if (spokeNativeBalance < shareBridgeFee + spokeGasBuffer) {\n throw new Error(\n `[MoreVaults] Insufficient native gas on spoke for TX1 (share bridge).\\n` +\n ` Need: ~${shareBridgeFee + spokeGasBuffer} wei (LZ fee + gas)\\n` +\n ` Have: ${spokeNativeBalance} wei`,\n )\n }\n\n // 3. Estimate asset bridge fee (TX3) and check hub gas\n // Quote Stargate/OFT fee for bridging assets back to spoke\n // Use convertToAssets estimate for quoting\n let estimatedAssetsOut = 0n\n let estimatedAssetBridgeFee = 0n\n let hubLiquidBalance = 0n\n\n // Read vault data on hub — need the actual vault address (not hub asset)\n // The vault address is same as route but we need it from the calling context\n // For now, read convertToAssets using the share token which IS the vault for ERC-4626\n // Actually we need the vault address. The hubAsset is the underlying token, not the vault.\n // We can get vault address by checking what contract the shares are from.\n // In MoreVaults, share OFT on hub wraps the vault token. Let's read token() from hub share OFT.\n\n // Get vault address from hub: the SHARE_OFT.token() on hub = vault address\n // But we have hubAssetOft which is Stargate pool, not share OFT.\n // Instead, read from the spoke SHARE_OFT's peer on hub.\n // Actually, for preflightSpokeRedeem we need the vault address passed in.\n // Let me simplify — estimate the LZ fee with a dummy amount.\n\n try {\n const toBytes32 = `0x${user.slice(2).padStart(64, '0')}` as `0x${string}`\n const dummyAmount = 1_000_000n // 1 USDC for fee estimation\n const feeResult = await hubClient.readContract({\n address: route.hubAssetOft,\n abi: OFT_ABI,\n functionName: 'quoteSend',\n args: [{\n dstEid: route.spokeEid,\n to: toBytes32,\n amountLD: dummyAmount,\n minAmountLD: dummyAmount * 99n / 100n,\n extraOptions: '0x' as `0x${string}`,\n composeMsg: '0x' as `0x${string}`,\n oftCmd: (route.isStargate ? '0x01' : '0x') as `0x${string}`,\n }, false],\n })\n estimatedAssetBridgeFee = feeResult.nativeFee\n } catch {\n // Can't quote — use conservative estimate\n estimatedAssetBridgeFee = 300_000_000_000_000n // 0.0003 ETH fallback\n }\n\n // Hub needs: TX2 gas (~0.0002 ETH) + TX3 LZ fee + TX3 gas (~0.0001 ETH)\n const hubGasBuffer = 300_000_000_000_000n // 0.0003 ETH for gas (TX2 + TX3)\n const totalHubNeeded = estimatedAssetBridgeFee + hubGasBuffer\n\n if (hubNativeBalance < totalHubNeeded) {\n throw new Error(\n `[MoreVaults] Insufficient ETH on hub chain for TX2 (redeem) + TX3 (asset bridge).\\n` +\n ` Need: ~${totalHubNeeded} wei (LZ fee ${estimatedAssetBridgeFee} + gas)\\n` +\n ` Have: ${hubNativeBalance} wei\\n` +\n ` Short: ${totalHubNeeded - hubNativeBalance} wei\\n` +\n ` Send ETH to ${userAddress} on chainId ${route.hubChainId} before redeeming.`,\n )\n }\n\n return {\n sharesOnSpoke,\n spokeNativeBalance,\n hubNativeBalance,\n estimatedAssetBridgeFee,\n estimatedAssetsOut,\n hubLiquidBalance,\n }\n}\n","import type { WalletClient } from 'viem'\nimport { WrongChainError } from './errors'\n\n/**\n * Validate that the walletClient is connected to the expected chain.\n * Only validates if hubChainId is provided — opt-in, non-breaking.\n */\nexport function validateWalletChain(walletClient: WalletClient, hubChainId?: number): void {\n if (!hubChainId) return\n const current = walletClient.chain?.id\n if (current !== undefined && current !== hubChainId) {\n throw new WrongChainError(current, hubChainId)\n }\n}\n","import {\n type Address,\n type PublicClient,\n type WalletClient,\n encodeAbiParameters,\n getAddress,\n zeroAddress,\n} from 'viem'\nimport { VAULT_ABI, BRIDGE_ABI, ERC20_ABI, CONFIG_ABI } from './abis'\nimport type {\n VaultAddresses,\n DepositResult,\n AsyncRequestResult,\n} from './types'\nimport { ActionType } from './types'\nimport { ensureAllowance, getVaultStatus, quoteLzFee } from './utils'\nimport { preflightSync, preflightAsync } from './preflight'\nimport { EscrowNotConfiguredError, VaultPausedError, CapacityFullError } from './errors'\nimport { validateWalletChain } from './chainValidation'\n\n/**\n * D1 / D3 — Simple deposit (ERC-4626 standard).\n *\n * Works for both local vaults and cross-chain hubs with oracle accounting ON.\n * When oracle accounting is enabled the cross-chain accounting is transparent\n * to the caller — the vault resolves totalAssets synchronously.\n *\n * **User transactions**: 1 approve (skipped if allowance sufficient) + 1 deposit.\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads and simulation\n * @param addresses Vault address set (only `vault` is used)\n * @param assets Amount of underlying token to deposit (in token decimals)\n * @param receiver Address that will receive the minted vault shares\n * @returns Transaction hash and amount of shares minted\n */\nexport async function depositSimple(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n assets: bigint,\n receiver: Address,\n): Promise<DepositResult> {\n const account = walletClient.account!\n const vault = getAddress(addresses.vault)\n\n // Validate wallet is on the correct chain (opt-in via hubChainId)\n validateWalletChain(walletClient, addresses.hubChainId)\n\n // Pre-flight: validate vault is operational and accepting deposits\n await preflightSync(publicClient, vault)\n\n // Resolve underlying asset\n const underlying = await publicClient.readContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'asset',\n })\n\n // Approve vault if needed\n await ensureAllowance(walletClient, publicClient, underlying, vault, assets)\n\n // Simulate then send\n const { result: shares } = await publicClient.simulateContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'deposit',\n args: [assets, getAddress(receiver)],\n account: account.address,\n })\n\n const txHash = await walletClient.writeContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'deposit',\n args: [assets, getAddress(receiver)],\n account,\n chain: walletClient.chain,\n })\n\n return { txHash, shares }\n}\n\n/**\n * Alias: D3 — Cross-chain hub deposit when oracle accounting is ON.\n * Exactly the same UX as depositSimple because the vault resolves accounting synchronously.\n */\nexport { depositSimple as depositCrossChainOracleOn }\n\n/**\n * D2 — Multi-asset deposit.\n *\n * Deposits multiple ERC-20 tokens into the vault in a single vault call.\n * The vault converts each token to the underlying via oracle pricing.\n *\n * **User transactions**: N approves (one per token, skipped if sufficient) + 1 deposit.\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads and simulation\n * @param addresses Vault address set (only `vault` is used)\n * @param tokens Array of token addresses to deposit\n * @param amounts Array of amounts (one per token, in each token's decimals)\n * @param receiver Address that will receive the minted vault shares\n * @param minShares Minimum shares to accept (slippage protection)\n * @returns Transaction hash and amount of shares minted\n */\nexport async function depositMultiAsset(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n tokens: Address[],\n amounts: bigint[],\n receiver: Address,\n minShares: bigint,\n): Promise<DepositResult> {\n const account = walletClient.account!\n const vault = getAddress(addresses.vault)\n\n // Validate wallet is on the correct chain (opt-in via hubChainId)\n validateWalletChain(walletClient, addresses.hubChainId)\n\n // Approve each token\n for (let i = 0; i < tokens.length; i++) {\n await ensureAllowance(walletClient, publicClient, tokens[i], vault, amounts[i])\n }\n\n const { result: shares } = await publicClient.simulateContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'deposit',\n args: [tokens, amounts, getAddress(receiver), minShares],\n account: account.address,\n })\n\n const txHash = await walletClient.writeContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'deposit',\n args: [tokens, amounts, getAddress(receiver), minShares],\n account,\n chain: walletClient.chain,\n })\n\n return { txHash, shares }\n}\n\n/**\n * D4 — Async deposit (cross-chain hub, oracle OFF).\n *\n * Sends assets to the escrow and initiates a cross-chain accounting request via\n * `initVaultActionRequest(DEPOSIT, ...)`. The LZ Read callback will resolve\n * accounting and `executeRequest` will mint shares.\n *\n * **User transactions**: 1 approve (to ESCROW, not vault!) + 1 initVaultActionRequest.\n * **Wait**: Shares arrive after the LZ callback + executeRequest (automated by keeper).\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads and simulation\n * @param addresses Vault address set (`vault` + `escrow` required)\n * @param assets Amount of underlying to deposit\n * @param receiver Address that will receive shares after resolution\n * @param lzFee msg.value for LZ Read fee (quote first with `quoteLzFee`)\n * @param extraOptions Optional LZ extra options bytes (default 0x)\n * @returns Transaction hash and GUID for tracking\n */\nexport async function depositAsync(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n assets: bigint,\n receiver: Address,\n lzFee: bigint,\n extraOptions: `0x${string}` = '0x',\n): Promise<AsyncRequestResult> {\n const account = walletClient.account!\n const vault = getAddress(addresses.vault)\n const escrow = addresses.escrow\n ? getAddress(addresses.escrow)\n : await publicClient.readContract({ address: vault, abi: CONFIG_ABI, functionName: 'getEscrow' })\n if (escrow === zeroAddress) throw new EscrowNotConfiguredError(vault)\n\n // Validate wallet is on the correct chain (opt-in via hubChainId)\n validateWalletChain(walletClient, addresses.hubChainId)\n\n // Pre-flight: validate async cross-chain setup before sending any transaction\n await preflightAsync(publicClient, vault, escrow)\n\n // Resolve underlying asset\n const underlying = await publicClient.readContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'asset',\n })\n\n // Approve ESCROW (not vault!) for the deposit amount\n await ensureAllowance(walletClient, publicClient, underlying, escrow, assets)\n\n // Encode parameters only (no selector) — contracts use abi.decode on these bytes\n const actionCallData = encodeAbiParameters(\n [{ type: 'uint256', name: 'assets' }, { type: 'address', name: 'receiver' }],\n [assets, getAddress(receiver)],\n ) as `0x${string}`\n\n const [{ result: guid }, gasEstimate] = await Promise.all([\n publicClient.simulateContract({\n address: vault,\n abi: BRIDGE_ABI,\n functionName: 'initVaultActionRequest',\n args: [ActionType.DEPOSIT, actionCallData, 0n, extraOptions],\n value: lzFee,\n account: account.address,\n }),\n publicClient.estimateContractGas({\n address: vault,\n abi: BRIDGE_ABI,\n functionName: 'initVaultActionRequest',\n args: [ActionType.DEPOSIT, actionCallData, 0n, extraOptions],\n value: lzFee,\n account: account.address,\n }),\n ])\n\n // LZ Read operations consistently underestimate gas — add 30% buffer.\n const gas = gasEstimate * 130n / 100n\n\n const txHash = await walletClient.writeContract({\n address: vault,\n abi: BRIDGE_ABI,\n functionName: 'initVaultActionRequest',\n args: [ActionType.DEPOSIT, actionCallData, 0n, extraOptions],\n value: lzFee,\n account,\n chain: walletClient.chain,\n gas,\n })\n\n return { txHash, guid: guid as `0x${string}` }\n}\n\n/**\n * D5 — Async mint (cross-chain hub, oracle OFF).\n *\n * Mints an exact amount of shares by depositing up to `maxAssets` of underlying.\n * Similar flow to D4 but uses MINT action type.\n *\n * **User transactions**: 1 approve (to ESCROW for maxAssets) + 1 initVaultActionRequest.\n * **Wait**: Shares arrive after the LZ callback + executeRequest.\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads and simulation\n * @param addresses Vault address set (`vault` + `escrow` required)\n * @param shares Exact number of shares to mint\n * @param maxAssets Maximum assets to spend (slippage protection)\n * @param receiver Address that will receive the minted shares\n * @param lzFee msg.value for LZ Read fee\n * @param extraOptions Optional LZ extra options bytes\n * @returns Transaction hash and GUID for tracking\n */\nexport async function mintAsync(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n shares: bigint,\n maxAssets: bigint,\n receiver: Address,\n lzFee: bigint,\n extraOptions: `0x${string}` = '0x',\n): Promise<AsyncRequestResult> {\n const account = walletClient.account!\n const vault = getAddress(addresses.vault)\n const escrow = addresses.escrow\n ? getAddress(addresses.escrow)\n : await publicClient.readContract({ address: vault, abi: CONFIG_ABI, functionName: 'getEscrow' })\n if (escrow === zeroAddress) throw new EscrowNotConfiguredError(vault)\n\n // Validate wallet is on the correct chain (opt-in via hubChainId)\n validateWalletChain(walletClient, addresses.hubChainId)\n\n // Pre-flight: validate async cross-chain setup before sending any transaction\n await preflightAsync(publicClient, vault, escrow)\n\n const underlying = await publicClient.readContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'asset',\n })\n\n // Approve ESCROW for maxAssets\n await ensureAllowance(walletClient, publicClient, underlying, escrow, maxAssets)\n\n // Encode parameters only (no selector) — contracts use abi.decode on these bytes\n const actionCallData = encodeAbiParameters(\n [{ type: 'uint256', name: 'shares' }, { type: 'address', name: 'receiver' }],\n [shares, getAddress(receiver)],\n ) as `0x${string}`\n\n // amountLimit = maxAssets (slippage check: actual assets spent must be <= maxAssets)\n const [{ result: guid }, gasEstimate] = await Promise.all([\n publicClient.simulateContract({\n address: vault,\n abi: BRIDGE_ABI,\n functionName: 'initVaultActionRequest',\n args: [ActionType.MINT, actionCallData, maxAssets, extraOptions],\n value: lzFee,\n account: account.address,\n }),\n publicClient.estimateContractGas({\n address: vault,\n abi: BRIDGE_ABI,\n functionName: 'initVaultActionRequest',\n args: [ActionType.MINT, actionCallData, maxAssets, extraOptions],\n value: lzFee,\n account: account.address,\n }),\n ])\n\n const gas = gasEstimate * 130n / 100n\n\n const txHash = await walletClient.writeContract({\n address: vault,\n abi: BRIDGE_ABI,\n functionName: 'initVaultActionRequest',\n args: [ActionType.MINT, actionCallData, maxAssets, extraOptions],\n value: lzFee,\n account,\n chain: walletClient.chain,\n gas,\n })\n\n return { txHash, guid: guid as `0x${string}` }\n}\n\n/**\n * Smart deposit — auto-selects the correct flow based on vault configuration.\n *\n * Calls getVaultStatus internally to determine the vault mode, then dispatches\n * to the appropriate flow:\n * - local / cross-chain-oracle → depositSimple (ERC-4626 deposit)\n * - cross-chain-async → depositAsync (initVaultActionRequest + LZ Read callback)\n *\n * ## Tested flows\n *\n * - [x] Hub-chain async deposit (Base→Base, vault 0x8f74...ba6):\n * smartDeposit auto-detects async → depositAsync → LZ Read callback ~4.5 min.\n * TX: 0x5284b4...ca24\n *\n * ## Untested flows\n *\n * - [ ] Hub-chain sync deposit (depositSimple path) — needs a vault with oracle ON\n * - [ ] Multi-asset deposit (depositMultiAsset) — separate entry point, not dispatched here\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads\n * @param addresses Vault address set (`escrow` required for async vaults)\n * @param assets Amount of underlying to deposit\n * @param receiver Address that will receive shares\n * @param extraOptions Optional LZ extra options (only used for async vaults)\n * @returns DepositResult or AsyncRequestResult depending on vault mode\n * @throws VaultPausedError if vault is paused\n * @throws CapacityFullError if vault is full\n */\nexport async function smartDeposit(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n assets: bigint,\n receiver: Address,\n extraOptions: `0x${string}` = '0x',\n): Promise<DepositResult | AsyncRequestResult> {\n const vault = getAddress(addresses.vault)\n const status = await getVaultStatus(publicClient, vault)\n\n if (status.mode === 'paused') {\n throw new VaultPausedError(vault)\n }\n if (status.mode === 'full') {\n throw new CapacityFullError(vault)\n }\n\n if (status.recommendedDepositFlow === 'depositAsync') {\n const lzFee = await quoteLzFee(publicClient, vault, extraOptions)\n return depositAsync(walletClient, publicClient, addresses, assets, receiver, lzFee, extraOptions)\n }\n\n // local or cross-chain-oracle\n return depositSimple(walletClient, publicClient, addresses, assets, receiver)\n}\n","import {\n type Address,\n type Hash,\n type PublicClient,\n type WalletClient,\n encodeAbiParameters,\n getAddress,\n pad,\n zeroAddress,\n} from 'viem'\nimport { VAULT_ABI, BRIDGE_ABI, OFT_ABI, CONFIG_ABI, ERC20_ABI } from './abis'\nimport type {\n VaultAddresses,\n RedeemResult,\n AsyncRequestResult,\n} from './types'\nimport { ActionType } from './types'\nimport { ensureAllowance, getVaultStatus, quoteLzFee } from './utils'\nimport { preflightAsync, preflightRedeemLiquidity } from './preflight'\nimport { EscrowNotConfiguredError } from './errors'\nimport { validateWalletChain } from './chainValidation'\nimport { OFT_ROUTES, CHAIN_ID_TO_EID } from './chains'\nimport { createChainClient } from './spokeRoutes'\nimport { OMNI_FACTORY_ADDRESS } from './topology'\n\n/**\n * R1 — Simple share redemption (ERC-4626 standard).\n *\n * Burns `shares` and returns the proportional amount of underlying assets.\n * If a withdrawal queue is enabled, the caller must have previously called\n * `requestRedeem` and waited for the timelock to expire.\n *\n * **User transactions**: 1 redeem call.\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads and simulation\n * @param addresses Vault address set (only `vault` is used)\n * @param shares Amount of vault shares to redeem\n * @param receiver Address that will receive the underlying assets\n * @param owner Owner of the shares being redeemed\n * @returns Transaction hash and amount of assets received\n */\nexport async function redeemShares(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n shares: bigint,\n receiver: Address,\n owner: Address,\n): Promise<RedeemResult> {\n const account = walletClient.account!\n const vault = getAddress(addresses.vault)\n\n // Validate wallet is on the correct chain (opt-in via hubChainId)\n validateWalletChain(walletClient, addresses.hubChainId)\n\n const { result: assets } = await publicClient.simulateContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'redeem',\n args: [shares, getAddress(receiver), getAddress(owner)],\n account: account.address,\n })\n\n const txHash = await walletClient.writeContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'redeem',\n args: [shares, getAddress(receiver), getAddress(owner)],\n account,\n chain: walletClient.chain,\n })\n\n return { txHash, assets }\n}\n\n/**\n * R2 — Withdraw by specifying the exact assets amount.\n *\n * Burns the necessary shares to withdraw exactly `assets` amount of underlying.\n * If a withdrawal queue is enabled, the caller must have previously called\n * `requestWithdraw` and waited for the timelock.\n *\n * **User transactions**: 1 withdraw call.\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads and simulation\n * @param addresses Vault address set (only `vault` is used)\n * @param assets Exact amount of underlying assets to withdraw\n * @param receiver Address that will receive the assets\n * @param owner Owner of the shares being burned\n * @returns Transaction hash and the actual assets withdrawn\n */\nexport async function withdrawAssets(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n assets: bigint,\n receiver: Address,\n owner: Address,\n): Promise<RedeemResult> {\n const account = walletClient.account!\n const vault = getAddress(addresses.vault)\n\n // Validate wallet is on the correct chain (opt-in via hubChainId)\n validateWalletChain(walletClient, addresses.hubChainId)\n\n const { result: sharesBurned } = await publicClient.simulateContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'withdraw',\n args: [assets, getAddress(receiver), getAddress(owner)],\n account: account.address,\n })\n\n const txHash = await walletClient.writeContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'withdraw',\n args: [assets, getAddress(receiver), getAddress(owner)],\n account,\n chain: walletClient.chain,\n })\n\n // For withdraw, the return is shares burned; assets is what was requested\n return { txHash, assets }\n}\n\n/**\n * R3 / R4 — Request redeem (queue shares for withdrawal).\n *\n * Places `shares` into the withdrawal queue. If a timelock is configured (R4),\n * the user must wait until `timelockEndsAt` before calling `redeemShares`.\n * If no timelock (R3), `redeemShares` can be called immediately after.\n *\n * Use `getWithdrawalRequest` to check the timelock status.\n *\n * **User transactions**: 1 requestRedeem call, then later 1 redeemShares call.\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for simulation\n * @param addresses Vault address set (only `vault` is used)\n * @param shares Amount of shares to queue for redemption\n * @param owner The address on behalf of which the request is made\n * @returns Transaction hash of the request\n */\nexport async function requestRedeem(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n shares: bigint,\n owner: Address,\n): Promise<{ txHash: Hash }> {\n const account = walletClient.account!\n const vault = getAddress(addresses.vault)\n\n // Validate wallet is on the correct chain (opt-in via hubChainId)\n validateWalletChain(walletClient, addresses.hubChainId)\n\n await publicClient.simulateContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'requestRedeem',\n args: [shares, getAddress(owner)],\n account: account.address,\n })\n\n const txHash = await walletClient.writeContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'requestRedeem',\n args: [shares, getAddress(owner)],\n account,\n chain: walletClient.chain,\n })\n\n return { txHash }\n}\n\n/**\n * Helper — Get the current withdrawal request for an owner.\n *\n * Returns the queued shares and timelock end timestamp.\n * Useful for showing a countdown timer in the UI (R4 flow).\n *\n * @param publicClient Public client for reading state\n * @param vault Vault address\n * @param owner Owner whose request to query\n * @returns Request info or null if no active request\n */\nexport async function getWithdrawalRequest(\n publicClient: PublicClient,\n vault: Address,\n owner: Address,\n): Promise<{ shares: bigint; timelockEndsAt: bigint } | null> {\n const [shares, timelockEndsAt] = await publicClient.readContract({\n address: getAddress(vault),\n abi: VAULT_ABI,\n functionName: 'getWithdrawalRequest',\n args: [getAddress(owner)],\n })\n\n if (shares === 0n) return null\n\n return { shares, timelockEndsAt }\n}\n\n/**\n * R5 — Async redeem (cross-chain hub, oracle OFF).\n *\n * Initiates an async redeem via `initVaultActionRequest(REDEEM, ...)`.\n * Shares are locked in the escrow while the LZ Read resolves accounting.\n * After `executeRequest`, assets are sent to the receiver.\n *\n * **IMPORTANT**: `amountLimit` MUST be 0 for REDEEM actions (not shares).\n * The shares amount is encoded in the actionCallData. Setting amountLimit to\n * a non-zero value would be interpreted as \"max assets to receive\" (inverted\n * slippage check), which is almost never what the user wants.\n *\n * **User transactions**: 1 approve (shares to ESCROW) + 1 initVaultActionRequest.\n * **Wait**: Assets arrive after LZ callback + executeRequest.\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads and simulation\n * @param addresses Vault address set (`vault` + `escrow` required)\n * @param shares Amount of shares to redeem\n * @param receiver Address that will receive the underlying assets\n * @param owner Owner of the shares (must match the initiator)\n * @param lzFee msg.value for LZ Read fee\n * @param extraOptions Optional LZ extra options bytes\n * @returns Transaction hash and GUID for tracking\n */\nexport async function redeemAsync(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n shares: bigint,\n receiver: Address,\n owner: Address,\n lzFee: bigint,\n extraOptions: `0x${string}` = '0x',\n): Promise<AsyncRequestResult> {\n const account = walletClient.account!\n const vault = getAddress(addresses.vault)\n const escrow = addresses.escrow\n ? getAddress(addresses.escrow)\n : await publicClient.readContract({ address: vault, abi: CONFIG_ABI, functionName: 'getEscrow' })\n if (escrow === zeroAddress) throw new EscrowNotConfiguredError(vault)\n\n // Validate wallet is on the correct chain (opt-in via hubChainId)\n validateWalletChain(walletClient, addresses.hubChainId)\n\n // Pre-flight: validate async cross-chain setup before sending any transaction\n await preflightAsync(publicClient, vault, escrow)\n\n // Pre-flight: check hub has enough liquid assets — avoids wasting LZ fee on a guaranteed refund\n await preflightRedeemLiquidity(publicClient, vault, shares)\n\n // Approve ESCROW for shares (vault share token is the vault itself for ERC-4626)\n await ensureAllowance(walletClient, publicClient, vault, escrow, shares)\n\n // Encode parameters only (no selector) — contracts use abi.decode on these bytes\n const actionCallData = encodeAbiParameters(\n [{ type: 'uint256', name: 'shares' }, { type: 'address', name: 'receiver' }, { type: 'address', name: 'owner' }],\n [shares, getAddress(receiver), getAddress(owner)],\n ) as `0x${string}`\n\n // amountLimit MUST be 0 for REDEEM — see JSDoc above\n const [{ result: guid }, gasEstimate] = await Promise.all([\n publicClient.simulateContract({\n address: vault,\n abi: BRIDGE_ABI,\n functionName: 'initVaultActionRequest',\n args: [ActionType.REDEEM, actionCallData, 0n, extraOptions],\n value: lzFee,\n account: account.address,\n }),\n publicClient.estimateContractGas({\n address: vault,\n abi: BRIDGE_ABI,\n functionName: 'initVaultActionRequest',\n args: [ActionType.REDEEM, actionCallData, 0n, extraOptions],\n value: lzFee,\n account: account.address,\n }),\n ])\n\n const gas = gasEstimate * 130n / 100n\n\n const txHash = await walletClient.writeContract({\n address: vault,\n abi: BRIDGE_ABI,\n functionName: 'initVaultActionRequest',\n args: [ActionType.REDEEM, actionCallData, 0n, extraOptions],\n value: lzFee,\n account,\n chain: walletClient.chain,\n gas,\n })\n\n return { txHash, guid: guid as `0x${string}` }\n}\n\n/**\n * Smart redeem — auto-selects the correct flow based on vault configuration.\n *\n * Detects the vault mode and dispatches to:\n * - Sync vaults (local / cross-chain-oracle): `redeemShares` (direct ERC-4626 redeem)\n * - Async vaults (cross-chain, oracle OFF): `redeemAsync` (LZ Read flow, quotes fee automatically)\n *\n * ## Tested flows\n *\n * - [x] Hub-chain async redeem (Base→Base, vault 0x8f74...ba6):\n * smartRedeem auto-detects async → redeemAsync → LZ Read callback ~4.5 min.\n * TX: 0xd890c4...8b58c\n *\n * ## Untested flows\n *\n * - [ ] Hub-chain sync redeem (redeemShares path) — needs a vault with oracle ON\n * - [ ] requestRedeem + withdrawAssets (withdrawal queue flow) — separate entry points\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads\n * @param addresses Vault address set (`escrow` required for async vaults)\n * @param shares Amount of shares to redeem\n * @param receiver Address that will receive the underlying assets\n * @param owner Owner of the shares being redeemed\n * @param extraOptions Optional LZ extra options (only used for async vaults)\n * @returns RedeemResult or AsyncRequestResult depending on vault mode\n */\nexport async function smartRedeem(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n shares: bigint,\n receiver: Address,\n owner: Address,\n extraOptions: `0x${string}` = '0x',\n): Promise<RedeemResult | AsyncRequestResult> {\n const vault = getAddress(addresses.vault)\n const status = await getVaultStatus(publicClient, vault)\n\n if (status.mode === 'paused') {\n throw new Error(`[MoreVaults] Vault ${vault} is paused. Cannot redeem.`)\n }\n\n if (status.recommendedDepositFlow === 'depositAsync') {\n // Async vault — use redeemAsync\n const lzFee = await quoteLzFee(publicClient, vault, extraOptions)\n return redeemAsync(walletClient, publicClient, addresses, shares, receiver, owner, lzFee, extraOptions)\n }\n\n // Sync vault — direct redeem\n return redeemShares(walletClient, publicClient, addresses, shares, receiver, owner)\n}\n\n/**\n * R6 — Bridge shares from spoke to hub chain via OFT.\n *\n * This is step 1 of a cross-chain spoke redeem flow:\n * 1. `bridgeSharesToHub()` — send shares from spoke → hub via SHARE_OFT\n * 2. `smartRedeem()` — redeem shares on hub → underlying (auto-detects async)\n * 3. `bridgeAssetsToSpoke()` — bridge assets from hub → spoke via asset OFT\n *\n * The steps happen on different chains and cannot be combined.\n * The frontend must switch chains between steps.\n *\n * **User transactions on spoke chain**: 1 approve (shares to shareOFT) + 1 OFT.send().\n * **Gas**: Requires native token on spoke for LZ fees, and gas on hub for steps 2+3.\n *\n * ## Tested flows\n *\n * - [x] SHARE_OFT bridge (Eth→Base, vault 0x8f74...ba6):\n * Delivery ~7 min. Required enforcedOptions on Eth SHARE_OFT for dstEid=30184.\n *\n * @param walletClient Wallet client on the SPOKE chain\n * @param publicClient Public client on the SPOKE chain\n * @param shareOFT OFTAdapter address for vault shares on the spoke chain\n * @param hubChainEid LayerZero Endpoint ID for the hub chain\n * @param shares Amount of vault shares to bridge\n * @param receiver Receiver address on the HUB chain\n * @param lzFee msg.value for OFT send (quote via OFT.quoteSend)\n * @returns Transaction hash of the OFT.send() call\n */\nexport async function bridgeSharesToHub(\n walletClient: WalletClient,\n publicClient: PublicClient,\n shareOFT: Address,\n hubChainEid: number,\n shares: bigint,\n receiver: Address,\n lzFee: bigint,\n): Promise<{ txHash: Hash }> {\n const account = walletClient.account!\n const oft = getAddress(shareOFT)\n\n // Approve OFT for share transfer\n await ensureAllowance(walletClient, publicClient, oft, oft, shares)\n\n const toBytes32 = pad(getAddress(receiver), { size: 32 })\n\n const sendParam = {\n dstEid: hubChainEid,\n to: toBytes32,\n amountLD: shares,\n minAmountLD: shares, // shares should bridge 1:1\n extraOptions: '0x' as `0x${string}`,\n composeMsg: '0x' as `0x${string}`,\n oftCmd: '0x' as `0x${string}`,\n }\n\n const fee = {\n nativeFee: lzFee,\n lzTokenFee: 0n,\n }\n\n const txHash = await walletClient.writeContract({\n address: oft,\n abi: OFT_ABI,\n functionName: 'send',\n args: [sendParam, fee, account.address],\n value: lzFee,\n account,\n chain: walletClient.chain,\n })\n\n return { txHash }\n}\n\n/**\n * R7 — Bridge underlying assets from hub back to spoke chain via OFT.\n *\n * This is the final step of a full spoke redeem flow:\n * 1. `bridgeSharesToHub()` — send shares from spoke → hub via SHARE_OFT\n * 2. `smartRedeem()` — redeem shares on hub → underlying assets (e.g. USDC)\n * 3. `bridgeAssetsToSpoke()` — bridge assets from hub → spoke via OFT\n *\n * For Stargate OFTs (stgUSDC, USDT, WETH), uses TAXI mode (oftCmd 0x01) for\n * immediate delivery. For non-Stargate OFTs, uses empty oftCmd (0x).\n *\n * **User transactions on hub chain**: 1 approve (assets to OFT) + 1 OFT.send().\n * **Gas**: Requires native token on hub for LZ fees.\n *\n * ## Tested flows\n *\n * - [x] Stargate OFT bridge (Base→Eth, stgUSDC, TAXI mode 0x01):\n * Delivery ~13 min. TX: 0x... (see redeem-async-hub.ts test)\n *\n * ## Untested flows\n *\n * - [ ] Standard OFT bridge (non-Stargate, oftCmd 0x) — needs non-Stargate asset vault\n *\n * @param walletClient Wallet client on the HUB chain\n * @param publicClient Public client on the HUB chain\n * @param assetOFT OFT address for the underlying asset on the hub chain\n * @param spokeChainEid LayerZero Endpoint ID for the spoke (destination) chain\n * @param amount Amount of underlying assets to bridge\n * @param receiver Receiver address on the SPOKE chain\n * @param lzFee msg.value for OFT send (quote via OFT.quoteSend)\n * @param isStargate Whether this is a Stargate OFT (uses TAXI mode)\n * @returns Transaction hash of the OFT.send() call\n */\nexport async function bridgeAssetsToSpoke(\n walletClient: WalletClient,\n publicClient: PublicClient,\n assetOFT: Address,\n spokeChainEid: number,\n amount: bigint,\n receiver: Address,\n lzFee: bigint,\n isStargate: boolean = true,\n): Promise<{ txHash: Hash }> {\n const account = walletClient.account!\n const oft = getAddress(assetOFT)\n\n // Read underlying token and approve if different from OFT\n const token = await publicClient.readContract({\n address: oft,\n abi: OFT_ABI,\n functionName: 'token',\n })\n\n if (getAddress(token) !== oft) {\n // OFTAdapter pattern: approve underlying token to OFT\n await ensureAllowance(walletClient, publicClient, token, oft, amount)\n } else {\n // Pure OFT: approve OFT to itself\n await ensureAllowance(walletClient, publicClient, oft, oft, amount)\n }\n\n const toBytes32 = pad(getAddress(receiver), { size: 32 })\n\n const sendParam = {\n dstEid: spokeChainEid,\n to: toBytes32,\n amountLD: amount,\n minAmountLD: amount * 99n / 100n, // 1% slippage tolerance for Stargate\n extraOptions: '0x' as `0x${string}`,\n composeMsg: '0x' as `0x${string}`,\n oftCmd: (isStargate ? '0x01' : '0x') as `0x${string}`,\n }\n\n const fee = {\n nativeFee: lzFee,\n lzTokenFee: 0n,\n }\n\n const txHash = await walletClient.writeContract({\n address: oft,\n abi: OFT_ABI,\n functionName: 'send',\n args: [sendParam, fee, account.address],\n value: lzFee,\n account,\n chain: walletClient.chain,\n })\n\n return { txHash }\n}\n\nexport interface SpokeRedeemRoute {\n /** Hub chain ID */\n hubChainId: number\n /** Spoke chain ID */\n spokeChainId: number\n /** LZ EID for the hub */\n hubEid: number\n /** LZ EID for the spoke */\n spokeEid: number\n /** Vault underlying asset address on hub (e.g. USDC on Base) */\n hubAsset: Address\n /** SHARE_OFT on spoke chain (user has shares here) */\n spokeShareOft: Address\n /** Asset OFT on hub for bridging back (e.g. Stargate USDC pool on Base) */\n hubAssetOft: Address\n /** Underlying asset address on spoke chain (e.g. USDC on Ethereum) */\n spokeAsset: Address\n /** Whether the asset OFT is a Stargate pool (determines oftCmd) */\n isStargate: boolean\n /** OFT route symbol (e.g. 'stgUSDC') */\n symbol: string\n}\n\nconst STARGATE_ASSETS = new Set(['stgUSDC', 'USDT', 'WETH'])\n\nconst FACTORY_COMPOSER_ABI = [\n {\n type: 'function' as const,\n name: 'vaultComposer' as const,\n inputs: [{ name: '_vault', type: 'address' as const }] as const,\n outputs: [{ name: '', type: 'address' as const }] as const,\n stateMutability: 'view' as const,\n },\n] as const\n\nconst REDEEM_COMPOSER_ABI = [\n {\n type: 'function' as const,\n name: 'SHARE_OFT' as const,\n inputs: [] as const,\n outputs: [{ name: '', type: 'address' as const }] as const,\n stateMutability: 'view' as const,\n },\n] as const\n\n/**\n * Resolve all addresses needed for a full spoke→hub→spoke redeem flow.\n *\n * Discovers dynamically:\n * - SHARE_OFT on the spoke chain (via hub composer → peers)\n * - Asset OFT on the hub chain (matches vault.asset() to OFT_ROUTES)\n * - Underlying asset on the spoke chain\n *\n * @param hubPublicClient Public client on the HUB chain\n * @param vault Vault address\n * @param hubChainId Hub chain ID\n * @param spokeChainId Spoke chain ID where user has shares\n * @returns All addresses needed for bridgeSharesToHub + redeemShares + bridgeAssetsToSpoke\n */\nexport async function resolveRedeemAddresses(\n hubPublicClient: PublicClient,\n vault: Address,\n hubChainId: number,\n spokeChainId: number,\n): Promise<SpokeRedeemRoute> {\n const v = getAddress(vault)\n const hubEid = CHAIN_ID_TO_EID[hubChainId]\n const spokeEid = CHAIN_ID_TO_EID[spokeChainId]\n if (!hubEid || !spokeEid) throw new Error(`No LZ EID for chainId ${!hubEid ? hubChainId : spokeChainId}`)\n\n // Read vault asset and composer address in parallel\n const [hubAsset, composerAddress] = await Promise.all([\n hubPublicClient.readContract({ address: v, abi: VAULT_ABI, functionName: 'asset' }) as Promise<Address>,\n hubPublicClient.readContract({\n address: OMNI_FACTORY_ADDRESS,\n abi: FACTORY_COMPOSER_ABI,\n functionName: 'vaultComposer',\n args: [v],\n }) as Promise<Address>,\n ])\n\n if (composerAddress === zeroAddress) {\n throw new Error(`[MoreVaults] No composer registered for vault ${vault} on hub chain ${hubChainId}`)\n }\n\n // Read SHARE_OFT from composer\n const hubShareOft = await hubPublicClient.readContract({\n address: composerAddress,\n abi: REDEEM_COMPOSER_ABI,\n functionName: 'SHARE_OFT',\n }) as Address\n\n // Get spoke SHARE_OFT via peers(spokeEid) on hub SHARE_OFT\n const spokeShareOftBytes32 = await hubPublicClient.readContract({\n address: hubShareOft,\n abi: OFT_ABI,\n functionName: 'peers',\n args: [spokeEid],\n }) as `0x${string}`\n\n // Convert bytes32 to address (last 20 bytes)\n const spokeShareOft = getAddress(`0x${spokeShareOftBytes32.slice(-40)}`) as Address\n\n // Find matching OFT route for the vault's asset on the hub chain\n let hubAssetOft: Address | null = null\n let spokeAsset: Address | null = null\n let isStargate = false\n let symbol = ''\n\n for (const [sym, chainMap] of Object.entries(OFT_ROUTES)) {\n const hubEntry = (chainMap as Record<number, { oft: string; token: string }>)[hubChainId]\n const spokeEntry = (chainMap as Record<number, { oft: string; token: string }>)[spokeChainId]\n if (!hubEntry || !spokeEntry) continue\n\n if (getAddress(hubEntry.token) === getAddress(hubAsset)) {\n hubAssetOft = getAddress(hubEntry.oft) as Address\n spokeAsset = getAddress(spokeEntry.token) as Address\n isStargate = STARGATE_ASSETS.has(sym)\n symbol = sym\n break\n }\n }\n\n if (!hubAssetOft || !spokeAsset) {\n throw new Error(\n `[MoreVaults] No OFT route found for vault asset ${hubAsset} ` +\n `between hub chain ${hubChainId} and spoke chain ${spokeChainId}`,\n )\n }\n\n return {\n hubChainId,\n spokeChainId,\n hubEid,\n spokeEid,\n hubAsset,\n spokeShareOft,\n hubAssetOft,\n spokeAsset,\n isStargate,\n symbol,\n }\n}\n","import { type Address, type PublicClient, getAddress } from 'viem'\nimport { BRIDGE_ABI, CONFIG_ABI, ERC20_ABI, VAULT_ABI, METADATA_ABI, OFT_ABI } from './abis'\nimport type { CrossChainRequestInfo } from './types'\nimport { getVaultStatus } from './utils'\nimport type { VaultStatus } from './utils'\nimport { discoverVaultTopology, OMNI_FACTORY_ADDRESS } from './topology'\nimport { createChainClient } from './spokeRoutes'\nimport { CHAIN_ID_TO_EID } from './chains'\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface UserPosition {\n /** Vault share balance */\n shares: bigint\n /** convertToAssets(shares) — what they'd get if they redeemed now */\n estimatedAssets: bigint\n /** Price of 1 full share in underlying (convertToAssets(10n ** decimals)) */\n sharePrice: bigint\n /** Vault decimals (for display) */\n decimals: number\n pendingWithdrawal: {\n shares: bigint\n timelockEndsAt: bigint\n /** block.timestamp >= timelockEndsAt (or timelockEndsAt === 0n) */\n canRedeemNow: boolean\n } | null // null if no pending withdrawal request\n}\n\n/**\n * Read the user's current position in the vault.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address (diamond proxy)\n * @param user User wallet address\n * @returns Full user position snapshot\n */\nexport async function getUserPosition(\n publicClient: PublicClient,\n vault: Address,\n user: Address,\n): Promise<UserPosition> {\n const v = getAddress(vault)\n const u = getAddress(user)\n\n // First batch: balance, decimals, withdrawal request — via multicall\n const [sharesResult, decimalsResult, withdrawalRequestResult] = await publicClient.multicall({\n contracts: [\n { address: v, abi: VAULT_ABI, functionName: 'balanceOf', args: [u] },\n { address: v, abi: METADATA_ABI, functionName: 'decimals' },\n { address: v, abi: VAULT_ABI, functionName: 'getWithdrawalRequest', args: [u] },\n ],\n allowFailure: false,\n })\n const block = await publicClient.getBlock()\n const shares = sharesResult\n const decimals = decimalsResult\n const withdrawalRequest = withdrawalRequestResult\n\n const [withdrawShares, timelockEndsAt] = withdrawalRequest as unknown as [bigint, bigint]\n\n // Second batch: convertToAssets calls (need shares and decimals from first batch)\n const oneShare = 10n ** BigInt(decimals)\n const [estimatedAssets, sharePrice] = await Promise.all([\n shares === 0n\n ? Promise.resolve(0n)\n : publicClient.readContract({ address: v, abi: VAULT_ABI, functionName: 'convertToAssets', args: [shares] }),\n publicClient.readContract({ address: v, abi: VAULT_ABI, functionName: 'convertToAssets', args: [oneShare] }),\n ])\n\n const currentTimestamp = block.timestamp\n\n const pendingWithdrawal =\n withdrawShares === 0n\n ? null\n : {\n shares: withdrawShares,\n timelockEndsAt,\n canRedeemNow: timelockEndsAt === 0n || currentTimestamp >= timelockEndsAt,\n }\n\n return {\n shares,\n estimatedAssets,\n sharePrice,\n decimals,\n pendingWithdrawal,\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Preview how many shares a given asset amount would mint.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @param assets Amount of underlying tokens to deposit\n * @returns Estimated shares to be minted\n */\nexport async function previewDeposit(\n publicClient: PublicClient,\n vault: Address,\n assets: bigint,\n): Promise<bigint> {\n return publicClient.readContract({\n address: getAddress(vault),\n abi: VAULT_ABI,\n functionName: 'previewDeposit',\n args: [assets],\n })\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Preview how many underlying assets a given share amount would redeem.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @param shares Amount of vault shares to redeem\n * @returns Estimated assets to be returned\n */\nexport async function previewRedeem(\n publicClient: PublicClient,\n vault: Address,\n shares: bigint,\n): Promise<bigint> {\n return publicClient.readContract({\n address: getAddress(vault),\n abi: VAULT_ABI,\n functionName: 'previewRedeem',\n args: [shares],\n })\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type DepositBlockReason = 'paused' | 'capacity-full' | 'not-whitelisted' | 'ok'\n\nexport interface DepositEligibility {\n allowed: boolean\n reason: DepositBlockReason\n}\n\n/**\n * Check whether a user is eligible to deposit into the vault right now.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @param user User wallet address\n * @returns Eligibility result with reason\n */\nexport async function canDeposit(\n publicClient: PublicClient,\n vault: Address,\n user: Address,\n): Promise<DepositEligibility> {\n const v = getAddress(vault)\n\n // Fetch paused + isHub + oraclesCrossChainAccounting in one batch\n const [isPaused, isHub, oraclesEnabled] = await publicClient.multicall({\n contracts: [\n { address: v, abi: CONFIG_ABI, functionName: 'paused' },\n { address: v, abi: CONFIG_ABI, functionName: 'isHub' },\n { address: v, abi: BRIDGE_ABI, functionName: 'oraclesCrossChainAccounting' },\n ],\n allowFailure: false,\n })\n\n if (isPaused) {\n return { allowed: false, reason: 'paused' }\n }\n\n // Cross-chain async hubs revert on maxDeposit — this is expected, not a whitelist block.\n // The vault accepts deposits via initVaultActionRequest instead of the standard ERC-4626 path.\n const isCrossChainAsync = isHub && !oraclesEnabled\n if (isCrossChainAsync) {\n return { allowed: true, reason: 'ok' }\n }\n\n // maxDeposit(user) can REVERT on vaults with whitelist/ACL\n let maxDepositAmount: bigint\n try {\n maxDepositAmount = await publicClient.readContract({\n address: v,\n abi: CONFIG_ABI,\n functionName: 'maxDeposit',\n args: [getAddress(user)],\n })\n } catch {\n // Revert means the vault has whitelist/ACL and this user is not approved\n return { allowed: false, reason: 'not-whitelisted' }\n }\n\n if (maxDepositAmount === 0n) {\n return { allowed: false, reason: 'capacity-full' }\n }\n return { allowed: true, reason: 'ok' }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface VaultMetadata {\n name: string\n symbol: string\n decimals: number\n underlying: Address\n underlyingSymbol: string\n underlyingDecimals: number\n}\n\n/**\n * Read display metadata for a vault and its underlying token.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @returns Vault and underlying token metadata\n */\nexport async function getVaultMetadata(\n publicClient: PublicClient,\n vault: Address,\n): Promise<VaultMetadata> {\n const v = getAddress(vault)\n\n // Batch 1: vault name, symbol, decimals, underlying — 1 eth_call via multicall\n const b1 = await publicClient.multicall({\n contracts: [\n { address: v, abi: METADATA_ABI, functionName: 'name' },\n { address: v, abi: METADATA_ABI, functionName: 'symbol' },\n { address: v, abi: METADATA_ABI, functionName: 'decimals' },\n { address: v, abi: VAULT_ABI, functionName: 'asset' },\n ] as const,\n allowFailure: false,\n })\n\n const [name, symbol, decimals, underlying] = b1\n const underlyingAddr = getAddress(underlying as Address)\n\n // Batch 2: underlying symbol + decimals — 1 eth_call via multicall\n const b2 = await publicClient.multicall({\n contracts: [\n { address: underlyingAddr, abi: METADATA_ABI, functionName: 'symbol' },\n { address: underlyingAddr, abi: METADATA_ABI, functionName: 'decimals' },\n ] as const,\n allowFailure: false,\n })\n\n const [underlyingSymbol, underlyingDecimals] = b2\n\n return {\n name,\n symbol,\n decimals,\n underlying: underlyingAddr,\n underlyingSymbol,\n underlyingDecimals,\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type AsyncRequestStatus = 'pending' | 'ready-to-execute' | 'completed' | 'refunded'\n\nexport interface AsyncRequestStatusInfo {\n status: AsyncRequestStatus\n /** Human-readable description */\n label: string\n /** Shares minted or assets returned (0 if still pending) */\n result: bigint\n}\n\n/**\n * Get the human-readable status of an async cross-chain request.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @param guid Request GUID returned by depositAsync / mintAsync / redeemAsync\n * @returns Status info with label and result\n */\nexport async function getAsyncRequestStatusLabel(\n publicClient: PublicClient,\n vault: Address,\n guid: `0x${string}`,\n): Promise<AsyncRequestStatusInfo> {\n const v = getAddress(vault)\n\n const [info, finalizationResult] = await Promise.all([\n publicClient.readContract({\n address: v,\n abi: BRIDGE_ABI,\n functionName: 'getRequestInfo',\n args: [guid],\n }) as Promise<CrossChainRequestInfo>,\n publicClient.readContract({\n address: v,\n abi: BRIDGE_ABI,\n functionName: 'getFinalizationResult',\n args: [guid],\n }),\n ])\n\n if (info.refunded) {\n return {\n status: 'refunded',\n label: 'Request refunded — tokens returned to initiator',\n result: 0n,\n }\n }\n if (info.finalized) {\n return {\n status: 'completed',\n label: 'Completed',\n result: finalizationResult,\n }\n }\n if (info.fulfilled) {\n return {\n status: 'ready-to-execute',\n label: 'Oracle responded — ready to execute',\n result: 0n,\n }\n }\n return {\n status: 'pending',\n label: 'Waiting for cross-chain oracle response...',\n result: 0n,\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface UserBalances {\n /** Vault shares the user holds */\n shareBalance: bigint\n /** Underlying token balance in wallet (for deposit input) */\n underlyingBalance: bigint\n /** convertToAssets(shareBalance) — vault position value */\n estimatedAssets: bigint\n}\n\n/**\n * Read the user's token balances relevant to a vault.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @param user User wallet address\n * @returns Share balance, underlying wallet balance, and estimated assets\n */\nexport async function getUserBalances(\n publicClient: PublicClient,\n vault: Address,\n user: Address,\n): Promise<UserBalances> {\n const v = getAddress(vault)\n const u = getAddress(user)\n\n // Batch 1: get underlying address, share balance, decimals\n const [shareBalance, , underlying] = await publicClient.multicall({\n contracts: [\n { address: v, abi: VAULT_ABI, functionName: 'balanceOf', args: [u] },\n { address: v, abi: METADATA_ABI, functionName: 'decimals' },\n { address: v, abi: VAULT_ABI, functionName: 'asset' },\n ],\n allowFailure: false,\n })\n\n const underlyingAddr = getAddress(underlying)\n\n // Batch 2: underlying balance + estimated assets (skip convertToAssets if no shares)\n const [underlyingBalance, estimatedAssets] = await Promise.all([\n publicClient.readContract({\n address: underlyingAddr,\n abi: ERC20_ABI,\n functionName: 'balanceOf',\n args: [u],\n }),\n shareBalance === 0n\n ? Promise.resolve(0n)\n : publicClient.readContract({\n address: v,\n abi: VAULT_ABI,\n functionName: 'convertToAssets',\n args: [shareBalance],\n }),\n ])\n\n return {\n shareBalance,\n underlyingBalance,\n estimatedAssets,\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface MaxWithdrawable {\n /** How many shares can be redeemed right now */\n shares: bigint\n /** How many underlying assets that corresponds to */\n assets: bigint\n}\n\n/**\n * Calculate the maximum amount a user can withdraw from a vault right now.\n *\n * For hub vaults without oracle accounting, this is limited by hub liquidity.\n * For local and oracle vaults, all assets are immediately redeemable.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @param user User wallet address\n * @returns Maximum withdrawable shares and assets\n */\nexport async function getMaxWithdrawable(\n publicClient: PublicClient,\n vault: Address,\n user: Address,\n): Promise<MaxWithdrawable> {\n const v = getAddress(vault)\n const u = getAddress(user)\n\n // Batch 1: isHub, oraclesCrossChainAccounting, user share balance, underlying address\n const [isHub, oraclesEnabled, userShares, underlying] = await publicClient.multicall({\n contracts: [\n { address: v, abi: CONFIG_ABI, functionName: 'isHub' },\n { address: v, abi: BRIDGE_ABI, functionName: 'oraclesCrossChainAccounting' },\n { address: v, abi: VAULT_ABI, functionName: 'balanceOf', args: [u] },\n { address: v, abi: VAULT_ABI, functionName: 'asset' },\n ],\n allowFailure: false,\n })\n\n if (userShares === 0n) {\n return { shares: 0n, assets: 0n }\n }\n\n const underlyingAddr = getAddress(underlying)\n\n // Batch 2: estimated assets for user shares + hub liquid balance\n const [estimatedAssets, hubLiquidBalance] = await Promise.all([\n publicClient.readContract({\n address: v,\n abi: VAULT_ABI,\n functionName: 'convertToAssets',\n args: [userShares],\n }),\n publicClient.readContract({\n address: underlyingAddr,\n abi: ERC20_ABI,\n functionName: 'balanceOf',\n args: [v],\n }),\n ])\n\n let maxAssets: bigint\n if (isHub && !oraclesEnabled) {\n // Hub vault: limited by hub liquidity\n maxAssets = estimatedAssets < hubLiquidBalance ? estimatedAssets : hubLiquidBalance\n } else {\n // Local or oracle vault: all assets redeemable\n maxAssets = estimatedAssets\n }\n\n // Convert back to shares if limited by hub liquidity\n let maxShares: bigint\n if (maxAssets < estimatedAssets) {\n maxShares = await publicClient.readContract({\n address: v,\n abi: VAULT_ABI,\n functionName: 'convertToShares',\n args: [maxAssets],\n })\n } else {\n maxShares = userShares\n }\n\n return {\n shares: maxShares,\n assets: maxAssets,\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type VaultSummary = VaultStatus & VaultMetadata\n\n/**\n * Get a combined snapshot of vault status and metadata in one call.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @returns Merged VaultStatus and VaultMetadata\n */\nexport async function getVaultSummary(\n publicClient: PublicClient,\n vault: Address,\n): Promise<VaultSummary> {\n const [status, metadata] = await Promise.all([\n getVaultStatus(publicClient, vault),\n getVaultMetadata(publicClient, vault),\n ])\n return { ...status, ...metadata }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst FACTORY_COMPOSER_ABI = [\n {\n type: 'function' as const,\n name: 'vaultComposer',\n inputs: [{ name: '_vault', type: 'address' }],\n outputs: [{ name: '', type: 'address' }],\n stateMutability: 'view' as const,\n },\n] as const\n\nconst COMPOSER_SHARE_OFT_ABI = [\n {\n type: 'function' as const,\n name: 'SHARE_OFT',\n inputs: [],\n outputs: [{ name: '', type: 'address' }],\n stateMutability: 'view' as const,\n },\n] as const\n\nexport interface MultiChainUserPosition {\n /** Shares held directly on the hub vault (vault.balanceOf) */\n hubShares: bigint\n /** Per-spoke SHARE_OFT balances: { [chainId]: bigint } */\n spokeShares: Record<number, bigint>\n /** hubShares + sum of all spokeShares */\n totalShares: bigint\n /** convertToAssets(totalShares) on the hub */\n estimatedAssets: bigint\n /** Share price: convertToAssets(10^decimals) */\n sharePrice: bigint\n /** Vault decimals */\n decimals: number\n /** Pending async withdrawal request on hub, or null */\n pendingWithdrawal: {\n shares: bigint\n timelockEndsAt: bigint\n canRedeemNow: boolean\n } | null\n}\n\n/**\n * Read the user's position across all chains of an omni vault.\n *\n * Discovers topology automatically, reads hub shares + pending withdrawal,\n * then reads SHARE_OFT balances on each spoke chain in parallel.\n *\n * For local (single-chain) vaults, spokeShares will be empty and this\n * behaves identically to getUserPosition.\n *\n * @param vault Vault address (same on all chains via CREATE3)\n * @param user User wallet address\n * @returns Aggregated position across all chains\n */\nexport async function getUserPositionMultiChain(\n vault: Address,\n user: Address,\n): Promise<MultiChainUserPosition> {\n const v = getAddress(vault)\n const u = getAddress(user)\n\n // Step 1: discover topology\n const topo = await discoverVaultTopology(vault)\n const hubClient = createChainClient(topo.hubChainId)\n if (!hubClient) throw new Error(`No public RPC for hub chainId ${topo.hubChainId}`)\n\n // Step 2: read hub data (shares, decimals, withdrawal request)\n const [hubShares, decimals, withdrawalRequest] = await (hubClient as PublicClient).multicall({\n contracts: [\n { address: v, abi: VAULT_ABI, functionName: 'balanceOf', args: [u] },\n { address: v, abi: METADATA_ABI, functionName: 'decimals' },\n { address: v, abi: VAULT_ABI, functionName: 'getWithdrawalRequest', args: [u] },\n ],\n allowFailure: false,\n })\n\n const [withdrawShares, timelockEndsAt] = withdrawalRequest as unknown as [bigint, bigint]\n\n // Step 3: resolve SHARE_OFT addresses for spokes (if any)\n const spokeShares: Record<number, bigint> = {}\n\n if (topo.spokeChainIds.length > 0) {\n // Get hub SHARE_OFT via factory → composer → SHARE_OFT\n let hubShareOft: Address | null = null\n try {\n const composerAddress = await (hubClient as PublicClient).readContract({\n address: OMNI_FACTORY_ADDRESS,\n abi: FACTORY_COMPOSER_ABI,\n functionName: 'vaultComposer',\n args: [v],\n }) as Address\n\n if (composerAddress !== '0x0000000000000000000000000000000000000000') {\n hubShareOft = await (hubClient as PublicClient).readContract({\n address: composerAddress,\n abi: COMPOSER_SHARE_OFT_ABI,\n functionName: 'SHARE_OFT',\n }) as Address\n }\n } catch { /* no composer — skip spoke reads */ }\n\n if (hubShareOft) {\n // Read spoke SHARE_OFT addresses via peers() and balances in parallel\n const spokePromises = topo.spokeChainIds.map(async (spokeChainId) => {\n try {\n const spokeEid = CHAIN_ID_TO_EID[spokeChainId]\n if (!spokeEid) return { chainId: spokeChainId, balance: 0n }\n\n // Get spoke SHARE_OFT address from hub peers()\n const spokeOftBytes32 = await (hubClient as PublicClient).readContract({\n address: hubShareOft!,\n abi: OFT_ABI,\n functionName: 'peers',\n args: [spokeEid],\n }) as `0x${string}`\n\n const spokeOft = getAddress(`0x${spokeOftBytes32.slice(-40)}`) as Address\n if (spokeOft === '0x0000000000000000000000000000000000000000') {\n return { chainId: spokeChainId, balance: 0n }\n }\n\n // Read balance on spoke chain\n const spokeClient = createChainClient(spokeChainId)\n if (!spokeClient) return { chainId: spokeChainId, balance: 0n }\n\n const balance = await (spokeClient as PublicClient).readContract({\n address: spokeOft,\n abi: ERC20_ABI,\n functionName: 'balanceOf',\n args: [u],\n })\n\n return { chainId: spokeChainId, balance }\n } catch {\n return { chainId: spokeChainId, balance: 0n }\n }\n })\n\n const results = await Promise.all(spokePromises)\n for (const { chainId, balance } of results) {\n spokeShares[chainId] = balance\n }\n }\n }\n\n // Step 4: compute totals\n const totalSpokeShares = Object.values(spokeShares).reduce((sum, b) => sum + b, 0n)\n const totalShares = hubShares + totalSpokeShares\n\n const oneShare = 10n ** BigInt(decimals)\n const [estimatedAssets, sharePrice] = await Promise.all([\n totalShares === 0n\n ? Promise.resolve(0n)\n : (hubClient as PublicClient).readContract({ address: v, abi: VAULT_ABI, functionName: 'convertToAssets', args: [totalShares] }),\n (hubClient as PublicClient).readContract({ address: v, abi: VAULT_ABI, functionName: 'convertToAssets', args: [oneShare] }),\n ])\n\n // Step 5: pending withdrawal\n const block = await (hubClient as PublicClient).getBlock()\n const pendingWithdrawal = withdrawShares === 0n\n ? null\n : {\n shares: withdrawShares,\n timelockEndsAt,\n canRedeemNow: timelockEndsAt === 0n || block.timestamp >= timelockEndsAt,\n }\n\n return {\n hubShares,\n spokeShares,\n totalShares,\n estimatedAssets,\n sharePrice,\n decimals,\n pendingWithdrawal,\n }\n}\n","import type { Address, PublicClient } from 'viem'\nimport { getVaultStatus } from './utils.js'\nimport { getVaultTopology } from './topology.js'\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface SpokeBalance {\n chainId: number\n totalAssets: bigint\n /** false if the RPC call to this spoke failed */\n isReachable: boolean\n}\n\nexport interface VaultDistribution {\n hubChainId: number\n /** Underlying token balance idle on the hub (not deployed to strategies) */\n hubLiquidBalance: bigint\n /** Hub totalAssets minus hubLiquidBalance (capital in Morpho, Aave, etc.) */\n hubStrategyBalance: bigint\n /** Hub vault totalAssets() */\n hubTotalAssets: bigint\n /** What the hub's accounting thinks is deployed on spokes */\n spokesDeployedBalance: bigint\n /** Actual per-spoke balances read directly from each spoke chain */\n spokeBalances: SpokeBalance[]\n /** hubTotalAssets + sum of reachable spoke totalAssets */\n totalActual: bigint\n oracleAccountingEnabled: boolean\n}\n\n/**\n * Read the full cross-chain capital distribution of a vault.\n *\n * Queries the hub for its status, then reads `totalAssets()` on each spoke\n * chain in parallel. Spoke calls are individually wrapped so a single\n * unreachable RPC never fails the entire call.\n *\n * @param hubClient Public client connected to the hub chain\n * @param vault Vault address (same on all chains via CREATE3)\n * @param spokeClients Map of chainId → PublicClient for each spoke chain\n *\n * @example\n * ```ts\n * const dist = await getVaultDistribution(baseClient, VAULT, {\n * [1]: ethClient,\n * [42161]: arbClient,\n * })\n * console.log(`Hub liquid: ${dist.hubLiquidBalance}`)\n * console.log(`Total actual: ${dist.totalActual}`)\n * ```\n */\nexport async function getVaultDistribution(\n hubClient: PublicClient,\n vault: Address,\n spokeClients: Record<number, PublicClient>,\n): Promise<VaultDistribution> {\n // Read hub status\n const hubStatus = await getVaultStatus(hubClient, vault)\n\n const hubChainId = Number(hubClient.chain?.id ?? 0)\n const hubTotalAssets = hubStatus.totalAssets\n const hubLiquidBalance = hubStatus.hubLiquidBalance\n const hubStrategyBalance = hubTotalAssets > hubLiquidBalance\n ? hubTotalAssets - hubLiquidBalance\n : 0n\n\n // Read each spoke's totalAssets in parallel, never throwing\n const spokeEntries = Object.entries(spokeClients).map(([chainIdStr, client]) => ({\n chainId: Number(chainIdStr),\n client,\n }))\n\n const spokeBalances: SpokeBalance[] = await Promise.all(\n spokeEntries.map(async ({ chainId, client }): Promise<SpokeBalance> => {\n try {\n const spokeStatus = await getVaultStatus(client, vault)\n return { chainId, totalAssets: spokeStatus.totalAssets, isReachable: true }\n } catch {\n return { chainId, totalAssets: 0n, isReachable: false }\n }\n }),\n )\n\n // totalActual = hub + reachable spokes\n const reachableSpokeSum = spokeBalances\n .filter(s => s.isReachable)\n .reduce((acc, s) => acc + s.totalAssets, 0n)\n\n const totalActual = hubTotalAssets + reachableSpokeSum\n\n return {\n hubChainId,\n hubLiquidBalance,\n hubStrategyBalance,\n hubTotalAssets,\n spokesDeployedBalance: hubStatus.spokesDeployedBalance,\n spokeBalances,\n totalActual,\n oracleAccountingEnabled: hubStatus.oracleAccountingEnabled,\n }\n}\n\n/**\n * Hub-only distribution — uses topology to discover spokes but does NOT\n * read spoke chains (no spoke clients needed).\n *\n * Returns hub data plus the list of spoke chainIds from the factory.\n * `spokeBalances` will be empty — callers must provide spoke clients to\n * `getVaultDistribution` for actual spoke reads.\n *\n * @param hubClient Public client connected to the hub chain\n * @param vault Vault address\n *\n * @example\n * ```ts\n * const dist = await getVaultDistributionWithTopology(baseClient, VAULT)\n * // dist.spokeBalances === [] (no spoke clients provided)\n * // dist.spokeChainIds tells you which chains to query\n * ```\n */\nexport async function getVaultDistributionWithTopology(\n hubClient: PublicClient,\n vault: Address,\n): Promise<VaultDistribution & { spokeChainIds: number[] }> {\n // Read hub status and topology in parallel\n const [hubStatus, topology] = await Promise.all([\n getVaultStatus(hubClient, vault),\n getVaultTopology(hubClient, vault),\n ])\n\n const hubChainId = Number(hubClient.chain?.id ?? 0)\n const hubTotalAssets = hubStatus.totalAssets\n const hubLiquidBalance = hubStatus.hubLiquidBalance\n const hubStrategyBalance = hubTotalAssets > hubLiquidBalance\n ? hubTotalAssets - hubLiquidBalance\n : 0n\n\n return {\n hubChainId,\n hubLiquidBalance,\n hubStrategyBalance,\n hubTotalAssets,\n spokesDeployedBalance: hubStatus.spokesDeployedBalance,\n spokeBalances: [],\n totalActual: hubTotalAssets, // hub-only, no spoke data\n oracleAccountingEnabled: hubStatus.oracleAccountingEnabled,\n spokeChainIds: topology.spokeChainIds,\n }\n}\n","import type { PublicClient } from 'viem'\n\n/**\n * Cast a wagmi PublicClient to the SDK's expected type.\n * Use this in React components to avoid `as any` casts:\n * ```ts\n * import { usePublicClient } from 'wagmi'\n * import { asSdkClient } from '@oydual31/more-vaults-sdk/viem'\n * const pc = asSdkClient(usePublicClient())\n * ```\n * wagmi v2 uses viem as a peer dependency, so the types are structurally\n * identical — this function validates the client is non-null and applies\n * a documented cast instead of an opaque `as any`.\n */\nexport function asSdkClient(client: unknown): PublicClient {\n if (!client) throw new Error('[MoreVaults] No public client available. Make sure wagmi is configured correctly.')\n return client as PublicClient\n}\n","import { useQuery } from '@tanstack/react-query'\nimport { usePublicClient } from 'wagmi'\nimport { asSdkClient, getVaultStatus } from '../viem/index.js'\nimport type { VaultStatus } from '../viem/index.js'\n\nexport type { VaultStatus }\n\ninterface UseVaultStatusOptions {\n /** Refetch interval in ms. Default: 30_000 (30s) */\n refetchInterval?: number\n}\n\n/**\n * Read the full vault status snapshot.\n * Automatically refetches on a configurable interval.\n *\n * @example\n * const { data: status, isLoading } = useVaultStatus('0xVAULT', 747)\n * if (status?.mode === 'cross-chain-async') { ... }\n */\nexport function useVaultStatus(\n vault: `0x${string}` | undefined,\n chainId: number,\n options?: UseVaultStatusOptions,\n) {\n const publicClient = usePublicClient({ chainId })\n return useQuery({\n queryKey: ['vaultStatus', vault, chainId],\n queryFn: () => getVaultStatus(asSdkClient(publicClient), vault!),\n enabled: !!vault && !!publicClient,\n refetchInterval: options?.refetchInterval ?? 30_000,\n staleTime: 15_000,\n })\n}\n","import { useQuery } from '@tanstack/react-query'\nimport { usePublicClient } from 'wagmi'\nimport { asSdkClient, getVaultMetadata } from '../viem/index.js'\nimport type { VaultMetadata } from '../viem/index.js'\n\nexport type { VaultMetadata }\n\n/**\n * Read display metadata for a vault and its underlying token.\n * Uses a long stale time (5 min) because metadata rarely changes.\n *\n * @example\n * const { data: meta } = useVaultMetadata('0xVAULT', 747)\n * // meta.name, meta.symbol, meta.underlying, meta.underlyingSymbol\n */\nexport function useVaultMetadata(\n vault: `0x${string}` | undefined,\n chainId: number,\n) {\n const publicClient = usePublicClient({ chainId })\n return useQuery({\n queryKey: ['vaultMetadata', vault, chainId],\n queryFn: () => getVaultMetadata(asSdkClient(publicClient), vault!),\n enabled: !!vault && !!publicClient,\n // Metadata (name, symbol, underlying) changes very rarely — 5 min stale time\n staleTime: 5 * 60_000,\n refetchInterval: 5 * 60_000,\n })\n}\n","import { useQuery } from '@tanstack/react-query'\nimport { usePublicClient } from 'wagmi'\nimport { asSdkClient, getUserPosition } from '../viem/index.js'\nimport type { UserPosition } from '../viem/index.js'\n\nexport type { UserPosition }\n\n/**\n * Read the user's current position in a vault.\n * Refetches every 15s to keep the balance display current.\n *\n * @example\n * const { data: position } = useUserPosition('0xVAULT', '0xUSER', 747)\n * // position.shares, position.estimatedAssets, position.pendingWithdrawal\n */\nexport function useUserPosition(\n vault: `0x${string}` | undefined,\n user: `0x${string}` | undefined,\n chainId: number,\n) {\n const publicClient = usePublicClient({ chainId })\n return useQuery({\n queryKey: ['userPosition', vault, user, chainId],\n queryFn: () => getUserPosition(asSdkClient(publicClient), vault!, user!),\n enabled: !!vault && !!user && !!publicClient,\n refetchInterval: 15_000,\n staleTime: 10_000,\n })\n}\n","import { useQuery } from '@tanstack/react-query'\nimport { getUserPositionMultiChain } from '../viem/userHelpers.js'\nimport type { MultiChainUserPosition } from '../viem/userHelpers.js'\n\nexport type { MultiChainUserPosition }\n\n/**\n * Read the user's position across all chains of an omni vault.\n *\n * Discovers topology automatically, reads hub shares + pending withdrawal,\n * then reads SHARE_OFT balances on each spoke chain in parallel.\n * Works without a connected wallet (uses public RPCs).\n *\n * @example\n * const { data: position } = useUserPositionMultiChain('0xVAULT', '0xUSER')\n * // position.hubShares — shares on hub (Base)\n * // position.spokeShares — { 1: 500n, 42161: 0n } per spoke\n * // position.totalShares — hub + all spokes\n * // position.estimatedAssets — convertToAssets(totalShares)\n * // position.pendingWithdrawal — async withdrawal if any\n */\nexport function useUserPositionMultiChain(\n vault: `0x${string}` | undefined,\n user: `0x${string}` | undefined,\n) {\n return useQuery<MultiChainUserPosition>({\n queryKey: ['userPositionMultiChain', vault, user],\n queryFn: () => getUserPositionMultiChain(vault!, user!),\n enabled: !!vault && !!user,\n refetchInterval: 30_000,\n staleTime: 15_000,\n })\n}\n","import { useQuery } from '@tanstack/react-query'\nimport { usePublicClient } from 'wagmi'\nimport { asSdkClient, quoteLzFee } from '../viem/index.js'\n\n/**\n * Quote the LayerZero fee required for async operations (D4, D5, R5).\n * Refreshes every 60s — fees change with network congestion.\n *\n * @example\n * const { fee, feeWithBuffer } = useLzFee('0xVAULT', 747)\n * // feeWithBuffer adds 1% buffer automatically (fee * 101 / 100)\n */\nexport function useLzFee(vault: `0x${string}` | undefined, chainId: number) {\n const publicClient = usePublicClient({ chainId })\n const query = useQuery({\n queryKey: ['lzFee', vault, chainId],\n queryFn: () => quoteLzFee(asSdkClient(publicClient), vault!),\n enabled: !!vault && !!publicClient,\n refetchInterval: 60_000,\n staleTime: 30_000,\n })\n return {\n ...query,\n fee: query.data,\n feeWithBuffer: query.data ? (query.data * 101n) / 100n : undefined,\n }\n}\n","import { useQuery } from '@tanstack/react-query'\nimport { usePublicClient } from 'wagmi'\nimport { asSdkClient, getAsyncRequestStatusLabel } from '../viem/index.js'\nimport type { AsyncRequestStatusInfo } from '../viem/index.js'\n\nexport type { AsyncRequestStatusInfo }\n\n/**\n * Poll the status of an async cross-chain request (D4/D5/R5) by GUID.\n *\n * Automatically stops polling when status reaches 'completed' or 'refunded'.\n * Polls every 10s while the request is still pending or ready-to-execute.\n *\n * @example\n * const { data } = useAsyncRequestStatus('0xVAULT', guid, 747)\n * // data.status: 'pending' | 'ready-to-execute' | 'completed' | 'refunded'\n * // data.label: human-readable description\n * // data.result: shares minted or assets returned (0n while pending)\n */\nexport function useAsyncRequestStatus(\n vault: `0x${string}` | undefined,\n guid: `0x${string}` | undefined,\n chainId: number,\n) {\n const publicClient = usePublicClient({ chainId })\n return useQuery<AsyncRequestStatusInfo>({\n queryKey: ['asyncRequestStatus', vault, guid, chainId],\n queryFn: () => getAsyncRequestStatusLabel(asSdkClient(publicClient), vault!, guid!),\n enabled: !!vault && !!guid && !!publicClient,\n refetchInterval: (query) => {\n const status = query.state.data?.status\n if (status === 'completed' || status === 'refunded') return false\n return 10_000\n },\n })\n}\n","import { usePublicClient, useChainId } from 'wagmi'\nimport { useQuery } from '@tanstack/react-query'\nimport { asSdkClient } from '../viem/wagmiCompat.js'\nimport {\n discoverVaultTopology,\n isOnHubChain,\n getAllVaultChainIds,\n OMNI_FACTORY_ADDRESS,\n} from '../viem/topology.js'\nimport type { VaultTopology } from '../viem/topology.js'\nimport type { Address } from 'viem'\n\nexport type { VaultTopology }\n\ninterface UseVaultTopologyReturn {\n topology: VaultTopology | undefined\n isLoading: boolean\n /**\n * true when the connected wallet is on the wrong chain to deposit.\n * Show a \"Switch to {hubChainId}\" prompt when this is true.\n */\n needsNetworkSwitch: boolean\n /**\n * All chain IDs where this vault exists (hub + spokes).\n * Use to build a multi-chain network selector.\n */\n allChainIds: number[]\n}\n\n/**\n * Resolve the cross-chain topology of a vault with automatic multi-chain discovery.\n *\n * Uses `discoverVaultTopology` internally: if the wallet's current chain doesn't\n * know the vault, it iterates all supported chains via public RPCs until the hub\n * is found. Works even without a connected wallet.\n *\n * @example\n * // Works regardless of which chain the wallet is on (or if disconnected)\n * const { topology, needsNetworkSwitch, allChainIds } = useVaultTopology('0xVAULT')\n *\n * if (needsNetworkSwitch) {\n * return <SwitchNetworkButton chainId={topology.hubChainId} />\n * }\n */\nexport function useVaultTopology(\n vault: Address | undefined,\n factoryAddress: Address = OMNI_FACTORY_ADDRESS,\n): UseVaultTopologyReturn {\n const currentChainId = useChainId()\n const publicClient = usePublicClient()\n\n const { data: topology, isLoading } = useQuery<VaultTopology>({\n // Key does NOT include currentChainId — topology is chain-independent\n queryKey: ['vaultTopology', vault, factoryAddress],\n queryFn: () => discoverVaultTopology(\n vault!,\n publicClient ? asSdkClient(publicClient) : null,\n factoryAddress,\n ),\n enabled: !!vault,\n staleTime: 5 * 60 * 1000, // topology rarely changes — 5 min cache\n })\n\n const needsNetworkSwitch = topology ? !isOnHubChain(currentChainId, topology) : false\n const allChainIds = topology ? getAllVaultChainIds(topology) : []\n\n return { topology, isLoading, needsNetworkSwitch, allChainIds }\n}\n","import { useState, useCallback } from 'react'\nimport { usePublicClient, useWalletClient, useChainId } from 'wagmi'\nimport {\n asSdkClient,\n depositAsync,\n getVaultStatus,\n} from '../viem/index.js'\nimport type { AsyncRequestStatusInfo } from '../viem/index.js'\nimport { useLzFee } from './useLzFee.js'\nimport { useAsyncRequestStatus } from './useAsyncRequestStatus.js'\n\ninterface UseOmniDepositReturn {\n /** Execute approve + depositAsync. Handles everything internally. */\n deposit: (amountInWei: bigint, receiver: `0x${string}`) => Promise<void>\n isLoading: boolean\n txHash: `0x${string}` | undefined\n /** GUID for cross-chain tracking. Available after tx confirmation. */\n guid: `0x${string}` | undefined\n /** Cross-chain request status. undefined until a guid is available. */\n requestStatus: AsyncRequestStatusInfo | undefined\n /** true when the wallet is connected to the wrong chain */\n wrongChain: boolean\n error: Error | undefined\n reset: () => void\n}\n\n/**\n * Complete hook for async deposits on hub vaults (D4 flow).\n *\n * Handles: fee quote, chain validation, approve, depositAsync, and GUID polling.\n * The deposit function wraps the entire flow — callers only pass amount + receiver.\n *\n * @example\n * const { deposit, isLoading, guid, requestStatus, wrongChain } = useOmniDeposit('0xVAULT', 747)\n *\n * if (wrongChain) return <SwitchNetworkButton chainId={747} />\n *\n * await deposit(parseUnits('100', 6), userAddress)\n * // requestStatus.status goes: 'pending' → 'completed' | 'refunded'\n */\nexport function useOmniDeposit(\n vault: `0x${string}` | undefined,\n hubChainId: number,\n): UseOmniDepositReturn {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const { data: walletClient } = useWalletClient({ chainId: hubChainId })\n const publicClient = usePublicClient({ chainId: hubChainId })\n const currentChainId = useChainId()\n\n const [isLoading, setIsLoading] = useState(false)\n const [txHash, setTxHash] = useState<`0x${string}` | undefined>()\n const [guid, setGuid] = useState<`0x${string}` | undefined>()\n const [error, setError] = useState<Error | undefined>()\n\n const { feeWithBuffer } = useLzFee(vault, hubChainId)\n const { data: requestStatus } = useAsyncRequestStatus(vault, guid, hubChainId)\n\n const wrongChain = currentChainId !== hubChainId\n\n const deposit = useCallback(\n async (amountInWei: bigint, receiver: `0x${string}`) => {\n if (!vault || !walletClient || !publicClient || !feeWithBuffer) return\n setIsLoading(true)\n setError(undefined)\n try {\n const pc = asSdkClient(publicClient)\n const status = await getVaultStatus(pc, vault)\n // walletClient from wagmi is structurally compatible with viem WalletClient\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await depositAsync(\n walletClient as any,\n pc,\n { vault, escrow: status.escrow, hubChainId },\n amountInWei,\n receiver,\n feeWithBuffer,\n )\n setTxHash(result.txHash)\n setGuid(result.guid)\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)))\n } finally {\n setIsLoading(false)\n }\n },\n [vault, walletClient, publicClient, feeWithBuffer, hubChainId],\n )\n\n const reset = useCallback(() => {\n setTxHash(undefined)\n setGuid(undefined)\n setError(undefined)\n setIsLoading(false)\n }, [])\n\n return { deposit, isLoading, txHash, guid, requestStatus, wrongChain, error, reset }\n}\n","import { useState, useCallback } from 'react'\nimport { usePublicClient, useWalletClient, useChainId } from 'wagmi'\nimport {\n asSdkClient,\n redeemAsync,\n getVaultStatus,\n} from '../viem/index.js'\nimport type { AsyncRequestStatusInfo } from '../viem/index.js'\nimport { useLzFee } from './useLzFee.js'\nimport { useAsyncRequestStatus } from './useAsyncRequestStatus.js'\n\ninterface UseOmniRedeemReturn {\n /** Execute approve + redeemAsync. Handles everything internally. */\n redeem: (sharesInWei: bigint, receiver: `0x${string}`, owner: `0x${string}`) => Promise<void>\n isLoading: boolean\n txHash: `0x${string}` | undefined\n /** GUID for cross-chain tracking. Available after tx confirmation. */\n guid: `0x${string}` | undefined\n /** Cross-chain request status. undefined until a guid is available. */\n requestStatus: AsyncRequestStatusInfo | undefined\n /** true when the wallet is connected to the wrong chain */\n wrongChain: boolean\n error: Error | undefined\n reset: () => void\n}\n\n/**\n * Complete hook for async redeems on hub vaults (R5 flow).\n *\n * Handles: fee quote, chain validation, share approve, redeemAsync, and GUID polling.\n *\n * @example\n * const { redeem, isLoading, guid, requestStatus, wrongChain } = useOmniRedeem('0xVAULT', 747)\n *\n * if (wrongChain) return <SwitchNetworkButton chainId={747} />\n *\n * await redeem(sharesInWei, userAddress, userAddress)\n * // requestStatus.status goes: 'pending' → 'completed' | 'refunded'\n */\nexport function useOmniRedeem(\n vault: `0x${string}` | undefined,\n hubChainId: number,\n): UseOmniRedeemReturn {\n const { data: walletClient } = useWalletClient({ chainId: hubChainId })\n const publicClient = usePublicClient({ chainId: hubChainId })\n const currentChainId = useChainId()\n\n const [isLoading, setIsLoading] = useState(false)\n const [txHash, setTxHash] = useState<`0x${string}` | undefined>()\n const [guid, setGuid] = useState<`0x${string}` | undefined>()\n const [error, setError] = useState<Error | undefined>()\n\n const { feeWithBuffer } = useLzFee(vault, hubChainId)\n const { data: requestStatus } = useAsyncRequestStatus(vault, guid, hubChainId)\n\n const wrongChain = currentChainId !== hubChainId\n\n const redeem = useCallback(\n async (sharesInWei: bigint, receiver: `0x${string}`, owner: `0x${string}`) => {\n if (!vault || !walletClient || !publicClient || !feeWithBuffer) return\n setIsLoading(true)\n setError(undefined)\n try {\n const pc = asSdkClient(publicClient)\n const status = await getVaultStatus(pc, vault)\n // walletClient from wagmi is structurally compatible with viem WalletClient\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await redeemAsync(\n walletClient as any,\n pc,\n { vault, escrow: status.escrow, hubChainId },\n sharesInWei,\n receiver,\n owner,\n feeWithBuffer,\n )\n setTxHash(result.txHash)\n setGuid(result.guid)\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)))\n } finally {\n setIsLoading(false)\n }\n },\n [vault, walletClient, publicClient, feeWithBuffer, hubChainId],\n )\n\n const reset = useCallback(() => {\n setTxHash(undefined)\n setGuid(undefined)\n setError(undefined)\n setIsLoading(false)\n }, [])\n\n return { redeem, isLoading, txHash, guid, requestStatus, wrongChain, error, reset }\n}\n","import { useState, useCallback } from 'react'\nimport { usePublicClient, useWalletClient } from 'wagmi'\nimport { asSdkClient, depositSimple } from '../viem/index.js'\nimport type { DepositResult } from '../viem/index.js'\n\ninterface UseDepositSimpleReturn {\n /** Execute approve + depositSimple (D1/D3 flows). */\n deposit: (amountInWei: bigint, receiver: `0x${string}`) => Promise<void>\n isLoading: boolean\n txHash: `0x${string}` | undefined\n /** Shares minted. Available after tx confirmation. */\n shares: bigint | undefined\n error: Error | undefined\n reset: () => void\n}\n\n/**\n * Hook for local and oracle-on cross-chain vaults (D1/D3 flows).\n *\n * Simpler than useOmniDeposit — no LZ fee, no GUID, no polling.\n * One approve + one deposit transaction.\n *\n * @example\n * const { deposit, isLoading, txHash, shares } = useDepositSimple('0xVAULT', 747)\n * await deposit(parseUnits('100', 6), userAddress)\n */\nexport function useDepositSimple(\n vault: `0x${string}` | undefined,\n chainId: number,\n): UseDepositSimpleReturn {\n const { data: walletClient } = useWalletClient({ chainId })\n const publicClient = usePublicClient({ chainId })\n\n const [isLoading, setIsLoading] = useState(false)\n const [result, setResult] = useState<DepositResult | undefined>()\n const [error, setError] = useState<Error | undefined>()\n\n const deposit = useCallback(\n async (amountInWei: bigint, receiver: `0x${string}`) => {\n if (!vault || !walletClient || !publicClient) return\n setIsLoading(true)\n setError(undefined)\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const res = await depositSimple(\n walletClient as any,\n asSdkClient(publicClient),\n { vault, hubChainId: chainId },\n amountInWei,\n receiver,\n )\n setResult(res)\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)))\n } finally {\n setIsLoading(false)\n }\n },\n [vault, walletClient, publicClient, chainId],\n )\n\n const reset = useCallback(() => {\n setResult(undefined)\n setError(undefined)\n setIsLoading(false)\n }, [])\n\n return {\n deposit,\n isLoading,\n txHash: result?.txHash,\n shares: result?.shares,\n error,\n reset,\n }\n}\n","import { useState, useCallback } from 'react'\nimport { usePublicClient, useWalletClient } from 'wagmi'\nimport { asSdkClient, redeemShares } from '../viem/index.js'\nimport type { RedeemResult } from '../viem/index.js'\n\ninterface UseRedeemSharesReturn {\n /** Execute redeemShares (R1 flow). */\n redeem: (sharesInWei: bigint, receiver: `0x${string}`, owner: `0x${string}`) => Promise<void>\n isLoading: boolean\n txHash: `0x${string}` | undefined\n /** Assets received. Available after tx confirmation. */\n assets: bigint | undefined\n error: Error | undefined\n reset: () => void\n}\n\n/**\n * Hook for standard ERC-4626 share redemption (R1 flow).\n *\n * Used for local and oracle-on cross-chain vaults.\n * No LZ fee required — single transaction.\n *\n * @example\n * const { redeem, isLoading, txHash, assets } = useRedeemShares('0xVAULT', 747)\n * await redeem(sharesInWei, userAddress, userAddress)\n */\nexport function useRedeemShares(\n vault: `0x${string}` | undefined,\n chainId: number,\n): UseRedeemSharesReturn {\n const { data: walletClient } = useWalletClient({ chainId })\n const publicClient = usePublicClient({ chainId })\n\n const [isLoading, setIsLoading] = useState(false)\n const [result, setResult] = useState<RedeemResult | undefined>()\n const [error, setError] = useState<Error | undefined>()\n\n const redeem = useCallback(\n async (sharesInWei: bigint, receiver: `0x${string}`, owner: `0x${string}`) => {\n if (!vault || !walletClient || !publicClient) return\n setIsLoading(true)\n setError(undefined)\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const res = await redeemShares(\n walletClient as any,\n asSdkClient(publicClient),\n { vault, hubChainId: chainId },\n sharesInWei,\n receiver,\n owner,\n )\n setResult(res)\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)))\n } finally {\n setIsLoading(false)\n }\n },\n [vault, walletClient, publicClient, chainId],\n )\n\n const reset = useCallback(() => {\n setResult(undefined)\n setError(undefined)\n setIsLoading(false)\n }, [])\n\n return {\n redeem,\n isLoading,\n txHash: result?.txHash,\n assets: result?.assets,\n error,\n reset,\n }\n}\n","import { useMemo } from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport type { Address, PublicClient } from 'viem'\nimport { getVaultDistribution } from '../viem/distribution.js'\nimport type { VaultDistribution } from '../viem/distribution.js'\nimport { createChainClient } from '../viem/spokeRoutes.js'\nimport { discoverVaultTopology } from '../viem/topology.js'\nimport type { VaultTopology } from '../viem/topology.js'\n\nexport type { VaultDistribution }\n\ninterface UseVaultDistributionReturn {\n distribution: VaultDistribution | undefined\n isLoading: boolean\n}\n\n/**\n * Read the full cross-chain capital distribution of a vault.\n *\n * Discovers the vault topology automatically via `discoverVaultTopology`\n * (works without a connected wallet), then creates hub and spoke clients\n * via public RPCs.\n *\n * Spoke reads that fail (bad RPC, timeout) degrade gracefully —\n * those spokes will appear with `isReachable: false`.\n *\n * @example\n * ```tsx\n * const { distribution, isLoading } = useVaultDistribution('0xVAULT')\n * if (distribution) {\n * console.log(`Hub liquid: ${distribution.hubLiquidBalance}`)\n * console.log(`Total actual: ${distribution.totalActual}`)\n * }\n * ```\n */\nexport function useVaultDistribution(\n vault: Address | undefined,\n): UseVaultDistributionReturn {\n // Step 1: discover topology (wallet-independent)\n const { data: topology } = useQuery<VaultTopology>({\n queryKey: ['vaultTopology', vault],\n queryFn: () => discoverVaultTopology(vault!),\n enabled: !!vault,\n staleTime: 5 * 60 * 1000,\n })\n\n // Build spoke clients from topology\n const spokeClients = useMemo((): Record<number, PublicClient> => {\n if (!topology) return {}\n const clients: Record<number, PublicClient> = {}\n for (const spokeChainId of topology.spokeChainIds) {\n const client = createChainClient(spokeChainId)\n if (client) clients[spokeChainId] = client as PublicClient\n }\n return clients\n }, [topology])\n\n // Step 2: fetch distribution using hub-chain client (not wallet client)\n const { data: distribution, isLoading } = useQuery<VaultDistribution>({\n queryKey: ['vaultDistribution', vault, topology?.hubChainId],\n queryFn: () => {\n const hubClient = createChainClient(topology!.hubChainId)\n if (!hubClient) throw new Error(`No public RPC for hub chainId ${topology!.hubChainId}`)\n return getVaultDistribution(hubClient as PublicClient, vault!, spokeClients)\n },\n enabled: !!vault && !!topology && topology.role !== 'local',\n staleTime: 30_000,\n })\n\n return { distribution, isLoading }\n}\n","import type { DepositResult, AsyncRequestResult, AsyncRequestStatusInfo } from '../viem/index.js'\nimport { useVaultStatus } from './useVaultStatus.js'\nimport { useOmniDeposit } from './useOmniDeposit.js'\nimport { useDepositSimple } from './useDepositSimple.js'\n\ninterface UseSmartDepositReturn {\n /**\n * Execute deposit using the correct flow for this vault's mode.\n * For async vaults: wraps depositAsync (D4) — returns guid for tracking.\n * For local/oracle vaults: wraps depositSimple (D1/D3) — returns shares.\n */\n deposit: (amountInWei: bigint, receiver: `0x${string}`) => Promise<void>\n isLoading: boolean\n txHash: `0x${string}` | undefined\n /** Shares minted (available for D1/D3 vaults after confirmation, undefined for D4). */\n shares: bigint | undefined\n /** GUID for cross-chain tracking (D4 vaults only). */\n guid: `0x${string}` | undefined\n /** Cross-chain request status (D4 vaults only). */\n requestStatus: AsyncRequestStatusInfo | undefined\n /** true when the wallet is connected to the wrong chain (D4 vaults only). */\n wrongChain: boolean\n /** Vault mode loaded from getVaultStatus. undefined while loading. */\n vaultMode: 'local' | 'cross-chain-oracle' | 'cross-chain-async' | 'paused' | 'full' | undefined\n error: Error | undefined\n reset: () => void\n}\n\n/**\n * Auto-selects the correct deposit flow based on vault mode.\n * Best for frontends that support multiple vault types.\n *\n * Internally uses useVaultStatus to detect the mode, then delegates to:\n * - useOmniDeposit (D4) for 'cross-chain-async' vaults\n * - useDepositSimple (D1/D3) for 'local' and 'cross-chain-oracle' vaults\n *\n * @example\n * const { deposit, isLoading, guid, requestStatus, vaultMode } = useSmartDeposit('0xVAULT', 747)\n *\n * if (vaultMode === 'paused') return <PausedBadge />\n *\n * await deposit(parseUnits('100', 6), userAddress)\n * // For async vaults: poll requestStatus until 'completed'\n * // For sync vaults: txHash + shares are available immediately\n */\nexport function useSmartDeposit(\n vault: `0x${string}` | undefined,\n hubChainId: number,\n): UseSmartDepositReturn {\n const { data: status } = useVaultStatus(vault, hubChainId)\n const omni = useOmniDeposit(vault, hubChainId)\n const simple = useDepositSimple(vault, hubChainId)\n\n const isAsync = status?.mode === 'cross-chain-async'\n\n const deposit = isAsync ? omni.deposit : simple.deposit\n\n return {\n deposit,\n isLoading: isAsync ? omni.isLoading : simple.isLoading,\n txHash: isAsync ? omni.txHash : simple.txHash,\n shares: isAsync ? undefined : simple.shares,\n guid: isAsync ? omni.guid : undefined,\n requestStatus: isAsync ? omni.requestStatus : undefined,\n wrongChain: isAsync ? omni.wrongChain : false,\n vaultMode: status?.mode,\n error: isAsync ? omni.error : simple.error,\n reset: isAsync ? omni.reset : simple.reset,\n }\n}\n","import type { AsyncRequestStatusInfo } from '../viem/index.js'\nimport { useVaultStatus } from './useVaultStatus.js'\nimport { useOmniRedeem } from './useOmniRedeem.js'\nimport { useRedeemShares } from './useRedeemShares.js'\n\ninterface UseSmartRedeemReturn {\n /**\n * Execute redeem using the correct flow for this vault's mode.\n * For async vaults: wraps redeemAsync (R5) — returns guid for tracking.\n * For local/oracle vaults: wraps redeemShares (R1) — returns assets.\n */\n redeem: (sharesInWei: bigint, receiver: `0x${string}`, owner: `0x${string}`) => Promise<void>\n isLoading: boolean\n txHash: `0x${string}` | undefined\n /** Assets received (available for R1 vaults after confirmation, undefined for R5). */\n assets: bigint | undefined\n /** GUID for cross-chain tracking (R5 vaults only). */\n guid: `0x${string}` | undefined\n /** Cross-chain request status (R5 vaults only). */\n requestStatus: AsyncRequestStatusInfo | undefined\n /** true when the wallet is connected to the wrong chain (R5 vaults only). */\n wrongChain: boolean\n /** Vault mode loaded from getVaultStatus. undefined while loading. */\n vaultMode: 'local' | 'cross-chain-oracle' | 'cross-chain-async' | 'paused' | 'full' | undefined\n error: Error | undefined\n reset: () => void\n}\n\n/**\n * Auto-selects the correct redeem flow based on vault mode.\n * Best for frontends that support multiple vault types.\n *\n * Internally uses useVaultStatus to detect the mode, then delegates to:\n * - useOmniRedeem (R5) for 'cross-chain-async' vaults\n * - useRedeemShares (R1) for 'local' and 'cross-chain-oracle' vaults\n *\n * @example\n * const { redeem, isLoading, guid, requestStatus, vaultMode } = useSmartRedeem('0xVAULT', 8453)\n *\n * if (vaultMode === 'paused') return <PausedBadge />\n *\n * await redeem(sharesInWei, userAddress, userAddress)\n * // For async vaults: poll requestStatus until 'completed'\n * // For sync vaults: txHash + assets are available immediately\n */\nexport function useSmartRedeem(\n vault: `0x${string}` | undefined,\n hubChainId: number,\n): UseSmartRedeemReturn {\n const { data: status } = useVaultStatus(vault, hubChainId)\n const omni = useOmniRedeem(vault, hubChainId)\n const simple = useRedeemShares(vault, hubChainId)\n\n const isAsync = status?.mode === 'cross-chain-async'\n\n const redeem = isAsync ? omni.redeem : simple.redeem\n\n return {\n redeem,\n isLoading: isAsync ? omni.isLoading : simple.isLoading,\n txHash: isAsync ? omni.txHash : simple.txHash,\n assets: isAsync ? undefined : simple.assets,\n guid: isAsync ? omni.guid : undefined,\n requestStatus: isAsync ? omni.requestStatus : undefined,\n wrongChain: isAsync ? omni.wrongChain : false,\n vaultMode: status?.mode,\n error: isAsync ? omni.error : simple.error,\n reset: isAsync ? omni.reset : simple.reset,\n }\n}\n","import { useQuery } from '@tanstack/react-query'\nimport type { Address } from 'viem'\nimport { getInboundRoutes, getUserBalancesForRoutes } from '../viem/spokeRoutes.js'\nimport type { InboundRouteWithBalance } from '../viem/spokeRoutes.js'\n\ninterface UseInboundRoutesReturn {\n routes: InboundRouteWithBalance[]\n isLoading: boolean\n error: Error | null\n}\n\n/**\n * Return the decimals typically used by a route's token symbol.\n *\n * Useful for formatting `userBalance` (a bigint in the token's smallest unit)\n * into a human-readable string.\n *\n * @example\n * ```ts\n * import { formatUnits } from 'viem'\n * const decimals = getRouteTokenDecimals(route.symbol)\n * const formatted = formatUnits(route.userBalance, decimals)\n * ```\n */\nexport function getRouteTokenDecimals(symbol: string): number {\n switch (symbol) {\n case 'stgUSDC':\n case 'USDT':\n case 'USDC':\n return 6\n default:\n return 18\n }\n}\n\n/**\n * Discover all valid inbound deposit routes for a vault and fetch the\n * connected user's token balance on each route's spoke chain.\n *\n * The hook is disabled until all four parameters are defined, so it is\n * safe to pass `undefined` during initial render.\n *\n * @example\n * ```tsx\n * const { routes, isLoading, error } = useInboundRoutes(\n * 8453, // hubChainId (Base)\n * '0xVAULT', // vault address\n * '0xASSET', // vault asset on hub\n * '0xUSER', // connected wallet\n * )\n *\n * for (const r of routes) {\n * const decimals = getRouteTokenDecimals(r.symbol)\n * console.log(`${r.symbol} on chain ${r.spokeChainId}: ${formatUnits(r.userBalance, decimals)}`)\n * }\n * ```\n */\nexport function useInboundRoutes(\n hubChainId: number | undefined,\n vault: Address | undefined,\n vaultAsset: Address | undefined,\n userAddress: Address | undefined,\n): UseInboundRoutesReturn {\n const enabled = hubChainId != null && !!vault && !!vaultAsset && !!userAddress\n\n const { data, isLoading, error } = useQuery<InboundRouteWithBalance[], Error>({\n queryKey: ['inboundRoutes', hubChainId, vault, vaultAsset, userAddress],\n queryFn: async () => {\n const routes = await getInboundRoutes(hubChainId!, vault!, vaultAsset!, userAddress!)\n return getUserBalancesForRoutes(routes, userAddress!)\n },\n enabled,\n staleTime: 60_000, // routes change infrequently — 1 min cache\n })\n\n return {\n routes: data ?? [],\n isLoading,\n error: error ?? null,\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/viem/chains.ts","../../src/viem/abis.ts","../../src/viem/types.ts","../../src/viem/errors.ts","../../src/viem/utils.ts","../../src/viem/spokeRoutes.ts","../../src/viem/topology.ts","../../src/viem/preflight.ts","../../src/viem/chainValidation.ts","../../src/viem/depositFlows.ts","../../src/viem/redeemFlows.ts","../../src/viem/userHelpers.ts","../../src/viem/distribution.ts","../../src/viem/wagmiCompat.ts","../../src/react/useVaultStatus.ts","../../src/react/useVaultMetadata.ts","../../src/react/useUserPosition.ts","../../src/react/useUserPositionMultiChain.ts","../../src/react/useLzFee.ts","../../src/react/useAsyncRequestStatus.ts","../../src/react/useVaultTopology.ts","../../src/react/useOmniDeposit.ts","../../src/react/useOmniRedeem.ts","../../src/react/useDepositSimple.ts","../../src/react/useRedeemShares.ts","../../src/react/useVaultDistribution.ts","../../src/react/useSmartDeposit.ts","../../src/react/useSmartRedeem.ts","../../src/react/useInboundRoutes.ts"],"names":["getAddress","zeroAddress","createPublicClient","http","fallback","localChainId","encodeAbiParameters","usePublicClient","useQuery","useChainId","useWalletClient","useState","useCallback","useMemo"],"mappings":"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","file":"index.cjs","sourcesContent":["/** EVM Chain IDs for chains supported by MoreVaults */\nexport const CHAIN_IDS = {\n flowEVMMainnet: 747,\n flowEVMTestnet: 545,\n arbitrum: 42161,\n base: 8453,\n ethereum: 1,\n optimism: 10,\n sonic: 146,\n bsc: 56,\n} as const\n\n/**\n * LayerZero Endpoint IDs (EID) for chains supported by MoreVaults.\n * Verified on-chain via MoreVaults OmniFactory.localEid() on each chain.\n * - flowMainnet: 30336 (0x7680) — confirmed from factory + LZ endpoint on Flow EVM mainnet\n * - base: 30184 (0x75e8) — confirmed from factory on Base\n * - arbitrum: 30110 (0x75b6) — confirmed from factory on Arbitrum\n * - ethereum: 30101 (0x75b5) — confirmed from factory on Ethereum\n * - optimism: 30111 — verified via LZ docs and on-chain quoteSend\n */\nexport const LZ_EIDS = {\n flowMainnet: 30336,\n flowTestnet: 30333,\n arbitrum: 30110,\n base: 30184,\n ethereum: 30101,\n optimism: 30111,\n sonic: 30332,\n bsc: 30102,\n} as const\n\n/** LayerZero EID → EVM Chain ID */\nexport const EID_TO_CHAIN_ID: Record<number, number> = {\n [LZ_EIDS.flowMainnet]: CHAIN_IDS.flowEVMMainnet,\n [LZ_EIDS.flowTestnet]: CHAIN_IDS.flowEVMTestnet,\n [LZ_EIDS.arbitrum]: CHAIN_IDS.arbitrum,\n [LZ_EIDS.base]: CHAIN_IDS.base,\n [LZ_EIDS.ethereum]: CHAIN_IDS.ethereum,\n [LZ_EIDS.optimism]: CHAIN_IDS.optimism,\n [LZ_EIDS.sonic]: CHAIN_IDS.sonic,\n [LZ_EIDS.bsc]: CHAIN_IDS.bsc,\n}\n\n/** EVM Chain ID → LayerZero EID */\nexport const CHAIN_ID_TO_EID: Record<number, number> = {\n [CHAIN_IDS.flowEVMMainnet]: LZ_EIDS.flowMainnet,\n [CHAIN_IDS.flowEVMTestnet]: LZ_EIDS.flowTestnet,\n [CHAIN_IDS.arbitrum]: LZ_EIDS.arbitrum,\n [CHAIN_IDS.base]: LZ_EIDS.base,\n [CHAIN_IDS.ethereum]: LZ_EIDS.ethereum,\n [CHAIN_IDS.optimism]: LZ_EIDS.optimism,\n [CHAIN_IDS.sonic]: LZ_EIDS.sonic,\n [CHAIN_IDS.bsc]: LZ_EIDS.bsc,\n}\n\n/**\n * LayerZero v2 OFT route config per asset symbol.\n *\n * Each entry maps chainId → { oft, token } where:\n * - `oft` = OFT contract to call send() on (pass as `spokeOFT` to depositFromSpoke)\n * - `token` = underlying ERC-20 the user approves before bridging\n * (zero address = native ETH, no approval needed)\n *\n * All routes verified on-chain via quoteSend() or peers(). Issuers vary per asset.\n */\nexport const OFT_ROUTES = {\n /**\n * stgUSDC — USDC bridged via Stargate v2.\n * Underlying on Eth/Arb/Base/Op: native USDC. On Flow: stgUSDC (Stargate's wrapped USDC).\n * Routes verified: Eth→Flow ✓ Arb→Flow ✓ Base→Flow ✓ Op→Flow ✓ Op→Base ✓ Op→Arb ✓\n */\n stgUSDC: {\n [747 /* flowEVMMainnet */]: { oft: '0xAF54BE5B6eEc24d6BFACf1cce4eaF680A8239398' as `0x${string}`, token: '0xF1815bd50389c46847f0Bda824eC8da914045D14' as `0x${string}` },\n [1 /* ethereum */]: { oft: '0xc026395860Db2d07ee33e05fE50ed7bD583189C7' as `0x${string}`, token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0xe8CDF27AcD73a434D661C84887215F7598e7d0d3' as `0x${string}`, token: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831' as `0x${string}` },\n [8453 /* base */]: { oft: '0x27a16dc786820B16E5c9028b75B99F6f604b5d26' as `0x${string}`, token: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' as `0x${string}` },\n [10 /* optimism */]: { oft: '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0' as `0x${string}`, token: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85' as `0x${string}` },\n [146 /* sonic */]: { oft: '0xA272fFe20cFfe769CdFc4b63088DCD2C82a2D8F9' as `0x${string}`, token: '0x29219dd400f2Bf60E5a23d13Be72B486D4038894' as `0x${string}` },\n },\n /**\n * USDT — USDT bridged via Stargate v2.\n * Routes verified: Arb→Flow ✓ Eth→Flow ✓ Op→Flow ✓ Op→Base ✓ Op→Arb ✓\n */\n USDT: {\n [747 /* flowEVMMainnet */]: { oft: '0xAf5191B0De278C7286d6C7CC6ab6BB8A73bA2Cd6' as `0x${string}`, token: '0x674843C06FF83502ddb4D37c2E09C01cdA38cbc8' as `0x${string}` },\n [1 /* ethereum */]: { oft: '0x933597a323Eb81cAe705C5bC29985172fd5A3973' as `0x${string}`, token: '0xdAC17F958D2ee523a2206206994597C13D831ec7' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0' as `0x${string}`, token: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9' as `0x${string}` },\n [10 /* optimism */]: { oft: '0x19cFCE47eD54a88614648DC3f19A5980097007dD' as `0x${string}`, token: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58' as `0x${string}` },\n },\n /**\n * PYUSD — PayPal USD OFT (issued by PayPal/Flow).\n * Routes verified: Eth→Flow ✓\n */\n PYUSD: {\n [747 /* flowEVMMainnet */]: { oft: '0x2aabea2058b5ac2d339b163c6ab6f2b6d53aabed' as `0x${string}`, token: '0x2aabea2058b5ac2d339b163c6ab6f2b6d53aabed' as `0x${string}` },\n [1 /* ethereum */]: { oft: '0xfa0e06b54986ad96de87a8c56fea76fbd8d493f8' as `0x${string}`, token: '0x6c3ea9036406852006290770BEdFcAbA0e23A0e8' as `0x${string}` },\n },\n /**\n * WFLOW — Wrapped FLOW NativeOFTAdapter (issued by Flow Foundation).\n * Routes verified: Eth→Flow ✓\n */\n WFLOW: {\n [747 /* flowEVMMainnet */]: { oft: '0xd296588850bee2770136464ffdddd78c32f2a07c' as `0x${string}`, token: '0xd296588850bee2770136464ffdddd78c32f2a07c' as `0x${string}` },\n [1 /* ethereum */]: { oft: '0xc1b45896b5fc9422a8f779653808297bb4f546f9' as `0x${string}`, token: '0x5c147e74D63B1D31AA3Fd78Eb229B65161983B2b' as `0x${string}` },\n },\n /**\n * WETH — ETH OFT via Stargate v2. underlying = native ETH (no approval needed).\n * Warning: Flow and Optimism routes error on quoteSend — do not use with those chains.\n */\n WETH: {\n [747 /* flowEVMMainnet */]: { oft: '0x45f1A95A4D3f3836523F5c83673c797f4d4d263B' as `0x${string}`, token: '0x2F6F07CDcf3588944Bf4C42aC74ff24bF56e7590' as `0x${string}` },\n [1 /* ethereum */]: { oft: '0x77b2043768d28E9C9aB44E1aBfC95944bcE57931' as `0x${string}`, token: '0x0000000000000000000000000000000000000000' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0xA45B5130f36CDcA45667738e2a258AB09f4A5f7F' as `0x${string}`, token: '0x0000000000000000000000000000000000000000' as `0x${string}` },\n [8453 /* base */]: { oft: '0xdc181Bd607330aeeBEF6ea62e03e5e1Fb4B6F7C7' as `0x${string}`, token: '0x0000000000000000000000000000000000000000' as `0x${string}` },\n },\n /**\n * sUSDe — Ethena staked USDe (yield-bearing stablecoin).\n * Pure OFT on Op/Arb/Base, OFTAdapter on Eth (wraps real sUSDe ERC4626).\n * Routes verified via peers(): Op↔Arb ✓ Op↔Eth ✓ Op↔Base ✓\n * No Flow peer.\n */\n sUSDe: {\n [1 /* ethereum */]: { oft: '0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2' as `0x${string}`, token: '0x9D39A5DE30e57443BfF2A8307A4256c8797A3497' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2' as `0x${string}`, token: '0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2' as `0x${string}` },\n [8453 /* base */]: { oft: '0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2' as `0x${string}`, token: '0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2' as `0x${string}` },\n [10 /* optimism */]: { oft: '0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2' as `0x${string}`, token: '0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2' as `0x${string}` },\n [56 /* bsc */]: { oft: '0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2' as `0x${string}`, token: '0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2' as `0x${string}` },\n },\n /**\n * USDe — Ethena USD stablecoin.\n * Pure OFT on Arb/Base/Op/BSC, OFTAdapter on Eth (wraps real USDe).\n * Routes verified via peers(): Arb↔Eth ✓ Arb↔Base ✓ BSC↔Op ✓ BSC↔Eth ✓ BSC↔Arb ✓\n * No Flow peer.\n */\n USDe: {\n [1 /* ethereum */]: { oft: '0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34' as `0x${string}`, token: '0x4c9EDD5852cd905f086C759E8383e09bff1E68B3' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34' as `0x${string}`, token: '0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34' as `0x${string}` },\n [8453 /* base */]: { oft: '0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34' as `0x${string}`, token: '0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34' as `0x${string}` },\n [10 /* optimism */]: { oft: '0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34' as `0x${string}`, token: '0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34' as `0x${string}` },\n [56 /* bsc */]: { oft: '0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34' as `0x${string}`, token: '0x5d3a1ff2b6bab83b63cd9ad0787074081a52ef34' as `0x${string}` },\n },\n /**\n * weETH — Ether.Fi liquid restaking token.\n * Pure OFT on Op/Base, OFTAdapter on Eth (wraps real weETH).\n * Routes verified via peers(): Op↔Eth ✓ Op↔Base ✓\n * No Flow or Arbitrum peer from Optimism.\n */\n weETH: {\n [1 /* ethereum */]: { oft: '0xcd2eb13d6831d4602d80e5db9230a57596cdca63' as `0x${string}`, token: '0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee' as `0x${string}` },\n [8453 /* base */]: { oft: '0x04c0599ae5a44757c0af6f9ec3b93da8976c150a' as `0x${string}`, token: '0x04c0599ae5a44757c0af6f9ec3b93da8976c150a' as `0x${string}` },\n [10 /* optimism */]: { oft: '0x5a7facb970d094b6c7ff1df0ea68d99e6e73cbff' as `0x${string}`, token: '0x5a7facb970d094b6c7ff1df0ea68d99e6e73cbff' as `0x${string}` },\n [56 /* bsc */]: { oft: '0x04c0599ae5a44757c0af6f9ec3b93da8976c150a' as `0x${string}`, token: '0x04c0599ae5a44757c0af6f9ec3b93da8976c150a' as `0x${string}` },\n [146 /* sonic */]: { oft: '0xa3d68b74bf0528fdd07263c60d6488749044914b' as `0x${string}`, token: '0xa3d68b74bf0528fdd07263c60d6488749044914b' as `0x${string}` },\n },\n /**\n * rsETH — Kelp DAO liquid restaking token.\n * Pure OFT on Op/Arb/Base, OFTAdapter on Eth (wraps real rsETH).\n * Routes verified via peers(): Op↔Eth ✓ Op↔Arb ✓ Op↔Base ✓\n * No Flow peer.\n */\n rsETH: {\n [1 /* ethereum */]: { oft: '0x85d456b2dff1fd8245387c0bfb64dfb700e98ef3' as `0x${string}`, token: '0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0x4186bfc76e2e237523cbc30fd220fe055156b41f' as `0x${string}`, token: '0x4186bfc76e2e237523cbc30fd220fe055156b41f' as `0x${string}` },\n [8453 /* base */]: { oft: '0x1bc71130a0e39942a7658878169764bbd8a45993' as `0x${string}`, token: '0x1bc71130a0e39942a7658878169764bbd8a45993' as `0x${string}` },\n [10 /* optimism */]: { oft: '0x4186bfc76e2e237523cbc30fd220fe055156b41f' as `0x${string}`, token: '0x4186bfc76e2e237523cbc30fd220fe055156b41f' as `0x${string}` },\n [146 /* sonic */]: { oft: '0xd75787ba9aba324420d522bda84c08c87e5099b1' as `0x${string}`, token: '0xd75787ba9aba324420d522bda84c08c87e5099b1' as `0x${string}` },\n },\n /**\n * rswETH — Swell Network liquid restaking token.\n * Pure OFT on Arb/Base, OFTAdapter on Eth (wraps real rswETH).\n * Routes verified via peers(): Arb↔Eth ✓ Arb↔Base ✓\n * No Flow or Optimism peer.\n */\n rswETH: {\n [1 /* ethereum */]: { oft: '0x1486d39646cdee84619bd05997319545a8575079' as `0x${string}`, token: '0xFAe103DC9cf190eD75350761e95403b7b8aFa6c0' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0xb1fe27b32ffb5ce54e272c096547f1e86c19e72f' as `0x${string}`, token: '0xb1fe27b32ffb5ce54e272c096547f1e86c19e72f' as `0x${string}` },\n [8453 /* base */]: { oft: '0x850cdf416668210ed0c36bfff5d21921c7ada3b8' as `0x${string}`, token: '0x850cdf416668210ed0c36bfff5d21921c7ada3b8' as `0x${string}` },\n },\n /**\n * USR — Resolv Labs USD stablecoin.\n * Pure OFT on Arb/Base, OFTAdapter on Eth.\n * Routes verified via peers(): Arb↔Eth ✓ Arb↔Base ✓\n * No Flow or Optimism peer.\n */\n USR: {\n [1 /* ethereum */]: { oft: '0xd2ee2776f34ef4e7325745b06e6d464b08d4be0e' as `0x${string}`, token: '0x66a1E37c9b0eAddca17d3662D6c05F4DECf3e110' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0x2492d0006411af6c8bbb1c8afc1b0197350a79e9' as `0x${string}`, token: '0x2492d0006411af6c8bbb1c8afc1b0197350a79e9' as `0x${string}` },\n [8453 /* base */]: { oft: '0x35e5db674d8e93a03d814fa0ada70731efe8a4b9' as `0x${string}`, token: '0x35e5db674d8e93a03d814fa0ada70731efe8a4b9' as `0x${string}` },\n [56 /* bsc */]: { oft: '0x2492d0006411af6c8bbb1c8afc1b0197350a79e9' as `0x${string}`, token: '0x2492d0006411af6c8bbb1c8afc1b0197350a79e9' as `0x${string}` },\n },\n /**\n * wstUSR — Resolv Labs wrapped staked USR (yield-bearing).\n * Pure OFT on Arb/Base, OFTAdapter on Eth.\n * Routes verified via peers(): Arb↔Eth ✓ Arb↔Base ✓\n * No Flow or Optimism peer.\n */\n wstUSR: {\n [1 /* ethereum */]: { oft: '0xab17c1fe647c37ceb9b96d1c27dd189bf8451978' as `0x${string}`, token: '0x1202F5C7b4B9E47a1A484E8B270be34dbbC75055' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0x66cfbd79257dc5217903a36293120282548e2254' as `0x${string}`, token: '0x66cfbd79257dc5217903a36293120282548e2254' as `0x${string}` },\n [8453 /* base */]: { oft: '0xb67675158b412d53fe6b68946483ba920b135ba1' as `0x${string}`, token: '0xb67675158b412d53fe6b68946483ba920b135ba1' as `0x${string}` },\n [56 /* bsc */]: { oft: '0x4254813524695def4163a169e901f3d7a1a55429' as `0x${string}`, token: '0x4254813524695def4163a169e901f3d7a1a55429' as `0x${string}` },\n },\n /**\n * USDtb — Ethena treasury-backed stablecoin.\n * Pure OFT on Arb/Base, OFTAdapter on Eth.\n * Routes verified via peers(): Arb↔Eth ✓ Arb↔Base ✓\n * No Flow or Optimism peer.\n */\n USDtb: {\n [1 /* ethereum */]: { oft: '0xc708b6887db46005da033501f8aebee72d191a5d' as `0x${string}`, token: '0xC139190F447e929f090Edeb554D95AbB8b18aC1C' as `0x${string}` },\n [42161 /* arbitrum */]: { oft: '0xc708b6887db46005da033501f8aebee72d191a5d' as `0x${string}`, token: '0xc708b6887db46005da033501f8aebee72d191a5d' as `0x${string}` },\n [8453 /* base */]: { oft: '0xc708b6887db46005da033501f8aebee72d191a5d' as `0x${string}`, token: '0xc708b6887db46005da033501f8aebee72d191a5d' as `0x${string}` },\n },\n} as const\n\n/**\n * oftCmd for Stargate v2 taxi mode (immediate per-message delivery).\n * Pass as `oftCmd` in SendParam when using stgUSDC, USDT, or WETH OFT_ROUTES entries.\n * Non-Stargate OFTs (PYUSD, WFLOW, sUSDe, USDe, weETH, rsETH) use empty bytes — pass `'0x'` instead.\n */\nexport const STARGATE_TAXI_CMD = '0x01' as const\n\n/**\n * Recommended timeouts for cross-chain operations (milliseconds).\n *\n * Based on real E2E tests:\n * - Standard OFT bridge (non-Stargate): ~5-10 min\n * - Stargate bridge: ~10-15 min, can reach 20 min under load\n * - LZ Read callback (async deposit/redeem): ~5-10 min\n * - Full spoke deposit (compose + oracle + share bridge): ~10-15 min\n * - Full spoke redeem (share bridge + async redeem + asset bridge): ~25-30 min\n *\n * UIs should show a progress indicator and NOT timeout before these values.\n */\nexport const LZ_TIMEOUTS = {\n /** Poll interval between balance/event checks */\n POLL_INTERVAL: 30_000,\n /** Standard OFT bridge (shares or assets, non-Stargate) */\n OFT_BRIDGE: 900_000, // 15 min\n /** Stargate bridge (USDC, USDT, WETH) — slower due to pool mechanics */\n STARGATE_BRIDGE: 1_800_000, // 30 min\n /** LZ Read callback (async vault actions) */\n LZ_READ_CALLBACK: 900_000, // 15 min\n /** Compose delivery to hub (deposit from spoke) */\n COMPOSE_DELIVERY: 2_700_000, // 45 min\n /** Full spoke→hub→spoke redeem (all steps combined) */\n FULL_SPOKE_REDEEM: 3_600_000, // 60 min\n} as const\n\n// ---------------------------------------------------------------------------\n// Legacy flat exports — kept for backwards compat, prefer OFT_ROUTES\n// ---------------------------------------------------------------------------\n\n/** @deprecated Use OFT_ROUTES.stgUSDC instead */\nexport const USDC_STARGATE_OFT: Partial<Record<number, `0x${string}`>> = Object.fromEntries(\n Object.entries(OFT_ROUTES.stgUSDC).map(([k, v]) => [k, v.oft])\n)\n/** @deprecated Use OFT_ROUTES.stgUSDC[chainId].token instead */\nexport const USDC_TOKEN: Partial<Record<number, `0x${string}`>> = Object.fromEntries(\n Object.entries(OFT_ROUTES.stgUSDC).map(([k, v]) => [k, v.token])\n)\n","/**\n * ABI fragments for MoreVaults SDK.\n * Extracted from compiled contract artifacts — only the selectors used by SDK flows.\n */\n\nexport const VAULT_ABI = [\n {\n type: 'function',\n name: 'deposit',\n inputs: [\n { name: 'assets', type: 'uint256' },\n { name: 'receiver', type: 'address' },\n ],\n outputs: [{ name: 'shares', type: 'uint256' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'deposit',\n inputs: [\n { name: 'tokens', type: 'address[]' },\n { name: 'assets', type: 'uint256[]' },\n { name: 'receiver', type: 'address' },\n { name: 'minAmountOut', type: 'uint256' },\n ],\n outputs: [{ name: 'shares', type: 'uint256' }],\n stateMutability: 'payable',\n },\n {\n type: 'function',\n name: 'mint',\n inputs: [\n { name: 'shares', type: 'uint256' },\n { name: 'receiver', type: 'address' },\n ],\n outputs: [{ name: 'assets', type: 'uint256' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'withdraw',\n inputs: [\n { name: 'assets', type: 'uint256' },\n { name: 'receiver', type: 'address' },\n { name: 'owner', type: 'address' },\n ],\n outputs: [{ name: 'shares', type: 'uint256' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'redeem',\n inputs: [\n { name: 'shares', type: 'uint256' },\n { name: 'receiver', type: 'address' },\n { name: 'owner', type: 'address' },\n ],\n outputs: [{ name: 'assets', type: 'uint256' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'requestRedeem',\n inputs: [\n { name: '_shares', type: 'uint256' },\n { name: '_onBehalfOf', type: 'address' },\n ],\n outputs: [],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'requestWithdraw',\n inputs: [\n { name: '_assets', type: 'uint256' },\n { name: '_onBehalfOf', type: 'address' },\n ],\n outputs: [],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'getWithdrawalRequest',\n inputs: [{ name: '_owner', type: 'address' }],\n outputs: [\n { name: 'shares', type: 'uint256' },\n { name: 'timelockEndsAt', type: 'uint256' },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'totalAssets',\n inputs: [],\n outputs: [{ name: '_totalAssets', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'totalSupply',\n inputs: [],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'balanceOf',\n inputs: [{ name: 'account', type: 'address' }],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'asset',\n inputs: [],\n outputs: [{ name: '', type: 'address' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'convertToShares',\n inputs: [{ name: 'assets', type: 'uint256' }],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'convertToAssets',\n inputs: [{ name: 'shares', type: 'uint256' }],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'previewDeposit',\n inputs: [{ name: 'assets', type: 'uint256' }],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'previewRedeem',\n inputs: [{ name: 'shares', type: 'uint256' }],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n] as const\n\nexport const BRIDGE_ABI = [\n {\n type: 'function',\n name: 'initVaultActionRequest',\n inputs: [\n { name: 'actionType', type: 'uint8' },\n { name: 'actionCallData', type: 'bytes' },\n { name: 'amountLimit', type: 'uint256' },\n { name: 'extraOptions', type: 'bytes' },\n ],\n outputs: [{ name: 'guid', type: 'bytes32' }],\n stateMutability: 'payable',\n },\n {\n type: 'function',\n name: 'getRequestInfo',\n inputs: [{ name: 'guid', type: 'bytes32' }],\n outputs: [\n {\n name: '',\n type: 'tuple',\n components: [\n { name: 'initiator', type: 'address' },\n { name: 'timestamp', type: 'uint64' },\n { name: 'actionType', type: 'uint8' },\n { name: 'actionCallData', type: 'bytes' },\n { name: 'fulfilled', type: 'bool' },\n { name: 'finalized', type: 'bool' },\n { name: 'refunded', type: 'bool' },\n { name: 'totalAssets', type: 'uint256' },\n { name: 'finalizationResult', type: 'uint256' },\n { name: 'amountLimit', type: 'uint256' },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'getFinalizationResult',\n inputs: [{ name: 'guid', type: 'bytes32' }],\n outputs: [{ name: 'result', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'quoteAccountingFee',\n inputs: [{ name: 'extraOptions', type: 'bytes' }],\n outputs: [{ name: 'nativeFee', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'oraclesCrossChainAccounting',\n inputs: [],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'view',\n },\n] as const\n\nexport const CONFIG_ABI = [\n {\n type: 'function',\n name: 'getEscrow',\n inputs: [],\n outputs: [{ name: 'escrow', type: 'address' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'getCrossChainAccountingManager',\n inputs: [],\n outputs: [{ name: '', type: 'address' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'isHub',\n inputs: [],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'getWithdrawalQueueStatus',\n inputs: [],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'getWithdrawalTimelock',\n inputs: [],\n outputs: [{ name: '', type: 'uint64' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'paused',\n inputs: [],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'maxDeposit',\n inputs: [{ name: 'receiver', type: 'address' }],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n] as const\n\nexport const ERC20_ABI = [\n {\n type: 'function',\n name: 'approve',\n inputs: [\n { name: 'spender', type: 'address' },\n { name: 'value', type: 'uint256' },\n ],\n outputs: [{ name: '', type: 'bool' }],\n stateMutability: 'nonpayable',\n },\n {\n type: 'function',\n name: 'allowance',\n inputs: [\n { name: 'owner', type: 'address' },\n { name: 'spender', type: 'address' },\n ],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'balanceOf',\n inputs: [{ name: 'account', type: 'address' }],\n outputs: [{ name: '', type: 'uint256' }],\n stateMutability: 'view',\n },\n] as const\n\n/**\n * Minimal ABI for reading ERC-20 / ERC-4626 token metadata.\n * Used to read name, symbol, and decimals from any token or vault.\n */\nexport const METADATA_ABI = [\n { type: 'function', name: 'name', inputs: [], outputs: [{ name: '', type: 'string' }], stateMutability: 'view' },\n { type: 'function', name: 'symbol', inputs: [], outputs: [{ name: '', type: 'string' }], stateMutability: 'view' },\n { type: 'function', name: 'decimals', inputs: [], outputs: [{ name: '', type: 'uint8' }], stateMutability: 'view' },\n] as const\n\n/**\n * Minimal OFT ABI for cross-chain bridging (LayerZero OFT standard).\n * Used by D6/D7 spoke-to-hub flows and R6 share bridging.\n */\nexport const OFT_ABI = [\n {\n type: 'function',\n name: 'send',\n inputs: [\n {\n name: '_sendParam',\n type: 'tuple',\n components: [\n { name: 'dstEid', type: 'uint32' },\n { name: 'to', type: 'bytes32' },\n { name: 'amountLD', type: 'uint256' },\n { name: 'minAmountLD', type: 'uint256' },\n { name: 'extraOptions', type: 'bytes' },\n { name: 'composeMsg', type: 'bytes' },\n { name: 'oftCmd', type: 'bytes' },\n ],\n },\n {\n name: '_fee',\n type: 'tuple',\n components: [\n { name: 'nativeFee', type: 'uint256' },\n { name: 'lzTokenFee', type: 'uint256' },\n ],\n },\n { name: '_refundAddress', type: 'address' },\n ],\n outputs: [\n {\n name: 'msgReceipt',\n type: 'tuple',\n components: [\n { name: 'guid', type: 'bytes32' },\n { name: 'nonce', type: 'uint64' },\n {\n name: 'fee',\n type: 'tuple',\n components: [\n { name: 'nativeFee', type: 'uint256' },\n { name: 'lzTokenFee', type: 'uint256' },\n ],\n },\n ],\n },\n {\n name: 'oftReceipt',\n type: 'tuple',\n components: [\n { name: 'amountSentLD', type: 'uint256' },\n { name: 'amountReceivedLD', type: 'uint256' },\n ],\n },\n ],\n stateMutability: 'payable',\n },\n {\n type: 'function',\n name: 'quoteSend',\n inputs: [\n {\n name: '_sendParam',\n type: 'tuple',\n components: [\n { name: 'dstEid', type: 'uint32' },\n { name: 'to', type: 'bytes32' },\n { name: 'amountLD', type: 'uint256' },\n { name: 'minAmountLD', type: 'uint256' },\n { name: 'extraOptions', type: 'bytes' },\n { name: 'composeMsg', type: 'bytes' },\n { name: 'oftCmd', type: 'bytes' },\n ],\n },\n { name: '_payInLzToken', type: 'bool' },\n ],\n outputs: [\n {\n name: 'msgFee',\n type: 'tuple',\n components: [\n { name: 'nativeFee', type: 'uint256' },\n { name: 'lzTokenFee', type: 'uint256' },\n ],\n },\n ],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'token',\n inputs: [],\n outputs: [{ name: '', type: 'address' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'peers',\n inputs: [{ name: '_eid', type: 'uint32' }],\n outputs: [{ name: '', type: 'bytes32' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'quoteOFT',\n inputs: [\n {\n name: '_sendParam',\n type: 'tuple',\n components: [\n { name: 'dstEid', type: 'uint32' },\n { name: 'to', type: 'bytes32' },\n { name: 'amountLD', type: 'uint256' },\n { name: 'minAmountLD', type: 'uint256' },\n { name: 'extraOptions', type: 'bytes' },\n { name: 'composeMsg', type: 'bytes' },\n { name: 'oftCmd', type: 'bytes' },\n ],\n },\n ],\n outputs: [\n {\n name: 'oftLimit',\n type: 'tuple',\n components: [\n { name: 'minAmountLD', type: 'uint256' },\n { name: 'maxAmountLD', type: 'uint256' },\n ],\n },\n {\n name: 'oftFeeDetails',\n type: 'tuple[]',\n components: [\n { name: 'feeAmountLD', type: 'int256' },\n { name: 'description', type: 'string' },\n ],\n },\n {\n name: 'oftReceipt',\n type: 'tuple',\n components: [\n { name: 'amountSentLD', type: 'uint256' },\n { name: 'amountReceivedLD', type: 'uint256' },\n ],\n },\n ],\n stateMutability: 'view',\n },\n] as const\n\n/**\n * Minimal LZ Endpoint V2 ABI for compose queue management.\n * Used by the Stargate 2-TX flow to check compose status and execute pending composes.\n */\nexport const LZ_ENDPOINT_ABI = [\n {\n type: 'function',\n name: 'composeQueue',\n inputs: [\n { name: 'from', type: 'address' },\n { name: 'to', type: 'address' },\n { name: 'guid', type: 'bytes32' },\n { name: 'index', type: 'uint16' },\n ],\n outputs: [{ name: 'messageHash', type: 'bytes32' }],\n stateMutability: 'view',\n },\n {\n type: 'function',\n name: 'lzCompose',\n inputs: [\n { name: '_from', type: 'address' },\n { name: '_to', type: 'address' },\n { name: '_guid', type: 'bytes32' },\n { name: '_index', type: 'uint16' },\n { name: '_message', type: 'bytes' },\n { name: '_extraData', type: 'bytes' },\n ],\n outputs: [],\n stateMutability: 'payable',\n },\n] as const","import type { Address, Hash, PublicClient, WalletClient } from 'viem'\n\nexport interface VaultAddresses {\n /** Hub vault address (diamond proxy) */\n vault: Address\n /** MoreVaultsEscrow — holds locked tokens during async cross-chain flows */\n escrow?: Address\n /** OFTAdapter for vault shares (cross-chain redeem only) */\n shareOFT?: Address\n /** OFT for USDC bridging (cross-chain deposits from spoke) */\n usdcOFT?: Address\n /**\n * Expected EVM chain ID of the hub. When provided, SDK functions will\n * throw a clear WrongChainError if the walletClient is on a different chain.\n * Prevents silent failures when MetaMask is connected to the wrong network.\n */\n hubChainId?: number\n}\n\nexport interface DepositResult {\n txHash: Hash\n shares: bigint\n}\n\nexport interface RedeemResult {\n txHash: Hash\n assets: bigint\n}\n\nexport interface AsyncRequestResult {\n txHash: Hash\n /** Cross-chain request GUID to track via getRequestInfo / getFinalizationResult */\n guid: `0x${string}`\n}\n\n/**\n * ActionType enum values matching MoreVaultsLib.ActionType on-chain.\n * DEPOSIT=0, MINT=1, WITHDRAW=2, REDEEM=3, MULTI_ASSETS_DEPOSIT=4, ACCRUE_FEES=5\n */\nexport const ActionType = {\n DEPOSIT: 0,\n MINT: 1,\n WITHDRAW: 2,\n REDEEM: 3,\n MULTI_ASSETS_DEPOSIT: 4,\n ACCRUE_FEES: 5,\n} as const\n\nexport type ActionTypeValue = (typeof ActionType)[keyof typeof ActionType]\n\n/**\n * Data needed to execute a pending LZ compose on the hub chain.\n * Returned by `depositFromSpoke` when the OFT is a Stargate V2 pool,\n * because Stargate cannot forward ETH to the compose executor.\n * The SDK user must call `executeCompose()` with this data as a second TX on the hub.\n */\nexport interface ComposeData {\n /** LZ Endpoint address on the hub chain */\n endpoint: Address\n /** The OFT/pool address that sent the compose (Stargate pool on hub) */\n from: Address\n /** MoreVaultsComposer address on the hub */\n to: Address\n /** LayerZero GUID from the original OFT.send() */\n guid: `0x${string}`\n /** Compose index (always 0 for single-compose messages) */\n index: number\n /** The full compose message bytes (reconstructed from composeMsg + OFT header) */\n message: `0x${string}`\n /** Whether this is a Stargate OFT that requires a 2-TX flow */\n isStargate: boolean\n /** Hub chain ID for creating the hub wallet/public client */\n hubChainId: number\n /** Hub block number just before TX1 was sent — used as search start for ComposeSent events */\n hubBlockStart: bigint\n}\n\n/**\n * Result from `depositFromSpoke`.\n * When `composeData` is present, the user must call `executeCompose()` on the hub chain.\n */\nexport interface SpokeDepositResult {\n txHash: Hash\n guid: `0x${string}`\n /** Present when OFT is Stargate V2 — user must execute compose on hub as TX2 */\n composeData?: ComposeData\n}\n\nexport interface CrossChainRequestInfo {\n initiator: Address\n timestamp: bigint\n actionType: number\n actionCallData: `0x${string}`\n fulfilled: boolean\n finalized: boolean\n refunded: boolean\n totalAssets: bigint\n finalizationResult: bigint\n amountLimit: bigint\n}\n","/**\n * Typed error classes for the MoreVaults SDK.\n *\n * Frontend code can use instanceof checks to handle errors programmatically:\n * catch (e) {\n * if (e instanceof InsufficientLiquidityError) { ... }\n * }\n */\n\nexport class MoreVaultsError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'MoreVaultsError'\n }\n}\n\nexport class VaultPausedError extends MoreVaultsError {\n constructor(vault: string) {\n super(`[MoreVaults] Vault ${vault} is paused. Cannot perform any actions.`)\n this.name = 'VaultPausedError'\n }\n}\n\nexport class CapacityFullError extends MoreVaultsError {\n constructor(vault: string) {\n super(`[MoreVaults] Vault ${vault} has reached deposit capacity. No more deposits accepted.`)\n this.name = 'CapacityFullError'\n }\n}\n\nexport class NotWhitelistedError extends MoreVaultsError {\n constructor(vault: string, user: string) {\n super(`[MoreVaults] Address ${user} is not whitelisted to deposit in vault ${vault}.`)\n this.name = 'NotWhitelistedError'\n }\n}\n\nexport class InsufficientLiquidityError extends MoreVaultsError {\n hubLiquid: bigint\n required: bigint\n constructor(vault: string, hubLiquid: bigint, required: bigint) {\n super(\n `[MoreVaults] Insufficient hub liquidity for redeem.\\n` +\n ` Hub liquid balance : ${hubLiquid}\\n` +\n ` Estimated required : ${required}\\n` +\n `Submitting this redeem will waste the LayerZero fee — the request will be auto-refunded.\\n` +\n `Ask the vault curator to repatriate liquidity from spoke chains first.`\n )\n this.name = 'InsufficientLiquidityError'\n this.hubLiquid = hubLiquid\n this.required = required\n }\n}\n\nexport class CCManagerNotConfiguredError extends MoreVaultsError {\n constructor(vault: string) {\n super(`[MoreVaults] CCManager not configured on vault ${vault}. Call setCrossChainAccountingManager(ccManagerAddress) as vault owner first.`)\n this.name = 'CCManagerNotConfiguredError'\n }\n}\n\nexport class EscrowNotConfiguredError extends MoreVaultsError {\n constructor(vault: string) {\n super(`[MoreVaults] Escrow not configured for vault ${vault}. The registry must have an escrow set for this vault.`)\n this.name = 'EscrowNotConfiguredError'\n }\n}\n\nexport class NotHubVaultError extends MoreVaultsError {\n constructor(vault: string) {\n super(`[MoreVaults] Vault ${vault} is not a hub vault. Async flows (D4/D5/R5) only work on hub vaults.`)\n this.name = 'NotHubVaultError'\n }\n}\n\nexport class MissingEscrowAddressError extends MoreVaultsError {\n constructor() {\n super(`[MoreVaults] This flow requires an escrow address. Set VaultAddresses.escrow before calling async deposit/redeem flows.`)\n this.name = 'MissingEscrowAddressError'\n }\n}\n\nexport class WrongChainError extends MoreVaultsError {\n constructor(currentChainId: number, expectedChainId: number) {\n super(\n `Wrong network: wallet is on chain ${currentChainId}, but the vault hub requires chain ${expectedChainId}. Switch networks before proceeding.`,\n )\n this.name = 'WrongChainError'\n }\n}\n","import {\n type Address,\n type Hash,\n type PublicClient,\n type WalletClient,\n getAddress,\n zeroAddress,\n} from 'viem'\nimport { BRIDGE_ABI, CONFIG_ABI, ERC20_ABI, VAULT_ABI, METADATA_ABI } from './abis'\nimport type { CrossChainRequestInfo } from './types'\n\n// ─────────────────────────────────────────────────────────────────────────────\n// TX receipt helper with retry — public RPCs can be slow, especially on Ethereum mainnet.\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Wait for a transaction receipt with generous timeout and retry logic.\n *\n * Public RPCs often timeout before the TX is mined. This helper retries\n * `waitForTransactionReceipt` up to 3 times with increasing timeouts,\n * so the SDK doesn't crash on slow RPCs.\n */\nexport async function waitForTx(\n publicClient: PublicClient,\n hash: Hash,\n maxRetries = 3,\n): Promise<void> {\n const timeouts = [60_000, 120_000, 180_000] // 1min, 2min, 3min\n for (let i = 0; i < maxRetries; i++) {\n try {\n await publicClient.waitForTransactionReceipt({\n hash,\n timeout: timeouts[i] ?? 180_000,\n })\n return\n } catch (e: any) {\n // If it's a timeout error, retry with longer timeout\n if (e.name === 'WaitForTransactionReceiptTimeoutError' && i < maxRetries - 1) {\n continue\n }\n throw e\n }\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type VaultMode =\n | 'local' // single-chain vault, no cross-chain\n | 'cross-chain-oracle' // hub with oracle-based accounting (sync)\n | 'cross-chain-async' // hub with off-chain accounting (async, D4/D5/R5)\n | 'paused' // vault is paused\n | 'full' // deposit capacity reached\n\nexport interface VaultStatus {\n /** Vault operating mode — determines which SDK flow to use */\n mode: VaultMode\n /** Which deposit function to call given the current configuration */\n recommendedDepositFlow: 'depositSimple' | 'depositAsync' | 'mintAsync' | 'none'\n /** Which redeem function to call given the current configuration */\n recommendedRedeemFlow: 'redeemShares' | 'redeemAsync' | 'none'\n\n // ── Configuration ────────────────────────────────────────────────────────\n isHub: boolean\n isPaused: boolean\n oracleAccountingEnabled: boolean\n\n /** address(0) means CCManager is not set — async flows will fail */\n ccManager: Address\n /** address(0) means escrow is not configured in the registry */\n escrow: Address\n\n // ── Withdrawal queue ─────────────────────────────────────────────────────\n withdrawalQueueEnabled: boolean\n /** Timelock duration in seconds (0 = no timelock) */\n withdrawalTimelockSeconds: bigint\n\n // ── Capacity ─────────────────────────────────────────────────────────────\n /**\n * Remaining deposit capacity in underlying token decimals.\n * `type(uint256).max` = no cap configured (unlimited).\n * `0n` = vault is full — no more deposits accepted.\n * If `depositAccessRestricted = true`, this value is `type(uint256).max` but\n * deposits are still gated by whitelist or other access control.\n */\n remainingDepositCapacity: bigint\n /**\n * True when `maxDeposit(address(0))` reverted, indicating the vault uses\n * whitelist or other access control to restrict who can deposit.\n * Deposit flows will succeed only for addresses the vault operator has approved.\n */\n depositAccessRestricted: boolean\n\n // ── Vault metrics ────────────────────────────────────────────────────────\n underlying: Address\n totalAssets: bigint\n totalSupply: bigint\n /** Vault share token decimals. Use this for display — never hardcode 18. */\n decimals: number\n /**\n * Price of 1 full share expressed in underlying token units.\n * = convertToAssets(10^decimals). Grows over time as the vault earns yield.\n */\n sharePrice: bigint\n /**\n * Underlying token balance held directly on the hub chain.\n * This is the only portion that can be paid out to redeeming users immediately.\n * (= ERC-20.balanceOf(vault) on the hub)\n */\n hubLiquidBalance: bigint\n /**\n * Approximate value deployed to spoke chains (totalAssets − hubLiquidBalance).\n * These funds are NOT immediately redeemable — the vault curator must\n * call executeBridging to repatriate them before large redeems can succeed.\n */\n spokesDeployedBalance: bigint\n /**\n * Maximum assets that can be redeemed right now without curator intervention.\n * - For hub vaults: equals `hubLiquidBalance` (only what the hub holds).\n * - For local/oracle vaults: equals `totalAssets` (all assets are local).\n * Attempting to redeem more than this will revert (R1) or be auto-refunded (R5).\n */\n maxImmediateRedeemAssets: bigint\n\n // ── Issues — empty when everything is correctly configured ───────────────\n /**\n * Human-readable list of configuration problems that would cause transactions\n * to fail. Empty array = vault is ready to use.\n */\n issues: string[]\n}\n\n/**\n * Read the full configuration and operational status of a vault in a single\n * multicall-friendly batch.\n *\n * Use this to:\n * - Determine which SDK flow to use (`recommendedDepositFlow`)\n * - Show a configuration checklist in an admin dashboard\n * - Surface `issues` to the developer before any transaction\n *\n * @param publicClient Public client for reads\n * @param vault Vault address (diamond proxy)\n * @returns Full vault status snapshot\n *\n * @example\n * ```ts\n * const status = await getVaultStatus(publicClient, VAULT)\n * if (status.issues.length) {\n * console.warn('Vault misconfigured:', status.issues)\n * }\n * // Use recommended flow:\n * if (status.recommendedDepositFlow === 'depositAsync') {\n * await depositAsync(walletClient, publicClient, { vault: VAULT, escrow: status.escrow }, ...)\n * }\n * ```\n */\nexport async function getVaultStatus(\n publicClient: PublicClient,\n vault: Address,\n): Promise<VaultStatus> {\n const v = getAddress(vault)\n\n // ── Batch 1: single multicall — 12 reads, 1 HTTP request ─────────────────\n // maxDeposit(address(0)) may revert on whitelisted vaults — allowFailure handles it.\n const b1 = await publicClient.multicall({\n contracts: [\n { address: v, abi: CONFIG_ABI, functionName: 'isHub' },\n { address: v, abi: CONFIG_ABI, functionName: 'paused' },\n { address: v, abi: BRIDGE_ABI, functionName: 'oraclesCrossChainAccounting' },\n { address: v, abi: CONFIG_ABI, functionName: 'getCrossChainAccountingManager' },\n { address: v, abi: CONFIG_ABI, functionName: 'getEscrow' },\n { address: v, abi: CONFIG_ABI, functionName: 'getWithdrawalQueueStatus' },\n { address: v, abi: CONFIG_ABI, functionName: 'getWithdrawalTimelock' },\n { address: v, abi: CONFIG_ABI, functionName: 'maxDeposit', args: [zeroAddress] },\n { address: v, abi: VAULT_ABI, functionName: 'asset' },\n { address: v, abi: VAULT_ABI, functionName: 'totalAssets' },\n { address: v, abi: VAULT_ABI, functionName: 'totalSupply' },\n { address: v, abi: METADATA_ABI, functionName: 'decimals' },\n ] as const,\n allowFailure: true,\n })\n\n const isHub = b1[0].status === 'success' ? b1[0].result as boolean : false\n const isPaused = b1[1].status === 'success' ? b1[1].result as boolean : false\n const oraclesEnabled = b1[2].status === 'success' ? b1[2].result as boolean : false\n const ccManager = b1[3].status === 'success' ? b1[3].result as Address : zeroAddress\n const escrow = b1[4].status === 'success' ? b1[4].result as Address : zeroAddress\n const withdrawalQueueEnabled = b1[5].status === 'success' ? b1[5].result as boolean : false\n const withdrawalTimelockSeconds = b1[6].status === 'success' ? b1[6].result as bigint : 0n\n // null = reverted (whitelist/ACL), bigint = normal return\n const maxDepositRaw = b1[7].status === 'success' ? b1[7].result as bigint : null\n const underlying = b1[8].status === 'success' ? b1[8].result as Address : zeroAddress\n const totalAssets = b1[9].status === 'success' ? b1[9].result as bigint : 0n\n const totalSupply = b1[10].status === 'success' ? b1[10].result as bigint : 0n\n const decimals = b1[11].status === 'success' ? Number(b1[11].result) : 18\n\n // ── Batch 2: depends on underlying + decimals from batch 1 ────────────────\n const oneShare = 10n ** BigInt(decimals)\n const b2 = await publicClient.multicall({\n contracts: [\n { address: getAddress(underlying), abi: ERC20_ABI, functionName: 'balanceOf', args: [v] },\n { address: v, abi: VAULT_ABI, functionName: 'convertToAssets', args: [oneShare] },\n ] as const,\n allowFailure: true,\n })\n\n const hubLiquidBalance = b2[0].status === 'success' ? b2[0].result as bigint : 0n\n const sharePrice = b2[1].status === 'success' ? b2[1].result as bigint : 0n\n\n const spokesDeployedBalance = totalAssets > hubLiquidBalance ? totalAssets - hubLiquidBalance : 0n\n\n // null = maxDeposit reverted.\n // For cross-chain-async hubs this is expected — the contract reverts with\n // NotAnERC4626CompatibleVault because maxDeposit is not meaningful in async mode.\n // Only treat the revert as \"whitelist/ACL\" when the vault is NOT a hub.\n const MAX_UINT256 = BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')\n const isCrossChainAsync = isHub && !oraclesEnabled\n const depositAccessRestricted = maxDepositRaw === null && !isCrossChainAsync\n const effectiveCapacity: bigint = (maxDepositRaw === null) ? MAX_UINT256 : maxDepositRaw\n\n // ── Derive mode ────────────────────────────────────────────────────────────\n let mode: VaultMode\n if (isPaused) {\n mode = 'paused'\n } else if (effectiveCapacity === 0n) {\n mode = 'full'\n } else if (!isHub) {\n mode = 'local'\n } else if (oraclesEnabled) {\n mode = 'cross-chain-oracle'\n } else {\n mode = 'cross-chain-async'\n }\n\n // ── Recommended flows ──────────────────────────────────────────────────────\n let recommendedDepositFlow: VaultStatus['recommendedDepositFlow']\n let recommendedRedeemFlow: VaultStatus['recommendedRedeemFlow']\n\n if (mode === 'paused' || mode === 'full') {\n recommendedDepositFlow = 'none'\n recommendedRedeemFlow = mode === 'paused' ? 'none' : 'redeemShares'\n } else if (mode === 'cross-chain-async') {\n recommendedDepositFlow = 'depositAsync'\n recommendedRedeemFlow = 'redeemAsync'\n } else {\n // local or cross-chain-oracle\n recommendedDepositFlow = 'depositSimple'\n recommendedRedeemFlow = 'redeemShares'\n }\n\n // ── maxImmediateRedeemAssets ───────────────────────────────────────────────\n const maxImmediateRedeemAssets = isHub && !oraclesEnabled ? hubLiquidBalance : totalAssets\n\n // ── Issues ─────────────────────────────────────────────────────────────────\n const issues: string[] = []\n\n if (isPaused) {\n issues.push('Vault is paused — no deposits or redeems are possible.')\n }\n if (effectiveCapacity === 0n && !isPaused) {\n issues.push('Deposit capacity is full — increase depositCapacity via setDepositCapacity().')\n }\n if (depositAccessRestricted) {\n issues.push('Deposit access is restricted (whitelist or other access control). Only approved addresses can deposit.')\n }\n if (isHub && !oraclesEnabled && ccManager === zeroAddress) {\n issues.push(\n 'CCManager not configured — async flows will revert. Call setCrossChainAccountingManager(address) as vault owner.',\n )\n }\n if (isHub && !oraclesEnabled && escrow === zeroAddress) {\n issues.push(\n 'Escrow not configured in registry — async flows will revert. Set the escrow via the MoreVaultsRegistry.',\n )\n }\n if (isHub) {\n if (hubLiquidBalance === 0n) {\n issues.push(\n `Hub has no liquid assets (hubLiquidBalance = 0). All redeems will be auto-refunded until the curator repatriates funds from spokes via executeBridging().`,\n )\n } else if (totalAssets > 0n && hubLiquidBalance * 10n < totalAssets) {\n const pct = Number((hubLiquidBalance * 10000n) / totalAssets) / 100\n issues.push(\n `Low hub liquidity: ${hubLiquidBalance} units liquid on hub (${pct.toFixed(1)}% of TVL). ` +\n `Redeems above ${hubLiquidBalance} underlying units will be auto-refunded. ` +\n `Curator must call executeBridging() to repatriate from spokes.`,\n )\n }\n if (spokesDeployedBalance > 0n) {\n const pct = ((Number(spokesDeployedBalance) / Number(totalAssets || 1n)) * 100).toFixed(1)\n issues.push(\n `${spokesDeployedBalance} units (~${pct}% of TVL) are deployed on spoke chains earning yield. ` +\n `These are NOT immediately redeemable — they require a curator repatriation (executeBridging) before users can withdraw them.`,\n )\n }\n }\n\n return {\n mode,\n recommendedDepositFlow,\n recommendedRedeemFlow,\n isHub,\n isPaused,\n oracleAccountingEnabled: oraclesEnabled,\n ccManager,\n escrow,\n withdrawalQueueEnabled,\n withdrawalTimelockSeconds: BigInt(withdrawalTimelockSeconds),\n remainingDepositCapacity: effectiveCapacity,\n depositAccessRestricted,\n underlying,\n totalAssets,\n totalSupply,\n decimals,\n sharePrice,\n hubLiquidBalance,\n spokesDeployedBalance,\n maxImmediateRedeemAssets,\n issues,\n }\n}\n\n/**\n * Ensure the spender has sufficient ERC-20 allowance; approve if not.\n *\n * Checks the current allowance and only sends an approve transaction if\n * the existing allowance is less than the required amount.\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads\n * @param token ERC-20 token address\n * @param spender Address to approve\n * @param amount Minimum required allowance\n */\nexport async function ensureAllowance(\n walletClient: WalletClient,\n publicClient: PublicClient,\n token: Address,\n spender: Address,\n amount: bigint,\n): Promise<void> {\n const account = walletClient.account!\n\n const allowance = await publicClient.readContract({\n address: getAddress(token),\n abi: ERC20_ABI,\n functionName: 'allowance',\n args: [account.address, getAddress(spender)],\n })\n\n if (allowance < amount) {\n const hash = await walletClient.writeContract({\n address: getAddress(token),\n abi: ERC20_ABI,\n functionName: 'approve',\n args: [getAddress(spender), amount],\n account,\n chain: walletClient.chain,\n })\n await waitForTx(publicClient, hash)\n }\n}\n\n/**\n * Quote the LayerZero native fee required for async vault actions.\n *\n * Call this before `depositAsync`, `mintAsync`, or `redeemAsync` to get the\n * exact `lzFee` (msg.value) needed.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address (diamond proxy)\n * @param extraOptions Optional LZ extra options bytes (default 0x)\n * @returns Required native fee in wei\n */\nexport async function quoteLzFee(\n publicClient: PublicClient,\n vault: Address,\n extraOptions: `0x${string}` = '0x',\n): Promise<bigint> {\n return publicClient.readContract({\n address: getAddress(vault),\n abi: BRIDGE_ABI,\n functionName: 'quoteAccountingFee',\n args: [extraOptions],\n })\n}\n\n/**\n * Check if a vault is operating in async mode (cross-chain hub with oracle OFF).\n *\n * When this returns `true`, deposits and redeems must use the async flows\n * (D4/D5/R5) which go through `initVaultActionRequest`.\n * When `false`, the vault either uses oracle-based accounting (sync) or is\n * a single-chain vault.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @returns `true` if the vault requires async cross-chain flows\n */\nexport async function isAsyncMode(\n publicClient: PublicClient,\n vault: Address,\n): Promise<boolean> {\n const v = getAddress(vault)\n\n // A vault is async if it's a hub AND oracle accounting is OFF\n const isHub = await publicClient.readContract({\n address: v,\n abi: CONFIG_ABI,\n functionName: 'isHub',\n })\n\n if (!isHub) return false\n\n const oraclesEnabled = await publicClient.readContract({\n address: v,\n abi: BRIDGE_ABI,\n functionName: 'oraclesCrossChainAccounting',\n })\n\n return !oraclesEnabled\n}\n\n/**\n * Poll for async request completion status.\n *\n * After calling an async flow (D4/D5/R5), use this to check whether the\n * LZ callback has resolved and `executeRequest` has been called.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @param guid Request GUID returned by the async flow\n * @returns Whether the request is fulfilled and the finalization result\n */\nexport async function getAsyncRequestStatus(\n publicClient: PublicClient,\n vault: Address,\n guid: `0x${string}`,\n): Promise<{ fulfilled: boolean; finalized: boolean; refunded: boolean; result: bigint }> {\n const info = (await publicClient.readContract({\n address: getAddress(vault),\n abi: BRIDGE_ABI,\n functionName: 'getRequestInfo',\n args: [guid],\n })) as unknown as CrossChainRequestInfo\n\n const finalizationResult = await publicClient.readContract({\n address: getAddress(vault),\n abi: BRIDGE_ABI,\n functionName: 'getFinalizationResult',\n args: [guid],\n })\n\n return {\n fulfilled: info.fulfilled,\n finalized: info.finalized,\n refunded: info.refunded,\n result: finalizationResult,\n }\n}\n\nexport interface AsyncRequestFinalResult {\n /** 'completed' = assets/shares received, 'refunded' = tokens returned to user */\n status: 'completed' | 'refunded'\n /** For deposit: shares minted. For redeem: assets returned. 0 if refunded. */\n result: bigint\n}\n\n/**\n * Poll an async cross-chain request until it finalizes or times out.\n *\n * This is the correct way to wait for smartDeposit/smartRedeem results on\n * async vaults. Do NOT poll balance — use this instead, which reads the\n * on-chain request state by GUID.\n *\n * @param publicClient Public client on the hub chain\n * @param vault Vault address\n * @param guid GUID from smartDeposit/smartRedeem result\n * @param pollInterval Milliseconds between polls (default: 30_000)\n * @param timeout Max wait time in milliseconds (default: 900_000 = 15 min)\n * @param onPoll Optional callback invoked after each poll with current status\n * @returns Final result with status and amount\n * @throws Error if timeout is reached\n *\n * @example\n * const depositResult = await smartDeposit(walletClient, publicClient, { vault }, amount, receiver)\n * if ('guid' in depositResult) {\n * const final = await waitForAsyncRequest(publicClient, vault, depositResult.guid, 30_000, 900_000, (s) => {\n * console.log(`Status: fulfilled=${s.fulfilled}, finalized=${s.finalized}`)\n * })\n * console.log(`Done: ${final.status}, result: ${final.result}`)\n * }\n */\nexport async function waitForAsyncRequest(\n publicClient: PublicClient,\n vault: Address,\n guid: `0x${string}`,\n pollInterval: number = 30_000,\n timeout: number = 900_000,\n onPoll?: (status: { fulfilled: boolean; finalized: boolean; refunded: boolean; result: bigint }) => void,\n): Promise<AsyncRequestFinalResult> {\n const deadline = Date.now() + timeout\n\n while (Date.now() < deadline) {\n const status = await getAsyncRequestStatus(publicClient, vault, guid)\n\n if (onPoll) onPoll(status)\n\n if (status.finalized) {\n return { status: 'completed', result: status.result }\n }\n if (status.refunded) {\n return { status: 'refunded', result: 0n }\n }\n\n await new Promise(r => setTimeout(r, pollInterval))\n }\n\n throw new Error(\n `[MoreVaults] Async request ${guid} did not finalize within ${timeout / 1000}s. ` +\n `The request may still complete — check https://layerzeroscan.com/tx/${guid}`,\n )\n}\n","import { type Address, createPublicClient, http, fallback, getAddress, zeroAddress } from 'viem'\nimport { OFT_ROUTES, CHAIN_ID_TO_EID } from './chains'\nimport { OFT_ABI, ERC20_ABI } from './abis'\nimport { getVaultTopology } from './topology'\nimport { isAsyncMode, quoteLzFee } from './utils'\n\nexport interface OutboundRoute {\n /** Chain ID where user can receive shares/assets */\n chainId: number\n /** Whether this chain is the hub (direct redeem) or a spoke (shares bridged back) */\n routeType: 'hub' | 'spoke'\n /** LZ EID for this chain */\n eid: number\n /** Native gas symbol */\n nativeSymbol: string\n}\n\n/**\n * Multiple public RPC endpoints per chain — tried in order via viem fallback transport.\n * First entry is preferred; subsequent entries are used if the first fails or times out.\n */\nconst PUBLIC_RPCS: Partial<Record<number, string[]>> = {\n 1: [\n 'https://ethereum-rpc.publicnode.com',\n 'https://ethereum.publicnode.com',\n 'https://eth.drpc.org',\n 'https://eth-mainnet.public.blastapi.io',\n 'https://0xrpc.io/eth',\n 'https://eth.llamarpc.com',\n ],\n 10: [\n 'https://mainnet.optimism.io',\n 'https://optimism-rpc.publicnode.com',\n 'https://op.drpc.org',\n ],\n 42161: [\n 'https://arbitrum-one-rpc.publicnode.com',\n 'https://arbitrum.publicnode.com',\n 'https://arbitrum.public.blockpi.network/v1/rpc/public',\n 'https://public-arb-mainnet.fastnode.io',\n ],\n 8453: [\n 'https://base-rpc.publicnode.com',\n 'https://base.llamarpc.com',\n 'https://base.drpc.org',\n 'https://mainnet.base.org',\n 'https://1rpc.io/base',\n 'https://base.rpc.subquery.network/public',\n ],\n 747: [\n 'https://mainnet.evm.nodes.onflow.org',\n ],\n 146: [\n 'https://rpc.soniclabs.com',\n 'https://sonic.drpc.org',\n ],\n 56: [\n 'https://bsc-dataseed1.binance.org',\n 'https://bsc-dataseed2.binance.org',\n 'https://bsc-rpc.publicnode.com',\n ],\n}\n\n// multicall3 is deployed at the same deterministic address on all supported chains\nconst MULTICALL3_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11' as const\n\n/** Returns a viem transport (factory) for a given chain ID, or null if not supported */\nexport function createChainTransport(chainId: number) {\n const rpcs = PUBLIC_RPCS[chainId]\n if (!rpcs?.length) return null\n return rpcs.length === 1 ? http(rpcs[0]) : fallback(rpcs.map(url => http(url)))\n}\n\n/** Create a public client with fallback transport for a given chain ID */\nexport function createChainClient(chainId: number) {\n const rpcs = PUBLIC_RPCS[chainId]\n if (!rpcs?.length) return null\n return createPublicClient({\n chain: {\n id: chainId,\n name: `chain-${chainId}`,\n nativeCurrency: { name: 'ETH', symbol: 'ETH', decimals: 18 },\n rpcUrls: { default: { http: rpcs as [string, ...string[]] } },\n contracts: { multicall3: { address: MULTICALL3_ADDRESS } },\n },\n transport: rpcs.length === 1 ? http(rpcs[0]) : fallback(rpcs.map(url => http(url))),\n })\n}\n\nconst SYMBOL_ABI = [{ name: 'symbol', type: 'function', stateMutability: 'view', inputs: [], outputs: [{ type: 'string' }] }] as const\n\n/** Read ERC20 symbol() on-chain. Falls back to `fallback` if the call fails. */\nasync function readTokenSymbol(client: ReturnType<typeof createChainClient>, token: Address, fallbackSymbol: string): Promise<string> {\n if (!client) return fallbackSymbol\n try {\n return await client.readContract({ address: token, abi: SYMBOL_ABI, functionName: 'symbol' })\n } catch {\n return fallbackSymbol\n }\n}\n\n/** @deprecated use PUBLIC_RPCS — kept for backwards compat in internal checks */\nconst PUBLIC_RPC: Partial<Record<number, string>> = Object.fromEntries(\n Object.entries(PUBLIC_RPCS).map(([k, v]) => [k, v![0]])\n)\n\n/** Native gas token symbol per chain ID — lzFeeEstimate is denominated in this token */\nexport const NATIVE_SYMBOL: Partial<Record<number, string>> = {\n 1: 'ETH',\n 10: 'ETH',\n 42161: 'ETH',\n 8453: 'ETH',\n 747: 'FLOW',\n 146: 'S',\n 56: 'BNB',\n}\n\nexport interface InboundRoute {\n /** Internal route identifier from OFT_ROUTES (e.g. 'stgUSDC') — do NOT show to users */\n symbol: string\n /** Chain ID where user sends from */\n spokeChainId: number\n /**\n * How the deposit is executed:\n * - 'direct' → user is on the hub chain, vault uses standard ERC-4626 (depositSimple). No LZ fee.\n * - 'direct-async' → user is on the hub chain, vault uses async accounting (depositAsync). LZ fee required.\n * - 'oft-compose' → user is on a spoke chain, use depositFromSpoke via OFT compose. LZ fee required.\n */\n depositType: 'direct' | 'direct-async' | 'oft-compose'\n /** OFT contract on spoke chain — pass as `spokeOFT` to depositFromSpoke. Null for direct deposits. */\n spokeOft: Address | null\n /** Token user must approve on spoke chain (zeroAddress = native ETH) */\n spokeToken: Address\n /**\n * Human-readable symbol of the token the user needs to hold on the spoke chain.\n * For OFTAdapters this is the underlying token symbol (e.g. 'USDC', 'weETH').\n * For pure OFTs this is the OFT's own symbol (e.g. 'sUSDe', 'USDe').\n * Use this — not `symbol` — when displaying the token name to users.\n */\n sourceTokenSymbol: string\n /** OFT contract on hub chain — receives tokens for the composer. Null for direct deposits. */\n hubOft: Address | null\n /** oftCmd to use in SendParam (0x01 for Stargate taxi, 0x for standard OFT) */\n oftCmd: `0x${string}`\n /** LZ fee estimate in native wei of the SPOKE chain (not always ETH — e.g. FLOW on Flow EVM) */\n lzFeeEstimate: bigint\n /** Native gas token symbol for the spoke chain — use this when displaying the fee */\n nativeSymbol: string\n}\n\nexport interface InboundRouteWithBalance extends InboundRoute {\n /** User's token balance on the spoke chain */\n userBalance: bigint\n}\n\n/**\n * Find all valid OFT inbound routes for a vault.\n *\n * Only returns routes for chains where the vault has a registered spoke —\n * this is required so the composer can send shares back to the user's chain.\n * The hub chain is always included as a 'direct' deposit option.\n *\n * Routes that revert on quoteSend() (no liquidity, no peer) are excluded.\n *\n * @param hubChainId Chain ID of the vault hub (e.g. 8453 for Base)\n * @param vault Vault address (to resolve registered spoke chains)\n * @param vaultAsset vault.asset() address on the hub chain\n * @param userAddress User address (used as receiver for fee quote)\n */\nexport async function getInboundRoutes(\n hubChainId: number,\n vault: Address,\n vaultAsset: Address,\n userAddress: Address,\n): Promise<InboundRoute[]> {\n const hubEid = CHAIN_ID_TO_EID[hubChainId]\n if (!hubEid) throw new Error(`No LZ EID for hub chainId ${hubChainId}`)\n\n // Fetch vault topology to get registered spoke chains\n const hubClient = createChainClient(hubChainId)\n if (!hubClient) throw new Error(`No public RPC for hub chainId ${hubChainId}`)\n const topology = await getVaultTopology(hubClient, vault)\n const registeredSpokes = new Set(topology.spokeChainIds)\n\n const results: InboundRoute[] = []\n\n for (const [symbol, chainMap] of Object.entries(OFT_ROUTES)) {\n const hubEntry = (chainMap as Record<number, { oft: string; token: string }>)[hubChainId]\n if (!hubEntry) continue\n\n // Does this OFT deliver the right asset to the hub?\n if (getAddress(hubEntry.token) !== getAddress(vaultAsset)) continue\n\n // oftCmd for OFT compose deposits: always '0x' (TAXI mode = immediate delivery with composeMsg).\n // Stargate V2 semantics: '0x' = TAXI (supports composeMsg), '0x01' = BUS (no composeMsg).\n // depositFromSpoke internally uses resolveOftCmd() which returns '0x' — match that here.\n const oftCmd: `0x${string}` = '0x'\n\n // Only check chains where the vault has a registered spoke\n // (composer needs to send shares back — requires a spoke vault on that chain)\n const spokesToCheck = Object.keys(chainMap)\n .map(Number)\n .filter(id => id !== hubChainId && registeredSpokes.has(id))\n\n await Promise.allSettled(\n spokesToCheck.map(async (spokeChainId) => {\n const spokeEntry = (chainMap as Record<number, { oft: string; token: string }>)[spokeChainId]\n if (!spokeEntry) return\n\n const client = createChainClient(spokeChainId)\n if (!client) return\n\n // Validate route via quoteSend — if it reverts, skip\n try {\n const receiverBytes32 = `0x${getAddress(userAddress).slice(2).padStart(64, '0')}` as `0x${string}`\n const spokeTokenAddr = getAddress(spokeEntry.token) as Address\n const [fee, sourceTokenSymbol] = await Promise.all([\n client.readContract({\n address: getAddress(spokeEntry.oft) as Address,\n abi: OFT_ABI,\n functionName: 'quoteSend',\n args: [{\n dstEid: hubEid,\n to: receiverBytes32,\n amountLD: 1_000_000n,\n minAmountLD: 0n,\n extraOptions: '0x',\n composeMsg: '0x',\n oftCmd,\n }, false],\n }),\n readTokenSymbol(client, spokeTokenAddr, symbol),\n ])\n\n results.push({\n symbol,\n spokeChainId,\n depositType: 'oft-compose',\n spokeOft: getAddress(spokeEntry.oft) as Address,\n spokeToken: spokeTokenAddr,\n sourceTokenSymbol,\n hubOft: getAddress(hubEntry.oft) as Address,\n oftCmd,\n lzFeeEstimate: fee.nativeFee,\n nativeSymbol: NATIVE_SYMBOL[spokeChainId] ?? 'ETH',\n })\n } catch {\n // Route not available — skip silently\n }\n })\n )\n }\n\n // Add the hub chain itself as a deposit option.\n // For async vaults the vault uses depositAsync which requires a LZ fee even on the hub chain.\n const [asyncMode, ...hubOftEntries] = await Promise.all([\n isAsyncMode(hubClient, vault),\n ...Object.entries(OFT_ROUTES).map(async ([symbol, chainMap]) => {\n const hubEntry = (chainMap as Record<number, { oft: string; token: string }>)[hubChainId]\n if (!hubEntry || getAddress(hubEntry.token) !== getAddress(vaultAsset)) return null\n return { symbol, hubEntry }\n }),\n ])\n\n const hubOftEntry = hubOftEntries.find((e) => e !== null) ?? null\n\n if (hubOftEntry) {\n const { symbol, hubEntry } = hubOftEntry\n const hubTokenAddr = getAddress(hubEntry.token) as Address\n const [sourceTokenSymbol, lzFeeEstimate] = await Promise.all([\n readTokenSymbol(hubClient, hubTokenAddr, symbol),\n asyncMode ? quoteLzFee(hubClient, vault) : Promise.resolve(0n),\n ])\n results.unshift({\n symbol,\n spokeChainId: hubChainId,\n depositType: asyncMode ? 'direct-async' : 'direct',\n spokeOft: null,\n spokeToken: hubTokenAddr,\n sourceTokenSymbol,\n hubOft: null,\n oftCmd: '0x',\n lzFeeEstimate,\n nativeSymbol: NATIVE_SYMBOL[hubChainId] ?? 'ETH',\n })\n }\n\n return results\n}\n\n/**\n * Fetch user token balances for each inbound route in parallel.\n * Routes with native ETH as token (zeroAddress) return the chain's ETH balance.\n */\nexport async function getUserBalancesForRoutes(\n routes: InboundRoute[],\n userAddress: Address,\n): Promise<InboundRouteWithBalance[]> {\n return Promise.all(\n routes.map(async (route) => {\n const client = createChainClient(route.spokeChainId)\n if (!client) return { ...route, userBalance: 0n }\n\n try {\n let userBalance: bigint\n\n if (route.spokeToken === zeroAddress) {\n userBalance = await client.getBalance({ address: getAddress(userAddress) as Address })\n } else {\n userBalance = await client.readContract({\n address: route.spokeToken,\n abi: ERC20_ABI,\n functionName: 'balanceOf',\n args: [getAddress(userAddress) as Address],\n })\n }\n\n return { ...route, userBalance }\n } catch {\n return { ...route, userBalance: 0n }\n }\n })\n )\n}\n\n/**\n * Find all outbound routes for a vault — chains where a user can receive\n * shares/assets when redeeming.\n *\n * The hub chain is always first (direct redeem). Spoke chains follow\n * (shares are bridged back via the composer).\n *\n * @param hubChainId Chain ID of the vault hub (e.g. 8453 for Base)\n * @param vault Vault address (to resolve registered spoke chains)\n */\nexport async function getOutboundRoutes(\n hubChainId: number,\n vault: Address,\n): Promise<OutboundRoute[]> {\n const hubEid = CHAIN_ID_TO_EID[hubChainId]\n if (!hubEid) throw new Error(`No LZ EID for hub chainId ${hubChainId}`)\n\n const hubClient = createChainClient(hubChainId)\n if (!hubClient) throw new Error(`No public RPC for hub chainId ${hubChainId}`)\n\n const topology = await getVaultTopology(hubClient, vault)\n\n const routes: OutboundRoute[] = [\n {\n chainId: hubChainId,\n routeType: 'hub',\n eid: hubEid,\n nativeSymbol: NATIVE_SYMBOL[hubChainId] ?? 'ETH',\n },\n ]\n\n for (const spokeChainId of topology.spokeChainIds) {\n const eid = CHAIN_ID_TO_EID[spokeChainId]\n if (!eid) continue\n\n routes.push({\n chainId: spokeChainId,\n routeType: 'spoke',\n eid,\n nativeSymbol: NATIVE_SYMBOL[spokeChainId] ?? 'ETH',\n })\n }\n\n return routes\n}\n\n/**\n * Quote the LayerZero native fee for a cross-chain deposit with a real amount.\n *\n * More precise than the `lzFeeEstimate` field on `InboundRoute`, which uses\n * a dummy 1 USDC amount.\n *\n * @param route An InboundRoute from `getInboundRoutes()`\n * @param hubChainId Chain ID of the vault hub (needed for LZ destination EID)\n * @param amount Real deposit amount in token decimals\n * @param userAddress User address (used as receiver for fee quote)\n * @returns Native fee in wei of the spoke chain's gas token, or 0n for direct deposits\n */\nexport async function quoteRouteDepositFee(\n route: InboundRoute,\n hubChainId: number,\n amount: bigint,\n userAddress: Address,\n): Promise<bigint> {\n if (route.depositType === 'direct') return 0n\n\n const hubEid = CHAIN_ID_TO_EID[hubChainId]\n if (!hubEid) throw new Error(`No LZ EID for hub chainId ${hubChainId}`)\n\n if (!route.spokeOft) throw new Error('Route is oft-compose but spokeOft is null')\n\n const client = createChainClient(route.spokeChainId)\n if (!client) throw new Error(`No public RPC for spoke chainId ${route.spokeChainId}`)\n\n const receiverBytes32 = `0x${getAddress(userAddress).slice(2).padStart(64, '0')}` as `0x${string}`\n const fee = await client.readContract({\n address: route.spokeOft,\n abi: OFT_ABI,\n functionName: 'quoteSend',\n args: [{\n dstEid: hubEid,\n to: receiverBytes32,\n amountLD: amount,\n minAmountLD: 0n,\n extraOptions: '0x',\n composeMsg: '0x',\n oftCmd: route.oftCmd,\n }, false],\n })\n\n return fee.nativeFee\n}\n","import { type Address, type PublicClient, getAddress } from 'viem'\nimport { EID_TO_CHAIN_ID, CHAIN_ID_TO_EID, CHAIN_IDS } from './chains'\nimport { createChainClient } from './spokeRoutes'\n\n// MoreVaults OMNI factory — same address on every supported chain (CREATE3)\nexport const OMNI_FACTORY_ADDRESS: Address = '0x7bDB8B17604b03125eFAED33cA0c55FBf856BB0C'\n\nconst FACTORY_ABI = [\n {\n name: 'localEid',\n type: 'function',\n inputs: [],\n outputs: [{ type: 'uint32' }],\n stateMutability: 'view',\n },\n {\n name: 'isCrossChainVault',\n type: 'function',\n inputs: [{ name: '__eid', type: 'uint32' }, { name: '_vault', type: 'address' }],\n outputs: [{ type: 'bool' }],\n stateMutability: 'view',\n },\n {\n name: 'hubToSpokes',\n type: 'function',\n inputs: [{ name: '__eid', type: 'uint32' }, { name: '_hubVault', type: 'address' }],\n outputs: [{ name: 'eids', type: 'uint32[]' }, { name: 'vaults', type: 'address[]' }],\n stateMutability: 'view',\n },\n {\n name: 'spokeToHub',\n type: 'function',\n inputs: [{ name: '__eid', type: 'uint32' }, { name: '_spokeVault', type: 'address' }],\n outputs: [{ name: 'eid', type: 'uint32' }, { name: 'vault', type: 'address' }],\n stateMutability: 'view',\n },\n] as const\n\nexport interface VaultTopology {\n /**\n * Role of this vault on the chain you queried:\n * - 'hub' → this chain holds the TVL, users deposit here\n * - 'spoke' → this chain is a yield deployment; deposits go to the hub\n * - 'local' → single-chain vault, no cross-chain setup\n */\n role: 'hub' | 'spoke' | 'local'\n\n /** Chain ID where the hub lives. Same as the queried chain when role='hub'. */\n hubChainId: number\n\n /**\n * All spoke chain IDs registered under this hub.\n * Empty when role='local'.\n * Since vaults are CREATE3-deployed, the vault address is the same on all chains.\n */\n spokeChainIds: number[]\n}\n\n/**\n * Resolve the cross-chain topology of a vault: hub chain + all spoke chains.\n *\n * Works for hub vaults, spoke vaults, and local (single-chain) vaults.\n * Because MoreVaults uses CREATE3, the vault address is identical on every chain —\n * only the chain IDs differ.\n *\n * @param publicClient Connected to the chain you want to inspect\n * @param vault Vault address (same on all chains)\n * @param factoryAddress MoreVaults factory (defaults to the known OMNI_FACTORY_ADDRESS)\n *\n * @example\n * // Querying from Base — will detect hub + Ethereum/Arbitrum spokes\n * const topo = await getVaultTopology(baseClient, '0x8f740...')\n * // { role: 'hub', hubChainId: 8453, spokeChainIds: [1, 42161] }\n *\n * // Querying from Ethereum — same vault is a spoke there\n * const topo = await getVaultTopology(ethClient, '0x8f740...')\n * // { role: 'spoke', hubChainId: 8453, spokeChainIds: [1, 42161] }\n */\nexport async function getVaultTopology(\n publicClient: PublicClient,\n vault: Address,\n factoryAddress: Address = OMNI_FACTORY_ADDRESS,\n): Promise<VaultTopology> {\n const v = getAddress(vault)\n const f = getAddress(factoryAddress)\n\n // Get local EID from the factory on the queried chain\n const localEid = await publicClient.readContract({\n address: f,\n abi: FACTORY_ABI,\n functionName: 'localEid',\n })\n\n // Check if this vault is a hub on the current chain\n const isHub = await publicClient.readContract({\n address: f,\n abi: FACTORY_ABI,\n functionName: 'isCrossChainVault',\n args: [localEid, v],\n })\n\n if (isHub) {\n // Hub: get all registered spokes\n const [spokeEids] = await publicClient.readContract({\n address: f,\n abi: FACTORY_ABI,\n functionName: 'hubToSpokes',\n args: [localEid, v],\n })\n\n const localChainId = EID_TO_CHAIN_ID[localEid] ?? Number(publicClient.chain?.id ?? 0)\n const spokeChainIds = (spokeEids as readonly number[])\n .map(eid => EID_TO_CHAIN_ID[eid])\n .filter((id): id is number => id !== undefined)\n\n return { role: 'hub', hubChainId: localChainId, spokeChainIds }\n }\n\n // Check if this vault is a spoke on the current chain\n const [hubEid, hubVault] = await publicClient.readContract({\n address: f,\n abi: FACTORY_ABI,\n functionName: 'spokeToHub',\n args: [localEid, v],\n })\n\n if (hubEid !== 0 && hubVault !== '0x0000000000000000000000000000000000000000') {\n // Spoke: resolve hub chain + get all siblings from hub's factory\n const hubChainId = EID_TO_CHAIN_ID[hubEid] ?? 0\n\n // We only have the current chain's client — return what we know\n // The hub's full spoke list requires a separate client for the hub chain\n // (callers can pass a hub-chain client to get the full picture)\n const spokeChainIds: number[] = []\n\n // If we happen to know the hub EID mapping, include local chain as a spoke\n const localChainId = EID_TO_CHAIN_ID[localEid]\n if (localChainId !== undefined) spokeChainIds.push(localChainId)\n\n return { role: 'spoke', hubChainId, spokeChainIds }\n }\n\n // Local vault — no cross-chain setup\n const localChainId = EID_TO_CHAIN_ID[localEid] ?? Number(publicClient.chain?.id ?? 0)\n return { role: 'local', hubChainId: localChainId, spokeChainIds: [] }\n}\n\n/**\n * Resolve the FULL topology of a vault by querying the hub chain directly.\n *\n * Provide a publicClient connected to the hub chain for complete spoke data.\n * If you don't know which chain is the hub, call `getVaultTopology` first\n * from any chain and use the returned `hubChainId` to create the hub client.\n *\n * @param hubChainClient Public client connected to the hub chain\n * @param vault Vault address\n * @param factoryAddress MoreVaults factory (defaults to OMNI_FACTORY_ADDRESS)\n */\nexport async function getFullVaultTopology(\n hubChainClient: PublicClient,\n vault: Address,\n factoryAddress: Address = OMNI_FACTORY_ADDRESS,\n): Promise<VaultTopology> {\n const topo = await getVaultTopology(hubChainClient, vault, factoryAddress)\n if (topo.role !== 'hub') {\n throw new Error(\n `getFullVaultTopology: client must be connected to the hub chain (${topo.hubChainId}), ` +\n `but got role=\"${topo.role}\". Connect to chainId ${topo.hubChainId} instead.`,\n )\n }\n return topo\n}\n\n/** All mainnet chain IDs where the OMNI_FACTORY is deployed */\nconst DISCOVERY_CHAIN_IDS = Object.values(CHAIN_IDS).filter(\n id => id !== 545, // exclude testnet\n) as number[]\n\n/**\n * Discover a vault's topology across all supported chains.\n *\n * Unlike `getVaultTopology` (which queries a single chain), this function\n * automatically iterates all supported chains when the initial query returns\n * `role: \"local\"`. This handles the case where the caller doesn't know which\n * chain the vault is deployed on, or when no wallet is connected.\n *\n * If a `publicClient` is provided, it's tried first. If that returns \"local\",\n * every other supported chain is probed via `createChainClient` (public RPCs).\n * If no `publicClient` is provided, all chains are probed.\n *\n * Once a hub is found, `getFullVaultTopology` is called to get the complete\n * spoke list.\n *\n * @param vault Vault address (same on all chains via CREATE3)\n * @param publicClient Optional — client for the \"preferred\" chain to try first\n * @param factoryAddress MoreVaults factory (defaults to OMNI_FACTORY_ADDRESS)\n *\n * @example\n * // No wallet connected — discovers that 0x8f74... is hub on Base\n * const topo = await discoverVaultTopology('0x8f740...')\n * // { role: 'hub', hubChainId: 8453, spokeChainIds: [1, 42161] }\n */\nexport async function discoverVaultTopology(\n vault: Address,\n publicClient?: PublicClient | null,\n factoryAddress: Address = OMNI_FACTORY_ADDRESS,\n): Promise<VaultTopology> {\n const v = getAddress(vault)\n\n // 1. Try the provided client first (fast path — avoids extra RPC calls)\n let triedChainId: number | undefined\n if (publicClient) {\n try {\n const topo = await getVaultTopology(publicClient, v, factoryAddress)\n if (topo.role !== 'local') {\n // Found hub or spoke — if spoke, resolve full topology from hub\n if (topo.role === 'spoke') {\n const hubClient = createChainClient(topo.hubChainId)\n if (hubClient) {\n try {\n return await getFullVaultTopology(hubClient, v, factoryAddress)\n } catch { /* fall through to return partial */ }\n }\n }\n return topo\n }\n triedChainId = publicClient.chain?.id\n } catch { /* client failed — continue with discovery */ }\n }\n\n // 2. Iterate all supported chains\n for (const chainId of DISCOVERY_CHAIN_IDS) {\n if (chainId === triedChainId) continue\n const client = createChainClient(chainId)\n if (!client) continue\n\n try {\n const topo = await getVaultTopology(client, v, factoryAddress)\n if (topo.role === 'hub') return topo\n if (topo.role === 'spoke') {\n // Found spoke — get full topology from hub\n const hubClient = createChainClient(topo.hubChainId)\n if (hubClient) {\n try {\n return await getFullVaultTopology(hubClient, v, factoryAddress)\n } catch { return topo }\n }\n return topo\n }\n } catch { /* this chain doesn't have the factory or vault — skip */ }\n }\n\n // 3. Not found on any chain — return local with chainId 0\n return { role: 'local', hubChainId: 0, spokeChainIds: [] }\n}\n\n/**\n * Check if a wallet is connected to the hub chain for a given vault.\n * Useful for showing a \"Switch to Base\" prompt before deposit.\n *\n * @param currentChainId Chain ID the wallet is currently connected to\n * @param topology Result of getVaultTopology\n */\nexport function isOnHubChain(currentChainId: number, topology: VaultTopology): boolean {\n return currentChainId === topology.hubChainId\n}\n\n/**\n * Get all chain IDs where this vault is deployed (hub + all spokes).\n */\nexport function getAllVaultChainIds(topology: VaultTopology): number[] {\n return [topology.hubChainId, ...topology.spokeChainIds]\n}\n","/**\n * Pre-flight validation helpers for MoreVaults SDK flows.\n *\n * Each function reads on-chain state and throws a descriptive error BEFORE\n * the actual contract call, so developers see a clear, actionable message\n * instead of a raw VM revert.\n */\n\nimport { type Address, type PublicClient, getAddress, zeroAddress } from 'viem'\nimport { CONFIG_ABI, BRIDGE_ABI, VAULT_ABI, ERC20_ABI, OFT_ABI } from './abis'\nimport { InsufficientLiquidityError } from './errors'\nimport { quoteComposeFee } from './crossChainFlows'\nimport { createChainClient } from './spokeRoutes'\nimport { EID_TO_CHAIN_ID, OFT_ROUTES } from './chains'\n\n/**\n * Pre-flight checks for async cross-chain flows (D4 / D5 / R5).\n *\n * Validates that:\n * 1. The CCManager is configured on the vault.\n * 2. An escrow is registered in the vault's registry.\n * 3. The vault is a hub (required for async flows).\n * 4. The vault does NOT have oracle-based cross-chain accounting enabled\n * (oracle-on vaults should use depositSimple / depositCrossChainOracleOn).\n * 5. The vault is not paused.\n *\n * All reads that are independent of each other are executed in parallel via\n * Promise.all to minimise latency.\n *\n * @param publicClient Public client for contract reads\n * @param vault Vault address (diamond proxy)\n * @param escrow Escrow address from VaultAddresses\n */\nexport async function preflightAsync(\n publicClient: PublicClient,\n vault: Address,\n escrow: Address,\n): Promise<void> {\n const v = getAddress(vault)\n\n // Parallel read: ccManager, escrow, isHub, oraclesCrossChainAccounting, paused\n const [ccManager, registeredEscrow, isHub, oraclesEnabled, isPaused] =\n await Promise.all([\n publicClient.readContract({\n address: v,\n abi: CONFIG_ABI,\n functionName: 'getCrossChainAccountingManager',\n }),\n publicClient.readContract({\n address: v,\n abi: CONFIG_ABI,\n functionName: 'getEscrow',\n }),\n publicClient.readContract({\n address: v,\n abi: CONFIG_ABI,\n functionName: 'isHub',\n }),\n publicClient.readContract({\n address: v,\n abi: BRIDGE_ABI,\n functionName: 'oraclesCrossChainAccounting',\n }),\n publicClient.readContract({\n address: v,\n abi: CONFIG_ABI,\n functionName: 'paused',\n }),\n ])\n\n if (ccManager === zeroAddress) {\n throw new Error(\n `[MoreVaults] CCManager not configured on vault ${vault}. Call setCrossChainAccountingManager(ccManagerAddress) as vault owner first.`,\n )\n }\n\n if (registeredEscrow === zeroAddress) {\n throw new Error(\n `[MoreVaults] Escrow not configured for vault ${vault}. The registry must have an escrow set for this vault.`,\n )\n }\n\n if (!isHub) {\n throw new Error(\n `[MoreVaults] Vault ${vault} is not a hub vault. Async flows (D4/D5/R5) only work on hub vaults.`,\n )\n }\n\n if (oraclesEnabled) {\n throw new Error(\n `[MoreVaults] Vault ${vault} has oracle-based cross-chain accounting enabled. Use depositSimple/depositCrossChainOracleOn instead of async flows.`,\n )\n }\n\n if (isPaused) {\n throw new Error(\n `[MoreVaults] Vault ${vault} is paused. Cannot perform any actions.`,\n )\n }\n}\n\n/**\n * Pre-flight liquidity check for async redeem (R5).\n *\n * Reads the hub's liquid balance of the underlying token and compares it\n * against the assets the user expects to receive. If the hub does not hold\n * enough liquid assets the redeem will be auto-refunded after the LZ round-trip,\n * wasting the LayerZero fee.\n *\n * Uses `convertToAssets` (not `previewRedeem`) because async cross-chain vaults\n * disable direct redeem and revert on `previewRedeem` by design.\n *\n * This check is best-effort: liquidity could change in the 1-5 minutes between\n * submission and execution. But it catches the common case where the hub is\n * already under-funded at the time of submission.\n *\n * @param publicClient Public client for contract reads\n * @param vault Vault address (diamond proxy)\n * @param shares Shares the user intends to redeem\n */\nexport async function preflightRedeemLiquidity(\n publicClient: PublicClient,\n vault: Address,\n shares: bigint,\n): Promise<void> {\n const v = getAddress(vault)\n\n // Batch 1: check if this is a hub vault without oracle accounting.\n // Only those vaults can have liquidity stranded on spoke chains.\n const [isHub, oraclesEnabled] = await Promise.all([\n publicClient.readContract({\n address: v,\n abi: CONFIG_ABI,\n functionName: 'isHub',\n }),\n publicClient.readContract({\n address: v,\n abi: BRIDGE_ABI,\n functionName: 'oraclesCrossChainAccounting',\n }),\n ])\n\n // Non-hub vaults and oracle-on hubs hold all redeemable assets locally —\n // no liquidity gap is possible, so skip the check.\n if (!isHub || oraclesEnabled) return\n\n // Batch 2: underlying address (needed for ERC-20 balanceOf)\n const underlying = await publicClient.readContract({\n address: v,\n abi: VAULT_ABI,\n functionName: 'asset',\n })\n\n // Batch 3: hub liquid balance + convertToAssets\n // NOTE: previewRedeem reverts on async cross-chain vaults (disabled by design).\n // convertToAssets is always safe and gives a correct lower-bound estimate.\n const [hubLiquid, assetsNeeded] = await Promise.all([\n publicClient.readContract({\n address: getAddress(underlying as Address),\n abi: ERC20_ABI,\n functionName: 'balanceOf',\n args: [v],\n }),\n publicClient.readContract({\n address: v,\n abi: VAULT_ABI,\n functionName: 'convertToAssets',\n args: [shares],\n }),\n ])\n\n const hubLiquidBig = hubLiquid as bigint\n const assetsNeededBig = assetsNeeded as bigint\n\n if (hubLiquidBig < assetsNeededBig) {\n throw new InsufficientLiquidityError(vault, hubLiquidBig, assetsNeededBig)\n }\n}\n\n/**\n * Pre-flight checks for synchronous deposit flows (D1 / D3).\n *\n * Validates that:\n * 1. The vault is not paused.\n * 2. The vault still has deposit capacity (maxDeposit > 0).\n *\n * Both reads are executed in parallel.\n *\n * @param publicClient Public client for contract reads\n * @param vault Vault address (diamond proxy)\n */\nexport async function preflightSync(\n publicClient: PublicClient,\n vault: Address,\n): Promise<void> {\n const v = getAddress(vault)\n\n // Run paused and maxDeposit in parallel.\n // maxDeposit(address(0)) may REVERT on whitelisted vaults — catch separately.\n const [isPaused, depositCapResult] = await Promise.all([\n publicClient.readContract({\n address: v,\n abi: CONFIG_ABI,\n functionName: 'paused',\n }),\n publicClient\n .readContract({\n address: v,\n abi: CONFIG_ABI,\n functionName: 'maxDeposit',\n args: [zeroAddress],\n })\n .catch(() => null as null),\n ])\n\n if (isPaused) {\n throw new Error(\n `[MoreVaults] Vault ${vault} is paused. Cannot perform any actions.`,\n )\n }\n\n // null means maxDeposit reverted → whitelist vault — skip capacity check\n // (the user may still be whitelisted; canDeposit will do user-specific check)\n if (depositCapResult !== null && depositCapResult === 0n) {\n throw new Error(\n `[MoreVaults] Vault ${vault} has reached deposit capacity. No more deposits accepted.`,\n )\n }\n}\n\n/**\n * Pre-flight checks for spoke-to-hub deposits (D6 / D7 via OFT Compose).\n *\n * Validates that:\n * 1. User has enough tokens on the spoke chain to deposit.\n * 2. User has enough native gas on the spoke chain for TX1 (OFT.send).\n * 3. For Stargate OFTs (2-TX flow): user has enough ETH on the hub chain\n * for TX2 (compose retry). This prevents sending TX1 only to get stuck\n * because there's no ETH on the hub for TX2.\n *\n * @param spokePublicClient Public client on the SPOKE chain\n * @param vault Vault address\n * @param spokeOFT OFT contract address on the spoke chain\n * @param hubEid LZ EID for the hub chain\n * @param spokeEid LZ EID for the spoke chain\n * @param amount Amount of tokens to deposit\n * @param userAddress User's wallet address\n * @param lzFee LZ fee for TX1 (from quoteDepositFromSpokeFee)\n * @returns Object with validated balances for UI display\n */\nexport async function preflightSpokeDeposit(\n spokePublicClient: PublicClient,\n vault: Address,\n spokeOFT: Address,\n hubEid: number,\n spokeEid: number,\n amount: bigint,\n userAddress: Address,\n lzFee: bigint,\n): Promise<{\n spokeTokenBalance: bigint\n spokeNativeBalance: bigint\n hubNativeBalance: bigint\n estimatedComposeFee: bigint\n isStargate: boolean\n}> {\n const oft = getAddress(spokeOFT)\n\n // Read the underlying token address from the OFT\n const spokeToken = await spokePublicClient.readContract({\n address: oft,\n abi: OFT_ABI,\n functionName: 'token',\n })\n\n // Check token balance + native balance on spoke in parallel\n const [spokeTokenBalance, spokeNativeBalance] = await Promise.all([\n spokePublicClient.readContract({\n address: spokeToken,\n abi: ERC20_ABI,\n functionName: 'balanceOf',\n args: [getAddress(userAddress)],\n }),\n spokePublicClient.getBalance({ address: getAddress(userAddress) }),\n ])\n\n // 1. Check token balance\n if (spokeTokenBalance < amount) {\n throw new Error(\n `[MoreVaults] Insufficient token balance on spoke chain.\\n` +\n ` Need: ${amount}\\n` +\n ` Have: ${spokeTokenBalance}\\n` +\n ` Token: ${spokeToken}`,\n )\n }\n\n // 2. Check native gas for TX1 (lzFee + gas buffer)\n const gasBuffer = 500_000_000_000_000n // 0.0005 ETH for gas\n if (spokeNativeBalance < lzFee + gasBuffer) {\n throw new Error(\n `[MoreVaults] Insufficient native gas on spoke chain for TX1.\\n` +\n ` Need: ~${lzFee + gasBuffer} wei (LZ fee + gas)\\n` +\n ` Have: ${spokeNativeBalance} wei`,\n )\n }\n\n // 3. For Stargate OFTs: check ETH on hub for TX2 (compose retry)\n const STARGATE_ASSETS = new Set(['stgUSDC', 'USDT', 'WETH'])\n let isStargate = false\n for (const [symbol, chainMap] of Object.entries(OFT_ROUTES)) {\n if (!STARGATE_ASSETS.has(symbol)) continue\n for (const entry of Object.values(chainMap as Record<number, { oft: string; token: string }>)) {\n if (getAddress(entry.oft) === oft) isStargate = true\n }\n }\n\n let hubNativeBalance = 0n\n let estimatedComposeFee = 0n\n\n if (isStargate) {\n const hubChainId = EID_TO_CHAIN_ID[hubEid]\n const hubClient = createChainClient(hubChainId)\n if (hubClient) {\n [hubNativeBalance, estimatedComposeFee] = await Promise.all([\n hubClient.getBalance({ address: getAddress(userAddress) }),\n quoteComposeFee(hubClient, vault, spokeEid, userAddress),\n ])\n\n const hubGasBuffer = 300_000_000_000_000n // 0.0003 ETH for gas\n const totalNeeded = estimatedComposeFee + hubGasBuffer\n\n if (hubNativeBalance < totalNeeded) {\n throw new Error(\n `[MoreVaults] Insufficient ETH on hub chain for TX2 (compose retry).\\n` +\n ` This is a Stargate 2-TX flow — TX2 requires ETH on the hub chain.\\n` +\n ` Need: ~${totalNeeded} wei (compose fee ${estimatedComposeFee} + gas)\\n` +\n ` Have: ${hubNativeBalance} wei\\n` +\n ` Short: ${totalNeeded - hubNativeBalance} wei\\n` +\n ` Send ETH to ${userAddress} on chainId ${hubChainId} before depositing.`,\n )\n }\n }\n }\n\n return {\n spokeTokenBalance,\n spokeNativeBalance,\n hubNativeBalance,\n estimatedComposeFee,\n isStargate,\n }\n}\n\n/**\n * Pre-flight checks for spoke→hub→spoke redeem (R6 + R1 + R7).\n *\n * Validates that:\n * 1. User has shares on the spoke chain.\n * 2. User has enough native gas on the spoke for TX1 (share bridge LZ fee + gas).\n * 3. User has enough native gas on the hub for TX2 (redeem gas) + TX3 (asset bridge LZ fee + gas).\n * 4. The vault has enough liquid assets on the hub to redeem.\n *\n * @param route SpokeRedeemRoute from resolveRedeemAddresses\n * @param shares Shares the user intends to redeem\n * @param userAddress User's wallet address\n * @param shareBridgeFee LZ fee for share bridge (TX1) — from quoteSend on spoke SHARE_OFT\n * @returns Validated balances for UI display\n */\nexport async function preflightSpokeRedeem(\n route: {\n hubChainId: number\n spokeChainId: number\n hubEid: number\n spokeEid: number\n hubAsset: `0x${string}`\n spokeShareOft: `0x${string}`\n hubAssetOft: `0x${string}`\n spokeAsset: `0x${string}`\n isStargate: boolean\n },\n shares: bigint,\n userAddress: `0x${string}`,\n shareBridgeFee: bigint,\n): Promise<{\n sharesOnSpoke: bigint\n spokeNativeBalance: bigint\n hubNativeBalance: bigint\n estimatedAssetBridgeFee: bigint\n estimatedAssetsOut: bigint\n hubLiquidBalance: bigint\n}> {\n const spokeClient = createChainClient(route.spokeChainId)\n const hubClient = createChainClient(route.hubChainId)\n if (!spokeClient) throw new Error(`No public RPC for spoke chainId ${route.spokeChainId}`)\n if (!hubClient) throw new Error(`No public RPC for hub chainId ${route.hubChainId}`)\n\n const user = getAddress(userAddress)\n const vault = getAddress(route.hubAsset) // vault address is same on all chains\n\n // Parallel reads: shares on spoke, native balances, vault data on hub\n const [sharesOnSpoke, spokeNativeBalance, hubNativeBalance] = await Promise.all([\n spokeClient.readContract({\n address: route.spokeShareOft,\n abi: ERC20_ABI,\n functionName: 'balanceOf',\n args: [user],\n }),\n spokeClient.getBalance({ address: user }),\n hubClient.getBalance({ address: user }),\n ])\n\n // 1. Check shares\n if (sharesOnSpoke < shares) {\n throw new Error(\n `[MoreVaults] Insufficient shares on spoke chain.\\n` +\n ` Need: ${shares}\\n` +\n ` Have: ${sharesOnSpoke}\\n` +\n ` Token: ${route.spokeShareOft}`,\n )\n }\n\n // 2. Check spoke gas for TX1\n const spokeGasBuffer = 500_000_000_000_000n // 0.0005 ETH\n if (spokeNativeBalance < shareBridgeFee + spokeGasBuffer) {\n throw new Error(\n `[MoreVaults] Insufficient native gas on spoke for TX1 (share bridge).\\n` +\n ` Need: ~${shareBridgeFee + spokeGasBuffer} wei (LZ fee + gas)\\n` +\n ` Have: ${spokeNativeBalance} wei`,\n )\n }\n\n // 3. Estimate asset bridge fee (TX3) and check hub gas\n // Quote Stargate/OFT fee for bridging assets back to spoke\n // Use convertToAssets estimate for quoting\n let estimatedAssetsOut = 0n\n let estimatedAssetBridgeFee = 0n\n let hubLiquidBalance = 0n\n\n // Read vault data on hub — need the actual vault address (not hub asset)\n // The vault address is same as route but we need it from the calling context\n // For now, read convertToAssets using the share token which IS the vault for ERC-4626\n // Actually we need the vault address. The hubAsset is the underlying token, not the vault.\n // We can get vault address by checking what contract the shares are from.\n // In MoreVaults, share OFT on hub wraps the vault token. Let's read token() from hub share OFT.\n\n // Get vault address from hub: the SHARE_OFT.token() on hub = vault address\n // But we have hubAssetOft which is Stargate pool, not share OFT.\n // Instead, read from the spoke SHARE_OFT's peer on hub.\n // Actually, for preflightSpokeRedeem we need the vault address passed in.\n // Let me simplify — estimate the LZ fee with a dummy amount.\n\n try {\n const toBytes32 = `0x${user.slice(2).padStart(64, '0')}` as `0x${string}`\n const dummyAmount = 1_000_000n // 1 USDC for fee estimation\n const feeResult = await hubClient.readContract({\n address: route.hubAssetOft,\n abi: OFT_ABI,\n functionName: 'quoteSend',\n args: [{\n dstEid: route.spokeEid,\n to: toBytes32,\n amountLD: dummyAmount,\n minAmountLD: dummyAmount * 99n / 100n,\n extraOptions: '0x' as `0x${string}`,\n composeMsg: '0x' as `0x${string}`,\n oftCmd: (route.isStargate ? '0x01' : '0x') as `0x${string}`,\n }, false],\n })\n estimatedAssetBridgeFee = feeResult.nativeFee\n } catch {\n // Can't quote — use conservative estimate\n estimatedAssetBridgeFee = 300_000_000_000_000n // 0.0003 ETH fallback\n }\n\n // Hub needs: TX2 gas (~0.0002 ETH) + TX3 LZ fee + TX3 gas (~0.0001 ETH)\n const hubGasBuffer = 300_000_000_000_000n // 0.0003 ETH for gas (TX2 + TX3)\n const totalHubNeeded = estimatedAssetBridgeFee + hubGasBuffer\n\n if (hubNativeBalance < totalHubNeeded) {\n throw new Error(\n `[MoreVaults] Insufficient ETH on hub chain for TX2 (redeem) + TX3 (asset bridge).\\n` +\n ` Need: ~${totalHubNeeded} wei (LZ fee ${estimatedAssetBridgeFee} + gas)\\n` +\n ` Have: ${hubNativeBalance} wei\\n` +\n ` Short: ${totalHubNeeded - hubNativeBalance} wei\\n` +\n ` Send ETH to ${userAddress} on chainId ${route.hubChainId} before redeeming.`,\n )\n }\n\n return {\n sharesOnSpoke,\n spokeNativeBalance,\n hubNativeBalance,\n estimatedAssetBridgeFee,\n estimatedAssetsOut,\n hubLiquidBalance,\n }\n}\n","import type { WalletClient } from 'viem'\nimport { WrongChainError } from './errors'\n\n/**\n * Validate that the walletClient is connected to the expected chain.\n * Only validates if hubChainId is provided — opt-in, non-breaking.\n */\nexport function validateWalletChain(walletClient: WalletClient, hubChainId?: number): void {\n if (!hubChainId) return\n const current = walletClient.chain?.id\n if (current !== undefined && current !== hubChainId) {\n throw new WrongChainError(current, hubChainId)\n }\n}\n","import {\n type Address,\n type PublicClient,\n type WalletClient,\n encodeAbiParameters,\n getAddress,\n zeroAddress,\n} from 'viem'\nimport { VAULT_ABI, BRIDGE_ABI, ERC20_ABI, CONFIG_ABI } from './abis'\nimport type {\n VaultAddresses,\n DepositResult,\n AsyncRequestResult,\n} from './types'\nimport { ActionType } from './types'\nimport { ensureAllowance, getVaultStatus, quoteLzFee } from './utils'\nimport { preflightSync, preflightAsync } from './preflight'\nimport { EscrowNotConfiguredError, VaultPausedError, CapacityFullError } from './errors'\nimport { validateWalletChain } from './chainValidation'\n\n/**\n * D1 / D3 — Simple deposit (ERC-4626 standard).\n *\n * Works for both local vaults and cross-chain hubs with oracle accounting ON.\n * When oracle accounting is enabled the cross-chain accounting is transparent\n * to the caller — the vault resolves totalAssets synchronously.\n *\n * **User transactions**: 1 approve (skipped if allowance sufficient) + 1 deposit.\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads and simulation\n * @param addresses Vault address set (only `vault` is used)\n * @param assets Amount of underlying token to deposit (in token decimals)\n * @param receiver Address that will receive the minted vault shares\n * @returns Transaction hash and amount of shares minted\n */\nexport async function depositSimple(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n assets: bigint,\n receiver: Address,\n): Promise<DepositResult> {\n const account = walletClient.account!\n const vault = getAddress(addresses.vault)\n\n // Validate wallet is on the correct chain (opt-in via hubChainId)\n validateWalletChain(walletClient, addresses.hubChainId)\n\n // Pre-flight: validate vault is operational and accepting deposits\n await preflightSync(publicClient, vault)\n\n // Resolve underlying asset\n const underlying = await publicClient.readContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'asset',\n })\n\n // Approve vault if needed\n await ensureAllowance(walletClient, publicClient, underlying, vault, assets)\n\n // Simulate then send\n const { result: shares } = await publicClient.simulateContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'deposit',\n args: [assets, getAddress(receiver)],\n account: account.address,\n })\n\n const txHash = await walletClient.writeContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'deposit',\n args: [assets, getAddress(receiver)],\n account,\n chain: walletClient.chain,\n })\n\n return { txHash, shares }\n}\n\n/**\n * Alias: D3 — Cross-chain hub deposit when oracle accounting is ON.\n * Exactly the same UX as depositSimple because the vault resolves accounting synchronously.\n */\nexport { depositSimple as depositCrossChainOracleOn }\n\n/**\n * D2 — Multi-asset deposit.\n *\n * Deposits multiple ERC-20 tokens into the vault in a single vault call.\n * The vault converts each token to the underlying via oracle pricing.\n *\n * **User transactions**: N approves (one per token, skipped if sufficient) + 1 deposit.\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads and simulation\n * @param addresses Vault address set (only `vault` is used)\n * @param tokens Array of token addresses to deposit\n * @param amounts Array of amounts (one per token, in each token's decimals)\n * @param receiver Address that will receive the minted vault shares\n * @param minShares Minimum shares to accept (slippage protection)\n * @returns Transaction hash and amount of shares minted\n */\nexport async function depositMultiAsset(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n tokens: Address[],\n amounts: bigint[],\n receiver: Address,\n minShares: bigint,\n): Promise<DepositResult> {\n const account = walletClient.account!\n const vault = getAddress(addresses.vault)\n\n // Validate wallet is on the correct chain (opt-in via hubChainId)\n validateWalletChain(walletClient, addresses.hubChainId)\n\n // Approve each token\n for (let i = 0; i < tokens.length; i++) {\n await ensureAllowance(walletClient, publicClient, tokens[i], vault, amounts[i])\n }\n\n const { result: shares } = await publicClient.simulateContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'deposit',\n args: [tokens, amounts, getAddress(receiver), minShares],\n account: account.address,\n })\n\n const txHash = await walletClient.writeContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'deposit',\n args: [tokens, amounts, getAddress(receiver), minShares],\n account,\n chain: walletClient.chain,\n })\n\n return { txHash, shares }\n}\n\n/**\n * D4 — Async deposit (cross-chain hub, oracle OFF).\n *\n * Sends assets to the escrow and initiates a cross-chain accounting request via\n * `initVaultActionRequest(DEPOSIT, ...)`. The LZ Read callback will resolve\n * accounting and `executeRequest` will mint shares.\n *\n * **User transactions**: 1 approve (to ESCROW, not vault!) + 1 initVaultActionRequest.\n * **Wait**: Shares arrive after the LZ callback + executeRequest (automated by keeper).\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads and simulation\n * @param addresses Vault address set (`vault` + `escrow` required)\n * @param assets Amount of underlying to deposit\n * @param receiver Address that will receive shares after resolution\n * @param lzFee msg.value for LZ Read fee (quote first with `quoteLzFee`)\n * @param extraOptions Optional LZ extra options bytes (default 0x)\n * @returns Transaction hash and GUID for tracking\n */\nexport async function depositAsync(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n assets: bigint,\n receiver: Address,\n lzFee: bigint,\n extraOptions: `0x${string}` = '0x',\n): Promise<AsyncRequestResult> {\n const account = walletClient.account!\n const vault = getAddress(addresses.vault)\n const escrow = addresses.escrow\n ? getAddress(addresses.escrow)\n : await publicClient.readContract({ address: vault, abi: CONFIG_ABI, functionName: 'getEscrow' })\n if (escrow === zeroAddress) throw new EscrowNotConfiguredError(vault)\n\n // Validate wallet is on the correct chain (opt-in via hubChainId)\n validateWalletChain(walletClient, addresses.hubChainId)\n\n // Pre-flight: validate async cross-chain setup before sending any transaction\n await preflightAsync(publicClient, vault, escrow)\n\n // Resolve underlying asset\n const underlying = await publicClient.readContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'asset',\n })\n\n // Approve ESCROW (not vault!) for the deposit amount\n await ensureAllowance(walletClient, publicClient, underlying, escrow, assets)\n\n // Encode parameters only (no selector) — contracts use abi.decode on these bytes\n const actionCallData = encodeAbiParameters(\n [{ type: 'uint256', name: 'assets' }, { type: 'address', name: 'receiver' }],\n [assets, getAddress(receiver)],\n ) as `0x${string}`\n\n const [{ result: guid }, gasEstimate] = await Promise.all([\n publicClient.simulateContract({\n address: vault,\n abi: BRIDGE_ABI,\n functionName: 'initVaultActionRequest',\n args: [ActionType.DEPOSIT, actionCallData, 0n, extraOptions],\n value: lzFee,\n account: account.address,\n }),\n publicClient.estimateContractGas({\n address: vault,\n abi: BRIDGE_ABI,\n functionName: 'initVaultActionRequest',\n args: [ActionType.DEPOSIT, actionCallData, 0n, extraOptions],\n value: lzFee,\n account: account.address,\n }),\n ])\n\n // LZ Read operations consistently underestimate gas — add 30% buffer.\n const gas = gasEstimate * 130n / 100n\n\n const txHash = await walletClient.writeContract({\n address: vault,\n abi: BRIDGE_ABI,\n functionName: 'initVaultActionRequest',\n args: [ActionType.DEPOSIT, actionCallData, 0n, extraOptions],\n value: lzFee,\n account,\n chain: walletClient.chain,\n gas,\n })\n\n return { txHash, guid: guid as `0x${string}` }\n}\n\n/**\n * D5 — Async mint (cross-chain hub, oracle OFF).\n *\n * Mints an exact amount of shares by depositing up to `maxAssets` of underlying.\n * Similar flow to D4 but uses MINT action type.\n *\n * **User transactions**: 1 approve (to ESCROW for maxAssets) + 1 initVaultActionRequest.\n * **Wait**: Shares arrive after the LZ callback + executeRequest.\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads and simulation\n * @param addresses Vault address set (`vault` + `escrow` required)\n * @param shares Exact number of shares to mint\n * @param maxAssets Maximum assets to spend (slippage protection)\n * @param receiver Address that will receive the minted shares\n * @param lzFee msg.value for LZ Read fee\n * @param extraOptions Optional LZ extra options bytes\n * @returns Transaction hash and GUID for tracking\n */\nexport async function mintAsync(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n shares: bigint,\n maxAssets: bigint,\n receiver: Address,\n lzFee: bigint,\n extraOptions: `0x${string}` = '0x',\n): Promise<AsyncRequestResult> {\n const account = walletClient.account!\n const vault = getAddress(addresses.vault)\n const escrow = addresses.escrow\n ? getAddress(addresses.escrow)\n : await publicClient.readContract({ address: vault, abi: CONFIG_ABI, functionName: 'getEscrow' })\n if (escrow === zeroAddress) throw new EscrowNotConfiguredError(vault)\n\n // Validate wallet is on the correct chain (opt-in via hubChainId)\n validateWalletChain(walletClient, addresses.hubChainId)\n\n // Pre-flight: validate async cross-chain setup before sending any transaction\n await preflightAsync(publicClient, vault, escrow)\n\n const underlying = await publicClient.readContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'asset',\n })\n\n // Approve ESCROW for maxAssets\n await ensureAllowance(walletClient, publicClient, underlying, escrow, maxAssets)\n\n // Encode parameters only (no selector) — contracts use abi.decode on these bytes\n const actionCallData = encodeAbiParameters(\n [{ type: 'uint256', name: 'shares' }, { type: 'address', name: 'receiver' }],\n [shares, getAddress(receiver)],\n ) as `0x${string}`\n\n // amountLimit = maxAssets (slippage check: actual assets spent must be <= maxAssets)\n const [{ result: guid }, gasEstimate] = await Promise.all([\n publicClient.simulateContract({\n address: vault,\n abi: BRIDGE_ABI,\n functionName: 'initVaultActionRequest',\n args: [ActionType.MINT, actionCallData, maxAssets, extraOptions],\n value: lzFee,\n account: account.address,\n }),\n publicClient.estimateContractGas({\n address: vault,\n abi: BRIDGE_ABI,\n functionName: 'initVaultActionRequest',\n args: [ActionType.MINT, actionCallData, maxAssets, extraOptions],\n value: lzFee,\n account: account.address,\n }),\n ])\n\n const gas = gasEstimate * 130n / 100n\n\n const txHash = await walletClient.writeContract({\n address: vault,\n abi: BRIDGE_ABI,\n functionName: 'initVaultActionRequest',\n args: [ActionType.MINT, actionCallData, maxAssets, extraOptions],\n value: lzFee,\n account,\n chain: walletClient.chain,\n gas,\n })\n\n return { txHash, guid: guid as `0x${string}` }\n}\n\n/**\n * Smart deposit — auto-selects the correct flow based on vault configuration.\n *\n * Calls getVaultStatus internally to determine the vault mode, then dispatches\n * to the appropriate flow:\n * - local / cross-chain-oracle → depositSimple (ERC-4626 deposit)\n * - cross-chain-async → depositAsync (initVaultActionRequest + LZ Read callback)\n *\n * ## Tested flows\n *\n * - [x] Hub-chain async deposit (Base→Base, vault 0x8f74...ba6):\n * smartDeposit auto-detects async → depositAsync → LZ Read callback ~4.5 min.\n * TX: 0x5284b4...ca24\n *\n * ## Untested flows\n *\n * - [ ] Hub-chain sync deposit (depositSimple path) — needs a vault with oracle ON\n * - [ ] Multi-asset deposit (depositMultiAsset) — separate entry point, not dispatched here\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads\n * @param addresses Vault address set (`escrow` required for async vaults)\n * @param assets Amount of underlying to deposit\n * @param receiver Address that will receive shares\n * @param extraOptions Optional LZ extra options (only used for async vaults)\n * @returns DepositResult or AsyncRequestResult depending on vault mode\n * @throws VaultPausedError if vault is paused\n * @throws CapacityFullError if vault is full\n */\nexport async function smartDeposit(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n assets: bigint,\n receiver: Address,\n extraOptions: `0x${string}` = '0x',\n): Promise<DepositResult | AsyncRequestResult> {\n const vault = getAddress(addresses.vault)\n const status = await getVaultStatus(publicClient, vault)\n\n if (status.mode === 'paused') {\n throw new VaultPausedError(vault)\n }\n if (status.mode === 'full') {\n throw new CapacityFullError(vault)\n }\n\n if (status.recommendedDepositFlow === 'depositAsync') {\n const lzFee = await quoteLzFee(publicClient, vault, extraOptions)\n return depositAsync(walletClient, publicClient, addresses, assets, receiver, lzFee, extraOptions)\n }\n\n // local or cross-chain-oracle\n return depositSimple(walletClient, publicClient, addresses, assets, receiver)\n}\n","import {\n type Address,\n type Hash,\n type PublicClient,\n type WalletClient,\n encodeAbiParameters,\n getAddress,\n pad,\n zeroAddress,\n} from 'viem'\nimport { VAULT_ABI, BRIDGE_ABI, OFT_ABI, CONFIG_ABI, ERC20_ABI } from './abis'\nimport type {\n VaultAddresses,\n RedeemResult,\n AsyncRequestResult,\n} from './types'\nimport { ActionType } from './types'\nimport { ensureAllowance, getVaultStatus, quoteLzFee } from './utils'\nimport { preflightAsync, preflightRedeemLiquidity } from './preflight'\nimport { EscrowNotConfiguredError } from './errors'\nimport { validateWalletChain } from './chainValidation'\nimport { OFT_ROUTES, CHAIN_ID_TO_EID } from './chains'\nimport { createChainClient } from './spokeRoutes'\nimport { OMNI_FACTORY_ADDRESS } from './topology'\n\n/**\n * R1 — Simple share redemption (ERC-4626 standard).\n *\n * Burns `shares` and returns the proportional amount of underlying assets.\n * If a withdrawal queue is enabled, the caller must have previously called\n * `requestRedeem` and waited for the timelock to expire.\n *\n * **User transactions**: 1 redeem call.\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads and simulation\n * @param addresses Vault address set (only `vault` is used)\n * @param shares Amount of vault shares to redeem\n * @param receiver Address that will receive the underlying assets\n * @param owner Owner of the shares being redeemed\n * @returns Transaction hash and amount of assets received\n */\nexport async function redeemShares(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n shares: bigint,\n receiver: Address,\n owner: Address,\n): Promise<RedeemResult> {\n const account = walletClient.account!\n const vault = getAddress(addresses.vault)\n\n // Validate wallet is on the correct chain (opt-in via hubChainId)\n validateWalletChain(walletClient, addresses.hubChainId)\n\n const { result: assets } = await publicClient.simulateContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'redeem',\n args: [shares, getAddress(receiver), getAddress(owner)],\n account: account.address,\n })\n\n const txHash = await walletClient.writeContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'redeem',\n args: [shares, getAddress(receiver), getAddress(owner)],\n account,\n chain: walletClient.chain,\n })\n\n return { txHash, assets }\n}\n\n/**\n * R2 — Withdraw by specifying the exact assets amount.\n *\n * Burns the necessary shares to withdraw exactly `assets` amount of underlying.\n * If a withdrawal queue is enabled, the caller must have previously called\n * `requestWithdraw` and waited for the timelock.\n *\n * **User transactions**: 1 withdraw call.\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads and simulation\n * @param addresses Vault address set (only `vault` is used)\n * @param assets Exact amount of underlying assets to withdraw\n * @param receiver Address that will receive the assets\n * @param owner Owner of the shares being burned\n * @returns Transaction hash and the actual assets withdrawn\n */\nexport async function withdrawAssets(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n assets: bigint,\n receiver: Address,\n owner: Address,\n): Promise<RedeemResult> {\n const account = walletClient.account!\n const vault = getAddress(addresses.vault)\n\n // Validate wallet is on the correct chain (opt-in via hubChainId)\n validateWalletChain(walletClient, addresses.hubChainId)\n\n const { result: sharesBurned } = await publicClient.simulateContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'withdraw',\n args: [assets, getAddress(receiver), getAddress(owner)],\n account: account.address,\n })\n\n const txHash = await walletClient.writeContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'withdraw',\n args: [assets, getAddress(receiver), getAddress(owner)],\n account,\n chain: walletClient.chain,\n })\n\n // For withdraw, the return is shares burned; assets is what was requested\n return { txHash, assets }\n}\n\n/**\n * R3 / R4 — Request redeem (queue shares for withdrawal).\n *\n * Places `shares` into the withdrawal queue. If a timelock is configured (R4),\n * the user must wait until `timelockEndsAt` before calling `redeemShares`.\n * If no timelock (R3), `redeemShares` can be called immediately after.\n *\n * Use `getWithdrawalRequest` to check the timelock status.\n *\n * **User transactions**: 1 requestRedeem call, then later 1 redeemShares call.\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for simulation\n * @param addresses Vault address set (only `vault` is used)\n * @param shares Amount of shares to queue for redemption\n * @param owner The address on behalf of which the request is made\n * @returns Transaction hash of the request\n */\nexport async function requestRedeem(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n shares: bigint,\n owner: Address,\n): Promise<{ txHash: Hash }> {\n const account = walletClient.account!\n const vault = getAddress(addresses.vault)\n\n // Validate wallet is on the correct chain (opt-in via hubChainId)\n validateWalletChain(walletClient, addresses.hubChainId)\n\n await publicClient.simulateContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'requestRedeem',\n args: [shares, getAddress(owner)],\n account: account.address,\n })\n\n const txHash = await walletClient.writeContract({\n address: vault,\n abi: VAULT_ABI,\n functionName: 'requestRedeem',\n args: [shares, getAddress(owner)],\n account,\n chain: walletClient.chain,\n })\n\n return { txHash }\n}\n\n/**\n * Helper — Get the current withdrawal request for an owner.\n *\n * Returns the queued shares and timelock end timestamp.\n * Useful for showing a countdown timer in the UI (R4 flow).\n *\n * @param publicClient Public client for reading state\n * @param vault Vault address\n * @param owner Owner whose request to query\n * @returns Request info or null if no active request\n */\nexport async function getWithdrawalRequest(\n publicClient: PublicClient,\n vault: Address,\n owner: Address,\n): Promise<{ shares: bigint; timelockEndsAt: bigint } | null> {\n const [shares, timelockEndsAt] = await publicClient.readContract({\n address: getAddress(vault),\n abi: VAULT_ABI,\n functionName: 'getWithdrawalRequest',\n args: [getAddress(owner)],\n })\n\n if (shares === 0n) return null\n\n return { shares, timelockEndsAt }\n}\n\n/**\n * R5 — Async redeem (cross-chain hub, oracle OFF).\n *\n * Initiates an async redeem via `initVaultActionRequest(REDEEM, ...)`.\n * Shares are locked in the escrow while the LZ Read resolves accounting.\n * After `executeRequest`, assets are sent to the receiver.\n *\n * **IMPORTANT**: `amountLimit` MUST be 0 for REDEEM actions (not shares).\n * The shares amount is encoded in the actionCallData. Setting amountLimit to\n * a non-zero value would be interpreted as \"max assets to receive\" (inverted\n * slippage check), which is almost never what the user wants.\n *\n * **User transactions**: 1 approve (shares to ESCROW) + 1 initVaultActionRequest.\n * **Wait**: Assets arrive after LZ callback + executeRequest.\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads and simulation\n * @param addresses Vault address set (`vault` + `escrow` required)\n * @param shares Amount of shares to redeem\n * @param receiver Address that will receive the underlying assets\n * @param owner Owner of the shares (must match the initiator)\n * @param lzFee msg.value for LZ Read fee\n * @param extraOptions Optional LZ extra options bytes\n * @returns Transaction hash and GUID for tracking\n */\nexport async function redeemAsync(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n shares: bigint,\n receiver: Address,\n owner: Address,\n lzFee: bigint,\n extraOptions: `0x${string}` = '0x',\n): Promise<AsyncRequestResult> {\n const account = walletClient.account!\n const vault = getAddress(addresses.vault)\n const escrow = addresses.escrow\n ? getAddress(addresses.escrow)\n : await publicClient.readContract({ address: vault, abi: CONFIG_ABI, functionName: 'getEscrow' })\n if (escrow === zeroAddress) throw new EscrowNotConfiguredError(vault)\n\n // Validate wallet is on the correct chain (opt-in via hubChainId)\n validateWalletChain(walletClient, addresses.hubChainId)\n\n // Pre-flight: validate async cross-chain setup before sending any transaction\n await preflightAsync(publicClient, vault, escrow)\n\n // Pre-flight: check hub has enough liquid assets — avoids wasting LZ fee on a guaranteed refund\n await preflightRedeemLiquidity(publicClient, vault, shares)\n\n // Approve ESCROW for shares (vault share token is the vault itself for ERC-4626)\n await ensureAllowance(walletClient, publicClient, vault, escrow, shares)\n\n // Encode parameters only (no selector) — contracts use abi.decode on these bytes\n const actionCallData = encodeAbiParameters(\n [{ type: 'uint256', name: 'shares' }, { type: 'address', name: 'receiver' }, { type: 'address', name: 'owner' }],\n [shares, getAddress(receiver), getAddress(owner)],\n ) as `0x${string}`\n\n // amountLimit MUST be 0 for REDEEM — see JSDoc above\n const [{ result: guid }, gasEstimate] = await Promise.all([\n publicClient.simulateContract({\n address: vault,\n abi: BRIDGE_ABI,\n functionName: 'initVaultActionRequest',\n args: [ActionType.REDEEM, actionCallData, 0n, extraOptions],\n value: lzFee,\n account: account.address,\n }),\n publicClient.estimateContractGas({\n address: vault,\n abi: BRIDGE_ABI,\n functionName: 'initVaultActionRequest',\n args: [ActionType.REDEEM, actionCallData, 0n, extraOptions],\n value: lzFee,\n account: account.address,\n }),\n ])\n\n const gas = gasEstimate * 130n / 100n\n\n const txHash = await walletClient.writeContract({\n address: vault,\n abi: BRIDGE_ABI,\n functionName: 'initVaultActionRequest',\n args: [ActionType.REDEEM, actionCallData, 0n, extraOptions],\n value: lzFee,\n account,\n chain: walletClient.chain,\n gas,\n })\n\n return { txHash, guid: guid as `0x${string}` }\n}\n\n/**\n * Smart redeem — auto-selects the correct flow based on vault configuration.\n *\n * Detects the vault mode and dispatches to:\n * - Sync vaults (local / cross-chain-oracle): `redeemShares` (direct ERC-4626 redeem)\n * - Async vaults (cross-chain, oracle OFF): `redeemAsync` (LZ Read flow, quotes fee automatically)\n *\n * ## Tested flows\n *\n * - [x] Hub-chain async redeem (Base→Base, vault 0x8f74...ba6):\n * smartRedeem auto-detects async → redeemAsync → LZ Read callback ~4.5 min.\n * TX: 0xd890c4...8b58c\n *\n * ## Untested flows\n *\n * - [ ] Hub-chain sync redeem (redeemShares path) — needs a vault with oracle ON\n * - [ ] requestRedeem + withdrawAssets (withdrawal queue flow) — separate entry points\n *\n * @param walletClient Wallet client with account attached\n * @param publicClient Public client for reads\n * @param addresses Vault address set (`escrow` required for async vaults)\n * @param shares Amount of shares to redeem\n * @param receiver Address that will receive the underlying assets\n * @param owner Owner of the shares being redeemed\n * @param extraOptions Optional LZ extra options (only used for async vaults)\n * @returns RedeemResult or AsyncRequestResult depending on vault mode\n */\nexport async function smartRedeem(\n walletClient: WalletClient,\n publicClient: PublicClient,\n addresses: VaultAddresses,\n shares: bigint,\n receiver: Address,\n owner: Address,\n extraOptions: `0x${string}` = '0x',\n): Promise<RedeemResult | AsyncRequestResult> {\n const vault = getAddress(addresses.vault)\n const status = await getVaultStatus(publicClient, vault)\n\n if (status.mode === 'paused') {\n throw new Error(`[MoreVaults] Vault ${vault} is paused. Cannot redeem.`)\n }\n\n if (status.recommendedDepositFlow === 'depositAsync') {\n // Async vault — use redeemAsync\n const lzFee = await quoteLzFee(publicClient, vault, extraOptions)\n return redeemAsync(walletClient, publicClient, addresses, shares, receiver, owner, lzFee, extraOptions)\n }\n\n // Sync vault — direct redeem\n return redeemShares(walletClient, publicClient, addresses, shares, receiver, owner)\n}\n\n/**\n * R6 — Bridge shares from spoke to hub chain via OFT.\n *\n * This is step 1 of a cross-chain spoke redeem flow:\n * 1. `bridgeSharesToHub()` — send shares from spoke → hub via SHARE_OFT\n * 2. `smartRedeem()` — redeem shares on hub → underlying (auto-detects async)\n * 3. `bridgeAssetsToSpoke()` — bridge assets from hub → spoke via asset OFT\n *\n * The steps happen on different chains and cannot be combined.\n * The frontend must switch chains between steps.\n *\n * **User transactions on spoke chain**: 1 approve (shares to shareOFT) + 1 OFT.send().\n * **Gas**: Requires native token on spoke for LZ fees, and gas on hub for steps 2+3.\n *\n * ## Tested flows\n *\n * - [x] SHARE_OFT bridge (Eth→Base, vault 0x8f74...ba6):\n * Delivery ~7 min. Required enforcedOptions on Eth SHARE_OFT for dstEid=30184.\n *\n * @param walletClient Wallet client on the SPOKE chain\n * @param publicClient Public client on the SPOKE chain\n * @param shareOFT OFTAdapter address for vault shares on the spoke chain\n * @param hubChainEid LayerZero Endpoint ID for the hub chain\n * @param shares Amount of vault shares to bridge\n * @param receiver Receiver address on the HUB chain\n * @param lzFee msg.value for OFT send (quote via OFT.quoteSend)\n * @returns Transaction hash of the OFT.send() call\n */\nexport async function bridgeSharesToHub(\n walletClient: WalletClient,\n publicClient: PublicClient,\n shareOFT: Address,\n hubChainEid: number,\n shares: bigint,\n receiver: Address,\n lzFee: bigint,\n): Promise<{ txHash: Hash }> {\n const account = walletClient.account!\n const oft = getAddress(shareOFT)\n\n // Approve OFT for share transfer\n await ensureAllowance(walletClient, publicClient, oft, oft, shares)\n\n const toBytes32 = pad(getAddress(receiver), { size: 32 })\n\n const sendParam = {\n dstEid: hubChainEid,\n to: toBytes32,\n amountLD: shares,\n minAmountLD: shares, // shares should bridge 1:1\n extraOptions: '0x' as `0x${string}`,\n composeMsg: '0x' as `0x${string}`,\n oftCmd: '0x' as `0x${string}`,\n }\n\n const fee = {\n nativeFee: lzFee,\n lzTokenFee: 0n,\n }\n\n const txHash = await walletClient.writeContract({\n address: oft,\n abi: OFT_ABI,\n functionName: 'send',\n args: [sendParam, fee, account.address],\n value: lzFee,\n account,\n chain: walletClient.chain,\n })\n\n return { txHash }\n}\n\n/**\n * R7 — Bridge underlying assets from hub back to spoke chain via OFT.\n *\n * This is the final step of a full spoke redeem flow:\n * 1. `bridgeSharesToHub()` — send shares from spoke → hub via SHARE_OFT\n * 2. `smartRedeem()` — redeem shares on hub → underlying assets (e.g. USDC)\n * 3. `bridgeAssetsToSpoke()` — bridge assets from hub → spoke via OFT\n *\n * For Stargate OFTs (stgUSDC, USDT, WETH), uses TAXI mode (oftCmd 0x01) for\n * immediate delivery. For non-Stargate OFTs, uses empty oftCmd (0x).\n *\n * **User transactions on hub chain**: 1 approve (assets to OFT) + 1 OFT.send().\n * **Gas**: Requires native token on hub for LZ fees.\n *\n * ## Tested flows\n *\n * - [x] Stargate OFT bridge (Base→Eth, stgUSDC, TAXI mode 0x01):\n * Delivery ~13 min. TX: 0x... (see redeem-async-hub.ts test)\n *\n * ## Untested flows\n *\n * - [ ] Standard OFT bridge (non-Stargate, oftCmd 0x) — needs non-Stargate asset vault\n *\n * @param walletClient Wallet client on the HUB chain\n * @param publicClient Public client on the HUB chain\n * @param assetOFT OFT address for the underlying asset on the hub chain\n * @param spokeChainEid LayerZero Endpoint ID for the spoke (destination) chain\n * @param amount Amount of underlying assets to bridge\n * @param receiver Receiver address on the SPOKE chain\n * @param lzFee msg.value for OFT send (quote via OFT.quoteSend)\n * @param isStargate Whether this is a Stargate OFT (uses TAXI mode)\n * @returns Transaction hash of the OFT.send() call\n */\nexport async function bridgeAssetsToSpoke(\n walletClient: WalletClient,\n publicClient: PublicClient,\n assetOFT: Address,\n spokeChainEid: number,\n amount: bigint,\n receiver: Address,\n lzFee: bigint,\n isStargate: boolean = true,\n): Promise<{ txHash: Hash }> {\n const account = walletClient.account!\n const oft = getAddress(assetOFT)\n\n // Read underlying token and approve if different from OFT\n const token = await publicClient.readContract({\n address: oft,\n abi: OFT_ABI,\n functionName: 'token',\n })\n\n if (getAddress(token) !== oft) {\n // OFTAdapter pattern: approve underlying token to OFT\n await ensureAllowance(walletClient, publicClient, token, oft, amount)\n } else {\n // Pure OFT: approve OFT to itself\n await ensureAllowance(walletClient, publicClient, oft, oft, amount)\n }\n\n const toBytes32 = pad(getAddress(receiver), { size: 32 })\n\n const sendParam = {\n dstEid: spokeChainEid,\n to: toBytes32,\n amountLD: amount,\n minAmountLD: amount * 99n / 100n, // 1% slippage tolerance for Stargate\n extraOptions: '0x' as `0x${string}`,\n composeMsg: '0x' as `0x${string}`,\n oftCmd: (isStargate ? '0x01' : '0x') as `0x${string}`,\n }\n\n const fee = {\n nativeFee: lzFee,\n lzTokenFee: 0n,\n }\n\n const txHash = await walletClient.writeContract({\n address: oft,\n abi: OFT_ABI,\n functionName: 'send',\n args: [sendParam, fee, account.address],\n value: lzFee,\n account,\n chain: walletClient.chain,\n })\n\n return { txHash }\n}\n\nexport interface SpokeRedeemRoute {\n /** Hub chain ID */\n hubChainId: number\n /** Spoke chain ID */\n spokeChainId: number\n /** LZ EID for the hub */\n hubEid: number\n /** LZ EID for the spoke */\n spokeEid: number\n /** Vault underlying asset address on hub (e.g. USDC on Base) */\n hubAsset: Address\n /** SHARE_OFT on spoke chain (user has shares here) */\n spokeShareOft: Address\n /** Asset OFT on hub for bridging back (e.g. Stargate USDC pool on Base) */\n hubAssetOft: Address\n /** Underlying asset address on spoke chain (e.g. USDC on Ethereum) */\n spokeAsset: Address\n /** Whether the asset OFT is a Stargate pool (determines oftCmd) */\n isStargate: boolean\n /** OFT route symbol (e.g. 'stgUSDC') */\n symbol: string\n}\n\nconst STARGATE_ASSETS = new Set(['stgUSDC', 'USDT', 'WETH'])\n\nconst FACTORY_COMPOSER_ABI = [\n {\n type: 'function' as const,\n name: 'vaultComposer' as const,\n inputs: [{ name: '_vault', type: 'address' as const }] as const,\n outputs: [{ name: '', type: 'address' as const }] as const,\n stateMutability: 'view' as const,\n },\n] as const\n\nconst REDEEM_COMPOSER_ABI = [\n {\n type: 'function' as const,\n name: 'SHARE_OFT' as const,\n inputs: [] as const,\n outputs: [{ name: '', type: 'address' as const }] as const,\n stateMutability: 'view' as const,\n },\n] as const\n\n/**\n * Resolve all addresses needed for a full spoke→hub→spoke redeem flow.\n *\n * Discovers dynamically:\n * - SHARE_OFT on the spoke chain (via hub composer → peers)\n * - Asset OFT on the hub chain (matches vault.asset() to OFT_ROUTES)\n * - Underlying asset on the spoke chain\n *\n * @param hubPublicClient Public client on the HUB chain\n * @param vault Vault address\n * @param hubChainId Hub chain ID\n * @param spokeChainId Spoke chain ID where user has shares\n * @returns All addresses needed for bridgeSharesToHub + redeemShares + bridgeAssetsToSpoke\n */\nexport async function resolveRedeemAddresses(\n hubPublicClient: PublicClient,\n vault: Address,\n hubChainId: number,\n spokeChainId: number,\n): Promise<SpokeRedeemRoute> {\n const v = getAddress(vault)\n const hubEid = CHAIN_ID_TO_EID[hubChainId]\n const spokeEid = CHAIN_ID_TO_EID[spokeChainId]\n if (!hubEid || !spokeEid) throw new Error(`No LZ EID for chainId ${!hubEid ? hubChainId : spokeChainId}`)\n\n // Read vault asset and composer address in parallel\n const [hubAsset, composerAddress] = await Promise.all([\n hubPublicClient.readContract({ address: v, abi: VAULT_ABI, functionName: 'asset' }) as Promise<Address>,\n hubPublicClient.readContract({\n address: OMNI_FACTORY_ADDRESS,\n abi: FACTORY_COMPOSER_ABI,\n functionName: 'vaultComposer',\n args: [v],\n }) as Promise<Address>,\n ])\n\n if (composerAddress === zeroAddress) {\n throw new Error(`[MoreVaults] No composer registered for vault ${vault} on hub chain ${hubChainId}`)\n }\n\n // Read SHARE_OFT from composer\n const hubShareOft = await hubPublicClient.readContract({\n address: composerAddress,\n abi: REDEEM_COMPOSER_ABI,\n functionName: 'SHARE_OFT',\n }) as Address\n\n // Get spoke SHARE_OFT via peers(spokeEid) on hub SHARE_OFT\n const spokeShareOftBytes32 = await hubPublicClient.readContract({\n address: hubShareOft,\n abi: OFT_ABI,\n functionName: 'peers',\n args: [spokeEid],\n }) as `0x${string}`\n\n // Convert bytes32 to address (last 20 bytes)\n const spokeShareOft = getAddress(`0x${spokeShareOftBytes32.slice(-40)}`) as Address\n\n // Find matching OFT route for the vault's asset on the hub chain\n let hubAssetOft: Address | null = null\n let spokeAsset: Address | null = null\n let isStargate = false\n let symbol = ''\n\n for (const [sym, chainMap] of Object.entries(OFT_ROUTES)) {\n const hubEntry = (chainMap as Record<number, { oft: string; token: string }>)[hubChainId]\n const spokeEntry = (chainMap as Record<number, { oft: string; token: string }>)[spokeChainId]\n if (!hubEntry || !spokeEntry) continue\n\n if (getAddress(hubEntry.token) === getAddress(hubAsset)) {\n hubAssetOft = getAddress(hubEntry.oft) as Address\n spokeAsset = getAddress(spokeEntry.token) as Address\n isStargate = STARGATE_ASSETS.has(sym)\n symbol = sym\n break\n }\n }\n\n if (!hubAssetOft || !spokeAsset) {\n throw new Error(\n `[MoreVaults] No OFT route found for vault asset ${hubAsset} ` +\n `between hub chain ${hubChainId} and spoke chain ${spokeChainId}`,\n )\n }\n\n return {\n hubChainId,\n spokeChainId,\n hubEid,\n spokeEid,\n hubAsset,\n spokeShareOft,\n hubAssetOft,\n spokeAsset,\n isStargate,\n symbol,\n }\n}\n","import { type Address, type PublicClient, getAddress } from 'viem'\nimport { BRIDGE_ABI, CONFIG_ABI, ERC20_ABI, VAULT_ABI, METADATA_ABI, OFT_ABI } from './abis'\nimport type { CrossChainRequestInfo } from './types'\nimport { getVaultStatus } from './utils'\nimport type { VaultStatus } from './utils'\nimport { discoverVaultTopology, OMNI_FACTORY_ADDRESS } from './topology'\nimport { createChainClient } from './spokeRoutes'\nimport { CHAIN_ID_TO_EID } from './chains'\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface UserPosition {\n /** Vault share balance */\n shares: bigint\n /** convertToAssets(shares) — what they'd get if they redeemed now */\n estimatedAssets: bigint\n /** Price of 1 full share in underlying (convertToAssets(10n ** decimals)) */\n sharePrice: bigint\n /** Vault decimals (for display) */\n decimals: number\n pendingWithdrawal: {\n shares: bigint\n timelockEndsAt: bigint\n /** block.timestamp >= timelockEndsAt (or timelockEndsAt === 0n) */\n canRedeemNow: boolean\n } | null // null if no pending withdrawal request\n}\n\n/**\n * Read the user's current position in the vault.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address (diamond proxy)\n * @param user User wallet address\n * @returns Full user position snapshot\n */\nexport async function getUserPosition(\n publicClient: PublicClient,\n vault: Address,\n user: Address,\n): Promise<UserPosition> {\n const v = getAddress(vault)\n const u = getAddress(user)\n\n // First batch: balance, decimals, withdrawal request — via multicall\n const [sharesResult, decimalsResult, withdrawalRequestResult] = await publicClient.multicall({\n contracts: [\n { address: v, abi: VAULT_ABI, functionName: 'balanceOf', args: [u] },\n { address: v, abi: METADATA_ABI, functionName: 'decimals' },\n { address: v, abi: VAULT_ABI, functionName: 'getWithdrawalRequest', args: [u] },\n ],\n allowFailure: false,\n })\n const block = await publicClient.getBlock()\n const shares = sharesResult\n const decimals = decimalsResult\n const withdrawalRequest = withdrawalRequestResult\n\n const [withdrawShares, timelockEndsAt] = withdrawalRequest as unknown as [bigint, bigint]\n\n // Second batch: convertToAssets calls (need shares and decimals from first batch)\n const oneShare = 10n ** BigInt(decimals)\n const [estimatedAssets, sharePrice] = await Promise.all([\n shares === 0n\n ? Promise.resolve(0n)\n : publicClient.readContract({ address: v, abi: VAULT_ABI, functionName: 'convertToAssets', args: [shares] }),\n publicClient.readContract({ address: v, abi: VAULT_ABI, functionName: 'convertToAssets', args: [oneShare] }),\n ])\n\n const currentTimestamp = block.timestamp\n\n const pendingWithdrawal =\n withdrawShares === 0n\n ? null\n : {\n shares: withdrawShares,\n timelockEndsAt,\n canRedeemNow: timelockEndsAt === 0n || currentTimestamp >= timelockEndsAt,\n }\n\n return {\n shares,\n estimatedAssets,\n sharePrice,\n decimals,\n pendingWithdrawal,\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Preview how many shares a given asset amount would mint.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @param assets Amount of underlying tokens to deposit\n * @returns Estimated shares to be minted\n */\nexport async function previewDeposit(\n publicClient: PublicClient,\n vault: Address,\n assets: bigint,\n): Promise<bigint> {\n return publicClient.readContract({\n address: getAddress(vault),\n abi: VAULT_ABI,\n functionName: 'previewDeposit',\n args: [assets],\n })\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Preview how many underlying assets a given share amount would redeem.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @param shares Amount of vault shares to redeem\n * @returns Estimated assets to be returned\n */\nexport async function previewRedeem(\n publicClient: PublicClient,\n vault: Address,\n shares: bigint,\n): Promise<bigint> {\n return publicClient.readContract({\n address: getAddress(vault),\n abi: VAULT_ABI,\n functionName: 'previewRedeem',\n args: [shares],\n })\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type DepositBlockReason = 'paused' | 'capacity-full' | 'not-whitelisted' | 'ok'\n\nexport interface DepositEligibility {\n allowed: boolean\n reason: DepositBlockReason\n}\n\n/**\n * Check whether a user is eligible to deposit into the vault right now.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @param user User wallet address\n * @returns Eligibility result with reason\n */\nexport async function canDeposit(\n publicClient: PublicClient,\n vault: Address,\n user: Address,\n): Promise<DepositEligibility> {\n const v = getAddress(vault)\n\n // Fetch paused + isHub + oraclesCrossChainAccounting in one batch\n const [isPaused, isHub, oraclesEnabled] = await publicClient.multicall({\n contracts: [\n { address: v, abi: CONFIG_ABI, functionName: 'paused' },\n { address: v, abi: CONFIG_ABI, functionName: 'isHub' },\n { address: v, abi: BRIDGE_ABI, functionName: 'oraclesCrossChainAccounting' },\n ],\n allowFailure: false,\n })\n\n if (isPaused) {\n return { allowed: false, reason: 'paused' }\n }\n\n // Cross-chain async hubs revert on maxDeposit — this is expected, not a whitelist block.\n // The vault accepts deposits via initVaultActionRequest instead of the standard ERC-4626 path.\n const isCrossChainAsync = isHub && !oraclesEnabled\n if (isCrossChainAsync) {\n return { allowed: true, reason: 'ok' }\n }\n\n // maxDeposit(user) can REVERT on vaults with whitelist/ACL\n let maxDepositAmount: bigint\n try {\n maxDepositAmount = await publicClient.readContract({\n address: v,\n abi: CONFIG_ABI,\n functionName: 'maxDeposit',\n args: [getAddress(user)],\n })\n } catch {\n // Revert means the vault has whitelist/ACL and this user is not approved\n return { allowed: false, reason: 'not-whitelisted' }\n }\n\n if (maxDepositAmount === 0n) {\n return { allowed: false, reason: 'capacity-full' }\n }\n return { allowed: true, reason: 'ok' }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface VaultMetadata {\n name: string\n symbol: string\n decimals: number\n underlying: Address\n underlyingSymbol: string\n underlyingDecimals: number\n}\n\n/**\n * Read display metadata for a vault and its underlying token.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @returns Vault and underlying token metadata\n */\nexport async function getVaultMetadata(\n publicClient: PublicClient,\n vault: Address,\n): Promise<VaultMetadata> {\n const v = getAddress(vault)\n\n // Batch 1: vault name, symbol, decimals, underlying — 1 eth_call via multicall\n const b1 = await publicClient.multicall({\n contracts: [\n { address: v, abi: METADATA_ABI, functionName: 'name' },\n { address: v, abi: METADATA_ABI, functionName: 'symbol' },\n { address: v, abi: METADATA_ABI, functionName: 'decimals' },\n { address: v, abi: VAULT_ABI, functionName: 'asset' },\n ] as const,\n allowFailure: false,\n })\n\n const [name, symbol, decimals, underlying] = b1\n const underlyingAddr = getAddress(underlying as Address)\n\n // Batch 2: underlying symbol + decimals — 1 eth_call via multicall\n const b2 = await publicClient.multicall({\n contracts: [\n { address: underlyingAddr, abi: METADATA_ABI, functionName: 'symbol' },\n { address: underlyingAddr, abi: METADATA_ABI, functionName: 'decimals' },\n ] as const,\n allowFailure: false,\n })\n\n const [underlyingSymbol, underlyingDecimals] = b2\n\n return {\n name,\n symbol,\n decimals,\n underlying: underlyingAddr,\n underlyingSymbol,\n underlyingDecimals,\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type AsyncRequestStatus = 'pending' | 'ready-to-execute' | 'completed' | 'refunded'\n\nexport interface AsyncRequestStatusInfo {\n status: AsyncRequestStatus\n /** Human-readable description */\n label: string\n /** Shares minted or assets returned (0 if still pending) */\n result: bigint\n}\n\n/**\n * Get the human-readable status of an async cross-chain request.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @param guid Request GUID returned by depositAsync / mintAsync / redeemAsync\n * @returns Status info with label and result\n */\nexport async function getAsyncRequestStatusLabel(\n publicClient: PublicClient,\n vault: Address,\n guid: `0x${string}`,\n): Promise<AsyncRequestStatusInfo> {\n const v = getAddress(vault)\n\n const [info, finalizationResult] = await Promise.all([\n publicClient.readContract({\n address: v,\n abi: BRIDGE_ABI,\n functionName: 'getRequestInfo',\n args: [guid],\n }) as Promise<CrossChainRequestInfo>,\n publicClient.readContract({\n address: v,\n abi: BRIDGE_ABI,\n functionName: 'getFinalizationResult',\n args: [guid],\n }),\n ])\n\n if (info.refunded) {\n return {\n status: 'refunded',\n label: 'Request refunded — tokens returned to initiator',\n result: 0n,\n }\n }\n if (info.finalized) {\n return {\n status: 'completed',\n label: 'Completed',\n result: finalizationResult,\n }\n }\n if (info.fulfilled) {\n return {\n status: 'ready-to-execute',\n label: 'Oracle responded — ready to execute',\n result: 0n,\n }\n }\n return {\n status: 'pending',\n label: 'Waiting for cross-chain oracle response...',\n result: 0n,\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface UserBalances {\n /** Vault shares the user holds */\n shareBalance: bigint\n /** Underlying token balance in wallet (for deposit input) */\n underlyingBalance: bigint\n /** convertToAssets(shareBalance) — vault position value */\n estimatedAssets: bigint\n}\n\n/**\n * Read the user's token balances relevant to a vault.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @param user User wallet address\n * @returns Share balance, underlying wallet balance, and estimated assets\n */\nexport async function getUserBalances(\n publicClient: PublicClient,\n vault: Address,\n user: Address,\n): Promise<UserBalances> {\n const v = getAddress(vault)\n const u = getAddress(user)\n\n // Batch 1: get underlying address, share balance, decimals\n const [shareBalance, , underlying] = await publicClient.multicall({\n contracts: [\n { address: v, abi: VAULT_ABI, functionName: 'balanceOf', args: [u] },\n { address: v, abi: METADATA_ABI, functionName: 'decimals' },\n { address: v, abi: VAULT_ABI, functionName: 'asset' },\n ],\n allowFailure: false,\n })\n\n const underlyingAddr = getAddress(underlying)\n\n // Batch 2: underlying balance + estimated assets (skip convertToAssets if no shares)\n const [underlyingBalance, estimatedAssets] = await Promise.all([\n publicClient.readContract({\n address: underlyingAddr,\n abi: ERC20_ABI,\n functionName: 'balanceOf',\n args: [u],\n }),\n shareBalance === 0n\n ? Promise.resolve(0n)\n : publicClient.readContract({\n address: v,\n abi: VAULT_ABI,\n functionName: 'convertToAssets',\n args: [shareBalance],\n }),\n ])\n\n return {\n shareBalance,\n underlyingBalance,\n estimatedAssets,\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface MaxWithdrawable {\n /** How many shares can be redeemed right now */\n shares: bigint\n /** How many underlying assets that corresponds to */\n assets: bigint\n}\n\n/**\n * Calculate the maximum amount a user can withdraw from a vault right now.\n *\n * For hub vaults without oracle accounting, this is limited by hub liquidity.\n * For local and oracle vaults, all assets are immediately redeemable.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @param user User wallet address\n * @returns Maximum withdrawable shares and assets\n */\nexport async function getMaxWithdrawable(\n publicClient: PublicClient,\n vault: Address,\n user: Address,\n): Promise<MaxWithdrawable> {\n const v = getAddress(vault)\n const u = getAddress(user)\n\n // Batch 1: isHub, oraclesCrossChainAccounting, user share balance, underlying address\n const [isHub, oraclesEnabled, userShares, underlying] = await publicClient.multicall({\n contracts: [\n { address: v, abi: CONFIG_ABI, functionName: 'isHub' },\n { address: v, abi: BRIDGE_ABI, functionName: 'oraclesCrossChainAccounting' },\n { address: v, abi: VAULT_ABI, functionName: 'balanceOf', args: [u] },\n { address: v, abi: VAULT_ABI, functionName: 'asset' },\n ],\n allowFailure: false,\n })\n\n if (userShares === 0n) {\n return { shares: 0n, assets: 0n }\n }\n\n const underlyingAddr = getAddress(underlying)\n\n // Batch 2: estimated assets for user shares + hub liquid balance\n const [estimatedAssets, hubLiquidBalance] = await Promise.all([\n publicClient.readContract({\n address: v,\n abi: VAULT_ABI,\n functionName: 'convertToAssets',\n args: [userShares],\n }),\n publicClient.readContract({\n address: underlyingAddr,\n abi: ERC20_ABI,\n functionName: 'balanceOf',\n args: [v],\n }),\n ])\n\n let maxAssets: bigint\n if (isHub && !oraclesEnabled) {\n // Hub vault: limited by hub liquidity\n maxAssets = estimatedAssets < hubLiquidBalance ? estimatedAssets : hubLiquidBalance\n } else {\n // Local or oracle vault: all assets redeemable\n maxAssets = estimatedAssets\n }\n\n // Convert back to shares if limited by hub liquidity\n let maxShares: bigint\n if (maxAssets < estimatedAssets) {\n maxShares = await publicClient.readContract({\n address: v,\n abi: VAULT_ABI,\n functionName: 'convertToShares',\n args: [maxAssets],\n })\n } else {\n maxShares = userShares\n }\n\n return {\n shares: maxShares,\n assets: maxAssets,\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type VaultSummary = VaultStatus & VaultMetadata\n\n/**\n * Get a combined snapshot of vault status and metadata in one call.\n *\n * @param publicClient Public client for reads\n * @param vault Vault address\n * @returns Merged VaultStatus and VaultMetadata\n */\nexport async function getVaultSummary(\n publicClient: PublicClient,\n vault: Address,\n): Promise<VaultSummary> {\n const [status, metadata] = await Promise.all([\n getVaultStatus(publicClient, vault),\n getVaultMetadata(publicClient, vault),\n ])\n return { ...status, ...metadata }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst FACTORY_COMPOSER_ABI = [\n {\n type: 'function' as const,\n name: 'vaultComposer',\n inputs: [{ name: '_vault', type: 'address' }],\n outputs: [{ name: '', type: 'address' }],\n stateMutability: 'view' as const,\n },\n] as const\n\nconst COMPOSER_SHARE_OFT_ABI = [\n {\n type: 'function' as const,\n name: 'SHARE_OFT',\n inputs: [],\n outputs: [{ name: '', type: 'address' }],\n stateMutability: 'view' as const,\n },\n] as const\n\nexport interface MultiChainUserPosition {\n /** Shares held directly on the hub vault (vault.balanceOf) */\n hubShares: bigint\n /** Per-spoke SHARE_OFT balances: { [chainId]: bigint } */\n spokeShares: Record<number, bigint>\n /** hubShares + sum of all spokeShares */\n totalShares: bigint\n /** convertToAssets(totalShares) on the hub */\n estimatedAssets: bigint\n /** Share price: convertToAssets(10^decimals) */\n sharePrice: bigint\n /** Vault decimals */\n decimals: number\n /** Pending async withdrawal request on hub, or null */\n pendingWithdrawal: {\n shares: bigint\n timelockEndsAt: bigint\n canRedeemNow: boolean\n } | null\n}\n\n/**\n * Read the user's position across all chains of an omni vault.\n *\n * Discovers topology automatically, reads hub shares + pending withdrawal,\n * then reads SHARE_OFT balances on each spoke chain in parallel.\n *\n * For local (single-chain) vaults, spokeShares will be empty and this\n * behaves identically to getUserPosition.\n *\n * @param vault Vault address (same on all chains via CREATE3)\n * @param user User wallet address\n * @returns Aggregated position across all chains\n */\nexport async function getUserPositionMultiChain(\n vault: Address,\n user: Address,\n): Promise<MultiChainUserPosition> {\n const v = getAddress(vault)\n const u = getAddress(user)\n\n // Step 1: discover topology\n const topo = await discoverVaultTopology(vault)\n const hubClient = createChainClient(topo.hubChainId)\n if (!hubClient) throw new Error(`No public RPC for hub chainId ${topo.hubChainId}`)\n\n // Step 2: read hub data (shares, decimals, withdrawal request)\n const [hubShares, decimals, withdrawalRequest] = await (hubClient as PublicClient).multicall({\n contracts: [\n { address: v, abi: VAULT_ABI, functionName: 'balanceOf', args: [u] },\n { address: v, abi: METADATA_ABI, functionName: 'decimals' },\n { address: v, abi: VAULT_ABI, functionName: 'getWithdrawalRequest', args: [u] },\n ],\n allowFailure: false,\n })\n\n const [withdrawShares, timelockEndsAt] = withdrawalRequest as unknown as [bigint, bigint]\n\n // Step 3: resolve SHARE_OFT addresses for spokes (if any)\n const spokeShares: Record<number, bigint> = {}\n\n if (topo.spokeChainIds.length > 0) {\n // Get hub SHARE_OFT via factory → composer → SHARE_OFT\n let hubShareOft: Address | null = null\n try {\n const composerAddress = await (hubClient as PublicClient).readContract({\n address: OMNI_FACTORY_ADDRESS,\n abi: FACTORY_COMPOSER_ABI,\n functionName: 'vaultComposer',\n args: [v],\n }) as Address\n\n if (composerAddress !== '0x0000000000000000000000000000000000000000') {\n hubShareOft = await (hubClient as PublicClient).readContract({\n address: composerAddress,\n abi: COMPOSER_SHARE_OFT_ABI,\n functionName: 'SHARE_OFT',\n }) as Address\n }\n } catch { /* no composer — skip spoke reads */ }\n\n if (hubShareOft) {\n // Read spoke SHARE_OFT addresses via peers() and balances in parallel\n const spokePromises = topo.spokeChainIds.map(async (spokeChainId) => {\n try {\n const spokeEid = CHAIN_ID_TO_EID[spokeChainId]\n if (!spokeEid) return { chainId: spokeChainId, balance: 0n }\n\n // Get spoke SHARE_OFT address from hub peers()\n const spokeOftBytes32 = await (hubClient as PublicClient).readContract({\n address: hubShareOft!,\n abi: OFT_ABI,\n functionName: 'peers',\n args: [spokeEid],\n }) as `0x${string}`\n\n const spokeOft = getAddress(`0x${spokeOftBytes32.slice(-40)}`) as Address\n if (spokeOft === '0x0000000000000000000000000000000000000000') {\n return { chainId: spokeChainId, balance: 0n }\n }\n\n // Read balance on spoke chain\n const spokeClient = createChainClient(spokeChainId)\n if (!spokeClient) return { chainId: spokeChainId, balance: 0n }\n\n const balance = await (spokeClient as PublicClient).readContract({\n address: spokeOft,\n abi: ERC20_ABI,\n functionName: 'balanceOf',\n args: [u],\n })\n\n return { chainId: spokeChainId, balance }\n } catch {\n return { chainId: spokeChainId, balance: 0n }\n }\n })\n\n const results = await Promise.all(spokePromises)\n for (const { chainId, balance } of results) {\n spokeShares[chainId] = balance\n }\n }\n }\n\n // Step 4: compute totals\n const totalSpokeShares = Object.values(spokeShares).reduce((sum, b) => sum + b, 0n)\n const totalShares = hubShares + totalSpokeShares\n\n const oneShare = 10n ** BigInt(decimals)\n const [estimatedAssets, sharePrice] = await Promise.all([\n totalShares === 0n\n ? Promise.resolve(0n)\n : (hubClient as PublicClient).readContract({ address: v, abi: VAULT_ABI, functionName: 'convertToAssets', args: [totalShares] }),\n (hubClient as PublicClient).readContract({ address: v, abi: VAULT_ABI, functionName: 'convertToAssets', args: [oneShare] }),\n ])\n\n // Step 5: pending withdrawal\n const block = await (hubClient as PublicClient).getBlock()\n const pendingWithdrawal = withdrawShares === 0n\n ? null\n : {\n shares: withdrawShares,\n timelockEndsAt,\n canRedeemNow: timelockEndsAt === 0n || block.timestamp >= timelockEndsAt,\n }\n\n return {\n hubShares,\n spokeShares,\n totalShares,\n estimatedAssets,\n sharePrice,\n decimals,\n pendingWithdrawal,\n }\n}\n","import type { Address, PublicClient } from 'viem'\nimport { getVaultStatus } from './utils.js'\nimport { getVaultTopology } from './topology.js'\n\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface SpokeBalance {\n chainId: number\n totalAssets: bigint\n /** false if the RPC call to this spoke failed */\n isReachable: boolean\n}\n\nexport interface VaultDistribution {\n hubChainId: number\n /** Underlying token balance idle on the hub (not deployed to strategies) */\n hubLiquidBalance: bigint\n /** Hub totalAssets minus hubLiquidBalance (capital in Morpho, Aave, etc.) */\n hubStrategyBalance: bigint\n /** Hub vault totalAssets() */\n hubTotalAssets: bigint\n /** What the hub's accounting thinks is deployed on spokes */\n spokesDeployedBalance: bigint\n /** Actual per-spoke balances read directly from each spoke chain */\n spokeBalances: SpokeBalance[]\n /** hubTotalAssets + sum of reachable spoke totalAssets */\n totalActual: bigint\n oracleAccountingEnabled: boolean\n}\n\n/**\n * Read the full cross-chain capital distribution of a vault.\n *\n * Queries the hub for its status, then reads `totalAssets()` on each spoke\n * chain in parallel. Spoke calls are individually wrapped so a single\n * unreachable RPC never fails the entire call.\n *\n * @param hubClient Public client connected to the hub chain\n * @param vault Vault address (same on all chains via CREATE3)\n * @param spokeClients Map of chainId → PublicClient for each spoke chain\n *\n * @example\n * ```ts\n * const dist = await getVaultDistribution(baseClient, VAULT, {\n * [1]: ethClient,\n * [42161]: arbClient,\n * })\n * console.log(`Hub liquid: ${dist.hubLiquidBalance}`)\n * console.log(`Total actual: ${dist.totalActual}`)\n * ```\n */\nexport async function getVaultDistribution(\n hubClient: PublicClient,\n vault: Address,\n spokeClients: Record<number, PublicClient>,\n): Promise<VaultDistribution> {\n // Read hub status\n const hubStatus = await getVaultStatus(hubClient, vault)\n\n const hubChainId = Number(hubClient.chain?.id ?? 0)\n const hubTotalAssets = hubStatus.totalAssets\n const hubLiquidBalance = hubStatus.hubLiquidBalance\n const hubStrategyBalance = hubTotalAssets > hubLiquidBalance\n ? hubTotalAssets - hubLiquidBalance\n : 0n\n\n // Read each spoke's totalAssets in parallel, never throwing\n const spokeEntries = Object.entries(spokeClients).map(([chainIdStr, client]) => ({\n chainId: Number(chainIdStr),\n client,\n }))\n\n const spokeBalances: SpokeBalance[] = await Promise.all(\n spokeEntries.map(async ({ chainId, client }): Promise<SpokeBalance> => {\n try {\n const spokeStatus = await getVaultStatus(client, vault)\n return { chainId, totalAssets: spokeStatus.totalAssets, isReachable: true }\n } catch {\n return { chainId, totalAssets: 0n, isReachable: false }\n }\n }),\n )\n\n // totalActual = hub + reachable spokes\n const reachableSpokeSum = spokeBalances\n .filter(s => s.isReachable)\n .reduce((acc, s) => acc + s.totalAssets, 0n)\n\n const totalActual = hubTotalAssets + reachableSpokeSum\n\n return {\n hubChainId,\n hubLiquidBalance,\n hubStrategyBalance,\n hubTotalAssets,\n spokesDeployedBalance: hubStatus.spokesDeployedBalance,\n spokeBalances,\n totalActual,\n oracleAccountingEnabled: hubStatus.oracleAccountingEnabled,\n }\n}\n\n/**\n * Hub-only distribution — uses topology to discover spokes but does NOT\n * read spoke chains (no spoke clients needed).\n *\n * Returns hub data plus the list of spoke chainIds from the factory.\n * `spokeBalances` will be empty — callers must provide spoke clients to\n * `getVaultDistribution` for actual spoke reads.\n *\n * @param hubClient Public client connected to the hub chain\n * @param vault Vault address\n *\n * @example\n * ```ts\n * const dist = await getVaultDistributionWithTopology(baseClient, VAULT)\n * // dist.spokeBalances === [] (no spoke clients provided)\n * // dist.spokeChainIds tells you which chains to query\n * ```\n */\nexport async function getVaultDistributionWithTopology(\n hubClient: PublicClient,\n vault: Address,\n): Promise<VaultDistribution & { spokeChainIds: number[] }> {\n // Read hub status and topology in parallel\n const [hubStatus, topology] = await Promise.all([\n getVaultStatus(hubClient, vault),\n getVaultTopology(hubClient, vault),\n ])\n\n const hubChainId = Number(hubClient.chain?.id ?? 0)\n const hubTotalAssets = hubStatus.totalAssets\n const hubLiquidBalance = hubStatus.hubLiquidBalance\n const hubStrategyBalance = hubTotalAssets > hubLiquidBalance\n ? hubTotalAssets - hubLiquidBalance\n : 0n\n\n return {\n hubChainId,\n hubLiquidBalance,\n hubStrategyBalance,\n hubTotalAssets,\n spokesDeployedBalance: hubStatus.spokesDeployedBalance,\n spokeBalances: [],\n totalActual: hubTotalAssets, // hub-only, no spoke data\n oracleAccountingEnabled: hubStatus.oracleAccountingEnabled,\n spokeChainIds: topology.spokeChainIds,\n }\n}\n","import type { PublicClient } from 'viem'\n\n/**\n * Cast a wagmi PublicClient to the SDK's expected type.\n * Use this in React components to avoid `as any` casts:\n * ```ts\n * import { usePublicClient } from 'wagmi'\n * import { asSdkClient } from '@oydual31/more-vaults-sdk/viem'\n * const pc = asSdkClient(usePublicClient())\n * ```\n * wagmi v2 uses viem as a peer dependency, so the types are structurally\n * identical — this function validates the client is non-null and applies\n * a documented cast instead of an opaque `as any`.\n */\nexport function asSdkClient(client: unknown): PublicClient {\n if (!client) throw new Error('[MoreVaults] No public client available. Make sure wagmi is configured correctly.')\n return client as PublicClient\n}\n","import { useQuery } from '@tanstack/react-query'\nimport { usePublicClient } from 'wagmi'\nimport { asSdkClient, getVaultStatus } from '../viem/index.js'\nimport type { VaultStatus } from '../viem/index.js'\n\nexport type { VaultStatus }\n\ninterface UseVaultStatusOptions {\n /** Refetch interval in ms. Default: 30_000 (30s) */\n refetchInterval?: number\n}\n\n/**\n * Read the full vault status snapshot.\n * Automatically refetches on a configurable interval.\n *\n * @example\n * const { data: status, isLoading } = useVaultStatus('0xVAULT', 747)\n * if (status?.mode === 'cross-chain-async') { ... }\n */\nexport function useVaultStatus(\n vault: `0x${string}` | undefined,\n chainId: number,\n options?: UseVaultStatusOptions,\n) {\n const publicClient = usePublicClient({ chainId })\n return useQuery({\n queryKey: ['vaultStatus', vault, chainId],\n queryFn: () => getVaultStatus(asSdkClient(publicClient), vault!),\n enabled: !!vault && !!publicClient,\n refetchInterval: options?.refetchInterval ?? 30_000,\n staleTime: 15_000,\n })\n}\n","import { useQuery } from '@tanstack/react-query'\nimport { usePublicClient } from 'wagmi'\nimport { asSdkClient, getVaultMetadata } from '../viem/index.js'\nimport type { VaultMetadata } from '../viem/index.js'\n\nexport type { VaultMetadata }\n\n/**\n * Read display metadata for a vault and its underlying token.\n * Uses a long stale time (5 min) because metadata rarely changes.\n *\n * @example\n * const { data: meta } = useVaultMetadata('0xVAULT', 747)\n * // meta.name, meta.symbol, meta.underlying, meta.underlyingSymbol\n */\nexport function useVaultMetadata(\n vault: `0x${string}` | undefined,\n chainId: number,\n) {\n const publicClient = usePublicClient({ chainId })\n return useQuery({\n queryKey: ['vaultMetadata', vault, chainId],\n queryFn: () => getVaultMetadata(asSdkClient(publicClient), vault!),\n enabled: !!vault && !!publicClient,\n // Metadata (name, symbol, underlying) changes very rarely — 5 min stale time\n staleTime: 5 * 60_000,\n refetchInterval: 5 * 60_000,\n })\n}\n","import { useQuery } from '@tanstack/react-query'\nimport { usePublicClient } from 'wagmi'\nimport { asSdkClient, getUserPosition } from '../viem/index.js'\nimport type { UserPosition } from '../viem/index.js'\n\nexport type { UserPosition }\n\n/**\n * Read the user's current position in a vault.\n * Refetches every 15s to keep the balance display current.\n *\n * @example\n * const { data: position } = useUserPosition('0xVAULT', '0xUSER', 747)\n * // position.shares, position.estimatedAssets, position.pendingWithdrawal\n */\nexport function useUserPosition(\n vault: `0x${string}` | undefined,\n user: `0x${string}` | undefined,\n chainId: number,\n) {\n const publicClient = usePublicClient({ chainId })\n return useQuery({\n queryKey: ['userPosition', vault, user, chainId],\n queryFn: () => getUserPosition(asSdkClient(publicClient), vault!, user!),\n enabled: !!vault && !!user && !!publicClient,\n refetchInterval: 15_000,\n staleTime: 10_000,\n })\n}\n","import { useQuery } from '@tanstack/react-query'\nimport { getUserPositionMultiChain } from '../viem/userHelpers.js'\nimport type { MultiChainUserPosition } from '../viem/userHelpers.js'\n\nexport type { MultiChainUserPosition }\n\n/**\n * Read the user's position across all chains of an omni vault.\n *\n * Discovers topology automatically, reads hub shares + pending withdrawal,\n * then reads SHARE_OFT balances on each spoke chain in parallel.\n * Works without a connected wallet (uses public RPCs).\n *\n * @example\n * const { data: position } = useUserPositionMultiChain('0xVAULT', '0xUSER')\n * // position.hubShares — shares on hub (Base)\n * // position.spokeShares — { 1: 500n, 42161: 0n } per spoke\n * // position.totalShares — hub + all spokes\n * // position.estimatedAssets — convertToAssets(totalShares)\n * // position.pendingWithdrawal — async withdrawal if any\n */\nexport function useUserPositionMultiChain(\n vault: `0x${string}` | undefined,\n user: `0x${string}` | undefined,\n) {\n return useQuery<MultiChainUserPosition>({\n queryKey: ['userPositionMultiChain', vault, user],\n queryFn: () => getUserPositionMultiChain(vault!, user!),\n enabled: !!vault && !!user,\n refetchInterval: 30_000,\n staleTime: 15_000,\n })\n}\n","import { useQuery } from '@tanstack/react-query'\nimport { usePublicClient } from 'wagmi'\nimport { asSdkClient, quoteLzFee } from '../viem/index.js'\n\n/**\n * Quote the LayerZero fee required for async operations (D4, D5, R5).\n * Refreshes every 60s — fees change with network congestion.\n *\n * @example\n * const { fee, feeWithBuffer } = useLzFee('0xVAULT', 747)\n * // feeWithBuffer adds 1% buffer automatically (fee * 101 / 100)\n */\nexport function useLzFee(vault: `0x${string}` | undefined, chainId: number) {\n const publicClient = usePublicClient({ chainId })\n const query = useQuery({\n queryKey: ['lzFee', vault, chainId],\n queryFn: () => quoteLzFee(asSdkClient(publicClient), vault!),\n enabled: !!vault && !!publicClient,\n refetchInterval: 60_000,\n staleTime: 30_000,\n })\n return {\n ...query,\n fee: query.data,\n feeWithBuffer: query.data ? (query.data * 101n) / 100n : undefined,\n }\n}\n","import { useQuery } from '@tanstack/react-query'\nimport { usePublicClient } from 'wagmi'\nimport { asSdkClient, getAsyncRequestStatusLabel } from '../viem/index.js'\nimport type { AsyncRequestStatusInfo } from '../viem/index.js'\n\nexport type { AsyncRequestStatusInfo }\n\n/**\n * Poll the status of an async cross-chain request (D4/D5/R5) by GUID.\n *\n * Automatically stops polling when status reaches 'completed' or 'refunded'.\n * Polls every 10s while the request is still pending or ready-to-execute.\n *\n * @example\n * const { data } = useAsyncRequestStatus('0xVAULT', guid, 747)\n * // data.status: 'pending' | 'ready-to-execute' | 'completed' | 'refunded'\n * // data.label: human-readable description\n * // data.result: shares minted or assets returned (0n while pending)\n */\nexport function useAsyncRequestStatus(\n vault: `0x${string}` | undefined,\n guid: `0x${string}` | undefined,\n chainId: number,\n) {\n const publicClient = usePublicClient({ chainId })\n return useQuery<AsyncRequestStatusInfo>({\n queryKey: ['asyncRequestStatus', vault, guid, chainId],\n queryFn: () => getAsyncRequestStatusLabel(asSdkClient(publicClient), vault!, guid!),\n enabled: !!vault && !!guid && !!publicClient,\n refetchInterval: (query) => {\n const status = query.state.data?.status\n if (status === 'completed' || status === 'refunded') return false\n return 10_000\n },\n })\n}\n","import { usePublicClient, useChainId } from 'wagmi'\nimport { useQuery } from '@tanstack/react-query'\nimport { asSdkClient } from '../viem/wagmiCompat.js'\nimport {\n discoverVaultTopology,\n isOnHubChain,\n getAllVaultChainIds,\n OMNI_FACTORY_ADDRESS,\n} from '../viem/topology.js'\nimport type { VaultTopology } from '../viem/topology.js'\nimport type { Address } from 'viem'\n\nexport type { VaultTopology }\n\ninterface UseVaultTopologyReturn {\n topology: VaultTopology | undefined\n isLoading: boolean\n /**\n * true when the connected wallet is on the wrong chain to deposit.\n * Show a \"Switch to {hubChainId}\" prompt when this is true.\n */\n needsNetworkSwitch: boolean\n /**\n * All chain IDs where this vault exists (hub + spokes).\n * Use to build a multi-chain network selector.\n */\n allChainIds: number[]\n}\n\n/**\n * Resolve the cross-chain topology of a vault with automatic multi-chain discovery.\n *\n * Uses `discoverVaultTopology` internally: if the wallet's current chain doesn't\n * know the vault, it iterates all supported chains via public RPCs until the hub\n * is found. Works even without a connected wallet.\n *\n * @example\n * // Works regardless of which chain the wallet is on (or if disconnected)\n * const { topology, needsNetworkSwitch, allChainIds } = useVaultTopology('0xVAULT')\n *\n * if (needsNetworkSwitch) {\n * return <SwitchNetworkButton chainId={topology.hubChainId} />\n * }\n */\nexport function useVaultTopology(\n vault: Address | undefined,\n factoryAddress: Address = OMNI_FACTORY_ADDRESS,\n): UseVaultTopologyReturn {\n const currentChainId = useChainId()\n const publicClient = usePublicClient()\n\n const { data: topology, isLoading } = useQuery<VaultTopology>({\n // Key does NOT include currentChainId — topology is chain-independent\n queryKey: ['vaultTopology', vault, factoryAddress],\n queryFn: () => discoverVaultTopology(\n vault!,\n publicClient ? asSdkClient(publicClient) : null,\n factoryAddress,\n ),\n enabled: !!vault,\n staleTime: 5 * 60 * 1000, // topology rarely changes — 5 min cache\n })\n\n const needsNetworkSwitch = topology ? !isOnHubChain(currentChainId, topology) : false\n const allChainIds = topology ? getAllVaultChainIds(topology) : []\n\n return { topology, isLoading, needsNetworkSwitch, allChainIds }\n}\n","import { useState, useCallback } from 'react'\nimport { usePublicClient, useWalletClient, useChainId } from 'wagmi'\nimport {\n asSdkClient,\n depositAsync,\n getVaultStatus,\n} from '../viem/index.js'\nimport type { AsyncRequestStatusInfo } from '../viem/index.js'\nimport { useLzFee } from './useLzFee.js'\nimport { useAsyncRequestStatus } from './useAsyncRequestStatus.js'\n\ninterface UseOmniDepositReturn {\n /** Execute approve + depositAsync. Handles everything internally. */\n deposit: (amountInWei: bigint, receiver: `0x${string}`) => Promise<void>\n isLoading: boolean\n txHash: `0x${string}` | undefined\n /** GUID for cross-chain tracking. Available after tx confirmation. */\n guid: `0x${string}` | undefined\n /** Cross-chain request status. undefined until a guid is available. */\n requestStatus: AsyncRequestStatusInfo | undefined\n /** true when the wallet is connected to the wrong chain */\n wrongChain: boolean\n error: Error | undefined\n reset: () => void\n}\n\n/**\n * Complete hook for async deposits on hub vaults (D4 flow).\n *\n * Handles: fee quote, chain validation, approve, depositAsync, and GUID polling.\n * The deposit function wraps the entire flow — callers only pass amount + receiver.\n *\n * @example\n * const { deposit, isLoading, guid, requestStatus, wrongChain } = useOmniDeposit('0xVAULT', 747)\n *\n * if (wrongChain) return <SwitchNetworkButton chainId={747} />\n *\n * await deposit(parseUnits('100', 6), userAddress)\n * // requestStatus.status goes: 'pending' → 'completed' | 'refunded'\n */\nexport function useOmniDeposit(\n vault: `0x${string}` | undefined,\n hubChainId: number,\n): UseOmniDepositReturn {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const { data: walletClient } = useWalletClient({ chainId: hubChainId })\n const publicClient = usePublicClient({ chainId: hubChainId })\n const currentChainId = useChainId()\n\n const [isLoading, setIsLoading] = useState(false)\n const [txHash, setTxHash] = useState<`0x${string}` | undefined>()\n const [guid, setGuid] = useState<`0x${string}` | undefined>()\n const [error, setError] = useState<Error | undefined>()\n\n const { feeWithBuffer } = useLzFee(vault, hubChainId)\n const { data: requestStatus } = useAsyncRequestStatus(vault, guid, hubChainId)\n\n const wrongChain = currentChainId !== hubChainId\n\n const deposit = useCallback(\n async (amountInWei: bigint, receiver: `0x${string}`) => {\n if (!vault || !walletClient || !publicClient || !feeWithBuffer) return\n setIsLoading(true)\n setError(undefined)\n try {\n const pc = asSdkClient(publicClient)\n const status = await getVaultStatus(pc, vault)\n // walletClient from wagmi is structurally compatible with viem WalletClient\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await depositAsync(\n walletClient as any,\n pc,\n { vault, escrow: status.escrow, hubChainId },\n amountInWei,\n receiver,\n feeWithBuffer,\n )\n setTxHash(result.txHash)\n setGuid(result.guid)\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)))\n } finally {\n setIsLoading(false)\n }\n },\n [vault, walletClient, publicClient, feeWithBuffer, hubChainId],\n )\n\n const reset = useCallback(() => {\n setTxHash(undefined)\n setGuid(undefined)\n setError(undefined)\n setIsLoading(false)\n }, [])\n\n return { deposit, isLoading, txHash, guid, requestStatus, wrongChain, error, reset }\n}\n","import { useState, useCallback } from 'react'\nimport { usePublicClient, useWalletClient, useChainId } from 'wagmi'\nimport {\n asSdkClient,\n redeemAsync,\n getVaultStatus,\n} from '../viem/index.js'\nimport type { AsyncRequestStatusInfo } from '../viem/index.js'\nimport { useLzFee } from './useLzFee.js'\nimport { useAsyncRequestStatus } from './useAsyncRequestStatus.js'\n\ninterface UseOmniRedeemReturn {\n /** Execute approve + redeemAsync. Handles everything internally. */\n redeem: (sharesInWei: bigint, receiver: `0x${string}`, owner: `0x${string}`) => Promise<void>\n isLoading: boolean\n txHash: `0x${string}` | undefined\n /** GUID for cross-chain tracking. Available after tx confirmation. */\n guid: `0x${string}` | undefined\n /** Cross-chain request status. undefined until a guid is available. */\n requestStatus: AsyncRequestStatusInfo | undefined\n /** true when the wallet is connected to the wrong chain */\n wrongChain: boolean\n error: Error | undefined\n reset: () => void\n}\n\n/**\n * Complete hook for async redeems on hub vaults (R5 flow).\n *\n * Handles: fee quote, chain validation, share approve, redeemAsync, and GUID polling.\n *\n * @example\n * const { redeem, isLoading, guid, requestStatus, wrongChain } = useOmniRedeem('0xVAULT', 747)\n *\n * if (wrongChain) return <SwitchNetworkButton chainId={747} />\n *\n * await redeem(sharesInWei, userAddress, userAddress)\n * // requestStatus.status goes: 'pending' → 'completed' | 'refunded'\n */\nexport function useOmniRedeem(\n vault: `0x${string}` | undefined,\n hubChainId: number,\n): UseOmniRedeemReturn {\n const { data: walletClient } = useWalletClient({ chainId: hubChainId })\n const publicClient = usePublicClient({ chainId: hubChainId })\n const currentChainId = useChainId()\n\n const [isLoading, setIsLoading] = useState(false)\n const [txHash, setTxHash] = useState<`0x${string}` | undefined>()\n const [guid, setGuid] = useState<`0x${string}` | undefined>()\n const [error, setError] = useState<Error | undefined>()\n\n const { feeWithBuffer } = useLzFee(vault, hubChainId)\n const { data: requestStatus } = useAsyncRequestStatus(vault, guid, hubChainId)\n\n const wrongChain = currentChainId !== hubChainId\n\n const redeem = useCallback(\n async (sharesInWei: bigint, receiver: `0x${string}`, owner: `0x${string}`) => {\n if (!vault || !walletClient || !publicClient || !feeWithBuffer) return\n setIsLoading(true)\n setError(undefined)\n try {\n const pc = asSdkClient(publicClient)\n const status = await getVaultStatus(pc, vault)\n // walletClient from wagmi is structurally compatible with viem WalletClient\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await redeemAsync(\n walletClient as any,\n pc,\n { vault, escrow: status.escrow, hubChainId },\n sharesInWei,\n receiver,\n owner,\n feeWithBuffer,\n )\n setTxHash(result.txHash)\n setGuid(result.guid)\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)))\n } finally {\n setIsLoading(false)\n }\n },\n [vault, walletClient, publicClient, feeWithBuffer, hubChainId],\n )\n\n const reset = useCallback(() => {\n setTxHash(undefined)\n setGuid(undefined)\n setError(undefined)\n setIsLoading(false)\n }, [])\n\n return { redeem, isLoading, txHash, guid, requestStatus, wrongChain, error, reset }\n}\n","import { useState, useCallback } from 'react'\nimport { usePublicClient, useWalletClient } from 'wagmi'\nimport { asSdkClient, depositSimple } from '../viem/index.js'\nimport type { DepositResult } from '../viem/index.js'\n\ninterface UseDepositSimpleReturn {\n /** Execute approve + depositSimple (D1/D3 flows). */\n deposit: (amountInWei: bigint, receiver: `0x${string}`) => Promise<void>\n isLoading: boolean\n txHash: `0x${string}` | undefined\n /** Shares minted. Available after tx confirmation. */\n shares: bigint | undefined\n error: Error | undefined\n reset: () => void\n}\n\n/**\n * Hook for local and oracle-on cross-chain vaults (D1/D3 flows).\n *\n * Simpler than useOmniDeposit — no LZ fee, no GUID, no polling.\n * One approve + one deposit transaction.\n *\n * @example\n * const { deposit, isLoading, txHash, shares } = useDepositSimple('0xVAULT', 747)\n * await deposit(parseUnits('100', 6), userAddress)\n */\nexport function useDepositSimple(\n vault: `0x${string}` | undefined,\n chainId: number,\n): UseDepositSimpleReturn {\n const { data: walletClient } = useWalletClient({ chainId })\n const publicClient = usePublicClient({ chainId })\n\n const [isLoading, setIsLoading] = useState(false)\n const [result, setResult] = useState<DepositResult | undefined>()\n const [error, setError] = useState<Error | undefined>()\n\n const deposit = useCallback(\n async (amountInWei: bigint, receiver: `0x${string}`) => {\n if (!vault || !walletClient || !publicClient) return\n setIsLoading(true)\n setError(undefined)\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const res = await depositSimple(\n walletClient as any,\n asSdkClient(publicClient),\n { vault, hubChainId: chainId },\n amountInWei,\n receiver,\n )\n setResult(res)\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)))\n } finally {\n setIsLoading(false)\n }\n },\n [vault, walletClient, publicClient, chainId],\n )\n\n const reset = useCallback(() => {\n setResult(undefined)\n setError(undefined)\n setIsLoading(false)\n }, [])\n\n return {\n deposit,\n isLoading,\n txHash: result?.txHash,\n shares: result?.shares,\n error,\n reset,\n }\n}\n","import { useState, useCallback } from 'react'\nimport { usePublicClient, useWalletClient } from 'wagmi'\nimport { asSdkClient, redeemShares } from '../viem/index.js'\nimport type { RedeemResult } from '../viem/index.js'\n\ninterface UseRedeemSharesReturn {\n /** Execute redeemShares (R1 flow). */\n redeem: (sharesInWei: bigint, receiver: `0x${string}`, owner: `0x${string}`) => Promise<void>\n isLoading: boolean\n txHash: `0x${string}` | undefined\n /** Assets received. Available after tx confirmation. */\n assets: bigint | undefined\n error: Error | undefined\n reset: () => void\n}\n\n/**\n * Hook for standard ERC-4626 share redemption (R1 flow).\n *\n * Used for local and oracle-on cross-chain vaults.\n * No LZ fee required — single transaction.\n *\n * @example\n * const { redeem, isLoading, txHash, assets } = useRedeemShares('0xVAULT', 747)\n * await redeem(sharesInWei, userAddress, userAddress)\n */\nexport function useRedeemShares(\n vault: `0x${string}` | undefined,\n chainId: number,\n): UseRedeemSharesReturn {\n const { data: walletClient } = useWalletClient({ chainId })\n const publicClient = usePublicClient({ chainId })\n\n const [isLoading, setIsLoading] = useState(false)\n const [result, setResult] = useState<RedeemResult | undefined>()\n const [error, setError] = useState<Error | undefined>()\n\n const redeem = useCallback(\n async (sharesInWei: bigint, receiver: `0x${string}`, owner: `0x${string}`) => {\n if (!vault || !walletClient || !publicClient) return\n setIsLoading(true)\n setError(undefined)\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const res = await redeemShares(\n walletClient as any,\n asSdkClient(publicClient),\n { vault, hubChainId: chainId },\n sharesInWei,\n receiver,\n owner,\n )\n setResult(res)\n } catch (err) {\n setError(err instanceof Error ? err : new Error(String(err)))\n } finally {\n setIsLoading(false)\n }\n },\n [vault, walletClient, publicClient, chainId],\n )\n\n const reset = useCallback(() => {\n setResult(undefined)\n setError(undefined)\n setIsLoading(false)\n }, [])\n\n return {\n redeem,\n isLoading,\n txHash: result?.txHash,\n assets: result?.assets,\n error,\n reset,\n }\n}\n","import { useMemo } from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport type { Address, PublicClient } from 'viem'\nimport { getVaultDistribution } from '../viem/distribution.js'\nimport type { VaultDistribution } from '../viem/distribution.js'\nimport { createChainClient } from '../viem/spokeRoutes.js'\nimport { discoverVaultTopology } from '../viem/topology.js'\nimport type { VaultTopology } from '../viem/topology.js'\n\nexport type { VaultDistribution }\n\ninterface UseVaultDistributionReturn {\n distribution: VaultDistribution | undefined\n isLoading: boolean\n}\n\n/**\n * Read the full cross-chain capital distribution of a vault.\n *\n * Discovers the vault topology automatically via `discoverVaultTopology`\n * (works without a connected wallet), then creates hub and spoke clients\n * via public RPCs.\n *\n * Spoke reads that fail (bad RPC, timeout) degrade gracefully —\n * those spokes will appear with `isReachable: false`.\n *\n * @example\n * ```tsx\n * const { distribution, isLoading } = useVaultDistribution('0xVAULT')\n * if (distribution) {\n * console.log(`Hub liquid: ${distribution.hubLiquidBalance}`)\n * console.log(`Total actual: ${distribution.totalActual}`)\n * }\n * ```\n */\nexport function useVaultDistribution(\n vault: Address | undefined,\n): UseVaultDistributionReturn {\n // Step 1: discover topology (wallet-independent)\n const { data: topology } = useQuery<VaultTopology>({\n queryKey: ['vaultTopology', vault],\n queryFn: () => discoverVaultTopology(vault!),\n enabled: !!vault,\n staleTime: 5 * 60 * 1000,\n })\n\n // Build spoke clients from topology\n const spokeClients = useMemo((): Record<number, PublicClient> => {\n if (!topology) return {}\n const clients: Record<number, PublicClient> = {}\n for (const spokeChainId of topology.spokeChainIds) {\n const client = createChainClient(spokeChainId)\n if (client) clients[spokeChainId] = client as PublicClient\n }\n return clients\n }, [topology])\n\n // Step 2: fetch distribution using hub-chain client (not wallet client)\n const { data: distribution, isLoading } = useQuery<VaultDistribution>({\n queryKey: ['vaultDistribution', vault, topology?.hubChainId],\n queryFn: () => {\n const hubClient = createChainClient(topology!.hubChainId)\n if (!hubClient) throw new Error(`No public RPC for hub chainId ${topology!.hubChainId}`)\n return getVaultDistribution(hubClient as PublicClient, vault!, spokeClients)\n },\n enabled: !!vault && !!topology && topology.role !== 'local',\n staleTime: 30_000,\n })\n\n return { distribution, isLoading }\n}\n","import type { DepositResult, AsyncRequestResult, AsyncRequestStatusInfo } from '../viem/index.js'\nimport { useVaultStatus } from './useVaultStatus.js'\nimport { useOmniDeposit } from './useOmniDeposit.js'\nimport { useDepositSimple } from './useDepositSimple.js'\n\ninterface UseSmartDepositReturn {\n /**\n * Execute deposit using the correct flow for this vault's mode.\n * For async vaults: wraps depositAsync (D4) — returns guid for tracking.\n * For local/oracle vaults: wraps depositSimple (D1/D3) — returns shares.\n */\n deposit: (amountInWei: bigint, receiver: `0x${string}`) => Promise<void>\n isLoading: boolean\n txHash: `0x${string}` | undefined\n /** Shares minted (available for D1/D3 vaults after confirmation, undefined for D4). */\n shares: bigint | undefined\n /** GUID for cross-chain tracking (D4 vaults only). */\n guid: `0x${string}` | undefined\n /** Cross-chain request status (D4 vaults only). */\n requestStatus: AsyncRequestStatusInfo | undefined\n /** true when the wallet is connected to the wrong chain (D4 vaults only). */\n wrongChain: boolean\n /** Vault mode loaded from getVaultStatus. undefined while loading. */\n vaultMode: 'local' | 'cross-chain-oracle' | 'cross-chain-async' | 'paused' | 'full' | undefined\n error: Error | undefined\n reset: () => void\n}\n\n/**\n * Auto-selects the correct deposit flow based on vault mode.\n * Best for frontends that support multiple vault types.\n *\n * Internally uses useVaultStatus to detect the mode, then delegates to:\n * - useOmniDeposit (D4) for 'cross-chain-async' vaults\n * - useDepositSimple (D1/D3) for 'local' and 'cross-chain-oracle' vaults\n *\n * @example\n * const { deposit, isLoading, guid, requestStatus, vaultMode } = useSmartDeposit('0xVAULT', 747)\n *\n * if (vaultMode === 'paused') return <PausedBadge />\n *\n * await deposit(parseUnits('100', 6), userAddress)\n * // For async vaults: poll requestStatus until 'completed'\n * // For sync vaults: txHash + shares are available immediately\n */\nexport function useSmartDeposit(\n vault: `0x${string}` | undefined,\n hubChainId: number,\n): UseSmartDepositReturn {\n const { data: status } = useVaultStatus(vault, hubChainId)\n const omni = useOmniDeposit(vault, hubChainId)\n const simple = useDepositSimple(vault, hubChainId)\n\n const isAsync = status?.mode === 'cross-chain-async'\n\n const deposit = isAsync ? omni.deposit : simple.deposit\n\n return {\n deposit,\n isLoading: isAsync ? omni.isLoading : simple.isLoading,\n txHash: isAsync ? omni.txHash : simple.txHash,\n shares: isAsync ? undefined : simple.shares,\n guid: isAsync ? omni.guid : undefined,\n requestStatus: isAsync ? omni.requestStatus : undefined,\n wrongChain: isAsync ? omni.wrongChain : false,\n vaultMode: status?.mode,\n error: isAsync ? omni.error : simple.error,\n reset: isAsync ? omni.reset : simple.reset,\n }\n}\n","import type { AsyncRequestStatusInfo } from '../viem/index.js'\nimport { useVaultStatus } from './useVaultStatus.js'\nimport { useOmniRedeem } from './useOmniRedeem.js'\nimport { useRedeemShares } from './useRedeemShares.js'\n\ninterface UseSmartRedeemReturn {\n /**\n * Execute redeem using the correct flow for this vault's mode.\n * For async vaults: wraps redeemAsync (R5) — returns guid for tracking.\n * For local/oracle vaults: wraps redeemShares (R1) — returns assets.\n */\n redeem: (sharesInWei: bigint, receiver: `0x${string}`, owner: `0x${string}`) => Promise<void>\n isLoading: boolean\n txHash: `0x${string}` | undefined\n /** Assets received (available for R1 vaults after confirmation, undefined for R5). */\n assets: bigint | undefined\n /** GUID for cross-chain tracking (R5 vaults only). */\n guid: `0x${string}` | undefined\n /** Cross-chain request status (R5 vaults only). */\n requestStatus: AsyncRequestStatusInfo | undefined\n /** true when the wallet is connected to the wrong chain (R5 vaults only). */\n wrongChain: boolean\n /** Vault mode loaded from getVaultStatus. undefined while loading. */\n vaultMode: 'local' | 'cross-chain-oracle' | 'cross-chain-async' | 'paused' | 'full' | undefined\n error: Error | undefined\n reset: () => void\n}\n\n/**\n * Auto-selects the correct redeem flow based on vault mode.\n * Best for frontends that support multiple vault types.\n *\n * Internally uses useVaultStatus to detect the mode, then delegates to:\n * - useOmniRedeem (R5) for 'cross-chain-async' vaults\n * - useRedeemShares (R1) for 'local' and 'cross-chain-oracle' vaults\n *\n * @example\n * const { redeem, isLoading, guid, requestStatus, vaultMode } = useSmartRedeem('0xVAULT', 8453)\n *\n * if (vaultMode === 'paused') return <PausedBadge />\n *\n * await redeem(sharesInWei, userAddress, userAddress)\n * // For async vaults: poll requestStatus until 'completed'\n * // For sync vaults: txHash + assets are available immediately\n */\nexport function useSmartRedeem(\n vault: `0x${string}` | undefined,\n hubChainId: number,\n): UseSmartRedeemReturn {\n const { data: status } = useVaultStatus(vault, hubChainId)\n const omni = useOmniRedeem(vault, hubChainId)\n const simple = useRedeemShares(vault, hubChainId)\n\n const isAsync = status?.mode === 'cross-chain-async'\n\n const redeem = isAsync ? omni.redeem : simple.redeem\n\n return {\n redeem,\n isLoading: isAsync ? omni.isLoading : simple.isLoading,\n txHash: isAsync ? omni.txHash : simple.txHash,\n assets: isAsync ? undefined : simple.assets,\n guid: isAsync ? omni.guid : undefined,\n requestStatus: isAsync ? omni.requestStatus : undefined,\n wrongChain: isAsync ? omni.wrongChain : false,\n vaultMode: status?.mode,\n error: isAsync ? omni.error : simple.error,\n reset: isAsync ? omni.reset : simple.reset,\n }\n}\n","import { useQuery } from '@tanstack/react-query'\nimport type { Address } from 'viem'\nimport { getInboundRoutes, getUserBalancesForRoutes } from '../viem/spokeRoutes.js'\nimport type { InboundRouteWithBalance } from '../viem/spokeRoutes.js'\n\ninterface UseInboundRoutesReturn {\n routes: InboundRouteWithBalance[]\n isLoading: boolean\n error: Error | null\n}\n\n/**\n * Return the decimals typically used by a route's token symbol.\n *\n * Useful for formatting `userBalance` (a bigint in the token's smallest unit)\n * into a human-readable string.\n *\n * @example\n * ```ts\n * import { formatUnits } from 'viem'\n * const decimals = getRouteTokenDecimals(route.symbol)\n * const formatted = formatUnits(route.userBalance, decimals)\n * ```\n */\nexport function getRouteTokenDecimals(symbol: string): number {\n switch (symbol) {\n case 'stgUSDC':\n case 'USDT':\n case 'USDC':\n return 6\n default:\n return 18\n }\n}\n\n/**\n * Discover all valid inbound deposit routes for a vault and fetch the\n * connected user's token balance on each route's spoke chain.\n *\n * The hook is disabled until all four parameters are defined, so it is\n * safe to pass `undefined` during initial render.\n *\n * @example\n * ```tsx\n * const { routes, isLoading, error } = useInboundRoutes(\n * 8453, // hubChainId (Base)\n * '0xVAULT', // vault address\n * '0xASSET', // vault asset on hub\n * '0xUSER', // connected wallet\n * )\n *\n * for (const r of routes) {\n * const decimals = getRouteTokenDecimals(r.symbol)\n * console.log(`${r.symbol} on chain ${r.spokeChainId}: ${formatUnits(r.userBalance, decimals)}`)\n * }\n * ```\n */\nexport function useInboundRoutes(\n hubChainId: number | undefined,\n vault: Address | undefined,\n vaultAsset: Address | undefined,\n userAddress: Address | undefined,\n): UseInboundRoutesReturn {\n const enabled = hubChainId != null && !!vault && !!vaultAsset && !!userAddress\n\n const { data, isLoading, error } = useQuery<InboundRouteWithBalance[], Error>({\n queryKey: ['inboundRoutes', hubChainId, vault, vaultAsset, userAddress],\n queryFn: async () => {\n const routes = await getInboundRoutes(hubChainId!, vault!, vaultAsset!, userAddress!)\n return getUserBalancesForRoutes(routes, userAddress!)\n },\n enabled,\n staleTime: 60_000, // routes change infrequently — 1 min cache\n })\n\n return {\n routes: data ?? [],\n isLoading,\n error: error ?? null,\n }\n}\n"]}