# Pair price may be manipulated by direct transfers

Caviar Pair.price derives reserves from live token balances, so an attacker can shift the reported price via direct transfers and drain third-party oracle integrations.

- Payout: Contest reward
- Severity: medium
- Program: Caviar
- Credited: Jeiwan
- Disclosed: 2023-01-26
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-12-caviar-findings/issues/383
- Library page: https://bugbountylibrary.com/r/c4%3A2022-12-caviar%3AM-05
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:oracle-manipulation

**Target:** Pair.sol AMM pool price function
**Root cause:** baseTokenReserves()/fractionalTokenReserves() read live ERC20/ETH balances instead of internally tracked reserves, so direct transfers change the computed price without respecting the K invariant.
**Steps:**
1. Identify Pair.price()/baseTokenReserves() reading ERC20(baseToken).balanceOf(address(this)) and balanceOf[address(this)]
2. Directly transfer base or fractional tokens to the Pair contract to skew the balance ratio
3. Read Pair.price() (or have an integration read it) to observe the manipulated spot price
4. Exploit the mispriced oracle in a third-party integration to extract value
**How found:** Code reading of the reserve/price functions: noticed price is computed from live contract balances rather than stored reserves, and that only initial liquidity and K-checked trades are supposed to move price, implying direct transfers bypass that constraint.
**Exploitation:** Attacker donates tokens directly to the Pair to move the spot price reported by price(), then trades against an integration that consumes Pair.price() as an oracle, profiting from the mispricing.
**Insight:** When an AMM exposes a spot price derived from balanceOf, check whether direct transfers can move it without the invariant check; spot oracles are manipulable, only time-weighted cumulative prices resist donation attacks.
