# Strategy Migration May Leave Tokens in the Old Strategy Impacting Share Calculations

Strategy migrate() assumes full withdrawal; partial withdrawal leaves tokens in old strategy, undervaluing totalValue() and overstating shares for new depositors, diluting existing holders.

- Payout: Audit contest
- Severity: high
- Program: prePO
- Found by: kirk-baird
- Disclosed: 2022-05-09
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2022-03-prepo-findings/issues/26
- Library page: https://bugbountylibrary.com/r/c4%3A2022-03-prepo%3AH-01
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:share-inflation

**Target:** SingleStrategyController.migrate() / Collateral.deposit() share math
**Root cause:** migrate() withdraws _oldStrategy.totalValue() but yield protocols may return less than requested; leftover tokens are excluded from totalValue(), so share price is understated.
**Steps:**
1. Deploy strategy where withdraw(amount) transfers less than amount (illiquid lending pool).
2. Owner calls `migrate(newStrategy)`; `_oldStrategy.withdraw(address(this), _oldStrategyBalance)` returns partial funds.
3. Leftover tokens remain in old strategy but `totalValue()` only counts new strategy.
4. User calls `Collateral.deposit()`; `_shares = (_amountToDeposit * totalSupply()) / _valueBefore` overstates shares due to low _valueBefore.
5. Call `migrate()` back to old strategy so totalValue() includes stuck tokens; new depositor withdraws overstated `_owed`, draining value from prior holders.
**How found:** Code review of migrate() noticed it trusts withdraw() to return the full requested amount and never verifies old strategy balance is zero, then traced how totalValue() feeds deposit share math.
**Exploitation:** Owner-triggered migration into an illiquid strategy leaves residual tokens; a depositor mints inflated shares at depressed totalValue(), then after migrating back the recovered tokens inflate totalValue() and the depositor redeems more than deposited, socializing loss to existing shareholders.
**Insight:** When integrating external yield protocols, never assume withdraw(amount) transfers exactly amount; verify post-withdraw balances and ensure accounting totals include any residual value, since share-price math amplifies small accounting gaps into dilution.
