# Unscaled reserves inflate pool math

Token amounts mixed across different decimal scales, or live decimals()/oracle reads feeding share and reward math

_Area: DeFi accounting and math bugs. Seen in 3 disclosed reports; latest 2025-09-01. Updated 2026-10-29._

## How it works
Pool, reward, and liquidity formulas assume every amount entering the math is expressed in the same unit. When raw token amounts with different decimals are combined without a precision multiplier, or when a divisor like `10 ** token.decimals()` is read live from an attacker-supplied token, the computed value no longer reflects real reserves. The invariant that must hold — value, shares, and rewards are proportional to actual scaled balances — silently breaks, and the error compounds across operations.

## Where it shows up
- Math that divides or multiplies by `10 ** decimals()` fetched at call time rather than cached [E1](https://bugbountylibrary.com/r/sherlock%3A2023-06-bond%3AH-2.md)
- Duplicated `get_dy`/swap math where one copy applies `precision_mul` and the sibling does not [E3](https://bugbountylibrary.com/r/cantina%3Aaquarius_aug2025%3A3.2.4.md)
- Reward or liquidity weighting that consumes pool liquidity computed from unscaled reserves [E3](https://bugbountylibrary.com/r/cantina%3Aaquarius_aug2025%3A3.2.4.md)
- Proportional `addValue`/`removeValue` that scales target and balances together without a `deMinimus` clamp [E2](https://bugbountylibrary.com/r/sherlock%3A2025-04-burve%3AM-5.md)
- Permissionless factories accepting user-supplied tokens whose metadata is attacker-controlled [E1](https://bugbountylibrary.com/r/sherlock%3A2023-06-bond%3AH-2.md)

## How to review
Identify every quantity in the formula and confirm its unit. Check that each token amount is scaled by a precision multiplier before entering shared math, and that any external metadata (decimals, price, oracle) used in amount math is cached at creation, not re-read at exercise/redeem. For invariant-bounded designs, recompute real value from stored balances and compare against `deMinimus * n * target` after sequences of proportional adds/removes — the bound must hold, not just the single-step formula [E2](https://bugbountylibrary.com/r/sherlock%3A2025-04-burve%3AM-5.md). Diff duplicated math implementations line by line [E3](https://bugbountylibrary.com/r/cantina%3Aaquarius_aug2025%3A3.2.4.md).

## Variants seen
- Attacker-controlled `decimals()` changing between create and exercise, making the quote divisor inconsistent [E1](https://bugbountylibrary.com/r/sherlock%3A2023-06-bond%3AH-2.md)
- Missing decimal scaling in a duplicated liquidity calculator while the pool copy was fixed [E3](https://bugbountylibrary.com/r/cantina%3Aaquarius_aug2025%3A3.2.4.md)
- Proportional scaling of target and balances letting value-target delta grow unbounded past `deMinimus` [E2](https://bugbountylibrary.com/r/sherlock%3A2025-04-burve%3AM-5.md)

## Why fixes fail
E3 shows a fix applied to the stableswap `get_dy` but not to the liquidity calculator's copy, leaving rewards overinflated. Duplicated math must be fixed everywhere it appears.

## Impact and severity
E1 led to full drain of the teller; E3 overinflated stable pool liquidity and rewards; E2 broke a documented invariant. Severity is high when the mispriced value gates minting, redemption, or reward distribution, and worse when the error compounds across repeated operations.

## Evidence
- E1: https://bugbountylibrary.com/r/sherlock%3A2023-06-bond%3AH-2.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2025-04-burve%3AM-5.md
- E3: https://bugbountylibrary.com/r/cantina%3Aaquarius_aug2025%3A3.2.4.md
