Summary
In Deploy.s.sol
the s_merkleRoot
variable don't reflect the amount that must be airdropped ($100).
Vulnerability Details
The amount values used to create the leafs of the merkle tree are not aligned with the token distribution annouced for this airdropper. The hash value of s_merkleRoot
in Deploy.s.sol
corresponds to an amount equivalent to 25e18 USDC.
In MerkleAirdropTest.t.sol
we can demonstrate this vulnerability by different approach, by inserting wrong merkle root with wrong proof and with wrong amount to collect.
bytes32 public GoodMerkleRoot = 0x3b2e22da63ae414086bec9c9da6b685f790c6fab200c7918f2879f08793d77bd;
bytes32 public WrongMerkleRoot = 0xf69aaa25bd4dd10deb2ccd8235266f7cc815f6e9d539e9f4d47cae16e0c36a05;
uint256 goodAmountToCollect = (25 * 1e6);
uint256 wrongAmountToCollect = (25 * 1e18);
uint256 goodAmountToSend = goodAmountToCollect * 4;
uint256 wrongAmountToSend = wrongAmountToCollect * 4;
address collectorOne = 0x20F41376c713072937eb02Be70ee1eD0D639966C;
bytes32 goodProofOne = 0x32cee63464b09930b5c3f59f955c86694a4c640a03aa57e6f743d8a3ca5c8838;
bytes32 goodProofTwo = 0x8ff683185668cbe035a18fccec4080d7a0331bb1bbc532324f40501de5e8ea5c;
bytes32 wrongProofOne = 0x4fd31fee0e75780cd67704fbc43caee70fddcaa43631e2e1bc9fb233fada2394;
bytes32 wrongProofTwo = 0xc88d18957ad6849229355580c1bde5de3ae3b78024db2e6c2a9ad674f7b59f84;
bytes32[] goodProof = [goodProofOne, goodProofTwo];
bytes32[] wrongProof = [wrongProofOne, wrongProofTwo];
function testUsersCanClaim() public {
uint256 startingBalance = token.balanceOf(collectorOne);
vm.deal(collectorOne, 1e9);
vm.startPrank(collectorOne);
airdrop.claim{ value: 1e9 }(collectorOne, wrongAmountToCollect, wrongProof);
vm.stopPrank();
uint256 endingBalance = token.balanceOf(collectorOne);
assertEq(endingBalance - startingBalance, wrongAmountToCollect);
}
function testRevertifwrongAmountToCollect() public {
vm.deal(collectorOne, 1e9);
vm.startPrank(collectorOne);
vm.expectRevert(MerkleAirdrop.MerkleAirdrop__InvalidProof.selector);
airdrop.claim{ value: 1e9 }(collectorOne, goodAmountToCollect, wrongProof);
vm.stopPrank();
}
Ran 1 test for test/MerkleAirdropTest.t.sol:MerkleAirdropTest
[PASS] testUsersCanClaim() (gas: 33930)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 6.44s (1.78s CPU time)
Ran 1 test suite in 6.44s (6.44s CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)
Ran 1 test for test/MerkleAirdropTest.t.sol:MerkleAirdropTest
[PASS] testRevertifwrongAmountToCollect() (gas: 27206)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.77s (728.31ms CPU time)
Ran 1 test suite in 4.77s (4.77s CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)
The first test pass because we are collecting the wrong amount (25e18) with the wrong merkleroot, the second test pass because we are trying to collect the good amount but this amount doesn't reflect the hash of the merkle root.
Impact
Winners won't be airdropped because the s_amountToAirdrop
which is equal to 4 * (25 * 1e6)
is not aligned with amount used to create the leafs of the merkle tree wich is 25e18
so the function i_airdropToken.safeTransfer(account, amount);
in MerkleAirdrop.sol
will revert because the contract doesn't have enough funds.
Tools Used
Manual review
Recommendations
Use the correct merkle root hash to be aligned with the token distibution announced.
bytes32 public s_merkleRoot = 0x3b2e22da63ae414086bec9c9da6b685f790c6fab200c7918f2879f08793d77bd;