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 V3arrow-up-right

  • 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 Alchemist

Correct implementations (withdraw, repay, burn, redeem):

Buggy implementations (liquidation functions):

  1. _forceRepay Line 774 (protocol fee transfer):

  1. _forceRepay Line 779 (transmuter transfer):

  1. _liquidate Line 826 (liquidator fee, earmark path):

  1. _liquidate Line 840 (liquidator fee, unearmark path):

  1. _doLiquidation Line 875 (transmuter transfer):

  1. _doLiquidation Line 879 (liquidator fee):

Impact Analysis

Immediate Impact per Liquidation:

  • MYT tokens transferred out but _mytSharesDeposited not decreased

  • Protocol'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.sol

  • Functions:

    • _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

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:

  1. Setup Initial State

  2. Trigger Liquidation

  3. Observe Bug - Token Accounting

  4. Observe Bug - TVL Inflation

  5. 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 _mytSharesDeposited update

  • 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?