# Liquidations for insolvent positions revert

AlchemistV3._subDebt underflows when liquidating an insolvent position, reverting liquidation and leaving bad debt.

- Payout: Contest reward
- Severity: medium
- Program: Alchemix
- Credited: frndz0ne
- Disclosed: 2025-07-15
- Write-up quality: 6/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_alchemix_may2025.pdf#3.2.22
- Library page: https://bugbountylibrary.com/r/cantina%3Aalchemix_may2025%3A3.2.22
- Tags: domain:web3 impact:dos kind:contest platform:cantina sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:dos vuln:liquidation

**Target:** AlchemistV3 lending contract _subDebt / liquidate
**Root cause:** _subDebt computes toFree = convertDebtTokensToYield(amount)*minimumCollateralization/FIXED_POINT_SCALAR and only caps it against _totalLocked, not account.rawLocked; for insolvent positions toFree exceeds rawLocked, so account.rawLocked -= toFree underflows and panics.
**Steps:**
1. Deploy AlchemistV3 with TestYieldToken whose price() is settable.
2. Deposit 10e18 yield tokens for externalUser, mint max AL tokens (tokenId 12).
3. Set fakeYieldToken price to 5e17 so position is insolvent.
4. Call `alchemist.liquidate(12)` -> panic 0x11 arithmetic underflow.
**How found:** Code review of _subDebt accounting: noticed toFree is clamped to _totalLocked but not to the per-account rawLocked, implying underflow when a single position's freed collateral exceeds its locked collateral.
**Insight:** When auditing debt-repayment math, check that per-account collateral reductions are clamped to the account's own balance, not just a global aggregate; insolvent/underwater positions are where these diverge.
