Proposal To Upgrade To UAV V3

Hi everyone, over the last several months we have been working with the folks at Chainlink to develop the UniswapAnchorView (UAV) V3. OZ has successfully audited the contract and it is ready for implementation.

Overview

Below are the high-level changes and improvements:

  • UAV V3 uses Uniswap V3 Oracles instead of V2
  • Increased number of markets available

The shift from using UNI-V2 to UNI-V3 is significant because V2 liquidity is drying up as liquidity providers move to V3 to capitalize on concentrated liquidity provisioning strategies. Having Compound’s UAV Oracle mimic this shift provides higher reliability and more security by reducing the risk of price manipulation or any other issues related to low liquidity.

UAV V3

The code can be found and reviewed on the UAV V3 Github page.

Below is the summary of changes:

  • The new UniswapAnchoredView (UAV) no longer records and keeps observations but instead queries the respective Uniswap V3 pool’s observe function to get a TWAP with the set anchor period when it’s needed (i.e., when a reporter calls validate on the UAV).
  • The price of an asset in Uniswap V3 is a function of the “tick” of the pool. The formula is price = 1.0001^tick. The math required for conversion between posted prices and the Uniswap V3 TWAP and the UAV representation has been modified to support this. Relevant libraries (TickMath and FullMath) have been included from the Uniswap V3 codebase.
  • The tests from the original UAV have been adapted to the new Uniswap V3 architecture - i.e., observations/TWAP tests were removed. Hardhat (+typechain) has been implemented so real Uniswap V3 pools can be used via forked mainnet in tests and eliminate the need for mocking Uniswap V3 pools.

This code has been audited, which you can see the results here: compound-uav3-audit - Google Drive

Below is a list of coins the protocol supports in the existing oracle contract and the TVL of the anchor market. Overall the change from v2 to v3 is very positive, however, there are a few markets where it is less.

Liquidity v2

ETH: $165m - 0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc
DAI: $18m - 0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11
USDC: N/A
USDT: N/A
WBTC: $21m - 0xBb2b8038a1640196FbE3e38816F3e67Cba72D940
BAT: $370k - 0xB6909B960DbbE7392D405429eB2b3649752b4838
ZRX: $268k - 0xc6F348dd3B91a56D117ec0071C1e9b83C0996De4
REPv2: $347k - 0x8979A3Ef9D540480342AC0F56e9D4c88807b1CBa
SAI: N/A
UNI: $22m - 0xd3d2E2692501A5c9Ca623199D38826e513033a17
COMP: $246k - 0xCFfDdeD873554F362Ac02f8Fb1f02E5ada10516f
LINK: $3m - 0xa2107FA5B38d9bbd2C461D6EDf11B11A50F6b974
TUSD: N/A
AAVE: $496k - 0xDFC14d2Af169B0D36C4EFF567Ada9b2E0CAE044f
SUSHI: $490k - 0xCE84867c3c02B05dc570d0135103d3fB9CC19433
MKR: $4m - 0x95b4eF2869eBD94BEb4eEE400a99824BF5DC325b
YFI: $661k - 0x2fDbAdf3C4D5A8666Bc06645B8358ab803996E28
USDP: N/A
FEI: $1m - 0x7713DD9Ca933848F6819F38B8352D9A15EA73F67

Not yet added to the protocol, but on the oracle contract:
MATIC: $1m - 0x819f3450dA6f110BA6Ea52195B3beaFa246062dE
RAI: $4m - 0x8aE720a71622e824F576b4A8C03031066548A3B1
LUSD $28k - 0xF20EF17b889b437C151eB5bA15A47bFc62bfF469
FRAX: $137k - 0xFD0A40Bc83C5faE4203DEc7e5929B446b07d1C76

Liquidity v3

ETH: $308m - 0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640
DAI: $54m - 0xc2e9f25be6257c210d7adf0d4cd6e3e881ba25f8
USDC: N/A
USDT: N/A
WBTC: $267m - 0xcbcdf9626bc03e24f779434178a73a0b4bad62ed
BAT: $1m - 0xae614a7a56cb79c04df2aeba6f5dab80a39ca78e
ZRX: $880k - 0x14424eeecbff345b38187d0b8b749e56faa68539
REPv2: $19k - 0xb055103b7633b61518cd806d95beeb2d4cd217e7
SAI: N/A
UNI: $12m - 0x1d42064fc4beb5f8aaf85f4617ae8b3b5b8bd801
COMP: $6m - 0xea4ba4ce14fdd287f380b55419b1c5b6c3f22ab6
LINK: $13m - 0xa6cc3c2531fdaa6ae1a3ca84c2855806728693e8
AAVE: $4m - 0x5ab53ee1d50eef2c1dd3d5402789cd27bb52c1bb
SUSHI: $280k - 0x73a6a761fe483ba19debb8f56ac5bbf14c0cdad1
MKR: $13m - 0xe8c6c9227491c0a8156a0106a0204d881bb7e531
YFI: $2m - 0x04916039b1f59d9745bf6e0a21f191d1e0a84287

Not yet added to the protocol, but on the oracle contract:
MATIC: $11m - 0x290a6a7460b308ee3f19023d2d00de604bcf5b42
RAI: $106k - 0x14de8287adc90f0f95bf567c0707670de52e3813
LUSD $114k- 0x9663f2ca0454accad3e094448ea6f77443880454
FRAX: couldn’t find anything worth referencing.

7 Likes

Great job @getty on getting this done! Having liquidity to back up our back-stop prices is important to have reliable, accurate, and manipulation minimized prices. Liquidity can move around making it important to have our code follow.

I’d like to share some words of caution when using Uniswap v3 as an anchor. While concentrated liquidity is better for traders, it’s worse for providing accurate and reliable oracle data.

A lack of liquidity higher or lower can mean it’s really easy to manipulate the price. Let’s take the COMP-ETH pool with the highest TVL (the 0.3% fee pool):

We see a lot of sell positions at the 0.0413 ETH price, a lot less between 0.0413 and the current price of 0.0354, and barely any buy positions below that price.

There’s very little liquidity supporting the price, so if someone were to dump COMP on this specific pool, the price would take a massive hit and could stay there for a while. COMP prices would then fail to update, or bad prices could slip through, or in the case the failover was active, we could suffer gruesome attacks.

We also noticed this with the UST-USDC pairs with the recent de-pegging event where UST’s Uniswap v3 price was at about $0.91 for a number of days while it was actually trading at a small fraction of that. This problem could have possibly affected other pairs as well.

From an oracle developer standpoint, I recommend having the requirement of sufficient full-range liquidity with some sort of guaranteed lock-up to prevent the liquidity from being removed.

6 Likes

Very cool! It seems to me like the scenario @TylerEther offers could be at least partially mitigated through a wrapper contract that simply takes a TVL-weighted average of the UAV V2 and UAV V3. Perhaps the benefits aren’t sufficient to justify the extra gas, but curious about your thoughts on whether UAV V2 could play a role in mitigating the concentrated liquidity risks of V3. Do you or others have a write-up relevant to these ideas that we could check out? Thanks!

1 Like

It’s best to not use stale prices, but doing so would damper the impact of such a failure scenario.

Aggregating Uniswap V2 and V3 directly on the other hand would result in a really strong price. I have roughly 4 months of data to support this - let me know if you want access.

1 Like

Fewer changes, fewer mistakes, less protocol revenue, less attention.

I’m curious what Compound’s past with using the failover has been. Do chainlink oracles go down for extended periods of time? Have any TWAP attacks been tried before?

This would mean aggregating and averaging V2 and V3 prices weighted by their respective liquidity, correct? Many newer tokens have a majority of liquidity concentrated on V3 - would hate to see low liquidity on V2 be an attack vector or a barrier to asset listing.

Thanks for working on this @GFXlabs - low liquidity on V2 has been a barrier to asset listing for many great projects.

I’m curious what Compound’s past with using the failover has been. Do chainlink oracles go down for extended periods of time? Have any TWAP attacks been tried before?

The failover has never been activated. So far we haven’t experienced any issues although the price feeds aren’t being monitored as far as I’m aware.

This would mean aggregating and averaging V2 and V3 prices weighted by their respective liquidity, correct? Many newer tokens have a majority of liquidity concentrated on V3 - would hate to see low liquidity on V2 be an attack vector or a barrier to asset listing.

Aggregating prices across multiple DEXs would be best. There’s not always going to be sufficient liquidity on Uniswap V2 or even V3. Sometimes the majority of liquidity can even be on Sushiswap or Curve in rare cases such as stETH-ETH. Fragmented liquidity has been a barrier to asset listing in the past and will likely continue to be a barrier, unfortunately.

I’d like to note that the minimum liquidity required for a Uniswap V2 pool is a lot lower than most people think. If we want the price to be 99% accurate, it must be profitable to perform arbitrage on the pool resulting in about a 1% change in price. This is a function of both liquidity and gas price. Because we use TWAPs (assuming the pool has minimum required liquidity for an accurate price), an attacker would have to manipulate the price every block over the TWAP period. It becomes even more expensive with miners performing arbitrage as well.

The real question becomes how do we guarantee that the fallback pool always has enough liquidity for an accurate price.

1 Like

I also have a comment on Uniswap v3’s observation cardinalities.

All of the UAV price updates call the Uniswap v3 pool oracle’s observe function. This function will revert if the pool oracle doesn’t have an observation for the past 15 minutes (i.e. the TWAP period).

Up to one observation is written per block (if there’s at least one trade in the block). So we must handle the worst case scenario where there’s a trade in the pool every block. Therefore, the underlying pool oracle’s observation cardinality must be at least 15 minutes / blockTime = 900 seconds / 10 seconds = 90. We use 10 seconds for block time as that’s what’s expected after the merge. Since blocks aren’t produced exactly every 10 seconds (or 11 seconds on average currently), we must use a bit higher than a cardinality of 90. I’d suggest requiring an observation cardinality of 120 to be safe.

Hi Compound Community,

The Chainlink Labs team is pleased to announce that we have successfully deployed the UniswapAnchoredView (UAV) V3 using the latest UAV configurations!

UniswapAnchoredView Contract

To recap, the update from Uniswap V2 to Uniswap V3 pools is crucial because V2’s liquidity continues to drop as liquidity providers migrate to V3. Compound’s UAV Oracle must follow this shift to provide a highly reliable and highly-secure price feed.

Below is the summary of the changes:

In addition, we’ve also increased the Uniswap observation cardinality to 150 on pools that were below 150. To elaborate, the “cardinality” in Uniswap is a term for the TWAP lookback history. It represents the state changes per block, so ten trades in a block get condensed and recorded as one update in the lookback. To save on gas costs, the cardinality starts at 2, and anyone can pay the gas cost for a deeper lookback. Therefore, increasing the cardinality to 150 ensures a safe minimum for the lookback history.

Uniswap V3 Liquidity Pools - As of Aug 5

Listed below are the Uniswap V3 pools and liquidity levels for each price feed in the UAV3. Note that it is required to reference the ETH-paired pools specifically:

  • ETH: $185M - 0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640
  • DAI: $19M - 0xc2e9f25be6257c210d7adf0d4cd6e3e881ba25f8
  • USDC: N/A
  • USDT: N/A
  • TUSD: N/A
  • WBTC: $244M - 0xcbcdf9626bc03e24f779434178a73a0b4bad62ed
  • BAT: $827K - 0xae614a7a56cb79c04df2aeba6f5dab80a39ca78e
  • ZRX: $928K - 0x14424eeecbff345b38187d0b8b749e56faa68539
  • REPv2: $30.5K - 0xb055103b7633b61518cd806d95beeb2d4cd217e7
  • SAI: N/A
  • UNI: $16.2M - 0x1d42064fc4beb5f8aaf85f4617ae8b3b5b8bd801
  • COMP: $4.3M - 0xea4ba4ce14fdd287f380b55419b1c5b6c3f22ab6
  • LINK: $8.1M - 0xa6cc3c2531fdaa6ae1a3ca84c2855806728693e8
  • AAVE: $3.9M - 0x5ab53ee1d50eef2c1dd3d5402789cd27bb52c1bb
  • SUSHI: $56.5K - 0x73a6a761fe483ba19debb8f56ac5bbf14c0cdad1
  • MKR: $11.8M - 0xe8c6c9227491c0a8156a0106a0204d881bb7e531
  • YFI: $178.5K - 0x04916039b1f59d9745bf6e0a21f191d1e0a84287
  • FEI: $233 - 0x2028D7Ef0223C45caDBF05E13F1823c1228012BF

We note that low liquidity in Uniswap v3 pools makes the TWAP price in those pools easier to manipulate. That may cause the Uniswap anchor to be less accurate than expected. However, this will not affect the accuracy of the primary price feed from Chainlink.

Next Steps

If the Compound community supports this upgrade, the following are the recommended next steps to proceed with this proposal:

  1. The Compound community will signal support using the above Uniswap V3 pools for the current UAV3 deployment.
  2. If supported, Chainlink Labs will configure all existing validator proxies to push prices to the new UAV candidate while continually pushing to the existing one. This is so that Compound voters can see the new UAV working as it should while the current UAV maintains full operation.
  3. Lastly, if the vote is passed and executed on-chain, The Comptroller will point to UAV V3 and use it for prices. At this stage, Chainlink will decommission UAV V2 by setting the ValidatorProxies to only point to the new one.
3 Likes

Really excited for Proposal 117 - fantastic collaboration all around to get to this :raised_hands:

2 Likes

integration with uniswap v3 pools sounds great.
and I’d like to check something before my voting activity.

I have checked compound v3 document but can not find out an anchor mechanism in there. It looks like comet is only depend on Chainlink price feed. isn’t it?

Hi @dakeshi, that’s right - Compound III is designed to use Chainlink Price Feeds directly. This is in line with how other major protocols use Chainlink. It also allows the Compound community to onboard new markets and deploy on more chains without a dependency on Uniswap.

An hour ago, Proposal 117 was executed, which updated the price feed that Compound v2 uses. This price feed contained an error that is causing transactions for ETH suppliers and borrowers to revert. Effectively, the cETH market is temporarily frozen.

OpenZeppelin, Chainlink, Compound Labs, and many members of the community are working to diagnose and fix this issue ASAP; GFX has created Proposal 119 which will revert the price feed to it’s original state.

You can still supply Ether collateral, and no users should be at risk of liquidation, or at risk of losing funds. If you have any questions, please join the community in Discord.

3 Likes

Here is an update on the incident and next steps for the Compound community:

On Aug 30th at 6:20 PM UTC, Compound Proposal 117 was executed to upgrade the Oracle Contract to a new version that uses Uniswap V3 instead of V2 for price feeds. It had passed a governance vote after being proposed by GFX Labs on behalf of ChainLink. The changes were reviewed by OpenZeppelin along with Dedaub and ABDK.

At 6:38 PM UTC, the proposal executor noticed that all calls coming from the Comptroller to getUnderlyingPrice for the cETH market were reverting and notified Compound developers of the issue. All other cToken markets appeared to be unaffected. Compound Labs, ChainLink, GFX Labs and OpenZeppelin teams were immediately notified and jumped into a war room.

At around 6:47 PM UTC, the proposal executor reported that because cETH does not have an underlying() method assumed to be present in every cToken contract by the new oracle implementation, the getUnderlyingPrice function returns empty bytes that cannot be decoded and the call reverts. This source of the issue was verified by Compound Labs and OpenZeppelin shortly after. This leaves withdrawals and liquidations in the cETH market effectively frozen while the issue remains in place.

At 7:14 PM UTC, a new proposal was submitted by GFX Labs to revert the upgrade and return to using the V2 Oracle contract. It is set to be passed and executed after a 7 day governance process. In the meantime, Compound Labs issued Twitter and Discord posts notifying users of the price feed issue while the war room participants continued to investigate the issue further to determine the impact on existing users.

The primary issue right now is a temporary denial of service for the cETH market which will be resolved by the new governance proposal. No funds are at risk at this time. The rest of the cToken markets on Compound V2 and all of V3 remain functional.

However, any users that deposited ETH and obtained cETH for opening borrow positions must be aware that they might get instantly liquidated whenever the fix proposal executes IF by that time the price of ETH has dropped significantly. These users can add collateral and repay borrowed assets normally to cover for eventual price drops by monitoring their borrow positions accordingly.

We’ll continue to work with the Compound community to ensure a speedy resolution and keep everyone informed on updates as they come. Once the immediate situation is resolved, a post-mortem will be forthcoming.

7 Likes

What is the eventual longterm plan? To alter UAV3 to accommodate cETH not having an underlying() function and redeploy?

Yes, there appears to be a simple fix to UAV3 that will accommodate cETH. We’ll focus on that after resolving the current disruption.

1 Like

Here is an update on the price feed issue for the cETH market. The fix proposal is still underway and expected to be executed in ~6 days.

As mentioned previously, users should be able to avoid any sudden liquidations caused by price changes once the fix proposal goes through by adding collateral or repaying borrowed assets. However, we’ve identified that some downstream protocols may not be capable of managing their positions at this time. For that reason, there may be a need to pause liquidations immediately before the proposal is executed to give these protocols time to adjust their positions.

OpenZeppelin has worked with Arr00 to prepare a proactive proposal that can be used to unpause liquidation IF the Pause Guardian decides that pausing is necessary. If market conditions do not change drastically and/or all positions are safe, then this will be unnecessary and the proposal will be canceled. We have also tested this proposal thoroughly to ensure it will work as intended since this will be the first time the unpause functionality may be used.

If the Pause Guardian does need to pause liquidations following the fix to protect some positions from unfair liquidations, this will only last for ~23 hours as the unpause proposal will reverse it shortly afterwards. Since this pause will impact all cToken markets, not just cETH, there are risks assumed by the protocol in case any other markets suffer a drop in price but it should be minor over the course of ~23 hours. If you are part of a protocol that is unable to manage positions or may otherwise be at risk of liquidations when price feeds turn on, please let us know in the community Discord.

We’ll continue to keep the community updated as we work with the Pause Guardian and other Compound participants to ensure the resolution is as smooth as possible. As we monitor the situation over the next week, we will also begin to work on a post-mortem that can be shared shortly after the fix is finalized.

3 Likes

Thanks @cylon. For transparency, could you share a preliminary list of the aforementioned protocols?

Currently, only Index Coop as mentioned in the Compound discord. I’ve confirmed that a few others are not at risk and will take the next few days to see if anyone else comes forward with concerns.

2 Likes