Summary
These contracts (BaseGauge, GaugeController) use veToken.balanceOf() instead of getVotingPower(). This ignores lock expiration decay, leading to incorrect boost and voting power calculations.
Vulnerability Details
The use of balanceOf() instead of getVotingPower() creates significant calculation discrepancies in the protocol.
In BaseGauge.sol#_applyBoost
function _applyBoost(address account, uint256 baseWeight) internal view virtual returns (uint256) {
IERC20 veToken = IERC20(IGaugeController(controller).veRAACToken());
uint256 veBalance = veToken.balanceOf(account);
In GaugeController.sol#vote
function vote(address gauge, uint256 weight) external override whenNotPaused {
uint256 votingPower = veRAACToken.balanceOf(msg.sender);
Economic Impact:
Boost calculations provide wrong multipliers
Reward distributions become inequitable
Incentive mechanisms fail to reward lock duration
Protocol revenue sharing becomes imbalanced
Impact
Users have no incentive to lock longer
Tools Used
Manual
Recommendations
Replace the instances of balanceOf with getVotingPower(account, block.timestamp) to reflect actual voting power.
function _applyBoost(address account, uint256 baseWeight) internal view returns (uint256) {
uint256 votingPower = veToken.getVotingPower(account, block.timestamp);
uint256 totalVotingPower = veToken.getTotalVotingPower();
return calculateBoost(votingPower, totalVotingPower, baseWeight);
}
function vote(address gauge, uint256 weight) external whenNotPaused {
uint256 votingPower = veToken.getVotingPower(msg.sender, block.timestamp);
_updateGaugeWeight(gauge, weight, votingPower);
}
function calculateBoost(address user, address pool, uint256 amount) external view returns (uint256) {
uint256 votingPower = veToken.getVotingPower(user, block.timestamp);
return _calculateBoost(votingPower, amount);
}