20,000 USDC
View results
Submission Details
Severity: low
Valid

Loss of precision in `Staking.updateFor()` will make user to lose claimable amount.

Summary

Staking.updateFor() calculates claimable amount based on _supplied * delta / 1e18.

It might cause precision loss but supplyIndex is updated.

Vulnerability Details

Let's say _supplied * _delta is 0.999e18, newly claimable shares will be zero, but supplyIndex will be updated to current index. So there's no way to recover lost precision.

function updateFor(address recipient) public {
update();
uint256 _supplied = balances[recipient];
if (_supplied > 0) {
uint256 _supplyIndex = supplyIndex[recipient];
supplyIndex[recipient] = index;
uint256 _delta = index - _supplyIndex;
if (_delta > 0) {
uint256 _share = _supplied * _delta / 1e18;// @audit - precision loss
claimable[recipient] += _share;
}
} else {
supplyIndex[recipient] = index;
}
}

Impact

If staking amount is small or updateFor is called frequently, user may lose staking reward because of precision loss.

Tools Used

Manual Review

Recommendations

It should divide by 1e18 in claim() not updateFor.

function claim() external {
updateFor(msg.sender);
- WETH.transfer(msg.sender, claimable[msg.sender]);
+ WETH.transfer(msg.sender, claimable[msg.sender] / 1e18);
claimable[msg.sender] = 0;
balance = WETH.balanceOf(address(this));
}
function updateFor(address recipient) public {
update();
uint256 _supplied = balances[recipient];
if (_supplied > 0) {
uint256 _supplyIndex = supplyIndex[recipient];
supplyIndex[recipient] = index;
uint256 _delta = index - _supplyIndex;
if (_delta > 0) {
- uint256 _share = _supplied * _delta / 1e18;// @audit - precision loss
+ uint256 _share = _supplied * _delta;
claimable[recipient] += _share;
}
} else {
supplyIndex[recipient] = index;
}
}

Support

FAQs

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

Give us feedback!