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

1 stars 0 forks source link

eLSeR17 - Staking new tokens disallows a user to unstake previously staked tokens #153

Closed sherlock-admin2 closed 1 month ago

sherlock-admin2 commented 1 month ago

eLSeR17

Medium

Staking new tokens disallows a user to unstake previously staked tokens

Summary

Calling stake() or _stakeEscrow() functions prevents from unstaking previously tokens which could be unstaked in normal conditions.

Vulnerability Detail

stake() and _stakeEscrow() update userLastStakeTime[] mapping for the _account being called, which is used to decide if a user can unstake() tokens or not. If one had previously staked tokens and after the cooldown period has passed they stake again, those tokens will not be available to unstake. The most likely case is that an operator calls for stakeEscrowOnBehalf() function (which calls _stakeEscrow()), leading to a situation in which _account user wanted to unstake their tokens but now they cannot.

Impact

Users may be required to wait for longer than expected to unstake their tokens if some of the stake functions are called. This waiting time ranges from 1 week to 1 year, which is a considerable time lapse.

Code Snippet

https://github.com/sherlock-audit/2024-07-kwenta-staking-contracts/blob/main/token/contracts/StakingRewardsV2.sol#L137-L145

Tool used

Manual Review

Recommendation

Recommendation is to use a mapping which tells the unstakeable amount for each address so that when some tokens are staked, we update this mapping with the corresponding amount.

.
.
.
mapping(address=>uint256) unstakeableTokens;

+struct Staked{
+uint256 timestamp;
+uint256 amount;
+}

mapping (address=> Staked[]) stakedTokens;
.
.
.
function _afterCooldown(address _account) internal view {
uint256 unstakeableTokens;
for(uint i=0; i<stakedTokens[_account]; i++){
    if(block.timestamp > stakedTokens[_account][i].timestamp + cooldownPeriod){
          unstakeableTokens += stakedTokens[_account][i].amount;
          delete stakedTokens[_account][i];
    }        
}
   unstakeableTokens[_account] +=  unstakeableTokens; 
    }