code-423n4 / 2024-03-abracadabra-money-findings

9 stars 7 forks source link

Users can be griefed by staking unlocked dust amounts on their behalf #187

Closed c4-bot-7 closed 8 months ago

c4-bot-7 commented 8 months ago

Lines of code

https://github.com/code-423n4/2024-03-abracadabra-money/blob/1f4693fdbf33e9ad28132643e2d6f7635834c6c6/src/staking/LockingMultiRewards.sol#L458-L477

Vulnerability details

Impact

and when the griefed user rewards are updated via _updateRewardsForUser(), the userRewardPerTokenPaid[user] will be set to the latest rewardPerToken_ , so when the griefed user calls any of the stake,withdraw or getRewards functions; the updated rewards will be less than he's entitled to because pendingUserRewardsPerToken = rewardPerToken_ - userRewardPerTokenPaid[user] = 0 (as long as the rewardPerToken hasn't been updated yet).

Proof of Concept

LockingMultiRewards._stakeFor function

function _stakeFor(address account, uint256 amount, bool lock_) internal {
        if (amount == 0) {
            revert ErrZeroAmount();
        }

        // This staking contract isn't using balanceOf, so it's safe to transfer immediately
        stakingToken.safeTransferFrom(msg.sender, address(this), amount);
        stakingTokenBalance += amount;

        _updateRewardsForUser(account);

        if (lock_) {
            _createLock(account, amount);
        } else {
            _balances[account].unlocked += amount;
            unlockedSupply += amount;

            emit LogStaked(account, amount);
        }
    }

Tools Used

Manual Review.

Recommended Mitigation Steps

Add a minimum staking amount for unlocked stakes similar to the minLockAmount used to check when creating locked stakes:

function _stakeFor(address account, uint256 amount, bool lock_) internal {
        if (amount == 0) {
            revert ErrZeroAmount();
        }

        // This staking contract isn't using balanceOf, so it's safe to transfer immediately
        stakingToken.safeTransferFrom(msg.sender, address(this), amount);
        stakingTokenBalance += amount;

        _updateRewardsForUser(account);

        if (lock_) {
            _createLock(account, amount);
        } else {
+           require(amount >= minUnlockedStakedAmount,"invalid staking amount");
            _balances[account].unlocked += amount;
            unlockedSupply += amount;

            emit LogStaked(account, amount);
        }
    }

Assessed type

Context

0xm3rlin commented 8 months ago

seems like minimal gas implications

c4-pre-sort commented 8 months ago

141345 marked the issue as insufficient quality report

141345 commented 8 months ago

stake dust amt for other users, seems expected behavior, no loss

thereksfour commented 8 months ago

Invalid, the user's rewards are accrued in rewards[][]

c4-judge commented 8 months ago

thereksfour marked the issue as unsatisfactory: Invalid