# USM: split-invariance rounding flaw in defund() drains ETH

USM's defund() FUM redemption curve was not split-invariant; redeeming in 64 slices paid more ETH than one call, draining ~70.8 ETH.

- Payout: Real-world hack
- Severity: high
- Program: USM
- Credited: DeFiHackLabs
- Disclosed: 2026-08-09
- Write-up quality: 8/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2026-08/USM_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20260809-usm
- Tags: domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:flash-loan vuln:precision-loss

**Target:** USM stablecoin fund()/defund() redemption curve (Solidity, Ethereum)
**Root cause:** defund() prices ETH off the arithmetic mean of current and estimated-final FUM sell price and contracts adjShrinkFactor per call; this averaging plus integer rounding is not split-invariant, so many small redemptions pay more total ETH than one large redemption.
**Steps:**
1. Flash-loan 11,579.978 WETH from Morpho Blue (0 fee) and unwrap to ETH.
2. Call `USM.fund{value: assets}(address(this), 0)` to mint a large FUM position.
3. Loop 63 times calling `USM.defund(address(this), 971_629_672_368_796_643_705_078, 0)`.
4. Call `USM.defund(address(this), FUM.balanceOf(address(this)), 0)` to burn the remainder.
5. Rewrap borrowed principal via `WETH.deposit` and approve Morpho to repay.
6. Net ~70.8 ETH profit retained.
**How found:** Recognized that defund()'s ETH payout uses the mean of current and estimated-final FUM sell price and mutates adjShrinkFactor per call, making the pricing non-split-invariant; verified oracle reads were identical before/during attack, confirming a pure rounding/state-contraction bug rather than price manipulation.
**Exploitation:** Attacker contract inside Morpho flash-loan callback unwraps WETH, funds a large FUM position, then redeems it in 64 equal slices across consecutive defund() calls; each call's mean-price averaging plus state contraction yields more ETH than a single redemption, so total ETH out exceeds ETH in by ~70.8 ETH after repaying the zero-fee loan.
**Insight:** When a redemption/withdrawal curve prices off an estimated post-trade price and mutates per-call state, test split-invariance: compare one large call vs N small calls of the same total and look for rounding/state-contraction drift that favors the split.
