Snowman Merkle Airdrop

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

Global Timer in earnSnow allows any user to Grief/DoS all other participants

Root + Impact

Description

The earnSnow function uses a single global variable s_earnTimer to manage the one-week cooldown for rewards.

uint256 public s_earnTimer;
// ...
if (block.timestamp < s_earnTimer) revert SnowmanAirdrop__WaitLonger();
s_earnTimer = block.timestamp + 1 weeks;

When any user successfully calls earnSnow, the timer is reset for everyone. A malicious actor (or even a regular user) can call this function as soon as the timer expires, effectively locking every other eligible user out of their rewards for another week.

Risk

Impact:

High. This is a permanent Denial of Service (DoS) for rewards. An attacker can ensure they are always the only one to receive tokens, or simply prevent anyone from receiving them by automating a call every 7 days.

Proof of Concept

function test_GriefingGlobalTimer() public {
// 1. Wait for the 1-week cooldown to pass
vm.warp(block.timestamp + 1 weeks + 1);
// 2. Attacker claims first
vm.prank(attacker);
airdrop.earnSnow();
// 3. Victim tries to claim immediately after
vm.prank(victim);
vm.expectRevert(SnowmanAirdrop.SnowmanAirdrop__WaitLonger.selector);
airdrop.earnSnow();
console2.log("Victim was successfully griefed by the global timer.");
}

Recommended Mitigation

Replace the global uint256 with a mapping to track cooldowns on a per-user basis.

// Change state variable
mapping(address => uint256) public s_lastEarnedTimestamp;
// Update function
function earnSnow() external {
if (block.timestamp < s_lastEarnedTimestamp[msg.sender] + 1 weeks) {
revert SnowmanAirdrop__WaitLonger();
}
s_lastEarnedTimestamp[msg.sender] = block.timestamp;
_mintSnow(msg.sender);
}
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 2 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!