In the StakeV2::startUnstake function, stakedTimes[msg.sender] is used to limit the number of times a user can initiate an unstake. However, instead of maintaining a separate counter, we can use vestings[msg.sender].length to enforce this restriction.
By doing so, we eliminate an unnecessary SSTORE operation (used to update stakedTimes[msg.sender]), which can help reduce gas costs.
StakeV2::startUnstake function:
function startUnstake(uint256 unStakeAmount) external {
require(unStakeAmount > 0, "Amount must be greater than 0");
=> require(stakedTimes[msg.sender] < STAKING_LIMIT, "Amount must be less then the STAKING_LIMIT constant");
...
vestings[msg.sender].push(Vesting(unStakeAmount, start, end));
=> stakedTimes[msg.sender]++;
emit VestingStarted(msg.sender, unStakeAmount, vestings[msg.sender].length - 1);
}
Recommendation
Modify the StakeV2::startUnstake function:
function startUnstake(uint256 unStakeAmount) external {
require(unStakeAmount > 0, "Amount must be greater than 0");
=> require(vestings[msg.sender].length < STAKING_LIMIT, "Amount must be less then the STAKING_LIMIT constant");
...
vestings[msg.sender].push(Vesting(unStakeAmount, start, end));
=> // Delete this line
emit VestingStarted(msg.sender, unStakeAmount, vestings[msg.sender].length - 1);
}
Modify the StakeV2::_unstake function:
function _unstake(uint256 index) private {
Vesting memory vesting = vestings[msg.sender][index];
(uint256 unlockedAmount, uint256 lockedAmount) = calculateVesting(vesting);
require(unlockedAmount != 0, "No unlocked amount");
_remove(msg.sender, index);
if (lockedAmount > 0) {
emit RageQuit(msg.sender, unlockedAmount, lockedAmount, index);
} else {
emit Unstake(msg.sender, unlockedAmount, index);
}
=> stakedTimes[msg.sender]--; // Delete this line
}
Proof of Concept
Proof of Concept
Modify the StakeV2::startUnstake function:
function startUnstake(uint256 unStakeAmount) external {
require(unStakeAmount > 0, "Amount must be greater than 0");
=> require(vestings[msg.sender].length < STAKING_LIMIT, "Amount must be less then the STAKING_LIMIT constant");
...
vestings[msg.sender].push(Vesting(unStakeAmount, start, end));
=> // Delete this line
emit VestingStarted(msg.sender, unStakeAmount, vestings[msg.sender].length - 1);
}
Modify the StakeV2::_unstake function:
function _unstake(uint256 index) private {
Vesting memory vesting = vestings[msg.sender][index];
(uint256 unlockedAmount, uint256 lockedAmount) = calculateVesting(vesting);
require(unlockedAmount != 0, "No unlocked amount");
_remove(msg.sender, index);
if (lockedAmount > 0) {
emit RageQuit(msg.sender, unlockedAmount, lockedAmount, index);
} else {
emit Unstake(msg.sender, unlockedAmount, index);
}
=> stakedTimes[msg.sender]--; // Delete this line
}