# Using balanceOf in _getTotalUnderlyingValue leads to accounting issues in claimRedemptionand liquidation

Alchemist's _getTotalUnderlyingValue uses raw yieldToken balanceOf, letting a redeemer temporarily deposit to inflate TVL, bypass bad-debt haircut in claimRedemption, and withdraw.

- Payout: Contest reward
- Severity: high
- Program: Alchemix
- Credited: touthang
- Disclosed: 2025-07-15
- Write-up quality: 7/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_alchemix_may2025.pdf#3.1.14
- Library page: https://bugbountylibrary.com/r/cantina%3Aalchemix_may2025%3A3.1.14
- Tags: domain:web3 impact:funds-loss kind:contest platform:cantina sev:high tech:evm tech:solidity technique:chained technique:source-review vuln:accounting-error vuln:business-logic vuln:liquidation

**Target:** AlchemistV3 / Transmuter redemption and liquidation accounting
**Root cause:** _getTotalUnderlyingValue() reads IERC20(yieldToken).balanceOf(address(this)), counting free collateral and directly transferred tokens, so TVL (and thus badDebtRatio and collateralization) can be inflated by anyone depositing or transferring yield tokens.
**Steps:**
1. Deploy AlchemistV3 with mock ERC4626 yield token; provider deposits 1,000,000 underlying.
2. Bob deposits 150 yield tokens and mints 100 alETH (totalSyntheticsIssued=100).
3. Jack creates redemption of 100 alETH via Transmuter.
4. Simulate bad debt: withdraw 500,000 underlying from yield token so 1 yield = 0.5 underlying; badDebtRatio = 1.333e18.
5. Jack deposits 500 yield tokens into Alchemist (no debt), inflating getTotalUnderlyingValue; badDebtRatio drops to 0.307e18.
6. Roll past transmute time, call `transmuter.claimRedemption(1)`; Jack receives 200 yield tokens instead of 150 (no haircut).
7. Call `alchemist.withdraw(500 ether, jack, 2)` to recover the inflating deposit.
**How found:** Code review of _getTotalUnderlyingValue noticed it uses raw balanceOf rather than tracked locked collateral, then traced its use in claimRedemption's badDebtRatio and liquidation collateralization to hypothesize temporary inflation.
**Exploitation:** Redeemer (or any third party) temporarily deposits yield tokens into the Alchemist right before claimRedemption, inflating getTotalUnderlyingValue so badDebtRatio falls below 1e18 and the claimAmount/feeAmount haircut is skipped; after claiming the full redemption, the deposit is withdrawn, leaving other redeemers to absorb the bad debt.
**Escalation:** Same inflated TVL also feeds calculateLiquidation's alchemistCurrentCollateralization, causing under-liquidated positions (partial instead of full liquidation) when yield tokens are present.
**Insight:** When a protocol derives solvency ratios from token.balanceOf(address(this)), check every consumer (redemption haircuts, liquidation thresholds) for a deposit-inflate-act-withdraw cycle; free collateral and direct transfers are attacker-controllable TVL.
