From dd35e9c2fc19d810f4e72757bb0e3e6a30edb814 Mon Sep 17 00:00:00 2001 From: TadejPolajnar Date: Thu, 27 Nov 2025 11:46:25 +0800 Subject: [PATCH 1/3] feat: Add logic to retrieve lagoon curator fees --- helpers/curators/index.ts | 65 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/helpers/curators/index.ts b/helpers/curators/index.ts index 848a5200b1..3e33870071 100644 --- a/helpers/curators/index.ts +++ b/helpers/curators/index.ts @@ -7,11 +7,12 @@ export interface CuratorConfig { methodology?: any; vaults: { - // chain => + // chain => [key: string]: { start?: IStartTimestamp | number | string; morpho?: Array; euler?: Array; + lagoon?: Array; // initial owner of morpho vaults morphoVaultOwners?: Array; @@ -227,6 +228,63 @@ export async function getEulerVaultFee(options: FetchOptions, balances: Balances } } +export async function getLagoonVaultFee(options: FetchOptions, balances: Balances, vaults: Array) { + const feeRateAbi = "function feeRates() external view returns(tuple(uint16 managementRate, uint16 performanceRate))"; + const ONE_YEAR = 365 * 24 * 60 * 60; + const { getERC4626VaultsYield } = await import("../erc4626"); + + // Get fee details from all vaults + const feeDetails = await options.api.multiCall({ + abi: feeRateAbi, + calls: vaults, + permitFailure: true + }); + + const assets = await options.api.multiCall({ + abi: 'address:asset', + calls: vaults, + permitFailure: true + }); + + const totalAssets = await options.api.multiCall({ + abi: 'uint256:totalAssets', + calls: vaults, + permitFailure: true + }); + + for (let i = 0; i < vaults.length; i++) { + if (!feeDetails[i] || !assets[i] || !totalAssets[i]) continue; + + const { performanceRate, managementRate } = feeDetails[i]; + + const dailyYield = await getERC4626VaultsYield({ options, vaults: [vaults[i]] }); + + const dailyManagementFee = (totalAssets[i]) * (managementRate / 10000) * ((options.toTimestamp - options.fromTimestamp) / ONE_YEAR); + + const dailyYieldUSD = await dailyYield.getUSDValue(); + + if (dailyYieldUSD > 0) { + // Calculate total yield before performance fee + // If performance fee is 10%, and depositors get dailyYield, then dailyYield represents 90% of total + // So totalYieldBeforeFee = dailyYield / 0.9 + const totalYieldBeforeFee = dailyYield.clone(1 / (1 - performanceRate / 10000), METRIC.ASSETS_YIELDS); + + const vaultTotalFees = totalYieldBeforeFee.clone(); + vaultTotalFees.add(assets[i], dailyManagementFee, METRIC.MANAGEMENT_FEES); + + const performanceFee = totalYieldBeforeFee.clone(); + performanceFee.subtract(dailyYield, METRIC.ASSETS_YIELDS); + + balances.dailyFees.add(vaultTotalFees); + balances.dailyRevenue.add(performanceFee); + balances.dailyRevenue.add(assets[i], dailyManagementFee, METRIC.MANAGEMENT_FEES); + } else if (dailyManagementFee > 0) { + balances.dailyFees.add(assets[i], dailyManagementFee, METRIC.MANAGEMENT_FEES); + balances.dailyRevenue.add(assets[i], dailyManagementFee, METRIC.MANAGEMENT_FEES); + } + } +} + export function getCuratorExport(curatorConfig: CuratorConfig): SimpleAdapter { const methodology = curatorConfig.methodology ? curatorConfig.methodology : { Fees: 'Total yields from deposited assets in all curated vaults.', @@ -244,12 +302,17 @@ export function getCuratorExport(curatorConfig: CuratorConfig): SimpleAdapter { const morphoVaults = await getMorphoVaults(options, vaults.morpho, vaults.morphoVaultOwners); const eulerVaults = await getEulerVaults(options, vaults.euler, vaults.eulerVaultOwners); + const lagoonVaults = vaults.lagoon || []; + if (morphoVaults.length > 0) { await getMorphoVaultFee(options, { dailyFees, dailyRevenue }, morphoVaults) } if (eulerVaults.length > 0) { await getEulerVaultFee(options, { dailyFees, dailyRevenue }, eulerVaults) } + if (lagoonVaults.length > 0) { + await getLagoonVaultFee(options, { dailyFees, dailyRevenue }, lagoonVaults) + } const dailySupplySideRevenue = dailyFees.clone(1, METRIC.ASSETS_YIELDS) dailySupplySideRevenue.subtract(dailyRevenue, METRIC.ASSETS_YIELDS) From 652bdc1dbb7bc7b34ba79625227df108524220bd Mon Sep 17 00:00:00 2001 From: TadejPolajnar Date: Thu, 27 Nov 2025 12:03:03 +0800 Subject: [PATCH 2/3] feat: Add lagoon vaults to tulip capital --- fees/tulip-capital.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fees/tulip-capital.ts b/fees/tulip-capital.ts index b3ae679b57..0cd06ebc4e 100644 --- a/fees/tulip-capital.ts +++ b/fees/tulip-capital.ts @@ -9,6 +9,10 @@ const curatorConfig: CuratorConfig = { eulerVaultOwners: [ '0x7c615e12D1163fc0DdDAA01B51922587034F5C93', ], + lagoon: [ + "0x936facdf10c8c36294e7b9d28345255539d81bc7", // RockSolid rock.rETH + "0xb09f761cb13baca8ec087ac476647361b6314f98", // Flagship cbBTC + ], }, berachain: { eulerVaultOwners: [ @@ -25,6 +29,17 @@ const curatorConfig: CuratorConfig = { '0x7c615e12D1163fc0DdDAA01B51922587034F5C93', ], }, + avax: { + lagoon: [ + "0x3048925b3ea5a8c12eecccb8810f5f7544db54af", // Turtle Avalanche USDC + "0xb893c8d7000e0408eb7d168152ec7fefdd0d25e3", // Turtle Avalanche BTC.b + ], + }, + tac: { + lagoon:[ + '0x279385c180f5d01c4a4bdff040f17b8957304762' // Noon USN TAC + ] + } } } From da08fc513d68d3a715fb70dd72d1aa2ed63d6ed7 Mon Sep 17 00:00:00 2001 From: TadejPolajnar Date: Thu, 27 Nov 2025 12:11:45 +0800 Subject: [PATCH 3/3] chore: Use constants as chain name in tulip capital config --- fees/tulip-capital.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/fees/tulip-capital.ts b/fees/tulip-capital.ts index 0cd06ebc4e..2b3cdb7654 100644 --- a/fees/tulip-capital.ts +++ b/fees/tulip-capital.ts @@ -1,8 +1,9 @@ +import { CHAIN } from "../helpers/chains"; import { CuratorConfig, getCuratorExport } from "../helpers/curators"; const curatorConfig: CuratorConfig = { vaults: { - ethereum: { + [CHAIN.ETHEREUM]: { morphoVaultOwners: [ '0x59e608E4842162480591032f3c8b0aE55C98d104', ], @@ -14,28 +15,28 @@ const curatorConfig: CuratorConfig = { "0xb09f761cb13baca8ec087ac476647361b6314f98", // Flagship cbBTC ], }, - berachain: { + [CHAIN.BERACHAIN]: { eulerVaultOwners: [ '0x18d23B961b11079EcD499c0EAD8E4F347e4d3A66', ], }, - bob: { + [CHAIN.BOB]: { eulerVaultOwners: [ '0x7c615e12D1163fc0DdDAA01B51922587034F5C93', ], }, - bsc: { + [CHAIN.BSC]: { eulerVaultOwners: [ '0x7c615e12D1163fc0DdDAA01B51922587034F5C93', ], }, - avax: { + [CHAIN.AVAX]: { lagoon: [ "0x3048925b3ea5a8c12eecccb8810f5f7544db54af", // Turtle Avalanche USDC "0xb893c8d7000e0408eb7d168152ec7fefdd0d25e3", // Turtle Avalanche BTC.b ], }, - tac: { + [CHAIN.TAC]: { lagoon:[ '0x279385c180f5d01c4a4bdff040f17b8957304762' // Noon USN TAC ]