# Too many rewards are distributed when a draw is closed

RngRelayAuction.rngComplete double-counts reserveForOpenDraw after closeDraw already folded it into reserve, overpaying RNG auction/relay recipients.

- Payout: Contest reward
- Severity: high
- Program: PoolTogether
- Credited: dirk\_y
- Disclosed: 2023-09-07
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-08-pooltogether-findings/issues/139
- Library page: https://bugbountylibrary.com/r/c4%3A2023-08-pooltogether%3AH-01
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:accounting-error vuln:reward-distribution

**Target:** RngRelayAuction.rngComplete / PrizePool reserve accounting
**Root cause:** After prizePool.closeDraw() adds the prior reserveForOpenDraw into reserve(), rngComplete still computes futureReserve as reserve() + reserveForOpenDraw(), counting two draws' pending reserves instead of one.
**Steps:**
1. Call `computeRewards(auctionResults)` off-chain: totalReserve = `prizePool.reserve() + prizePool.reserveForOpenDraw()` — correct baseline.
2. Relayer calls `rngComplete(_sequenceId, _randomNumber, _auctionResults)`; inside, `prizePool.closeDraw(_randomNumber)` folds prior reserveForOpenDraw into reserve().
3. Contract then sets `futureReserve = prizePool.reserve() + prizePool.reserveForOpenDraw()`, now including the next draw's pending reserve.
4. `RewardLib.rewards(auctionResults, futureReserve)` pays RNG auction and relay recipients a fraction of the inflated reserve, overpaying them.
**How found:** Reading rngComplete flow: noticed computeRewards correctly uses reserve()+reserveForOpenDraw() pre-close, but the same formula is reused post-closeDraw when reserve() already absorbed the prior open-draw amount — a state-ordering double count.
**Exploitation:** A relayer/bot observes the inflated futureReserve and relays the auction result, receiving rewards computed on a reserve that includes tokens not yet added, extracting excess tokens from the prize pool reserve.
**Insight:** When a helper computes a value pre-state-change and the same formula is reused after the state change, check whether the mutation already folded in the term — ordering bugs in reserve/accounting snapshots are common in draw/settlement flows.
