Snowman Merkle Airdrop

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

Unlimited Snow Token Inflation via earnSnow() (No Per-User Limit / Supply Cap)

Root + Impact

Description

Normal Behavior

The earnSnow() function is intended to allow each user to mint 1 Snow token per week for free, until the farming period ends.

This mechanism is expected to:

  • Enforce a per-user limit

  • Prevent a single address from accumulating an unfair share of Snow supply

Issue

The earnSnow() function enforces a global cooldown using s_earnTimer, instead of tracking minting per user.

There is:

❌ No per-user mint tracking

❌ No per-user limit

❌ No global supply cap

As a result, the same address can mint Snow tokens indefinitely, once every week, for the entire farming duration.

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;
}

Because the timer is global and not tied to msg.sender, nothing prevents the same address from repeatedly calling earnSnow() every week.

Risk

Likelihood:

  • Reason 1: Permissionless — any address can call earnSnow()

  • Reason 2: No special timing or setup required

  • Reason 3: Fully deterministic and repeatable

Impact:

  • Impact 1: A single user can accumulate an outsized share of Snow supply for free

  • Impact 2: Token supply inflation undermines Snow’s intended economic model

  • Impact 3: Fair distribution assumptions are violated

Proof of Concept

This proof of concept demonstrates that earnSnow() lacks per-user enforcement and allows unlimited free minting by the same address over time.

1. Attacker calls earnSnow()
1 Snow is minted to attacker
→ s_earnTimer is set
2. Attacker waits 1 week
3. Attacker calls earnSnow() again
→ Another Snow token is minted to the same address
4. Steps 23 can be repeated every week until FARMING_DURATION ends
→ Unlimited Snow tokens minted by a single address

No additional accounts, permissions, or external contracts are required.

Recommended Mitigation

Track free mint eligibility per user and optionally enforce a maximum number of free mints.

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

Optionally:

// enforce a max number of free mints per address
mapping(address => uint256) public freeMints;
uint256 public constant MAX_FREE_MINTS = X;
Updates

Lead Judging Commences

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