Snowman Merkle Airdrop

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

Users who buySnow() prevent others from being able to earnSnow() for one week past the transaction.

[M-1] Snow::buySnow() Resets the earn timer when called, requiring all users to wait one week after purchasing before being able to use Snow::earnSnow() again, allowing only one user to earn per wekk

Description:
In Snow.sol on line 87, s_earnTimer gets reset after the user buys snow, this causes the user to need to wait a week after purchasing before they can earn snow again, essentially punishing all other users because of one person buying snow.

this contradicts the about section of the repo which states that "* The Snow token can either be earned for free onece a week, or bought at anytime, up until during the ::FARMING_DURATION is over."

the statement above does not specify that all users share one exclusive chance to earn once per week and that there is only one winner.

Impact:
A user that buys snow will will prevent all other users from being able to call earnSnow() for one week from user "A's" transaction time, denying them the ability to earn snow

Proof of Concept:
My script is not working, but the logic holds true

Time Alice (passive, wants to earn) Bob (active, keeps buying snow) s_earnTimer Value Can Alice earn?
Day 0 Calls earnSnow()
Day 0 ✅ Yes
Day 3
Calls buySnow() Day 3 ❌ No
Day 7 Tries to call earnSnow()
Day 3 ❌ No (Day 7 < Day 10)
Day 10
Calls buySnow() Day 10 ❌ No
Day 17 Tries to call earnSnow()
Day 10 ❌ No (Day 17 < Day 17)
Day 18
Calls buySnow() Day 18 ❌ No

Alice is unable to try earning snow because bob keeps buying snow, denying alice the ability to partake.

Recommended Mitigation:
Correct the documentation to reflect this and remove the following line from buySnow, in order to allow earning irrespective of buying:

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

Additionally s_earnTimer could be made a non global value if we want each individual user to be able to earnSnow() once per week even after buying. By modifying line 30 in Snow.sol:

Change this:
- uint256 private s_earnTimer;
To this:
+ mapping(address => uint256) private s_earnTimer;
Updates

Lead Judging Commences

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