@oydual31/more-vaults-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +283 -0
- package/dist/ethers/index.cjs +973 -0
- package/dist/ethers/index.cjs.map +1 -0
- package/dist/ethers/index.d.cts +671 -0
- package/dist/ethers/index.d.ts +671 -0
- package/dist/ethers/index.js +924 -0
- package/dist/ethers/index.js.map +1 -0
- package/dist/viem/index.cjs +1426 -0
- package/dist/viem/index.cjs.map +1 -0
- package/dist/viem/index.d.cts +1291 -0
- package/dist/viem/index.d.ts +1291 -0
- package/dist/viem/index.js +1377 -0
- package/dist/viem/index.js.map +1 -0
- package/package.json +46 -0
- package/src/ethers/abis.ts +82 -0
- package/src/ethers/crossChainFlows.ts +206 -0
- package/src/ethers/depositFlows.ts +347 -0
- package/src/ethers/errors.ts +81 -0
- package/src/ethers/index.ts +103 -0
- package/src/ethers/preflight.ts +156 -0
- package/src/ethers/redeemFlows.ts +286 -0
- package/src/ethers/types.ts +67 -0
- package/src/ethers/userHelpers.ts +480 -0
- package/src/ethers/utils.ts +377 -0
- package/src/viem/abis.ts +392 -0
- package/src/viem/crossChainFlows.ts +220 -0
- package/src/viem/depositFlows.ts +331 -0
- package/src/viem/errors.ts +81 -0
- package/src/viem/index.ts +100 -0
- package/src/viem/preflight.ts +204 -0
- package/src/viem/redeemFlows.ts +337 -0
- package/src/viem/types.ts +56 -0
- package/src/viem/userHelpers.ts +489 -0
- package/src/viem/utils.ts +421 -0
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Address,
|
|
3
|
+
type PublicClient,
|
|
4
|
+
type WalletClient,
|
|
5
|
+
getAddress,
|
|
6
|
+
zeroAddress,
|
|
7
|
+
} from 'viem'
|
|
8
|
+
import { BRIDGE_ABI, CONFIG_ABI, ERC20_ABI, VAULT_ABI, METADATA_ABI } from './abis'
|
|
9
|
+
import type { CrossChainRequestInfo } from './types'
|
|
10
|
+
|
|
11
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
export type VaultMode =
|
|
14
|
+
| 'local' // single-chain vault, no cross-chain
|
|
15
|
+
| 'cross-chain-oracle' // hub with oracle-based accounting (sync)
|
|
16
|
+
| 'cross-chain-async' // hub with off-chain accounting (async, D4/D5/R5)
|
|
17
|
+
| 'paused' // vault is paused
|
|
18
|
+
| 'full' // deposit capacity reached
|
|
19
|
+
|
|
20
|
+
export interface VaultStatus {
|
|
21
|
+
/** Vault operating mode — determines which SDK flow to use */
|
|
22
|
+
mode: VaultMode
|
|
23
|
+
/** Which deposit function to call given the current configuration */
|
|
24
|
+
recommendedDepositFlow: 'depositSimple' | 'depositAsync' | 'mintAsync' | 'none'
|
|
25
|
+
/** Which redeem function to call given the current configuration */
|
|
26
|
+
recommendedRedeemFlow: 'redeemShares' | 'redeemAsync' | 'none'
|
|
27
|
+
|
|
28
|
+
// ── Configuration ────────────────────────────────────────────────────────
|
|
29
|
+
isHub: boolean
|
|
30
|
+
isPaused: boolean
|
|
31
|
+
oracleAccountingEnabled: boolean
|
|
32
|
+
|
|
33
|
+
/** address(0) means CCManager is not set — async flows will fail */
|
|
34
|
+
ccManager: Address
|
|
35
|
+
/** address(0) means escrow is not configured in the registry */
|
|
36
|
+
escrow: Address
|
|
37
|
+
|
|
38
|
+
// ── Withdrawal queue ─────────────────────────────────────────────────────
|
|
39
|
+
withdrawalQueueEnabled: boolean
|
|
40
|
+
/** Timelock duration in seconds (0 = no timelock) */
|
|
41
|
+
withdrawalTimelockSeconds: bigint
|
|
42
|
+
|
|
43
|
+
// ── Capacity ─────────────────────────────────────────────────────────────
|
|
44
|
+
/**
|
|
45
|
+
* Remaining deposit capacity in underlying token decimals.
|
|
46
|
+
* `type(uint256).max` = no cap configured (unlimited).
|
|
47
|
+
* `0n` = vault is full — no more deposits accepted.
|
|
48
|
+
* If `depositAccessRestricted = true`, this value is `type(uint256).max` but
|
|
49
|
+
* deposits are still gated by whitelist or other access control.
|
|
50
|
+
*/
|
|
51
|
+
remainingDepositCapacity: bigint
|
|
52
|
+
/**
|
|
53
|
+
* True when `maxDeposit(address(0))` reverted, indicating the vault uses
|
|
54
|
+
* whitelist or other access control to restrict who can deposit.
|
|
55
|
+
* Deposit flows will succeed only for addresses the vault operator has approved.
|
|
56
|
+
*/
|
|
57
|
+
depositAccessRestricted: boolean
|
|
58
|
+
|
|
59
|
+
// ── Vault metrics ────────────────────────────────────────────────────────
|
|
60
|
+
underlying: Address
|
|
61
|
+
totalAssets: bigint
|
|
62
|
+
totalSupply: bigint
|
|
63
|
+
/** Vault share token decimals. Use this for display — never hardcode 18. */
|
|
64
|
+
decimals: number
|
|
65
|
+
/**
|
|
66
|
+
* Price of 1 full share expressed in underlying token units.
|
|
67
|
+
* = convertToAssets(10^decimals). Grows over time as the vault earns yield.
|
|
68
|
+
*/
|
|
69
|
+
sharePrice: bigint
|
|
70
|
+
/**
|
|
71
|
+
* Underlying token balance held directly on the hub chain.
|
|
72
|
+
* This is the only portion that can be paid out to redeeming users immediately.
|
|
73
|
+
* (= ERC-20.balanceOf(vault) on the hub)
|
|
74
|
+
*/
|
|
75
|
+
hubLiquidBalance: bigint
|
|
76
|
+
/**
|
|
77
|
+
* Approximate value deployed to spoke chains (totalAssets − hubLiquidBalance).
|
|
78
|
+
* These funds are NOT immediately redeemable — the vault curator must
|
|
79
|
+
* call executeBridging to repatriate them before large redeems can succeed.
|
|
80
|
+
*/
|
|
81
|
+
spokesDeployedBalance: bigint
|
|
82
|
+
/**
|
|
83
|
+
* Maximum assets that can be redeemed right now without curator intervention.
|
|
84
|
+
* - For hub vaults: equals `hubLiquidBalance` (only what the hub holds).
|
|
85
|
+
* - For local/oracle vaults: equals `totalAssets` (all assets are local).
|
|
86
|
+
* Attempting to redeem more than this will revert (R1) or be auto-refunded (R5).
|
|
87
|
+
*/
|
|
88
|
+
maxImmediateRedeemAssets: bigint
|
|
89
|
+
|
|
90
|
+
// ── Issues — empty when everything is correctly configured ───────────────
|
|
91
|
+
/**
|
|
92
|
+
* Human-readable list of configuration problems that would cause transactions
|
|
93
|
+
* to fail. Empty array = vault is ready to use.
|
|
94
|
+
*/
|
|
95
|
+
issues: string[]
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Read the full configuration and operational status of a vault in a single
|
|
100
|
+
* multicall-friendly batch.
|
|
101
|
+
*
|
|
102
|
+
* Use this to:
|
|
103
|
+
* - Determine which SDK flow to use (`recommendedDepositFlow`)
|
|
104
|
+
* - Show a configuration checklist in an admin dashboard
|
|
105
|
+
* - Surface `issues` to the developer before any transaction
|
|
106
|
+
*
|
|
107
|
+
* @param publicClient Public client for reads
|
|
108
|
+
* @param vault Vault address (diamond proxy)
|
|
109
|
+
* @returns Full vault status snapshot
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* const status = await getVaultStatus(publicClient, VAULT)
|
|
114
|
+
* if (status.issues.length) {
|
|
115
|
+
* console.warn('Vault misconfigured:', status.issues)
|
|
116
|
+
* }
|
|
117
|
+
* // Use recommended flow:
|
|
118
|
+
* if (status.recommendedDepositFlow === 'depositAsync') {
|
|
119
|
+
* await depositAsync(walletClient, publicClient, { vault: VAULT, escrow: status.escrow }, ...)
|
|
120
|
+
* }
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export async function getVaultStatus(
|
|
124
|
+
publicClient: PublicClient,
|
|
125
|
+
vault: Address,
|
|
126
|
+
): Promise<VaultStatus> {
|
|
127
|
+
const v = getAddress(vault)
|
|
128
|
+
|
|
129
|
+
// ── Batch 1: single multicall — 12 reads, 1 HTTP request ─────────────────
|
|
130
|
+
// maxDeposit(address(0)) may revert on whitelisted vaults — allowFailure handles it.
|
|
131
|
+
const b1 = await publicClient.multicall({
|
|
132
|
+
contracts: [
|
|
133
|
+
{ address: v, abi: CONFIG_ABI, functionName: 'isHub' },
|
|
134
|
+
{ address: v, abi: CONFIG_ABI, functionName: 'paused' },
|
|
135
|
+
{ address: v, abi: BRIDGE_ABI, functionName: 'oraclesCrossChainAccounting' },
|
|
136
|
+
{ address: v, abi: CONFIG_ABI, functionName: 'getCrossChainAccountingManager' },
|
|
137
|
+
{ address: v, abi: CONFIG_ABI, functionName: 'getEscrow' },
|
|
138
|
+
{ address: v, abi: CONFIG_ABI, functionName: 'getWithdrawalQueueStatus' },
|
|
139
|
+
{ address: v, abi: CONFIG_ABI, functionName: 'getWithdrawalTimelock' },
|
|
140
|
+
{ address: v, abi: CONFIG_ABI, functionName: 'maxDeposit', args: [zeroAddress] },
|
|
141
|
+
{ address: v, abi: VAULT_ABI, functionName: 'asset' },
|
|
142
|
+
{ address: v, abi: VAULT_ABI, functionName: 'totalAssets' },
|
|
143
|
+
{ address: v, abi: VAULT_ABI, functionName: 'totalSupply' },
|
|
144
|
+
{ address: v, abi: METADATA_ABI, functionName: 'decimals' },
|
|
145
|
+
] as const,
|
|
146
|
+
allowFailure: true,
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
const isHub = b1[0].status === 'success' ? b1[0].result as boolean : false
|
|
150
|
+
const isPaused = b1[1].status === 'success' ? b1[1].result as boolean : false
|
|
151
|
+
const oraclesEnabled = b1[2].status === 'success' ? b1[2].result as boolean : false
|
|
152
|
+
const ccManager = b1[3].status === 'success' ? b1[3].result as Address : zeroAddress
|
|
153
|
+
const escrow = b1[4].status === 'success' ? b1[4].result as Address : zeroAddress
|
|
154
|
+
const withdrawalQueueEnabled = b1[5].status === 'success' ? b1[5].result as boolean : false
|
|
155
|
+
const withdrawalTimelockSeconds = b1[6].status === 'success' ? b1[6].result as bigint : 0n
|
|
156
|
+
// null = reverted (whitelist/ACL), bigint = normal return
|
|
157
|
+
const maxDepositRaw = b1[7].status === 'success' ? b1[7].result as bigint : null
|
|
158
|
+
const underlying = b1[8].status === 'success' ? b1[8].result as Address : zeroAddress
|
|
159
|
+
const totalAssets = b1[9].status === 'success' ? b1[9].result as bigint : 0n
|
|
160
|
+
const totalSupply = b1[10].status === 'success' ? b1[10].result as bigint : 0n
|
|
161
|
+
const decimals = b1[11].status === 'success' ? Number(b1[11].result) : 18
|
|
162
|
+
|
|
163
|
+
// ── Batch 2: depends on underlying + decimals from batch 1 ────────────────
|
|
164
|
+
const oneShare = 10n ** BigInt(decimals)
|
|
165
|
+
const b2 = await publicClient.multicall({
|
|
166
|
+
contracts: [
|
|
167
|
+
{ address: getAddress(underlying), abi: ERC20_ABI, functionName: 'balanceOf', args: [v] },
|
|
168
|
+
{ address: v, abi: VAULT_ABI, functionName: 'convertToAssets', args: [oneShare] },
|
|
169
|
+
] as const,
|
|
170
|
+
allowFailure: true,
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
const hubLiquidBalance = b2[0].status === 'success' ? b2[0].result as bigint : 0n
|
|
174
|
+
const sharePrice = b2[1].status === 'success' ? b2[1].result as bigint : 0n
|
|
175
|
+
|
|
176
|
+
const spokesDeployedBalance = totalAssets > hubLiquidBalance ? totalAssets - hubLiquidBalance : 0n
|
|
177
|
+
|
|
178
|
+
// null = maxDeposit reverted → whitelist/ACL vault
|
|
179
|
+
const MAX_UINT256 = BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
|
|
180
|
+
const depositAccessRestricted = maxDepositRaw === null
|
|
181
|
+
const effectiveCapacity: bigint = depositAccessRestricted ? MAX_UINT256 : maxDepositRaw
|
|
182
|
+
|
|
183
|
+
// ── Derive mode ────────────────────────────────────────────────────────────
|
|
184
|
+
let mode: VaultMode
|
|
185
|
+
if (isPaused) {
|
|
186
|
+
mode = 'paused'
|
|
187
|
+
} else if (effectiveCapacity === 0n) {
|
|
188
|
+
mode = 'full'
|
|
189
|
+
} else if (!isHub) {
|
|
190
|
+
mode = 'local'
|
|
191
|
+
} else if (oraclesEnabled) {
|
|
192
|
+
mode = 'cross-chain-oracle'
|
|
193
|
+
} else {
|
|
194
|
+
mode = 'cross-chain-async'
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// ── Recommended flows ──────────────────────────────────────────────────────
|
|
198
|
+
let recommendedDepositFlow: VaultStatus['recommendedDepositFlow']
|
|
199
|
+
let recommendedRedeemFlow: VaultStatus['recommendedRedeemFlow']
|
|
200
|
+
|
|
201
|
+
if (mode === 'paused' || mode === 'full') {
|
|
202
|
+
recommendedDepositFlow = 'none'
|
|
203
|
+
recommendedRedeemFlow = mode === 'paused' ? 'none' : 'redeemShares'
|
|
204
|
+
} else if (mode === 'cross-chain-async') {
|
|
205
|
+
recommendedDepositFlow = 'depositAsync'
|
|
206
|
+
recommendedRedeemFlow = 'redeemAsync'
|
|
207
|
+
} else {
|
|
208
|
+
// local or cross-chain-oracle
|
|
209
|
+
recommendedDepositFlow = 'depositSimple'
|
|
210
|
+
recommendedRedeemFlow = 'redeemShares'
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// ── maxImmediateRedeemAssets ───────────────────────────────────────────────
|
|
214
|
+
const maxImmediateRedeemAssets = isHub && !oraclesEnabled ? hubLiquidBalance : totalAssets
|
|
215
|
+
|
|
216
|
+
// ── Issues ─────────────────────────────────────────────────────────────────
|
|
217
|
+
const issues: string[] = []
|
|
218
|
+
|
|
219
|
+
if (isPaused) {
|
|
220
|
+
issues.push('Vault is paused — no deposits or redeems are possible.')
|
|
221
|
+
}
|
|
222
|
+
if (effectiveCapacity === 0n && !isPaused) {
|
|
223
|
+
issues.push('Deposit capacity is full — increase depositCapacity via setDepositCapacity().')
|
|
224
|
+
}
|
|
225
|
+
if (depositAccessRestricted) {
|
|
226
|
+
issues.push('Deposit access is restricted (whitelist or other access control). Only approved addresses can deposit.')
|
|
227
|
+
}
|
|
228
|
+
if (isHub && !oraclesEnabled && ccManager === zeroAddress) {
|
|
229
|
+
issues.push(
|
|
230
|
+
'CCManager not configured — async flows will revert. Call setCrossChainAccountingManager(address) as vault owner.',
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
if (isHub && !oraclesEnabled && escrow === zeroAddress) {
|
|
234
|
+
issues.push(
|
|
235
|
+
'Escrow not configured in registry — async flows will revert. Set the escrow via the MoreVaultsRegistry.',
|
|
236
|
+
)
|
|
237
|
+
}
|
|
238
|
+
if (isHub) {
|
|
239
|
+
if (hubLiquidBalance === 0n) {
|
|
240
|
+
issues.push(
|
|
241
|
+
`Hub has no liquid assets (hubLiquidBalance = 0). All redeems will be auto-refunded until the curator repatriates funds from spokes via executeBridging().`,
|
|
242
|
+
)
|
|
243
|
+
} else if (totalAssets > 0n && hubLiquidBalance * 10n < totalAssets) {
|
|
244
|
+
const pct = Number((hubLiquidBalance * 10000n) / totalAssets) / 100
|
|
245
|
+
issues.push(
|
|
246
|
+
`Low hub liquidity: ${hubLiquidBalance} units liquid on hub (${pct.toFixed(1)}% of TVL). ` +
|
|
247
|
+
`Redeems above ${hubLiquidBalance} underlying units will be auto-refunded. ` +
|
|
248
|
+
`Curator must call executeBridging() to repatriate from spokes.`,
|
|
249
|
+
)
|
|
250
|
+
}
|
|
251
|
+
if (spokesDeployedBalance > 0n) {
|
|
252
|
+
const pct = ((Number(spokesDeployedBalance) / Number(totalAssets || 1n)) * 100).toFixed(1)
|
|
253
|
+
issues.push(
|
|
254
|
+
`${spokesDeployedBalance} units (~${pct}% of TVL) are deployed on spoke chains earning yield. ` +
|
|
255
|
+
`These are NOT immediately redeemable — they require a curator repatriation (executeBridging) before users can withdraw them.`,
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
mode,
|
|
262
|
+
recommendedDepositFlow,
|
|
263
|
+
recommendedRedeemFlow,
|
|
264
|
+
isHub,
|
|
265
|
+
isPaused,
|
|
266
|
+
oracleAccountingEnabled: oraclesEnabled,
|
|
267
|
+
ccManager,
|
|
268
|
+
escrow,
|
|
269
|
+
withdrawalQueueEnabled,
|
|
270
|
+
withdrawalTimelockSeconds: BigInt(withdrawalTimelockSeconds),
|
|
271
|
+
remainingDepositCapacity: effectiveCapacity,
|
|
272
|
+
depositAccessRestricted,
|
|
273
|
+
underlying,
|
|
274
|
+
totalAssets,
|
|
275
|
+
totalSupply,
|
|
276
|
+
decimals,
|
|
277
|
+
sharePrice,
|
|
278
|
+
hubLiquidBalance,
|
|
279
|
+
spokesDeployedBalance,
|
|
280
|
+
maxImmediateRedeemAssets,
|
|
281
|
+
issues,
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Ensure the spender has sufficient ERC-20 allowance; approve if not.
|
|
287
|
+
*
|
|
288
|
+
* Checks the current allowance and only sends an approve transaction if
|
|
289
|
+
* the existing allowance is less than the required amount.
|
|
290
|
+
*
|
|
291
|
+
* @param walletClient Wallet client with account attached
|
|
292
|
+
* @param publicClient Public client for reads
|
|
293
|
+
* @param token ERC-20 token address
|
|
294
|
+
* @param spender Address to approve
|
|
295
|
+
* @param amount Minimum required allowance
|
|
296
|
+
*/
|
|
297
|
+
export async function ensureAllowance(
|
|
298
|
+
walletClient: WalletClient,
|
|
299
|
+
publicClient: PublicClient,
|
|
300
|
+
token: Address,
|
|
301
|
+
spender: Address,
|
|
302
|
+
amount: bigint,
|
|
303
|
+
): Promise<void> {
|
|
304
|
+
const account = walletClient.account!
|
|
305
|
+
|
|
306
|
+
const allowance = await publicClient.readContract({
|
|
307
|
+
address: getAddress(token),
|
|
308
|
+
abi: ERC20_ABI,
|
|
309
|
+
functionName: 'allowance',
|
|
310
|
+
args: [account.address, getAddress(spender)],
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
if (allowance < amount) {
|
|
314
|
+
const hash = await walletClient.writeContract({
|
|
315
|
+
address: getAddress(token),
|
|
316
|
+
abi: ERC20_ABI,
|
|
317
|
+
functionName: 'approve',
|
|
318
|
+
args: [getAddress(spender), amount],
|
|
319
|
+
account,
|
|
320
|
+
chain: walletClient.chain,
|
|
321
|
+
})
|
|
322
|
+
await publicClient.waitForTransactionReceipt({ hash })
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Quote the LayerZero native fee required for async vault actions.
|
|
328
|
+
*
|
|
329
|
+
* Call this before `depositAsync`, `mintAsync`, or `redeemAsync` to get the
|
|
330
|
+
* exact `lzFee` (msg.value) needed.
|
|
331
|
+
*
|
|
332
|
+
* @param publicClient Public client for reads
|
|
333
|
+
* @param vault Vault address (diamond proxy)
|
|
334
|
+
* @param extraOptions Optional LZ extra options bytes (default 0x)
|
|
335
|
+
* @returns Required native fee in wei
|
|
336
|
+
*/
|
|
337
|
+
export async function quoteLzFee(
|
|
338
|
+
publicClient: PublicClient,
|
|
339
|
+
vault: Address,
|
|
340
|
+
extraOptions: `0x${string}` = '0x',
|
|
341
|
+
): Promise<bigint> {
|
|
342
|
+
return publicClient.readContract({
|
|
343
|
+
address: getAddress(vault),
|
|
344
|
+
abi: BRIDGE_ABI,
|
|
345
|
+
functionName: 'quoteAccountingFee',
|
|
346
|
+
args: [extraOptions],
|
|
347
|
+
})
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Check if a vault is operating in async mode (cross-chain hub with oracle OFF).
|
|
352
|
+
*
|
|
353
|
+
* When this returns `true`, deposits and redeems must use the async flows
|
|
354
|
+
* (D4/D5/R5) which go through `initVaultActionRequest`.
|
|
355
|
+
* When `false`, the vault either uses oracle-based accounting (sync) or is
|
|
356
|
+
* a single-chain vault.
|
|
357
|
+
*
|
|
358
|
+
* @param publicClient Public client for reads
|
|
359
|
+
* @param vault Vault address
|
|
360
|
+
* @returns `true` if the vault requires async cross-chain flows
|
|
361
|
+
*/
|
|
362
|
+
export async function isAsyncMode(
|
|
363
|
+
publicClient: PublicClient,
|
|
364
|
+
vault: Address,
|
|
365
|
+
): Promise<boolean> {
|
|
366
|
+
const v = getAddress(vault)
|
|
367
|
+
|
|
368
|
+
// A vault is async if it's a hub AND oracle accounting is OFF
|
|
369
|
+
const isHub = await publicClient.readContract({
|
|
370
|
+
address: v,
|
|
371
|
+
abi: CONFIG_ABI,
|
|
372
|
+
functionName: 'isHub',
|
|
373
|
+
})
|
|
374
|
+
|
|
375
|
+
if (!isHub) return false
|
|
376
|
+
|
|
377
|
+
const oraclesEnabled = await publicClient.readContract({
|
|
378
|
+
address: v,
|
|
379
|
+
abi: BRIDGE_ABI,
|
|
380
|
+
functionName: 'oraclesCrossChainAccounting',
|
|
381
|
+
})
|
|
382
|
+
|
|
383
|
+
return !oraclesEnabled
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Poll for async request completion status.
|
|
388
|
+
*
|
|
389
|
+
* After calling an async flow (D4/D5/R5), use this to check whether the
|
|
390
|
+
* LZ callback has resolved and `executeRequest` has been called.
|
|
391
|
+
*
|
|
392
|
+
* @param publicClient Public client for reads
|
|
393
|
+
* @param vault Vault address
|
|
394
|
+
* @param guid Request GUID returned by the async flow
|
|
395
|
+
* @returns Whether the request is fulfilled and the finalization result
|
|
396
|
+
*/
|
|
397
|
+
export async function getAsyncRequestStatus(
|
|
398
|
+
publicClient: PublicClient,
|
|
399
|
+
vault: Address,
|
|
400
|
+
guid: `0x${string}`,
|
|
401
|
+
): Promise<{ fulfilled: boolean; finalized: boolean; result: bigint }> {
|
|
402
|
+
const info = (await publicClient.readContract({
|
|
403
|
+
address: getAddress(vault),
|
|
404
|
+
abi: BRIDGE_ABI,
|
|
405
|
+
functionName: 'getRequestInfo',
|
|
406
|
+
args: [guid],
|
|
407
|
+
})) as unknown as CrossChainRequestInfo
|
|
408
|
+
|
|
409
|
+
const finalizationResult = await publicClient.readContract({
|
|
410
|
+
address: getAddress(vault),
|
|
411
|
+
abi: BRIDGE_ABI,
|
|
412
|
+
functionName: 'getFinalizationResult',
|
|
413
|
+
args: [guid],
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
return {
|
|
417
|
+
fulfilled: info.fulfilled,
|
|
418
|
+
finalized: info.finalized,
|
|
419
|
+
result: finalizationResult,
|
|
420
|
+
}
|
|
421
|
+
}
|