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

Players who make only 1 prediction will be unable to claim a reward

Summary

The isEligibleForReward function checks that the last match result has been set and that the player has made more than one prediction. Any player that pays one prediction fee should be eligible for reward according to docs, however isEligibleForReward returns false for any user with 1 prediction.

Vulnerability Details

If an approved player makes a prediction and pays the prediction fee, they are eligible for a reward according to documentation. Currently isEligibleForReward returns false for any player with one prediction. When they try to withdraw, it will revert with the custom error ThePredicter__NotEligibleForWithdraw in ThePredicter::withdraw.

function isEligibleForReward(address player) public view returns (bool) {
return
results[NUM_MATCHES - 1] != Result.Pending &&
//@audit-data a user who makes one prediction will be ineligible for their reward
@> playersPredictions[player].predictionsCount > 1;
}
function withdraw() public {
if (!scoreBoard.isEligibleForReward(msg.sender)) {
revert ThePredicter__NotEligibleForWithdraw();
}

POC

Add test to ThePredicter.test.sol
Reverts when player who makes one prediction and gets it right attempts to claim reward

function test_userCantWithdraw() public {
address stranger2 = makeAddr("stranger2");
address stranger3 = makeAddr("stranger3");
vm.startPrank(stranger);
vm.deal(stranger, 1 ether);
thePredicter.register{value: 0.04 ether}();
vm.stopPrank();
vm.startPrank(stranger2);
vm.deal(stranger2, 1 ether);
thePredicter.register{value: 0.04 ether}();
vm.stopPrank();
vm.startPrank(stranger3);
vm.deal(stranger3, 1 ether);
thePredicter.register{value: 0.04 ether}();
vm.stopPrank();
vm.startPrank(organizer);
thePredicter.approvePlayer(stranger);
thePredicter.approvePlayer(stranger2);
thePredicter.approvePlayer(stranger3);
vm.stopPrank();
vm.startPrank(stranger);
thePredicter.makePrediction{value: 0.0001 ether}(
1,
ScoreBoard.Result.Draw
);
thePredicter.makePrediction{value: 0.0001 ether}(
2,
ScoreBoard.Result.Draw
);
thePredicter.makePrediction{value: 0.0001 ether}(
3,
ScoreBoard.Result.Draw
);
vm.stopPrank();
vm.startPrank(stranger2);
thePredicter.makePrediction{value: 0.0001 ether}(
1,
ScoreBoard.Result.Draw
);
thePredicter.makePrediction{value: 0.0001 ether}(
2,
ScoreBoard.Result.First
);
thePredicter.makePrediction{value: 0.0001 ether}(
3,
ScoreBoard.Result.First
);
vm.stopPrank();
vm.startPrank(stranger3);
thePredicter.makePrediction{value: 0.0001 ether}(
1,
ScoreBoard.Result.First
);
vm.stopPrank();
vm.startPrank(organizer);
scoreBoard.setResult(0, ScoreBoard.Result.First);
scoreBoard.setResult(1, ScoreBoard.Result.First);
scoreBoard.setResult(2, ScoreBoard.Result.First);
scoreBoard.setResult(3, ScoreBoard.Result.First);
scoreBoard.setResult(4, ScoreBoard.Result.First);
scoreBoard.setResult(5, ScoreBoard.Result.First);
scoreBoard.setResult(6, ScoreBoard.Result.First);
scoreBoard.setResult(7, ScoreBoard.Result.First);
scoreBoard.setResult(8, ScoreBoard.Result.First);
vm.stopPrank();
vm.startPrank(organizer);
thePredicter.withdrawPredictionFees();
vm.stopPrank();
vm.startPrank(stranger2);
thePredicter.withdraw();
vm.stopPrank();
vm.startPrank(stranger3);
vm.expectRevert(
abi.encodeWithSelector(
ThePredicter__NotEligibleForWithdraw.selector
)
);
thePredicter.withdraw();
vm.stopPrank();
}

Impact

Any user with one prediction will be unable to claim a reward

Tools Used

Manual Review

Recommendations

Change check to ensure playersPredictions[player].predictionsCount is >= 1

function isEligibleForReward(address player) public view returns (bool) {
return
results[NUM_MATCHES - 1] != Result.Pending &&
//@audit-data a user who makes one prediction will be ineligible for their reward
- playersPredictions[player].predictionsCount > 1;
+ playersPredictions[player].predictionsCount >= 1;
}
Updates

Lead Judging Commences

NightHawK Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

The eligibility criteria is wrong

Players with only one prediction cannot withdraw.

Support

FAQs

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