Tracking error due to fees, and oracle may undervalue LP shares by to-be-accrued fees #15
Description
There might be two subtleties relating to LP fee accural in Uniswap which affect the accuracy of this oracle:
(i) for the purpose of valuing the shares, this oracle assumes that the assets in the pool will eventually be rebalanced such that the balances of the two assets represent equal value. This assumption is necessary in order for the LP price oracle to be resistant to manipulation of pair balances (by sanwiched back-and-forth trading, for example). However, the assumption is not exactly accurate due to the presence of the 0.30% taker fee (in the current Uniswap code), meaning that if "full arbitrage" occurs it will only take the balances to a ratio that is 0.30% away from "market value". This 0.30% discrepancy is always "in favour of the LPs" meaning that the oracle effectively undervalues the LP shares by up to 0.30% in these instances (and by less when the price implied by current balances is less than 0.30% away from "market value").
For an example of an oracle implementation which does not have this discrepancy, (probably) at the cost of burning more gas, see here. The tl;dr is that this implementation simulates the effects of an actual profit-maximising trade on the balances of the pool, instead of using the elegant but simplified formulas in this repo.
(ii) the effect of protocol fee accrual on the value of LP shares is not taken into account. Specifically, the implementation in this repo relies on the hypothesis that sqrt(res0 * res1) / totalSupply
is invariant across trades, mints, and burns. In fact, this quantity is not quite invariant, since it can increase by the accrual of taker fees, but this growth is precisely the discrepancy described in (i) above which results in a slight undervaluation of the shares by the oracle. However, due to the presence of the _mintFee
function in Uniswap, it is also possible for this invariant to decrease, when _mintFee
is called from mint
or burn
, and a decrease in this invariant will result in an overvaluation of the shares, which is potentially more problematic for our purposes. Moreover, the magnitude of the overvaluation is not bounded by 0.30%, and can in theory be very large if mint
or burn
have not been called for a long time while a significant increase in sqrt(res0 * res1) / totalSupply
has occured due to trading.
Explicitly, since the protocol fee is hardcoded to ~17% (while currently disabled), the oracle will overvalue the LP shares by 17% of the fee growth since the last call to mint
or burn
. Taking GRT/USDC, a pool with currently very high fee revenue, as an example, we see that if mint
or burn
have not been called for a day, then the shares will be overvalued by ~0.35%, and if no one calls it for a week they will be overvalued by 2.4%, etc. Obviously, it is very unlikely that the pool will go for so long without any mint
or burn
, and I am not aware of any way to stop them from being called or otherwise force this outcome, but it is still worth keeping in mind by anyone consuming this oracle, since in some cases this could be problematic.
Incidentally, the oracle implementation linked earlier, explicitly accounts for _mintFee
here, avoiding this problem. Another way around it would have been to somehow call _mintFee
before starting the calculations, however I don't see a way of doing that since minting or burning 0 shares is not allowed.