Proposal: Make use of multiple price feeds in the oracle for highly correlated assets to reduce the risk of unnecessary liquidations. For now, this includes the oracles for USDC, USDT, DAI, and SUSD, but could be expanded as Chainlink feeds are added. For a given asset X, the proposal is to use the X → USD price feed and the ETH → USD price feed to derive the X → ETH price. For example:
USDC → USD → ETH
USDT → USD → ETH
DAI → USD → ETH
YFI → ETH (unchanged)
Rationale: AAVE currently uses Chainlink as the primary oracle for all assets, which is a very resilient oracle network and is extremely difficult to manipulate. But the way Chainlink feeds are implemented in AAVE create unnecessary volatility for stablecoin pairs, which makes borrowing unnecessarily risky. This is because all stablecoin prices are converted to their ETH equivalent via the chainlink oracle. This creates volatility for a few different reasons.
There is a 1% allowed deviation from the median price before the price feed for any asset will update. This means that the assets can increase your debt ratio by about 2% by just random chance alone.
Different stablecoins are used in different markets. In the short term volatility situation of a market crash, stablecoin prices when converting to ETH will behave differently by asset because the liquidity for each asset pair is different. This can skew comparisons between stablecoins intensely, and could cause unnecessary liquidations.
A lot of these problems can be fixed when you note that most of the volatility in pricing happens in the stablecoin to cryptocurrency conversion. If all correlated assets share the same price feed for the volatile conversion, then the ratio between the correlated assets would no longer change due to price volatility. This solution has no impact on any assets that are correlated with ETH, and is win win as long as the solution can be implemented safely. Please see discussion below for more in depth detail on the issue.
It seems to me that the following are required if the change I’m proposing is to be implemented:
Create a contract for each asset pair that aggregates the price from two Chainlink contracts and consolidates them into one price in a format that the AAVE oracle can accept. I built a proof of concept which can be compared to the current feed on Rinkeby for DAI to ETH. This is literally my first actual solidity code so it probably needs some work and testing. I think I’ve demonstrated that it’s possible though.
Submit a proposal to the chain to call the setAssetSources function on the AAVE oracle to point to the new contracts.
Hi @pakim249 . Your points are really valid for certain cases, like the ones you mention of stablecoins.
Something to also consider for your example of leverage on stablecoins and that can also be problematic in certain situations is that the update of the prices for each stablecoin (in ETH) is async by the nature of Chainlink. Meaning that the price update of DAI in ETH could be updated before USDC in ETH, creating a bit of price divergence in the meantime (apart from the divergence you mention of $0.99 and $1.01.
There are from my perspective 3 type of solutions for this:
Using USD as reference in certain Aave deployments. This helps with stablecoins, but could be not so good for other tokens used as collateral, as their correlation with ETH is usually higher than with USD. So for markets with only stablecoins (or assets hardly pegged to them) and maybe ETH/BTC, could be fine.
Try to find a solution on the oracle side to have more synchronization on the oracle updates. This is not trivial, because systems like Chainlink work so well at the moment precisely because of being able to do async updates, based on a % of deviation with the previous price submitted to the chain.
More speculatively, try to find an “hybrid” solution. Maybe defining on the Aave reserves configurations the price of reference and having an unique source of conversion (ETH/USD?). This could be challenging technically and maybe introduce some other side problems, but potentially worth it to explore.
I’m not sure if this is where you were going with your third idea, but it makes sense to me to calculate the price of a stablecoin as:
Stablecoin → USD → ETH (the price reference for liquidators) → USD
where currently it is:
Stablecoin → ETH → USD
This way, we can take advantage of the lower variance of the stablecoin → USD conversion whenever those metrics are available in chainlink. Yeah it’s kind of weird but I think it’s the best solution for capital efficiency of stablecoins given the architecture of Chainlink.
As a starting point, do you have any statistics on the liquidations that did occur that would not have occurred under the proposed method, and liquidations that did not occur that would have occurred under the proposed method? And for the former, liquidations that would have occured anyways under the current method within a relatively short time window (say 24hrs). Would also be interesting to quantify the non-LQM occurrences of depositing USDC/DAI (collateral) and borrowing USDT (non-collateral). Collectively feels like an edge case where liquidations would occur under either approach during volatility and that may otherwise become moot post-LQM.
Thanks for the questions. No, unfortunately I haven’t done the work to get those statistics. I’ll work on seeing if I can query the subgraph to get this information. I don’t think this is an edge case sort of issue though. If there haven’t been any liquidations because of this, it is likely because people have adjusted their positions in order to avoid this price fluctuation getting them liquidated, and so querying for that information wouldn’t give us the answer we are looking for anyway.
Also, as @eboado pointed out, the asynchronous nature of Chainlink price updates can create a price divergence beyond the 1% deviation of the price feed itself. I will also try to find data on this, but I’m only just learning how to query the graph so it might take me a while. But this seems like a potentially catastrophic black swan event that is completely preventable by having pegged assets share the same price feed for high variation conversions (e.g. USD to ETH) and have another conversion to the peg (e.g. DAI, USDC, USDT to USD), though I have no idea how simple this would be to implement in the contracts.
Especially with the massive rise in stablecoin usage recently, I think being brought a third of the way to liquidation on practically a daily basis when borrowing another stablecoin should at least be worth a serious look for the largest liquidity provider in the ecosystem. And the fix I’m proposing is to simply use the same reliable price feeds as before, but use more of them! Taking large stablecoin positions should not be as risky as it is right now, and this is probably even more relevant as AAVE is introducing institutional investors into the mix.
@pakim249 thanks for bringing this out. I agree 100% that this is something that needs improvement. I would go as far as replacing all the price feeds with USD based ones, as this should technically be possible if all the feeds are updated in one transaction. It can be simulated using a mainnet fork. Are you willing to tackle this task? I can provide the needed technical support.
I’ve actually been working on building the information needed to justify this change. A fork sounds like a good idea to actually test how this would work. What I’ve done so far is build some historical data of price ratios between the relevant price feeds by querying the blockchain data directly. My next step is to try and build and test a contract that can output prices using two oracles instead of just one. Is this the kind of thing that you’re looking for? It’s my first go at this kind of thing so I’ll be a little slow but I’ll try to bring a solid case forward for changing the oracle mechanism. I’ll definitely let you know if I need help.
I’m not entirely sure my methodology is correct, so please explore my work with a grain of salt. I explain the process of making this spreadsheet in the readme. The results seem to capture the volatility of May 19 very well though, with the ratio of price feeds between USDC and USDT getting to ~0.917 at the lowest point. If you filter on the feeds that only convert to USD though, the lowest result is only 0.977 on May 19.
I also thought about replacing every feed with USD ones as well, but that would actually introduce the very same volatility problem into tokens that are tightly correlated with ETH. This might become an issue at the time of voting. I think the only win-win situation is to make use of multiple price feeds to ensure that correlated assets share the same price feed for a volatile conversion, which still could take the form of replacing ETH with USD as the base asset.
Sidenote: It’s interesting that USDT tends to get to such high prices in particular when converted to ETH compared to USDC and DAI. My initial speculation is that CEXes that operate primarily with USDT update their price feeds much quicker than blockchain oracles, so large price swings would have USDT prices updated before USDC or DAI prices.
I’m only just learning, but I have experience in other languages so that helps. I built the following test of concept contract, trying to make it fit into the interface that the aave oracle uses.:
This is actually a pretty interesting way to factor out the micro-volatility of the stablecoin side in stablecoin pairs. I can see an immediate benefit to quality, accuracy and smoothness of the price points
@eboado 's points on synchronicity are critical though. With no guarantees on the order of the price feed updates (which are price driven), we could be momentously getting even bigger price divergence.
Maybe one interesting point to explore is whether the price feeds could be updated on demand upon a 1% divergence on the “composite” price feed. I don’t think this is a possibility in the current Chainlink architecture, but it shouldn’t be too hard to implement if the economics work (the benefit from updating the feed so as to reduce divergence needs to be greater than the gas cost incurred by the node operators).
I think I will try to further explore the possibilities of this construct in the Witnet price feeds. I’ll share here any advancements or findings.
P.s.: @pakim249 your code looks just right. Only the virtual modifier in latestAnswer() and decimals() seems somehow redundant to me because I wouldn’t expect this contract to be inherited.
Thanks for your thoughts and the code advice! Regarding updating the feeds on demand, my thinking is that the periods in which you would want to update stablecoin price feeds to the composite ones are precisely the periods in which node operators would have to pay the most gas to do so, and their transaction must go through before liquidators if our goal is to protect AAVE positions from unnecessary liquidations.
If we wanted this functionality, couldn’t we just build the logic into the price feed itself? Also, I wonder if that logic would be redundant. The AAVE oracle contract already has a backup oracle, and can be triggered by returning a price feed answer of 0 which could serve as the trigger to change a price feed.
With the launch of V3 and it’s promise of isolated lending pools with higher LTV, I thought it would be a good time to revive this discussion. Official Chainlink documentation now even describes this method of using oracles to get different price denominations not available natively. But for our purposes, it’s simply a way to reduce price feed volatility for stable pairs with practically no downside.
@pakim249 V3 is designed to have USD native oracles rather than ETH native. THis will help with volatility especially in relation to stablecoins.
Would you like to sync with @eboado on pushing the upgrade of the price feeds to USD for V2? This step is critical on the upgrade path of the V2 markets to V3