# Saddle Finance metapool swap mispricing drains $10M

Saddle USDv2 metapool swap mispriced sUSD/SaddleUSDV2, letting an attacker flash-loan $15M USDC and drain ~$10M via repeated swaps.

- Payout: Real-world hack
- Severity: critical
- Program: Saddle Finance
- Analysis by: DeFiHackLabs
- Disclosed: 2022-04-30
- Write-up quality: 6/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2022-04/Saddle_exp.sol
- Library page: http://bugbountylibrary.com/r/dhl%3A20220430-saddle
- Tags: area:web3 domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:critical tech:evm tech:solidity vuln:accounting-error vuln:flash-loan vuln:oracle-manipulation

**Target:** Saddle USDv2 metapool swap() on Ethereum mainnet
**Root cause:** The Saddle USDv2 metapool's swap pricing between sUSD and the pool LP token (SaddleUSDV2) was manipulable, so swapping in and out of the metapool at skewed rates extracted value from the pool.
**Steps:**
1. Flash-loan 15,000,000 USDC from Euler (`flashLoan(address(this), usdc, 15_000_000e6, ...)`)
2. Approve and swap USDC->sUSD on Curve sUSD pool via `exchange(1, 3, amount, 1)`
3. Approve sUSD to Saddle pool `0x824dcD7b044D60df2e89B1bB888e66D8BCf41491` and call `swap(0, 1, amount, 1, block.timestamp)` to get SaddleUSDV2
4. Approve SaddleUSDV2 and call `swap(1, 0, amount, 1, block.timestamp)` to swap back to sUSD
5. Swap sUSD->USDC on Curve via `exchange(3, 1, amount, 1)`
6. Repay Euler flash loan with fee; keep remaining USDC (~$10M profit)
**Exploitation:** Attacker flash-borrowed 15M USDC from Euler, routed through Curve to sUSD, then performed a round-trip swap sUSD->SaddleUSDV2->sUSD on the Saddle metapool at a manipulated rate, converted back to USDC on Curve, repaid the loan and kept ~$10M.
**Insight:** Metapools that price their own LP token as a swap asset are vulnerable to round-trip swaps: check whether swapping into and out of the LP token in one tx yields more of the underlying than deposited, especially when the LP token price is derived from pool balances rather than an external oracle.

