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

PuppyRaffle::enterRaffle linear search compuatation to check duplicate address + would make it unfair for every player that enter the raffle at a later time

Summary

PuppyRaffle::enterRaffle is too computationally intensive making it so for every call it spends more and more gas, making the whole purpose of this protocol unrealistic.

Vulnerability Details

The enterRaffle function in the PuppyRaffle contract performs an highly intensive computation each time anyone calls on it to enter an ongoing lottery which makes it so that for every entry into an ongoing contest their would be an increase in gas fee for the next person that would want to enter the contest, making the lottery totally unfair.

Impact

I would be showing the amount of gas used for entering the PuppyRaffle contract with varying number of players in the newPlayers array and from that you would be able to deduct how serious this bug 🐛 is.

Calling the PuppyRaffle::enterRaffle with 10 players in the newPlayers array we are passing in as an argument to the function

code

modifier ManyPlayersEntered1() {
address[] memory players = new address[](10);
for(uint256 player = 0; player < players.length; player++ ){
players[player] = address(player + 1);
}
puppyRaffle.enterRaffle{value: entranceFee * players.length}(players);
_;
}
function testMakesEntranceMoreExpensiveDueToHeavyEntryComputation() public ManyPlayersEntered1 {
}

output

Running 1 test for test/PuppyRaffleTest.t.sol:PuppyRaffleTest
[PASS] testMakesEntranceMoreExpensiveDueToHeavyEntryComputation() (gas: 307963)
Traces:
[307963] PuppyRaffleTest::testMakesEntranceMoreExpensiveDueToHeavyEntryComputation()
├─ [291155] PuppyRaffle::enterRaffle{value: 10000000000000000000}([0x0000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000003, 0x0000000000000000000000000000000000000004, 0x0000000000000000000000000000000000000005, 0x0000000000000000000000000000000000000006, 0x0000000000000000000000000000000000000007, 0x0000000000000000000000000000000000000008, 0x0000000000000000000000000000000000000009, 0x000000000000000000000000000000000000000A])
│ ├─ emit RaffleEnter(newPlayers: [0x0000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000003, 0x0000000000000000000000000000000000000004, 0x0000000000000000000000000000000000000005, 0x0000000000000000000000000000000000000006, 0x0000000000000000000000000000000000000007, 0x0000000000000000000000000000000000000008, 0x0000000000000000000000000000000000000009, 0x000000000000000000000000000000000000000A])
│ └─ ← ()
└─ ← ()
Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 18.39ms

conclusion

calling the PuppyRaffle::enterRaffle with 10 players in the newPlayers argument we are passing in cost 307963 gas


Calling the PuppyRaffle::enterRaffle with 20 players in the newPlayers array we are passing in as an argument to the function

code

modifier ManyPlayersEntered2() {
address[] memory players = new address[](20);
for(uint256 player = 0; player < players.length; player++ ){
players[player] = address(player + 1);
}
puppyRaffle.enterRaffle{value: entranceFee * players.length}(players);
_;
}
function testMakesEntranceMoreExpensiveDueToHeavyEntryComputation() public ManyPlayersEntered2 {
}

output

Running 1 test for test/PuppyRaffleTest.t.sol:PuppyRaffleTest
[PASS] testMakesEntranceMoreExpensiveDueToHeavyEntryComputation() (gas: 656774)
Traces:
[656774] PuppyRaffleTest::testMakesEntranceMoreExpensiveDueToHeavyEntryComputation()
├─ [637413] PuppyRaffle::enterRaffle{value: 20000000000000000000}([0x0000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000003, 0x0000000000000000000000000000000000000004, 0x0000000000000000000000000000000000000005, 0x0000000000000000000000000000000000000006, 0x0000000000000000000000000000000000000007, 0x0000000000000000000000000000000000000008, 0x0000000000000000000000000000000000000009, 0x000000000000000000000000000000000000000A, 0x000000000000000000000000000000000000000b, 0x000000000000000000000000000000000000000C, 0x000000000000000000000000000000000000000d, 0x000000000000000000000000000000000000000E, 0x000000000000000000000000000000000000000F, 0x0000000000000000000000000000000000000010, 0x0000000000000000000000000000000000000011, 0x0000000000000000000000000000000000000012, 0x0000000000000000000000000000000000000013, 0x0000000000000000000000000000000000000014])
│ ├─ emit RaffleEnter(newPlayers: [0x0000000000000000000000000000000000000001, 0x0000000000000000000000000000000000000002, 0x0000000000000000000000000000000000000003, 0x0000000000000000000000000000000000000004, 0x0000000000000000000000000000000000000005, 0x0000000000000000000000000000000000000006, 0x0000000000000000000000000000000000000007, 0x0000000000000000000000000000000000000008, 0x0000000000000000000000000000000000000009, 0x000000000000000000000000000000000000000A, 0x000000000000000000000000000000000000000b, 0x000000000000000000000000000000000000000C, 0x000000000000000000000000000000000000000d, 0x000000000000000000000000000000000000000E, 0x000000000000000000000000000000000000000F, 0x0000000000000000000000000000000000000010, 0x0000000000000000000000000000000000000011, 0x0000000000000000000000000000000000000012, 0x0000000000000000000000000000000000000013, 0x0000000000000000000000000000000000000014])
│ └─ ← ()
└─ ← ()
Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.16ms
Ran 1 test suites: 1 tests passed, 0 failed, 0 skipped (1 total tests)

conclusion

calling the PuppyRaffle::enterRaffle with 20 players in the newPlayers argument we are passing in cost 656774 gas


Tools Used

Foundry

Recommendations

I would recommend the protocol use a mapping for storing the address of every member that entered into the Raffle an address to bool mapping would do the trick mapping(address => bool) . this is would make sure that we have a constant time search when we are trying to verify that there is no duplicate address in the data structure that saves every players that have entered the raffle.

Updates

Lead Judging Commences

Hamiltonite Lead Judge almost 2 years 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.