Skip to content

Latest commit

 

History

History
60 lines (51 loc) · 2.25 KB

038.md

File metadata and controls

60 lines (51 loc) · 2.25 KB

Rich Smoke Cheetah

High

Reward could be lost if there is no staker

Summary

If there is a distribution and all the stakers withdraw, then for the rest of the reward duration, if no one stakes, the reward will be stuck forever.

Vulnerability Detail

We can see here that the reward is distributed only if the totalEarningPower is higher than 0.

function rewardPerTokenAccumulated() public view virtual returns (uint256) { 
   if (totalEarningPower == 0) return rewardPerTokenAccumulatedCheckpoint; 
  
   return rewardPerTokenAccumulatedCheckpoint 
     + (scaledRewardRate * (lastTimeRewardDistributed() - lastCheckpointTime)) / totalEarningPower; 
 } 

The problem is that if during a reward distribution all the stakers withdraw, then the funds will be stuck forever in the smart contract.

Proof-Of-Concept

You can copy-paste this test in a contract of the GovernanceStaker.t.sol file and run forge test --mt test_stuckBalancePOC.

function test_stuckBalancePOC() public {
     address BOB = makeAddr("BOB");    
     // Bob stake 1 token 
    (, GovernanceStaker.DepositIdentifier _depositId) = _boundMintAndStake(BOB, 1e18,BOB);
     uint256 _rewardAmount = 1000e18;
     //The protocol notify some rewards
    _mintTransferAndNotifyReward( _rewardAmount);
    //We jump the half of the reward duration
    _jumpAheadByPercentOfRewardDuration(50);
    //Bob claim his rewards
     vm.prank(BOB);
    govStaker.claimReward(_depositId);
    //Bob the withdraw his staking balance
     vm.prank(BOB);
    govStaker.withdraw(_depositId,1e18);
    //We jump the rest of the reward duration
    _jumpAheadByPercentOfRewardDuration(50);
   uint256 unclaimedReward=  govStaker.unclaimedReward(_depositId);
   uint256 rewardGovBalance = rewardToken.balanceOf(address(govStaker));
   // we can see that Bob have no unclaimed reward
    assertEq(unclaimedReward, 0);
    //There is some funds that are stuck in the contract
    assertEq(rewardGovBalance, 500e18 +1);
   }

Impact

The rewards will be stuck forever.

Code Snippet

https://github.com/sherlock-audit/2024-11-tally/blob/main/staker/src/GovernanceStaker.sol#L303-L308

Tool used

Foundry

Recommendation

The protocol should implement a function to redistribute the undistributed rewards.