Each user is supposed to be able to earn free Snow once per week, on their own independent weekly schedule.
s_earnTimer is a single global storage variable rather than a per-user mapping. earnSnow reverts while block.timestamp < s_earnTimer + 1 weeks, and both earnSnow and buySnow overwrite s_earnTimer = block.timestamp. As a result only one address in the entire system can earn per week, and any buySnow call resets the window for everyone. (Separately, earnSnow mints 1 wei instead of 1e18, so the "free token" is 1e-18 of a token.)
```solidity
// src/Snow.sol
@> if (block.timestamp < s_earnTimer + 1 weeks) revert S__Timer();
_mint(msg.sender, 1); // mints 1 wei, not 1 whole token
@> s_earnTimer = block.timestamp; // GLOBAL timer, shared by all users; also set by buySnow()
```
Because the timer is global and not keyed by msg.sender, one user's action sets the cooldown for the whole protocol.
Likelihood:
Occurs the moment any single user calls earnSnow (or anyone calls buySnow) in a given week, which sets the global timer and reverts the next caller regardless of that caller's own history.
An attacker repeatedly calling buySnow keeps the timer pinned indefinitely, continuously griefing the free-earn feature for the entire user base at negligible cost.
Impact:
Denial-of-service of the core "earn weekly for free" mechanism for all users — at most one address can ever earn in any given week.
The advertised per-user weekly free earn is unusable for everyone but the first caller.
User A earns successfully, which sets the global timer. User B — who has never earned — is immediately blocked:
```solidity
function test_global_timer_blocks_other_users() public {
vm.prank(alice);
snow.earnSnow(); // sets the GLOBAL s_earnTimer
}
```
The same revert occurs for every other user for a full week, and any buySnow call restarts the week.
Make the timer per-user by keying it on msg.sender, mint a whole token, and stop resetting it in buySnow:
```diff
uint256 private s_earnTimer;
mapping(address => uint256) private s_earnTimer;
function earnSnow() external {
}
// remove the s_earnTimer assignment from buySnow() entirely
```
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.