# Incorrect assumption in PoolMath.sol can cause underflow when zapping is used

PoolMath._zapSwapAmount right-shifts reserves/zap amounts to 80 bits, zeroing z0 and underflowing r1*z0-r0*z1, reverting zapping deposits.

- Payout: Contest reward
- Severity: medium
- Program: Salty.IO
- Credited: t0x1c
- Disclosed: 2024-04-19
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2024-01-salty-findings/issues/232
- Library page: https://bugbountylibrary.com/r/c4%3A2024-01-salty%3AM-25
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:precision-loss

**Target:** PoolMath.sol _zapSwapAmount / _determineZapSwapAmount (AMM liquidity zapping)
**Root cause:** Normalizing inputs to 80 bits via right shift can reduce z0 to 0, breaking the invariant r1*z0 > r0*z1 that the C computation relies on, causing underflow.
**Steps:**
1. Call PoolMath._determineZapSwapAmount(1500000000, 2000000000 ether, 150, 100 ether).
2. maximumMSB=90 triggers shift=10; z0 = 150>>10 = 0.
3. C = r0*(r1*z0 - r0*z1)/(r1+z1) underflows since r1*z0=0 < r0*z1.
4. Transaction reverts; depositLiquidityAndIncreaseShare with useZapping=true fails.
**How found:** Code-reading of the comment claiming r1*z0 > r0*z1 is guaranteed by the caller's conditional, then noticing the 80-bit right-shift normalization can zero out z0 and violate that invariant.
**Insight:** When a function asserts an invariant guaranteed by its caller, check whether internal precision-reduction (bit shifting) can silently break that invariant before the arithmetic that depends on it.
