Snowman Merkle Airdrop

First Flight #42
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: low
Valid

s_earnTimer is reset on every mint

Root + Impact

Description

  • SNOWshould be able to be earned once per week

  • Current implementation limits the earning of free snow by the resetting of the s_earnTimeron every earn/buy, basically resulting in a running timer that becomes unusable with multiple users

function buySnow(uint256 amount) external payable canFarmSnow {
if (msg.value == (s_buyFee * amount)) {
_mint(msg.sender, amount);
} else {
i_weth.safeTransferFrom(msg.sender, address(this), (s_buyFee * amount));
_mint(msg.sender, amount);
}
//@> s_earnTimer = block.timestamp;
emit SnowBought(msg.sender, amount);
}
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:

  • When one person buys snow multiple times per week, it resets the timer

  • When Person B buys/earns snow while Person A is waiting for the 1 week timer, it resets

Impact:

  • On high activity from users, the timer will likely always be reset before 1 week expires, resulting in no user being able to earn free SNOW

Proof of Concept

Recommended Mitigation

  1. Do not set the timer on buySnow, we want the timer to reset when we call earnSnow as this can only happen once per week. The initial state is correct as the first time it is called the user should receive its first free SNOW.

- uint256 private s_earnTimer;
+ mapping(address => uint256) private s_earnTimer;
function buySnow(uint256 amount) external payable canFarmSnow {
if (msg.value == (s_buyFee * amount)) {
_mint(msg.sender, amount);
} else {
i_weth.safeTransferFrom(
msg.sender,
address(this),
(s_buyFee * amount)
);
_mint(msg.sender, amount);
}
+ // No longer needed
- s_earnTimer = block.timestamp;
emit SnowBought(msg.sender, amount);
}
function earnSnow() external canFarmSnow {
+ uint256 lastEarn = s_earnTimers[msg.sender];
+ if (lastEarn != 0 && block.timestamp < (s_earnTimer + 1 weeks)) {
- if (s_earnTimer != 0 && block.timestamp < (s_earnTimer + 1 weeks)) {
revert S__Timer();
}
_mint(msg.sender, 1);
- s_earnTimer = block.timestamp;
+ s_earnTimers[msg.sender] = block.timestamp;
}
Updates

Lead Judging Commences

yeahchibyke Lead Judge 3 months ago
Submission Judgement Published
Validated
Assigned finding tags:

buying of snow resets global timer thus affecting earning of free snow

When buySnow is successfully called, the global timer is reset. This inadvertently affects the earning of snow as that particular action also depends on the global timer.

Support

FAQs

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