Snowman Merkle Airdrop

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

Users are unable to earn a free token per week

Due to s_earnTimer being a global variable if a single user either buys a snow token or if a user claims the free token then the timer resets and now users have to wait even longer even if they didn't claim a free token in a week.

Description

  • when a user buys a snow token or if somebody claims a free token after a week it resets the s_earnTimer to the current block.timestamp meaning that the timer restes to 0.

  • the problem is that if a user waits 1 week to claim a free token and another users either buys a token or claim their free token then the timer resets for every other users using the contract. Which will result in the first user waiting even longer to claim a free token.

// >>> EXTERNAL FUNCTIONS
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: High

  • This would happen anytime a user either buys a snow token or either a user earns a free snow token after a week.

Impact: High

  • When a user buys or earns a snow token the s_earnTimer gets set to the current block.timestamp meaning that the timer gets reset. And since s_earnTimer is a global variable it restes the time timer for every user in the contract. Making the earnSnow function useless since no one would be able to claim a free token due to the timer being reset every time.

Proof of Concept

-Alice waits 1 week like intended to earn a free token
-Bob calls the buySnow function and buys a snow token
-s_earnTimer is then set to the current block.timestamp at the end of the function
-This resets the timer for every other user
-2 minutes later Alice calls the earnSnow function but the function reverts due to the timer resetting
-Now Alice has to wait another week to claim a free token(Alice might even wait longer if someone else comes and buys a snow token resetting the timer again)

Recommended Mitigation

A good fix would have every user have their own timer

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

Lead Judging Commences

yeahchibyke Lead Judge 17 days 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.