# Hack Analysis: Saddle Finance, April 2022

Saddle Meta pool mispriced LP tokens vs underlying assets due to missing base virtual price scaling, letting an attacker flash-loan and swap-loop to drain ~$11m.

- Payout: Real-world hack
- Severity: critical
- Program: Saddle Finance
- Credited: Immunefi
- Disclosed: 2022-11-17
- Write-up quality: 8/10
- Original: https://immunefi.com/blog/bug-fix-reviews/hack-analysis-saddle-finance-april-2022/
- Library page: https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-hack-analysis-saddle-finance-april-2022
- Tags: domain:web3 impact:funds-loss kind:incident platform:immunefi sev:critical tech:evm tech:solidity technique:incomplete-fix technique:source-review vuln:accounting-error vuln:business-logic vuln:flash-loan vuln:oracle-manipulation

**Target:** Saddle sUSD Meta pool / MetaSwapUtils swap function
**Root cause:** MetaSwapUtils swap-to-LP-token path omitted scaling dy by the base LP token's virtual price, so LP tokens were mispriced relative to underlying assets. The math was correct for deposits/withdrawals and underlying swaps but not for token-to-LP swaps.
**Steps:**
1. Flash loan 15,000,000 USDC from Euler (0x07df2ad9878F8797B4055230bbAE5C808b8259b3) via ERC3156 onFlashLoan hook.
2. Swap USDC to sUSD via Curve sUSD pool 0xA5407eAE9Ba41422680e2e00537571bcC53efBfD using `exchange(1,3,amount,1)`.
3. Approve and swap sUSD to Saddle DAI/USDC/USDT LP token via Meta pool 0x824dcD7b044D60df2e89B1bB888e66D8BCf41491 with `swap(0,1,amount,1,block.timestamp)`.
4. Swap LP token back to sUSD via same pool with `swap(1,0,amount,1,block.timestamp)`, exploiting mispricing to gain ~2m sUSD.
5. Swap sUSD back to USDC via Curve `exchange(3,1,amount,1)`.
6. Approve Euler to pull amount+fee and return `keccak256("ERC3156FlashBorrower.onFlashLoan")` to repay loan, keeping profit.
**How found:** Author notes Saddle reimplemented Curve's Meta pool in Solidity rather than forking Vyper, introducing math inconsistencies; compared line 424 (missing base virtual price scaling) against line 277 where the check is correctly implemented, and recognized the same bug previously exploited on Nerve and Synapse forks.
**Exploitation:** Attacker flash-loaned 15m USDC from Euler (fee-free), converted to sUSD via Curve, then swapped sUSD->LP->sUSD through the mispriced Saddle Meta pool to inflate sUSD balance, converted back to USDC, repaid the loan, and kept ~$2m profit in the PoC (real attack drained ~$11m across three txs).
**Escalation:** Repeated back-and-forth swaps between sUSD and LP token to drain all available Meta pool liquidity, then also drained the standard pool whose LP token was in the Meta pool.
**Insight:** When a protocol reimplements a reference implementation in a different language, diff the math line-by-line against the original for asymmetric paths (e.g., token->LP vs LP->token); known bugs on forks often persist in live pools even after a 'fix' migration.
