57464 sc high incorrect accounting in stargate strategy causes protocol insolvency and user liquidations

Submitted on Oct 26th 2025 at 13:16:49 UTC by @terrah for Audit Comp | Alchemix V3arrow-up-right

  • Report ID: #57464

  • Report Type: Smart Contract

  • Report severity: High

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

  • Impacts:

    • Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield

Description

Bug Description

The StargateEthPoolStrategy contract uses pool.redeemable() to report its assets instead of the actual LP token balance. In Stargate V2, redeemable() returns instantly available credits which can be significantly lower than the actual LP token value during normal AIPM operations.

Brief/Intro

StargateEthPoolStrategy.realAssets() reports pool.redeemable(address(this)) instead of lp.balanceOf(address(this)). During regular Stargate V2 AIPM credit rebalancing operations, redeemable() can drop to 20% of actual LP value while the strategy still holds 100% of LP tokens. This false underreporting flows through the Morpho vault conversion rate into AlchemistV3's collateral calculations, causing healthy user positions to appear undercollateralized and get liquidated with permanent loss of funds.

It's worth noting that this is not a "black-swan" type of event on Stargate part, but normal protocol operations.

Details

In StargateEthPoolStrategy.sol line 98-101:

The Stargate V2 documentation states: "The AIPM dynamically adjusts the distribution of credits across pathways in response to observed changes in volume and user behavior, optimizing liquidity, slippage, and fee structures for the protocol." (Source: Stargate documentation)

I'm including Stargate code as redeemable function is not well documented in the docs. From StargatePool.sol lines 153-165:

This means pool.redeemable() can return much less than the actual LP token value held. The strategy may hold 100 ETH worth of LP tokens, but pool.redeemable() returns only 20 ETH during credit rebalancing.

The flow of the bug:

  1. Strategy holds 100 ETH worth of LP tokens (lp.balanceOf = 100 ETH)

  2. AIPM moves credits to another pathway (normal operations)

  3. pool.redeemable() now returns 20 ETH (only instant liquidity available)

  4. realAssets() returns 20 ETH instead of 100 ETH

  5. MYT vault (Morpho V2) aggregates: vault.totalAssets() uses strategy.realAssets()

  6. AlchemistV3 converts: convertYieldTokensToUnderlying() uses vault conversion rate

  7. User with 100 MYT shares and 80 ETH debt appears to have only 20 ETH collateral

  8. Collateralization ratio = 20/80 = 0.25 (25%) instead of 100/80 = 1.25 (125%)

  9. AlchemistV3._liquidate() executes because ratio is below collateralizationLowerBound

  10. User permanently loses collateral to transmuter and pays liquidation fees

From AlchemistV3.sol:

The Stargate documentation confirms this is expected behavior: "At its most malicious, the AIPM could cause liveness issues for certain pathways if it, for example, withdrew 100% of credits on a pathway meaning no volume can move between those two pools. This mechanism can also be protective in case of chain exploit, or asset depeg." This means credit movements are not rare events but active protocol operations.

Impact

This causes protocol insolvency. The protocol reports holding less collateral than it actually has, leading to false liquidations of healthy positions. The accounting discrepancy is not theoretical - during AIPM credit rebalancing (which happens during normal operations to optimize liquidity), pool.redeemable() can report 20-30% of actual LP value while the LP tokens remain fully owned by the strategy.

Example scenario with real numbers:

Strategy holds 1000 ETH in LP tokens. AIPM moves credits to high-demand pathway. pool.redeemable() drops to 200 ETH. All users with Stargate collateral now show 80% less collateral value. Any user with debt ratio above 125% (using real 1000 ETH value) now appears to have ratio below 25% (using false 200 ETH value) and gets liquidated.

A user with 100 ETH collateral and 80 ETH debt (healthy 125% ratio) loses their entire position plus liquidation fees because the system thinks they only have 20 ETH collateral (false 25% ratio). When credits return hours or days later, the user's collateral is already gone - sent to transmuter and paid as liquidation fees.

This affects all users with Stargate strategy collateral during credit rebalancing periods. The loss is permanent and irreversible. Users lose principal funds, not unclaimed yield.

Risk Breakdown

Difficulty: None (happens automatically during normal protocol operations) Likelihood: High (AIPM rebalances credits regularly based on bridge volume) Impact: Critical (permanent loss of user funds via false liquidations)

The AIPM actively manages credits across pathways. The Stargate documentation states this is core functionality, not an edge case. Credit rebalancing happens whenever there are volume changes across chains, which is daily or multiple times per day in production.

Recommendation

Change realAssets() to return the actual LP token balance instead of instant redeemable amount:

The strategy's real assets are the LP tokens it owns, not the instantly redeemable liquidity. Redemption timing is a liquidity constraint that should not affect accounting. The LP tokens retain their full value even when credits are temporarily moved to other pathways.

This change accurately represents the strategy's holdings for collateral calculations while redemption mechanics remain unchanged in the allocate/deallocate functions which already handle the redemption process correctly.

References

Stargate V2 Documentation on AIPM: https://stargateprotocol.gitbook.io/stargate/v2-user-docs/whats-new-in-stargate-v2/credit-allocation-system

Stargate V2 FAQ on AIPM risks: https://stargateprotocol.gitbook.io/stargate/v/v2-user-docs/faq

StargateEthPoolStrategy.sol (lines 98-101) AlchemistV3.sol _liquidate function MYT vault (Morpho V2) totalAssets calculation

Proof of Concept

Proof of Concept

Was this helpful?