DeFiFoundry
20,000 USDC
View results
Submission Details
Severity: low
Invalid

The management for adding reward should be more accurate.

Summary

For the FjordStaking contract, the rewards come from three sources: RewardAdmin addReward and the penalty amount if some stakers claim early or someone sends FJO tokens to FjordStaking.

Based on the calculation for the pendingRewards, No direct relationships between pendingRewardsand the input amount for the function addReward.

uint256 pendingRewards = (currentBalance + totalVestedStaked + newVestedStaked) - totalStaked - newStaked - totalRewards;

Supply one view function showing the pendingRewardscan help owner and user get more accurate pendingRewards Info

Vulnerability Details

Currently, the pendingRewards calculation is as below; there are no direct relationships between the pendingRewards and the input amount when calling addReward.

So, the pending rewards for the admin seem to be a random number for admin. It will be more beneficial for admin if one view function is added to supply the pendingRewards. Not only supply help when calling addReward, but also give the owner or the user the current situations for pendingRewards

uint256 pendingRewards = (currentBalance + totalVestedStaked + newVestedStaked) - totalStaked - newStaked - totalRewards;

// FjordStaking contract
function _checkEpochRollover() internal {
uint16 latestEpoch = getEpoch(block.timestamp);
if (latestEpoch > currentEpoch) {
//Time to rollover
currentEpoch = latestEpoch;
if (totalStaked > 0) {
uint256 currentBalance = fjordToken.balanceOf(address(this));
// no distribute the rewards to the users coming in the current epoch
uint256 pendingRewards = (currentBalance + totalVestedStaked + newVestedStaked)
- totalStaked - newStaked - totalRewards;
uint256 pendingRewardsPerToken = (pendingRewards * PRECISION_18) / totalStaked;
totalRewards += pendingRewards;
for (uint16 i = lastEpochRewarded + 1; i < currentEpoch; i++) {
rewardPerToken[i] = rewardPerToken[lastEpochRewarded] + pendingRewardsPerToken;
emit RewardPerTokenChanged(i, rewardPerToken[i]);
}
} else {
for (uint16 i = lastEpochRewarded + 1; i < currentEpoch; i++) {
rewardPerToken[i] = rewardPerToken[lastEpochRewarded];
emit RewardPerTokenChanged(i, rewardPerToken[i]);
}
}
totalStaked += newStaked;
totalVestedStaked += newVestedStaked;
newStaked = 0;
newVestedStaked = 0;
lastEpochRewarded = currentEpoch - 1;
}
}

Impact

Admin can't quickly get the accurate pending reward information if someone pays the penalty amount or others mistakenly send FJO tokens to FjordStaking.

Tools Used

Manual

Recommendations

  1. Create public view function pendingRewards.

  2. Apply calcPendingRewards in _checkEpochRollover.

function _checkEpochRollover() internal {
uint16 latestEpoch = getEpoch(block.timestamp);
if (latestEpoch > currentEpoch) {
//Time to rollover
currentEpoch = latestEpoch;
if (totalStaked > 0) {
// no distribute the rewards to the users coming in the current epoch
uint256 pendingRewards = calcPendingRewards();
uint256 pendingRewardsPerToken = (pendingRewards *
PRECISION_18) / totalStaked;
totalRewards += pendingRewards;
for (uint16 i = lastEpochRewarded + 1; i < currentEpoch; i++) {
rewardPerToken[i] =
rewardPerToken[lastEpochRewarded] +
pendingRewardsPerToken;
emit RewardPerTokenChanged(i, rewardPerToken[i]);
}
} else {
for (uint16 i = lastEpochRewarded + 1; i < currentEpoch; i++) {
rewardPerToken[i] = rewardPerToken[lastEpochRewarded];
emit RewardPerTokenChanged(i, rewardPerToken[i]);
}
}
totalStaked += newStaked;
totalVestedStaked += newVestedStaked;
newStaked = 0;
newVestedStaked = 0;
lastEpochRewarded = currentEpoch - 1;
}
}
function calcPendingRewards() public view returns (uint256) {
uint256 currentBalance = fjordToken.balanceOf(address(this));
uint256 pendingRewards = (currentBalance +
totalVestedStaked +
newVestedStaked) -
totalStaked -
newStaked -
totalRewards;
return pendingRewards;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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