# Vault.withdraw mixes normalized and standard amounts

Vault.withdraw compares 18-decimal normalized amounts against raw token balances, letting an attacker withdraw tiny shares for inflated USDC/USDT payouts.

- Payout: Audit contest
- Severity: high
- Program: yAxis
- Found by: cmichel
- Disclosed: 2021-11-10
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2021-09-yaxis-findings/issues/131
- Library page: https://bugbountylibrary.com/r/c4%3A2021-09-yaxis%3AH-08
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** Vault.withdraw / balance normalization in Solidity vault contract
**Root cause:** Vault.balance() normalizes token balances to 18 decimals, but withdraw() compares the normalized _amount against the raw IERC20.balanceOf value and subtracts them directly, mixing decimal scales.
**Steps:**
1. Call Vault.withdraw with _output = USDC (6 decimals) and a tiny share amount.
2. _amount is computed from normalized 18-decimal balance, so it is huge relative to raw USDC units.
3. `if (_balance < _amount)` triggers because raw 6-decimal _balance is far smaller than normalized _amount.
4. `_toWithdraw = _amount.sub(_balance)` yields an inflated 18-decimal value passed to `_controller.withdraw(_output, _toWithdraw)`.
5. Controller withdraws the inflated USDC amount, attacker receives far more than their share value.
**How found:** Code review of Vault.balance() noting _normalizeDecimals padding to 18 decimals, then tracing consumers of balance() and spotting withdraw() comparing the normalized _amount to an unnormalized IERC20.balanceOf value.
**Exploitation:** Attacker deposits/withdraws a minimal share amount specifying a low-decimal output token (USDC/USDT); the normalized _amount dwarfs the raw balance, causing the controller to withdraw and pay out an inflated token amount to the attacker.
**Insight:** When a protocol normalizes decimals in one helper, audit every consumer that mixes that value with raw token balances—especially subtraction/comparison sites—since scale mismatch silently inflates amounts for tokens with <18 decimals.
