Snowman Merkle Airdrop

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

[H-2] `Snow::earnSnow()` Function Uses Shared `s_earnTimer` Allowing Only One Address To Earn Snow Per Week

[H-2] Snow::earnSnow() Function Uses Shared s_earnTimer Allowing Only One Address To Earn Snow Per Week

Description

  • All addresses should be able to call the Snow::earnSnow() function during the farming phase once a week to earn Snow tokens before the airdrop.

  • When the first address calls the function, the Snow::s_earnTimer variable is updated for the whole contract, thus disallowing any other address from calling this function to earn Snow tokens.

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 is a common function that everyone has access to and would use before the airdrop.

Impact: High

  • This would effectively cause a Denial-of-Service as others who legitimately want to earn Snow tokens would cause a revert.

Proof of Concept

The following test was added to TestSnow.sol to demonstrate the issue.

function testOnlyOneCanEarnSnow() public {
vm.prank(ashley);
snow.earnSnow();
assert(snow.balanceOf(ashley) == 1);
vm.prank(jerry);
vm.expectRevert(); // Should not revert as Jerry has not earned his free Snow token yet, but reverts
snow.earnSnow();
}

Recommended Mitigation

Instead of all addresses sharing a single s_earnTimer variable, a mapping can be used for each address to store the last claimed time for each address.

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

Under earnSnow():

function earnSnow() external canFarmSnow {
- if (s_earnTimer != 0 && block.timestamp < (s_earnTimer + 1 weeks)) {
+ if (earnTimer[msg.sender] != 0 && block.timestamp < (earnTimer[msg.sender] + 1 weeks)) {
revert S__Timer();
}
_mint(msg.sender, 1);
- s_earnTimer = block.timestamp;
+ earnTimer[msg.sender] = block.timestamp;
}
Updates

Lead Judging Commences

yeahchibyke Lead Judge
3 months ago
yeahchibyke Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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