Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: high
Valid

Incorrect veRAACToken getTotalVotingPower() used throughout the protocol across multiple contracts

Description

getTotalVotingPower() is used across the protocol assuming it gives the current total voting power of the veRAACTokens:

File: contracts/core/tokens/veRAACToken.sol
559: /**
560: * @notice Gets the total voting power of all veRAAC tokens
561: * @dev Returns the total supply of veRAAC tokens
562: * @return The total voting power across all holders
563: */
564: function getTotalVotingPower() external view override returns (uint256) {
565:@---> return totalSupply();
566: }

But the function returns totalSupply() which is just the number of veRAACTokens minted. The voting power is determined by the lock duration remaining and decays over time. It could even be zero if the lock has expired.
Total voting power will always be equal to or less than totalSupply. More often than not, it would be lesser.

Impact

These are some of the areas affected by this miscalculation:

1. FeeCollector.sol

Location: _processDistributions() and _calculatePendingRewards() function

uint256 totalVeRAACSupply = veRAACToken.getTotalVotingPower();

Impact:

  • Incorrect calculation of fee distribution shares

  • Users receive larger shares than deserved based on raw token supply rather than actual voting power

  • Undermines the incentive to lock tokens for longer periods

2. Governance.sol

Location: quorum() function

function quorum() public view override returns (uint256) {
return (_veToken.getTotalVotingPower() * quorumNumerator) / QUORUM_DENOMINATOR;
}

Impact:

  • Incorrect calculation of governance quorum requirements

  • Makes reaching quorum harder than intended since actual voting power is lower than total supply

  • Could block legitimate governance actions

3. BoostCalculator.sol

Location: calculateBoost() function (called internally by Gauge contracts)

function calculateBoost(
uint256 veBalance,
uint256 totalVeSupply,
BoostParameters memory params
) internal pure returns (uint256)

Impact:

  • Incorrect calculation of boost multipliers

  • Users receive higher boost than deserved based on undecayed total supply

  • Affects reward distributions and incentive mechanics

4. BaseGauge.sol

Location: _updateReward() function (called by updateReward() modifier which is applied on critical functions like stake(), withdraw(), getReward(), etc.)

  • Call sequence: _updateReward() --> earned() --> getUserWeight() --> _applyBoost() --> directly uses veToken.totalSupply()

function _applyBoost(
address account,
uint256 baseWeight
) internal view virtual returns (uint256)

Impact:

  • Incorrect calculation of boost & reward

Mitigation

Implement a code which calculates the actual current total voting power which should be the sum of each user's current voting power. A snapshot based system could be used, something akin to the getPastTotalSupply() function inside PowerCheckpoint.sol library which is already imported in veRAACToken.sol.

Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Validated
Assigned finding tags:

veRAACToken::getTotalVotingPower returns non-decaying totalSupply while individual voting powers decay, causing impossible governance quorums and stuck rewards in FeeCollector

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Validated
Assigned finding tags:

veRAACToken::getTotalVotingPower returns non-decaying totalSupply while individual voting powers decay, causing impossible governance quorums and stuck rewards in FeeCollector

Appeal created

t0x1c Submitter
about 1 month ago
inallhonesty Lead Judge
about 1 month ago
inallhonesty Lead Judge 27 days ago
Submission Judgement Published
Validated
Assigned finding tags:

veRAACToken::getTotalVotingPower returns non-decaying totalSupply while individual voting powers decay, causing impossible governance quorums and stuck rewards in FeeCollector

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.