Snowman Merkle Airdrop

First Flight #42
Beginner FriendlyFoundrySolidityNFT
100 EXP
Submission Details
Impact: high
Likelihood: high

Global Timer on earnSnow() Enables Denial of Service

Author Revealed upon completion

Root + Impact

Description

  • The earnSnow() function allows users to mint 1 SNOW token per week during the farming period. A cooldown mechanism is enforced using the s_earnTimer variable.

  • s_earnTimer is a global timestamp shared across all users. This means a single user can call earnSnow() and set the timer, which then blocks everyone else from using the function for the next 7 days. This enables griefing and DoS by any externally owned account.

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

Risk

Likelihood:

  • This will occur any time a user successfully calls earnSnow(), as it unconditionally updates the shared s_earnTimer.

  • It will be exploited when any user wants to block others by repeatedly calling the function before the 1-week window expires.

Impact:

  • Only one address can mint through earnSnow() per 7-day interval, breaking fairness and expected behavior.

  • Repeated exploitation permanently disables earning for everyone else, leading to denial of service and potential centralization of token distribution.

Proof of Concept

contract SnowGriefingPoC {
Snow public snow;
constructor(address _snow) {
snow = Snow(_snow);
}
function grief() external {
// Calls earnSnow() and updates the global s_earnTimer
snow.earnSnow();
}
}

Recommended Mitigation

- uint256 private s_earnTimer;
+ mapping(address => uint256) private s_earnTimers;

Support

FAQs

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