@oydual31/more-vaults-sdk 0.1.0 → 0.1.2
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/README.md +15 -3
- package/dist/ethers/index.cjs +69 -0
- package/dist/ethers/index.cjs.map +1 -1
- package/dist/ethers/index.d.cts +44 -1
- package/dist/ethers/index.d.ts +44 -1
- package/dist/ethers/index.js +64 -1
- package/dist/ethers/index.js.map +1 -1
- package/dist/viem/index.cjs +67 -0
- package/dist/viem/index.cjs.map +1 -1
- package/dist/viem/index.d.cts +46 -1
- package/dist/viem/index.d.ts +46 -1
- package/dist/viem/index.js +62 -1
- package/dist/viem/index.js.map +1 -1
- package/package.json +7 -3
- package/src/ethers/chainValidation.ts +16 -0
- package/src/ethers/chains.ts +35 -0
- package/src/ethers/depositFlows.ts +13 -0
- package/src/ethers/errors.ts +9 -0
- package/src/ethers/index.ts +7 -0
- package/src/ethers/redeemFlows.ts +13 -0
- package/src/ethers/types.ts +6 -0
- package/src/ethers/wagmiCompat.ts +17 -0
- package/src/viem/chainValidation.ts +14 -0
- package/src/viem/chains.ts +35 -0
- package/src/viem/depositFlows.ts +13 -0
- package/src/viem/errors.ts +9 -0
- package/src/viem/index.ts +11 -0
- package/src/viem/redeemFlows.ts +13 -0
- package/src/viem/types.ts +6 -0
- package/src/viem/wagmiCompat.ts +18 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oydual31/more-vaults-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "TypeScript SDK for MoreVaults protocol — viem/wagmi and ethers.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -40,7 +40,11 @@
|
|
|
40
40
|
"ethers": ">=6.0.0"
|
|
41
41
|
},
|
|
42
42
|
"peerDependenciesMeta": {
|
|
43
|
-
"viem": {
|
|
44
|
-
|
|
43
|
+
"viem": {
|
|
44
|
+
"optional": true
|
|
45
|
+
},
|
|
46
|
+
"ethers": {
|
|
47
|
+
"optional": true
|
|
48
|
+
}
|
|
45
49
|
}
|
|
46
50
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Signer } from 'ethers'
|
|
2
|
+
import { WrongChainError } from './errors'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Validate that the signer is connected to the expected chain.
|
|
6
|
+
* Only validates if hubChainId is provided — opt-in, non-breaking.
|
|
7
|
+
*/
|
|
8
|
+
export async function validateWalletChain(signer: Signer, hubChainId?: number): Promise<void> {
|
|
9
|
+
if (!hubChainId) return
|
|
10
|
+
const network = await signer.provider?.getNetwork()
|
|
11
|
+
if (!network) return
|
|
12
|
+
const current = Number(network.chainId)
|
|
13
|
+
if (current !== hubChainId) {
|
|
14
|
+
throw new WrongChainError(current, hubChainId)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** EVM Chain IDs for chains supported by MoreVaults */
|
|
2
|
+
export const CHAIN_IDS = {
|
|
3
|
+
flowEVMMainnet: 747,
|
|
4
|
+
flowEVMTestnet: 545,
|
|
5
|
+
arbitrum: 42161,
|
|
6
|
+
base: 8453,
|
|
7
|
+
ethereum: 1,
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
10
|
+
/** LayerZero Endpoint IDs (EID) for chains supported by MoreVaults */
|
|
11
|
+
export const LZ_EIDS = {
|
|
12
|
+
flowMainnet: 30332,
|
|
13
|
+
flowTestnet: 30333,
|
|
14
|
+
arbitrum: 30110,
|
|
15
|
+
base: 30184,
|
|
16
|
+
ethereum: 30101,
|
|
17
|
+
} as const;
|
|
18
|
+
|
|
19
|
+
/** LayerZero EID → EVM Chain ID */
|
|
20
|
+
export const EID_TO_CHAIN_ID: Record<number, number> = {
|
|
21
|
+
[LZ_EIDS.flowMainnet]: CHAIN_IDS.flowEVMMainnet,
|
|
22
|
+
[LZ_EIDS.flowTestnet]: CHAIN_IDS.flowEVMTestnet,
|
|
23
|
+
[LZ_EIDS.arbitrum]: CHAIN_IDS.arbitrum,
|
|
24
|
+
[LZ_EIDS.base]: CHAIN_IDS.base,
|
|
25
|
+
[LZ_EIDS.ethereum]: CHAIN_IDS.ethereum,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/** EVM Chain ID → LayerZero EID */
|
|
29
|
+
export const CHAIN_ID_TO_EID: Record<number, number> = {
|
|
30
|
+
[CHAIN_IDS.flowEVMMainnet]: LZ_EIDS.flowMainnet,
|
|
31
|
+
[CHAIN_IDS.flowEVMTestnet]: LZ_EIDS.flowTestnet,
|
|
32
|
+
[CHAIN_IDS.arbitrum]: LZ_EIDS.arbitrum,
|
|
33
|
+
[CHAIN_IDS.base]: LZ_EIDS.base,
|
|
34
|
+
[CHAIN_IDS.ethereum]: LZ_EIDS.ethereum,
|
|
35
|
+
};
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "./types";
|
|
10
10
|
import { preflightAsync, preflightSync } from "./preflight";
|
|
11
11
|
import { MissingEscrowAddressError, VaultPausedError, CapacityFullError } from "./errors";
|
|
12
|
+
import { validateWalletChain } from "./chainValidation";
|
|
12
13
|
import { getVaultStatus, quoteLzFee } from "./utils";
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -53,6 +54,9 @@ export async function depositSimple(
|
|
|
53
54
|
): Promise<DepositResult> {
|
|
54
55
|
const provider = signer.provider!;
|
|
55
56
|
|
|
57
|
+
// Validate wallet is on the correct chain (opt-in via hubChainId)
|
|
58
|
+
await validateWalletChain(signer, addresses.hubChainId);
|
|
59
|
+
|
|
56
60
|
// Pre-flight: validate vault is operational and accepting deposits
|
|
57
61
|
await preflightSync(provider, addresses.vault);
|
|
58
62
|
|
|
@@ -114,6 +118,9 @@ export async function depositMultiAsset(
|
|
|
114
118
|
receiver: string,
|
|
115
119
|
minShares: bigint
|
|
116
120
|
): Promise<DepositResult> {
|
|
121
|
+
// Validate wallet is on the correct chain (opt-in via hubChainId)
|
|
122
|
+
await validateWalletChain(signer, addresses.hubChainId);
|
|
123
|
+
|
|
117
124
|
// Approve each token
|
|
118
125
|
for (let i = 0; i < tokens.length; i++) {
|
|
119
126
|
await ensureAllowance(signer, tokens[i], addresses.vault, amounts[i]);
|
|
@@ -190,6 +197,9 @@ export async function depositAsync(
|
|
|
190
197
|
if (!addresses.escrow) throw new MissingEscrowAddressError();
|
|
191
198
|
const escrow = addresses.escrow;
|
|
192
199
|
|
|
200
|
+
// Validate wallet is on the correct chain (opt-in via hubChainId)
|
|
201
|
+
await validateWalletChain(signer, addresses.hubChainId);
|
|
202
|
+
|
|
193
203
|
// Pre-flight: validate async cross-chain setup before sending any transaction
|
|
194
204
|
await preflightAsync(provider, addresses.vault, escrow);
|
|
195
205
|
|
|
@@ -262,6 +272,9 @@ export async function mintAsync(
|
|
|
262
272
|
if (!addresses.escrow) throw new MissingEscrowAddressError();
|
|
263
273
|
const escrow = addresses.escrow;
|
|
264
274
|
|
|
275
|
+
// Validate wallet is on the correct chain (opt-in via hubChainId)
|
|
276
|
+
await validateWalletChain(signer, addresses.hubChainId);
|
|
277
|
+
|
|
265
278
|
// Pre-flight: validate async cross-chain setup before sending any transaction
|
|
266
279
|
await preflightAsync(provider, addresses.vault, escrow);
|
|
267
280
|
|
package/src/ethers/errors.ts
CHANGED
|
@@ -79,3 +79,12 @@ export class MissingEscrowAddressError extends MoreVaultsError {
|
|
|
79
79
|
this.name = 'MissingEscrowAddressError'
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
+
|
|
83
|
+
export class WrongChainError extends MoreVaultsError {
|
|
84
|
+
constructor(currentChainId: number, expectedChainId: number) {
|
|
85
|
+
super(
|
|
86
|
+
`Wrong network: wallet is on chain ${currentChainId}, but the vault hub requires chain ${expectedChainId}. Switch networks before proceeding.`,
|
|
87
|
+
)
|
|
88
|
+
this.name = 'WrongChainError'
|
|
89
|
+
}
|
|
90
|
+
}
|
package/src/ethers/index.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
// MoreVaults SDK -- ethers.js v6
|
|
2
2
|
// Barrel export for all flows and utilities.
|
|
3
3
|
|
|
4
|
+
// --- Chain constants ---
|
|
5
|
+
export { CHAIN_IDS, LZ_EIDS, EID_TO_CHAIN_ID, CHAIN_ID_TO_EID } from "./chains";
|
|
6
|
+
|
|
4
7
|
// --- Types ---
|
|
5
8
|
export type {
|
|
6
9
|
VaultAddresses,
|
|
@@ -36,6 +39,7 @@ export {
|
|
|
36
39
|
EscrowNotConfiguredError,
|
|
37
40
|
NotHubVaultError,
|
|
38
41
|
MissingEscrowAddressError,
|
|
42
|
+
WrongChainError,
|
|
39
43
|
} from "./errors";
|
|
40
44
|
|
|
41
45
|
// --- Deposit flows ---
|
|
@@ -101,3 +105,6 @@ export type {
|
|
|
101
105
|
MaxWithdrawable,
|
|
102
106
|
VaultSummary,
|
|
103
107
|
} from "./userHelpers";
|
|
108
|
+
|
|
109
|
+
// --- wagmi / ethers adapter compatibility ---
|
|
110
|
+
export { asSdkSigner } from "./wagmiCompat";
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import type { ContractTransactionReceipt } from "ethers";
|
|
15
15
|
import { preflightAsync, preflightRedeemLiquidity } from "./preflight";
|
|
16
16
|
import { MissingEscrowAddressError } from "./errors";
|
|
17
|
+
import { validateWalletChain } from "./chainValidation";
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Ensure `spender` has at least `amount` allowance from `owner`.
|
|
@@ -58,6 +59,9 @@ export async function redeemShares(
|
|
|
58
59
|
receiver: string,
|
|
59
60
|
owner: string
|
|
60
61
|
): Promise<RedeemResult> {
|
|
62
|
+
// Validate wallet is on the correct chain (opt-in via hubChainId)
|
|
63
|
+
await validateWalletChain(signer, addresses.hubChainId);
|
|
64
|
+
|
|
61
65
|
const vault = new Contract(addresses.vault, VAULT_ABI, signer);
|
|
62
66
|
|
|
63
67
|
// Static call to get the return value (assets) before broadcasting
|
|
@@ -92,6 +96,9 @@ export async function withdrawAssets(
|
|
|
92
96
|
receiver: string,
|
|
93
97
|
owner: string
|
|
94
98
|
): Promise<RedeemResult> {
|
|
99
|
+
// Validate wallet is on the correct chain (opt-in via hubChainId)
|
|
100
|
+
await validateWalletChain(signer, addresses.hubChainId);
|
|
101
|
+
|
|
95
102
|
const vault = new Contract(addresses.vault, VAULT_ABI, signer);
|
|
96
103
|
const tx = await vault.withdraw(assets, receiver, owner);
|
|
97
104
|
const receipt = await tx.wait();
|
|
@@ -122,6 +129,9 @@ export async function requestRedeem(
|
|
|
122
129
|
shares: bigint,
|
|
123
130
|
owner: string
|
|
124
131
|
): Promise<{ receipt: ContractTransactionReceipt }> {
|
|
132
|
+
// Validate wallet is on the correct chain (opt-in via hubChainId)
|
|
133
|
+
await validateWalletChain(signer, addresses.hubChainId);
|
|
134
|
+
|
|
125
135
|
const vault = new Contract(addresses.vault, VAULT_ABI, signer);
|
|
126
136
|
const tx = await vault.requestRedeem(shares, owner);
|
|
127
137
|
const receipt = await tx.wait();
|
|
@@ -192,6 +202,9 @@ export async function redeemAsync(
|
|
|
192
202
|
if (!addresses.escrow) throw new MissingEscrowAddressError();
|
|
193
203
|
const escrow = addresses.escrow;
|
|
194
204
|
|
|
205
|
+
// Validate wallet is on the correct chain (opt-in via hubChainId)
|
|
206
|
+
await validateWalletChain(signer, addresses.hubChainId);
|
|
207
|
+
|
|
195
208
|
// Pre-flight: validate async cross-chain setup before sending any transaction
|
|
196
209
|
await preflightAsync(provider, addresses.vault, escrow);
|
|
197
210
|
|
package/src/ethers/types.ts
CHANGED
|
@@ -10,6 +10,12 @@ export interface VaultAddresses {
|
|
|
10
10
|
shareOFT?: string;
|
|
11
11
|
/** OFT address for USDC bridging (cross-chain only). */
|
|
12
12
|
usdcOFT?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Expected EVM chain ID of the hub. When provided, SDK functions will
|
|
15
|
+
* throw a clear WrongChainError if the signer is on a different chain.
|
|
16
|
+
* Prevents silent failures when MetaMask is connected to the wrong network.
|
|
17
|
+
*/
|
|
18
|
+
hubChainId?: number;
|
|
13
19
|
}
|
|
14
20
|
|
|
15
21
|
/** Result of a synchronous deposit or mint. */
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Signer } from 'ethers'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Cast an ethers Signer (e.g. from wagmi's useEthersSigner adapter) to
|
|
5
|
+
* the SDK's expected type. Use this to avoid `as any` casts:
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { useEthersSigner } from './wagmi-ethers-adapter'
|
|
8
|
+
* import { asSdkSigner } from '@oydual31/more-vaults-sdk/ethers'
|
|
9
|
+
* const signer = asSdkSigner(useEthersSigner())
|
|
10
|
+
* ```
|
|
11
|
+
* This function validates the signer is non-null and applies a documented
|
|
12
|
+
* cast instead of an opaque `as any`.
|
|
13
|
+
*/
|
|
14
|
+
export function asSdkSigner(signer: unknown): Signer {
|
|
15
|
+
if (!signer) throw new Error('[MoreVaults] No signer available. Make sure the wallet is connected and wagmi is configured correctly.')
|
|
16
|
+
return signer as Signer
|
|
17
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { WalletClient } from 'viem'
|
|
2
|
+
import { WrongChainError } from './errors'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Validate that the walletClient is connected to the expected chain.
|
|
6
|
+
* Only validates if hubChainId is provided — opt-in, non-breaking.
|
|
7
|
+
*/
|
|
8
|
+
export function validateWalletChain(walletClient: WalletClient, hubChainId?: number): void {
|
|
9
|
+
if (!hubChainId) return
|
|
10
|
+
const current = walletClient.chain?.id
|
|
11
|
+
if (current !== undefined && current !== hubChainId) {
|
|
12
|
+
throw new WrongChainError(current, hubChainId)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** EVM Chain IDs for chains supported by MoreVaults */
|
|
2
|
+
export const CHAIN_IDS = {
|
|
3
|
+
flowEVMMainnet: 747,
|
|
4
|
+
flowEVMTestnet: 545,
|
|
5
|
+
arbitrum: 42161,
|
|
6
|
+
base: 8453,
|
|
7
|
+
ethereum: 1,
|
|
8
|
+
} as const
|
|
9
|
+
|
|
10
|
+
/** LayerZero Endpoint IDs (EID) for chains supported by MoreVaults */
|
|
11
|
+
export const LZ_EIDS = {
|
|
12
|
+
flowMainnet: 30332,
|
|
13
|
+
flowTestnet: 30333,
|
|
14
|
+
arbitrum: 30110,
|
|
15
|
+
base: 30184,
|
|
16
|
+
ethereum: 30101,
|
|
17
|
+
} as const
|
|
18
|
+
|
|
19
|
+
/** LayerZero EID → EVM Chain ID */
|
|
20
|
+
export const EID_TO_CHAIN_ID: Record<number, number> = {
|
|
21
|
+
[LZ_EIDS.flowMainnet]: CHAIN_IDS.flowEVMMainnet,
|
|
22
|
+
[LZ_EIDS.flowTestnet]: CHAIN_IDS.flowEVMTestnet,
|
|
23
|
+
[LZ_EIDS.arbitrum]: CHAIN_IDS.arbitrum,
|
|
24
|
+
[LZ_EIDS.base]: CHAIN_IDS.base,
|
|
25
|
+
[LZ_EIDS.ethereum]: CHAIN_IDS.ethereum,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** EVM Chain ID → LayerZero EID */
|
|
29
|
+
export const CHAIN_ID_TO_EID: Record<number, number> = {
|
|
30
|
+
[CHAIN_IDS.flowEVMMainnet]: LZ_EIDS.flowMainnet,
|
|
31
|
+
[CHAIN_IDS.flowEVMTestnet]: LZ_EIDS.flowTestnet,
|
|
32
|
+
[CHAIN_IDS.arbitrum]: LZ_EIDS.arbitrum,
|
|
33
|
+
[CHAIN_IDS.base]: LZ_EIDS.base,
|
|
34
|
+
[CHAIN_IDS.ethereum]: LZ_EIDS.ethereum,
|
|
35
|
+
}
|
package/src/viem/depositFlows.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { ActionType } from './types'
|
|
|
15
15
|
import { ensureAllowance, getVaultStatus, quoteLzFee } from './utils'
|
|
16
16
|
import { preflightSync, preflightAsync } from './preflight'
|
|
17
17
|
import { MissingEscrowAddressError, VaultPausedError, CapacityFullError } from './errors'
|
|
18
|
+
import { validateWalletChain } from './chainValidation'
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* D1 / D3 — Simple deposit (ERC-4626 standard).
|
|
@@ -42,6 +43,9 @@ export async function depositSimple(
|
|
|
42
43
|
const account = walletClient.account!
|
|
43
44
|
const vault = getAddress(addresses.vault)
|
|
44
45
|
|
|
46
|
+
// Validate wallet is on the correct chain (opt-in via hubChainId)
|
|
47
|
+
validateWalletChain(walletClient, addresses.hubChainId)
|
|
48
|
+
|
|
45
49
|
// Pre-flight: validate vault is operational and accepting deposits
|
|
46
50
|
await preflightSync(publicClient, vault)
|
|
47
51
|
|
|
@@ -111,6 +115,9 @@ export async function depositMultiAsset(
|
|
|
111
115
|
const account = walletClient.account!
|
|
112
116
|
const vault = getAddress(addresses.vault)
|
|
113
117
|
|
|
118
|
+
// Validate wallet is on the correct chain (opt-in via hubChainId)
|
|
119
|
+
validateWalletChain(walletClient, addresses.hubChainId)
|
|
120
|
+
|
|
114
121
|
// Approve each token
|
|
115
122
|
for (let i = 0; i < tokens.length; i++) {
|
|
116
123
|
await ensureAllowance(walletClient, publicClient, tokens[i], vault, amounts[i])
|
|
@@ -169,6 +176,9 @@ export async function depositAsync(
|
|
|
169
176
|
if (!addresses.escrow) throw new MissingEscrowAddressError()
|
|
170
177
|
const escrow = getAddress(addresses.escrow)
|
|
171
178
|
|
|
179
|
+
// Validate wallet is on the correct chain (opt-in via hubChainId)
|
|
180
|
+
validateWalletChain(walletClient, addresses.hubChainId)
|
|
181
|
+
|
|
172
182
|
// Pre-flight: validate async cross-chain setup before sending any transaction
|
|
173
183
|
await preflightAsync(publicClient, vault, escrow)
|
|
174
184
|
|
|
@@ -244,6 +254,9 @@ export async function mintAsync(
|
|
|
244
254
|
if (!addresses.escrow) throw new MissingEscrowAddressError()
|
|
245
255
|
const escrow = getAddress(addresses.escrow)
|
|
246
256
|
|
|
257
|
+
// Validate wallet is on the correct chain (opt-in via hubChainId)
|
|
258
|
+
validateWalletChain(walletClient, addresses.hubChainId)
|
|
259
|
+
|
|
247
260
|
// Pre-flight: validate async cross-chain setup before sending any transaction
|
|
248
261
|
await preflightAsync(publicClient, vault, escrow)
|
|
249
262
|
|
package/src/viem/errors.ts
CHANGED
|
@@ -79,3 +79,12 @@ export class MissingEscrowAddressError extends MoreVaultsError {
|
|
|
79
79
|
this.name = 'MissingEscrowAddressError'
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
+
|
|
83
|
+
export class WrongChainError extends MoreVaultsError {
|
|
84
|
+
constructor(currentChainId: number, expectedChainId: number) {
|
|
85
|
+
super(
|
|
86
|
+
`Wrong network: wallet is on chain ${currentChainId}, but the vault hub requires chain ${expectedChainId}. Switch networks before proceeding.`,
|
|
87
|
+
)
|
|
88
|
+
this.name = 'WrongChainError'
|
|
89
|
+
}
|
|
90
|
+
}
|
package/src/viem/index.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
// MoreVaults SDK — viem/wagmi
|
|
2
2
|
// Provides typed helpers for all deposit, redeem, and cross-chain vault flows.
|
|
3
3
|
|
|
4
|
+
// --- Chain constants ---
|
|
5
|
+
export { CHAIN_IDS, LZ_EIDS, EID_TO_CHAIN_ID, CHAIN_ID_TO_EID } from './chains'
|
|
6
|
+
|
|
4
7
|
// --- ABIs ---
|
|
5
8
|
export {
|
|
6
9
|
VAULT_ABI,
|
|
@@ -33,6 +36,7 @@ export {
|
|
|
33
36
|
EscrowNotConfiguredError,
|
|
34
37
|
NotHubVaultError,
|
|
35
38
|
MissingEscrowAddressError,
|
|
39
|
+
WrongChainError,
|
|
36
40
|
} from './errors'
|
|
37
41
|
|
|
38
42
|
// --- Deposit Flows ---
|
|
@@ -98,3 +102,10 @@ export type {
|
|
|
98
102
|
MaxWithdrawable,
|
|
99
103
|
VaultSummary,
|
|
100
104
|
} from './userHelpers'
|
|
105
|
+
|
|
106
|
+
// --- wagmi compatibility ---
|
|
107
|
+
// Re-export viem's PublicClient type for wagmi compatibility.
|
|
108
|
+
// wagmi's usePublicClient() returns a type that is structurally compatible
|
|
109
|
+
// with viem's PublicClient but TypeScript may complain without this cast helper.
|
|
110
|
+
export type { PublicClient as SdkPublicClient } from 'viem'
|
|
111
|
+
export { asSdkClient } from './wagmiCompat'
|
package/src/viem/redeemFlows.ts
CHANGED
|
@@ -17,6 +17,7 @@ import { ActionType } from './types'
|
|
|
17
17
|
import { ensureAllowance } from './utils'
|
|
18
18
|
import { preflightAsync, preflightRedeemLiquidity } from './preflight'
|
|
19
19
|
import { MissingEscrowAddressError } from './errors'
|
|
20
|
+
import { validateWalletChain } from './chainValidation'
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* R1 — Simple share redemption (ERC-4626 standard).
|
|
@@ -46,6 +47,9 @@ export async function redeemShares(
|
|
|
46
47
|
const account = walletClient.account!
|
|
47
48
|
const vault = getAddress(addresses.vault)
|
|
48
49
|
|
|
50
|
+
// Validate wallet is on the correct chain (opt-in via hubChainId)
|
|
51
|
+
validateWalletChain(walletClient, addresses.hubChainId)
|
|
52
|
+
|
|
49
53
|
const { result: assets } = await publicClient.simulateContract({
|
|
50
54
|
address: vault,
|
|
51
55
|
abi: VAULT_ABI,
|
|
@@ -94,6 +98,9 @@ export async function withdrawAssets(
|
|
|
94
98
|
const account = walletClient.account!
|
|
95
99
|
const vault = getAddress(addresses.vault)
|
|
96
100
|
|
|
101
|
+
// Validate wallet is on the correct chain (opt-in via hubChainId)
|
|
102
|
+
validateWalletChain(walletClient, addresses.hubChainId)
|
|
103
|
+
|
|
97
104
|
const { result: sharesBurned } = await publicClient.simulateContract({
|
|
98
105
|
address: vault,
|
|
99
106
|
abi: VAULT_ABI,
|
|
@@ -143,6 +150,9 @@ export async function requestRedeem(
|
|
|
143
150
|
const account = walletClient.account!
|
|
144
151
|
const vault = getAddress(addresses.vault)
|
|
145
152
|
|
|
153
|
+
// Validate wallet is on the correct chain (opt-in via hubChainId)
|
|
154
|
+
validateWalletChain(walletClient, addresses.hubChainId)
|
|
155
|
+
|
|
146
156
|
await publicClient.simulateContract({
|
|
147
157
|
address: vault,
|
|
148
158
|
abi: VAULT_ABI,
|
|
@@ -231,6 +241,9 @@ export async function redeemAsync(
|
|
|
231
241
|
if (!addresses.escrow) throw new MissingEscrowAddressError()
|
|
232
242
|
const escrow = getAddress(addresses.escrow)
|
|
233
243
|
|
|
244
|
+
// Validate wallet is on the correct chain (opt-in via hubChainId)
|
|
245
|
+
validateWalletChain(walletClient, addresses.hubChainId)
|
|
246
|
+
|
|
234
247
|
// Pre-flight: validate async cross-chain setup before sending any transaction
|
|
235
248
|
await preflightAsync(publicClient, vault, escrow)
|
|
236
249
|
|
package/src/viem/types.ts
CHANGED
|
@@ -9,6 +9,12 @@ export interface VaultAddresses {
|
|
|
9
9
|
shareOFT?: Address
|
|
10
10
|
/** OFT for USDC bridging (cross-chain deposits from spoke) */
|
|
11
11
|
usdcOFT?: Address
|
|
12
|
+
/**
|
|
13
|
+
* Expected EVM chain ID of the hub. When provided, SDK functions will
|
|
14
|
+
* throw a clear WrongChainError if the walletClient is on a different chain.
|
|
15
|
+
* Prevents silent failures when MetaMask is connected to the wrong network.
|
|
16
|
+
*/
|
|
17
|
+
hubChainId?: number
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
export interface DepositResult {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PublicClient } from 'viem'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Cast a wagmi PublicClient to the SDK's expected type.
|
|
5
|
+
* Use this in React components to avoid `as any` casts:
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { usePublicClient } from 'wagmi'
|
|
8
|
+
* import { asSdkClient } from '@oydual31/more-vaults-sdk/viem'
|
|
9
|
+
* const pc = asSdkClient(usePublicClient())
|
|
10
|
+
* ```
|
|
11
|
+
* wagmi v2 uses viem as a peer dependency, so the types are structurally
|
|
12
|
+
* identical — this function validates the client is non-null and applies
|
|
13
|
+
* a documented cast instead of an opaque `as any`.
|
|
14
|
+
*/
|
|
15
|
+
export function asSdkClient(client: unknown): PublicClient {
|
|
16
|
+
if (!client) throw new Error('[MoreVaults] No public client available. Make sure wagmi is configured correctly.')
|
|
17
|
+
return client as PublicClient
|
|
18
|
+
}
|