Skip to content

FIX guard against vault share price rebase in curator fee calculations#6332

Closed
SissonJ wants to merge 1 commit intoDefiLlama:masterfrom
Gauntlet-xyz:fix-gauntlet-fees
Closed

FIX guard against vault share price rebase in curator fee calculations#6332
SissonJ wants to merge 1 commit intoDefiLlama:masterfrom
Gauntlet-xyz:fix-gauntlet-fees

Conversation

@SissonJ
Copy link
Copy Markdown

@SissonJ SissonJ commented Apr 3, 2026

Summary

  • Fixes a case in getMorphoVaultFee, getEulerVaultFee, and getMorphoVaultV2Fee where a vault
    share price rebase (i.e. rateAfter < rateBefore) would cause false negative fee reporting
  • When rateAfter <= rateBefore, the growth rate is now set to 0n — reporting zero fees is
    preferable to reporting a false negative

Root cause

When a Morpho/Euler vault undergoes a share price rebase, rateAfter can be less than rateBefore.
The original subtraction rateAfter - rateBefore results in incorrect fee reports with an adjustment. Under normal vault operation, share price constantly goes up, so this case was left unchecked

Test plan

  • Run pnpm test fees gauntlet 2026-04-01 and confirm no negative values

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 3, 2026

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Fixed vault fee and interest yield calculations to prevent negative amounts in scenarios where rates do not increase.

Walkthrough

The computation of growthRate in three vault fee calculation functions was modified to conditionally return 0n instead of allowing negative values. When the rate after is not greater than the rate before, the growth rate now evaluates to zero, preventing negative fee calculations in rebased scenarios.

Changes

Cohort / File(s) Summary
Growth Rate Calculation Logic
helpers/curators/index.ts
Modified growthRate computation in getMorphoVaultFee, getEulerVaultFee, and getMorphoVaultV2Fee to conditionally return 0n when rateAfter <= rateBefore, preventing negative growth-based yields.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested labels

helper, methodology, bug-fix

🚥 Pre-merge checks | ❌ 6

❌ Failed checks (4 warnings, 2 inconclusive)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title does not follow the required format [type] protocol-name - description; it uses 'FIX' instead of a bracketed type and lacks a specific protocol name. Reformat the title to follow the specified pattern, for example: '[FIX] morpho-euler - guard against vault share price rebase in curator fee calculations'
Description check ⚠️ Warning The PR description does not match the repository's template, which is designed for new protocol listings with fields like name, TVL, audit links, and category; this PR is a code fix with a different structure. Either adapt the description to match the template structure or clarify that this PR template is only applicable to protocol listing submissions, not code fixes.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 50.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Breakdown Methodology Check ⚠️ Warning METRICS.EulerPerformanceFee and METRICS.EulerYieldsToSuppliers are used in .add() calls but missing from breakdownMethodology object. Add EulerPerformanceFee and EulerYieldsToSuppliers entries to breakdownMethodology; replace unused OtherAssetYieldsToSuppliers with EulerYieldsToSuppliers.
Income Statement Compliance ❓ Inconclusive Unable to access helpers/curators/index.ts file content; cannot verify income statement compliance formula. Provide the file content or code repository access to verify dailyRevenue = dailyFees - dailySupplySideRevenue.
Version 2 Required ❓ Inconclusive Unable to determine the nature and scope of changes due to missing context and files. Provide the actual file changes, git diff, or file contents to assess whether this is a new adapter, an update to an existing adapter, or out-of-scope changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
helpers/curators/index.ts (2)

22-40: 🧹 Nitpick | 🔵 Trivial

Add JSDoc comments for exported functions and interfaces.

The exported entities CuratorConfig, getEulerVaultFee, and getCuratorExport lack JSDoc documentation. As per coding guidelines, public functions in helper files should include JSDoc comments to document purpose, parameters, return types, and important behavior (such as the rebase handling introduced in this PR).

📝 Example JSDoc structure
+/**
+ * Configuration for curator vault fee tracking
+ * `@property` methodology - Optional methodology description for the adapter
+ * `@property` breakdownFees - Whether to break down fees by source (Morpho/Euler)
+ * `@property` vaults - Vault addresses and owners by chain
+ */
 export interface CuratorConfig {
   methodology?: any;
   breakdownFees?: boolean;
+/**
+ * Calculate fees for Euler vaults
+ * `@param` options - Fetch options with API and time range
+ * `@param` balances - Balances object to accumulate fees, revenue, and supply-side revenue
+ * `@param` vaults - Array of Euler vault addresses
+ * `@param` breakdownFees - Whether to label fees by source
+ * `@remarks` When vault share price rebases (rateAfter <= rateBefore), growth rate is set to 0
+ */
 export async function getEulerVaultFee(options: FetchOptions, balances: Balances, vaults: Array<string>, breakdownFees?: boolean) {
+/**
+ * Generate a fees adapter for curator vaults
+ * `@param` curatorConfig - Configuration specifying vaults and owners per chain
+ * `@returns` SimpleAdapter configured to track curator fees across Morpho and Euler vaults
+ * `@remarks` Handles vault share price rebases by clamping negative growth to zero
+ */
 export function getCuratorExport(curatorConfig: CuratorConfig): SimpleAdapter {

As per coding guidelines: "Include JSDoc comments for public functions in helper files"

Also applies to: 244-244, 336-336

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@helpers/curators/index.ts` around lines 22 - 40, The CuratorConfig interface
and exported functions getEulerVaultFee and getCuratorExport are missing JSDoc;
add JSDoc comments above each exported symbol (CuratorConfig, getEulerVaultFee,
getCuratorExport) describing their purpose, parameters/types (e.g., explain
vaults shape, start type, morpho/euler arrays), return values, and any important
behavior such as rebase handling/assumptions or optional fields (breakdownFees,
vault owner arrays). Ensure the comments include parameter descriptions and
return type information and mention edge cases (e.g., how rebase is handled) so
consumers and tooling (TS/IDE) get clear documentation.

403-403: 🧹 Nitpick | 🔵 Trivial

Update the comment at line 403 to reflect the actual behavior after growthRate clamping.

The review comment correctly identifies that growthRate is now clamped to 0n (lines 218, 255, 303), which ensures all fee calculations from vault yields are non-negative. The original comment "we allow negative fees for vaults because vaults can make yields or make loss too" no longer accurately describes the behavior—losses now result in zero fees, not negative fees.

Consider either:

  1. Removing the flag if curator-based adapters don't have independent negative fee sources
  2. Updating the comment to reflect the new clamping logic: "we allow negative fees from secondary revenue sources that dependent adapters may include (e.g., asset liquidation costs, rewards that exceed base yields)"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@helpers/curators/index.ts` at line 403, The comment on allowNegativeValue
should be updated to reflect that growthRate is clamped to 0n (see growthRate
clamp occurrences at lines where growthRate is set) so vault yields cannot
produce negative fees; change the comment on the allowNegativeValue flag to
either remove it if curator-based adapters truly have no other negative-fee
sources, or revise it to explain that negative fees are only allowed for
secondary/independent revenue sources (e.g., asset liquidation costs or reward
accounting) and not from growthRate-derived vault yields which are clamped to
zero.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@helpers/curators/index.ts`:
- Around line 22-40: The CuratorConfig interface and exported functions
getEulerVaultFee and getCuratorExport are missing JSDoc; add JSDoc comments
above each exported symbol (CuratorConfig, getEulerVaultFee, getCuratorExport)
describing their purpose, parameters/types (e.g., explain vaults shape, start
type, morpho/euler arrays), return values, and any important behavior such as
rebase handling/assumptions or optional fields (breakdownFees, vault owner
arrays). Ensure the comments include parameter descriptions and return type
information and mention edge cases (e.g., how rebase is handled) so consumers
and tooling (TS/IDE) get clear documentation.
- Line 403: The comment on allowNegativeValue should be updated to reflect that
growthRate is clamped to 0n (see growthRate clamp occurrences at lines where
growthRate is set) so vault yields cannot produce negative fees; change the
comment on the allowNegativeValue flag to either remove it if curator-based
adapters truly have no other negative-fee sources, or revise it to explain that
negative fees are only allowed for secondary/independent revenue sources (e.g.,
asset liquidation costs or reward accounting) and not from growthRate-derived
vault yields which are clamped to zero.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1e7a188b-bf85-40ba-ad60-7f68930581fd

📥 Commits

Reviewing files that changed from the base of the PR and between 48b81b3 and 48b454b.

📒 Files selected for processing (1)
  • helpers/curators/index.ts

@SissonJ
Copy link
Copy Markdown
Author

SissonJ commented Apr 3, 2026

Instead of setting growthRate to 0 when a share price rebase is detected, we could develop a function that queries more granular data for the vault and calculates the growthRate before the share price rebase and after, retaining the data quality in the affected bucket

@noateden
Copy link
Copy Markdown
Contributor

noateden commented Apr 4, 2026

hi @SissonJ we want to track negative impact on vault. When the price shares were reduced, that incurred loss for depositors

@noateden noateden closed this Apr 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants