57632 sc high inflated tvl in mytsharesdeposited hides protocol insolvency
Submitted on Oct 27th 2025 at 18:55:15 UTC by @niffylord for Audit Comp | Alchemix V3
Report ID: #57632
Report Type: Smart Contract
Report severity: High
Target: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistV3.sol
Impacts:
Protocol insolvency
Description
Brief / Intro
Whenever _forceRepay or _doLiquidation sends MYT out of the Alchemist, _mytSharesDeposited is left unchanged. getTotalUnderlyingValue() therefore reports collateral that no longer exists, keeping the transmuter bad-debt ratio artificially low. Attackers (or normal users) can continue redeeming and minting against phantom collateral until the protocol runs out of backing, leading to protocol insolvency.
Vulnerability Details
_forceRepay(src/AlchemistV3.sol:750-789) and_doLiquidation(src/AlchemistV3.sol:867-889) transfer MYT to the transmuter/liquidator but never decrement_mytSharesDeposited.getTotalUnderlyingValue()(src/AlchemistV3.sol:1239-1241) converts_mytSharesDepositedto underlying to produce TVL. After the transfer, this value still includes the shares that were sent out.Transmuter.getBadDebtRatio()(src/Transmuter.sol:215-226) divides total synthetics by that TVL. With the denominator inflated, the ratio remains below 1 even when collateral has already left the system, so redemptions are not scaled and fresh debt can still be minted.Repeated forced repayments or liquidations drain actual MYT while accounting remains unchanged, eventually leaving outstanding alAssets without backing.
Impact Details
Impact: Protocol insolvency
TVL is overstated by the amount of MYT removed via
_forceRepayand_doLiquidation.Users continue to redeem at face value because the bad-debt ratio understates insolvency; transmuter releases MYT that no longer exists.
The discrepancy can grow to the entire protocol collateral, leaving alAssets unbacked and the protocol insolvent.
References
src/AlchemistV3.sollines 750-789, 867-889, 1239-1241src/Transmuter.sollines 215-226PoC:
src/test/poc/MytSharesDepositedPoC.t.sol
Proof of Concept
Ensure dependencies are installed (per project README) and Foundry is available.
Run the dedicated test:
Test flow (implemented in
src/test/poc/MytSharesDepositedPoC.t.sol):Create a borrower, deposit MYT, mint the maximum allowable alTokens.
Pump the mock strategy’s share price to mimic accrued yield.
Trigger liquidation from another user; MYT leaves the Alchemist via
_doLiquidation.Compare
getTotalUnderlyingValue()(uses_mytSharesDeposited) with the actual MYT balance still held by the Alchemist.
Logs show
Tracked underlying (post)unchanged whileActual underlying (post)drops to zero. The test asserts the discrepancy, proving_mytSharesDepositednever accounted for the transfer and the protocol now believes it holds collateral that is gone.
PoC Source
Was this helpful?