58288 sc critical incorrect fee payment logic leads to underpayment

Submitted on Nov 1st 2025 at 00:35:05 UTC by @Petrus for Audit Comp | Alchemix V3arrow-up-right

  • Report ID: #58288

  • Report Type: Smart Contract

  • Report severity: Critical

  • 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 _resolveRepaymentFee () in AlchemistV3 computes the full repayment fee but only deducts the capped amount from the account's collateral balance while returning, emitting, and enabling transfer of the uncapped full fee, causing per-account accounting overstatements and potential over-withdrawals.

Vulnerability Details

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; // Caps subtraction 

 

    emit RepaymentFee(accountId, repaidAmountInYield, msg.sender, fee); // Full fee 

    return fee; // Full fee transferred in caller 

} 

The function calculates the full fee based on repaidAmountInYield but deducts only the minimum of fee and account.collateralBalance from the per-account collateralBalance, then emits and returns the uncapped fee for transfer in the caller, allowing the full amount to be transferred from the contract's total balance without fully deducting from the account's tracked balance.

Soln

To fix the mismatched accounting issue in _resolveRepaymentFee by ensuring the returned, emitted, and transferred fee matches the actual amount deducted from the account's collateral balance (capping it to available funds), compute and use an actualFee variable consistently to prevent over-transfers and per-account balance overstatements.

Impact Details

Per-account collateral accounting becomes overstated relative to actual outflows, enabling over-withdrawals from the liquidated account and diverging summed account balances from the global token holdings.

References

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

Proof of Concept

Proof of Concept/

Run the test in AlchemistV3.t.sol

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

Was this helpful?