Summary
enterRaffle function should not allow players after raffleDuration has passed to avoid creating an unfavorable situation for the players that entered within the raffleDuration period.
Vulnerability Details
There is no check implemented to prevent new players to enter the raffle after the duration has passed. This is only implemented in the selectWinner function. The current implementation suggests that the raffle is open as long as no one calls the selectWInner function after the raffleDuration has passed.
PoC
function testCanEnterRaffleRegardlessOfTheDuration() public {
address[] memory players = new address[](1);
players[0] = playerOne;
puppyRaffle.enterRaffle{value: entranceFee}(players);
assertEq(puppyRaffle.players(0), playerOne);
address[] memory latePlayers = new address[](1);
address lateEntrant = makeAddr("All progress takes place outside the comfort zone.!");
latePlayers[0] = lateEntrant;
vm.warp(block.timestamp + duration * 30);
vm.roll(block.number + 100);
puppyRaffle.enterRaffle{value: entranceFee}(latePlayers);
assertEq(puppyRaffle.players(1), lateEntrant);
}
Impact
The ability to enter after the raflfeDuration has passed lowers the winning chances of the participants that complied with the raffleDuration.
Tools Used
Manual review
Recommendations
function enterRaffle(address[] memory newPlayers) public payable {
require(msg.value == entranceFee * newPlayers.length, "PuppyRaffle: Must send enough to enter raffle");
++ require(block.timestamp < raffleStartTime + raffleDuration, "PuppyRaffle: Raffle over");
for (uint256 i = 0; i < newPlayers.length; i++) {
players.push(newPlayers[i]);
}
// Check for duplicates
for (uint256 i = 0; i < players.length - 1; i++) {
for (uint256 j = i + 1; j < players.length; j++) {
require(players[i] != players[j], "PuppyRaffle: Duplicate player");
}
}
emit RaffleEnter(newPlayers);
}