# The formula of number of prizes for a degree is wrong

DrawCalculator's prize-count formula for a degree over-subtracts lower tiers, shrinking the divisor and paying out larger prizes than designed.

- Payout: Audit contest
- Severity: high
- Program: PoolTogether
- Found by: WatchPug
- Disclosed: 2021-11-05
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2021-10-pooltogether-findings/issues/33
- Library page: https://bugbountylibrary.com/r/c4%3A2021-10-pooltogether%3AH-01
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:reward-distribution

**Target:** DrawCalculator.sol _numberOfPrizesForIndex (Solidity smart contract)
**Root cause:** _numberOfPrizesForIndex subtracts all lower-degree prize counts instead of only the immediately preceding degree, so the computed number of prizes per degree is smaller than the true value.
**Steps:**
1. Read docs formula: prizes(degree) = (2^bitRange)^degree - (2^bitRange)^(degree-1) - ...
2. Inspect `_numberOfPrizesForIndex` loop subtracting `bitRangeDecimal**(_prizeTierIndex-1)` for every lower index
3. Derive correct closed form: f(n) = 2^(bitRange*n) - 2^(bitRange*(n-1))
4. Show divisor is too small, so `prize for a degree = total * degreePct / numberOfPrizes` is inflated
5. Fix: `return (1 << _bitRangeSize*_prizeTierIndex) - (1 << _bitRangeSize*(_prizeTierIndex-1))` for index>0, else 1
**How found:** Compared the documented prize-distribution formula against the Solidity implementation and noticed the loop subtracts every lower degree rather than just the previous one; proved the correct closed form two ways.
**Insight:** When a contract implements a documented combinatorial formula, re-derive the closed form and check the loop's subtraction set — off-by-many in a divisor silently inflates payouts.
