# Different spot prices used during the comparison

Notional's Balancer composable vault compared spot price (secondary/primary) against oracle price (primary/secondary), so manipulation detection could be bypassed, letting trades execute against a manipulated pool.

- Payout: Contest reward
- Severity: high
- Program: Notional
- Credited: xiaoming90
- Disclosed: 2023-10-09
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2023-10-notional-judging/issues/85
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-10-notional%3AH-7
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:evm tech:solidity technique:source-review vuln:oracle-manipulation

**Target:** BalancerComposableAuraVault / SingleSidedLPVaultBase price check
**Root cause:** StableMath._calcSpotPrice returns spot price Y/X (secondary base / primary quote) while _getOraclePairPrice returns primary/secondary, so the manipulation bounds comparison in _calculateLPTokenValue compares mismatched price orientations.
**Steps:**
1. Read BalancerComposableAuraVault._checkPriceAndCalculateValue: calls SPOT_PRICE.getComposableSpotPrices then _calculateLPTokenValue(balances, spotPrices).
2. Note StableMath._calcSpotPrice comment: 'spot price Y/X' = secondary(base)/primary(quote).
3. Read SingleSidedLPVaultBase._calculateLPTokenValue: `price = _getOraclePairPrice(primaryToken, tokens[i])` returns primary/secondary.
4. Observe bounds `lowerLimit`/`upperLimit` computed from oracle price are compared directly to spotPrices[i] of opposite orientation.
5. Conclude a manipulated pool can pass the check (or cause false-positive reverts), allowing trade execution against manipulated pool.
**How found:** Code review of the spot-price helper and its consumer: noticed the doc comment defining spot price as Y/X (secondary/primary) while the oracle price is primary/secondary, then traced the comparison in _calculateLPTokenValue to confirm the orientation mismatch.
**Exploitation:** Attacker manipulates the Balancer composable pool's balances so the inverted spot price still falls within the oracle-derived bounds; the vault's manipulation guard fails to revert and the trade executes against the manipulated pool, extracting value from the vault.
**Insight:** When a manipulation guard compares a DEX-derived spot price to an oracle, verify both are quoted in the same base/quote orientation; Balancer's _calcSpotPrice returns Y/X which is easily inverted relative to oracle pair conventions.
