56975 sc high liquidation fee trapping in alchemistv3
Submitted on Oct 22nd 2025 at 11:01:12 UTC by @Paludo0x for Audit Comp | Alchemix V3
Report ID: #56975
Report Type: Smart Contract
Report severity: High
Target: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistV3.sol
Impacts:
Permanent freezing of unclaimed royalties
Description
Brief/Intro
In AlchemistV3::liquidate() the liquidator’s feeInYield is carved out of the seized collateral amountLiquidated but its payout is conditionally gated by account.collateralBalance >= feeInYield after the seizure.
If the gate fails, the fee is neither sent to the liquidator nor forwarded to the Transmuter, leaving these tokens locked in the AlchemistV3 contract.
With no recovery function, this results in permanent freezing of unclaimed royalties (liquidator fees).
Vulnerability Details
This is the vulnerability flow in AlchemixV3::_doLiquidation():
Seize the borrower's collateral
Send NET to the Transmuter: (gross - fee)
Pay the liquidator FEE ONLY IF enough residual collateral remains
These are the keypoints that make implementation wrong:
Step (2) reserves
feeInYieldby sending only(amountLiquidated - feeInYield)to the Transmuter.Step (3) may skip sending the fee if the post-seizure accounting residual is
< feeInYield.There is no fallback path to re-route the fee anywhere. The reserved amount remains in the AlchemistV3 contract balance, permanently frozen.
The branch is real, but its reachability depends on parameters. In debt units, fee trapping requires:
With m = minimumCollateralization and fee fraction phi = liquidatorFee / 10_000, this reduces to the threshold:
For the defaults in this repo (m ≈ 1.111…), the threshold is ≈ 90.91% (≈ 9091 bps). With the default liquidatorFee = 300 bps (3%), the inequality does not hold, so the problematic branch is not reachable under normal settings. It becomes reachable only with extreme fee configurations.
Impact Details
The impact is High: Permanent freezing of unclaimed royalties.
Permanent freezing: The unpaid liquidator fee is never sent and cannot be reclaimed on-chain (no skim/sweep/recover path), leaving the fee permanently frozen in AlchemistV3.
Incentive erosion: Liquidators may be underpaid exactly when positions are near the threshold, reducing liquidation participation and increasing systemic risk.
(Recommended Fix)
When the gate fails, send all seized to the Transmuter.
Implement a governance function
sweepTrappedFees
Proof of Concept
Proof of Concept
What PoC tests show:
test_FeeTrapping_Condition_Unreachable_With_Default_Fee: UsescalculateLiquidationto sample undercollateralized states and shows that, with default fee,collateral ≥ debtToBurn + 2*feealways holds; the branch cannot trigger in practice.test_FeeTrapping_Condition_Becomes_Possible_When_Fee_Above_Threshold: Temporarily raises the fee above the threshold and demonstratescollateral < debtToBurn + 2*feecan hold, proving the branch exists but is extreme-only.
Was this helpful?