Defi is a new and growing part of the Ethereum ecosystem, but one of the key pieces that is just beginning to get attention is oracles. Without oracles, defi would only have access to on-chain information which severely limits its applicability to real world use cases. As most of you know, the space is already using oracles but there tends to be a lack of common knowledge with regard to their usage and security models. As new projects are beginning to build and current projects look to rework their designs into something more secure, hopefully this article can be a reference to the best practices, not for oracles, but for users of oracles. We won’t touch too much on the best design principles of oracles and their security models, but rather just on how to use any oracle if you’re building on Ethereum. So if you have the goal of security, censorship resistance, and decentralization, here are some best practices when building your smart contract and/or applications.
Practice 1: Oracle design and interaction must be a forethought in your protocol.
The easiest implementation of an oracle is a centralized one. You (the project owner) will just enter in a price. You see a lot of protocols use these oracles when they launch, often using a simple multisig for security; opting for the route of “progressive decentralization” (we have a lot of thoughts on this), saying that they will move to a decentralized oracle in the future. This can be fine for a hackathon, but it’s way too easy to begin relying on the performance of a centralized oracle as they perform so much better than any decentralized one could ever pretend to. When you can rely on instantaneously correct values submitted on-chain, you make different design decisions about the capability and user-experience of your system than you would otherwise.
Projects that launched using this philosophy of progressive oracle decentralization are now in the awkward position of having users that expect a certain experience, but they have a product that fundamentally doesn’t work securely with current decentralized technology stacks. They are forced to feign decentralization by adding parties to the centralized multi-sig or they quietly kick the can further down the road while they pray the scalability trilemma will be solved. Point is, decentralized oracle design is not easily retrofitted into your protocol unless it was at part of a well considered plan from the beginning.
Practice 2: Don’t rely on fast oracles
We always like to assume it will stay up and timely, but there are some not so unlikely scenarios where finality on the blockchain may take several minutes to finalize and you could be without an oracle.
Ethereum is still new. Although blocks are usually updated in a few seconds, during periods of stress, it can take a long time to get transactions to confirm. If you recall the crypto-kitties crisis or even the more recent “Black Thursday” explosion of gas prices, some transactions can take hours to push through if you aren’t paying ridiculous gas fees. And even if you do assume your protocol’s users are economically incentivized to pay these fees, do you really want them to be forced to pay these fees?
In addition to the network congestion problem, devs should also consider the extreme case of Ethereum going down. It’s unlikely that a long term disruption of the network would take place, but for short periods of time, one must consider the implications when utilizing a chain that lacks finality while at the same time interacting with off-chain and (often) fast moving information. We always like to assume it will stay up and timely, but there are some not so unlikely scenarios where finality on the blockchain may take several minutes to finalize and you could be without an oracle. This doesn’t mean that you can’t pick a time frame that you ideally want oracles in. Targeting a realistic uptime for oracles is great, but a robust defi protocol should have preparations for these edge cases. One of which should definitely be:
Practice 3: Assume your oracle can fail / be corrupted
Don’t assume finality in your oracle. A lot of protocols make the mistake of having an oracle update push some action (an example would be a derivative contract that settles as soon as an oracle updates). This is a mistake. You should have a standard operating procedure for your oracles failures, even if they are hopefully never used.
To review the basics, oracles can be broken in two ways:
-A bad value is submitted by your oracle
-Your oracle service shuts down and does not push a value on-chain (liveness)
The first problem occurs when your oracle breaks. For instance, if you’re using a centralized price feed and they accidentally multiply the value by 10,000. You don’t want to settle on this value and often even the oracle itself will delete this value (e.g. in Tellor this would be disputed and removed). But the problem remains — how long do you wait for checks to happen?
This is ultimately up to your protocol, and should remain at the protocol level since some contracts may be fine with a slower/more robust checking mechanism than others. A good example of this delay is the hour long oracle update period by Maker. Take your time and don’t assume it’s correct.
The second way to break an oracle is more devious. It occurs when an oracle does not update the value. An example could be your centralized oracle loses his private key and can’t update the contract. Now what happens to your derivative? Another problem with liveness would be that your oracle provider doesn’t push a value on-chain fast enough. Say the Ethereum network is clogged and gas prices are $20 per transaction. If your oracle only submits a $1 transaction fee, it could take hours for your contract to update. Referring back to practice 2, you should be ready for this; but you should also be cognizant of whether your oracle provider has the ability to unilaterally control this delay. With Tellor, we have a competition to put data on-chain (PoW), so liveness is a crypto-economic guarantee. Some more centralized options do not have such guarantees and the oracle provider could stand to delay transactions or could even censor when they update based upon bribes or their own positions.
When oracles are corrupted or censored, there are several options, all of which are hopefully never used. Some options include:
- Pause the contract and wait for a valid oracle value
- Defer to a different/fallback oracle
- Utilize multiple oracles
- Return any money / settle to a default value
Fallbacks and security should be primarily handled at the protocol level. Which fallback option should be used in each case is hard to say in a general fashion, but just be sure that all parties are sufficiently disincentivized from seeking out these options as their purpose would be to secure the network, not provide another avenue for malicious attacks.
Practice 4: Know the cost to break your oracle
Whether or not an oracle wants to admit, there is always a cost to break an oracle. Some are calculated by some cost to buy reputation and vote on the outcome, many are ultimately calculated by some fraction of the market cap of their token, and probably even more so are simply based on the cost to corrupt or censor known parties (e.g. the traditional centralized model). No matter what the cost to break, or even if it’s not set in stone, you should have a general idea of how secure your protocol is. For projects hoping to one day hold millions, if not billions of dollars, having an oracle backed up by a token with a market cap of a few million dollars, or the reputation of one group of people, is major security risk.
Knowing the cost to break allows one to determine how much security is needed to secure your system. One oracle may not be able to secure all the funds in a smart contract but by using multiple oracles or having other fallback methods, the cost to break the system would increase. Currently, there is an ongoing effort (EIP 2362) by multiple oracles in the space to standardize price/numeric data feeds and make it easier for new protocols to easily integrate multiple oracles into their system.
You should know where the ultimate security of your protocol comes from. If you outsource your price feed security to an oracle provider, know the details of when they will fail and handle it accordingly. If you want to have ultimate governance of your protocol, then own it in a way that secures the integrity and decentralization in the system. Ethereum is a phenomenal ecosystem of projects building some of the most cutting edge programs in the world and oracles are beginning to get the attention they deserve. We can build a system that makes sense on a decentralized network; we just have to be honest about the limitations, smart about the edge cases, and determined to create truly decentralized applications.