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 V3
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:
The majority of the liquidated amount is sent to the Transmuter.
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.
Incorrect Accounting: The Alchemist's reported getTotalUnderlyingValue is permanently inflated, misleading users and external integrators about the protocol's solvency.
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.
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
mytbalance and any underlying assets redeemed from the Alchemist), leaving later users with nothing.Magnitude of Loss: The loss is not capped. It is proportional to the amount of
mytliquidated 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
Alchemist Liquidate Function: The function where
myttokens are transferred out without updating_mytSharesDeposited.
https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/AlchemistV3.sol#L874-L880
Alchemist
_getTotalUnderlyingValueFunction: The function that uses the inflated_mytSharesDepositedto report TVL.
https://github.com/alchemix-finance/v3-poc/blob/a192ab313c81ba3ab621d9ca1ee000110fbdd1e9/src/AlchemistV3.sol#L1239
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?