# Unlocked amount will be different from original locked amount based on price movement and minimumCollateralization ratio change

AlchemistV3 recomputes freed collateral from current yield-token price and minCollateralization, so after full repayment users cannot withdraw their full deposit.

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

**Target:** AlchemistV3.sol _addDebt/_subDebt collateral lock accounting
**Root cause:** _addDebt locks convertDebtTokensToYield(amount)*minimumCollateralization and _subDebt frees the same formula recomputed at repayment time, so price or minCollateralization changes make freed != locked.
**Steps:**
1. Deposit 100 yield tokens, mint 50 debt tokens via `alchemist.mint(tokenId, debtAmount, alice)` recording rawLocked.
2. Advance a block and change yield token price (mock supply update) so convertDebtTokensToYield differs.
3. Fully repay via `alchemist.repay(debtAmount, tokenId)`; debt==0 but freeCollateral < original deposit.
4. Call `alchemist.withdraw(collateral, alice, tokenId)`; reverts IllegalArgument because freeCollateral < amount.
**How found:** Code reading of _addDebt/_subDebt revealed the lock and free amounts are both derived from live convertDebtTokensToYield and minimumCollateralization rather than a stored checkpoint, making them diverge over time.
**Exploitation:** No attacker profit path; any borrower who repays after yield-token price appreciation or a minCollateralization change is left with locked collateral they cannot withdraw, causing user fund loss.
**Insight:** When a protocol locks collateral at action time but frees it by recomputing the same formula later, check whether any input to that formula (price, ratio, exchange rate) is mutable between the two events; stored checkpoints are required.
