57101 sc critical same block earmark early exit leaves stale transmuter balance causing under earmarking

Submitted on Oct 23rd 2025 at 13:31:03 UTC by @Icon0x for Audit Comp | Alchemix V3arrow-up-right

  • Report ID: #57101

  • Report Type: Smart Contract

  • Report severity: Critical

  • Target: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/AlchemistV3.sol

  • Impacts:

    • Protocol insolvency

    • Smart contract unable to operate due to lack of token funds

    • Stale lastTransmuterTokenBalance from same-block _earmark() calls causes inflated cover calculation in the next earmark, leading to under-earmarking of debt and incorrect borrowing capacity.

Description

Brief/Intro

Same-block earmark() early-exit leaves a stale transmuter balance, inflating “cover” next block and under‑earmarking debt, letting borrowers overborrow, delaying redemptions, and raising bad‑debt/insolvency risk.

Vulnerability Details

In AlchemistV3.sol::_earmark(), an early-return guard if (block.number <= lastEarmarkBlock) return; exits on subsequent calls within the same block. When the transmuter’s MYT balance changes between two same-block calls (e.g., via repay, direct MYT transfer, or equivalent inflow), the second _earmark() doesn’t update lastTransmuterTokenBalance. On the next block, _earmark() computes “cover” as transmuterCurrentBalance - lastTransmuterTokenBalance using this stale value, which inflates the perceived cover and reduces the amount of debt earmarked below what it should be. The behavior can be triggered by two _earmark()-invoking actions in the same block (e.g., poke() twice by different users, withdraw()+poke(), etc.), and it’s not fully prevented by the mint/repay same-block restriction.

Vulnerable in order of Operation:

Impact Details

The stale lastTransmuterTokenBalance causes the next _earmark() to over-count cover and under-earmark system debt, allowing borrowers to retain more unearmarked debt and therefore more borrowing headroom than intended, distorting redemption pressure and global accounting in favor of borrowers and against redeemers.

Proof of Concept

Proof of Concept

Add the below test suite to AlchemistV3.t.sol file

Then run: `forge test --match-test test_EarmarkVulnerability -vvvv

Was this helpful?