BaseGauge::_applyBoost returns an 1e4 boosted value instead of an 1e18 value, reducing the amount of rewards users receive.
BaseGauge::_applyBoost() should calculate the user's boosted amount eligible for rewards.
BoostCalculator.calculateBoost function calculates the boost multiplier based on the veToken balances and min/maxBoost.
It returns a boost value in basis points.
Then, the boost is multiplied by baseWeight and divided by 1e18.
baseWeight is an 1e18 amount. The returned boosted amount returned by getUserWeight is in basis points: 1e18 * 1e4 / 1e18. (1)
The boosted amount is multiplied by getRewardPerTokenreturned value.
For simplicity let's consider userStates[account].rewardPerTokenPaid == 0 and userStates[account].rewards == 0.
The earned function can be simplified to : getUserWeight(account) * getRewardPerToken() / 1e18
Let's examine the precision of the value returned by getRewardPerToken :
Again, for simplicity let's suppose rewardPerTokenStored == 0.
rewardRate represents the reward amount per second, in rewardToken precision, updated when notifyRewardAmount is called.
Supposing both rewardToken and stakingToken have 18 decimals, then getRewardPerToken returns an 1e18 value : deltaTime * rewardRate * 1e18 / totalSupply(). (2).
From (1) and (2) it can be conclude that earned function returns an amount with 4 decimal precision.
Instead it should return an amount with 18 decimals.
This value is saved in state.rewards and claimed by user.
Users receive less rewards.
If both stakingToken and rewardToken used have 18 decimals, _applyBoost must be updated to return an 1e18 amount.
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.