58547 sc high mismatched accounting and transfer for capped fees

Submitted on Nov 3rd 2025 at 07:23:58 UTC by @Petrus for Audit Comp | Alchemix V3arrow-up-right

  • Report ID: #58547

  • 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

Brief/Intro

The _doLiquidation () in AlchemistV3 subtracts the full amountLiquidated from the account's collateralBalance before transferring the net amount to the transmuter and conditionally paying the feeInYield to the liquidator based on the remaining balance, typically failing the check and leaving fees unpaid or succeeding without further deduction to overstate the account's balance.

Vulnerability Details

Snippet from the affected _doLiquidation:

// update user balance and debt 

account.collateralBalance = account.collateralBalance > amountLiquidated ? account.collateralBalance - amountLiquidated : 0; 

_subDebt(accountId, debtToBurn); 

  

// send liquidation amount - fee to transmuter 

TokenUtils.safeTransfer(myt, transmuter, amountLiquidated - feeInYield); 

  

// send base fee to liquidator if available 

if (feeInYield > 0 && account.collateralBalance >= feeInYield) {  // Post-sub check 

    TokenUtils.safeTransfer(myt, msg.sender, feeInYield);  // No further sub! 

} 

The function subtracts the full amountLiquidated from the account's collateralBalance before transferring amountLiquidated - feeInYield to the transmuter and checking the post-subtraction collateralBalance >= feeInYield to conditionally transfer the feeInYield to the liquidator without further subtracting it from the account balance, often preventing the fee transfer or leaving the balance overstated if transferred.

Recommendation

To fix the incorrect fee payment logic in _doLiquidation by removing the flawed post-subtraction check and always transferring the feeInYield to the liquidator (as it's intended from the liquidated collateral), while ensuring the total deduction from account.collateralBalance matches the outflows to transmuter and liquidator to maintain accurate accounting.

OR precisely, transfer amountLiquidated - feeInYield to the transmuter and feeInYield to the liquidator.

Impact Details

Liquidators are frequently underpaid or unpaid, disincentivizing liquidations, while successful transfers cause accounting mismatches that enable over-withdrawals

References

https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/AlchemistV3.sol#L852

Proof of Concept

Proof of Concept

Put the test in AlchemistV3.t.sol

Run the test with: forge test --match-test testLiquidationUnpaidFeeAndUnderstatedUserCollateral -vvvv

Was this helpful?