Users may not be able to predict on matches because of the deadline wrongly set to far from the start time of the match
Based on the design of this protocol players should be able to predict until an hour before the start of a match which is 20:00 each day. on the first day the makePrediction() function in ThePredicter.sol prevents users from making prediction 19 hours before the start of the match, on the second day users can only predict 24 hours before the start of the match, on the 3rd day users can only predict 29 hours before the start time like that onward, on the last day users can only predict 59 hours (which is about 2 days and 11 hours) before the match contrary to the 1 hour intended design
Add this file to test and run forge t --mc AuditTest --mt test_makePredictions -vvvvv
pragma solidity ^0.8.13;
import {Test, console} from "forge-std/Test.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {ThePredicter} from "../src/ThePredicter.sol";
import {ScoreBoard} from "../src/ScoreBoard.sol";
import{ReentrancyAttack} from "../src/ReentrancyAttack.sol";
contract AuditTest is Test {
ThePredicter public thePredicter;
ScoreBoard public scoreBoard;
ReentrancyAttack public reentrancyAttack;
uint256 private constant START_TIME = 1723752000;
address public organizer = makeAddr("organizer");
address public stranger = makeAddr("stranger");
address public player = makeAddr("player");
address public player2 = makeAddr("player2");
function setUp() public {
vm.startPrank(organizer);
scoreBoard = new ScoreBoard();
thePredicter = new ThePredicter(
address(scoreBoard),
0.04 ether,
0.0001 ether
);
scoreBoard.setThePredicter(address(thePredicter));
vm.stopPrank();
reentrancyAttack = new ReentrancyAttack(thePredicter);
vm.deal(address(reentrancyAttack), 0.04 ether);
}
function test_makePredictions() public{
vm.deal(player, 1 ether);
vm.prank(player);
thePredicter.register{value: 0.04 ether}();
vm.startPrank(organizer);
thePredicter.approvePlayer(player);
vm.stopPrank();
vm.expectRevert();
vm.warp(START_TIME - 3600);
vm.startPrank(player);
thePredicter.makePrediction{value: 0.0001 ether}(0, ScoreBoard.Result.First);
vm.stopPrank();
vm.expectRevert();
vm.warp(START_TIME - 14400);
vm.startPrank(player);
thePredicter.makePrediction{value: 0.0001 ether}(0, ScoreBoard.Result.First);
vm.stopPrank();
vm.expectRevert();
vm.warp(START_TIME - 64800);
vm.startPrank(player);
thePredicter.makePrediction{value: 0.0001 ether}(0, ScoreBoard.Result.First);
vm.stopPrank();
vm.warp(START_TIME - 68400);
vm.startPrank(player);
thePredicter.makePrediction{value: 0.0001 ether}(0, ScoreBoard.Result.First);
vm.stopPrank();
vm.expectRevert();
vm.warp(START_TIME + 86400 - 3600);
vm.startPrank(player);
thePredicter.makePrediction{value: 0.0001 ether}(1, ScoreBoard.Result.First);
vm.stopPrank();
vm.expectRevert();
vm.warp(START_TIME + 86400 - 82800);
vm.startPrank(player);
thePredicter.makePrediction{value: 0.0001 ether}(1, ScoreBoard.Result.First);
vm.stopPrank();
vm.warp(START_TIME + 86400 - 86400);
vm.startPrank(player);
thePredicter.makePrediction{value: 0.0001 ether}(1, ScoreBoard.Result.First);
vm.stopPrank();
vm.expectRevert();
vm.warp(START_TIME + 86400 * 8 - 3600);
vm.startPrank(player);
thePredicter.makePrediction{value: 0.0001 ether}(8, ScoreBoard.Result.First);
vm.stopPrank();
vm.expectRevert();
vm.warp(START_TIME + 86400 * 8 - 208800);
vm.startPrank(player);
thePredicter.makePrediction{value: 0.0001 ether}(8, ScoreBoard.Result.First);
vm.stopPrank();
vm.warp(START_TIME + 86400 * 8 - 212400);
vm.startPrank(player);
thePredicter.makePrediction{value: 0.0001 ether}(8, ScoreBoard.Result.First);
vm.stopPrank();
}
}
This could lead to all the users not being able to predict and therefore the organizers not getting the money from the prediction fees
The calculation for deadline should be fixed on makePrediction() in ThePredicter.sol and setPrediction() in Scoreboard.sol
function makePrediction(
uint256 matchNumber,
ScoreBoard.Result prediction
) public payable {
if (msg.value != predictionFee) {
revert ThePredicter__IncorrectPredictionFee();
}
- if (block.timestamp > START_TIME + matchNumber * 68400 - 68400) {
revert ThePredicter__PredictionsAreClosed();
}
+ if (block.timestamp > START_TIME + matchNumber * 86400 - 3600) {
revert ThePredicter__PredictionsAreClosed();
}
scoreBoard.confirmPredictionPayment(msg.sender, matchNumber);
scoreBoard.setPrediction(msg.sender, matchNumber, prediction);
}
function setPrediction(
address player,
uint256 matchNumber,
Result result
) public {
- if (block.timestamp <= START_TIME + matchNumber * 68400 - 68400)
+ if (block.timestamp <= START_TIME + matchNumber * 86400 - 3600)
playersPredictions[player].predictions[matchNumber] = result;
playersPredictions[player].predictionsCount = 0;
for (uint256 i = 0; i < NUM_MATCHES; ++i) {
if (
playersPredictions[player].predictions[i] != Result.Pending &&
playersPredictions[player].isPaid[i]
) ++playersPredictions[player].predictionsCount;
}
}