Here’s how Uniswap could be the decentralized price oracle for DeFi
DeFi applications need oracles to connect with the rest of the world. Today most DeFi projects use off-chain partly centralized price oracles. They are not fully decentralized, need maintenance and are costly, so they have not a lot of pairs available. However, a better and more decentralized solution might be available, and it might be under the eyes of everyone: Uniswap. In this article I’m going to explain how Uniswap could be used as the truly decentralized price oracle for the DeFi apps on the Ethereum ecosystem.
If you haven’t already, I would suggest you to give a look to the UniswapV2 documentation before jumping in this article, in particular the Introduction to Oracles.
Why we should use Uniswap as a price oracle
- A price oracle based on Uniswap would be fully on-chain: this mean that such a price oracle could be fully decentralized, unlike off-chain price oracle where price sources are points of centralization. This would also mean more security, as there is no need to worry about potential attacks to the external price sources.
- Unlimited pairs availability: as of November 25th, there are around 24000 pairs available on UniswapV2. But the nice thing about Uniswap is that everyone can create a new pair if it is not available yet. Such property may be inherited by a price oracle built on Uniswap. On the other hand, off-chain price oracles need maintenance and can provide only a limited number of pairs since each one of them has maintenance costs.
- TWAP: the biggest problems of on-chain price oracles have always been the high risk of manipulation. If a DeFi application use a decentralized exchange as a price oracle by reading the current price on the exchange, then it is easy for an attacker to manipulate that price through a flash loan. In fact, in the past we have seen different cases of this kind of attack (the most recent one, the Harvest Finance hack). However, this problem has been solved by UniswapV2 since it allows the use of TWAPs (Time-Weighted Average Price). Through their use an on-chain oracle can calculate the average price during a certain time interval. This calculated value is much harder to manipulate, especially if a pair has high liquidity and if the interval is long.
Difficulties
The main difficulty faced building a price oracle based on Uniswap is keeping the price fresh and updated at a low cost. TWAPs are implemented on UniswapV2 through an accumulator to which every second is added the current price. It is possible to calculate the average price between two instants in time when the value of the accumulator is known for both those instants, by calculating the difference and dividing by the time elapsed. However, while it is easy to retrieve the value that the accumulator has now, it is not easy to obtain the value that it had in an arbitrary point in time in the past.
If gas costs were not a problem, there would be two possible solutions:
- Updating the price regularly: at every update, the current accumulator could be saved in memory so that at the next update it would be possible to calculate the average price in the time elapsed by using it. If the price was updated each hour, then at every update it would be possible to calculate the average price during the last hour. The problem with this approach is that it requires a high costs active maintenance, and this make it no better under this point of view than off-chain oracles.
- Using storage proofs: for more info on this approach please read https://medium.com/@epheph/using-uniswap-v2-oracle-with-storage-proofs-3530e699e1d3.
Simplicity is the key
The problem with the two previous approach is the elevated gas costs, and at that point it would be more convenient to use off-chain price oracles. But sometimes the best approach is the simplest: we can save the accumulator every time that the price is read on the oracle so that it can be used for future reads. When we need to calculate the price, we can use the saved accumulators in order to calculate the freshest price that is also the average price of an interval longer than a predefined constant MIN_T
. In this way we can create a gas efficient price oracle that:
- does not need any maintenance
- is fully decentralized
- is always available
- is hard to manipulate, as prices are calculated as an average over an interval longer then
MIN_T
The main drawback with this approach is that prices are not guaranteed to be fresh. In fact, if for a certain pair the price was last updated a few days ago, we will only be able to calculate the average of the price since the last update since we don’t have saved any newer accumulator. However, this is not really a major drawback, for a few reasons:
- For DeFi applications this is likely not going to be a security issue. Each case should be analyzed separately, however this is unlikely going to be a problem because if the market price was to be much different than the price provided by the oracle, and this was economically advantageous to the users of a DeFi application, than those users would take profit from the situation as soon as possible, thus updating the oracle and refreshing it with the freshest price.
- A DeFi application could add additional layers of security if needed, for example requiring that the price is calculated as the average of an interval shorter than a chosen
MAX_T
. - If the current market price were to be more advantageous than the price provided by the oracle for a user to do a certain operation, than the user could update the oracle and wait
MIN_T
. At this point the oracle would provide the freshest price and the user could do the operation at the advantageous price.
One oracle for everyone
We can notice that this kind of oracle would work better when it receives frequent updates, that is if many DeFi applications were to use the same oracle. This should be the final objective: having a common price oracle for many DeFi applications. For this reason, this oracle should be trustable, free and easy for everyone to use. DeFi developers would be incentivized to use an existing price oracle based on Uniswap instead of creating a new one, as the first option would be much easier and more convenient. We can truly say that in this case unity makes strength!
If you want to see an actual implementation of this kind of price oracle, please check my article A simple and fully decentralized price oracle based on Uniswap for DeFi.