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

Inability to Unstake with Reward Claiming as Documented (`FjordStaking::unstake`)

Description

The FjordStaking::unstake function is intended to allow users to unstake their tokens while also claiming any pending rewards. According to the documentation, users should be able to unstake tokens early by bypassing the reward cooldown period of 3 epochs, incurring a penalty. However, the current implementation does not provide this functionality. Instead, it strictly enforces the lock cycle and prevents any unstaking before the cycle is complete, which contradicts the documented behavior.

Additionally, the NatSpec comments mention a _isEarly parameter that should allow users to bypass the lock cycle with a penalty. However, this parameter does not exist in the function’s signature or implementation, further deviating from the documented intent and potentially misleading users and developers.

Impact

This issue has a high severity because it directly impacts the user experience and contract functionality. Users are unable to claim rewards and unstake their tokens simultaneously, which might lead to a lack of trust in the protocol and potential financial losses if users are forced to keep their tokens locked for longer than expected. The discrepancy between the documentation and the actual implementation also increases the risk of incorrect usage or reliance on non-existent features.

Proof of Concepts

The following code snippet from the FjordStaking::unstake function illustrates the issue:

if (currentEpoch != _epoch) {
// _epoch less than current epoch then user can unstake after at complete lockCycle
if (currentEpoch - _epoch <= lockCycle) revert UnstakeEarly();
}

The above code enforces the lock cycle strictly, preventing any unstaking before the lock cycle is complete. This contradicts the documented functionality that suggests users can claim reward early with a penalty.

Furthermore, the NatSpec documentation suggests a non-existent _isEarly parameter should allow users to bypass the rewards cooldown:

/// @dev This function allows users to unstake a certain number of FJORD tokens,
/// while also claiming all the pending rewards. If _isEarly is true then the
/// user will be able to bypass rewards cooldown of 3 epochs and claim early,
/// but will incur early claim penalty.

This _isEarly parameter is not implemented, leading to further confusion and misalignment between the code and its documentation.

In contrast, the FjordStaking::claimReward function includes logic for handling early claims with a penalty:

if (!_isClaimEarly) {
claimReceipts[msg.sender] = ClaimReceipt({
requestEpoch: currentEpoch,
amount: ud.unclaimedRewards
});
emit ClaimReceiptCreated(msg.sender, currentEpoch);
return (0, 0);
}
rewardAmount = ud.unclaimedRewards;
penaltyAmount = rewardAmount / 2;
rewardAmount -= penaltyAmount;

The FjordStaking::claimReward function allows users to claim rewards early with a penalty, but similar functionality is missing in the unstake function, making it impossible to claim rewards and unstake simultaneously under the conditions implied by the documentation.

Recommended Mitigation

  1. Code Modification: Update the FjordStaking::unstake function to include a similar penalty mechanism as found in FjordStaking::claimReward. This would involve checking whether the unstake is occurring within the lock cycle, applying a penalty to the rewards, and allowing the unstake to proceed.

  2. Parameter Implementation: Consider implementing the _isEarly parameter as suggested in the documentation, ensuring that users can choose to unstake early with the corresponding penalty applied.

  3. Documentation Update: If strict enforcement of the lock cycle is the intended behavior, update the documentation to reflect this. The documentation should clearly state that early unstaking is not allowed under any circumstances, thereby avoiding any confusion for the users.

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.