Fair Uniswap's LP Token Pricing 🦄

Fair Uniswap's LP Token Pricing 🦄
  • The recent Warp Finance's hack is the result of using vulnerable Uniswap's LP token prices. The attacker was able to drain ~$7.8M worth of DAI for a significantly smaller value of collateral remaining in the protocol.
  • The attack uses the typical flash loan attack vector:
    Flash loan --> skew reserves --> fake LP token pricing --> pay back flash loan.
  • One of the new features on Alpha Homora v2 is to enable users to supply LP tokens as collateral to open leveraged yield farming or leveraged liquidity providing positions. As we have seen, this feature requires Alpha Homora v2 to determine the price of LP token in an unmanipulatable way.
  • We have a solution to prevent this attack that has already been implemented on Alpha Homora v2 contract, and we'd like to share with our community on how we think of pricing LP tokens in an unmanipulatable way. We refer to this unmanipulatable LP price as a Fair LP Price.

Fair UNI-V2 LP Pricing

The price of an LP token is the sum of the underlying asset value:

$$ Price_{LP} = \sum_{asset\in LP} \bigg(Price_{asset} \cdot Reserve_{asset} \bigg). $$

So, only two factors determine the value of an LP token: underlying asset price \(Price_{asset}\), and underlying asset reserve (per LP token), \(Reserve_{asset}\).

However,  \(Price_{asset}\) and \(Reserve_{asset}\) may be vulnerable to manipulations from e.g. flash loans. For example, if an asset price is derived from AMM spot price, then an attacker can skew the spot price with a flash-loan sandwich attack. Similarly for the reserve derived from AMM reserves, e.g. from Uniswap's \(\texttt{getReserves()}\).

A flash-loan sandwich attack involves 3 steps:
1. Flash loan and pump the underlying asset to the pool (temporarily faking reserve balances)
2. Attack the target protocol (getting false reserve balances)
3. Dump the asset back and return the borrowed asset.

To compute Fair LP Price, we would need ways to find Fair Asset Price and Fair Asset Reserve.

Here, "fair" refers to unmanipulatability from e.g. flash loan attacks or temporary skewness.

Fair Asset Prices

There are many options to retrieve the Fair Asset Price on-chain, each of which has its own merits and downsides. The options include

  • Decentralized Price Oracle - E.g. ChainLink, Band Protocol. Asset prices are limited to the assets the oracle supports.
  • On-chain TWAP - E.g. Uniswap's TWAP, Keep3r Network. Asset prices are limited to the ones in Uniswap pools (and perhaps ones with sufficiently deep liquidity).
  • Centralized Feed - E.g. self-feed the prices on-chain using multiple centralized sources, for example, from CoinGecko, CoinMarketCap, CryptoCompare.

From these choices, we can assume we have the Fair Asset Price ready. The remaining part is to figure out how to derive Fair Asset Reserve.

Fair Asset Reserves

The actual underlying reserves of an LP token of an AMM can be manipulated, either from organic swapping or from attack vectors.

Straight-forward Approach (Vulnerable to price manipulation)

An trivial approach would be to get the current reserves of the underlying assets of the LP token divided by the LP token's total supply, e.g. Uniswap's \(\texttt{getReserves()}\). However, attack vectors such as flash-loan sandwich attack can temporarily skew the reserves and fake the underlying reserves.

This vulnerable LP pricing is the root cause of Warp Finance's recent hack.

So, how do we actually find Fair Asset Reserves?

Fair Asset Reserves Solution

The key idea is to infer the reserve ratio from the ratio of the underlying assets' fair prices. Here are the steps:

  1. Get current underlying asset reserves from \(\texttt{getReserves()}\) only to compute the product K.
    Ex: If current ETH/BTC pool reserve is 10,000 ETH + 200 BTC, then the product \(K = (10000\cdot 10^{18} )\cdot (200\cdot 10^{18} )= 2\cdot 10^{42}.\)
  2. Get fair price ratio \(P\) between the underlying assets.
    Ex: If ETH fair price is 650 USDT and BTC fair price is 22,000 USDT, then ETH-to-BTC fair price is 650/22,000 = 0.03.
  3. The fair asset reserves are then \(\sqrt{K/P}\) and \(\sqrt{K\cdot P}\).
    Ex: The ETH/BTC fair reserves are then 8228 ETH + 243 BTC.

The third step relies on the fact that Uniswap's spot price is given by the proportion of the underlying reserves, so this is simply working backwards from fair asset prices to fair asset reserves proportion.

Actual Implementation for Fair Asset Reserves

In Alpha Homora v2, the protocol also relies on fair LP token pricing. So, here's what the actual implementation looks like in smart contract code:

The Formula

Here's the result of combining fair asset prices and fair asset reserves:

$$ P = 2\cdot \frac{\sqrt{r_0 \cdot r_1} \cdot \sqrt{p_0\cdot p_1}}{totalSupply},$$

where \(r_i\) is the asset \(i\)'s pool balance and \(p_i\) is the asset \(i\)'s fair price.

Conclusion

With the combination of fair asset prices and fair asset reserves, we can now derive the fair LP token prices that are unmanipulatable and safe from attack vectors such as flash loan attacks.

This Fair LP Pricing also applies to other AMMs that use the constant product curve as well.