# CompoundStrategy attempts to transfer out a greater amount of ETH than will actually be withdrawn, leading to DoS

CompoundStrategy computes cETH to redeem via exchangeRateStored, but Compound truncates redeemAmount, so received ETH is slightly less than requested, failing the balance check and DoSing withdrawals.

- Payout: Contest reward
- Severity: high
- Program: Tapioca DAO
- Credited: kaden
- Disclosed: 2023-11-16
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-07-tapioca-findings/issues/674
- Library page: https://bugbountylibrary.com/r/c4%3A2023-07-tapioca%3AH-50
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:dos vuln:precision-loss

**Target:** CompoundStrategy._withdraw / CEther.redeem
**Root cause:** Strategy computes cTokens to redeem as amount*1e18/exchangeRate, but Compound's redeemFresh recomputes redeemAmount via mulScalarTruncate, truncating down so the ETH received is slightly less than the requested amount.
**Steps:**
1. Call CompoundStrategy._withdraw(to, amount) where amount > wrappedNative balance.
2. Strategy computes toWithdraw = (amount - queued) * 1e18 / exchangeRateStored.
3. cToken.redeem(toWithdraw) is called; Compound recomputes redeemAmount = truncate(exchangeRate * toWithdraw), which is < requested amount.
4. Post-redeem check `wrappedNative.balanceOf(this) >= amount` fails, reverting the withdrawal.
**How found:** Compared CompoundStrategy's cToken calculation against CEther's redeemFresh math, noticed truncation in mulScalarTruncate yields a smaller redeemAmount than the strategy expects, verified with a Remix reproduction using exchangeRateStored 200877136531571418792530957.
**Exploitation:** Any user withdrawing when wrappedNative balance is insufficient triggers the revert; no attacker capital needed, just normal withdrawal flow causes DoS.
**Insight:** When integrating with Compound-style cTokens, don't compute cToken amounts from exchangeRate and assume exact underlying out; truncation in mulScalarTruncate means redeemUnderlying is the safe primitive for exact-amount withdrawals.
