diff --git a/fees/yieldfi/index.ts b/fees/yieldfi/index.ts index 64a827560c..a792b2f4dc 100644 --- a/fees/yieldfi/index.ts +++ b/fees/yieldfi/index.ts @@ -24,10 +24,43 @@ const CONTRACTS = { V2_MANAGER: { [CHAIN.ETHEREUM]: "0x03ACc35286bAAE6D73d99a9f14Ef13752208C8dC", }, - FROM_BLOCK: { - [CHAIN.ETHEREUM]: 24241384, - [CHAIN.BSC]: 76733207, - }, +} + +const YIELD_SEGMENTS = 10 + +const PROTOCOL_START_TS: Record = { + [CHAIN.ETHEREUM]: Math.floor(new Date("2024-11-11T00:00:00Z").getTime() / 1000), + [CHAIN.BSC]: Math.floor(new Date("2025-07-27T00:00:00Z").getTime() / 1000), +} + +async function fetchVaultDeployedLogs(options: FetchOptions, vaultDeployer: string) { + const startTs = PROTOCOL_START_TS[options.chain] + if (startTs === undefined) return [] + const deployFromBlock = await options.getBlock(startTs, options.chain, {}) + const toBlock = await options.getToBlock() + if (deployFromBlock > toBlock) return [] + const span = toBlock - deployFromBlock + const seen = new Set() + const merged: any[] = [] + for (let i = 0; i < YIELD_SEGMENTS; i++) { + const chunkFrom = deployFromBlock + Math.floor((i * span) / YIELD_SEGMENTS) + const chunkTo = i === YIELD_SEGMENTS - 1 ? toBlock : deployFromBlock + Math.floor(((i + 1) * span) / YIELD_SEGMENTS) - 1 + if (chunkFrom > chunkTo) continue + const chunkLogs = await options.getLogs({ + target: vaultDeployer, + eventAbi: ABI.DEPLOY_VAULT, + cacheInCloud: true, + fromBlock: chunkFrom, + toBlock: chunkTo, + }) + for (const log of chunkLogs) { + const key = String(log.vault).toLowerCase() + if (seen.has(key)) continue + seen.add(key) + merged.push(log) + } + } + return merged } async function fetch(options: FetchOptions): Promise { @@ -38,7 +71,6 @@ async function fetch(options: FetchOptions): Promise { const manager = CONTRACTS.V2_MANAGER[options.chain]; const navManager = CONTRACTS.NAV_MANAGER[options.chain]; const vaultDeployer = CONTRACTS.VAULT_DEPLOYER[options.chain]; - const fromBlock = CONTRACTS.FROM_BLOCK[options.chain]; if (yieldProxy) { const yieldDistributedLogs = await options.getLogs({ target: yieldProxy, eventAbi: ABI.YIELD_PROXY }); @@ -57,12 +89,7 @@ async function fetch(options: FetchOptions): Promise { target: navManager, eventAbi: ABI.NAV, }); - const vaultDeployedLogs = await options.getLogs({ - target: vaultDeployer, - eventAbi: ABI.DEPLOY_VAULT, - cacheInCloud: true, - fromBlock, - }); + const vaultDeployedLogs = await fetchVaultDeployedLogs(options, vaultDeployer); navManagerLogs.forEach((log: any) => { dailyFees.add(log.vault, log.managementFee + log.performanceFee); @@ -70,16 +97,39 @@ async function fetch(options: FetchOptions): Promise { }); const vaults = vaultDeployedLogs.map((log: any) => log.vault); - const totalSupplies = await options.api.multiCall({ abi: 'uint256:totalSupply', calls: vaults, permitFailure: true }); const assets = await options.api.multiCall({ abi: 'address:asset', calls: vaults, permitFailure: true }); const decimals = await options.api.multiCall({ abi: 'uint8:decimals', calls: vaults, permitFailure: true }); const assetDecimals = await options.api.multiCall({ abi: 'uint8:decimals', calls: assets, permitFailure: true }); - const vaultRateBefore = await options.fromApi.multiCall({ abi: 'uint256:getRate', calls: vaults, permitFailure: true }); - const vaultRateAfter = await options.toApi.multiCall({ abi: 'uint256:getRate', calls: vaults, permitFailure: true }); + + const fromFeeBlock = await options.getFromBlock(); + const toFeeBlock = await options.getToBlock(); + const feeSpan = toFeeBlock - fromFeeBlock; + const boundaryBlocks: number[] = []; + for (let j = 0; j <= YIELD_SEGMENTS; j++) { + boundaryBlocks.push(j === YIELD_SEGMENTS ? toFeeBlock : fromFeeBlock + Math.floor((j * feeSpan) / YIELD_SEGMENTS)); + } + + const suppliesAt: any[][] = []; + const ratesAt: any[][] = []; + for (const block of boundaryBlocks) { + suppliesAt.push(await options.api.multiCall({ abi: 'uint256:totalSupply', calls: vaults, permitFailure: true, block })); + ratesAt.push(await options.api.multiCall({ abi: 'uint256:getRate', calls: vaults, permitFailure: true, block })); + } for (let i = 0; i < vaults.length; i++) { - if (assets[i] && totalSupplies[i] && decimals[i] && assetDecimals[i] && vaultRateAfter[i] && vaultRateBefore[i]) - dailyFees.add(assets[i], (totalSupplies[i] / 10 ** decimals[i]) * (vaultRateAfter[i] - vaultRateBefore[i]) / 10 ** (decimals[i] - assetDecimals[i])); + if (!assets[i] || decimals[i] == null || assetDecimals[i] == null) continue; + let acc = 0; + for (let k = 0; k < YIELD_SEGMENTS; k++) { + const s0 = suppliesAt[k][i]; + const s1 = suppliesAt[k + 1][i]; + const r0 = ratesAt[k][i]; + const r1 = ratesAt[k + 1][i]; + if (s0 == null || s1 == null || r0 == null || r1 == null) continue; + const avgSupply = (Number(s0) + Number(s1)) / 2; + const rateDelta = Number(r1) - Number(r0); + acc += (avgSupply / 10 ** decimals[i]) * rateDelta / 10 ** (decimals[i] - assetDecimals[i]); + } + if (acc !== 0) dailyFees.add(assets[i], acc); } } const dailySupplySideRevenue = dailyFees.clone();