# IdleProvider's balanceUnderlying and calcShares outputs are misscaled by up to 10^12

IdleProvider.balanceUnderlying and calcShares mis-scale by underlying vs LP token decimals, overstating USDC/USDT balances 10^12x and understating shares, corrupting vault rebalancing.

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

**Target:** IdleProvider.sol (yield optimizer provider adapter)
**Root cause:** balanceUnderlying divides by 10^underlyingDecimals while exchangeRate is already scaled to underlying decimals, leaving LP token (18) decimals; calcShares multiplies by 10^underlyingDecimals instead of 1e18, leaving underlying decimals.
**Steps:**
1. Note Idle LP tokens are 18 decimals; underlying (USDC/USDT) are 6 decimals.
2. balanceUnderlying: `(balanceShares * tokenPrice()) / 10**underlyingDecimals` yields 18-decimal output, overstating by 10^12 for USDC.
3. calcShares: `(_amount * 10**underlyingDecimals) / tokenPrice()` yields 6-decimal output, understating shares by 10^12.
4. These feed Vault.rebalanceCheckProtocols, pullFunds, and withdrawFromProtocol, corrupting allocation math.
5. Fix: divide/multiply by 1e18 instead of 10**underlyingDecimals.
**How found:** Code review of IdleProvider scaling: noticed exchangeRate() (tokenPrice) is documented as 'price in underlying' and already carries underlying decimals, so the extra 10**decimals factor double-counts decimals.
**Insight:** When adapting a provider, verify the scaling convention of the protocol's price oracle (tokenPrice/exchangeRate) against the LP token decimals rather than assuming it matches the underlying token's decimals.
