# Locking rewards tokens in Staking contract when there are no stakes

Staking contract's rewardPerTokenStored isn't updated when totalSupply is zero, so rewards sent during no-stake periods are permanently locked.

- Payout: Contest reward
- Severity: medium
- Program: Wenwin
- Credited: Haipls
- Disclosed: 2023-04-12
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-03-wenwin-findings/issues/76
- Library page: https://bugbountylibrary.com/r/c4%3A2023-03-wenwin%3AM-07
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** Staking.sol reward accounting (Solidity)
**Root cause:** rewardPerToken() returns rewardPerTokenStored unchanged when _totalSupply == 0, so rewards transferred while no one is staked are never accounted for and remain stuck in the contract.
**Steps:**
1. Deploy protocol; buy tickets and call `lottery.claimRewards(LotteryRewardType.STAKING)` before any stake exists — reward tokens land in Staking with totalSupply 0.
2. First user stakes; `rewardPerTokenStored` stays 0 and `lastUpdateTicketId` advances, so pre-stake rewards are excluded.
3. User exits (totalSupply back to 0); further claimed rewards again accumulate unaccounted.
4. Observe rewardToken.balanceOf(staking) grows while rewardPerTokenStored never reflects it — funds locked forever.
**How found:** Code-reading of Staking.rewardPerToken() and the `_totalSupply == 0` early return, then reasoned about the claimRewards flow in Lottery.sol pushing rewards to Staking before any stake exists; confirmed with a Foundry test logging balances vs rewardPerTokenStored.
**Insight:** In Synthetix-style staking reward accounting, the zero-totalSupply branch silently drops rewards; check whether reward tokens can be pushed to the contract while totalSupply is 0 (e.g. via a separate claim function) — those tokens become permanently stranded.
