# `LMPVault._withdraw()` can revert due to an arithmetic underflow

LMPVault._withdraw loop computes totalAssetsToPull - max(debtDecrease, totalAssetsPulled) after debtDecrease exceeds totalAssetsToPull, underflowing and reverting user withdrawals.

- Payout: Contest reward
- Severity: medium
- Program: Tokemak
- Credited: Flora
- Disclosed: 2023-06-30
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-06-tokemak-judging/issues/519
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-06-tokemak%3AM-3
- Tags: domain:web3 impact:dos kind:contest platform:sherlock sev:medium tech:solidity technique:source-review vuln:accounting-error vuln:dos

**Target:** LMPVault.sol _withdraw / _calcUserWithdrawSharesToBurn
**Root cause:** Loop only breaks when totalAssetsPulled >= totalAssetsToPull, but maxAssetsToPull is computed as totalAssetsToPull - max(debtDecrease, totalAssetsPulled); if debtDecrease alone exceeds totalAssetsToPull the subtraction underflows.
**Steps:**
1. Deposit 1500 baseAsset into LMPVault.
2. Rebalance 700 to DV1, 600 to DV2, 200 to DV3.
3. Drop DV2 price to 70% (7e17) so its 600 is worth 420.
4. Call `_lmpVault.redeem(1000, address(this), address(this))`.
5. Loop processes DV2, debtDecrease exceeds totalAssetsToPull, next iteration computes totalAssetsToPull - max(...) and reverts on underflow.
**How found:** Code reading of the _withdraw loop: noticed the loop exit condition uses totalAssetsPulled while the per-iteration maxAssetsToPull uses max(debtDecrease, totalAssetsPulled), a mismatch that allows debtDecrease to exceed totalAssetsToPull.
**Insight:** When a loop's exit condition and its per-iteration subtraction use different operands (pulled vs max(debtDecrease,pulled)), a destination vault with a large debtDecrease can push the max above the target and underflow the next iteration's subtraction; check every loop that subtracts a max() from a target.
