Curve price feed
The Curve price feed returns the USD price for a single Curve LP share. The price is computed as
ICurvePool.get_virtual_price() multiplied by the USD price of the cheapest asset in the Curve pool currently.
The intuition behind this is that it is more profitable to withdraw the asset with the largest balance in the pool (since otherwise the user will suffer imbalancing fees), which will be the cheapest asset. Therefore, a fair price for a Curve LP share is based on the price of the cheapest asset.
get_virtual_price() manipulation affecting Gearbox, the price feed checks the
get_virtual_price() returned value against preset lower and upper bounds. If the value falls outside the bounds, the function reverts.
The bounds are configured by the governance and the upper bound is typically set to the current value +2%.
Beyond the intuition, we also want to show that the defined calculation cannot overestimate the value of a Curve LP, since otherwise the discrepancy can be exploited to steal money from LPs.
Curve's invariant is defined as
where is balance for the i-th token in pool, is the number of tokens, is the amplification parameter and is a constant representing the virtual price of the token.
Curve price oracle equation
We want to prove that
is true for any Curve pool. is price of Curve LP token nominated in -th coin.
Real curve LP price is equal to
where by definition is the price of -th coin nominated in -th coin (or ). Substituting, we get:
which is always true by definition of .
ICurvePool.get_virtual_price() is calculated as . So the price oracle value calculated as
ICurvePool.get_virtual_price()*min(p_i) corresponds to the right hand side in the inequality. Hence, Gearbox will always value Curve LP tokens conservatively as long as
get_virtual_price() is not manipulated.