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

Incorrect Type Casting of`int8` to `uint8` in `withdraw` Function Leads to Potential Miscalculation of Rewards

Summary

Incorrect type casting of int8 to uint8 in the withdraw function can lead to unexpected large values, causing potential calculation errors and unfair reward distribution.

Vulnerability Details

The withdraw function in the ThePredicter contract uses uint8(score) to cast an int8 score to a uint8. If the score is negative, this conversion results in an unexpected large value due to the two's complement representation of negative numbers in binary form. This can cause incorrect reward calculations and potential manipulation of scores.

The issue is in this function:
https://github.com/Cyfrin/2024-07-the-predicter/blob/main/src/ThePredicter.sol#L111-L144

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); //@audit
uint256 totalShares = uint256(totalPositivePoints);
uint256 reward = 0;
reward = maxScore < 0
? entranceFee
: (shares * players.length * entranceFee) / totalShares;
if (reward > 0) {
scoreBoard.clearPredictionsCount(msg.sender);
(bool success, ) = msg.sender.call{value: reward}("");
require(success, "Failed to withdraw");
}
}

The problem is in this line: uint256 shares = uint8(score);

Proof of Concept (PoC):
Consider the following example:

If score is -1 (binary 11111111 in int8):
Casting -1 to uint8 results in 255.
If score is -5 (binary 11111011 in int8):
Casting -5 to uint8 results in 251.
This casting can lead to incorrect reward calculations and unfair distribution.

Impact

Incorrect Reward Calculation: The withdraw function may distribute incorrect rewards due to the misinterpreted scores.
Potential Manipulation: Malicious actors can exploit this to receive higher rewards than they are eligible for.

Tools Used

Manual Review

Recommendations

Ensure that the score is non-negative before casting it to an unsigned integer type. Use a require statement to enforce this:

int8 score = scoreBoard.getPlayerScore(msg.sender);
require(score >= 0, "Score must be non-negative");
uint256 shares = uint256(uint8(score));
Updates

Lead Judging Commences

NightHawK Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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