A trustless price oracle for ERC20 tokens on Ethereum Mainnet
For many smart contract protocols, an on-chain source of truth for asset prices is critical. Examples include lending protocols that need to value collateral or asset management protocols that need to rebalance a portfolio. Unfortunately, existing price oracle implementations are either controlled by a single party or lack the right incentives to keep prices accurate.
Polaris is an on-chain price oracle that is powered by Uniswap and designed to be accurate, resistant to price manipulation, and self-sustaining.
Uniswap is a decentralized exchange and automated market maker. Instead of matching buyers and sellers with an order book, it pools liquidity from market makers and uses an algorithm to set the price. Automated market makers like Uniswap have prices that are close to the market price, because whenever price imbalances exist, arbitrage opportunities are created and the price quickly corrects.
Unfortunately, blindly accepting Uniswap’s spot price as the true price is not acceptable because it is trivial to manipulate the price on Uniswap in a single block.
Consider the “sandwich” attack:
- Attacker sells tokens on Uniswap to manipulate the price
- Now that the price is inaccurate, attacker liquidates loans on a lending protocol that uses Uniswap to value collateral
- Attacker repurchases all tokens initially sold
Since the attacker is only required to pay trading fees, and not required to maintain the manipulated price, the attack can be very profitable. This attack can also be executed in a single transaction by a smart contract.
Polaris makes attacks more costly by taking the median of price checkpoints from Uniswap over time. By extending the required duration of price manipulation beyond a single transaction, manipulating the price becomes much more difficult and costly. This solution makes a small compromise on the liveliness of the price in order to resist price manipulation.
Polaris is designed to have low costs to maintain and high costs to attack. For this reason, it uses the following rules to determine the price:
- Return the median of the last 15 checkpoints as the price
- If more than one checkpoint is registered within a 3.5 minute period (15 blocks), count the median of these checkpoints as a single checkpoint
When a normal change in Uniswap price occurs, the oracle will reflect the new price in a maximum of 8 checkpoints, with one checkpoint registered in each 3.5 minute period. However, in an attack scenario, a malicious actor would potentially have to register a manipulated price multiple times within a single period if there are honest checkpoints to defend the attack. The attacker would lose thousands of dollars in trading fees for each price manipulation with an uncertain chance at success, while the honest checkpoints would be inexpensive to register in order to defend the system.
In addition, Polaris only allows externally owned accounts to register checkpoints in order to prevent sandwich attacks from smart contracts.
Polaris uses a set of incentives to encourage third party actors to regularly checkpoint prices and maintain an accurate price feed. In order to reward “pokers”, Polaris charges smart contracts a monthly subscription fee for the ability to read prices from the oracle. In anticipation of using the oracle for our secured lending protocol, Marble is currently the first paying subscriber of the ETH-DAI price feed.
Third parties are incentivized to “poke” the price oracle under the following conditions:
- The current price on Uniswap is >1% different from the median price.
- The current price on Uniswap is >1% different from the median of all checkpoints in the last 3.5 minutes
- The current price on Uniswap is >1% different from the last checkpoint
- It has been >3 hours since the last price checkpoint was registered
The price oracle rewards pokers by minting oracle tokens for checkpoints that satisfy the above criteria. Oracle tokens can then be used to redeem revenues of the system.
We backtested the oracle’s performance with historical Uniswap DAI/ETH prices for every block since January 1, 2019. Using only incentivized “pokes” as checkpoints for the oracle, we found that the oracle would have tracked the Uniswap price closely.
As expected, the oracle lags behind the spot price on Uniswap when there is a fast price crash:
However, it is quick to collapse to market price after only ~10 minutes.
Based on an average of ~200k gas per poke, 5 Gwei gas price, and historical ETH/DAI Uniswap volatility, the estimated yearly cost for a network of incentivized pokers to maintain the oracle would be ~20 ETH.
If we want truly fair and self-sustaining financial markets, we need an oracle system that is accurate, fast, unbiased, and resistant to price manipulation. This is a first attempt towards that goal. We realize it may not be perfect so we are eager to hear feedback and constructive criticism from the decentralized finance community. Please reach out at firstname.lastname@example.org or on Twitter @marbleprotocol.