[LlamaLend]: fxSAVE Market Action Response

Post-Mortem: LlamaLend FxSAVE Market

During the 31st of January to the 1st of February, we saw a market-wide sell-off. Despite fxSAVE being a yield-bearing stablecoin and correlated to crvUSD, bad debt occurred in this lending market (It has since been entirely paid off thanks to resolution by the Convex team). In this piece, we try to illuminate:

  1. What went wrong?
  2. What has been done about it?
  3. How do we mitigate this in the future?

1. What went wrong?

The emergence of bad debt in the fxSAVE market was not the result of a single failure, but rather a confluence of structural vulnerabilities triggered by a market-wide sell-off.

1.1 Thin Liquidity in Oracle Pool

At the time of the crash, the scrvUSD/fxSAVE Pool (0xb6E4821c6fCABe32f5F452dfD3Ef20Ce2A3a48E2), which was used in part as the oracle for the lending market, had relatively low TVL.


Source: Curve API

Given that this was the only direct trade venue for the fxSAVE market on Curve, trades through this pool likely cause disproportionate volatility in the Oracle price of the lending market.


Source: Curve Monitor

We can see that the pool has been highly utilized, averaging 3000% utilization in the last 24 h.


Source: Curve Monitor

The chart above shows the fxSAVE price per crvUSD, with the blue line representing the Oracle Price. We can see that, inspecting the oracle price, several dips were caused by severe movement routed through this pool.

1.2 Leverage, Deleveraging, and Oracle Feedback Loops

Borrowers in correlated yield-bearing stablecoin markets typically employ looping strategies, earning yield on the collateral while borrowing against it. These strategies are usually operated at low health factors, under the assumption of a tight correlation between collateral and debt.

Odos is the primary router for enabling users to leverage and deleverage in the Curve frontend. If we cross-verify the route indexed by Odos for a trade from fxSAVE to crvUSD, the scrvUSD/fxSAVE Pool is the only pool that can reach fxSAVE.


Source: Odos

Hence, in the fxSAVE market:

  • DEX aggregators (e.g., Odos) indexed scrvUSD / fxSAVE as the primary route
  • As market conditions deteriorated, deleveraging pressure increased.
  • These deleveraging trades flowed through the same thin pool that powered the oracle.

A typical deleveraging flow may look something like this:

  1. Sell fxSAVE for scrvUSD
  2. Sell scrvUSD for crvUSD
  3. Repay Debt
  4. Repeat

Because the pool was small relative to market size, deleveraging consistently pushed the pool price in a direction that worsened the oracle exchange rate. This created a feedback loop:

  1. Deleveraging trades move the pool price
  2. The oracle reflects this movement
  3. Borrower health deteriorates according to the oracle
  4. Further deleveraging is triggered

As a result, the oracle increasingly reflected execution pressure in a thin pool, rather than fundamental asset values.

1.3 Ineffective Liquidation Pathways

Direct liquidation routes also would have been routed through the fxSAVE/scrvUSD Pool. Let’s consider a typical direct path during a liquidation event:

  1. Flashloan crvUSD
  2. Repay Hard liquidatable positions
  3. Swap fxSAVE for scrvUSD (devaluation of fxSAVE relative to scrvUSD)
  4. scrvUSD for crvUSD
  5. Repay flashloan

Liquidations, like borrowers’ deleveraging behaviour, would have worsened the exchange rate in a thin pool.

Indirect routes are available by routing through USDC/fxUSD and redeeming instantly from fxProtocol, at a 1% fee; however, they are non-standard routes that may not be picked up by generalized liquidation bots (which generally evaluate feasibility based on pool configuration and states rather than custom routes through protocols). Given that the market is aggressively parameterized with a 1.4% liquidation discount, little profit would remain after paying a 1% redemption fee and facing external frictions.

1.4 Embedded Basis Risk in the Oracle Design

During the market crash, crvUSD experienced a mild depeg, while fxUSD increased marginally. This may violate some assumption made in the price oracle design. The chart below shows the market price divergence of fxUSD (the underlying to fxSAVE) to crvUSD:


Source: Dune - Dex Hourly Prices

Even at the time of writing, according to Dune, secondary market prices continue to diverge from the AggregatorStablePrice contract.


Source: Dune

The components used to calculate the price of fxSAVE for the market are the Price per Share (PPS) of the frxSAVE/fxUSD ERC-4626 vault, the fxSAVE/scrvUSD pool, and the aggregated crvUSD/USD contract.

The oracle price is calculated from the PPS from the fxSAVE Vault, the fxUSD/crvUSD exchange rate from the fxSAVE/scrvUSD pool (see the note below for details), and the Aggregated crvUSD price. This yields the following oracle price conversion formula:

oracle\_price \approx (\frac{fxSAVE}{fxUSD} \times \frac{fxUSD}{crvUSD} \times agg(\frac{crvUSD}{USD}))

This simplifies to assuming:

oracle\_price \approx \frac{fxSAVE}{USD}

Oracle price is denominated in USD via an aggregated crvUSD contract; price discovery delays, weighting, and EMA effects are prominent in the aggregated crvUSD-crvUSD price delta. These deltas can create situations where the true redemption value of fxSAVE is also affected. Under normal conditions, this basis effect was minimal in isolation; it amplified oracle volatility when the price of fxUSD/crvUSD came from a thin pool.

How fxUSD/crvUSD is derived from the fxSAVE/scrvUSD pool

Note: If the pool is configured with asset_types[i] = 3 (ERC4626) for both fxSAVE and scrvUSD, the pool’s pricing logic first “unwraps” each vault share into its underlying asset value via ERC4626(token).convertToAssets(...) inside _stored_rates() . Concretely, the AMM works on xp balances xp[i] = balance[i] * rate[i] / 1e18 , where rate[i] is the ERC4626 share→asset conversion (plus decimal normalization). That means the pool’s state price between the two LP coins is effectively a price between their underlyings, and you can derive the underlying fxUSD/crvUSD cross-rate by combining the pool price with each vault’s share→asset rate:

\frac{\text{fxUSD}}{\text{crvUSD}} = \frac{\text{fxSAVE}}{\text{scrvUSD}} \times \frac{\text{crvUSD per 1 scrvUSD share}}{\text{fxUSD per 1 fxSAVE share}}

where “crvUSD per 1 scrvUSD share” and “fxUSD per 1 fxSAVE share” come from convertToAssets(1 share) (appropriately scaled to 1e18). This is the “trick”: the pool doesn’t need a direct fxUSD/crvUSD oracle; it infers it from the pool price of the wrappers plus the ERC4626 conversion rates.

2. What is being done about it?

Convex stepped in by selling some of its FXN to absorb losses and help clear bad debt. They have also temporarily added liquidity to the fxSAVE/scrvUSD pool to further improve direct liquidation pathways and strengthen oracle resiliency while an alternative oracle can be voted to replace the existing oracle. This voluntary action cleared the bad debt — kudos to those involved.

FxProtocol temporarily reduced redemption fees to 0.05% to improve the viability of liquidation. Lower fees made indirect liquidation routes economically more attractive and helped Convex to liquidate at lower cost. The team is now considering whether a permanently lower redemption fee could keep these liquidation pathways open in future stress scenarios.

3. How do we mitigate this in the future?

3.1 New Oracle contract

LlamaRisk proposes an alternative Oracle Contract. The vote for the replacement of the oracle has already been shared on the governance forum. The components involved in pricing are the Price per Share from the ERC4626 Vault (which approximates fxSAVE/fxUSD), fxUSD/USDC pool, USDC/crvUSD pool, and the Aggregated crvUSD Price contract. The conceptual formulation can be outlined below:

oracle\_price \approx (\frac{fxSAVE}{fxUSD} \times \frac{fxUSD}{USDC} \times \frac{USDC}{crvUSD} \times agg(\frac{crvUSD}{USD}))

The price feed simplifies to:

oracle\_price \approx \frac{fxSAVE}{USD}

The oracle assumes that the crvUSD price is equivalent to one dollar. The advantage is two-fold: 1) Deeper Liquidity Pools within the pricing components; 2) The liquidation venue is disentangled from pools used in the market’s price oracle.

3.2 Oracle Monitoring

LlamaRisk plans to implement oracle monitoring to detect when key pools used in price oracles reach low TVL. This will provide early warnings about market safety and allow for preemptive updates to the pools used as oracles. Over time, we plan to make this system more sophisticated or move away from pool-based oracles altogether.

Additional Potential Procedures and Features

Emergence and Bad Debt Procedure: We are in discussion with Curve DAO and its key stakeholders on how bad debt should be handled. We believe there should be standard emergency procedures for situations such as the fxSAVE market. Fast action is required to address Oracle issues, which may require special measures, such as fast-tracked governance votes.

For instance, in cases of bad debt involving yield-bearing assets correlated with and paired with crvUSD (such as fxSAVE), we believe a custom controller with pre-minted crvUSD should be used to liquidate the bad debt. Curve DAO could then hold the seized assets until their original value is recouped through interest earned on the underlying assets. In this model, Curve DAO temporarily becomes the holder of the bad debt. Each case must still be evaluated individually, as the held assets implicitly represent the backing of crvUSD.

For collateral not paired with crvUSD, we expect that, with the launch of V2, a share of fees from lending activities could be redirected to an insurance fund. This fund would be reserved for bad-debt liquidation, subject to clear guidelines defining when and how it can be used.

Further discussion is needed to refine these ideas, including market eligibility criteria and implementation details.

Dual Oracle Contracts: Swiss stake on its development roadmap, the implementation of dual oracle contracts, which enable the use of smooth curve pools for soft-liquidation and robust Chainlink oracles during hard liquidation. This would help prevent pools oracles from impacting the price, suffering from low liquidity

Soft Liquidation Pause: Swiss Stake includes in its development roadmap a concept for pausing soft liquidations when position health is below 0. Insolvent positions are currently exposed to continuous erosion while in soft liquidation, requiring urgent resolution. A solution would require moving insolvent positions to a reserve outside the AMM so that they dont continue to experience erosion from arbitrage.

Conclusion

The fxSAVE market event was not caused by a fundamental failure of fxSAVE or its underlying fxUSD, but rather by the interaction of oracle fragility, thin liquidity, and impaired liquidation dynamics under stress. It should serve as an important case study, prompting corrective actions and informing future risk-management processes within Curve DAO. We again thank Convex - without their intervention, this would have been a far more costly lesson.

The vote to set a new implementation for the fxSAVE-long lend market has passed here:

This oracle uses fxUSD as a proxy for fxSAVE to price in a more robust way. It uses the fxUSD/USDC * USDC/crvUSD pools * fxSAVE vault * agg_crvUSD to price as fxSAVE/USD. The caveat of this pricing method is that it only references the fxSAVE price per share rather than the market price itself, so a system failure of fxSAVE may not be immediately reflected in the oracle price. Since this tail risk is likely to make a negligible difference to legitimate liquidations processing, the trade off in ensuring stable oracle pricing for users is justifiable.