56855 sc medium liquidations fail with arithmetic underflow when forced repayment exhausts collateral
Submitted on Oct 21st 2025 at 09:21:44 UTC by @InAllHonesty for Audit Comp | Alchemix V3
Report ID: #56855
Report Type: Smart Contract
Report severity: Medium
Target: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistV3.sol
Impacts:
Permanent freezing of funds
Description
Brief/Intro
The _forceRepay() function sends the account's entire collateral balance to the transmuter during liquidation, but the calling function _liquidate() then attempts to pay a repayment fee to the liquidator from that same exhausted balance. This causes an arithmetic underflow in the ERC20 transfer, reverting the entire liquidation transaction. Positions where the collateral value approximately equals the earmarked debt cannot be liquidated, leaving bad debt stuck in the protocol.
Vulnerability Details
Conditions for trigger:
Account has earmarked debt
Collateral value approximately equals the earmarked debt
Liquidation attempts forced repayment
No excess collateral remains for fees
When liquidating an undercollateralized position with earmarked debt, the protocol calls _forceRepay() to repay the debt using the account's collateral. The function calculates a protocol fee but fails to reserve it:
After _forceRepay() returns, if the debt was fully repaid, _liquidate() calls _resolveRepaymentFee() to compensate the liquidator:
The _resolveRepaymentFee() function calculates the fee and attempts to transfer it:
The issue is that the Alchemist contract's actual token balance is zero after sending everything to the transmuter. When TokenUtils.safeTransfer() tries to send the repayment fee to the liquidator, the underlying ERC20 transfer underflows and reverts.
Impact Details
Positions where collateralBalance ≈ earmarkedDebt (in yield token terms) cannot be liquidated. The transaction reverts with an arithmetic underflow before the liquidation completes. This leaves bad debt positions stuck in the protocol.
Even in cases where enough collateral exists to avoid the underflow, the protocol still loses revenue because the fee validation check if (account.collateralBalance > protocolFeeTotal) fails after the balance is set to zero. The event emits a protocolFeeTotal value that was never actually collected.
References
_forceRepay - https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/AlchemistV3.sol#L738-L782 _liquidate - https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/AlchemistV3.sol#L791-L843 _resolveRepaymentFee - https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/AlchemistV3.sol#L900-L907
Proof of Concept
Proof of Concept
Paste the following at the end of AlchemistV3.t.sol:
Run using forge test --mt testForceRepayUnderflowAndFeeLoss -vvvv
Was this helpful?