Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: high
Invalid

Arithmetic Errors in Reward Calculation in ThePredicter::withdraw function

Relevant GitHub Links

https://github.com/Cyfrin/2024-07-the-predicter/blob/main/src/ThePredicter.sol#L111-L145

Summary

In the withdraw function, the reward calculation involves potentially dangerous arithmetic operations

Vulnerability Details

In the withdraw function, the reward calculation involves potentially dangerous arithmetic operations. Specifically, the calculation:
which is found here:

reward = (shares * players.length * entranceFee) / totalShares;

If totalShares is zero, this will result in a division by zero, causing the contract to revert or behave unexpectedly.

Impact

This can cause the contract to fail when trying to distribute rewards, leading to a denial of service.

Tools Used

Manual

Recommendations

Ensure totalShares is not zero before performing the division. Handle cases where totalShares is zero to prevent division by zero.

function withdraw() public {
if (!scoreBoard.isEligibleForReward(msg.sender)) {
revert ThePredicter__NotEligibleForWithdraw();
}
int8 score = scoreBoard.getPlayerScore(msg.sender);
int8 maxScore = -1;
int256 totalPositivePoints = 0;
for (uint256 i = 0; i < players.length; ++i) {
int8 cScore = scoreBoard.getPlayerScore(players[i]);
if (cScore > maxScore) maxScore = cScore;
if (cScore > 0) totalPositivePoints += cScore;
}
if (maxScore > 0 && score <= 0) {
revert ThePredicter__NotEligibleForWithdraw();
}
- uint256 shares = uint8(score);
- uint256 totalShares = uint256(totalPositivePoints);
- uint256 reward = 0;
- if (totalShares > 0) {
- reward = maxScore < 0
- ? entranceFee
- : (shares * players.length * entranceFee) / totalShares;
- }
+ uint256 shares = uint256(score);
+ uint256 totalShares = uint256(totalPositivePoints);
+ // Ensure that the reward calculation is only done if `totalShares` is greater than zero
+ uint256 reward = maxScore < 0
+ ? entranceFee
+ : (totalShares > 0 ? (shares * players.length * entranceFee) / totalShares : 0);
if (reward > 0) {
scoreBoard.clearPredictionsCount(msg.sender);
(bool success, ) = msg.sender.call{value: reward}("");
require(success, "Failed to withdraw");
}
}
Updates

Lead Judging Commences

NightHawK Lead Judge 12 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.