Malda Lending: Migration Failure Due To Token Mismatch

by Mireille Lambert 55 views

Hey guys! Let's dive into a critical issue discovered during the Sherlock audit for the Malda lending protocol. It's about a potential migration failure, and it's pretty serious. So, buckle up, and let's break it down in a way that's easy to grasp.

High-Severity Issue: Migration Failure Due to Token Mismatch

Summary

This issue can halt the entire migration process! Imagine trying to move your assets and hitting a brick wall. That's what this bug does. The problem lies in how minCollateral is calculated and used as minAmountOut during the migration. Basically, a mismatch between the expected units (mTokens) and the actual units (underlying assets) can cause the migration to fail. This happens due to a token mismatch when the exchange rate is off.

To expand, the core issue lies in a miscalculation of the minCollateral value, which is subsequently used as minAmountOut within the mintOrBorrowMigration function. Specifically, minCollateral is calculated in the underlying asset's units, while it should be expressed in mToken units. This discrepancy leads to a critical failure during the minting process, particularly when the exchange rate exceeds a certain threshold, around 1.111 (expressed as 1.111e18 in mantissa). Let's delve deeper into the root cause of this problem.

The calculation takes place in the Migrator.sol contract, where minCollateral is hardcoded to 90% of the collateralUnderlyingAmount. This value, which is in the underlying asset's units, is then passed as minAmountOut to the mintOrBorrowMigration function. The expectation here is that minAmountOut should represent the minimum amount of mTokens to be minted. However, because the value is provided in the underlying asset's units, it sets the stage for a potential mismatch. This mismatch becomes a problem when the mintTokens value, calculated within the __mint function, falls below the minAmountOut threshold. This situation occurs when the exchange rate between the underlying asset and its mToken counterpart is high enough.

Root Cause

The heart of the problem is in Migrator.sol, where minCollateral is stubbornly set to 90% of collateralUnderlyingAmount (in the underlying asset's units). But here's the kicker: this value is then passed as minAmountOut (which should be in mToken units) to mintOrBorrowMigration. This mix-up leads to a revert in the __mint function because the mintTokens >= minAmountOut check here fails. The failure occurs when the exchange rate goes beyond approximately 1.111 (mantissa 1.111e18).

                uint256 minCollateral = position.collateralUnderlyingAmount -
                    ((position.collateralUnderlyingAmount * 1e4) / 1e5);

                ImErc20Host(position.maldaMarket).mintOrBorrowMigration(
                    true,
                    position.collateralUnderlyingAmount,
                    msg.sender,
                    address(0),
                    minCollateral // <-- This is supposed to be in mToken but here underlying value is passed
                );

Breaking it down further, this discrepancy means that during the migration process, the system expects a certain number of mTokens to be minted based on the collateral provided. However, because the minAmountOut value is derived from the underlying asset's amount rather than the mToken's equivalent, the check for sufficient tokens minted often fails. This failure is particularly pronounced when the exchange rate—the ratio of the underlying asset to its mToken representation—is above a certain threshold. The exchange rate reflects the market value and demand dynamics between the underlying asset and its mToken, and a higher rate indicates that more of the underlying asset is needed to mint an equivalent amount of mTokens.

In simpler terms, imagine you're exchanging currency, and the exchange rate fluctuates. If you're expecting to receive a certain amount in the new currency (mTokens) but the rate changes such that you receive less than expected (due to minCollateral being miscalculated), the transaction would fail. In the context of the Malda lending protocol migration, this means that users attempting to migrate their positions might find their transactions reverting, effectively halting the migration process for them.

Internal Pre-conditions

For this vulnerability to rear its ugly head, there's one crucial internal condition:

  1. The Malda market exchange rate mantissa must be greater than 1.111e18. This is pretty common, especially after interest accrual bumps up the rates over time. It is important to emphasize that the exchange rate here refers to the ratio between the underlying asset and its corresponding mToken within the Malda lending market. An exchange rate mantissa greater than 1.111e18 signifies that the mToken is valued higher relative to the underlying asset, a condition that frequently arises due to accumulated interest and market dynamics. This scenario is not merely a theoretical edge case; it's a practical consideration that the protocol must handle gracefully to ensure smooth operations and migrations.

The reason this exchange rate threshold is so critical lies in its direct impact on the mintTokens calculation within the __mint function. As previously discussed, mintTokens is calculated by dividing the collateralUnderlyingAmount by the exchange rate. When the exchange rate exceeds 1.111e18, the resulting mintTokens value can fall below the miscalculated minAmountOut, which is based on the underlying asset's units rather than the mToken's. This creates a mismatch that triggers the require statement to fail, thus reverting the transaction and halting the migration process.

External Pre-conditions

Luckily, there are no specific external conditions that need to be met for this to be a problem. This makes it even more concerning because it can happen under normal market conditions.

Attack Path

Let's walk through how an attacker could trigger this issue:

  1. User invokes migrateAllPositions(): A user tries to move their positions from Mendi to Malda. This is the starting point for the migration process, and it's where our vulnerability comes into play.
  2. Contract collects positions via _collectMendiPositions: The contract gathers the user's positions and calculates minCollateral as 90% of collateralUnderlyingAmount (in underlying units). This is where the miscalculation happens, setting the stage for the subsequent failure.
  3. mintOrBorrowMigration called on Malda market: For the collateral, the contract calls mintOrBorrowMigration(true, collateralUnderlyingAmount, ..., minCollateral) on the Malda market. This is the crucial step where the mismatched minCollateral is passed, leading to potential issues down the line.
  4. mintTokens calculated in __mint: Inside the __mint function, mintTokens is calculated as div_(collateralUnderlyingAmount, exchangeRate). This calculation is correct in principle, but it's here that the comparison with the miscalculated minAmountOut will cause trouble.
  5. require(mintTokens >= minAmountOut) fails: If the exchangeRate is greater than approximately 1.111e18, the require statement fails, reverting the mint and stopping the entire migration process dead in its tracks. This is the climax of the attack path, where the vulnerability materializes, preventing users from migrating their positions.

It's important to note that the exchange rate exceeding 1.11e18 is not a rare occurrence. For instance, historical data from platforms like Compound Finance, as highlighted in the audit, shows that the exchange rates for various assets frequently surpass this threshold. This makes the vulnerability highly practical and underscores the importance of addressing it to ensure the smooth functioning of the migration process.

Referencing the _exchangeRateStored variable of contracts on networks such as Compound Finance further supports this point. These rates are not static; they fluctuate based on market demand, supply, and interest accrual. Therefore, relying on an assumption that the exchange rate will always be below the critical threshold is risky and could lead to unexpected migration failures. The variability of exchange rates is a key consideration when designing financial protocols, especially those involving token migrations and minting processes. Protocols need to be robust enough to handle these fluctuations and ensure transactions can complete successfully under a wide range of market conditions.

Impact

This is a big deal, guys! Users trying to migrate will find their transactions failing. Their positions will be stuck in Mendi, and the migrator contract becomes useless. There's currently no workaround, which makes this a critical issue.

In essence, the impact of this vulnerability extends beyond mere inconvenience; it poses a significant operational risk to the Malda lending protocol and its users. The inability to execute migrations can disrupt investment strategies, lock up assets, and erode trust in the protocol's reliability. Moreover, the fact that there is no immediate fix exacerbates the problem, highlighting the need for a swift and effective resolution.

The severity of the impact is amplified by the fact that migrations are often time-sensitive and crucial for users seeking to take advantage of new opportunities or to manage risk. When a migration process fails, it can lead to financial losses, missed investment windows, and a general sense of frustration among users. These outcomes can negatively affect the protocol's reputation and its ability to attract and retain users.

PoC

Unfortunately, there was no Proof of Concept (PoC) provided in the original audit report. A PoC would have demonstrated exactly how this vulnerability could be exploited.

Mitigation

Similarly, there was no specific mitigation strategy suggested in the report. However, the core of the solution lies in correcting the calculation of minCollateral. It should be expressed in mToken units, not underlying asset units. This could involve using the exchange rate to convert the value appropriately. It's a crucial fix that will prevent the mismatch and allow migrations to proceed smoothly.

Repair input keyword

  • Why does a token mismatch in minAmountOut cause migration failure? Can you simplify the explanation?
  • What preconditions, both internal and external, can lead to this migration failure?
  • Explain the step-by-step attack path that could exploit this vulnerability.
  • What is the overall impact of this migration failure on users and the protocol?
  • How can we fix the calculation of minCollateral to prevent this issue?

Title

Malda Lending: Token Mismatch Migration Failure