sherlock-audit / 2024-07-kwenta-staking-contracts-judging

1 stars 0 forks source link

Modern Grape Bull - There may be a dust amount of USDC/kwenta remaining in the contract, where kwenta will be permanently stuck #175

Closed sherlock-admin4 closed 1 month ago

sherlock-admin4 commented 1 month ago

Modern Grape Bull

Low/Info

There may be a dust amount of USDC/kwenta remaining in the contract, where kwenta will be permanently stuck

Summary

Due to rounding issues, there may be a dust amount of USDC/kwenta remaining in the contract, where kwenta will be permanently stuck

Vulnerability Detail

Due to the division accuracy issue of notifyRewardAmount in calculating RewardRate, there may be a dust amount of funds left in the contract

POC:

    function test_1() public {
        uint256 rewardsDurantion = stakingRewardsV2.rewardsDuration();

        console2.log(rewardsDurantion);
        address Alice = makeAddr("Alice");

        fundAndApproveAccountV2(Alice, 3 ether);

        vm.startPrank(Alice);
        stakingRewardsV2.stake(3 ether);
        vm.stopPrank();

        vm.warp(block.timestamp + 4 weeks);
        deal(address(kwenta), address(rewardsNotifier), 10e18);
        deal(address(usdc), address(rewardsNotifier), 10e6);
        vm.startPrank(address(supplySchedule));
        rewardsNotifier.notifyRewardAmount(10 ether);
        vm.stopPrank();

        vm.warp(block.timestamp + 1 weeks);

        vm.startPrank(Alice);
        stakingRewardsV2.exit();
        vm.stopPrank();

        console2.log(
            "kwenta balance: %s",
            kwenta.balanceOf(address(stakingRewardsV2))
        );
        console2.log(
            "usdc balance: %s",
            usdc.balanceOf(address(stakingRewardsV2))
        );
    }

log:

Ran 1 test for test/foundry/unit/StakingRewardsV2/StakingRewardsV2.t.sol:StakingRewardsV2Test
[PASS] test_1() (gas: 970284)
Logs:
  604800
  kwenta balance: 323200
  usdc balance: 323200

Impact

The reward tokens for dust accumulation continue to accumulate in the contract, and users receive slightly smaller returns than expected. The accumulated kwenta tokens will be permanently trapped in the contract

Code Snippet

github:https://github.com/sherlock-audit/2024-07-kwenta-staking-contracts/blob/0527fb7425206a3338c23177416436c6286cedf9/token/contracts/StakingRewardsV2.sol#L651

    function notifyRe6wardAmount(uint256 _reward, uint256 _rewardUsdc)
        external
        onlyRewardsNotifier
        updateReward(address(0))
    {
        if (block.timestamp >= periodFinish) {
            rewardRate = _reward / rewardsDuration;
            rewardRateUSDC = _rewardUsdc / rewardsDuration;
        } else {
            uint256 remaining = periodFinish - block.timestamp;

            uint256 leftover = remaining * rewardRate;
            rewardRate = (_reward + leftover) / rewardsDuration;

            uint256 leftoverUsdc = remaining * rewardRateUSDC;
            rewardRateUSDC = (_rewardUsdc + leftoverUsdc) / rewardsDuration;
        }

        lastUpdateTime = block.timestamp;
        periodFinish = block.timestamp + rewardsDuration;
        emit RewardAdded(_reward, _rewardUsdc);
    }

Tool used

Manual Review

Recommendation

  1. Use more accurate division to calculate rewardRate
  2. Set up a function that allows the withdrawal of reward tokens when the total staking amount is zero