@oydual31/more-vaults-sdk 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oydual31/more-vaults-sdk",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "TypeScript SDK for MoreVaults protocol — viem/wagmi and ethers.js",
5
5
  "type": "module",
6
6
  "exports": {
@@ -13,6 +13,11 @@
13
13
  "types": "./dist/ethers/index.d.ts",
14
14
  "import": "./dist/ethers/index.js",
15
15
  "require": "./dist/ethers/index.cjs"
16
+ },
17
+ "./react": {
18
+ "types": "./dist/react/index.d.ts",
19
+ "import": "./dist/react/index.js",
20
+ "require": "./dist/react/index.cjs"
16
21
  }
17
22
  },
18
23
  "files": [
@@ -26,18 +31,25 @@
26
31
  "prepublishOnly": "npm run build"
27
32
  },
28
33
  "dependencies": {
29
- "viem": "^2.21.0",
30
- "ethers": "^6.13.0"
34
+ "ethers": ">=6.0.0",
35
+ "viem": ">=2.0.0"
31
36
  },
32
37
  "devDependencies": {
38
+ "@tanstack/react-query": "^5.90.21",
33
39
  "@types/node": "^22.0.0",
40
+ "@types/react": "^18.3.28",
41
+ "react": "^18.3.1",
34
42
  "tsup": "^8.0.0",
35
43
  "tsx": "^4.19.0",
36
- "typescript": "^5.7.0"
44
+ "typescript": "^5.7.0",
45
+ "wagmi": "^2.19.5"
37
46
  },
38
47
  "peerDependencies": {
48
+ "@tanstack/react-query": ">=5.0.0",
49
+ "ethers": ">=6.0.0",
50
+ "react": ">=18.0.0",
39
51
  "viem": ">=2.0.0",
40
- "ethers": ">=6.0.0"
52
+ "wagmi": ">=2.0.0"
41
53
  },
42
54
  "peerDependenciesMeta": {
43
55
  "viem": {
@@ -45,6 +57,15 @@
45
57
  },
46
58
  "ethers": {
47
59
  "optional": true
60
+ },
61
+ "wagmi": {
62
+ "optional": true
63
+ },
64
+ "react": {
65
+ "optional": true
66
+ },
67
+ "@tanstack/react-query": {
68
+ "optional": true
48
69
  }
49
70
  }
50
71
  }
@@ -265,10 +265,14 @@ export async function getVaultStatus(
265
265
 
266
266
  const spokesDeployedBalance: bigint = totalAssets > hubLiquidBalance ? totalAssets - hubLiquidBalance : 0n;
267
267
 
268
- // null = maxDeposit reverted → whitelist/ACL vault
268
+ // null = maxDeposit reverted.
269
+ // For cross-chain-async hubs this is expected — the contract reverts with
270
+ // NotAnERC4626CompatibleVault because maxDeposit is not meaningful in async mode.
271
+ // Only treat the revert as "whitelist/ACL" when the vault is NOT a hub.
269
272
  const MAX_UINT256 = BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
270
- const depositAccessRestricted = maxDepositRaw === null;
271
- const effectiveCapacity: bigint = depositAccessRestricted ? MAX_UINT256 : maxDepositRaw!;
273
+ const isCrossChainAsync = isHub && !oraclesEnabled;
274
+ const depositAccessRestricted = maxDepositRaw === null && !isCrossChainAsync;
275
+ const effectiveCapacity: bigint = maxDepositRaw === null ? MAX_UINT256 : maxDepositRaw!;
272
276
 
273
277
  // ── Derive mode ────────────────────────────────────────────────────────────
274
278
  let mode: VaultMode;
@@ -0,0 +1,26 @@
1
+ // MoreVaults SDK — React hooks (wagmi v2 + @tanstack/react-query v5)
2
+ // Peer dependencies: react >=18, wagmi >=2, @tanstack/react-query >=5
3
+
4
+ // --- Read hooks ---
5
+ export { useVaultStatus } from './useVaultStatus.js'
6
+ export type { VaultStatus } from './useVaultStatus.js'
7
+
8
+ export { useVaultMetadata } from './useVaultMetadata.js'
9
+ export type { VaultMetadata } from './useVaultMetadata.js'
10
+
11
+ export { useUserPosition } from './useUserPosition.js'
12
+ export type { UserPosition } from './useUserPosition.js'
13
+
14
+ export { useLzFee } from './useLzFee.js'
15
+
16
+ export { useAsyncRequestStatus } from './useAsyncRequestStatus.js'
17
+ export type { AsyncRequestStatusInfo } from './useAsyncRequestStatus.js'
18
+
19
+ // --- Action hooks ---
20
+ export { useOmniDeposit } from './useOmniDeposit.js'
21
+ export { useOmniRedeem } from './useOmniRedeem.js'
22
+ export { useDepositSimple } from './useDepositSimple.js'
23
+ export { useRedeemShares } from './useRedeemShares.js'
24
+
25
+ // --- Smart (auto-routing) hooks ---
26
+ export { useSmartDeposit } from './useSmartDeposit.js'
@@ -0,0 +1,36 @@
1
+ import { useQuery } from '@tanstack/react-query'
2
+ import { usePublicClient } from 'wagmi'
3
+ import { asSdkClient, getAsyncRequestStatusLabel } from '../viem/index.js'
4
+ import type { AsyncRequestStatusInfo } from '../viem/index.js'
5
+
6
+ export type { AsyncRequestStatusInfo }
7
+
8
+ /**
9
+ * Poll the status of an async cross-chain request (D4/D5/R5) by GUID.
10
+ *
11
+ * Automatically stops polling when status reaches 'completed' or 'refunded'.
12
+ * Polls every 10s while the request is still pending or ready-to-execute.
13
+ *
14
+ * @example
15
+ * const { data } = useAsyncRequestStatus('0xVAULT', guid, 747)
16
+ * // data.status: 'pending' | 'ready-to-execute' | 'completed' | 'refunded'
17
+ * // data.label: human-readable description
18
+ * // data.result: shares minted or assets returned (0n while pending)
19
+ */
20
+ export function useAsyncRequestStatus(
21
+ vault: `0x${string}` | undefined,
22
+ guid: `0x${string}` | undefined,
23
+ chainId: number,
24
+ ) {
25
+ const publicClient = usePublicClient({ chainId })
26
+ return useQuery<AsyncRequestStatusInfo>({
27
+ queryKey: ['asyncRequestStatus', vault, guid, chainId],
28
+ queryFn: () => getAsyncRequestStatusLabel(asSdkClient(publicClient), vault!, guid!),
29
+ enabled: !!vault && !!guid && !!publicClient,
30
+ refetchInterval: (query) => {
31
+ const status = query.state.data?.status
32
+ if (status === 'completed' || status === 'refunded') return false
33
+ return 10_000
34
+ },
35
+ })
36
+ }
@@ -0,0 +1,76 @@
1
+ import { useState, useCallback } from 'react'
2
+ import { usePublicClient, useWalletClient } from 'wagmi'
3
+ import { asSdkClient, depositSimple } from '../viem/index.js'
4
+ import type { DepositResult } from '../viem/index.js'
5
+
6
+ interface UseDepositSimpleReturn {
7
+ /** Execute approve + depositSimple (D1/D3 flows). */
8
+ deposit: (amountInWei: bigint, receiver: `0x${string}`) => Promise<void>
9
+ isLoading: boolean
10
+ txHash: `0x${string}` | undefined
11
+ /** Shares minted. Available after tx confirmation. */
12
+ shares: bigint | undefined
13
+ error: Error | undefined
14
+ reset: () => void
15
+ }
16
+
17
+ /**
18
+ * Hook for local and oracle-on cross-chain vaults (D1/D3 flows).
19
+ *
20
+ * Simpler than useOmniDeposit — no LZ fee, no GUID, no polling.
21
+ * One approve + one deposit transaction.
22
+ *
23
+ * @example
24
+ * const { deposit, isLoading, txHash, shares } = useDepositSimple('0xVAULT', 747)
25
+ * await deposit(parseUnits('100', 6), userAddress)
26
+ */
27
+ export function useDepositSimple(
28
+ vault: `0x${string}` | undefined,
29
+ chainId: number,
30
+ ): UseDepositSimpleReturn {
31
+ const { data: walletClient } = useWalletClient({ chainId })
32
+ const publicClient = usePublicClient({ chainId })
33
+
34
+ const [isLoading, setIsLoading] = useState(false)
35
+ const [result, setResult] = useState<DepositResult | undefined>()
36
+ const [error, setError] = useState<Error | undefined>()
37
+
38
+ const deposit = useCallback(
39
+ async (amountInWei: bigint, receiver: `0x${string}`) => {
40
+ if (!vault || !walletClient || !publicClient) return
41
+ setIsLoading(true)
42
+ setError(undefined)
43
+ try {
44
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
+ const res = await depositSimple(
46
+ walletClient as any,
47
+ asSdkClient(publicClient),
48
+ { vault, hubChainId: chainId },
49
+ amountInWei,
50
+ receiver,
51
+ )
52
+ setResult(res)
53
+ } catch (err) {
54
+ setError(err instanceof Error ? err : new Error(String(err)))
55
+ } finally {
56
+ setIsLoading(false)
57
+ }
58
+ },
59
+ [vault, walletClient, publicClient, chainId],
60
+ )
61
+
62
+ const reset = useCallback(() => {
63
+ setResult(undefined)
64
+ setError(undefined)
65
+ setIsLoading(false)
66
+ }, [])
67
+
68
+ return {
69
+ deposit,
70
+ isLoading,
71
+ txHash: result?.txHash,
72
+ shares: result?.shares,
73
+ error,
74
+ reset,
75
+ }
76
+ }
@@ -0,0 +1,27 @@
1
+ import { useQuery } from '@tanstack/react-query'
2
+ import { usePublicClient } from 'wagmi'
3
+ import { asSdkClient, quoteLzFee } from '../viem/index.js'
4
+
5
+ /**
6
+ * Quote the LayerZero fee required for async operations (D4, D5, R5).
7
+ * Refreshes every 60s — fees change with network congestion.
8
+ *
9
+ * @example
10
+ * const { fee, feeWithBuffer } = useLzFee('0xVAULT', 747)
11
+ * // feeWithBuffer adds 1% buffer automatically (fee * 101 / 100)
12
+ */
13
+ export function useLzFee(vault: `0x${string}` | undefined, chainId: number) {
14
+ const publicClient = usePublicClient({ chainId })
15
+ const query = useQuery({
16
+ queryKey: ['lzFee', vault, chainId],
17
+ queryFn: () => quoteLzFee(asSdkClient(publicClient), vault!),
18
+ enabled: !!vault && !!publicClient,
19
+ refetchInterval: 60_000,
20
+ staleTime: 30_000,
21
+ })
22
+ return {
23
+ ...query,
24
+ fee: query.data,
25
+ feeWithBuffer: query.data ? (query.data * 101n) / 100n : undefined,
26
+ }
27
+ }
@@ -0,0 +1,97 @@
1
+ import { useState, useCallback } from 'react'
2
+ import { usePublicClient, useWalletClient, useChainId } from 'wagmi'
3
+ import {
4
+ asSdkClient,
5
+ depositAsync,
6
+ getVaultStatus,
7
+ } from '../viem/index.js'
8
+ import type { AsyncRequestStatusInfo } from '../viem/index.js'
9
+ import { useLzFee } from './useLzFee.js'
10
+ import { useAsyncRequestStatus } from './useAsyncRequestStatus.js'
11
+
12
+ interface UseOmniDepositReturn {
13
+ /** Execute approve + depositAsync. Handles everything internally. */
14
+ deposit: (amountInWei: bigint, receiver: `0x${string}`) => Promise<void>
15
+ isLoading: boolean
16
+ txHash: `0x${string}` | undefined
17
+ /** GUID for cross-chain tracking. Available after tx confirmation. */
18
+ guid: `0x${string}` | undefined
19
+ /** Cross-chain request status. undefined until a guid is available. */
20
+ requestStatus: AsyncRequestStatusInfo | undefined
21
+ /** true when the wallet is connected to the wrong chain */
22
+ wrongChain: boolean
23
+ error: Error | undefined
24
+ reset: () => void
25
+ }
26
+
27
+ /**
28
+ * Complete hook for async deposits on hub vaults (D4 flow).
29
+ *
30
+ * Handles: fee quote, chain validation, approve, depositAsync, and GUID polling.
31
+ * The deposit function wraps the entire flow — callers only pass amount + receiver.
32
+ *
33
+ * @example
34
+ * const { deposit, isLoading, guid, requestStatus, wrongChain } = useOmniDeposit('0xVAULT', 747)
35
+ *
36
+ * if (wrongChain) return <SwitchNetworkButton chainId={747} />
37
+ *
38
+ * await deposit(parseUnits('100', 6), userAddress)
39
+ * // requestStatus.status goes: 'pending' → 'completed' | 'refunded'
40
+ */
41
+ export function useOmniDeposit(
42
+ vault: `0x${string}` | undefined,
43
+ hubChainId: number,
44
+ ): UseOmniDepositReturn {
45
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
46
+ const { data: walletClient } = useWalletClient({ chainId: hubChainId })
47
+ const publicClient = usePublicClient({ chainId: hubChainId })
48
+ const currentChainId = useChainId()
49
+
50
+ const [isLoading, setIsLoading] = useState(false)
51
+ const [txHash, setTxHash] = useState<`0x${string}` | undefined>()
52
+ const [guid, setGuid] = useState<`0x${string}` | undefined>()
53
+ const [error, setError] = useState<Error | undefined>()
54
+
55
+ const { feeWithBuffer } = useLzFee(vault, hubChainId)
56
+ const { data: requestStatus } = useAsyncRequestStatus(vault, guid, hubChainId)
57
+
58
+ const wrongChain = currentChainId !== hubChainId
59
+
60
+ const deposit = useCallback(
61
+ async (amountInWei: bigint, receiver: `0x${string}`) => {
62
+ if (!vault || !walletClient || !publicClient || !feeWithBuffer) return
63
+ setIsLoading(true)
64
+ setError(undefined)
65
+ try {
66
+ const pc = asSdkClient(publicClient)
67
+ const status = await getVaultStatus(pc, vault)
68
+ // walletClient from wagmi is structurally compatible with viem WalletClient
69
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
70
+ const result = await depositAsync(
71
+ walletClient as any,
72
+ pc,
73
+ { vault, escrow: status.escrow, hubChainId },
74
+ amountInWei,
75
+ receiver,
76
+ feeWithBuffer,
77
+ )
78
+ setTxHash(result.txHash)
79
+ setGuid(result.guid)
80
+ } catch (err) {
81
+ setError(err instanceof Error ? err : new Error(String(err)))
82
+ } finally {
83
+ setIsLoading(false)
84
+ }
85
+ },
86
+ [vault, walletClient, publicClient, feeWithBuffer, hubChainId],
87
+ )
88
+
89
+ const reset = useCallback(() => {
90
+ setTxHash(undefined)
91
+ setGuid(undefined)
92
+ setError(undefined)
93
+ setIsLoading(false)
94
+ }, [])
95
+
96
+ return { deposit, isLoading, txHash, guid, requestStatus, wrongChain, error, reset }
97
+ }
@@ -0,0 +1,96 @@
1
+ import { useState, useCallback } from 'react'
2
+ import { usePublicClient, useWalletClient, useChainId } from 'wagmi'
3
+ import {
4
+ asSdkClient,
5
+ redeemAsync,
6
+ getVaultStatus,
7
+ } from '../viem/index.js'
8
+ import type { AsyncRequestStatusInfo } from '../viem/index.js'
9
+ import { useLzFee } from './useLzFee.js'
10
+ import { useAsyncRequestStatus } from './useAsyncRequestStatus.js'
11
+
12
+ interface UseOmniRedeemReturn {
13
+ /** Execute approve + redeemAsync. Handles everything internally. */
14
+ redeem: (sharesInWei: bigint, receiver: `0x${string}`, owner: `0x${string}`) => Promise<void>
15
+ isLoading: boolean
16
+ txHash: `0x${string}` | undefined
17
+ /** GUID for cross-chain tracking. Available after tx confirmation. */
18
+ guid: `0x${string}` | undefined
19
+ /** Cross-chain request status. undefined until a guid is available. */
20
+ requestStatus: AsyncRequestStatusInfo | undefined
21
+ /** true when the wallet is connected to the wrong chain */
22
+ wrongChain: boolean
23
+ error: Error | undefined
24
+ reset: () => void
25
+ }
26
+
27
+ /**
28
+ * Complete hook for async redeems on hub vaults (R5 flow).
29
+ *
30
+ * Handles: fee quote, chain validation, share approve, redeemAsync, and GUID polling.
31
+ *
32
+ * @example
33
+ * const { redeem, isLoading, guid, requestStatus, wrongChain } = useOmniRedeem('0xVAULT', 747)
34
+ *
35
+ * if (wrongChain) return <SwitchNetworkButton chainId={747} />
36
+ *
37
+ * await redeem(sharesInWei, userAddress, userAddress)
38
+ * // requestStatus.status goes: 'pending' → 'completed' | 'refunded'
39
+ */
40
+ export function useOmniRedeem(
41
+ vault: `0x${string}` | undefined,
42
+ hubChainId: number,
43
+ ): UseOmniRedeemReturn {
44
+ const { data: walletClient } = useWalletClient({ chainId: hubChainId })
45
+ const publicClient = usePublicClient({ chainId: hubChainId })
46
+ const currentChainId = useChainId()
47
+
48
+ const [isLoading, setIsLoading] = useState(false)
49
+ const [txHash, setTxHash] = useState<`0x${string}` | undefined>()
50
+ const [guid, setGuid] = useState<`0x${string}` | undefined>()
51
+ const [error, setError] = useState<Error | undefined>()
52
+
53
+ const { feeWithBuffer } = useLzFee(vault, hubChainId)
54
+ const { data: requestStatus } = useAsyncRequestStatus(vault, guid, hubChainId)
55
+
56
+ const wrongChain = currentChainId !== hubChainId
57
+
58
+ const redeem = useCallback(
59
+ async (sharesInWei: bigint, receiver: `0x${string}`, owner: `0x${string}`) => {
60
+ if (!vault || !walletClient || !publicClient || !feeWithBuffer) return
61
+ setIsLoading(true)
62
+ setError(undefined)
63
+ try {
64
+ const pc = asSdkClient(publicClient)
65
+ const status = await getVaultStatus(pc, vault)
66
+ // walletClient from wagmi is structurally compatible with viem WalletClient
67
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
68
+ const result = await redeemAsync(
69
+ walletClient as any,
70
+ pc,
71
+ { vault, escrow: status.escrow, hubChainId },
72
+ sharesInWei,
73
+ receiver,
74
+ owner,
75
+ feeWithBuffer,
76
+ )
77
+ setTxHash(result.txHash)
78
+ setGuid(result.guid)
79
+ } catch (err) {
80
+ setError(err instanceof Error ? err : new Error(String(err)))
81
+ } finally {
82
+ setIsLoading(false)
83
+ }
84
+ },
85
+ [vault, walletClient, publicClient, feeWithBuffer, hubChainId],
86
+ )
87
+
88
+ const reset = useCallback(() => {
89
+ setTxHash(undefined)
90
+ setGuid(undefined)
91
+ setError(undefined)
92
+ setIsLoading(false)
93
+ }, [])
94
+
95
+ return { redeem, isLoading, txHash, guid, requestStatus, wrongChain, error, reset }
96
+ }
@@ -0,0 +1,77 @@
1
+ import { useState, useCallback } from 'react'
2
+ import { usePublicClient, useWalletClient } from 'wagmi'
3
+ import { asSdkClient, redeemShares } from '../viem/index.js'
4
+ import type { RedeemResult } from '../viem/index.js'
5
+
6
+ interface UseRedeemSharesReturn {
7
+ /** Execute redeemShares (R1 flow). */
8
+ redeem: (sharesInWei: bigint, receiver: `0x${string}`, owner: `0x${string}`) => Promise<void>
9
+ isLoading: boolean
10
+ txHash: `0x${string}` | undefined
11
+ /** Assets received. Available after tx confirmation. */
12
+ assets: bigint | undefined
13
+ error: Error | undefined
14
+ reset: () => void
15
+ }
16
+
17
+ /**
18
+ * Hook for standard ERC-4626 share redemption (R1 flow).
19
+ *
20
+ * Used for local and oracle-on cross-chain vaults.
21
+ * No LZ fee required — single transaction.
22
+ *
23
+ * @example
24
+ * const { redeem, isLoading, txHash, assets } = useRedeemShares('0xVAULT', 747)
25
+ * await redeem(sharesInWei, userAddress, userAddress)
26
+ */
27
+ export function useRedeemShares(
28
+ vault: `0x${string}` | undefined,
29
+ chainId: number,
30
+ ): UseRedeemSharesReturn {
31
+ const { data: walletClient } = useWalletClient({ chainId })
32
+ const publicClient = usePublicClient({ chainId })
33
+
34
+ const [isLoading, setIsLoading] = useState(false)
35
+ const [result, setResult] = useState<RedeemResult | undefined>()
36
+ const [error, setError] = useState<Error | undefined>()
37
+
38
+ const redeem = useCallback(
39
+ async (sharesInWei: bigint, receiver: `0x${string}`, owner: `0x${string}`) => {
40
+ if (!vault || !walletClient || !publicClient) return
41
+ setIsLoading(true)
42
+ setError(undefined)
43
+ try {
44
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
+ const res = await redeemShares(
46
+ walletClient as any,
47
+ asSdkClient(publicClient),
48
+ { vault, hubChainId: chainId },
49
+ sharesInWei,
50
+ receiver,
51
+ owner,
52
+ )
53
+ setResult(res)
54
+ } catch (err) {
55
+ setError(err instanceof Error ? err : new Error(String(err)))
56
+ } finally {
57
+ setIsLoading(false)
58
+ }
59
+ },
60
+ [vault, walletClient, publicClient, chainId],
61
+ )
62
+
63
+ const reset = useCallback(() => {
64
+ setResult(undefined)
65
+ setError(undefined)
66
+ setIsLoading(false)
67
+ }, [])
68
+
69
+ return {
70
+ redeem,
71
+ isLoading,
72
+ txHash: result?.txHash,
73
+ assets: result?.assets,
74
+ error,
75
+ reset,
76
+ }
77
+ }
@@ -0,0 +1,70 @@
1
+ import type { DepositResult, AsyncRequestResult, AsyncRequestStatusInfo } from '../viem/index.js'
2
+ import { useVaultStatus } from './useVaultStatus.js'
3
+ import { useOmniDeposit } from './useOmniDeposit.js'
4
+ import { useDepositSimple } from './useDepositSimple.js'
5
+
6
+ interface UseSmartDepositReturn {
7
+ /**
8
+ * Execute deposit using the correct flow for this vault's mode.
9
+ * For async vaults: wraps depositAsync (D4) — returns guid for tracking.
10
+ * For local/oracle vaults: wraps depositSimple (D1/D3) — returns shares.
11
+ */
12
+ deposit: (amountInWei: bigint, receiver: `0x${string}`) => Promise<void>
13
+ isLoading: boolean
14
+ txHash: `0x${string}` | undefined
15
+ /** Shares minted (available for D1/D3 vaults after confirmation, undefined for D4). */
16
+ shares: bigint | undefined
17
+ /** GUID for cross-chain tracking (D4 vaults only). */
18
+ guid: `0x${string}` | undefined
19
+ /** Cross-chain request status (D4 vaults only). */
20
+ requestStatus: AsyncRequestStatusInfo | undefined
21
+ /** true when the wallet is connected to the wrong chain (D4 vaults only). */
22
+ wrongChain: boolean
23
+ /** Vault mode loaded from getVaultStatus. undefined while loading. */
24
+ vaultMode: 'local' | 'cross-chain-oracle' | 'cross-chain-async' | 'paused' | 'full' | undefined
25
+ error: Error | undefined
26
+ reset: () => void
27
+ }
28
+
29
+ /**
30
+ * Auto-selects the correct deposit flow based on vault mode.
31
+ * Best for frontends that support multiple vault types.
32
+ *
33
+ * Internally uses useVaultStatus to detect the mode, then delegates to:
34
+ * - useOmniDeposit (D4) for 'cross-chain-async' vaults
35
+ * - useDepositSimple (D1/D3) for 'local' and 'cross-chain-oracle' vaults
36
+ *
37
+ * @example
38
+ * const { deposit, isLoading, guid, requestStatus, vaultMode } = useSmartDeposit('0xVAULT', 747)
39
+ *
40
+ * if (vaultMode === 'paused') return <PausedBadge />
41
+ *
42
+ * await deposit(parseUnits('100', 6), userAddress)
43
+ * // For async vaults: poll requestStatus until 'completed'
44
+ * // For sync vaults: txHash + shares are available immediately
45
+ */
46
+ export function useSmartDeposit(
47
+ vault: `0x${string}` | undefined,
48
+ hubChainId: number,
49
+ ): UseSmartDepositReturn {
50
+ const { data: status } = useVaultStatus(vault, hubChainId)
51
+ const omni = useOmniDeposit(vault, hubChainId)
52
+ const simple = useDepositSimple(vault, hubChainId)
53
+
54
+ const isAsync = status?.mode === 'cross-chain-async'
55
+
56
+ const deposit = isAsync ? omni.deposit : simple.deposit
57
+
58
+ return {
59
+ deposit,
60
+ isLoading: isAsync ? omni.isLoading : simple.isLoading,
61
+ txHash: isAsync ? omni.txHash : simple.txHash,
62
+ shares: isAsync ? undefined : simple.shares,
63
+ guid: isAsync ? omni.guid : undefined,
64
+ requestStatus: isAsync ? omni.requestStatus : undefined,
65
+ wrongChain: isAsync ? omni.wrongChain : false,
66
+ vaultMode: status?.mode,
67
+ error: isAsync ? omni.error : simple.error,
68
+ reset: isAsync ? omni.reset : simple.reset,
69
+ }
70
+ }
@@ -0,0 +1,29 @@
1
+ import { useQuery } from '@tanstack/react-query'
2
+ import { usePublicClient } from 'wagmi'
3
+ import { asSdkClient, getUserPosition } from '../viem/index.js'
4
+ import type { UserPosition } from '../viem/index.js'
5
+
6
+ export type { UserPosition }
7
+
8
+ /**
9
+ * Read the user's current position in a vault.
10
+ * Refetches every 15s to keep the balance display current.
11
+ *
12
+ * @example
13
+ * const { data: position } = useUserPosition('0xVAULT', '0xUSER', 747)
14
+ * // position.shares, position.estimatedAssets, position.pendingWithdrawal
15
+ */
16
+ export function useUserPosition(
17
+ vault: `0x${string}` | undefined,
18
+ user: `0x${string}` | undefined,
19
+ chainId: number,
20
+ ) {
21
+ const publicClient = usePublicClient({ chainId })
22
+ return useQuery({
23
+ queryKey: ['userPosition', vault, user, chainId],
24
+ queryFn: () => getUserPosition(asSdkClient(publicClient), vault!, user!),
25
+ enabled: !!vault && !!user && !!publicClient,
26
+ refetchInterval: 15_000,
27
+ staleTime: 10_000,
28
+ })
29
+ }
@@ -0,0 +1,29 @@
1
+ import { useQuery } from '@tanstack/react-query'
2
+ import { usePublicClient } from 'wagmi'
3
+ import { asSdkClient, getVaultMetadata } from '../viem/index.js'
4
+ import type { VaultMetadata } from '../viem/index.js'
5
+
6
+ export type { VaultMetadata }
7
+
8
+ /**
9
+ * Read display metadata for a vault and its underlying token.
10
+ * Uses a long stale time (5 min) because metadata rarely changes.
11
+ *
12
+ * @example
13
+ * const { data: meta } = useVaultMetadata('0xVAULT', 747)
14
+ * // meta.name, meta.symbol, meta.underlying, meta.underlyingSymbol
15
+ */
16
+ export function useVaultMetadata(
17
+ vault: `0x${string}` | undefined,
18
+ chainId: number,
19
+ ) {
20
+ const publicClient = usePublicClient({ chainId })
21
+ return useQuery({
22
+ queryKey: ['vaultMetadata', vault, chainId],
23
+ queryFn: () => getVaultMetadata(asSdkClient(publicClient), vault!),
24
+ enabled: !!vault && !!publicClient,
25
+ // Metadata (name, symbol, underlying) changes very rarely — 5 min stale time
26
+ staleTime: 5 * 60_000,
27
+ refetchInterval: 5 * 60_000,
28
+ })
29
+ }