57883 sc high mytsharesdeposited updates in liquidation functions leads to critical tvl inflation
Submitted on Oct 29th 2025 at 11:19:37 UTC by @Diavol0 for Audit Comp | Alchemix V3
Report ID: #57883
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
Summary
Multiple liquidation-related functions in AlchemistV3 (_forceRepay, _liquidate, and _doLiquidation) fail to update the global _mytSharesDeposited variable after transferring MYT tokens out of the contract. This creates a permanent accounting inflation where _mytSharesDeposited exceeds the actual MYT token balance held by the protocol. This inflation corrupts the Total Value Locked (TVL) calculation used in critical solvency checks, potentially allowing the protocol to bypass emergency liquidation protections during market stress events.
Root Cause
The protocol maintains _mytSharesDeposited as a tracking variable for the total MYT (yield token shares) held by the Alchemist contract. This value is used in _getTotalUnderlyingValue() to calculate the protocol's TVL, which feeds into global collateralization checks.
The invariant that must be maintained:
_mytSharesDeposited == actual MYT token balance held by AlchemistCorrect implementations (withdraw, repay, burn, redeem):
Buggy implementations (liquidation functions):
_forceRepay Line 774 (protocol fee transfer):
_forceRepay Line 779 (transmuter transfer):
_liquidate Line 826 (liquidator fee, earmark path):
_liquidate Line 840 (liquidator fee, unearmark path):
_doLiquidation Line 875 (transmuter transfer):
_doLiquidation Line 879 (liquidator fee):
Impact Analysis
Immediate Impact per Liquidation:
MYT tokens transferred out but
_mytSharesDepositednot decreasedProtocol's actual MYT balance <
_mytSharesDeposited_getTotalUnderlyingValue()returns inflated TVL
Test Results Demonstrate:
Single liquidation: 1.14e18 MYT inflation
TVL inflation: 109e18 underlying tokens (40.6% inflation!)
Global collateralization artificially boosted by 151%
Actual collateralization: 373%
Reported collateralization: 524%
Critical Security Implication:
Line 1258 in calculateLiquidation() contains an emergency protection mechanism:
This check uses _getTotalUnderlyingValue() which depends on the inflated _mytSharesDeposited:
Result: When protocol is actually under-collateralized, the inflated _mytSharesDeposited makes it appear safe, bypassing emergency protections.
Cumulative Effect:
Every liquidation adds more inflation
No self-healing mechanism exists
Worsens progressively with protocol usage
Cannot be corrected without upgrade
Affected Components
Contract:
AlchemistV3.solFunctions:
_forceRepay()(Lines 738-782)_liquidate()(Lines 793-851)_doLiquidation()(Lines 853-884)
Variable:
_mytSharesDeposited(global state)Call Chain:
liquidate() → _liquidate() → [_forceRepay(), _doLiquidation()]Affected Calculation:
_getTotalUnderlyingValue()→calculateLiquidation()Line 862
Link to Proof of Concept
https://gist.github.com/6newbie/4b21d92c84a7f1bdcbd5f673a8c872eb
Proof of Concept
Step-by-Step Reproduction
Prerequisites:
AlchemistV3 contract deployed and initialized
User positions with debt exist
Transmuter operational for earmarking
Steps:
Setup Initial State
Trigger Liquidation
Observe Bug - Token Accounting
Observe Bug - TVL Inflation
Observe Bug - Collateralization Inflation
Automated Test Verification
A comprehensive test case is provided as a standalone file for easy integration.
Test File Location:
testBug_Complete_Liquidation_Path_MytShares_Inflation.sol(standalone test function in my gist)
Run test:
Expected output:
The test demonstrates:
✅ MYT tokens transferred out without
_mytSharesDepositedupdate✅ TVL inflation of 40.6% from a single liquidation
✅ Global collateralization artificially boosted by 151%
✅ Protocol invariant broken:
_mytSharesDeposited ≠ actual MYT balance
Comparison: Complete Call Paths
Scenario: Liquidation with 60% earmarked debt
Was this helpful?