Whenever an pseudo empty slot == zero address array element at any index, selected as winner index by on-chain randomness login, mint to the zero address error exception occurs. This issue makes sense, according to EIP-721 NFT token can't be minted to zero address.
Manual review.
address winner = address(0);
for (; winner == address(0);) {
uint256 winnerIndex =
uint256(keccak256(abi.encodePacked(msg.sender, block.timestamp, block.difficulty))) % players.length;
winner = players[winnerIndex];
}
I'm not sure if this works mitigation works on mainnet (live chain), Since it raises MemoryLimitOOG exception on local testnet (foundry).
address[] private legitPlayers;
function selectWinner() external {
require(block.timestamp >= raffleStartTime + raffleDuration, "PuppyRaffle: Raffle not over");
for (uint256 i = 0; i < players.length; i++) {
if (players[i] == address(0)) {
console.log("yes found zero address");
continue;
}
console.log("zero address not found forwarding...");
legitPlayers.push(players[i]);
}
players = legitPlayers;
delete legitPlayers;
require(players.length >= 4, "PuppyRaffle: Need at least 4 players");
uint256 winnerIndex =
uint256(keccak256(abi.encodePacked(msg.sender, block.timestamp, block.difficulty))) % players.length;
address winner = players[winnerIndex];
uint256 totalAmountCollected = players.length * entranceFee;
uint256 prizePool = (totalAmountCollected * 80) / 100;
uint256 fee = (totalAmountCollected * 20) / 100;
totalFees = totalFees + uint64(fee);
uint256 tokenId = totalSupply();
uint256 rarity = uint256(keccak256(abi.encodePacked(msg.sender, block.difficulty))) % 100;
if (rarity <= COMMON_RARITY) {
tokenIdToRarity[tokenId] = COMMON_RARITY;
} else if (rarity <= COMMON_RARITY + RARE_RARITY) {
tokenIdToRarity[tokenId] = RARE_RARITY;
} else {
tokenIdToRarity[tokenId] = LEGENDARY_RARITY;
}
delete players;
raffleStartTime = block.timestamp;
previousWinner = winner;
(bool success,) = winner.call{value: prizePool}("");
require(success, "PuppyRaffle: Failed to send prize pool to winner");
_safeMint(winner, tokenId);
}