Failure Resistance: The Dual Oracle Design

In the presentation below, Liquity’s CTO, Rick Pardoe, presents insights into how the Liquity protocol is leveraging both Chainlink and Tellor’s oracle services to provide their users with the most accurate price feeds.

Below are some more in-depth explanations of key concepts highlighted during his talk

What is Liquity?
Liquity is a decentralised borrowing protocol built on Ethereum. It allows users to draw interest-free loans, using Ether as loan collateral. Loans are paid out in LUSD, a stablecoin that is pegged to the US dollar. One of the unique features of the protocol is that it is completely immutable and censorship resistant. This means that the Liquity protocol is built to run without the need for human intervention. No one person, or centralized entity has the ability to alter the protocol in any way.

Using a DEX as an oracle 
When deciding on which oracles to use, Liquity considered using a “DEX”, such as Uniswap V2. A DEX, or decentralized exchange, refers to a peer-to-peer marketplace where users can trade cryptocurrencies directly with each other without having to rely on any centralized third party or middleman. Examples of popular decentralized exchanges include Uniswap and SushiSwap. With sufficient trading volume, a DEX will always have information on the last price that a certain pair was traded at, making it a good source for price data. 

The Uniswap V2 price oracle that Rick mentions, makes use of a price aggregation method known as Time-Weighted Average Prices (TWAP). It is an aggregation method that takes the average price of a token pair over a certain period of time. This form of aggregation can be useful in excluding short-term price fluctuations or manipulation of spot prices. While using a TWAP oracle like Uniswap V2 can be attractive to protocols looking for decentralized and immutable price oracle options, there are no guarantees of the liquidity of tokens on a DEX, due to the free flows of capital. The less liquidity a token has in a pool, the lower the cost of attack. This means that certain pairs could be “cheaper” to manipulate due to the low volume, thus making them more susceptible to attacks such as flash loan attacks. For those that might be unfamiliar with what exactly flash loan attacks are, here is a useful article by Binance Academy which explains the concept and provides some real-life examples.

Shortcomings of the mean/median approach
In his presentation, Rick Pardoe talks about why taking the mean or median price from oracles could result in inaccurate results.

Firstly, taking the mean (or average) price from a few oracles would not work if one of the oracles is dishonest or corrupt. Just one outlier piece of data is needed for the entire result to be rendered inaccurate. For example, if there are 5 oracles reporting the following prices: 

Oracle A: $5.01
Oracle B: $5
Oracle C: $4.99
Oracle D: $25
Oracle E: $5

The mean result would be $9, when in reality, the correct price should be closer to $5. 

Using the median result is also not desirable because if that piece of price data is wrong, the price reported on the entire Liquity system will be incorrect. 

For example, if there are 3 oracles reporting the following price data,

Oracle A: $4.99
Oracle B: $5
Oracle C: $5.50

The median result would be $5, which would be correct.

However, a bounded attack would be possible if just one of the oracles is corrupt. A bad actor could take control of the weakest oracle and insert the incorrect result into the middle and make itself the source of the price of the entire Liquity system. This is referred to as a “bounded” attack because the bad actor is limited to inserting themselves between the 2 honest oracles. If more than 1 oracle is corrupt then an unbounded attack could be possible. The diagram below depicts an illustration of an unbounded attack.

Diagram 1: Illustration of a bounded attack

Oracle B: $5
Oracle A: $5.49
Oracle C: $5.50

The median result would be $5.49, which would be inaccurate.

Liquity’s Price Feed Contract Code
In his explanation of Liquity’s price feed contract code, Rick elaborates on the trade-off that Liquity had to take when implementing the dual-oracle design. According to Rick, the “fetch price function” code, which is used to fetch price data from its oracles, has many different “branches” to it, as it needs to be reactive to several different scenarios. Having more branches results in the code having increased complexity. Having this more complex code, in order to achieve greater resilience of the entire Liquity system, is the tradeoff that had to be made when building the protocol. The fact that the Liquity system is required to consider and react to very specific scenarios leads to there being a greater surface area for attacks. While the dual oracle design is, in theory, meant to be more resilient, this resiliency can only be achieved if the code works perfectly as intended. Therefore, there is more pressure on developers to get the code right. Due to the higher complexity of the code, the overall resilience that is meant to be brought about by Liquity’s dual oracle design is, in practice, harder to achieve.

Oracle Logic In Liquity
The Liquity protocol calls both Chainlink (primary) and Tellor (fallback) oracles for every user operation. Each time, three prices are requested – The current & previous price from the primary oracle, and the current price from fallback oracle. This way, the protocol is able to keep track of the state of each oracle and only switches to the fallback oracle if the primary oracle is frozen or broken. 

It would be undesirable for transactions on Liquity to revert even if one oracle stops working or has been compromised. Users should still be able to adjust their loans based on the best price that can be fetched. This is another reason why three prices are called during each operation.

Liquity uses “try-catch statements” for all external oracle calls. In coding, the “try-catch statement” makes it possible to make different external calls inside an operation, and have the overall operation succeed even if one of the external calls fails.

When does Liquity switch to the Fallback oracle?
If the primary oracle is broken or frozen, the protocol will switch to use the fallback oracle. Another scenario in which they switch, would be if 2 consecutive primary oracle price updates show a difference in price of more than 50%.

Example: ETH/USD price shows $1500 in Update A, and then the next price fetched is $4000. This huge jump in price would be considered abnormal, and the protocol would switch to the fallback oracle for price data in order to ensure that the most accurate price of ETH/USD is being used on Liquity.

However, the switch will only happen if the secondary oracle does not agree with the primary oracle. (Recall: For every operation, Liquity fetches the current and previous prices from the primary oracle and the current price from the fallback oracle). If the fallback oracle does agree with the price, then this is a sign that the price change could actually be a legitimate market movement. This is how the Liquity protocol ensures that there is an actual discrepancy in price data before switching to the fallback oracle. 

Off-chain Signature Aggregations
Off-chain signature aggregations are a type of data computation that is done outside of a blockchain as opposed to within the blockchain (on-chain). Off-chain signature aggregations help to avoid network congestions and are far less expensive than on-chain aggregations. This is because there is a certain number of transactions that can take place per second on every blockchain before it becomes congested and slows down. On-chain data aggregation is a part of these transactional activities. At the same time, every activity on the blockchain will incur “gas fees”. In order to improve efficiency, scalability and reduce costs, Chainlink aggregates reports from its several nodes off-chain, into a single oracle report, and brings it back on-chain. While off-chain aggregation is cheaper & more efficient, it is also less transparent than on-chain aggregation which is far easier to monitor. 

Gas fees for oracle usage
During his presentation, Rick mentions that the gas price of the oracle data fetching is about 60000 units. In comparison, the bare minimum gas price for an Ethereum transaction is 21000 units. Gas fees typically increase in proportion to the complexity of the transaction. While 60000 may not seem like much of a stretch for such an important activity, the cost still has to be borne by the users of the protocol for each operation. For more information about gas prices and fees on Ethereum, refer to the documentation here

Liquity’s use of the dual-oracle design showcases the team’s dedication to ensuring the highest level of security for the protocol. Liquity has also been allocated a score of 97% on DeFiSafety. Their implementation of more than one oracle has also sparked further debate on the importance of developing best practices and industry standards for both oracle networks and users, in order to ensure the security and longevity of the entire ecosystem.

The Blockchain Oracle Summit was the world’s first conference to focus solely on the importance of oracles and their design. Several experts in the field gathered in Berlin to share their work and experience building and using various oracle services 

For more details about Liquity’s dual oracle design refer to this article.

Find out more about Liquity:
Liquity Documentation
Liquity Twitter
Liquity Discord
Liquity Youtube
Rick Pardoe Twitter

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top