# Basket range formula is inefficient, leading the protocol to unnecessary haircut

Reserve's basket range formula over-widens the estimate band (~4% vs <1%), causing unnecessary haircuts and user value loss when a small trade could recollateralize.

- Payout: Contest reward
- Severity: high
- Program: Reserve
- Credited: 0xA5DF
- Disclosed: 2023-04-27
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-01-reserve-findings/issues/235
- Library page: https://bugbountylibrary.com/r/c4%3A2023-01-reserve%3AH-02
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:oracle-manipulation

**Target:** RTokenAsset.basketRange / BackingManager.manageTokens recollateralization logic
**Root cause:** Basket range is computed by dividing total collateral value by basket-unit price using min/max oracle prices, which compounds oracle deviation across all tokens instead of computing a base basket count plus per-token diffs.
**Steps:**
1. Set basket so balances are 99% for 3 tokens and 95% for the 4th via `setPrimeBasket` + `refreshBasket`.
2. Call `rTokenAsset.basketRange()` and observe top ~99.9, bottom ~95.9 (band ~4%).
3. Call `backingManager.manageTokens([])` and observe `basketsNeeded` drops to ~94.9 via haircut despite prices being nearly equal.
4. Compare to expected range ~98±0.03% which would allow a simple trade instead of haircut.
**How found:** Reasoned about how the range band scales with oracle error deviation (±1%) and noticed the band becomes ~4% instead of <1% when collateral is slightly short; confirmed with a PoC test computing range and post-haircut basketsNeeded.
**Insight:** When auditing oracle-price-derived range/bounds math, check whether min/max price deviations are applied per-asset and summed versus applied to an aggregate ratio—aggregation amplifies the band and can trigger lossy fallback paths like haircuts.
