Snowman Merkle Airdrop

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

Gas Waste via Unused Claimers Array in SnowmanAirdrop Contract

Description

Normal Behavior

The SnowmanAirdrop contract should efficiently manage storage and only allocate gas for variables that are actively used in the contract logic.

Issue Description

The s_claimers array is declared to store addresses of claimers but is never populated throughout the contract, resulting in wasted gas for storage allocation.

Root + Impact

Description

The contract declares a storage array for tracking claimers but fails to utilize it, creating unnecessary gas costs without providing any functionality.

Root Cause

// @> Unused storage array declared but never populated
address[] private s_claimers; // array to store addresses of claimers
// @> This array is never written to or read from in any function

The claimSnowman() function processes claims but never adds addresses to the s_claimers array 2 .

Risk

Likelihood:

  • Reason 1: The array is declared in storage but never written to during contract execution

  • Reason 2: No functions read from or modify the s_claimers array

Impact:

  • Impact 1: Unnecessary gas costs for storage slot allocation during deployment

  • Impact 2: Confusing code structure that suggests functionality that doesn't exist

  • Impact 3: Potential future maintenance issues if developers assume the array is being used

Proof of Concept

function testUnusedClaimersArray() public {
// Deploy contract and perform claims
vm.prank(alice);
snow.approve(address(airdrop), 1);
bytes32 aliceDigest = airdrop.getMessageHash(alice);
(uint8 aliceV, bytes32 aliceR, bytes32 aliceS) = vm.sign(aliceKey, aliceDigest);
vm.prank(satoshi);
airdrop.claimSnowman(alice, ALICE_PROOF, aliceV, aliceR, aliceS);
// Check that claimers array is still empty despite successful claim
address[] memory claimers = airdrop.getClaimers(); // This function doesn't exist but would show empty array
assertEq(claimers.length, 0); // Array remains unused
}

Recommended Mitigation

contract SnowmanAirdrop is EIP712, ReentrancyGuard {
using SafeERC20 for Snow;
// >>> ERRORS
error SA__InvalidProof();
error SA__InvalidSignature();
error SA__ZeroAddress();
error SA__ZeroAmount();
// >>> TYPE
struct SnowmanClaim {
address receiver;
uint256 amount;
}
// >>> VARIABLES
- address[] private s_claimers; // array to store addresses of claimers
bytes32 private immutable i_merkleRoot; // Merkle root used to validate airdrop claims
Snow private immutable i_snow; // Snow token to be staked for the airdrop
Snowman private immutable i_snowman; // Snowman nft to be claimed
mapping(address => bool) private s_hasClaimedSnowman; // mapping to verify if an address has claimed Snowman

Alternatively, if claim tracking is desired, implement proper functionality:

function claimSnowman(address receiver, bytes32[] calldata merkleProof, uint8 v, bytes32 r, bytes32 s)
external
nonReentrant
{
// ... existing validation logic ...
s_hasClaimedSnowman[receiver] = true;
+ s_claimers.push(receiver); // Actually use the array
emit SnowmanClaimedSuccessfully(receiver, amount);
i_snowman.mintSnowman(receiver, amount);
}
function getClaimers() external view returns (address[] memory) {
return s_claimers;
}
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 3 hours 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!