Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: medium
Valid

Gas expensive duplicate check using double for loop.

Summary

In the 'enterRaffle' function, two loops are used to check if the player's address is already in the 'players' list. This makes it cheaper for the first participants, but more expensive for those who join later because we have to check through a longer list of players leading to the computational overhead.

Vulnerability Details

Below is the outcome of a test in foundry which checks the gas used for entering the first 100 players into the puppy raffle compared to the gas used to enter the next 100 players into the raffle. The gas consumption is approx. 189% more for the later participants.

[PASS] testEnterRaffleGas() (gas: 28854459)
Logs:
Gas cost of the first 100 players: 6261862
Gas cost of the next 100 players: 18077609

Impact

  1. 'Denial of Service attack' is possible if an attacker enters the raffle with loads of addresses at the beginning making it extremely expensive for the consecutive players to enter leading to an 'out of gas' error.

  2. Excessive amount of gas makes it unfair for upcoming players to enter the raffle.

Tools Used

Foundry

Recommendations

Mapping 'mapping(address => bool)' can be created for every player address to store his presence. Hence we can simply check the boolean value to determine whether the address is already present or not.
'enterRaffle' can be modified to include the below code.

function enterRaffle(address[] memory newPlayers) public payable {
require(msg.value == entranceFee * newPlayers.length, "PuppyRaffle: Must send enough to enter raffle");
// Create a mapping to store the presence of players
//mapping(address => bool) playerExists;
// Check for duplicates and add non-duplicate players to the players array
for (uint256 i = 0; i < newPlayers.length; i++) {
// Ensure the player is not a duplicate
require(!playerExists[newPlayers[i]], "PuppyRaffle: Duplicate player");
// Mark the player as seen
playerExists[newPlayers[i]] = true;
// Add non-duplicate players to the players array
players.push(newPlayers[i]);
}
emit RaffleEnter(newPlayers);
}

Gas used throw this method is as below

Running 1 test for test/PuppyRaffleTest.t.sol:PuppyRaffleTest
[PASS] testEnterRaffleGas() (gas: 13684909)
Logs:
Gas cost of the first 100 players: 4589362
Gas cost of the next 100 players: 4580559
Updates

Lead Judging Commences

Hamiltonite Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

denial-of-service-in-enter-raffle

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.