Lucene search

K
code423n4Code4renaCODE423N4:2023-03-MUTE-FINDINGS-ISSUES-23
HistoryApr 03, 2023 - 12:00 a.m.

An edge case in amplifier allows user to stake after end time, causing reward to be locked in the contract

2023-04-0300:00:00
Code4rena
github.com
6
edge case
amplifier
staking
end time
rewards
contract
vulnerability
proof of concept
protocol
admin
mitigation

Lines of code

Vulnerability details

Proof of Concept

Observe that if nobody has staked after the period has ended, it’s still possible for a single user to stake even though the period has ended.
<https://github.com/code-423n4/2023-03-mute/blob/main/contracts/amplifier/MuteAmplifier.sol#L208-L212&gt;

        if (firstStakeTime == 0) {
            firstStakeTime = block.timestamp;
        } else {
            require(block.timestamp &lt; endTime, "MuteAmplifier::stake: staking is over");
        }

The staker can’t get any of the rewards because the update modifier won’t drip the rewards (since _mostRecentValueCalcTime = firstStakeTime >= endTime).
<https://github.com/code-423n4/2023-03-mute/blob/main/contracts/amplifier/MuteAmplifier.sol#L89-L95&gt;

        if (_mostRecentValueCalcTime == 0) {
            _mostRecentValueCalcTime = firstStakeTime;
        }

        uint256 totalCurrentStake = totalStake();

        if (totalCurrentStake &gt; 0 && _mostRecentValueCalcTime &lt; endTime) {
            ...
        }

At the same time, the protocol can’t withdraw the rewards with rescueToken either since there is a staker, and no reward has been claimed yet (so the following check fails).
<https://github.com/code-423n4/2023-03-mute/blob/main/contracts/amplifier/MuteAmplifier.sol#L187&gt;

        else if (tokenToRescue == muteToken) {
            if (totalStakers &gt; 0) {
                require(amount &lt;= IERC20(muteToken).balanceOf(address(this)).sub(totalRewards.sub(totalClaimedRewards)),
                    "MuteAmplifier::rescueTokens: that muteToken belongs to stakers"
                );
            }
        }

Impact

Suppose the staking period ends and nobody has staked. The admin would like to withdraw the rewards. A malicious user can front-run the rescueTokens call with a call to stake to lock all the rewards inside the contract indefinitely.

Tools Used

Manual Review

#Recommended Mitigation Steps
The require shouldn’t be inside the else block.


The text was updated successfully, but these errors were encountered:

All reactions