56560 sc high liquidation base fee transfer is gated by a condition that s usually false

Submitted on Oct 17th 2025 at 16:25:30 UTC by @spongebob for Audit Comp | Alchemix V3arrow-up-right

  • Report ID: #56560

  • Report Type: Smart Contract

  • Report severity: High

  • Target: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistV3.sol

  • Impacts:

    • Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield

Description

In calculateLiquidation the gross seize amount already bundles the base fee (grossCollateralToSeize = debtToBurn + fee), so amountLiquidated later passed around includes the fee portion feeInYield

_doLiquidation immediately deducts that full amountLiquidated from account.collateralBalance, leaving only any residual collateral, then forwards just amountLiquidated - feeInYield to the transmuter

https://github.com/alchemix-finance/v3-poc/blob/b2e2aba046c36ff5e1db6f40f399e93cd2bdaad0/src/AlchemistV3.sol#L857-L865

The subsequent guard if (feeInYield > 0 && account.collateralBalance >= feeInYield) now checks the post-deduction balance. This condition is equivalent to requiring the account to hold at least grossCollateralToSeize + fee beforehand and will be false whenever the liquidation seizes everything available.

https://github.com/alchemix-finance/v3-poc/blob/b2e2aba046c36ff5e1db6f40f399e93cd2bdaad0/src/AlchemistV3.sol#L867-L869

When the guard fails the liquidator never receives the base fee even though it was already removed from the victim account, so the seized fee remains with the contract.

Impact

I consider this a critical issue that results in direct theft of user funds because when _doLiquidation reduces account.collateralBalance by amountLiquidated, the borrower permanently loses the entire seized amount. Only amountLiquidated - feeInYield is forwarded to the transmuter and the base-fee portion is supposed to go to the liquidator.

Because the subsequent transfer is gated on the already-reduced account.collateralBalance, the fee is often never paid out. The tokens remain trapped in the contract, so the borrower’s collateral is confiscated without being credited to any counterparty as intended.

Recommendation

Transfer the fee to the liquidator before debiting the account and then send the remainder to the transmuter, or keep the current order but drop the balance check so the fee distribution always executes.

Proof of Concept

Add this test to AlchemixV3.t.sol and run forge test --mt testPOC_Liquidator_Fee_Trapped_Due_To_PostDeduction_Guard -vvvv

Was this helpful?