@augustdigital/sdk 8.11.0 → 8.12.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.
@@ -36,6 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.getSwapRouterDepositResult = void 0;
39
40
  exports.getVault = getVault;
40
41
  exports.getVaultLoans = getVaultLoans;
41
42
  exports.getVaultSubaccountLoans = getVaultSubaccountLoans;
@@ -548,7 +549,7 @@ async function getVaultAllocations(vault, options) {
548
549
  unfilteredTokens: unfilteredTokens,
549
550
  };
550
551
  }
551
- async function getVaultAvailableRedemptions({ vault, wallet, options, }) {
552
+ async function getVaultAvailableRedemptions({ vault, wallet, options, prefetchedReads, }) {
552
553
  try {
553
554
  // Stellar vaults don't support on-chain redemptions yet
554
555
  if ((0, utils_3.isStellarAddress)(vault)) {
@@ -592,8 +593,9 @@ async function getVaultAvailableRedemptions({ vault, wallet, options, }) {
592
593
  else {
593
594
  decimals = await (0, core_1.getDecimals)(provider, vault);
594
595
  }
595
- const ld = await vaultContract.lagDuration();
596
- const lagDuration = Number(ld);
596
+ const lagDuration = typeof prefetchedReads?.lagDuration === 'number'
597
+ ? prefetchedReads.lagDuration
598
+ : Number(await vaultContract.lagDuration());
597
599
  const { withdrawalRequesteds, withdrawalProcesseds } = await (0, subgraph_1.getSubgraphAllWithdrawals)(vault, provider);
598
600
  // format
599
601
  const availableRedemptions = [];
@@ -991,10 +993,15 @@ async function getVaultRedemptionHistory({ vault, wallet, lookbackBlocks, option
991
993
  throw e;
992
994
  }
993
995
  }
996
+ // Moved to core/helpers/swap-router.ts to break the adapters/evm ↔
997
+ // modules/vaults/getters import cycle (CLAUDE.md §9); re-exported here for
998
+ // back-compat with existing importers.
999
+ var swap_router_1 = require("../../core/helpers/swap-router");
1000
+ Object.defineProperty(exports, "getSwapRouterDepositResult", { enumerable: true, get: function () { return swap_router_1.getSwapRouterDepositResult; } });
994
1001
  /**
995
1002
  * Vault Positions
996
1003
  */
997
- async function getVaultPositions({ vault, wallet, solanaWallet, stellarWallet, options, }) {
1004
+ async function getVaultPositions({ vault, wallet, solanaWallet, stellarWallet, options, prefetchedReads, }) {
998
1005
  try {
999
1006
  const tokenizedVaults = await (0, core_1.fetchTokenizedVault)(vault ? vault : undefined, options?.headers, false, false);
1000
1007
  if (!tokenizedVaults || tokenizedVaults.length === 0) {
@@ -1100,24 +1107,37 @@ async function getVaultPositions({ vault, wallet, solanaWallet, stellarWallet, o
1100
1107
  abi: abis_1.ABI_LENDING_POOL_V2,
1101
1108
  address: v.address,
1102
1109
  });
1110
+ // Batched reads only apply to the vault this call was made for —
1111
+ // guard against a multi-row backend response reusing them.
1112
+ const prefetched = v.address?.toLowerCase?.() === String(vault).toLowerCase()
1113
+ ? prefetchedReads
1114
+ : undefined;
1103
1115
  // get vault metadata and balance based on version
1104
1116
  let bal = BigInt(0);
1105
1117
  if (version === 'evm-2') {
1106
1118
  const receiptAddress = await (0, core_1.getReceiptTokenAddress)(provider, vault);
1107
1119
  decimals = await (0, core_1.getDecimals)(provider, receiptAddress, false);
1108
1120
  if (wallet && (0, ethers_1.isAddress)(wallet)) {
1109
- const receiptContract = (0, core_1.createContract)({
1110
- provider,
1111
- abi: TokenizedVaultV2Receipt_1.ABI_TOKENIZED_VAULT_V2_RECEIPT,
1112
- address: receiptAddress,
1113
- });
1114
- bal = await receiptContract.balanceOf(wallet);
1121
+ if (typeof prefetched?.balance === 'bigint') {
1122
+ bal = prefetched.balance;
1123
+ }
1124
+ else {
1125
+ const receiptContract = (0, core_1.createContract)({
1126
+ provider,
1127
+ abi: TokenizedVaultV2Receipt_1.ABI_TOKENIZED_VAULT_V2_RECEIPT,
1128
+ address: receiptAddress,
1129
+ });
1130
+ bal = await receiptContract.balanceOf(wallet);
1131
+ }
1115
1132
  }
1116
1133
  }
1117
1134
  else {
1118
1135
  decimals = await (0, core_1.getDecimals)(provider, vault);
1119
1136
  if (wallet && (0, ethers_1.isAddress)(wallet)) {
1120
- bal = await vaultContract.balanceOf(wallet);
1137
+ bal =
1138
+ typeof prefetched?.balance === 'bigint'
1139
+ ? prefetched.balance
1140
+ : await vaultContract.balanceOf(wallet);
1121
1141
  }
1122
1142
  }
1123
1143
  const balance = (0, core_1.toNormalizedBn)(bal, decimals);
@@ -1126,6 +1146,7 @@ async function getVaultPositions({ vault, wallet, solanaWallet, stellarWallet, o
1126
1146
  vault: v.address,
1127
1147
  wallet,
1128
1148
  options,
1149
+ prefetchedReads: prefetched,
1129
1150
  });
1130
1151
  // get aggregate redemption amount
1131
1152
  const aggregateAvailableRedemptions = availableRedemptions.reduce((acc, curr) => acc + BigInt(curr.amount.raw), BigInt(0));
@@ -1859,6 +1880,15 @@ async function getVaultUserLifetimePnl({ vault, wallet, options, }) {
1859
1880
  if (!tokenizedVault) {
1860
1881
  throw new Error(`Vault ${vault} not found`);
1861
1882
  }
1883
+ // getDecimals resolves to `undefined` on a failed/absent decimals() read.
1884
+ // Unguarded, that undefined flows into `10 ** decimals` (=> NaN) and
1885
+ // toNormalizedBn(x, undefined), and the first BigInt(NaN) throws the opaque
1886
+ // "The number NaN cannot be converted to a BigInt" error. Decimals must come
1887
+ // from the chain — never assume a fallback — so fail fast with actionable
1888
+ // context. Transient RPC blips recover on the caller's retry.
1889
+ if (typeof decimals !== 'number' || !Number.isFinite(decimals)) {
1890
+ throw new Error(`Failed to resolve decimals for vault ${vault}`);
1891
+ }
1862
1892
  // Fetch LayerZero deposits/redeems for supported vaults
1863
1893
  const lzVaultKey = (0, deposits_1.isLayerZeroVault)(vault);
1864
1894
  let lzDeposits = [];
@@ -50,6 +50,17 @@ export declare class AugustVaults extends AugustBase {
50
50
  * Includes closed vaults that are still visible (`status: 'closed'`,
51
51
  * `is_visible: true`) so consumers can render positions held in closed
52
52
  * vaults; closed vaults with `is_visible: false` are excluded.
53
+ *
54
+ * RPC volume (worst case, wallet enrichment path): the per-vault
55
+ * `balanceOf`/`lagDuration` reads are aggregated into chunked Multicall3
56
+ * `aggregate3` batches per chain (10 calls per chunk) on chains where the
57
+ * canonical Multicall3 deployment is verified; other chains (e.g. Citrea
58
+ * 4114) keep one `eth_call` per read. Measured with
59
+ * `benchmarks/request-counter.js` on a cold cache for a wallet with 62
60
+ * vaults across Ethereum + Avalanche: 83 RPC HTTP requests before batching,
61
+ * 54 after (~35% fewer; 124 per-vault `eth_call`s collapse into ~13
62
+ * `aggregate3` calls — the remaining requests are the per-vault cached
63
+ * decimals/receipt-token reads on a cold cache).
53
64
  * @param options Filtering and enrichment configuration
54
65
  * @returns Array of vault objects with optional loans/allocations/positions
55
66
  */
@@ -202,7 +213,18 @@ export declare class AugustVaults extends AugustBase {
202
213
  lookbackBlocks?: number;
203
214
  }): Promise<import("../../types").IVaultRedemptionHistoryItem[]>;
204
215
  /**
216
+ * Fetch the wallet's positions across vaults — a single vault, one chain,
217
+ * or every chain with a configured provider.
205
218
  *
219
+ * RPC volume (worst case, multi-vault paths): the two non-cacheable
220
+ * per-vault reads (`balanceOf`, `lagDuration`) are aggregated into chunked
221
+ * Multicall3 `aggregate3` batches per chain (10 calls per chunk) on chains
222
+ * where the canonical deployment is verified; unverified chains (e.g.
223
+ * Citrea 4114) and non-EVM vaults keep one `eth_call` per read. Measured
224
+ * with `benchmarks/request-counter.js` on a cold cache for a wallet with 62
225
+ * vaults across Ethereum + Avalanche: 83 RPC HTTP requests before batching,
226
+ * 54 after (~35% fewer). A vault whose batched read fails (e.g. paused)
227
+ * falls back to its own per-vault reads — never to a zeroed balance.
206
228
  */
207
229
  getVaultPositions({ vault, wallet, chainId, showAllVaults, solanaWallet, stellarWallet, options, }: {
208
230
  vault?: IAddress;
@@ -66,6 +66,7 @@ const constants_1 = require("../../adapters/sui/constants");
66
66
  const vaults_2 = require("../../core/constants/vaults");
67
67
  const write_actions_1 = require("./write.actions");
68
68
  const read_actions_1 = require("./read.actions");
69
+ const prefetch_1 = require("./prefetch");
69
70
  /**
70
71
  * Vault operations class handling multi-chain vault queries and user positions.
71
72
  * Supports both EVM and Solana vaults with unified interface.
@@ -120,6 +121,17 @@ class AugustVaults extends core_1.AugustBase {
120
121
  * Includes closed vaults that are still visible (`status: 'closed'`,
121
122
  * `is_visible: true`) so consumers can render positions held in closed
122
123
  * vaults; closed vaults with `is_visible: false` are excluded.
124
+ *
125
+ * RPC volume (worst case, wallet enrichment path): the per-vault
126
+ * `balanceOf`/`lagDuration` reads are aggregated into chunked Multicall3
127
+ * `aggregate3` batches per chain (10 calls per chunk) on chains where the
128
+ * canonical Multicall3 deployment is verified; other chains (e.g. Citrea
129
+ * 4114) keep one `eth_call` per read. Measured with
130
+ * `benchmarks/request-counter.js` on a cold cache for a wallet with 62
131
+ * vaults across Ethereum + Avalanche: 83 RPC HTTP requests before batching,
132
+ * 54 after (~35% fewer; 124 per-vault `eth_call`s collapse into ~13
133
+ * `aggregate3` calls — the remaining requests are the per-vault cached
134
+ * decimals/receipt-token reads on a cold cache).
123
135
  * @param options Filtering and enrichment configuration
124
136
  * @returns Array of vault objects with optional loans/allocations/positions
125
137
  */
@@ -248,6 +260,14 @@ class AugustVaults extends core_1.AugustBase {
248
260
  if ((options.wallet && (0, ethers_1.isAddress)(options.wallet)) ||
249
261
  (options.solanaWallet &&
250
262
  utils_1.SolanaUtils.isSolanaAddress(options.solanaWallet))) {
263
+ // Batch the per-vault balanceOf/lagDuration reads (Multicall3, grouped
264
+ // by chain) before fanning out — vaults the batch couldn't serve fall
265
+ // back to their own reads inside getVaultPositions.
266
+ const prefetchedReads = await (0, prefetch_1.prefetchVaultPositionReads)({
267
+ vaults: vaultsPerAvailableProviders,
268
+ wallet: options.wallet,
269
+ providers: this.providers,
270
+ });
251
271
  // fetch all positions for user wallet
252
272
  const vaultResponses = await (0, core_1.promiseSettle)(vaultsPerAvailableProviders.map((v) => (0, getters_1.getVaultPositions)({
253
273
  vault: v.address,
@@ -262,6 +282,7 @@ class AugustVaults extends core_1.AugustBase {
262
282
  augustKey: this.keys?.august,
263
283
  subgraphKey: this.keys?.graph,
264
284
  },
285
+ prefetchedReads: prefetchedReads.get(String(v.address).toLowerCase()),
265
286
  })), 5, // 5 retries
266
287
  2000);
267
288
  // return vault object with position property
@@ -609,7 +630,18 @@ class AugustVaults extends core_1.AugustBase {
609
630
  });
610
631
  }
611
632
  /**
633
+ * Fetch the wallet's positions across vaults — a single vault, one chain,
634
+ * or every chain with a configured provider.
612
635
  *
636
+ * RPC volume (worst case, multi-vault paths): the two non-cacheable
637
+ * per-vault reads (`balanceOf`, `lagDuration`) are aggregated into chunked
638
+ * Multicall3 `aggregate3` batches per chain (10 calls per chunk) on chains
639
+ * where the canonical deployment is verified; unverified chains (e.g.
640
+ * Citrea 4114) and non-EVM vaults keep one `eth_call` per read. Measured
641
+ * with `benchmarks/request-counter.js` on a cold cache for a wallet with 62
642
+ * vaults across Ethereum + Avalanche: 83 RPC HTTP requests before batching,
643
+ * 54 after (~35% fewer). A vault whose batched read fails (e.g. paused)
644
+ * falls back to its own per-vault reads — never to a zeroed balance.
613
645
  */
614
646
  async getVaultPositions({ vault, wallet, chainId, showAllVaults, solanaWallet, stellarWallet, options, }) {
615
647
  // if (!this.authorized) throw new Error('Not authorized.');
@@ -646,6 +678,13 @@ class AugustVaults extends core_1.AugustBase {
646
678
  const allVaults = await (0, core_1.fetchTokenizedVaults)(undefined, this.headers, false, false);
647
679
  if (chainId) {
648
680
  const vaultsPerChain = allVaults.filter((v) => v.chain === chainId);
681
+ // Batch balanceOf/lagDuration via Multicall3 before the per-vault
682
+ // fan-out; un-batched vaults fall back to their own reads.
683
+ const prefetchedReads = await (0, prefetch_1.prefetchVaultPositionReads)({
684
+ vaults: vaultsPerChain,
685
+ wallet,
686
+ providers: this.providers,
687
+ });
649
688
  const vaultResponses = await Promise.all(vaultsPerChain.map((v) => (0, getters_1.getVaultPositions)({
650
689
  vault: v.address,
651
690
  solanaWallet,
@@ -660,6 +699,7 @@ class AugustVaults extends core_1.AugustBase {
660
699
  subgraphKey: this.keys?.graph,
661
700
  headers: this.headers,
662
701
  },
702
+ prefetchedReads: prefetchedReads.get(String(v.address).toLowerCase()),
663
703
  })));
664
704
  const flattened = vaultResponses.flat();
665
705
  let final;
@@ -682,6 +722,13 @@ class AugustVaults extends core_1.AugustBase {
682
722
  // outer catch, and silently return PENDING (then get filtered out).
683
723
  (v?.chain_type === 'solana' && !!this.solanaService) ||
684
724
  (this.providers?.[v?.chain] ? true : false));
725
+ // Batch balanceOf/lagDuration via Multicall3, grouped by chain, before
726
+ // the per-vault fan-out; un-batched vaults fall back to their own reads.
727
+ const prefetchedReads = await (0, prefetch_1.prefetchVaultPositionReads)({
728
+ vaults: vaultsPerAvailableProviders,
729
+ wallet,
730
+ providers: this.providers,
731
+ });
685
732
  const vaultResponses = await Promise.all(vaultsPerAvailableProviders.map((v) => (0, getters_1.getVaultPositions)({
686
733
  vault: v.address,
687
734
  solanaWallet,
@@ -696,6 +743,7 @@ class AugustVaults extends core_1.AugustBase {
696
743
  subgraphKey: this.keys?.graph,
697
744
  headers: this.headers,
698
745
  },
746
+ prefetchedReads: prefetchedReads.get(String(v.address).toLowerCase()),
699
747
  })));
700
748
  const flattened = vaultResponses.flat();
701
749
  let final;
@@ -734,6 +782,12 @@ class AugustVaults extends core_1.AugustBase {
734
782
  // deposited token address; propagate it so consumers render the right
735
783
  // asset symbol instead of guessing the vault's first deposit asset.
736
784
  assetIn: h.assetIn,
785
+ // withdraw-request rows carry the burned share amount. Normalize with
786
+ // the vault decimals (the share token's own decimals) so UIs can show
787
+ // the receipt-token quantity that was actually burned.
788
+ shares: h.shares
789
+ ? (0, core_1.toNormalizedBn)(BigInt(h.shares), h.decimals)
790
+ : undefined,
737
791
  }));
738
792
  }
739
793
  // Helper function to fetch history for a vault
@@ -0,0 +1,65 @@
1
+ import type { IAddress, ITokenizedVault } from '../../types';
2
+ /**
3
+ * Per-vault on-chain reads resolved ahead of the positions fan-out, so
4
+ * `getVaultPositions` / `getVaultAvailableRedemptions` can skip their own
5
+ * `balanceOf` / `lagDuration` RPCs. A missing field means the read was not
6
+ * (or could not be) prefetched — the getter falls back to its own call.
7
+ * @internal
8
+ */
9
+ export interface IPrefetchedVaultReads {
10
+ /** Raw share/receipt-token balance of the wallet (`balanceOf`). */
11
+ balance?: bigint;
12
+ /** Vault redemption lag in seconds (`lagDuration`). */
13
+ lagDuration?: number;
14
+ }
15
+ /**
16
+ * Minimal shape of a backend tokenized-vault row the prefetch needs. The
17
+ * full backend response type is looser than this; only these fields are read.
18
+ * @internal
19
+ */
20
+ interface IPrefetchableVault {
21
+ address: string;
22
+ chain: number;
23
+ chain_type?: string;
24
+ /**
25
+ * Backend vault kind. `getVaultVersionV2` reads this to classify evm-2
26
+ * (`multiAssetVault`) vaults whose address isn't in the hardcoded
27
+ * `MULTI_ASSET_VAULTS` list; without it such a vault would be misclassified
28
+ * as evm-1 and the batch would target the vault itself for `balanceOf`
29
+ * instead of its receipt token.
30
+ */
31
+ internal_type?: ITokenizedVault['internal_type'];
32
+ }
33
+ /**
34
+ * Batch the two non-cacheable per-vault reads (`balanceOf`, `lagDuration`)
35
+ * for a vault list via Multicall3, grouped by chain, ahead of the per-vault
36
+ * positions fan-out.
37
+ *
38
+ * Scope and fallback rules (task 52):
39
+ * - Only EVM vaults on chains with a configured provider AND a verified
40
+ * Multicall3 deployment are batched. Solana/Stellar vaults, unverified
41
+ * chains (e.g. Citrea 4114), and provider-less chains are skipped — they
42
+ * keep today's exact per-vault read path.
43
+ * - `balanceOf` targets the receipt token for evm-2 vaults (resolved through
44
+ * the same cached `getReceiptTokenAddress` the getters use) and the vault
45
+ * itself for evm-1. Without an EVM wallet only `lagDuration` is batched.
46
+ * - Failures never propagate: a reverting vault call is simply absent from
47
+ * the result map, and a whole-chain error drops that chain's entries. The
48
+ * worst case is always "no prefetch → per-vault fallback", never wrong data.
49
+ *
50
+ * RPC cost: per batched chain, `ceil(reads / 10)` `eth_call`s (+1 cold
51
+ * `lpTokenAddress` per evm-2 vault) instead of ~2 `eth_call`s per vault.
52
+ *
53
+ * @param vaults Backend tokenized-vault rows about to be fanned out over.
54
+ * @param wallet Optional EVM wallet for `balanceOf` reads.
55
+ * @param providers Chain-id → RPC-url map (the module's `this.providers`).
56
+ * @returns Map keyed by lowercased vault address; vaults with no batched
57
+ * reads have no entry.
58
+ * @internal
59
+ */
60
+ export declare function prefetchVaultPositionReads({ vaults, wallet, providers, }: {
61
+ vaults: IPrefetchableVault[];
62
+ wallet?: IAddress;
63
+ providers?: Partial<Record<number, string>>;
64
+ }): Promise<Map<string, IPrefetchedVaultReads>>;
65
+ export {};
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.prefetchVaultPositionReads = prefetchVaultPositionReads;
4
+ const ethers_1 = require("ethers");
5
+ const abis_1 = require("../../abis");
6
+ const TokenizedVaultV2Receipt_1 = require("../../abis/TokenizedVaultV2Receipt");
7
+ const core_1 = require("../../core");
8
+ /**
9
+ * Batch the two non-cacheable per-vault reads (`balanceOf`, `lagDuration`)
10
+ * for a vault list via Multicall3, grouped by chain, ahead of the per-vault
11
+ * positions fan-out.
12
+ *
13
+ * Scope and fallback rules (task 52):
14
+ * - Only EVM vaults on chains with a configured provider AND a verified
15
+ * Multicall3 deployment are batched. Solana/Stellar vaults, unverified
16
+ * chains (e.g. Citrea 4114), and provider-less chains are skipped — they
17
+ * keep today's exact per-vault read path.
18
+ * - `balanceOf` targets the receipt token for evm-2 vaults (resolved through
19
+ * the same cached `getReceiptTokenAddress` the getters use) and the vault
20
+ * itself for evm-1. Without an EVM wallet only `lagDuration` is batched.
21
+ * - Failures never propagate: a reverting vault call is simply absent from
22
+ * the result map, and a whole-chain error drops that chain's entries. The
23
+ * worst case is always "no prefetch → per-vault fallback", never wrong data.
24
+ *
25
+ * RPC cost: per batched chain, `ceil(reads / 10)` `eth_call`s (+1 cold
26
+ * `lpTokenAddress` per evm-2 vault) instead of ~2 `eth_call`s per vault.
27
+ *
28
+ * @param vaults Backend tokenized-vault rows about to be fanned out over.
29
+ * @param wallet Optional EVM wallet for `balanceOf` reads.
30
+ * @param providers Chain-id → RPC-url map (the module's `this.providers`).
31
+ * @returns Map keyed by lowercased vault address; vaults with no batched
32
+ * reads have no entry.
33
+ * @internal
34
+ */
35
+ async function prefetchVaultPositionReads({ vaults, wallet, providers, }) {
36
+ const reads = new Map();
37
+ const hasWallet = !!(wallet && (0, ethers_1.isAddress)(wallet));
38
+ const byChain = new Map();
39
+ for (const v of vaults) {
40
+ if (!v?.address || !(0, ethers_1.isAddress)(v.address))
41
+ continue;
42
+ if (!(0, core_1.isMulticall3Supported)(v.chain))
43
+ continue;
44
+ if (!providers?.[v.chain])
45
+ continue;
46
+ const group = byChain.get(v.chain) ?? [];
47
+ group.push(v);
48
+ byChain.set(v.chain, group);
49
+ }
50
+ await Promise.all(Array.from(byChain.entries()).map(async ([chain, chainVaults]) => {
51
+ try {
52
+ // Same cache key as the getters (`createProvider(rpcUrl)` without a
53
+ // chainId) so the receipt-token/decimals caches stay shared.
54
+ const provider = (0, core_1.createProvider)(providers[chain]);
55
+ // Resolve each vault's `balanceOf` target — the receipt token for
56
+ // evm-2 vaults (one `lpTokenAddress` read each on a cold cache),
57
+ // the vault itself otherwise. Bound the fan-out to
58
+ // `MULTICALL3_BATCH_SIZE` concurrent reads (CLAUDE.md §4.1): a wallet
59
+ // with many uncached evm-2 vaults on one chain would otherwise burst
60
+ // N simultaneous reads before the aggregate3 batch even fires.
61
+ const balanceTargets = [];
62
+ for (let i = 0; i < chainVaults.length; i += core_1.MULTICALL3_BATCH_SIZE) {
63
+ const slice = chainVaults.slice(i, i + core_1.MULTICALL3_BATCH_SIZE);
64
+ const resolved = await Promise.all(slice.map(async (v) => {
65
+ if (!hasWallet)
66
+ return undefined;
67
+ if ((0, core_1.getVaultVersionV2)(v) === 'evm-2') {
68
+ // Cached + in-flight-deduped; a cold miss costs the same
69
+ // `lpTokenAddress` read the getter itself would make.
70
+ return (0, core_1.getReceiptTokenAddress)(provider, v.address);
71
+ }
72
+ return v.address;
73
+ }));
74
+ balanceTargets.push(...resolved);
75
+ }
76
+ const calls = [];
77
+ const slots = [];
78
+ chainVaults.forEach((v, i) => {
79
+ calls.push({
80
+ target: v.address,
81
+ abi: abis_1.ABI_LENDING_POOL_V2,
82
+ functionName: 'lagDuration',
83
+ });
84
+ slots.push({ address: v.address, field: 'lagDuration' });
85
+ const target = balanceTargets[i];
86
+ if (hasWallet && target && (0, ethers_1.isAddress)(target)) {
87
+ calls.push({
88
+ target: target,
89
+ abi: target === v.address
90
+ ? abis_1.ABI_LENDING_POOL_V2
91
+ : TokenizedVaultV2Receipt_1.ABI_TOKENIZED_VAULT_V2_RECEIPT,
92
+ functionName: 'balanceOf',
93
+ args: [wallet],
94
+ });
95
+ slots.push({ address: v.address, field: 'balance' });
96
+ }
97
+ });
98
+ const results = await (0, core_1.multicall3Aggregate)(provider, chain, calls);
99
+ results.forEach((r, i) => {
100
+ if (!r.success)
101
+ return;
102
+ const slot = slots[i];
103
+ const key = slot.address.toLowerCase();
104
+ const entry = reads.get(key) ?? {};
105
+ if (slot.field === 'lagDuration') {
106
+ entry.lagDuration = Number(r.value);
107
+ }
108
+ else {
109
+ entry.balance = BigInt(r.value);
110
+ }
111
+ reads.set(key, entry);
112
+ });
113
+ }
114
+ catch (e) {
115
+ core_1.Logger.log.warn('prefetchVaultPositionReads', `chain ${chain} prefetch failed — falling back to per-vault reads`, e);
116
+ }
117
+ }));
118
+ return reads;
119
+ }
120
+ //# sourceMappingURL=prefetch.js.map