56363 sc high mytsharesdeposited not correctly updated in all cases leading to incorrect protocol collateralization and reduced liquidation incentives

Submitted on Oct 15th 2025 at 04:19:12 UTC by @silencedogood for Audit Comp | Alchemix V3arrow-up-right

  • Report ID: #56363

  • Report Type: Smart Contract

  • Report severity: High

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

  • Impacts:

    • Contract fails to deliver promised returns, but doesn't lose value

Description

Brief/Intro

_mytSharesDeposited is not updated in all cases correctly in AlchemistV3, when MYT funds are transferred out. This leads to an overestimation of the current protocol collateralization, as well as reduced liquidation fees.

Vulnerability Details

_mytSharesDeposited is intended to differentiate between tokens deposited into a CDP and balance of the contract. However during functions _forceRepay(), _liquidate() and _doLiquidation(), MYT tokens may be transferred out of the contract but not accounted for by reducing _mytSharesDeposited accordingly. This leads to _mytSharesDeposited being artificially high.

An artificially high _mytSharesDeposited value leads to an overestimation of the protocol's current collateralization and an artificially high value for getTotalUnderlyingValue(). In partial liquidations and in cases where alchemistCurrentCollateralization is slightly higher than alchemistMinimumCollateralizatio, this overestimation can lead to liquidations incorrectly skipping setting outsourcedFee to non-zero. Thus leading to a reduce fee and incentive for partial liquidations:

    function calculateLiquidation(
        uint256 collateral,
        uint256 debt,
        uint256 targetCollateralization,
        uint256 alchemistCurrentCollateralization,
        uint256 alchemistMinimumCollateralization,
        uint256 feeBps
    ) public pure returns (uint256 grossCollateralToSeize, uint256 debtToBurn, uint256 fee, uint256 outsourcedFee) {
        if (debt >= collateral) {
            outsourcedFee = (debt * feeBps) / BPS;
            // fully liquidate debt if debt is greater than collateral
            return (collateral, debt, 0, outsourcedFee);
        }


        if (alchemistCurrentCollateralization < alchemistMinimumCollateralization) {
            outsourcedFee = (debt * feeBps) / BPS;
            // fully liquidate debt in high ltv global environment
            return (debt, debt, 0, outsourcedFee);
        }


        // fee is taken from surplus = collateral - debt
        uint256 surplus = collateral > debt ? collateral - debt : 0;


        fee = (surplus * feeBps) / BPS;


        // collateral remaining for margin‐restore calc
        uint256 adjCollat = collateral - fee;


        // compute m*d  (both plain units)
        uint256 md = (targetCollateralization * debt) / FIXED_POINT_SCALAR;


        // if md <= adjCollat, nothing to liquidate
        if (md <= adjCollat) {
            return (0, 0, fee, 0);
        }


        // numerator = md - adjCollat
        uint256 num = md - adjCollat;


        // denom = m - 1  =>  (targetCollateralization - FIXED_POINT_SCALAR)/FIXED_POINT_SCALAR
        uint256 denom = targetCollateralization - FIXED_POINT_SCALAR;


        // debtToBurn = (num * FIXED_POINT_SCALAR) / denom
        debtToBurn = (num * FIXED_POINT_SCALAR) / denom;


        // gross collateral seize = net + fee
        grossCollateralToSeize = debtToBurn + fee;
    }

https://github.com/alchemix-finance/v3-poc/blob/b2e2aba046c36ff5e1db6f40f399e93cd2bdaad0/src/AlchemistV3.sol#L1244-L1291

Impact Details

Overestimating protocol MYT shares leads to an overestimation of protocol health, which is systemically dangerous. Furthermore, during partial liquidations, this overestimation can lead to the liquidator's outsourcedFee being skipped entirely, leading to loss of incentive for liquidators to act during high global LTV situations.

In my following PoC, two users deposit the same amount of tokens, but user 2 is fully liquidated, leading to:

  1. No outsourcedFee for partial liquidation of user 1, when there should have been

  2. Reported protocol current collateralization appearing 2x bigger than it should, because the full liquidation transferred collateral tokens out but didn't reduce tracked balance. Thus protocol collateral massively overstated

References

https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistV3.sol?utm_source=immunefi#L1244-L1291

Proof of Concept

Proof of Concept

Paste the following unit test into src/test/AlchemistV3.t.sol and run:

Was this helpful?