57511 sc medium protocol could atleast be taking a part of the protocol fee

Submitted on Oct 26th 2025 at 20:43:31 UTC by @PotEater for Audit Comp | Alchemix V3arrow-up-right

  • Report ID: #57511

  • Report Type: Smart Contract

  • Report severity: Medium

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

  • Impacts:

Description

Brief/Intro

The function _forceRepay is designed in a way where if the collateralBalance is smaller than the protocolFeeTotal, the account doesn't pay for the fee. This design makes the protocol lose on potential fees. The code could be changed in a way that if the account doesn't have enough, the code will attempt to decrease the fee to the account collateral, so at least a part of it is paid, making the most out of it.

Vulnerability Details

If the account doesn't have enough to pay for the fee, the fee is not deducted from account's collateral.

This behavior could be changed so the fee is then decreased at least to the colalteral balance so at least a part of the fee is taken.

Code snippet:

        if (account.collateralBalance > protocolFeeTotal) {
            account.collateralBalance -= protocolFeeTotal;
            // Transfer the protocol fee to the protocol fee receiver
            TokenUtils.safeTransfer(myt, protocolFeeReceiver, protocolFeeTotal);
        }

This code could be changed into clamping the fee if its larger so at least minimum is taken. This could be the change:

Impact Details

The impact is that the protocol is losing on a potential profits that could be made if the account still has some collateral.

The protocol could take at least a part of the fee, if not the full amount.

References

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

Proof of Concept

Proof of Concept

Add this function in the AlchemistV3.t.sol test file:

This PoC demonstrates how the function doesn't deduct any fee when the account doesn't have enough to cover the fee.

Meaning it doesn't take at least a part of it.

To exactly demonstrate the issue I slightly edited the implementation:

Result:

Result shows that no fee was taken, not even a part of it.

Was this helpful?