The Snow::earnSnow() function fails to track weekly token claims on a per-user basis. As a result, only one user can claim a token per week globally, instead of each user being allowed to claim once per week individually which breaks the core functionality.
The Snow::earnSnow() function currently uses a single global timestamp s_earnTimer to track when a claim was last made. This implementation restricts the entire system to one token claim per week, regardless of how many users are trying to claim.
This violates a core design invariant which states "The Snow token can either be earned for free onece a week, or bought at anytime, up until during the ::FARMING_DURATION is over."
Due to this flaw, after 12 weeks, only 12 tokens can ever be earned globally, completely blocking all other users from participating. This creates a Denial-of-Service once one user has claimed and severely limits the intended distribution of tokens.
The correct number of distributed tokens is supposed to be 12 tokens * n where "n" is the number of participants.
Vulnerable
Snow::earnSnow
The severity of this issue is High for the following reasons:
Impact: High: a core invariant in the protocol is broken and functionality is limited
Likelihood: High - this issue is trigger each week whenever earnSnow is called.
The existence of this issue causes:
Decreased distribution of Snow tokens than the Protocol intended. This will affect its acceptance and use within the blockchain system.
User dissatisfaction as they cannot claim free tokens and therefore are forced to make purely financial investments.
As proof of the validity of the issue, I have provided the below runnable code.
Description
First User - ashley - calls Snow:;earnSnow and is minted a token
The second user - victory - within the same week tries to obtain a free Snow token.
Victory calls Snow::earnSnow but this call reverts due to the contract tracking claims globally instead of per-user.
Code
Run with: forge test --mt testOnlyOneUserCanEarnFreeSnow -vvv
The recommended mitigation is to replace s_earnTimer with a mapping that contains a user-specific timestamp each time they call earnSnow. Each call will check the mapping to verify that the user is calling a week after they last called.
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.