Author: Samczsun
Translation: Olivia
At the end of 2019, I published an article entitled “Taking undercollateralized loans for fun and for profit”. In it, I described economic attacks on Ethereum DApps, which rely on accurate price data for one or more tokens. It is now the end of 2020. Unfortunately, many projects have made very similar mistakes since then. The most recent example is the Harvest Finance hack, which caused a collective loss of US$24 million for agreement users.
Although developers are familiar with vulnerabilities such as reentry, price manipulation by oracles is obviously not a problem that people often consider. On the contrary, loopholes based on reentrancy have declined over the years, while loopholes based on price oracle manipulation are now on the rise. Therefore, I decided it was time for someone to publish an authoritative resource on price oracle manipulation.
This article is divided into three parts. For those who are not familiar with this problem, there is an introduction to oracle and oracle manipulation. Those who want to test their knowledge can skip to the case study, where we reviewed past vulnerabilities and exploits related to oracles. Finally, we summarized some techniques that developers can use to protect their projects from oracle manipulation.
Oracle manipulation in real life
Wednesday, December 1, 2015. Your name is David Spago, and you are at the Duke of Beijing concert in Melbourne, Australia. You want to meet the band in person, but there are two security guards standing between you and the backstage channel. It is impossible for them to let some ordinary people walk in directly.
You want to know how the security guards will react if you act like an ordinary person. The band’s family members will definitely be allowed to visit the band’s backstage, so all you have to do is make the security guards believe you are their family. You think for a while and come up with a plan that can only be described as a genius or a madman.
After arranging everything quickly, you walk to the security guard confidently. You introduced yourself as David Spago, Peking Duk’s family. When the security asked you to provide evidence, you showed them irrefutable evidence-Wikipedia.
The security beckons to you and makes you wait. Five minutes later, you are wondering whether you should escape before the law enforcement officers show up. When you were about to leave, Ruben Styles came over and introduced himself. You walked to a green room with him. The band was impressed by your ingenuity, and finally you drank a few bottles of beer together. Later, they shared what happened on their Facebook page.
What is a price oracle machine?
A price oracle machine is basically anything for which you can consult price information. When Pam asked Dwight about the cash value of Schrute Buck, Dwight was like a price oracle.
On Ethereum, everything is a smart contract, and so are price oracles. Therefore, it is more useful to understand how the price oracle machine obtains price information. One way is that you can simply get the existing off-chain price data from the price API or exchange and bring it to the chain. Another way, you can calculate the real-time price by consulting the on-chain decentralized exchange.
Both of these options have their own advantages and disadvantages. Off-chain data generally responds slowly to fluctuations. Whether this feature is good or bad depends on the purpose of using it. However, it usually requires a few privileged users to push data on the chain, so you must believe that they will not go bad and cannot be duressed to push bad updates. The data on the chain does not require any privileged access and is always up-to-date, but this means that it can be easily manipulated by attackers, which can lead to disastrous consequences.
What might go wrong?
Let’s take a look at a few cases. In these cases, a price oracle with low integration level caused significant economic losses in DeFi projects.
Synthetix sKRW Oracle failure
Synthetix is a derivatives platform that allows users to access assets such as other currencies. To achieve this goal, Synthetix (at the time) relied on a customized off-chain price push, where the total price calculated from a set of secret price pushes was posted on the chain at fixed time intervals. These prices then allow users to trade long or short against the supported assets.
On June 25, 2019, one of the price pushes that Synthetix relied on erroneously reported that the Korean won price was 1,000 times higher than the real exchange rate. Due to other errors in other parts of the price oracle system, this price was accepted by the system and published on the chain. A trading robot on the chain quickly bought and sold on the sKRW market.
In theory, the robot can make a total of more than $1 billion in profits, although the Synthetix team can negotiate with traders in exchange for bug bonuses to return funds.
Synthetix correctly executed the oracle contract and extracted prices from multiple sources to prevent traders from predicting price changes before posting them on the chain. However, an isolated case of an upstream price source malfunctioning led to a devastating attack. This illustrates the risk of price oracles using off-chain data: you don’t know how the price is calculated, so your system must be carefully designed so that all potential failure modes can be properly handled.
Mortgage
As mentioned earlier, I published an article in September 2019 outlining the risks associated with using price oracles that rely on on-chain data. Although I strongly recommend reading the original post, it is quite long and contains many technical details, which may be difficult to digest. Therefore, I will provide a simplified explanation here.
Imagine you want to bring decentralized lending to the blockchain. Users are allowed to deposit assets as collateral and borrow other assets. The maximum amount is determined by the value of the assets they deposit. Suppose a user wants to use ETH as collateral to borrow US dollars. The current price of ETH is 400 US dollars, and the mortgage rate is 150%.
If the user deposits 375 ETH, it is equivalent to depositing $150,000 in collateral. Every 1.5 dollars of collateral can borrow one dollar, so they can borrow up to 100,000 dollars from the system.
But of course, on the blockchain, it is not as simple as announcing that 1 ETH is worth $400, because a malicious user can simply declare that 1 ETH is worth $1000 and then take all the money from the system. Therefore, it is tempting for developers to get the latest price read by the oracle, such as the current spot price of Uniswap, Kyber or other decentralized exchanges.
At first glance, this seems to be the correct approach. After all, as long as you want to buy or sell ETH, the price of Uniswap is always roughly correct, because any deviation will be quickly corrected by arbitrageurs. However, it turns out that during the transaction process, the spot price of the decentralized exchange may make a big mistake, as shown in the following example.
Consider how Uniswap’s reserves work. The price is calculated based on the amount of assets held by the reserve, but as users trade between ETH and USD, the assets held by the reserve will change. What if a malicious user makes a transaction before and after a loan from your platform?
Before the user took a loan, they bought 5000 ETH for $2 million. The price calculated by Uniswap exchange now is 1 ETH=1,733.33 USD. Now, their 375 ETH can be used as collateral for assets worth $433,333.33, and they have borrowed these assets. Finally, they exchanged 5,000 ETH for their original $2,000,000, thereby resetting the price. The end result is that your loan platform just allows users to borrow an extra $333,333.33 without putting in any collateral.
This case study illustrates the most common mistake when using a decentralized exchange as a price oracle-the attacker almost completely controls the price during the transaction, and trying to accurately read the price is like reading it on a scale. The weight before settlement is the same. You are likely to get the wrong number, and depending on the situation, you may lose a lot of money.
Synthetix MKR manipulation
In December 2019, Synthetix was attacked again due to manipulation of price oracles. This time it is worth noting that it crosses the barrier between on-chain price data and off-chain price data.
Reddit user u/MusaTheRedGuard observed that an attacker made some very suspicious transactions against sMKR and iMKR (reverse MKR). The attacker first bought a long MKR position by buying sMKR, and then purchased a large amount of MKR from the Uniswap ETH/MKR trading pair. After waiting for a while, the attacker sold their sMKR for iMKR and sold their MKR back to Uniswap. Then they repeat the process.
Behind the scenes, the attackers’ transactions through Uniswap allow them to change the price of MKR on Synthetix at will. This is probably because the off-chain price push that Synthetix relies on actually relies on the maker’s on-chain price, and there is not enough liquidity to allow arbitrageurs to reset the market to the best state.
This incident shows that even if you think you are using off-chain price data, in fact you may still be using on-chain price data, and you may still be exposed to the complexity of using these data.
bZx hacker
In February 2020, bZx was hacked twice within a few days and lost about 1 million US dollars. You can find the excellent technical analysis of the two hackers written by Palkeo here, but we only look at the second attack by the hacker.
In the second hacking attack, the attacker first used ETH to purchase almost all of the sUSD on Kyber. Then, the attacker himself purchased the second batch of sUSD from Synthetix and deposited it on bZx. The attackers used sUSD as collateral and borrowed the maximum amount of ETH they allowed. Then they sold sUSD back to Kyber.
If you have been paying attention, you will realize that this is essentially the same mortgage attack, but using different collateral and different decentralized exchanges.
yVault Bug
On July 25, 2020, I reported a bug to yEarn about the launch of their new yVault contract. I will briefly summarize below.
The yVault system allows users to deposit Tokens and earn profitability on them, without the need to manage them themselves. Internally, the vault will track the total issuance of yVault Token and the total amount of basic Token deposited. The value of a single yVault Token is given by the ratio of the minted Token to the deposited Token. Any proceeds earned by the vault will be apportioned to all issued yVault Tokens (and therefore to all yVault Token holders).
The first yVault allows users to earn USDC yields by providing liquidity to the Balancer MUSD/USDC pool. When users provide liquidity to the Balancer pool, they will receive BPT in return, and BPT can redeem part of the pool. Therefore, yVault calculates the value of its holdings based on the amount of MUSD/USDC that can be redeemed with its BPT.
This seems to be the correct way to implement it, but unfortunately, it is the same as the principle given before-the state of the Balancer pool during the transaction is not stable and cannot be trusted. In this case, due to the price curve selected by Balancer, users will not get a 1:1 exchange rate when switching from USDC to MUSD, but they will actually leave some MUSD in the pool. This means that the value of BPT can be temporarily amplified, which allows an attacker to manipulate the price at will, and subsequently deplete the vault.
This incident shows that price oracles do not always clearly reflect price data. Developers need to be wary of what kind of data they ingest and consider whether these data can be easily manipulated by unauthorized users.
Hacking for yield farming
On October 26, 2020, an unknown user invaded the liquidity mining pool. You may have guessed the technology used by now. You can read the official post-event report here, but I once again summarized it for you: the attacker falsified the USDC price in the curve pool by executing a transaction, enters the farming pool at a reduced price, and restores the price by reversing the previous transaction. And exit the farming pond at a higher price. This resulted in losses of more than 33 million U.S. dollars.
How can I protect myself?
Now, I hope you have learned to recognize the common ground – it’s not always safe for you to use price oracles. If you don’t follow proper precautions, an attacker may attack your agreement and send all your money to they. Although there is no one-size-fits-all repair method to refer to, here are some solutions that have worked for other projects in the past. Maybe one of them will also apply to you.
Find a pool with sufficient liquidity
Like jumping into the shallows of a swimming pool, jumping into an illiquid market is painful and can result in significant expenses that will change your life forever. Before you consider the complexity of the specific price oracle you plan to use, consider whether the token is liquid enough to ensure integration with your platform.
A bird in hand is better than two in the forest
It can be fascinating to see the potential exchange rate on Uniswap, but it does not mean that it is the final price until you actually click on the transaction and the token is placed in your wallet. Similarly, the best way to determine the exchange rate between two assets is to exchange assets directly. This method is very good, because there is no rebate and no in case. However, for agreements such as lending platforms, it may not be applicable, because these agreements require the holding of original assets.
Decentralized oracle
One way to summarize the problem with oracles that rely on on-chain data is that they are a bit too trendy. That being the case, why not introduce a little artificial delay? Write a contract that can update itself with the latest price on a decentralized exchange like Uniswap, but only when a small number of privileged users make a request. Now even if an attacker can manipulate the price, they cannot make your protocol really use it.
This method is really simple to implement, and it is a quick fix, but it also has some disadvantages-when the link is congested, you may not be able to update the price as quickly as you want, and you are still vulnerable to sandwich attacks. In addition, now your users need to believe that you will really keep the price updated.
Delayed defense
Manipulating price oracles is a time-sensitive operation because arbitrageurs are always observing and hoping to have the opportunity to optimize any suboptimal market. If the attacker wants to minimize the risk, they will want to complete the two transactions required to manipulate the price oracle in one transaction, so that there will be no chance for arbitrageurs to jump in the middle. As a protocol developer, if your system supports it, you may only need to implement a delay as short as 1 block between users entering and exiting the system.
Of course, this may affect composability, and the cooperation between miners and traders is on the rise. In the future, bad actors may manipulate price oracles in multiple transactions because they know that the miners they work with guarantee that no one can jump in the middle and get a share of their profits.
Time Weighted Average Price (TWAP)
Uniswap V2 introduces a TWAP oracle machine for developers on the chain. The document describes the specific security guarantees provided by the oracle in more detail, but generally speaking, for large pools that have not been congested on the chain for a long time, the TWAP oracle has strong resistance to oracle manipulation attacks. However, due to the nature of its implementation, its response speed may not be fast enough when the market is volatile, and it is only applicable to assets that already have liquid tokens on the chain.
M-of-N price feed
Sometimes people will say that if you want to do something well, you do it yourself. If you convene N trusted friends and ask them to submit the on-chain price they think is appropriate, the best M answers will become the current price. What will happen?
Many large projects are now using this method. Maker runs a set of price sources operated by trusted entities, Compound created Open oracles, and has reporters such as Coinbase, Chainlink aggregates the price data of Chainlink operators and makes them public on the chain. Just remember that if you choose to use one of these solutions, you have now delegated trust to a third party, and your users must do the same. Requiring the reporter to manually post updates on the chain also means that when the market is volatile and the chain is congested, price updates may not be completed in time.
in conclusion
Price predictors are an important part of DeFi security, but they are often overlooked. It is difficult to use price oracles safely, and there are many ways that you and your users can suffer. In this article, we introduced an example of manipulation of price oracles in the past, and determined that reading price information in the middle of a transaction may be unsafe and may lead to catastrophic financial losses. We also discussed some of the techniques used in other projects to combat price oracle manipulation in the past. But in the end, each situation is unique, and you may find yourself unsure whether you are using the price oracle correctly. If this is the case, please feel free to contact us for advice!