# Vault's withdrawFromProtocol incorrectly scales amount to be withdrawn

Vault.withdrawFromProtocol scales amount to LP-token decimals before passing to Provider.calcShares(), which expects underlying decimals, causing 100x over-withdrawal for cUSDC.

- Payout: Contest reward
- Severity: high
- Program: Derby
- Credited: hyh
- Disclosed: 2022-10-17
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2023-01-derby-judging/issues/132
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-01-derby%3AH-11
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:precision-loss

**Target:** Vault.withdrawFromProtocol / Provider.calcShares in Derby yield optimiser
**Root cause:** withdrawFromProtocol converts _amount from vaultCurrency to LP-token decimals via protocol.uScale, but all Provider.calcShares() implementations expect the amount in underlying-token decimals, so the two scaling conventions collide whenever LP and underlying decimals differ.
**Steps:**
1. Note vaultCurrency == underlying (USDC, 6 decimals); CompoundProvider LP is cUSDC (8 decimals), so protocol.uScale = 10^8.
2. Call withdrawFromProtocol(compound_usdc_01, 10^12) intending to withdraw 10^6 USDC.
3. Observe `_amount = (10^12 * 10^8) / 10^6 = 10^14` passed to calcShares.
4. CompoundProvider.calcShares treats 10^14 as USDC amount and computes shares for ~10^8 USDC (100x the intended withdrawal).
**How found:** Code reading of withdrawFromProtocol's decimal conversion against each Provider's calcShares() NatSpec ('_amount Amount in underlying token e.g USDC'), spotting the mismatch between uScale (LP decimals) and the underlying-decimal expectation, then computing the concrete 100x factor for cUSDC.
**Exploitation:** Any vault rebalance/withdrawal path invoking withdrawFromProtocol with a non-trivial amount against a protocol whose LP decimals differ from underlying (Compound cTokens=8, Idle=18) withdraws a scaled-up amount, misbalancing the vault and shifting effective distribution away from expected allocations, causing depositor losses.
**Insight:** When a struct field like uScale encodes LP-token decimals, verify every consumer's unit expectation separately — a single scaling variable reused across an internal conversion and an external calcShares() call is a classic unit-mismatch bug; check LP vs underlying decimals for each integrated protocol (cTokens=8, Idle=18).
