Skip to content

fix: call distribute_fees in AccrueFees so junior LPs receive their fee multiplier - #73

Closed
0x-SquidSol wants to merge 1 commit into
dcccrypto:masterfrom
0x-SquidSol:fix/distribute-fees-never-called-in-accrue-fees
Closed

fix: call distribute_fees in AccrueFees so junior LPs receive their fee multiplier#73
0x-SquidSol wants to merge 1 commit into
dcccrypto:masterfrom
0x-SquidSol:fix/distribute-fees-never-called-in-accrue-fees

Conversation

@0x-SquidSol

Copy link
Copy Markdown
Contributor

Summary

math.rs::distribute_fees() was defined as part of the PERC-303 tranche feature but was never called anywhere. This meant the junior_fee_mult_bps parameter had zero effect on actual fee distribution:

Before (broken) After (fixed)
total_fees_earned += fee_delta (global) total_fees_earned += fee_delta (global)
junior_balance unchanged junior_balance += junior_fee from distribute_fees()
Senior captures 100% of fee delta Senior captures fee_delta - junior_fee
junior_fee_mult_bps has no effect Junior receives multiplied share as designed

Why This Matters

The tranche design explicitly states junior LPs take first-loss risk in exchange for a multiplied fee share (junior_fee_mult_bps). Without this fix:

  • Junior LPs absorb all losses (by design, already implemented)
  • Junior LPs receive no extra fees — the multiplier is dead code
  • This is a violation of the stated risk/reward trade-off that LP holders opted into when depositing as junior

How The Fix Works

After incrementing total_fees_earned by fee_delta, if tranches are active and junior LP supply > 0:

  1. Compute (junior_fee, _) = distribute_fees(junior_balance, senior_balance, junior_fee_mult_bps, fee_delta)
  2. junior_balance += junior_fee
  3. Senior implicitly receives fee_delta - junior_fee because senior_balance = total_pool_value() - junior_balance and total_pool_value() already includes the full fee_delta via total_fees_earned.

Pools without tranches are completely unaffected.

Test plan

  • All existing tests pass (cargo test)
  • Verify junior LP balance increases by multiplied share after AccrueFees
  • Verify senior LP balance increases by remainder after AccrueFees
  • Verify non-tranche pools are unaffected

…ee multiplier

math.rs::distribute_fees() was defined as part of the PERC-303 tranche
feature but was never called anywhere. This meant that even when a pool
had tranches enabled with junior_fee_mult_bps > 10000 (e.g. 2x), the
junior sub-pool never received any additional fee allocation:

- total_fees_earned increased by fee_delta (global pool value rises)
- junior_balance stayed unchanged
- senior_balance (= total_pool_value - junior_balance) captured the entire
  fee delta
- junior_fee_mult_bps had zero effect on actual fee distribution

This violates the stated invariant of the tranche feature: junior LPs
accept higher risk (absorb losses first) in exchange for a multiplied
fee share. Without this call, they take the risk but get no benefit.

Fix: after incrementing total_fees_earned by fee_delta, check if tranches
are active and call distribute_fees(junior_balance, senior_balance,
junior_fee_mult_bps, fee_delta) to compute the junior share, then
credit junior_balance with that share. Senior implicitly receives the
remainder because senior_balance is derived as total_pool_value() -
junior_balance and total_fees_earned already includes the full fee_delta.

Note: distribute_fees is only called when pool.tranche_enabled() and
junior_total_lp > 0, so non-tranche and purely-senior pools are
unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Apr 1, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@0x-SquidSol has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 23 minutes and 33 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 23 minutes and 33 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b54f5d81-2c72-4137-9170-28ef25e4223e

📥 Commits

Reviewing files that changed from the base of the PR and between 1881738 and 0514dbd.

📒 Files selected for processing (1)
  • src/processor.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@dcccrypto dcccrypto left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Security review — Call distribute_fees in AccrueFees so junior LPs receive fee multiplier. Prevents fee revenue from being silently lost. Security APPROVED ✅

@dcccrypto

Copy link
Copy Markdown
Owner

Superseded by PR#95 (merged) and PR#96 (omnibus test coverage). All changes in this PR are already in master. Closing as part of PERC-8433 cleanup.

@dcccrypto

Copy link
Copy Markdown
Owner

Implemented in PR #98 and merged to master. Thank you for identifying this vulnerability — the fix was applied based on your diff after two rounds of security review.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants