58036 sc critical incorrect fee deduction may drain collateral pool when account balance is insufficient

Submitted on Oct 30th 2025 at 06:59:09 UTC by @joicygiore for Audit Comp | Alchemix V3arrow-up-right

  • Report ID: #58036

  • Report Type: Smart Contract

  • Report severity: Critical

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

  • Impacts:

    • Protocol insolvency

Description

Brief/Intro

During liquidation or repayment, the contract calls _resolveRepaymentFee() to deduct a fee from the user’s collateral balance and transfer it to the liquidator. However, when the account’s collateral balance is insufficient, the function still issues the full fee amount, effectively paying the remaining fee using the global collateral pool. This behavior can unintentionally deplete collateral belonging to other users.

Vulnerability Details

As shown below, the repayment logic deducts the smaller of fee or account.collateralBalance from the account, but always returns the full fee amount. The caller (liquidator) subsequently receives this full fee, regardless of whether the account had enough collateral to cover it.

    // AlchemistV3::_resolveRepaymentFee()
    function _resolveRepaymentFee(uint256 accountId, uint256 repaidAmountInYield) internal returns (uint256 fee) {
        Account storage account = _accounts[accountId];
        // calculate repayment fee and deduct from account
@>        fee = repaidAmountInYield * repaymentFee / BPS;
@>        account.collateralBalance -= fee > account.collateralBalance ? account.collateralBalance : fee;
        emit RepaymentFee(accountId, repaidAmountInYield, msg.sender, fee);
        return fee;
    }

AlchemistV3::_resolveRepaymentFee() function is invoked from _liquidate() as follows:

Even if the account has insufficient collateral, the liquidator still receives a full payout, effectively draining funds from the overall contract balance, which includes collateral belonging to other users.

Impact Details

If an insolvent position is liquidated, the function compensates the liquidator with the full fee amount, drawing the deficit from the contract’s total collateral balance. This can lead to:

  • Depletion of other users’ deposits.

  • Inability for unaffected users to withdraw their full collateral. Thus, this issue can result in loss of user funds and compromise the protocol’s solvency.

References

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

Proof of Concept

Proof of Concept

Add the following test to src/test/AlchemistV3.t.sol and run it:

Was this helpful?