The FeeCollector.sol contract's reward distribution mechanism has a critical flaw in how it calculates user reward shares. While a user's voting power naturally decays over their lock period, this decaying power is compared against the non-decaying total supply of veRAAC tokens when determining reward shares. This mismatch causes users to receive disproportionately smaller rewards as their locks ages, effectively punishing long-term holders and resulting in protocol fees becoming permanently locked in the contract.
The vulnerability stems from a mismatch between how voting power decays and how rewards are calculated in the FeeCollector's distribution mechanism. Let's examine how fees flow through the system and where they get trapped:
The distribution process follows these steps:
Protocol fees accumulate in the CollectedFees struct
When distributeCollectedFees() is called, it:
Calculates the total fees to distribute
Allocates 80% to veRAACToken holders based on voting power
Records these reward shares in the contract state
Deletes all collected fees with delete collectedFees
The critical issue emerges from how rewards are calculated versus how they're tracked:
Where:
userVotingPower = User's voting power that decays linearly over the lock period
totalVotingPower = Total supply of veRAAC tokens which does not decay
Consider a user who locks 1000 RAAC tokens for 2 years:
At lock creation (t=0):
Voting Power = 500 (scaled based on lock duration)
veRAAC Total Supply = 1000
Reward Share = 500/1000 = 50% of rewards
Near lock expiry (t=700 days):
Voting Power ≈ 15.75 (due to linear decay)
veRAAC Total Supply = still 1000 (no decay)
Reward Share = 15.75/1000 = 1.575% of rewards
Because distributeCollectedFees() deletes all fee records after calculating these diminished rewards:
Each distribution cycle permanently locks away an increasing portion of protocol fees as locks age. This creates a compounding loss of value that should have been distributed to protocol participants.
High:
Severely penalizes long-term token holders by drastically reducing their rewards as their lock ages
Results in protocol fees becoming permanently trapped in the contract
Creates misaligned incentives that work against the protocol's goal of encouraging long-term holding
High - This issue will affect every user who locks tokens and every fee distribution event. The impact becomes more severe as locks age and will be particularly pronounced for longer lock durations.
Convert the project into a foundry project, ensuring test in foundry.toml points to a designated test directory.
Comment out the forking object from the hardhat.congif.cjs file:
Copy the following code into the test folder:
Run forge test -vv
Logs:
Compare against total actual voting power rather than total supply:
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.