Liquid Staking

Stakelink
DeFiHardhatOracle
50,000 USDC
View results
Submission Details
Severity: high
Invalid

StakingPool._updateStrategyRewards(): totalStaked can become unexpected value when casted to uint256

Summary

The critical bug in the StakingPool contract is related to the handling of the totalStaked variable during the _updateStrategyRewards() function. This bug can lead to incorrect accounting of the total staked amount, potentially allowing for manipulation of the staking logic and endangering the integrity of the contract's financial operations.

Vulnerability Details

The updateStrategyRewards() function (which does access control check and then calls _updateStrategyRewards() internal function) is designed to update the rewards and fees based on balance changes in strategies since the last update. It iterates through a list of strategy indices, calculates the total rewards, and updates the totalStaked variable accordingly. The issue arises in the following lines of the _updateStrategyRewards() function:

if (totalRewards != 0) {
totalStaked = uint256(int256(totalStaked) + totalRewards);
}

Here, totalRewards is an int256 and totalStaked is casted to int256 as well in order to do the addition. If int256(totalStaked) + totalRewards < 0, casting it directly to uint256 introduces severe issue. This is because int256 in Solidity is representation by 2's complement, the MSB is the sign bit. When casting to uint256, the sign bit will be interpreted as the actual content of the value, so the end result is usually a lot larger than expected. For example, below is a quick PoC that you can test in Remix IDE:

pragma solidity ^0.8.0;
contract TestCasting {
uint256 totalStaked = 1337;
int256 totalRewards = -1338;
function castInt256ToUint256() public view returns (uint256) {
uint256 result = uint256(int256(totalStaked) + totalRewards);
return result;
}
}

The expected return value is uint256(-1) = 1, but actually the return value is 115792089237316195423570985008687907853269984665640564039457584007913129639935.

Impact

The accounting system that depends on totalStaked will be wrong if the scenario described above happens.

Tools Used

Manual review, Remix IDE

Recommendations

Implement an absolute value function:

function abs(int256 x) public pure returns (uint256) {
if (x < 0) {
// If x is negative, return its negation
return uint256(-x);
} else {
// If x is non-negative, return it as is
return uint256(x);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.