AirDropper

AI First Flight #5
Beginner FriendlyDeFiFoundry
EXP
View results
Submission Details
Impact: medium
Likelihood: high
Invalid

No method to fund the contract

Root + Impact

Description

  • Normal behavior: An airdrop contract should hold ERC-20 tokens that it can distribute to claimants; deployer or owner normally deposits tokens into the contract before claims start.

  • Issue: The MerkleAirdrop contract (see MerkleAirdrop.sol) never provides a way to deposit or pull ERC-20 tokens into the contract (the constructor only stores the token address). As a result, claims will attempt to transfer tokens from the contract balance and will fail when the contract holds no tokens.

contract MerkleAirdrop is Ownable {
// ...
constructor(bytes32 merkleRoot, IERC20 airdropToken) Ownable(msg.sender) {
@> i_merkleRoot = merkleRoot;
@> i_airdropToken = airdropToken; // token address is recorded, but no tokens are pulled/transferred into this contract
}
function claim(
address account,
uint256 amount,
bytes32[] calldata merkleProof
) external payable {
// ...
@> i_airdropToken.safeTransfer(account, amount); // transfers from contract balance — but contract may have zero token balance
}
// ...
}

Risk

Likelihood:

  • During airdrop setup, deployer will expect the contract to be funded via a contract method but will not find one, causing claim attempts to fail when users try to redeem tokens.

  • Automated or scripted claim flows will trigger failed transactions and revert gas, because safeTransfer will revert when the contract lacks sufficient token balance.

Impact:

  • All legitimate claims will revert and users will not receive tokens until the contract is funded externally.

  • Lost gas costs and degraded trust in the airdrop; owner may be blamed for a broken distribution flow.

Proof of Concept

// POC (solidity pseudo-test)
// 1) Deploy ERC20 token and Mint some tokens to deployer
// 2) Deploy MerkleAirdrop with merkle root and token address
// 3) Do NOT transfer tokens into the MerkleAirdrop contract address
// 4) Call claim with a valid proof and msg.value == FEE
// Expected: claim reverts when executing i_airdropToken.safeTransfer(...)
merkleAirdrop.claim{value: 1e9}(claimer, amount, proof); // reverts due to insufficient token balance in contract

Recommended Mitigation

- // current contract records the token but offers no deposit method
+ // add a deposit method so owner (or anyone) can fund the contract via approved transfer
+ function fundAirdrop(uint256 amount) external onlyOwner {
+ // owner must `approve(contract, amount)` on the token first
+ i_airdropToken.safeTransferFrom(msg.sender, address(this), amount);
+ }
+
+ // alternatively, allow anyone to top-up:
+ function depositAirdrop(uint256 amount) external {
+ i_airdropToken.safeTransferFrom(msg.sender, address(this), amount);
+ }

Notes: Ensure callers approve the contract (approve(contractAddress, amount)) before calling fundAirdrop / depositAirdrop. Consider emitting an event on deposit and validating total available airdrop balance if needed.

Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 6 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!