Skip to content

Commit 477fdee

Browse files
committed
roll out curators fees breakdown
1 parent d9b5781 commit 477fdee

File tree

2 files changed

+98
-68
lines changed

2 files changed

+98
-68
lines changed

factory/curators.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ const configs: Record<string, CuratorConfig> = {
397397
},
398398
},
399399
"yearn-curating": {
400+
breakdownFees: true,
400401
vaults: {
401402
[CHAIN.ETHEREUM]: {
402403
morphoVaultOwners: ['0xFc5F89d29CCaa86e5410a7ad9D9d280d4455C12B'],
@@ -407,6 +408,7 @@ const configs: Record<string, CuratorConfig> = {
407408
},
408409
},
409410
"zerolend-vaults": {
411+
breakdownFees: true,
410412
vaults: {
411413
[CHAIN.ETHEREUM]: {
412414
eulerVaultOwners: zerolendMultisigs,

helpers/curators/index.ts

Lines changed: 96 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,27 @@
11
import * as sdk from "@defillama/sdk";
22
import { BaseAdapter, FetchOptions, IStartTimestamp, SimpleAdapter } from "../../adapters/types";
33
import { ABI, EulerConfigs, MorphoConfigs } from "./configs";
4-
import { METRIC } from "../metrics";
4+
5+
const METRICS = {
6+
// use this label for all yield sources if breakdownFees was not set
7+
AssetYields: 'Assets Yields',
8+
9+
// set
10+
OtherAssetYields: 'Other Asset Yields',
11+
OtherAssetYieldsToSuppliers: 'Other Asset Yields Distributed To Supliers',
12+
OtherAssetYieldsToCurator: 'Other Asset Yields To Curator',
13+
MorphoYields: 'Morpho Yields',
14+
MorphoYieldsToSuppliers: 'Morpho Yields Distributed To Supliers',
15+
MorphoPerformanceFee: 'Morpho Performance Fees',
16+
MorphoManagementFee: 'Morpho Performance Fees',
17+
EulerYields: 'Euler Yields',
18+
EulerYieldsToSuppliers: 'Euler Yields Distributed To Supliers',
19+
EulerPerformanceFee: 'Euler Performance Fees',
20+
}
521

622
export interface CuratorConfig {
723
methodology?: any;
8-
24+
breakdownFees?: boolean;
925
vaults: {
1026
// chain =>
1127
[key: string]: {
@@ -24,9 +40,9 @@ export interface CuratorConfig {
2440
}
2541

2642
interface Balances {
27-
dailyFees: sdk.Balances,
28-
dailyRevenue: sdk.Balances,
29-
dailySupplySideRevenue?: sdk.Balances
43+
dailyFees: sdk.Balances;
44+
dailyRevenue: sdk.Balances;
45+
dailySupplySideRevenue: sdk.Balances;
3046
}
3147

3248
interface VaultERC4626Info {
@@ -188,7 +204,7 @@ async function getVaultERC4626Info(options: FetchOptions, vaults: Array<string>,
188204
return vaultInfo;
189205
}
190206

191-
async function getMorphoVaultFee(options: FetchOptions, balances: Balances, vaults: Array<string>) {
207+
async function getMorphoVaultFee(options: FetchOptions, balances: Balances, vaults: Array<string>, breakdownFees?: boolean) {
192208
const vaultInfo = await getVaultERC4626Info(options, vaults, true)
193209
const vaultFeeRates = await options.api.multiCall({
194210
abi: ABI.morpho.fee,
@@ -199,25 +215,30 @@ async function getMorphoVaultFee(options: FetchOptions, balances: Balances, vaul
199215
for (let i = 0; i < vaultInfo.length; i++) {
200216
const growthRate = vaultInfo[i].rateAfter - vaultInfo[i].rateBefore
201217

202-
if (growthRate > 0) {
203-
const vaultFeeRate = BigInt(vaultFeeRates[i] ? vaultFeeRates[i] : 0)
204-
205-
// morpho vault include fee directly to vault shares
206-
// it mean that vault fees were added from vault token shares
218+
const vaultFeeRate = BigInt(vaultFeeRates[i] ? vaultFeeRates[i] : 0)
207219

208-
// interest earned and distributed to vault deposited including fees
209-
const interestEarnedIncludingFees = vaultInfo[i].balance * growthRate / BigInt(10**18)
210-
211-
// interest earned by vault curator
212-
const interestFee = interestEarnedIncludingFees * vaultFeeRate / BigInt(1e18)
220+
// morpho vault include fee directly to vault shares
221+
// it mean that vault fees were added from vault token shares
213222

214-
balances.dailyFees.add(vaultInfo[i].asset, interestEarnedIncludingFees, METRIC.ASSETS_YIELDS)
215-
balances.dailyRevenue.add(vaultInfo[i].asset, interestFee, METRIC.ASSETS_YIELDS)
223+
// interest earned and distributed to vault deposited including fees
224+
const interestEarnedIncludingFees = vaultInfo[i].balance * growthRate / BigInt(10**18)
225+
226+
// interest earned by vault curator
227+
const interestFee = interestEarnedIncludingFees * vaultFeeRate / BigInt(1e18)
228+
229+
if (breakdownFees) {
230+
balances.dailyFees.add(vaultInfo[i].asset, interestEarnedIncludingFees, METRICS.MorphoYields)
231+
balances.dailyRevenue.add(vaultInfo[i].asset, interestFee, METRICS.MorphoPerformanceFee)
232+
balances.dailySupplySideRevenue.add(vaultInfo[i].asset, interestEarnedIncludingFees- interestFee, METRICS.MorphoYieldsToSuppliers)
233+
} else {
234+
balances.dailyFees.add(vaultInfo[i].asset, interestEarnedIncludingFees, METRICS.AssetYields)
235+
balances.dailyRevenue.add(vaultInfo[i].asset, interestFee, METRICS.AssetYields)
236+
balances.dailySupplySideRevenue.add(vaultInfo[i].asset, interestEarnedIncludingFees- interestFee, METRICS.AssetYields)
216237
}
217238
}
218239
}
219240

220-
export async function getEulerVaultFee(options: FetchOptions, balances: Balances, vaults: Array<string>) {
241+
export async function getEulerVaultFee(options: FetchOptions, balances: Balances, vaults: Array<string>, breakdownFees?: boolean) {
221242
const vaultInfo = await getVaultERC4626Info(options, vaults)
222243
const vaultFeeRates = await options.api.multiCall({
223244
abi: ABI.euler.interestFee,
@@ -228,32 +249,36 @@ export async function getEulerVaultFee(options: FetchOptions, balances: Balances
228249
for (let i = 0; i < vaultInfo.length; i++) {
229250
const growthRate = vaultInfo[i].rateAfter - vaultInfo[i].rateBefore
230251

231-
if (growthRate > 0) {
232-
const vaultFeeRate = BigInt(vaultFeeRates[i] ? vaultFeeRates[i] : 0)
233-
234-
// euler vault subtract fee directly from interest when collecting
235-
// it mean that vault fees were remove from vault token shares
252+
const vaultFeeRate = BigInt(vaultFeeRates[i] ? vaultFeeRates[i] : 0)
236253

237-
// interest earned and distributed to vault deposited after fees
238-
const interestEarned = vaultInfo[i].balance * growthRate / BigInt(1e18)
239-
240-
// interest earned and distributed to vault deposited and vault curator before fees
241-
let interestEarnedBeforeFee = interestEarned
242-
if (vaultFeeRate < BigInt(1e4)) {
243-
interestEarnedBeforeFee = interestEarned * BigInt(1e4) / (BigInt(1e4) - vaultFeeRate)
244-
}
254+
// euler vault subtract fee directly from interest when collecting
255+
// it mean that vault fees were remove from vault token shares
245256

246-
// interest earned by vault curator
247-
const interestFee = interestEarnedBeforeFee - interestEarned
257+
// interest earned and distributed to vault deposited after fees
258+
const interestEarned = vaultInfo[i].balance * growthRate / BigInt(1e18)
259+
260+
// interest earned and distributed to vault deposited and vault curator before fees
261+
let interestEarnedBeforeFee = interestEarned
262+
if (vaultFeeRate < BigInt(1e4)) {
263+
interestEarnedBeforeFee = interestEarned * BigInt(1e4) / (BigInt(1e4) - vaultFeeRate)
264+
}
248265

249-
balances.dailyFees.add(vaultInfo[i].asset, interestEarnedBeforeFee, METRIC.ASSETS_YIELDS)
250-
balances.dailyRevenue.add(vaultInfo[i].asset, interestFee, METRIC.ASSETS_YIELDS)
251-
if (balances.dailySupplySideRevenue) balances.dailySupplySideRevenue.add(vaultInfo[i].asset, interestEarnedBeforeFee - interestFee, METRIC.ASSETS_YIELDS)
266+
// interest earned by vault curator
267+
const interestFee = interestEarnedBeforeFee - interestEarned
268+
269+
if (breakdownFees) {
270+
balances.dailyFees.add(vaultInfo[i].asset, interestEarnedBeforeFee, METRICS.EulerYields)
271+
balances.dailyRevenue.add(vaultInfo[i].asset, interestFee, METRICS.EulerPerformanceFee)
272+
balances.dailySupplySideRevenue.add(vaultInfo[i].asset, interestEarnedBeforeFee - interestFee, METRICS.EulerYieldsToSuppliers)
273+
} else {
274+
balances.dailyFees.add(vaultInfo[i].asset, interestEarnedBeforeFee, METRICS.AssetYields)
275+
balances.dailyRevenue.add(vaultInfo[i].asset, interestFee, METRICS.AssetYields)
276+
balances.dailySupplySideRevenue.add(vaultInfo[i].asset, interestEarnedBeforeFee - interestFee, METRICS.AssetYields)
252277
}
253278
}
254279
}
255280

256-
async function getMorphoVaultV2Fee(options: FetchOptions, balances: Balances, vaults: Array<string>) {
281+
async function getMorphoVaultV2Fee(options: FetchOptions, balances: Balances, vaults: Array<string>, breakdownFees?: boolean) {
257282
const vaultInfo = await getVaultERC4626Info(options, vaults, true)
258283
const vaultPerformanceFeeRates = await options.api.multiCall({
259284
abi: ABI.morpho.performanceFee,
@@ -269,27 +294,32 @@ async function getMorphoVaultV2Fee(options: FetchOptions, balances: Balances, va
269294
for (let i = 0; i < vaultInfo.length; i++) {
270295
const growthRate = vaultInfo[i].rateAfter - vaultInfo[i].rateBefore
271296

297+
const vaultPerformanceFeeRate = BigInt(vaultPerformanceFeeRates[i] ? vaultPerformanceFeeRates[i] : 0)
298+
const vaultManagementFeeRate = BigInt(vaultManagementFeeRates[i] ? vaultManagementFeeRates[i] : 0)
272299

273-
if (growthRate > 0) {
274-
const vaultPerformanceFeeRate = BigInt(vaultPerformanceFeeRates[i] ? vaultPerformanceFeeRates[i] : 0)
275-
const vaultManagementFeeRate = BigInt(vaultManagementFeeRates[i] ? vaultManagementFeeRates[i] : 0)
276-
277-
// morpho vault include fee directly to vault shares
278-
// it mean that vault fees were added from vault token shares
300+
// morpho vault include fee directly to vault shares
301+
// it mean that vault fees were added from vault token shares
279302

280-
// interest earned and distributed to vault deposited including fees
281-
const interestEarnedIncludingFees = vaultInfo[i].balance * growthRate / BigInt(10**18)
282-
283-
// interest earned by vault curator - performance fee
284-
const interestPerformanceFee = interestEarnedIncludingFees * vaultPerformanceFeeRate / BigInt(1e18)
285-
286-
// interest earned by vault curator - management fee
287-
const timeElapsed = options.toTimestamp - options.fromTimestamp
288-
const interestManagementFee = interestEarnedIncludingFees * vaultManagementFeeRate * BigInt(timeElapsed) / BigInt(1e18)
289-
290-
balances.dailyFees.add(vaultInfo[i].asset, interestEarnedIncludingFees, METRIC.ASSETS_YIELDS)
291-
balances.dailyRevenue.add(vaultInfo[i].asset, interestPerformanceFee, METRIC.ASSETS_YIELDS)
292-
balances.dailyRevenue.add(vaultInfo[i].asset, interestManagementFee, METRIC.ASSETS_YIELDS)
303+
// interest earned and distributed to vault deposited including fees
304+
const interestEarnedIncludingFees = vaultInfo[i].balance * growthRate / BigInt(10**18)
305+
306+
// interest earned by vault curator - performance fee
307+
const interestPerformanceFee = interestEarnedIncludingFees * vaultPerformanceFeeRate / BigInt(1e18)
308+
309+
// interest earned by vault curator - management fee
310+
const timeElapsed = options.toTimestamp - options.fromTimestamp
311+
const interestManagementFee = interestEarnedIncludingFees * vaultManagementFeeRate * BigInt(timeElapsed) / BigInt(1e18)
312+
313+
if (breakdownFees) {
314+
balances.dailyFees.add(vaultInfo[i].asset, interestEarnedIncludingFees, METRICS.MorphoYields)
315+
balances.dailyRevenue.add(vaultInfo[i].asset, interestPerformanceFee, METRICS.MorphoManagementFee)
316+
balances.dailyRevenue.add(vaultInfo[i].asset, interestManagementFee, METRICS.MorphoManagementFee)
317+
balances.dailySupplySideRevenue.add(vaultInfo[i].asset, interestEarnedIncludingFees - interestPerformanceFee - interestManagementFee, METRICS.MorphoYieldsToSuppliers)
318+
} else {
319+
balances.dailyFees.add(vaultInfo[i].asset, interestEarnedIncludingFees, METRICS.AssetYields)
320+
balances.dailyRevenue.add(vaultInfo[i].asset, interestPerformanceFee, METRICS.AssetYields)
321+
balances.dailyRevenue.add(vaultInfo[i].asset, interestManagementFee, METRICS.AssetYields)
322+
balances.dailySupplySideRevenue.add(vaultInfo[i].asset, interestEarnedIncludingFees - interestPerformanceFee - interestManagementFee, METRICS.AssetYields)
293323
}
294324
}
295325
}
@@ -303,13 +333,14 @@ export function getCuratorExport(curatorConfig: CuratorConfig): SimpleAdapter {
303333
}
304334
const breakdownMethodology = {
305335
Fees: {
306-
[METRIC.ASSETS_YIELDS]: 'Interest yields generated from deposited assets in all curated vaults, including both curator fees and depositor yields',
336+
[METRICS.AssetYields]: 'Interest yields generated from deposited assets in all curated vaults, including both curator fees and depositor yields',
337+
[METRICS.MorphoYields]: 'Interest yields generated from deposited assets in all curated vaults, including both curator fees and depositor yields',
307338
},
308339
Revenue: {
309-
[METRIC.ASSETS_YIELDS]: 'Portion of interest yields retained by vault curators as management and performance fees',
340+
[METRICS.AssetYields]: 'Portion of interest yields retained by vault curators as management and performance fees',
310341
},
311342
SupplySideRevenue: {
312-
[METRIC.ASSETS_YIELDS]: 'Portion of interest yields distributed to vault depositors/investors after curator fees are deducted',
343+
[METRICS.AssetYields]: 'Portion of interest yields distributed to vault depositors/investors after curator fees are deducted',
313344
},
314345
}
315346
const exportObject: BaseAdapter = {}
@@ -319,6 +350,7 @@ export function getCuratorExport(curatorConfig: CuratorConfig): SimpleAdapter {
319350
fetch: (async (options: FetchOptions) => {
320351
let dailyFees = options.createBalances()
321352
let dailyRevenue = options.createBalances()
353+
let dailySupplySideRevenue = options.createBalances()
322354

323355
// morpho meta vaults
324356
const morphoVaults = await getMorphoVaults(options, vaults.morpho, vaults.morphoVaultOwners);
@@ -329,20 +361,15 @@ export function getCuratorExport(curatorConfig: CuratorConfig): SimpleAdapter {
329361
const eulerVaults = await getEulerVaults(options, vaults.euler, vaults.eulerVaultOwners);
330362

331363
if (morphoVaults.length > 0) {
332-
await getMorphoVaultFee(options, { dailyFees, dailyRevenue }, morphoVaults)
364+
await getMorphoVaultFee(options, { dailyFees, dailyRevenue, dailySupplySideRevenue }, morphoVaults, curatorConfig.breakdownFees)
333365
}
334366
if (morphoVaultsV2.length > 0) {
335-
await getMorphoVaultV2Fee(options, { dailyFees, dailyRevenue }, morphoVaultsV2)
367+
await getMorphoVaultV2Fee(options, { dailyFees, dailyRevenue, dailySupplySideRevenue }, morphoVaultsV2, curatorConfig.breakdownFees)
336368
}
337369
if (eulerVaults.length > 0) {
338-
await getEulerVaultFee(options, { dailyFees, dailyRevenue }, eulerVaults)
370+
await getEulerVaultFee(options, { dailyFees, dailyRevenue, dailySupplySideRevenue }, eulerVaults, curatorConfig.breakdownFees)
339371
}
340372

341-
const dailySupplySideRevenue = options.createBalances()
342-
const tempBalance = dailyFees.clone()
343-
tempBalance.subtract(dailyRevenue)
344-
dailySupplySideRevenue.addBalances(tempBalance, METRIC.ASSETS_YIELDS)
345-
346373
return {
347374
dailyFees,
348375
dailyRevenue,
@@ -359,6 +386,7 @@ export function getCuratorExport(curatorConfig: CuratorConfig): SimpleAdapter {
359386
methodology,
360387
breakdownMethodology,
361388
adapter: exportObject,
389+
allowNegativeValue: true, // we allow negative fees for vaults because vaults can make yields or make loss too
362390
}
363391
}
364392

0 commit comments

Comments
 (0)