50450 sc high logic error in streak validation causes legitimate jackpot wins to be denied violating reward contract expectations
Submitted on Jul 24th 2025 at 19:18:58 UTC by @Bug82427 for Attackathon | Plume Network
Report ID: #50450
Report Type: Smart Contract
Report severity: High
Target: https://github.com/immunefi-team/attackathon-plume-network/blob/main/plume/src/spin/Spin.sol
Impacts: Contract fails to deliver promised returns, but doesn't lose value
Description
In the Spin contract, jackpot eligibility is determined during handleRandomness() by checking whether userDataStorage.streakCount is greater than or equal to (currentWeek + 2). However, this streak count reflects the user’s state before the current spin. Since updateUserData() is called after this check, users spinning their way into jackpot eligibility are denied their rightful rewards.
This is a classic logic flaw in state-dependent access control, where stale state is used to make a reward decision. The impact is that users who legitimately earn jackpot eligibility during their current spin will have their win silently discarded if they land on the jackpot, despite meeting all conditions.
While no funds are stolen or transferred, the jackpot — which should have been won — is withheld. The spin fee is still consumed and non-refundable. This results in broken reward mechanics and undermines user trust. The jackpot funds remain in the contract but the user’s reward is lost forever due to a flawed conditional check.
Proof of Concept
Assumptions:
currentWeek = 3Jackpot eligibility requires
streakCount ≥ currentWeek + 2 = 5Player Alice has
streakCount = 4before spinningAlice is about to spin and successfully lands on a jackpot
Execution trace (stepper):
Oracle returns randomness
The Supra oracle later calls
handleRandomness(...)with a result corresponding torewardCategory = "Jackpot".Inside
handleRandomness(), the contract retrieves Alice’suserDataStorage:streakCount == 4lastSpinWeek == currentWeek == 3
During this spin,
streakCountwould be incremented to 5 byupdateUserData(), but that update has not yet run.
Conclusion
State-dependent reward checks use a stale streakCount (pre-spin) before updateUserData() runs, which causes legitimate jackpot wins earned during the current spin to be denied. This breaks the reward mechanics: users pay the spin fee but may be incorrectly prevented from receiving a jackpot they earned that same spin.
References
Target contract: https://github.com/immunefi-team/attackathon-plume-network/blob/main/plume/src/spin/Spin.sol
Was this helpful?