@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.
@@ -0,0 +1,1377 @@
1
+ import { getAddress, zeroAddress, encodeAbiParameters, pad } from 'viem';
2
+
3
+ // src/viem/abis.ts
4
+ var VAULT_ABI = [
5
+ {
6
+ type: "function",
7
+ name: "deposit",
8
+ inputs: [
9
+ { name: "assets", type: "uint256" },
10
+ { name: "receiver", type: "address" }
11
+ ],
12
+ outputs: [{ name: "shares", type: "uint256" }],
13
+ stateMutability: "nonpayable"
14
+ },
15
+ {
16
+ type: "function",
17
+ name: "deposit",
18
+ inputs: [
19
+ { name: "tokens", type: "address[]" },
20
+ { name: "assets", type: "uint256[]" },
21
+ { name: "receiver", type: "address" },
22
+ { name: "minAmountOut", type: "uint256" }
23
+ ],
24
+ outputs: [{ name: "shares", type: "uint256" }],
25
+ stateMutability: "payable"
26
+ },
27
+ {
28
+ type: "function",
29
+ name: "mint",
30
+ inputs: [
31
+ { name: "shares", type: "uint256" },
32
+ { name: "receiver", type: "address" }
33
+ ],
34
+ outputs: [{ name: "assets", type: "uint256" }],
35
+ stateMutability: "nonpayable"
36
+ },
37
+ {
38
+ type: "function",
39
+ name: "withdraw",
40
+ inputs: [
41
+ { name: "assets", type: "uint256" },
42
+ { name: "receiver", type: "address" },
43
+ { name: "owner", type: "address" }
44
+ ],
45
+ outputs: [{ name: "shares", type: "uint256" }],
46
+ stateMutability: "nonpayable"
47
+ },
48
+ {
49
+ type: "function",
50
+ name: "redeem",
51
+ inputs: [
52
+ { name: "shares", type: "uint256" },
53
+ { name: "receiver", type: "address" },
54
+ { name: "owner", type: "address" }
55
+ ],
56
+ outputs: [{ name: "assets", type: "uint256" }],
57
+ stateMutability: "nonpayable"
58
+ },
59
+ {
60
+ type: "function",
61
+ name: "requestRedeem",
62
+ inputs: [
63
+ { name: "_shares", type: "uint256" },
64
+ { name: "_onBehalfOf", type: "address" }
65
+ ],
66
+ outputs: [],
67
+ stateMutability: "nonpayable"
68
+ },
69
+ {
70
+ type: "function",
71
+ name: "requestWithdraw",
72
+ inputs: [
73
+ { name: "_assets", type: "uint256" },
74
+ { name: "_onBehalfOf", type: "address" }
75
+ ],
76
+ outputs: [],
77
+ stateMutability: "nonpayable"
78
+ },
79
+ {
80
+ type: "function",
81
+ name: "getWithdrawalRequest",
82
+ inputs: [{ name: "_owner", type: "address" }],
83
+ outputs: [
84
+ { name: "shares", type: "uint256" },
85
+ { name: "timelockEndsAt", type: "uint256" }
86
+ ],
87
+ stateMutability: "view"
88
+ },
89
+ {
90
+ type: "function",
91
+ name: "totalAssets",
92
+ inputs: [],
93
+ outputs: [{ name: "_totalAssets", type: "uint256" }],
94
+ stateMutability: "view"
95
+ },
96
+ {
97
+ type: "function",
98
+ name: "totalSupply",
99
+ inputs: [],
100
+ outputs: [{ name: "", type: "uint256" }],
101
+ stateMutability: "view"
102
+ },
103
+ {
104
+ type: "function",
105
+ name: "balanceOf",
106
+ inputs: [{ name: "account", type: "address" }],
107
+ outputs: [{ name: "", type: "uint256" }],
108
+ stateMutability: "view"
109
+ },
110
+ {
111
+ type: "function",
112
+ name: "asset",
113
+ inputs: [],
114
+ outputs: [{ name: "", type: "address" }],
115
+ stateMutability: "view"
116
+ },
117
+ {
118
+ type: "function",
119
+ name: "convertToShares",
120
+ inputs: [{ name: "assets", type: "uint256" }],
121
+ outputs: [{ name: "", type: "uint256" }],
122
+ stateMutability: "view"
123
+ },
124
+ {
125
+ type: "function",
126
+ name: "convertToAssets",
127
+ inputs: [{ name: "shares", type: "uint256" }],
128
+ outputs: [{ name: "", type: "uint256" }],
129
+ stateMutability: "view"
130
+ },
131
+ {
132
+ type: "function",
133
+ name: "previewDeposit",
134
+ inputs: [{ name: "assets", type: "uint256" }],
135
+ outputs: [{ name: "", type: "uint256" }],
136
+ stateMutability: "view"
137
+ },
138
+ {
139
+ type: "function",
140
+ name: "previewRedeem",
141
+ inputs: [{ name: "shares", type: "uint256" }],
142
+ outputs: [{ name: "", type: "uint256" }],
143
+ stateMutability: "view"
144
+ }
145
+ ];
146
+ var BRIDGE_ABI = [
147
+ {
148
+ type: "function",
149
+ name: "initVaultActionRequest",
150
+ inputs: [
151
+ { name: "actionType", type: "uint8" },
152
+ { name: "actionCallData", type: "bytes" },
153
+ { name: "amountLimit", type: "uint256" },
154
+ { name: "extraOptions", type: "bytes" }
155
+ ],
156
+ outputs: [{ name: "guid", type: "bytes32" }],
157
+ stateMutability: "payable"
158
+ },
159
+ {
160
+ type: "function",
161
+ name: "getRequestInfo",
162
+ inputs: [{ name: "guid", type: "bytes32" }],
163
+ outputs: [
164
+ {
165
+ name: "",
166
+ type: "tuple",
167
+ components: [
168
+ { name: "initiator", type: "address" },
169
+ { name: "timestamp", type: "uint64" },
170
+ { name: "actionType", type: "uint8" },
171
+ { name: "actionCallData", type: "bytes" },
172
+ { name: "fulfilled", type: "bool" },
173
+ { name: "finalized", type: "bool" },
174
+ { name: "refunded", type: "bool" },
175
+ { name: "totalAssets", type: "uint256" },
176
+ { name: "finalizationResult", type: "uint256" },
177
+ { name: "amountLimit", type: "uint256" }
178
+ ]
179
+ }
180
+ ],
181
+ stateMutability: "view"
182
+ },
183
+ {
184
+ type: "function",
185
+ name: "getFinalizationResult",
186
+ inputs: [{ name: "guid", type: "bytes32" }],
187
+ outputs: [{ name: "result", type: "uint256" }],
188
+ stateMutability: "view"
189
+ },
190
+ {
191
+ type: "function",
192
+ name: "quoteAccountingFee",
193
+ inputs: [{ name: "extraOptions", type: "bytes" }],
194
+ outputs: [{ name: "nativeFee", type: "uint256" }],
195
+ stateMutability: "view"
196
+ },
197
+ {
198
+ type: "function",
199
+ name: "oraclesCrossChainAccounting",
200
+ inputs: [],
201
+ outputs: [{ name: "", type: "bool" }],
202
+ stateMutability: "view"
203
+ }
204
+ ];
205
+ var CONFIG_ABI = [
206
+ {
207
+ type: "function",
208
+ name: "getEscrow",
209
+ inputs: [],
210
+ outputs: [{ name: "escrow", type: "address" }],
211
+ stateMutability: "view"
212
+ },
213
+ {
214
+ type: "function",
215
+ name: "getCrossChainAccountingManager",
216
+ inputs: [],
217
+ outputs: [{ name: "", type: "address" }],
218
+ stateMutability: "view"
219
+ },
220
+ {
221
+ type: "function",
222
+ name: "isHub",
223
+ inputs: [],
224
+ outputs: [{ name: "", type: "bool" }],
225
+ stateMutability: "view"
226
+ },
227
+ {
228
+ type: "function",
229
+ name: "getWithdrawalQueueStatus",
230
+ inputs: [],
231
+ outputs: [{ name: "", type: "bool" }],
232
+ stateMutability: "view"
233
+ },
234
+ {
235
+ type: "function",
236
+ name: "getWithdrawalTimelock",
237
+ inputs: [],
238
+ outputs: [{ name: "", type: "uint64" }],
239
+ stateMutability: "view"
240
+ },
241
+ {
242
+ type: "function",
243
+ name: "paused",
244
+ inputs: [],
245
+ outputs: [{ name: "", type: "bool" }],
246
+ stateMutability: "view"
247
+ },
248
+ {
249
+ type: "function",
250
+ name: "maxDeposit",
251
+ inputs: [{ name: "receiver", type: "address" }],
252
+ outputs: [{ name: "", type: "uint256" }],
253
+ stateMutability: "view"
254
+ }
255
+ ];
256
+ var ERC20_ABI = [
257
+ {
258
+ type: "function",
259
+ name: "approve",
260
+ inputs: [
261
+ { name: "spender", type: "address" },
262
+ { name: "value", type: "uint256" }
263
+ ],
264
+ outputs: [{ name: "", type: "bool" }],
265
+ stateMutability: "nonpayable"
266
+ },
267
+ {
268
+ type: "function",
269
+ name: "allowance",
270
+ inputs: [
271
+ { name: "owner", type: "address" },
272
+ { name: "spender", type: "address" }
273
+ ],
274
+ outputs: [{ name: "", type: "uint256" }],
275
+ stateMutability: "view"
276
+ },
277
+ {
278
+ type: "function",
279
+ name: "balanceOf",
280
+ inputs: [{ name: "account", type: "address" }],
281
+ outputs: [{ name: "", type: "uint256" }],
282
+ stateMutability: "view"
283
+ }
284
+ ];
285
+ var METADATA_ABI = [
286
+ { type: "function", name: "name", inputs: [], outputs: [{ name: "", type: "string" }], stateMutability: "view" },
287
+ { type: "function", name: "symbol", inputs: [], outputs: [{ name: "", type: "string" }], stateMutability: "view" },
288
+ { type: "function", name: "decimals", inputs: [], outputs: [{ name: "", type: "uint8" }], stateMutability: "view" }
289
+ ];
290
+ var OFT_ABI = [
291
+ {
292
+ type: "function",
293
+ name: "send",
294
+ inputs: [
295
+ {
296
+ name: "_sendParam",
297
+ type: "tuple",
298
+ components: [
299
+ { name: "dstEid", type: "uint32" },
300
+ { name: "to", type: "bytes32" },
301
+ { name: "amountLD", type: "uint256" },
302
+ { name: "minAmountLD", type: "uint256" },
303
+ { name: "extraOptions", type: "bytes" },
304
+ { name: "composeMsg", type: "bytes" },
305
+ { name: "oftCmd", type: "bytes" }
306
+ ]
307
+ },
308
+ {
309
+ name: "_fee",
310
+ type: "tuple",
311
+ components: [
312
+ { name: "nativeFee", type: "uint256" },
313
+ { name: "lzTokenFee", type: "uint256" }
314
+ ]
315
+ },
316
+ { name: "_refundAddress", type: "address" }
317
+ ],
318
+ outputs: [
319
+ {
320
+ name: "msgReceipt",
321
+ type: "tuple",
322
+ components: [
323
+ { name: "guid", type: "bytes32" },
324
+ { name: "nonce", type: "uint64" },
325
+ {
326
+ name: "fee",
327
+ type: "tuple",
328
+ components: [
329
+ { name: "nativeFee", type: "uint256" },
330
+ { name: "lzTokenFee", type: "uint256" }
331
+ ]
332
+ }
333
+ ]
334
+ },
335
+ {
336
+ name: "oftReceipt",
337
+ type: "tuple",
338
+ components: [
339
+ { name: "amountSentLD", type: "uint256" },
340
+ { name: "amountReceivedLD", type: "uint256" }
341
+ ]
342
+ }
343
+ ],
344
+ stateMutability: "payable"
345
+ },
346
+ {
347
+ type: "function",
348
+ name: "quoteSend",
349
+ inputs: [
350
+ {
351
+ name: "_sendParam",
352
+ type: "tuple",
353
+ components: [
354
+ { name: "dstEid", type: "uint32" },
355
+ { name: "to", type: "bytes32" },
356
+ { name: "amountLD", type: "uint256" },
357
+ { name: "minAmountLD", type: "uint256" },
358
+ { name: "extraOptions", type: "bytes" },
359
+ { name: "composeMsg", type: "bytes" },
360
+ { name: "oftCmd", type: "bytes" }
361
+ ]
362
+ },
363
+ { name: "_payInLzToken", type: "bool" }
364
+ ],
365
+ outputs: [
366
+ {
367
+ name: "msgFee",
368
+ type: "tuple",
369
+ components: [
370
+ { name: "nativeFee", type: "uint256" },
371
+ { name: "lzTokenFee", type: "uint256" }
372
+ ]
373
+ }
374
+ ],
375
+ stateMutability: "view"
376
+ }
377
+ ];
378
+
379
+ // src/viem/types.ts
380
+ var ActionType = {
381
+ DEPOSIT: 0,
382
+ MINT: 1,
383
+ WITHDRAW: 2,
384
+ REDEEM: 3,
385
+ MULTI_ASSETS_DEPOSIT: 4,
386
+ ACCRUE_FEES: 5
387
+ };
388
+
389
+ // src/viem/errors.ts
390
+ var MoreVaultsError = class extends Error {
391
+ constructor(message) {
392
+ super(message);
393
+ this.name = "MoreVaultsError";
394
+ }
395
+ };
396
+ var VaultPausedError = class extends MoreVaultsError {
397
+ constructor(vault) {
398
+ super(`[MoreVaults] Vault ${vault} is paused. Cannot perform any actions.`);
399
+ this.name = "VaultPausedError";
400
+ }
401
+ };
402
+ var CapacityFullError = class extends MoreVaultsError {
403
+ constructor(vault) {
404
+ super(`[MoreVaults] Vault ${vault} has reached deposit capacity. No more deposits accepted.`);
405
+ this.name = "CapacityFullError";
406
+ }
407
+ };
408
+ var NotWhitelistedError = class extends MoreVaultsError {
409
+ constructor(vault, user) {
410
+ super(`[MoreVaults] Address ${user} is not whitelisted to deposit in vault ${vault}.`);
411
+ this.name = "NotWhitelistedError";
412
+ }
413
+ };
414
+ var InsufficientLiquidityError = class extends MoreVaultsError {
415
+ hubLiquid;
416
+ required;
417
+ constructor(vault, hubLiquid, required) {
418
+ super(
419
+ `[MoreVaults] Insufficient hub liquidity for redeem.
420
+ Hub liquid balance : ${hubLiquid}
421
+ Estimated required : ${required}
422
+ Submitting this redeem will waste the LayerZero fee \u2014 the request will be auto-refunded.
423
+ Ask the vault curator to repatriate liquidity from spoke chains first.`
424
+ );
425
+ this.name = "InsufficientLiquidityError";
426
+ this.hubLiquid = hubLiquid;
427
+ this.required = required;
428
+ }
429
+ };
430
+ var CCManagerNotConfiguredError = class extends MoreVaultsError {
431
+ constructor(vault) {
432
+ super(`[MoreVaults] CCManager not configured on vault ${vault}. Call setCrossChainAccountingManager(ccManagerAddress) as vault owner first.`);
433
+ this.name = "CCManagerNotConfiguredError";
434
+ }
435
+ };
436
+ var EscrowNotConfiguredError = class extends MoreVaultsError {
437
+ constructor(vault) {
438
+ super(`[MoreVaults] Escrow not configured for vault ${vault}. The registry must have an escrow set for this vault.`);
439
+ this.name = "EscrowNotConfiguredError";
440
+ }
441
+ };
442
+ var NotHubVaultError = class extends MoreVaultsError {
443
+ constructor(vault) {
444
+ super(`[MoreVaults] Vault ${vault} is not a hub vault. Async flows (D4/D5/R5) only work on hub vaults.`);
445
+ this.name = "NotHubVaultError";
446
+ }
447
+ };
448
+ var MissingEscrowAddressError = class extends MoreVaultsError {
449
+ constructor() {
450
+ super(`[MoreVaults] This flow requires an escrow address. Set VaultAddresses.escrow before calling async deposit/redeem flows.`);
451
+ this.name = "MissingEscrowAddressError";
452
+ }
453
+ };
454
+ async function getVaultStatus(publicClient, vault) {
455
+ const v = getAddress(vault);
456
+ const b1 = await publicClient.multicall({
457
+ contracts: [
458
+ { address: v, abi: CONFIG_ABI, functionName: "isHub" },
459
+ { address: v, abi: CONFIG_ABI, functionName: "paused" },
460
+ { address: v, abi: BRIDGE_ABI, functionName: "oraclesCrossChainAccounting" },
461
+ { address: v, abi: CONFIG_ABI, functionName: "getCrossChainAccountingManager" },
462
+ { address: v, abi: CONFIG_ABI, functionName: "getEscrow" },
463
+ { address: v, abi: CONFIG_ABI, functionName: "getWithdrawalQueueStatus" },
464
+ { address: v, abi: CONFIG_ABI, functionName: "getWithdrawalTimelock" },
465
+ { address: v, abi: CONFIG_ABI, functionName: "maxDeposit", args: [zeroAddress] },
466
+ { address: v, abi: VAULT_ABI, functionName: "asset" },
467
+ { address: v, abi: VAULT_ABI, functionName: "totalAssets" },
468
+ { address: v, abi: VAULT_ABI, functionName: "totalSupply" },
469
+ { address: v, abi: METADATA_ABI, functionName: "decimals" }
470
+ ],
471
+ allowFailure: true
472
+ });
473
+ const isHub = b1[0].status === "success" ? b1[0].result : false;
474
+ const isPaused = b1[1].status === "success" ? b1[1].result : false;
475
+ const oraclesEnabled = b1[2].status === "success" ? b1[2].result : false;
476
+ const ccManager = b1[3].status === "success" ? b1[3].result : zeroAddress;
477
+ const escrow = b1[4].status === "success" ? b1[4].result : zeroAddress;
478
+ const withdrawalQueueEnabled = b1[5].status === "success" ? b1[5].result : false;
479
+ const withdrawalTimelockSeconds = b1[6].status === "success" ? b1[6].result : 0n;
480
+ const maxDepositRaw = b1[7].status === "success" ? b1[7].result : null;
481
+ const underlying = b1[8].status === "success" ? b1[8].result : zeroAddress;
482
+ const totalAssets = b1[9].status === "success" ? b1[9].result : 0n;
483
+ const totalSupply = b1[10].status === "success" ? b1[10].result : 0n;
484
+ const decimals = b1[11].status === "success" ? Number(b1[11].result) : 18;
485
+ const oneShare = 10n ** BigInt(decimals);
486
+ const b2 = await publicClient.multicall({
487
+ contracts: [
488
+ { address: getAddress(underlying), abi: ERC20_ABI, functionName: "balanceOf", args: [v] },
489
+ { address: v, abi: VAULT_ABI, functionName: "convertToAssets", args: [oneShare] }
490
+ ],
491
+ allowFailure: true
492
+ });
493
+ const hubLiquidBalance = b2[0].status === "success" ? b2[0].result : 0n;
494
+ const sharePrice = b2[1].status === "success" ? b2[1].result : 0n;
495
+ const spokesDeployedBalance = totalAssets > hubLiquidBalance ? totalAssets - hubLiquidBalance : 0n;
496
+ const MAX_UINT256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
497
+ const depositAccessRestricted = maxDepositRaw === null;
498
+ const effectiveCapacity = depositAccessRestricted ? MAX_UINT256 : maxDepositRaw;
499
+ let mode;
500
+ if (isPaused) {
501
+ mode = "paused";
502
+ } else if (effectiveCapacity === 0n) {
503
+ mode = "full";
504
+ } else if (!isHub) {
505
+ mode = "local";
506
+ } else if (oraclesEnabled) {
507
+ mode = "cross-chain-oracle";
508
+ } else {
509
+ mode = "cross-chain-async";
510
+ }
511
+ let recommendedDepositFlow;
512
+ let recommendedRedeemFlow;
513
+ if (mode === "paused" || mode === "full") {
514
+ recommendedDepositFlow = "none";
515
+ recommendedRedeemFlow = mode === "paused" ? "none" : "redeemShares";
516
+ } else if (mode === "cross-chain-async") {
517
+ recommendedDepositFlow = "depositAsync";
518
+ recommendedRedeemFlow = "redeemAsync";
519
+ } else {
520
+ recommendedDepositFlow = "depositSimple";
521
+ recommendedRedeemFlow = "redeemShares";
522
+ }
523
+ const maxImmediateRedeemAssets = isHub && !oraclesEnabled ? hubLiquidBalance : totalAssets;
524
+ const issues = [];
525
+ if (isPaused) {
526
+ issues.push("Vault is paused \u2014 no deposits or redeems are possible.");
527
+ }
528
+ if (effectiveCapacity === 0n && !isPaused) {
529
+ issues.push("Deposit capacity is full \u2014 increase depositCapacity via setDepositCapacity().");
530
+ }
531
+ if (depositAccessRestricted) {
532
+ issues.push("Deposit access is restricted (whitelist or other access control). Only approved addresses can deposit.");
533
+ }
534
+ if (isHub && !oraclesEnabled && ccManager === zeroAddress) {
535
+ issues.push(
536
+ "CCManager not configured \u2014 async flows will revert. Call setCrossChainAccountingManager(address) as vault owner."
537
+ );
538
+ }
539
+ if (isHub && !oraclesEnabled && escrow === zeroAddress) {
540
+ issues.push(
541
+ "Escrow not configured in registry \u2014 async flows will revert. Set the escrow via the MoreVaultsRegistry."
542
+ );
543
+ }
544
+ if (isHub) {
545
+ if (hubLiquidBalance === 0n) {
546
+ issues.push(
547
+ `Hub has no liquid assets (hubLiquidBalance = 0). All redeems will be auto-refunded until the curator repatriates funds from spokes via executeBridging().`
548
+ );
549
+ } else if (totalAssets > 0n && hubLiquidBalance * 10n < totalAssets) {
550
+ const pct = Number(hubLiquidBalance * 10000n / totalAssets) / 100;
551
+ issues.push(
552
+ `Low hub liquidity: ${hubLiquidBalance} units liquid on hub (${pct.toFixed(1)}% of TVL). Redeems above ${hubLiquidBalance} underlying units will be auto-refunded. Curator must call executeBridging() to repatriate from spokes.`
553
+ );
554
+ }
555
+ if (spokesDeployedBalance > 0n) {
556
+ const pct = (Number(spokesDeployedBalance) / Number(totalAssets || 1n) * 100).toFixed(1);
557
+ issues.push(
558
+ `${spokesDeployedBalance} units (~${pct}% of TVL) are deployed on spoke chains earning yield. These are NOT immediately redeemable \u2014 they require a curator repatriation (executeBridging) before users can withdraw them.`
559
+ );
560
+ }
561
+ }
562
+ return {
563
+ mode,
564
+ recommendedDepositFlow,
565
+ recommendedRedeemFlow,
566
+ isHub,
567
+ isPaused,
568
+ oracleAccountingEnabled: oraclesEnabled,
569
+ ccManager,
570
+ escrow,
571
+ withdrawalQueueEnabled,
572
+ withdrawalTimelockSeconds: BigInt(withdrawalTimelockSeconds),
573
+ remainingDepositCapacity: effectiveCapacity,
574
+ depositAccessRestricted,
575
+ underlying,
576
+ totalAssets,
577
+ totalSupply,
578
+ decimals,
579
+ sharePrice,
580
+ hubLiquidBalance,
581
+ spokesDeployedBalance,
582
+ maxImmediateRedeemAssets,
583
+ issues
584
+ };
585
+ }
586
+ async function ensureAllowance(walletClient, publicClient, token, spender, amount) {
587
+ const account = walletClient.account;
588
+ const allowance = await publicClient.readContract({
589
+ address: getAddress(token),
590
+ abi: ERC20_ABI,
591
+ functionName: "allowance",
592
+ args: [account.address, getAddress(spender)]
593
+ });
594
+ if (allowance < amount) {
595
+ const hash = await walletClient.writeContract({
596
+ address: getAddress(token),
597
+ abi: ERC20_ABI,
598
+ functionName: "approve",
599
+ args: [getAddress(spender), amount],
600
+ account,
601
+ chain: walletClient.chain
602
+ });
603
+ await publicClient.waitForTransactionReceipt({ hash });
604
+ }
605
+ }
606
+ async function quoteLzFee(publicClient, vault, extraOptions = "0x") {
607
+ return publicClient.readContract({
608
+ address: getAddress(vault),
609
+ abi: BRIDGE_ABI,
610
+ functionName: "quoteAccountingFee",
611
+ args: [extraOptions]
612
+ });
613
+ }
614
+ async function isAsyncMode(publicClient, vault) {
615
+ const v = getAddress(vault);
616
+ const isHub = await publicClient.readContract({
617
+ address: v,
618
+ abi: CONFIG_ABI,
619
+ functionName: "isHub"
620
+ });
621
+ if (!isHub) return false;
622
+ const oraclesEnabled = await publicClient.readContract({
623
+ address: v,
624
+ abi: BRIDGE_ABI,
625
+ functionName: "oraclesCrossChainAccounting"
626
+ });
627
+ return !oraclesEnabled;
628
+ }
629
+ async function getAsyncRequestStatus(publicClient, vault, guid) {
630
+ const info = await publicClient.readContract({
631
+ address: getAddress(vault),
632
+ abi: BRIDGE_ABI,
633
+ functionName: "getRequestInfo",
634
+ args: [guid]
635
+ });
636
+ const finalizationResult = await publicClient.readContract({
637
+ address: getAddress(vault),
638
+ abi: BRIDGE_ABI,
639
+ functionName: "getFinalizationResult",
640
+ args: [guid]
641
+ });
642
+ return {
643
+ fulfilled: info.fulfilled,
644
+ finalized: info.finalized,
645
+ result: finalizationResult
646
+ };
647
+ }
648
+ async function preflightAsync(publicClient, vault, escrow) {
649
+ const v = getAddress(vault);
650
+ const [ccManager, registeredEscrow, isHub, oraclesEnabled, isPaused] = await Promise.all([
651
+ publicClient.readContract({
652
+ address: v,
653
+ abi: CONFIG_ABI,
654
+ functionName: "getCrossChainAccountingManager"
655
+ }),
656
+ publicClient.readContract({
657
+ address: v,
658
+ abi: CONFIG_ABI,
659
+ functionName: "getEscrow"
660
+ }),
661
+ publicClient.readContract({
662
+ address: v,
663
+ abi: CONFIG_ABI,
664
+ functionName: "isHub"
665
+ }),
666
+ publicClient.readContract({
667
+ address: v,
668
+ abi: BRIDGE_ABI,
669
+ functionName: "oraclesCrossChainAccounting"
670
+ }),
671
+ publicClient.readContract({
672
+ address: v,
673
+ abi: CONFIG_ABI,
674
+ functionName: "paused"
675
+ })
676
+ ]);
677
+ if (ccManager === zeroAddress) {
678
+ throw new Error(
679
+ `[MoreVaults] CCManager not configured on vault ${vault}. Call setCrossChainAccountingManager(ccManagerAddress) as vault owner first.`
680
+ );
681
+ }
682
+ if (registeredEscrow === zeroAddress) {
683
+ throw new Error(
684
+ `[MoreVaults] Escrow not configured for vault ${vault}. The registry must have an escrow set for this vault.`
685
+ );
686
+ }
687
+ if (!isHub) {
688
+ throw new Error(
689
+ `[MoreVaults] Vault ${vault} is not a hub vault. Async flows (D4/D5/R5) only work on hub vaults.`
690
+ );
691
+ }
692
+ if (oraclesEnabled) {
693
+ throw new Error(
694
+ `[MoreVaults] Vault ${vault} has oracle-based cross-chain accounting enabled. Use depositSimple/depositCrossChainOracleOn instead of async flows.`
695
+ );
696
+ }
697
+ if (isPaused) {
698
+ throw new Error(
699
+ `[MoreVaults] Vault ${vault} is paused. Cannot perform any actions.`
700
+ );
701
+ }
702
+ }
703
+ async function preflightRedeemLiquidity(publicClient, vault, shares) {
704
+ const v = getAddress(vault);
705
+ const underlying = await publicClient.readContract({
706
+ address: v,
707
+ abi: VAULT_ABI,
708
+ functionName: "asset"
709
+ });
710
+ const [hubLiquid, assetsNeeded] = await Promise.all([
711
+ publicClient.readContract({
712
+ address: getAddress(underlying),
713
+ abi: ERC20_ABI,
714
+ functionName: "balanceOf",
715
+ args: [v]
716
+ }),
717
+ publicClient.readContract({
718
+ address: v,
719
+ abi: VAULT_ABI,
720
+ functionName: "convertToAssets",
721
+ args: [shares]
722
+ })
723
+ ]);
724
+ if (hubLiquid < assetsNeeded) {
725
+ throw new Error(
726
+ `[MoreVaults] Insufficient hub liquidity for redeem.
727
+ Hub liquid balance : ${hubLiquid}
728
+ Estimated required : ${assetsNeeded}
729
+ Submitting this redeem will waste the LayerZero fee \u2014 the request will be auto-refunded.
730
+ Ask the vault curator to repatriate liquidity from spoke chains first.`
731
+ );
732
+ }
733
+ }
734
+ async function preflightSync(publicClient, vault) {
735
+ const v = getAddress(vault);
736
+ const [isPaused, depositCapResult] = await Promise.all([
737
+ publicClient.readContract({
738
+ address: v,
739
+ abi: CONFIG_ABI,
740
+ functionName: "paused"
741
+ }),
742
+ publicClient.readContract({
743
+ address: v,
744
+ abi: CONFIG_ABI,
745
+ functionName: "maxDeposit",
746
+ args: [zeroAddress]
747
+ }).catch(() => null)
748
+ ]);
749
+ if (isPaused) {
750
+ throw new Error(
751
+ `[MoreVaults] Vault ${vault} is paused. Cannot perform any actions.`
752
+ );
753
+ }
754
+ if (depositCapResult !== null && depositCapResult === 0n) {
755
+ throw new Error(
756
+ `[MoreVaults] Vault ${vault} has reached deposit capacity. No more deposits accepted.`
757
+ );
758
+ }
759
+ }
760
+
761
+ // src/viem/depositFlows.ts
762
+ async function depositSimple(walletClient, publicClient, addresses, assets, receiver) {
763
+ const account = walletClient.account;
764
+ const vault = getAddress(addresses.vault);
765
+ await preflightSync(publicClient, vault);
766
+ const underlying = await publicClient.readContract({
767
+ address: vault,
768
+ abi: VAULT_ABI,
769
+ functionName: "asset"
770
+ });
771
+ await ensureAllowance(walletClient, publicClient, underlying, vault, assets);
772
+ const { result: shares } = await publicClient.simulateContract({
773
+ address: vault,
774
+ abi: VAULT_ABI,
775
+ functionName: "deposit",
776
+ args: [assets, getAddress(receiver)],
777
+ account: account.address
778
+ });
779
+ const txHash = await walletClient.writeContract({
780
+ address: vault,
781
+ abi: VAULT_ABI,
782
+ functionName: "deposit",
783
+ args: [assets, getAddress(receiver)],
784
+ account,
785
+ chain: walletClient.chain
786
+ });
787
+ return { txHash, shares };
788
+ }
789
+ async function depositMultiAsset(walletClient, publicClient, addresses, tokens, amounts, receiver, minShares) {
790
+ const account = walletClient.account;
791
+ const vault = getAddress(addresses.vault);
792
+ for (let i = 0; i < tokens.length; i++) {
793
+ await ensureAllowance(walletClient, publicClient, tokens[i], vault, amounts[i]);
794
+ }
795
+ const { result: shares } = await publicClient.simulateContract({
796
+ address: vault,
797
+ abi: VAULT_ABI,
798
+ functionName: "deposit",
799
+ args: [tokens, amounts, getAddress(receiver), minShares],
800
+ account: account.address
801
+ });
802
+ const txHash = await walletClient.writeContract({
803
+ address: vault,
804
+ abi: VAULT_ABI,
805
+ functionName: "deposit",
806
+ args: [tokens, amounts, getAddress(receiver), minShares],
807
+ account,
808
+ chain: walletClient.chain
809
+ });
810
+ return { txHash, shares };
811
+ }
812
+ async function depositAsync(walletClient, publicClient, addresses, assets, receiver, lzFee, extraOptions = "0x") {
813
+ const account = walletClient.account;
814
+ const vault = getAddress(addresses.vault);
815
+ if (!addresses.escrow) throw new MissingEscrowAddressError();
816
+ const escrow = getAddress(addresses.escrow);
817
+ await preflightAsync(publicClient, vault);
818
+ const underlying = await publicClient.readContract({
819
+ address: vault,
820
+ abi: VAULT_ABI,
821
+ functionName: "asset"
822
+ });
823
+ await ensureAllowance(walletClient, publicClient, underlying, escrow, assets);
824
+ const actionCallData = encodeAbiParameters(
825
+ [{ type: "uint256", name: "assets" }, { type: "address", name: "receiver" }],
826
+ [assets, getAddress(receiver)]
827
+ );
828
+ const { result: guid } = await publicClient.simulateContract({
829
+ address: vault,
830
+ abi: BRIDGE_ABI,
831
+ functionName: "initVaultActionRequest",
832
+ args: [ActionType.DEPOSIT, actionCallData, 0n, extraOptions],
833
+ value: lzFee,
834
+ account: account.address
835
+ });
836
+ const txHash = await walletClient.writeContract({
837
+ address: vault,
838
+ abi: BRIDGE_ABI,
839
+ functionName: "initVaultActionRequest",
840
+ args: [ActionType.DEPOSIT, actionCallData, 0n, extraOptions],
841
+ value: lzFee,
842
+ account,
843
+ chain: walletClient.chain
844
+ });
845
+ return { txHash, guid };
846
+ }
847
+ async function mintAsync(walletClient, publicClient, addresses, shares, maxAssets, receiver, lzFee, extraOptions = "0x") {
848
+ const account = walletClient.account;
849
+ const vault = getAddress(addresses.vault);
850
+ if (!addresses.escrow) throw new MissingEscrowAddressError();
851
+ const escrow = getAddress(addresses.escrow);
852
+ await preflightAsync(publicClient, vault);
853
+ const underlying = await publicClient.readContract({
854
+ address: vault,
855
+ abi: VAULT_ABI,
856
+ functionName: "asset"
857
+ });
858
+ await ensureAllowance(walletClient, publicClient, underlying, escrow, maxAssets);
859
+ const actionCallData = encodeAbiParameters(
860
+ [{ type: "uint256", name: "shares" }, { type: "address", name: "receiver" }],
861
+ [shares, getAddress(receiver)]
862
+ );
863
+ const { result: guid } = await publicClient.simulateContract({
864
+ address: vault,
865
+ abi: BRIDGE_ABI,
866
+ functionName: "initVaultActionRequest",
867
+ args: [ActionType.MINT, actionCallData, maxAssets, extraOptions],
868
+ value: lzFee,
869
+ account: account.address
870
+ });
871
+ const txHash = await walletClient.writeContract({
872
+ address: vault,
873
+ abi: BRIDGE_ABI,
874
+ functionName: "initVaultActionRequest",
875
+ args: [ActionType.MINT, actionCallData, maxAssets, extraOptions],
876
+ value: lzFee,
877
+ account,
878
+ chain: walletClient.chain
879
+ });
880
+ return { txHash, guid };
881
+ }
882
+ async function smartDeposit(walletClient, publicClient, addresses, assets, receiver, extraOptions = "0x") {
883
+ const vault = getAddress(addresses.vault);
884
+ const status = await getVaultStatus(publicClient, vault);
885
+ if (status.mode === "paused") {
886
+ throw new VaultPausedError(vault);
887
+ }
888
+ if (status.mode === "full") {
889
+ throw new CapacityFullError(vault);
890
+ }
891
+ if (status.recommendedDepositFlow === "depositAsync") {
892
+ const lzFee = await quoteLzFee(publicClient, vault, extraOptions);
893
+ return depositAsync(walletClient, publicClient, addresses, assets, receiver, lzFee, extraOptions);
894
+ }
895
+ return depositSimple(walletClient, publicClient, addresses, assets, receiver);
896
+ }
897
+ async function depositFromSpoke(walletClient, publicClient, spokeOFT, hubEid, spokeEid, amount, receiver, lzFee, minMsgValue = 0n, minSharesOut = 0n, minAmountLD, extraOptions = "0x") {
898
+ const account = walletClient.account;
899
+ const oft = getAddress(spokeOFT);
900
+ await ensureAllowance(walletClient, publicClient, oft, oft, amount);
901
+ const receiverBytes32 = pad(getAddress(receiver), { size: 32 });
902
+ const hopSendParam = {
903
+ dstEid: spokeEid,
904
+ to: receiverBytes32,
905
+ amountLD: 0n,
906
+ minAmountLD: minSharesOut,
907
+ extraOptions: "0x",
908
+ composeMsg: "0x",
909
+ oftCmd: "0x"
910
+ };
911
+ const composeMsgBytes = encodeAbiParameters(
912
+ [
913
+ {
914
+ type: "tuple",
915
+ name: "hopSendParam",
916
+ components: [
917
+ { type: "uint32", name: "dstEid" },
918
+ { type: "bytes32", name: "to" },
919
+ { type: "uint256", name: "amountLD" },
920
+ { type: "uint256", name: "minAmountLD" },
921
+ { type: "bytes", name: "extraOptions" },
922
+ { type: "bytes", name: "composeMsg" },
923
+ { type: "bytes", name: "oftCmd" }
924
+ ]
925
+ },
926
+ { type: "uint256", name: "minMsgValue" }
927
+ ],
928
+ [hopSendParam, minMsgValue]
929
+ );
930
+ const sendParam = {
931
+ dstEid: hubEid,
932
+ to: receiverBytes32,
933
+ amountLD: amount,
934
+ minAmountLD: minAmountLD ?? amount,
935
+ extraOptions,
936
+ composeMsg: composeMsgBytes,
937
+ oftCmd: "0x"
938
+ };
939
+ const fee = {
940
+ nativeFee: lzFee,
941
+ lzTokenFee: 0n
942
+ };
943
+ const txHash = await walletClient.writeContract({
944
+ address: oft,
945
+ abi: OFT_ABI,
946
+ functionName: "send",
947
+ args: [sendParam, fee, account.address],
948
+ value: lzFee,
949
+ account,
950
+ chain: walletClient.chain
951
+ });
952
+ return { txHash };
953
+ }
954
+ async function quoteDepositFromSpokeFee(publicClient, spokeOFT, hubEid, spokeEid, amount, receiver, minMsgValue = 0n, minSharesOut = 0n, minAmountLD, extraOptions = "0x") {
955
+ const oft = getAddress(spokeOFT);
956
+ const receiverBytes32 = pad(getAddress(receiver), { size: 32 });
957
+ const hopSendParam = {
958
+ dstEid: spokeEid,
959
+ to: receiverBytes32,
960
+ amountLD: 0n,
961
+ minAmountLD: minSharesOut,
962
+ extraOptions: "0x",
963
+ composeMsg: "0x",
964
+ oftCmd: "0x"
965
+ };
966
+ const composeMsgBytes = encodeAbiParameters(
967
+ [
968
+ {
969
+ type: "tuple",
970
+ name: "hopSendParam",
971
+ components: [
972
+ { type: "uint32", name: "dstEid" },
973
+ { type: "bytes32", name: "to" },
974
+ { type: "uint256", name: "amountLD" },
975
+ { type: "uint256", name: "minAmountLD" },
976
+ { type: "bytes", name: "extraOptions" },
977
+ { type: "bytes", name: "composeMsg" },
978
+ { type: "bytes", name: "oftCmd" }
979
+ ]
980
+ },
981
+ { type: "uint256", name: "minMsgValue" }
982
+ ],
983
+ [hopSendParam, minMsgValue]
984
+ );
985
+ const sendParam = {
986
+ dstEid: hubEid,
987
+ to: receiverBytes32,
988
+ amountLD: amount,
989
+ minAmountLD: minAmountLD ?? amount,
990
+ extraOptions,
991
+ composeMsg: composeMsgBytes,
992
+ oftCmd: "0x"
993
+ };
994
+ const fee = await publicClient.readContract({
995
+ address: oft,
996
+ abi: OFT_ABI,
997
+ functionName: "quoteSend",
998
+ args: [sendParam, false]
999
+ });
1000
+ return fee.nativeFee;
1001
+ }
1002
+ async function redeemShares(walletClient, publicClient, addresses, shares, receiver, owner) {
1003
+ const account = walletClient.account;
1004
+ const vault = getAddress(addresses.vault);
1005
+ const { result: assets } = await publicClient.simulateContract({
1006
+ address: vault,
1007
+ abi: VAULT_ABI,
1008
+ functionName: "redeem",
1009
+ args: [shares, getAddress(receiver), getAddress(owner)],
1010
+ account: account.address
1011
+ });
1012
+ const txHash = await walletClient.writeContract({
1013
+ address: vault,
1014
+ abi: VAULT_ABI,
1015
+ functionName: "redeem",
1016
+ args: [shares, getAddress(receiver), getAddress(owner)],
1017
+ account,
1018
+ chain: walletClient.chain
1019
+ });
1020
+ return { txHash, assets };
1021
+ }
1022
+ async function withdrawAssets(walletClient, publicClient, addresses, assets, receiver, owner) {
1023
+ const account = walletClient.account;
1024
+ const vault = getAddress(addresses.vault);
1025
+ const { result: sharesBurned } = await publicClient.simulateContract({
1026
+ address: vault,
1027
+ abi: VAULT_ABI,
1028
+ functionName: "withdraw",
1029
+ args: [assets, getAddress(receiver), getAddress(owner)],
1030
+ account: account.address
1031
+ });
1032
+ const txHash = await walletClient.writeContract({
1033
+ address: vault,
1034
+ abi: VAULT_ABI,
1035
+ functionName: "withdraw",
1036
+ args: [assets, getAddress(receiver), getAddress(owner)],
1037
+ account,
1038
+ chain: walletClient.chain
1039
+ });
1040
+ return { txHash, assets };
1041
+ }
1042
+ async function requestRedeem(walletClient, publicClient, addresses, shares, owner) {
1043
+ const account = walletClient.account;
1044
+ const vault = getAddress(addresses.vault);
1045
+ await publicClient.simulateContract({
1046
+ address: vault,
1047
+ abi: VAULT_ABI,
1048
+ functionName: "requestRedeem",
1049
+ args: [shares, getAddress(owner)],
1050
+ account: account.address
1051
+ });
1052
+ const txHash = await walletClient.writeContract({
1053
+ address: vault,
1054
+ abi: VAULT_ABI,
1055
+ functionName: "requestRedeem",
1056
+ args: [shares, getAddress(owner)],
1057
+ account,
1058
+ chain: walletClient.chain
1059
+ });
1060
+ return { txHash };
1061
+ }
1062
+ async function getWithdrawalRequest(publicClient, vault, owner) {
1063
+ const [shares, timelockEndsAt] = await publicClient.readContract({
1064
+ address: getAddress(vault),
1065
+ abi: VAULT_ABI,
1066
+ functionName: "getWithdrawalRequest",
1067
+ args: [getAddress(owner)]
1068
+ });
1069
+ if (shares === 0n) return null;
1070
+ return { shares, timelockEndsAt };
1071
+ }
1072
+ async function redeemAsync(walletClient, publicClient, addresses, shares, receiver, owner, lzFee, extraOptions = "0x") {
1073
+ const account = walletClient.account;
1074
+ const vault = getAddress(addresses.vault);
1075
+ if (!addresses.escrow) throw new MissingEscrowAddressError();
1076
+ const escrow = getAddress(addresses.escrow);
1077
+ await preflightAsync(publicClient, vault);
1078
+ await preflightRedeemLiquidity(publicClient, vault, shares);
1079
+ await ensureAllowance(walletClient, publicClient, vault, escrow, shares);
1080
+ const actionCallData = encodeAbiParameters(
1081
+ [{ type: "uint256", name: "shares" }, { type: "address", name: "receiver" }, { type: "address", name: "owner" }],
1082
+ [shares, getAddress(receiver), getAddress(owner)]
1083
+ );
1084
+ const { result: guid } = await publicClient.simulateContract({
1085
+ address: vault,
1086
+ abi: BRIDGE_ABI,
1087
+ functionName: "initVaultActionRequest",
1088
+ args: [ActionType.REDEEM, actionCallData, 0n, extraOptions],
1089
+ value: lzFee,
1090
+ account: account.address
1091
+ });
1092
+ const txHash = await walletClient.writeContract({
1093
+ address: vault,
1094
+ abi: BRIDGE_ABI,
1095
+ functionName: "initVaultActionRequest",
1096
+ args: [ActionType.REDEEM, actionCallData, 0n, extraOptions],
1097
+ value: lzFee,
1098
+ account,
1099
+ chain: walletClient.chain
1100
+ });
1101
+ return { txHash, guid };
1102
+ }
1103
+ async function bridgeSharesToHub(walletClient, publicClient, shareOFT, hubChainEid, shares, receiver, lzFee) {
1104
+ const account = walletClient.account;
1105
+ const oft = getAddress(shareOFT);
1106
+ await ensureAllowance(walletClient, publicClient, oft, oft, shares);
1107
+ const toBytes32 = pad(getAddress(receiver), { size: 32 });
1108
+ const sendParam = {
1109
+ dstEid: hubChainEid,
1110
+ to: toBytes32,
1111
+ amountLD: shares,
1112
+ minAmountLD: shares,
1113
+ // shares should bridge 1:1
1114
+ extraOptions: "0x",
1115
+ composeMsg: "0x",
1116
+ oftCmd: "0x"
1117
+ };
1118
+ const fee = {
1119
+ nativeFee: lzFee,
1120
+ lzTokenFee: 0n
1121
+ };
1122
+ const txHash = await walletClient.writeContract({
1123
+ address: oft,
1124
+ abi: OFT_ABI,
1125
+ functionName: "send",
1126
+ args: [sendParam, fee, account.address],
1127
+ value: lzFee,
1128
+ account,
1129
+ chain: walletClient.chain
1130
+ });
1131
+ return { txHash };
1132
+ }
1133
+ async function getUserPosition(publicClient, vault, user) {
1134
+ const v = getAddress(vault);
1135
+ const u = getAddress(user);
1136
+ const [sharesResult, decimalsResult, withdrawalRequestResult] = await publicClient.multicall({
1137
+ contracts: [
1138
+ { address: v, abi: VAULT_ABI, functionName: "balanceOf", args: [u] },
1139
+ { address: v, abi: METADATA_ABI, functionName: "decimals" },
1140
+ { address: v, abi: VAULT_ABI, functionName: "getWithdrawalRequest", args: [u] }
1141
+ ],
1142
+ allowFailure: false
1143
+ });
1144
+ const block = await publicClient.getBlock();
1145
+ const shares = sharesResult;
1146
+ const decimals = decimalsResult;
1147
+ const withdrawalRequest = withdrawalRequestResult;
1148
+ const [withdrawShares, timelockEndsAt] = withdrawalRequest;
1149
+ const oneShare = 10n ** BigInt(decimals);
1150
+ const [estimatedAssets, sharePrice] = await Promise.all([
1151
+ shares === 0n ? Promise.resolve(0n) : publicClient.readContract({ address: v, abi: VAULT_ABI, functionName: "convertToAssets", args: [shares] }),
1152
+ publicClient.readContract({ address: v, abi: VAULT_ABI, functionName: "convertToAssets", args: [oneShare] })
1153
+ ]);
1154
+ const currentTimestamp = block.timestamp;
1155
+ const pendingWithdrawal = withdrawShares === 0n ? null : {
1156
+ shares: withdrawShares,
1157
+ timelockEndsAt,
1158
+ canRedeemNow: timelockEndsAt === 0n || currentTimestamp >= timelockEndsAt
1159
+ };
1160
+ return {
1161
+ shares,
1162
+ estimatedAssets,
1163
+ sharePrice,
1164
+ decimals,
1165
+ pendingWithdrawal
1166
+ };
1167
+ }
1168
+ async function previewDeposit(publicClient, vault, assets) {
1169
+ return publicClient.readContract({
1170
+ address: getAddress(vault),
1171
+ abi: VAULT_ABI,
1172
+ functionName: "previewDeposit",
1173
+ args: [assets]
1174
+ });
1175
+ }
1176
+ async function previewRedeem(publicClient, vault, shares) {
1177
+ return publicClient.readContract({
1178
+ address: getAddress(vault),
1179
+ abi: VAULT_ABI,
1180
+ functionName: "previewRedeem",
1181
+ args: [shares]
1182
+ });
1183
+ }
1184
+ async function canDeposit(publicClient, vault, user) {
1185
+ const v = getAddress(vault);
1186
+ const isPaused = await publicClient.readContract({
1187
+ address: v,
1188
+ abi: CONFIG_ABI,
1189
+ functionName: "paused"
1190
+ });
1191
+ if (isPaused) {
1192
+ return { allowed: false, reason: "paused" };
1193
+ }
1194
+ let maxDepositAmount;
1195
+ try {
1196
+ maxDepositAmount = await publicClient.readContract({
1197
+ address: v,
1198
+ abi: CONFIG_ABI,
1199
+ functionName: "maxDeposit",
1200
+ args: [getAddress(user)]
1201
+ });
1202
+ } catch {
1203
+ return { allowed: false, reason: "not-whitelisted" };
1204
+ }
1205
+ if (maxDepositAmount === 0n) {
1206
+ return { allowed: false, reason: "capacity-full" };
1207
+ }
1208
+ return { allowed: true, reason: "ok" };
1209
+ }
1210
+ async function getVaultMetadata(publicClient, vault) {
1211
+ const v = getAddress(vault);
1212
+ const b1 = await publicClient.multicall({
1213
+ contracts: [
1214
+ { address: v, abi: METADATA_ABI, functionName: "name" },
1215
+ { address: v, abi: METADATA_ABI, functionName: "symbol" },
1216
+ { address: v, abi: METADATA_ABI, functionName: "decimals" },
1217
+ { address: v, abi: VAULT_ABI, functionName: "asset" }
1218
+ ],
1219
+ allowFailure: false
1220
+ });
1221
+ const [name, symbol, decimals, underlying] = b1;
1222
+ const underlyingAddr = getAddress(underlying);
1223
+ const b2 = await publicClient.multicall({
1224
+ contracts: [
1225
+ { address: underlyingAddr, abi: METADATA_ABI, functionName: "symbol" },
1226
+ { address: underlyingAddr, abi: METADATA_ABI, functionName: "decimals" }
1227
+ ],
1228
+ allowFailure: false
1229
+ });
1230
+ const [underlyingSymbol, underlyingDecimals] = b2;
1231
+ return {
1232
+ name,
1233
+ symbol,
1234
+ decimals,
1235
+ underlying: underlyingAddr,
1236
+ underlyingSymbol,
1237
+ underlyingDecimals
1238
+ };
1239
+ }
1240
+ async function getAsyncRequestStatusLabel(publicClient, vault, guid) {
1241
+ const v = getAddress(vault);
1242
+ const [info, finalizationResult] = await Promise.all([
1243
+ publicClient.readContract({
1244
+ address: v,
1245
+ abi: BRIDGE_ABI,
1246
+ functionName: "getRequestInfo",
1247
+ args: [guid]
1248
+ }),
1249
+ publicClient.readContract({
1250
+ address: v,
1251
+ abi: BRIDGE_ABI,
1252
+ functionName: "getFinalizationResult",
1253
+ args: [guid]
1254
+ })
1255
+ ]);
1256
+ if (info.refunded) {
1257
+ return {
1258
+ status: "refunded",
1259
+ label: "Request refunded \u2014 tokens returned to initiator",
1260
+ result: 0n
1261
+ };
1262
+ }
1263
+ if (info.finalized) {
1264
+ return {
1265
+ status: "completed",
1266
+ label: "Completed",
1267
+ result: finalizationResult
1268
+ };
1269
+ }
1270
+ if (info.fulfilled) {
1271
+ return {
1272
+ status: "ready-to-execute",
1273
+ label: "Oracle responded \u2014 ready to execute",
1274
+ result: 0n
1275
+ };
1276
+ }
1277
+ return {
1278
+ status: "pending",
1279
+ label: "Waiting for cross-chain oracle response...",
1280
+ result: 0n
1281
+ };
1282
+ }
1283
+ async function getUserBalances(publicClient, vault, user) {
1284
+ const v = getAddress(vault);
1285
+ const u = getAddress(user);
1286
+ const [shareBalance, , underlying] = await publicClient.multicall({
1287
+ contracts: [
1288
+ { address: v, abi: VAULT_ABI, functionName: "balanceOf", args: [u] },
1289
+ { address: v, abi: METADATA_ABI, functionName: "decimals" },
1290
+ { address: v, abi: VAULT_ABI, functionName: "asset" }
1291
+ ],
1292
+ allowFailure: false
1293
+ });
1294
+ const underlyingAddr = getAddress(underlying);
1295
+ const [underlyingBalance, estimatedAssets] = await Promise.all([
1296
+ publicClient.readContract({
1297
+ address: underlyingAddr,
1298
+ abi: ERC20_ABI,
1299
+ functionName: "balanceOf",
1300
+ args: [u]
1301
+ }),
1302
+ shareBalance === 0n ? Promise.resolve(0n) : publicClient.readContract({
1303
+ address: v,
1304
+ abi: VAULT_ABI,
1305
+ functionName: "convertToAssets",
1306
+ args: [shareBalance]
1307
+ })
1308
+ ]);
1309
+ return {
1310
+ shareBalance,
1311
+ underlyingBalance,
1312
+ estimatedAssets
1313
+ };
1314
+ }
1315
+ async function getMaxWithdrawable(publicClient, vault, user) {
1316
+ const v = getAddress(vault);
1317
+ const u = getAddress(user);
1318
+ const [isHub, oraclesEnabled, userShares, underlying] = await publicClient.multicall({
1319
+ contracts: [
1320
+ { address: v, abi: CONFIG_ABI, functionName: "isHub" },
1321
+ { address: v, abi: BRIDGE_ABI, functionName: "oraclesCrossChainAccounting" },
1322
+ { address: v, abi: VAULT_ABI, functionName: "balanceOf", args: [u] },
1323
+ { address: v, abi: VAULT_ABI, functionName: "asset" }
1324
+ ],
1325
+ allowFailure: false
1326
+ });
1327
+ if (userShares === 0n) {
1328
+ return { shares: 0n, assets: 0n };
1329
+ }
1330
+ const underlyingAddr = getAddress(underlying);
1331
+ const [estimatedAssets, hubLiquidBalance] = await Promise.all([
1332
+ publicClient.readContract({
1333
+ address: v,
1334
+ abi: VAULT_ABI,
1335
+ functionName: "convertToAssets",
1336
+ args: [userShares]
1337
+ }),
1338
+ publicClient.readContract({
1339
+ address: underlyingAddr,
1340
+ abi: ERC20_ABI,
1341
+ functionName: "balanceOf",
1342
+ args: [v]
1343
+ })
1344
+ ]);
1345
+ let maxAssets;
1346
+ if (isHub && !oraclesEnabled) {
1347
+ maxAssets = estimatedAssets < hubLiquidBalance ? estimatedAssets : hubLiquidBalance;
1348
+ } else {
1349
+ maxAssets = estimatedAssets;
1350
+ }
1351
+ let maxShares;
1352
+ if (maxAssets < estimatedAssets) {
1353
+ maxShares = await publicClient.readContract({
1354
+ address: v,
1355
+ abi: VAULT_ABI,
1356
+ functionName: "convertToShares",
1357
+ args: [maxAssets]
1358
+ });
1359
+ } else {
1360
+ maxShares = userShares;
1361
+ }
1362
+ return {
1363
+ shares: maxShares,
1364
+ assets: maxAssets
1365
+ };
1366
+ }
1367
+ async function getVaultSummary(publicClient, vault) {
1368
+ const [status, metadata] = await Promise.all([
1369
+ getVaultStatus(publicClient, vault),
1370
+ getVaultMetadata(publicClient, vault)
1371
+ ]);
1372
+ return { ...status, ...metadata };
1373
+ }
1374
+
1375
+ export { ActionType, BRIDGE_ABI, CCManagerNotConfiguredError, CONFIG_ABI, CapacityFullError, ERC20_ABI, EscrowNotConfiguredError, InsufficientLiquidityError, METADATA_ABI, MissingEscrowAddressError, MoreVaultsError, NotHubVaultError, NotWhitelistedError, OFT_ABI, VAULT_ABI, VaultPausedError, bridgeSharesToHub, canDeposit, depositAsync, depositSimple as depositCrossChainOracleOn, depositFromSpoke, depositFromSpoke as depositFromSpokeAsync, depositMultiAsset, depositSimple, ensureAllowance, getAsyncRequestStatus, getAsyncRequestStatusLabel, getMaxWithdrawable, getUserBalances, getUserPosition, getVaultMetadata, getVaultStatus, getVaultSummary, getWithdrawalRequest, isAsyncMode, mintAsync, preflightAsync, preflightRedeemLiquidity, preflightSync, previewDeposit, previewRedeem, quoteDepositFromSpokeFee, quoteLzFee, redeemAsync, redeemShares, requestRedeem, smartDeposit, withdrawAssets };
1376
+ //# sourceMappingURL=index.js.map
1377
+ //# sourceMappingURL=index.js.map