Snowman Merkle Airdrop

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

Global earnTimer Causes Denial of Service for Token Farming

Root + Impact

Description

  • Describe the normal behavior in one or more sentences

  • The earnSnow() function uses a single global timer (s_earnTimer) that is shared across all users. When any user successfully calls earnSnow(), they update this global timer, preventing ALL other users from earning tokens for the next week.

  • Explain the specific issue or problem in one or more sentences

  • Only one user globally can earn free Snow tokens per week, creating a winner-takes-all scenario. This severely limits token distribution and makes the farming feature essentially useless for 99.99% of users. MEV bots will likely dominate this function, extracting all farming rewards.

// Root cause in the codebase with @> marks to highlight the relevant section
/ MEV Bot exploitation:
contract FarmingBot {
Snow snow;
function farmAllTokens() external {
// Bot monitors blockchain
// As soon as 1 week passes, bot immediately calls:
snow.earnSnow();

Risk

Likelihood:

  • Reason 1

  • This creates a severe race condition where only the first user to call the function after each week-long cooldown can earn the free token, effectively denying service to all other users. This is a critical design flaw that makes the farming mechanism unusable for the vast majority of users.

  • Reason 2

Impact:

  • Impact 1

  • Only one user globally can earn free Snow tokens per week, creating a winner-takes-all scenario. This severely limits token distribution and makes the farming feature essentially useless for 99.99% of users. MEV bots will likely dominate this function, extracting all farming rewards.

  • Impact 2

Proof of Concept

/ Add per-user timer mapping
mapping(address => uint256) private s_userEarnTimers;
function earnSnow() external canFarmSnow {
if (s_userEarnTimers[msg.sender] != 0 &&
block.timestamp < (s_userEarnTimers[msg.sender] + 1 weeks)) {
revert S__Timer();
}
_mint(msg.sender, 1);
s_userEarnTimers[msg.sender] = block.timestamp;
}

Recommended Mitigation

- remove this code
function earnSnow() external canFarmSnow {
if (s_earnTimer != 0 && block.timestamp < (s_earnTimer + 1 weeks)) {
revert S__Timer();
}
_mint(msg.sender, 1);
s_earnTimer = block.timestamp;
+ add this code/ Add per-user timer mapping
mapping(address => uint256) private s_userEarnTimers;
function earnSnow() external canFarmSnow {
if (s_userEarnTimers[msg.sender] != 0 &&
block.timestamp < (s_userEarnTimers[msg.sender] + 1 weeks)) {
revert S__Timer();
}
_mint(msg.sender, 1);
s_userEarnTimers[msg.sender] = block.timestamp;
}
Updates

Lead Judging Commences

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