99 * - `fetchVaultApy` — Subsquid version, returns null if vault has no markets
1010 * - `fetchVaultApyViem` — viem version, returns { apy, markets } or null
1111 */
12+ import { compact } from 'lodash'
1213import type { PublicClient } from 'viem'
1314import { getAddress } from 'viem'
1415
@@ -192,8 +193,18 @@ export async function fetchVaultMarketsViem(
192193
193194 // 2. Market IDs from both queues
194195 const queueCalls = [
195- ...Array . from ( { length : supplyLenN } , ( _ , i ) => ( { address : vault , abi : META_MORPHO_ABI_JSON , functionName : 'supplyQueue' as const , args : [ BigInt ( i ) ] } ) ) ,
196- ...Array . from ( { length : withdrawLenN } , ( _ , i ) => ( { address : vault , abi : META_MORPHO_ABI_JSON , functionName : 'withdrawQueue' as const , args : [ BigInt ( i ) ] } ) ) ,
196+ ...Array . from ( { length : supplyLenN } , ( _ , i ) => ( {
197+ address : vault ,
198+ abi : META_MORPHO_ABI_JSON ,
199+ functionName : 'supplyQueue' as const ,
200+ args : [ BigInt ( i ) ] ,
201+ } ) ) ,
202+ ...Array . from ( { length : withdrawLenN } , ( _ , i ) => ( {
203+ address : vault ,
204+ abi : META_MORPHO_ABI_JSON ,
205+ functionName : 'withdrawQueue' as const ,
206+ args : [ BigInt ( i ) ] ,
207+ } ) ) ,
197208 ]
198209
199210 const queueResults = await client . multicall ( { contracts : queueCalls , allowFailure : false } )
@@ -206,53 +217,47 @@ export async function fetchVaultMarketsViem(
206217
207218 if ( allIds . length === 0 ) return [ ]
208219
209- // 4. Fetch market state, position, params, config
210- const perMarketCalls = allIds . flatMap ( ( id ) => [
211- { address : morpho , abi : MORPHO_ABI_JSON , functionName : 'market' as const , args : [ id ] } ,
212- { address : morpho , abi : MORPHO_ABI_JSON , functionName : 'position' as const , args : [ id , vault ] } ,
213- { address : morpho , abi : MORPHO_ABI_JSON , functionName : 'idToMarketParams' as const , args : [ id ] } ,
214- { address : vault , abi : META_MORPHO_ABI_JSON , functionName : 'config' as const , args : [ id ] } ,
220+ // 4. Fetch market state, position, params, config (parallel multicalls)
221+ const [ marketStates , positions , marketParams , configs ] = await Promise . all ( [
222+ client . multicall ( {
223+ contracts : allIds . map ( ( id ) => ( { address : morpho , abi : MORPHO_ABI_JSON , functionName : 'market' as const , args : [ id ] } ) ) ,
224+ allowFailure : false ,
225+ } ) ,
226+ client . multicall ( {
227+ contracts : allIds . map ( ( id ) => ( { address : morpho , abi : MORPHO_ABI_JSON , functionName : 'position' as const , args : [ id , vault ] } ) ) ,
228+ allowFailure : false ,
229+ } ) ,
230+ client . multicall ( {
231+ contracts : allIds . map ( ( id ) => ( { address : morpho , abi : MORPHO_ABI_JSON , functionName : 'idToMarketParams' as const , args : [ id ] } ) ) ,
232+ allowFailure : false ,
233+ } ) ,
234+ client . multicall ( {
235+ contracts : allIds . map ( ( id ) => ( { address : vault , abi : META_MORPHO_ABI_JSON , functionName : 'config' as const , args : [ id ] } ) ) ,
236+ allowFailure : false ,
237+ } ) ,
215238 ] )
216239
217- const perMarketResults = await client . multicall ( { contracts : perMarketCalls , allowFailure : false } )
218-
219- // Parse per-market results (4 calls per market)
220- // viem returns multi-output functions as arrays, so destructure by position.
221- const parsed = allIds . map ( ( _ , i ) => {
222- const base = i * 4
223- const [ totalSupplyAssets , totalSupplyShares , totalBorrowAssets , , , fee ] = perMarketResults [ base ] as unknown as bigint [ ]
224- const [ supplyShares ] = perMarketResults [ base + 1 ] as unknown as bigint [ ]
225- const [ loanToken , , , irm ] = perMarketResults [ base + 2 ] as unknown as `0x${string } `[ ]
226- const [ cap ] = perMarketResults [ base + 3 ] as unknown as bigint [ ]
227- return {
228- state : { totalSupplyAssets, totalSupplyShares, totalBorrowAssets, fee } ,
229- pos : { supplyShares } ,
230- params : { loanToken, irm } ,
231- cfg : { cap } ,
232- }
233- } )
234-
235240 // 5. Per-market IRM + decimals (single multicall batch)
236- const irmAndDecimalCalls = parsed . flatMap ( ( { params } , i ) => {
237- const hasIrm = params . irm && params . irm . toLowerCase ( ) !== ADDRESS_ZERO
241+ const irmAndDecimalCalls = marketParams . flatMap ( ( [ loanToken , , , irm ] , i ) => {
242+ const hasIrm = irm && irm . toLowerCase ( ) !== ADDRESS_ZERO
238243 return [
239244 hasIrm
240- ? { address : getAddress ( params . irm ) , abi : IRM_ABI_JSON , functionName : 'rateAtTarget' as const , args : [ allIds [ i ] ] }
245+ ? { address : getAddress ( irm ) , abi : IRM_ABI_JSON , functionName : 'rateAtTarget' as const , args : [ allIds [ i ] ] }
241246 : null ,
242- { address : getAddress ( params . loanToken ) , abi : ERC20_ABI_JSON , functionName : 'decimals' as const } ,
247+ { address : getAddress ( loanToken ) , abi : ERC20_ABI_JSON , functionName : 'decimals' as const } ,
243248 ]
244249 } )
245250 const irmAndDecimalResults = await client . multicall ( {
246- contracts : irmAndDecimalCalls . filter ( ( c ) : c is NonNullable < typeof c > => c !== null ) ,
251+ contracts : compact ( irmAndDecimalCalls ) ,
247252 allowFailure : true ,
248253 } )
249254
250255 // Map results back, accounting for skipped IRM calls
251256 let resultIdx = 0
252257 const ratesAtTarget : bigint [ ] = [ ]
253258 const decimals : number [ ] = [ ]
254- for ( const { params } of parsed ) {
255- const hasIrm = params . irm && params . irm . toLowerCase ( ) !== ADDRESS_ZERO
259+ for ( const [ , , , irm ] of marketParams ) {
260+ const hasIrm = irm && irm . toLowerCase ( ) !== ADDRESS_ZERO
256261 if ( hasIrm ) {
257262 const r = irmAndDecimalResults [ resultIdx ++ ]
258263 const rate = r . status === 'success' ? ( r . result as bigint ) : 0n
@@ -266,20 +271,26 @@ export async function fetchVaultMarketsViem(
266271
267272 // 6. Assemble
268273 return allIds . map ( ( marketId , i ) => {
269- const { state, pos, cfg } = parsed [ i ]
274+ // market: [totalSupplyAssets, totalSupplyShares, totalBorrowAssets, totalBorrowShares, lastUpdate, fee]
275+ const [ totalSupplyAssets , totalSupplyShares , totalBorrowAssets , , , fee ] = marketStates [ i ]
276+ // position: [supplyShares, borrowShares, collateral]
277+ const [ supplyShares ] = positions [ i ]
278+ // config: [cap, enabled, removableAt]
279+ const [ cap ] = configs [ i ]
280+
270281 let vaultSupplyAssets = 0n
271- if ( pos . supplyShares > 0n && state . totalSupplyShares > 0n ) {
272- vaultSupplyAssets = ( pos . supplyShares * state . totalSupplyAssets ) / state . totalSupplyShares
282+ if ( supplyShares > 0n && totalSupplyShares > 0n ) {
283+ vaultSupplyAssets = ( supplyShares * totalSupplyAssets ) / totalSupplyShares
273284 }
274285
275286 return {
276287 marketId,
277- totalSupplyAssets : state . totalSupplyAssets ,
278- totalBorrowAssets : state . totalBorrowAssets ,
279- fee : state . fee ,
288+ totalSupplyAssets,
289+ totalBorrowAssets,
290+ fee,
280291 vaultSupplyAssets,
281292 rateAtTarget : ratesAtTarget [ i ] ,
282- cap : cfg . cap ,
293+ cap,
283294 decimals : decimals [ i ] ,
284295 inSupplyQueue : supplySet . has ( marketId as `0x${string } `) ,
285296 } satisfies MarketForApy
0 commit comments