Skip to content
This repository has been archived by the owner on Jan 12, 2025. It is now read-only.

Matin - The emergencyWithdraw() lacks the harvest function, leading to loss of rewards #536

Closed
sherlock-admin3 opened this issue Jul 15, 2024 · 1 comment
Labels
Non-Reward This issue will not receive a payout

Comments

@sherlock-admin3
Copy link
Contributor

sherlock-admin3 commented Jul 15, 2024

Matin

Medium

The emergencyWithdraw() lacks the harvest function, leading to loss of rewards

Summary

The absence of the harvesting mechanism in emergencyWithdraw() can lead to significant loss of accumulated rewards for users who invoke this function. This impacts users' earnings and diminishes the overall attractiveness of the staking mechanism, as users cannot retrieve the rewards they have earned up to the emergency withdrawal point.

Vulnerability Detail

The emergencyWithdraw() function in the contract MlumStaking is designed to allow stakers to withdraw their staked tokens during emergencies.
However, it does not call the _harvestPosition() function before withdrawing the tokens. This means that any accrued rewards up to that point are not claimed and are consequently lost.
As we can see in the contract, all the important functions responsible for depositing and withdrawing staked tokens call the _harvestPosition() to accrue the reward tokens.
The emergencyWithdraw() function, at its heart destroys the position (burns the corresponding NFT) and ignores all the accumulated rewards:

    function emergencyWithdraw(uint256 tokenId) external override nonReentrant {
        _requireOnlyOwnerOf(tokenId);

        StakingPosition storage position = _stakingPositions[tokenId];

        // position should be unlocked
        require(
            _unlockOperators.contains(msg.sender)
                || (position.startLockTime + position.lockDuration) <= _currentBlockTimestamp() || isUnlocked(),
            "locked"
        );
        // emergencyWithdraw: locked

        uint256 amount = position.amount;

        // update total lp supply
        _stakedSupply = _stakedSupply - amount;
        _stakedSupplyWithMultiplier = _stakedSupplyWithMultiplier - position.amountWithMultiplier;

        // destroy position (ignore boost points)
        _destroyPosition(tokenId);

        emit EmergencyWithdraw(tokenId, amount);
        stakedToken.safeTransfer(msg.sender, amount);
    }

The lack of harvesting the accumulated rewards would lead to loss of the accumulated reward tokens inside the contract 'MlumStaking`.

Impact

Loss of reward tokens during emergency withdrawing

Proof of Concept

Alice has been staking her tokens in a reward-generating pool for several weeks. During this period, she accumulates significant rewards due to the pool's incentive structure.

  1. Alice stakes 100 tokens.
  2. Over 4 weeks, she accumulates 20 reward tokens.
  3. An unforeseen event causes Alice to urgently need her staked tokens. She wrongly calls the emergencyWithdraw() function to retrieve her 100 tokens.
  4. The emergencyWithdraw() function withdraws her staked tokens but does not call the harvest function.
  5. As a result, the 20 accumulated reward tokens remain unclaimed and are lost.

Alice loses the 20 reward tokens she earned over 4 weeks, impacting her total earnings and reducing the benefits of her participation in the staking pool.

Code Snippet

The Function emergencyWithdraw()

Tool used

Manual Review

Recommendation

Consider calling the _harvestPosition() before destroying the position inside the function emergencyWithdraw() in MlumStaking.

@github-actions github-actions bot added the Excluded Excluded by the judge without consulting the protocol or the senior label Jul 21, 2024
@0xSmartContract 0xSmartContract added Medium A Medium severity issue. Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label and removed Excluded Excluded by the judge without consulting the protocol or the senior labels Jul 27, 2024
@sherlock-admin4 sherlock-admin4 changed the title Kind Spruce Ant - The emergencyWithdraw() lacks the harvest function, leading to loss of rewards Matin - The emergencyWithdraw() lacks the harvest function, leading to loss of rewards Jul 29, 2024
@sherlock-admin4 sherlock-admin4 added the Reward A payout will be made for this issue label Jul 29, 2024
@WangSecurity WangSecurity removed Medium A Medium severity issue. Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label labels Aug 20, 2024
@sherlock-admin2 sherlock-admin2 added Non-Reward This issue will not receive a payout and removed Reward A payout will be made for this issue labels Aug 20, 2024
@WangSecurity
Copy link

Invalid based on the discussion under #460

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Non-Reward This issue will not receive a payout
Projects
None yet
Development

No branches or pull requests

5 participants