Deposit Sandwich

If the maxOracleDeviationBips bound is set too loose, then sandwich attacks on all LP funds could become possible.

Overview

The HOT assumes that at any point in time, reserves in the pool can be in arbitrary proportions. This is because, unlike traditional CFMMs, in the HOT, the solvers can request a quote at different prices than the AMM spot price.

Therefore, the reserves in the HOT can theoretically be split into 2 categories:

  • Active Reserves: Reserves that are available for both Solver and AMM swaps. These are always distributed pro rata over the AMM curve and tracked using the _effectiveAMMLiquidity variable.

  • Passive Reserves: Reserves that are only utilized by Solver Swaps, because they are imbalanced.

_updateAMMLiquidity

The HOT has an internal function called _updateAMMLiquidity which is called whenever we want to update the _effectiveAMMLiquidity to the maximum possible value, depending upon the available reserves.

But calling updateAMMLiquidity arbitrarily is dangerous because it essentially allows anyone to “redeposit” all of the LP funds into the active reserves.

If called without proper checks, this redeposit could be sandwiched like a normal UniV3 LP deposit.

The big difference is that in the case of UniV3 positions, each LP only deposits funds they own, so they can make sure to set slippage parameters correctly. But in the case of this “redeposit”, an attacker will be able to deposit all passive reserves (owned by all LPs of the pool) into the pool and sandwich everyone.

This is why we only allow updates to be made _effectiveAMMLiquidity under strict checks or by the trusted liquidity provider role.

Concrete Attack Example

Here is a concrete formulation of the kinds of attacks that could happen here without any special protections.

Let the current passive reserves in the pool be: (10 ETH, 5000 USDC).

The pool spot price is 2000 USDC/ETH.

If _updateAMMLiquidity is called correctly, then 2.5 ETH and 5000 USDC should be added to the active AMM Liquidity.

Now, an attacker can do the following:

  1. Manipulate spot price to 10 USDC/ETH

  2. Deposit/Withdraw 1 wei of ETH and almost negligible USDC pro rata

  3. This deposit/withdrawal would trigger an updateAMMLiquidity call, which would have caused the pool to add 10 ETH, and 500 USDC ( according to the current spot price ) into the pool.

  4. Now the attack begins. The attacker was just able to deposit a huge amount of liquidity at a really bad price. They can utilize this liquidity to swap back to the true price and make a huge arbitrage profit.

In this case, the pool just became willing to sell its 10 ETH, which would have been valued at 20,000 USDC for somewhere close to 100 dollars.

Protections

The _updateAMMLiquidity function can only be called in the following 4 cases:

  1. setPriceBounds: This function can only be called by the HOT Liquidity Provider, which is a trusted role, and will set the slippage parameters correctly.

  2. HOT Swap: The hot swap ensures that the AMM spot price is within the maximum deviation allowed to the guardian oracle price.

  3. Withdraw Liquidity: The effective AMM liquidity is capped such that it can never increase after a withdrawal, even if a large amount of passive funds are "redeposited" during the withdrawal call.

  4. Deposit Liquidity: The AMM spot price is checked against the guardian oracle price before a deposit ( just like a hot swap ). If the spot price has been manipulated too far away from the Oracle price, then the deposit is reverted.

Moreover, the updateAMMLiquidity call is made after the most important operations to increase capital efficiency and ensure that passive reserves are not accumulated in excess.

The HOT Liquidity Provider is expected to have a safe rebalance function, which can also do manual rebalancing in case the reserve composition of the pool gets too skewed in one direction.

Last updated