Snow.sol::s_earnTimer
Locks Rewards for All UsersThe s_earnTimer
in Snow.sol
is implemented as a single, global state variable. This means that when any single user successfully calls the earnSnow()
function, this s_earnTimer
is updated, and the cooldown period (1 week) is applied to all users. Consequently, if one user earns Snow, no other user can earn for the entire 1-week duration, irrespective of their individual earning history.
This design creates a significant griefing risk. A malicious or uncoordinated user could repeatedly call earnSnow()
(or multiple accounts could collaborate), continuously resetting the global timer. This effectively prevents the entire community from earning Snow tokens for extended periods, severely undermining the intended reward mechanism and user engagement.
1. User A calls `earnSnow()`.
2. `s_earnTimer` is updated to `block.timestamp`.
3. User B, even if they have never earned before, attempts to call `earnSnow()`.
4. The transaction for User B reverts with `S__Timer()`, because `block.timestamp < s_earnTimer + 1 weeks` is true for everyone.
Add the following test function in `TestSnow.t.sol` to demonstrate the vulnerability:
```javascript
function testGlobalTimerGriefing() public {
vm.prank(ashley);
snow.earnSnow(); // Ashley successfully earns, updating global timer
assertEq(snow.balanceOf(ashley), 1);
vm.prank(jerry);
vm.expectRevert(); // Jerry attempts to earn immediately after, but is blocked
snow.earnSnow();
}
```
Replace the single global s_earnTimer
with individual timers for each user. This can be achieved by using a mapping mapping(address => uint256) private s_userEarnTimer;
to store the last earned timestamp for each address.
```diff
+ mapping(address => uint256) private s_userEarnTimer; // New: Per-user timer mapping
function earnSnow() external canEarnSnow {
- if (block.timestamp < s_earnTimer + 1 weeks) {
+ if (block.timestamp < s_userEarnTimer[msg.sender] + 1 weeks) { // Check specific user's timer
revert S__Timer();
}
_mint(msg.sender, 1); // Or whatever the earning amount is
- s_earnTimer = block.timestamp; // Problematic: Updates global timer
+ s_userEarnTimer[msg.sender] = block.timestamp; // Recommended: Update user's specific timer
emit SnowEarned(msg.sender, 1);
}
```
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.