From 3cb0b4d0dffbbed52413484306f35b2e0960ebf3 Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Sun, 15 Mar 2026 10:42:40 +0000 Subject: [PATCH] [#93] Batch balanceOf checks with multicall in ReaderPortfolio Replace N individual balanceOf RPC calls with a single multicall. Only fetch price/TVL data for tokens the user actually holds, reducing RPC overhead from O(N) to O(1) + O(held). Co-Authored-By: Claude Opus 4.6 (1M context) --- src/components/ReaderPortfolio.tsx | 31 +++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/components/ReaderPortfolio.tsx b/src/components/ReaderPortfolio.tsx index 80dc8929..88406739 100644 --- a/src/components/ReaderPortfolio.tsx +++ b/src/components/ReaderPortfolio.tsx @@ -37,20 +37,29 @@ export function ReaderPortfolio() { if (!storylines || storylines.length === 0) return []; - // Check balance for each token (parallel) + // Batch all balanceOf checks into a single multicall + const balanceCalls = storylines.map((sl) => ({ + address: sl.token_address as Address, + abi: erc20Abi, + functionName: "balanceOf" as const, + args: [address], + })); + + const balanceResults = await publicClient.multicall({ contracts: balanceCalls }); + + // Filter to only storylines with non-zero balance + const held = storylines + .map((sl, i) => ({ sl, balance: balanceResults[i] })) + .filter((h) => h.balance.status === "success" && h.balance.result > BigInt(0)); + + if (held.length === 0) return []; + + // Fetch price, 24h change, and TVL only for held tokens const results = await Promise.all( - storylines.map(async (sl): Promise => { + held.map(async ({ sl, balance: balanceResult }): Promise => { const tokenAddr = sl.token_address as Address; + const balance = balanceResult.result as bigint; try { - const balance = await publicClient.readContract({ - address: tokenAddr, - abi: erc20Abi, - functionName: "balanceOf", - args: [address], - }); - - if (balance === BigInt(0)) return null; - const [price, priceChangeResult, tvlResult] = await Promise.all([ publicClient.readContract({ address: MCV2_BOND,