Within the FjordStaking#claimReward(), the penaltyAmount is supposed to be deducted from the rewardAmount only when a user claim early.
However, within the FjordStaking#claimReward(), the penaltyAmount would be deducted from the rewardAmount even when a user does not claim early (which the user claim after the reward cooldown period elapsed).
When a user would receive the rewards from their staking, the user would call the FjordStaking#claimReward().
Within the FjordStaking#claimReward(), the half of the rewardAmount (rewardAmount / 2) would be stored into the penaltyAmount.
Then, the penaltyAmount would be subtracted from the rewardAmount (rewardAmount -= penaltyAmount).
Finally, the rewardAmount left (subtracted) would be transferred to the user (msg.sender) like this:
https://github.com/Cyfrin/2024-08-fjord/blob/main/src/FjordStaking.sol#L645-L646
https://github.com/Cyfrin/2024-08-fjord/blob/main/src/FjordStaking.sol#L654
According to the NatSpec of the FjordStaking#claimReward() above, the penalty is supposed to be applied to the user's rewards - if the user would claim earlier than the cooldown period of 3 epochs (21 days) like this:
/// if the user chooses to bypass the reward cooldown of 3 epochs,
/// then reward penalty will be levied.
Also, according to the diagram of the "Rewards Issuance" in the code walkthrough (and discord), only when a user would claim early (< 21 days), 50% of rewardAmount is supposed to be sent to the xFJO stakers as a penalty.
However, within the FjordStaking#claimReward(), the penaltyAmount would always be subtracted from the rewardAmount - even if a user would not claim early (which the user claim after the reward cooldown period elapsed)
This lead to unintended-situation that even if a user would not claim early, the penaltyAmount would be subtracted from the rewardAmount of the user.
As a result, the user would receive only 50% of the rewardAmount (in other words, the user would lose the 50% of the rewardAmount that the user was supposed to receive) - even though the user would claim after the reward cooldown period elapsed (which does not claim early).
The severity of this vulnerability should be considered as a "High". Because sophisticated users, who claim their rewards after the cooldown period elapsed, would always lose 50% of their rewardAmount.
Foundry
Within the FjordStaking#claimReward(), consider adding the else block to the if (_isClaimEarly == True) block.
Then, consider moving the penaltyAmount calculation and the penaltyAmount deduction (from the rewardAmount) to the else block - so that the penaltyAmount would be applied (deducted from the rewardAmount) only when a user claim early like this:
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.