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

FJO stakers who locked less then six weeks can also get some share of penalty rewards.

Summary

For the design, the penalty rewards will be distributed to the FJO stakers who locked at least six weeks, but actually, the stakers who locked less than six weeks can also get some share of the penalty rewards.

Vulnerability Details

The scenario can occur in the situations below.

Steps:

1: Staker1 and staker2 stake 1 ether fjord token in epoch 1

2: RewardAdmin Add 1 ether reward and enter epoch 2

3: Staker1 claimReward ealry in epoch3

4: Staker2 claimReward ealry in epoch4

staker2 rewards calcuation: 2 ether rewards/ 2 ether staked = 1 ether rewards, claim early only get 0.5 ether fjo token

staker1 rewards calcuation:

like staker2 also have 1 ether rewards.

As staker2 claim early, 0.5 ether fjo token as pending rewards. For staker2, the new pending rewards will give him is 0.25 ether, another the same was given staker2

Now, the staker1 claim early in epoch4, actual rewards is (1+ 0.25)/2 = 0.625

POC

function test_POC_PenaltyRewardsForAnotherClaimRewardEearlyUser() public {
address staker1 = makeAddr("staker1");
address staker2 = makeAddr("staker2");
deal(address(token), staker1, 1 ether);
deal(address(token), staker2, 1 ether);
// user1 and user2 each stake 1 ether fjo token in epoch 1
vm.startPrank(staker1);
token.approve(address(fjordStaking), 1 ether);
fjordStaking.stake(1 ether);
vm.stopPrank();
vm.startPrank(staker2);
token.approve(address(fjordStaking), 1 ether);
fjordStaking.stake(1 ether);
vm.stopPrank();
// add 1 ether fjo token reward and enter epoch 2
skip(1 weeks);
vm.prank(minter);
fjordStaking.addReward(2 ether);
skip(1 weeks); // enter epoch 3, user1 claimReward early
vm.startPrank(staker2);
fjordStaking.claimReward(true);
vm.stopPrank();
console.log(
"staker2 claim reward early, get rewards: %d",
token.balanceOf(staker2)
);
skip(1 weeks); // enter epoch 4, user1 still claimReward early
vm.startPrank(staker1);
fjordStaking.claimReward(true);
vm.stopPrank();
console.log(
"staker1 still claim early, get rewards: %d",
token.balanceOf(staker1)
);
}

Impact

Users who stake less than six weeks can still get a share of the penalty rewards.

All the penalty rewards are not all distributed to the stakers who stake for at least six weeks.

Tools Used

Manual

Recommendations

1. PendingRewards balance calculation as below, so the penalty rewards will be part of the pending rewards, which will be distributed to the stakers still staked in the following epochs. And more will distribute the staker who stake at least six weeks. If logic dealing with stakers who stake less than six weeks will make the logic more complex.

uint256 currentBalance = fjordToken.balanceOf(address(this));
uint256 pendingRewards = (currentBalance +
totalVestedStaked +
newVestedStaked) -
totalStaked -
newStaked -
totalRewards;

2. It seems more rational to change the intro: the penalty rewards will contribute to the protocol's pending rewards, which will distribute the rewards to the stakers who still staked in the following eopchs. Stakers who stake at least six weeks not only get their whole rewards, but also get the penalty rewards with no discount.

Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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