The RAAC Protocol’s governance and reward mechanisms rely on the accurate measurement of users’ voting power, which is time-weighted due to decay and incremental changes from additional token locks. However, in the veRAACToken
contract and related modules (GaugeController, BoostCalculator, BaseGauge, BoostController, etc.), the balanceOf
function is used in lieu of the correct getVotingPower
function. The balanceOf
function returns a stale, non-time-weighted balance, whereas getVotingPower
computes the current, time-weighted voting power based on decay and lock duration.
This misimplementation propagates across multiple functions:
Minting and Burning: In the increase
and extend
functions, using balanceOf(msg.sender)
instead of getVotingPower(msg.sender)
leads to an incorrect calculation of new vs. old voting power. Consequently, users receive an excessive number of veRAAC tokens (or have too many burned) during lock modifications.
Reward Distribution and Boost Calculation: Functions such as calculateBoost
, getCurrentBoost
, and getLockPosition
use the stale balance, leading to distorted boost factors and erroneous reward allocations.
Governance & Voting: Modules like GaugeController::vote
, BaseGauge::_applyBoost
, and BaseGauge::voteDirection
depend on these miscalculated values, which can undermine governance decisions and quorum calculations.
The root cause is the widespread use of balanceOf
to determine a user’s voting power, despite the existence of a correct helper function getVotingPower
that applies the decay slope and time-weighting. This oversight severely undermines the protocol’s tokenomics and the fairness of its incentive and governance mechanisms.
balanceOf
vs. getVotingPower
In several key functions, the contract uses balanceOf
to fetch a user’s veRAAC token balance. However, because veRAAC tokens are subject to a decay mechanism over time, the “raw” balance from balanceOf
does not accurately reflect a user’s current voting power. The correct approach is to use the getVotingPower
function, which calculates the time-weighted balance:
Below are specific examples where balanceOf
is misused:
veRAACToken::increase
:
Issue: The non-time-weighted balance causes excessive minting when new veRAAC tokens are issued, distorting the user’s effective voting power.
veRAACToken::extend
:
Issue: Using balanceOf
here results in an inaccurate comparison, potentially causing improper burning or minting actions.
veRAACToken::calculateBoost
:
veRAACToken::getCurrentBoost
:
veRAACToken::getLockPosition
:
Issue: All of the above lead to misrepresentations in boost factors, resulting in inaccurate reward distribution and misaligned governance weight.
balanceOf
Several other functions in related modules contain similar issues:
GaugeController::vote:
BoostCalculator::calculateBoost:
BaseGauge::_applyBoost:
BaseGauge::voteDirection:
BoostController::delegateBoost & _calculateBoost:
Similar issues occur where balanceOf
is used to gauge the user’s boost balance.
Furthermore, the veRAACToken::getTotalVotingPower
function returns totalSupply()
which can be stale because veRAAC tokens are rebasable. An internal helper to update each user's voting power dynamically is needed.
The following Foundry test suite demonstrates how the misuse of balanceOf
leads to incorrect and stale voting power values across the contract, thereby affecting minting, burning, and reward calculations.
Create a Foundry Project:
Remove Unnecessary Files:
Delete any extraneous files to streamline the project.
Convert Your Hardhat Project (if applicable):
Move your contracts into the src
directory.
Create Test and Mocks Folders:
Create a test
directory (adjacent to src
) and a mocks
directory if needed.
Add the Test Suite:
In the test
directory, create a test file (e.g., VeRAACTokenTest.t.sol
) and paste the above test suite.
Run the Test:
Execute:
Expected Output:
The output should reveal that the values retrieved using balanceOf
are stale compared to those computed by getVotingPower
, confirming the vulnerability. For example, you might see:
Incorrect Minting and Burning of veRAACTokens:
Users may receive an inflated number of veRAACTokens when increasing or extending their locks, thereby distorting their effective voting power and skewing governance outcomes.
Inaccurate Reward Distribution:
Boost and reward calculations based on stale voting power lead to unfair reward allocations. Some users may receive rewards far beyond their entitlement while others are undercompensated.
Governance Manipulation and Quorum Distortion:
Misrepresenting users’ voting power undermines the integrity of governance. Voting and quorum calculations become unreliable, potentially enabling attackers to dominate decision-making or block legitimate proposals.
Misrepresentation of User Lock Positions:
Functions like getLockPosition
return outdated information, leading users to make poor decisions based on incorrect data.
Overall Protocol Instability:
The systemic reliance on stale data can destabilize multiple layers of the protocol—from tokenomics and reward distribution to governance and boost mechanics.
Manual Review
Foundry
Console Log (Foundry)
To mitigate this vulnerability, all instances where balanceOf
is used to obtain a user’s voting power must be replaced with getVotingPower
. Additionally, any function retrieving total supply values (which are subject to decay and rebase) should use an updated mechanism that reflects current voting power.
veRAACToken::increase
:veRAACToken::extend
:veRAACToken::calculateBoost
:veRAACToken::getCurrentBoost
:veRAACToken::getLockPosition
:GaugeController::vote
:BoostCalculator::calculateBoost
:BaseGauge::_applyBoost
:BaseGauge::voteDirection
:BoostController::delegateBoost
and _calculateBoost
:Replace any instance of veToken.balanceOf(user)
and veToken.totalSupply()
with the corresponding updated functions that reflect current, time-weighted voting power.
Additional Check:
For thelock
andincrease
functions, implement a check to enforce the maximum total locked amount cap:
Implementing these modifications ensures that all functions throughout the protocol use the correct, time-weighted voting power for all calculations, thereby preserving the integrity of minting/burning, reward allocation, and governance mechanisms.
By addressing this critical issue, the RAAC Protocol can safeguard its tokenomics, ensure fair reward distribution, and maintain robust governance functionality based on accurate, up-to-date voting power metrics.
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.