Core Contracts

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

Incorrect reward calculation based on veToken balance allows reward manipulation

Relevant Context

The BaseGauge contract implements a staking mechanism with boosted rewards based on veToken (voting escrow token) balances. Users can stake tokens and earn rewards, with their reward rate being boosted based on their veToken holdings.

Finding Description

In BaseGauge#earned, rewards are calculated using getUserWeight which depends on the user's veToken balance rather than their staked token balance. The boost multiplier in _applyBoost is correctly calculated, but it's being applied to a base weight that doesn't consider the user's actual stake.

The _getBaseWeight function returns the gauge's global weight from the controller instead of the user's staked balance. This means rewards are proportional to veToken holdings regardless of how many tokens are actually staked in the gauge.

Impact Explanation

High. Users can exploit this to earn disproportionate rewards by:

  1. Staking minimal amounts in the gauge

  2. Holding large amounts of veToken
    This leads to unfair reward distribution and potential drain of reward tokens.

Likelihood Explanation

High. The economic incentive is significant, and the exploitation requires no special conditions or complex setup - just holding veToken and making a minimal stake.

Proof of Concept

  1. Alice stakes 1 token in the gauge

  2. Bob stakes 1000 tokens in the gauge

  3. Alice holds 1000 veTokens

  4. Bob holds 1 veToken

  5. Despite Bob having 1000x more staked tokens, Alice earns more rewards due to her higher veToken balance

The key issue can be seen in the reward calculation flow:

  • earned calls getUserWeight

  • getUserWeight gets base weight from _getBaseWeight which returns global gauge weight

  • _applyBoost multiplies this by veToken-based boost

  • User's actual stake (_balances[account]) is never considered

Recommendation

Modify _getBaseWeight to return the user's staked balance:

function _getBaseWeight(address account) internal view virtual returns (uint256) {
// Use staked balance as base weight instead of global gauge weight
return _balances[account];
}

This ensures rewards are primarily based on staked amounts, with veToken balance only affecting the boost multiplier as intended.

Updates

Lead Judging Commences

inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Validated
Assigned finding tags:

BaseGauge::earned calculates rewards using getUserWeight instead of staked balances, potentially allowing users to claim rewards by gaining weight without proper reward checkpoint updates

inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Validated
Assigned finding tags:

BaseGauge::earned calculates rewards using getUserWeight instead of staked balances, potentially allowing users to claim rewards by gaining weight without proper reward checkpoint updates

Support

FAQs

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