# When a D3MM pool repays all of the borrowed funds to vault using `D3Funding.sol repayAll`, an attacker can steal double the amount of those funds from vault

D3VaultFunding._poolRepayAll subtracts instead of adds the repaid amount to vault balance, letting an attacker deposit/withdraw the phantom difference and drain 2x the repayment.

- Payout: Contest reward
- Severity: high
- Program: Dodo
- Credited: 0x4db5362c
- Disclosed: 2023-06-14
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2023-06-dodo-judging/issues/217
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-06-dodo%3AH-5
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** D3Vault / D3Funding smart contracts (Solidity)
**Root cause:** In _poolRepayAll, info.balance is decremented by the repaid amount instead of incremented, so the vault's recorded balance diverges from its real token balance by 2x the repayment.
**Steps:**
1. Vault holds 100,000 USDC; pool borrows 20,000 USDC.
2. Pool calls D3Funding.repayAll(token) -> D3VaultFunding.poolRepayAll -> _poolRepayAll.
3. _poolRepayAll sets totalBorrows=0 and balance=100,000-20,000=80,000, then transfers 20,000 USDC from pool to vault (real balance 120,000).
4. Attacker calls userDeposit(user, token): amount = realBalance - info.balance = 120,000-80,000 = 40,000; dTokens minted, info.balance=120,000.
5. Attacker calls userWithdraw(user, token) to redeem 40,000 USDC, draining the phantom difference.
**How found:** Code review of the repay path: noticed _poolRepayAll decrements info.balance while also transferring tokens in, contradicting the intended 'increase balance' step, then traced how userDeposit computes amount from realBalance - info.balance to realize the gap is claimable.
**Exploitation:** Attacker monitors for a pool's repayAll call, then front-runs/immediately calls userDeposit to capture the 2x discrepancy as newly minted dTokens, and withdraws the underlying USDC from the vault for risk-free profit.
**Insight:** When auditing vault-style accounting, compare every state update against the actual token transfer direction; any place where recorded balance moves opposite to real balance creates a claimable delta via deposit/withdraw share math.
