# Rounding errors in AlchemistV3::_forceRepay() lead to account state corruption and under- flow in _sync()

Double yield/debt token conversion in AlchemistV3 _forceRepay leaves 1 wei earmarked debt after liquidation clears debt, causing underflow revert in _sync and bricking account operations.

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

**Target:** AlchemistV3 smart contract (_liquidate/_forceRepay/_sync)
**Root cause:** _liquidate converts earmarked debt to yield then _forceRepay converts back to debt, losing 1 wei; credit < earmarked leaves account.earmarked > 0 while liquidation later sets account.debt == 0.
**Steps:**
1. Deploy AlchemistV3 with a position (0xbeef) minting debt near minimum collateralization
2. Create a transmuter redemption to start earmarking debt
3. Inflate yield token supply 12% to shift price and make position liquidatable
4. Call `alchemist.liquidate(tokenIdFor0xBeef)` — _forceRepay leaves 1 wei earmarked, then debt fully cleared
5. Call `alchemist.poke(tokenIdFor0xBeef)` — _sync computes `account.debt - account.earmarked` = 0 - 1 wei and reverts with arithmetic underflow (0x11)
**How found:** Code review of _liquidate/_forceRepay conversion path: noticed earmarked is converted debt→yield→debt, hypothesized rounding loss, then traced that _liquidate can zero debt while earmarked stays positive, and confirmed _sync's `debt - earmarked` underflows.
**Exploitation:** Any liquidator triggering liquidation of an earmarked position leaves residual earmarked debt with zero debt; subsequent _sync-dependent user operations (poke, deposit, withdraw, repay) revert, permanently bricking the position and locking user collateral.
**Insight:** When a value is round-tripped through two unit conversions, check whether the residual dust can violate invariants like `debt >= earmarked`; liquidation paths that zero one field while leaving the other are prime spots for underflow DoS.
