Summary
Use custom errors instead of require statements. It saves gas and makes your code more streamlined and easier to parse.
Vulnerability Details
require(msg.value == entranceFee * newPlayers.length, "PuppyRaffle: Must send enough to enter raffle");
require(players[i] != players[j], "PuppyRaffle: Duplicate player");
require(playerAddress == msg.sender, "PuppyRaffle: Only the player can refund");
require(playerAddress != address(0), "PuppyRaffle: Player already refunded, or is not active");
Impact
People have to spend more gas when they interact with your protocol and your code is less organized for others who may want to look at it, build off it, etc.
Tools Used
Manual
Recommendations
Add custom errors at the top of the code:
error PuppyRaffle__NotEnoughEth();
error PuppyRaffle__DuplicatePlayer();
error PuppyRaffle__OnlyPlayerCanRefund();
error PuppyRaffle__ZeroAddress();
Then change the code as follows:
if(msg.value < entranceFee * newPlayers.length) {
revert PuppyRaffle__NotEnoughEth();}
if(players[i] = players[j]) {
revert PuppyRaffle__DuplicatePlayer();
if(playerAddress != msg.sender){
revert PuppyRaffle__OnlyPlayerCanRefund();}
if(playerAddress = address(0)) {
revert PuppyRaffle__ZeroAddress()};