57963 sc high incorrect mytsharesdeposited accounting in liquidate allows theft of user funds via corrupted bad debt ratio

Submitted on Oct 29th 2025 at 16:47:31 UTC by @Outliers for Audit Comp | Alchemix V3arrow-up-right

  • Report ID: #57963

  • Report Type: Smart Contract

  • Report severity: High

  • 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

During the liquidation process, the Alchemist contract transfers yield tokens (myt) to the Transmuter and a fee to the liquidator without updating its internal accounting variable _mytSharesDeposited. This omission artificially inflates the system's total collateral value, which in turn corrupts the bad debt calculation in the Transmuter. As a result, during a system insolvency, users would be able to claim more underlying assets than they are entitled to, systematically draining the protocol and pushing the realised losses onto the last users to withdraw.

Vulnerability Details

The core of the vulnerability is a missing state update in the liquidate function of the Alchemist contract. The _mytSharesDeposited variable is a critical internal accounting metric that tracks the total amount of yield tokens (myt) the Alchemist considers as deposited collateral. This variable is correctly updated in functions like deposit, withdraw, and repay, but is erroneously omitted during liquidations.

When a liquidation occurs, myt tokens are transferred out of the Alchemist contract:

  1. The majority of the liquidated amount is sent to the Transmuter.

  2. A fee is sent to the liquidator.

However, the _mytSharesDeposited is not reduced, creating a discrepancy between the contract's actual token balance and its internal ledger.

Code Snippet from Alchemist (liquidate function):

This inflated _mytSharesDeposited value directly impacts the calculation of _getTotalUnderlyingValue(), which is used to determine the overall health of the system.

Code Snippet from Alchemist (_getTotalUnderlyingValue function):

The miscalculated totalUnderlyingValue is then passed to the Transmuter's bad debt ratio calculation. This ratio determines how much users can claim when the system is under-collateralized. An inflated totalUnderlyingValue makes the system appear healthier than it is, leading to an incorrect (lower) badDebtRatio.

Code Snippet from Transmuter (simplified logic):

Because the badDebtRatio is artificially low due to the inflated denominator, the condition badDebtRatio > 1e18 may never be met, or the scaling factor applied may be insufficient. Consequently, users can claim a disproportionately large amount of underlying assets relative to the protocol's actual collateral, effectively draining it.

Impact Details

The impact of this vulnerability is theft of yield/protocol fees and direct theft of user funds, leading to a loss of user funds without a reasonable limit.

  1. Incorrect Accounting: The Alchemist's reported getTotalUnderlyingValue is permanently inflated, misleading users and external integrators about the protocol's solvency.

  2. Corrupted Insolvency Process: In a worst-case scenario where the system becomes under-collateralised (bad debt exists), the Transmuter will miscalculate the user's share of the remaining collateral.

  3. Systematic Drainage: Users transmuting their synthetic tokens will receive more underlying assets than they are entitled to. This will systematically drain the Transmuter's reserves (both its myt balance and any underlying assets redeemed from the Alchemist), leaving later users with nothing.

  4. Magnitude of Loss: The loss is not capped. It is proportional to the amount of myt liquidated without proper accounting. In a mass liquidation event, the accounting error could become very large, leading to a near-total drain of the protocol's collateral and a complete breakdown of the transmutation mechanism.

References

  1. Alchemist Liquidate Function: The function where myt tokens are transferred out without updating _mytSharesDeposited.

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

  1. Alchemist _getTotalUnderlyingValue Function: The function that uses the inflated _mytSharesDeposited to report TVL.

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

  1. Transmuter Bad Debt Calculation: The logic that relies on the Alchemist's getTotalUnderlyingValue() to determine user payouts during insolvency.

https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/Transmuter.sol#L217-L226

Proof of Concept

Proof of Concept

Add this helper function to transmuter.sol

Result

Was this helpful?