Hey everyone, this post is a follow up on the recent developer call we had describing the proposal to switch the current oracle mechanism to Chainlink price feeds combined with a Uniswap anchor acting as a safety net.
This proposal is based on the feedback of Compound community members. Today, I want to describe the implementation we put in place and ensure everyone understands the workflow this new oracle system will have if voted in. The last part of this post will also contain links to testing contracts we’ve deployed on mainnet.
Current Mechanism
First off, I would like to give a quick description of the current system so we all have shared context. The UniswapAnchoredView
(UAV) is currently configured with multiple markets, each containing the name, cToken
, underlying token, Uniswap V2 pool data and conversion data. Prices are posted to it via a configured reporter
. If it is believed that the reporter
account has been compromised (private keys stolen, etc.), there is a function called invalidateReporter()
, which can be called by the reporter
which permanently switches over to the Uniswap V2 TWAP prices.
Signed prices are posted to the UniswapAnchoredView
regularly, by the reporter
. During this transaction, the following steps occur:
- Signatures are verified
- For each posted price:
- Update the Uniswap V2 TWAP window if due
- Update the anchor price
- If posted price is within threshold of anchor price: store the posted price
- Else, if posted price is outside of the threshold: store the anchor price
New Community Proposal
UniswapAnchoredView Modifications
The community indicated their desire to switch over to Chainlink production price feeds in place of the current reporter. They also indicated a desire to keep a Uniswap Anchor as a safety net to remain in place. Hence, our current proposal modifies the existing architecture whilst maintaining the same anchor mechanism. This architecture is very much optimized to give compound users low gas costs.
The key differences are:
- Prices will now be pushed from production aggregators, each responsible for a single asset. They call the
validate()
function, which replaces thepostPrices()
function. This change is so that the UAV conforms to theAggregatorValidatorInterface
, which production aggregators are compatible with. - The Compound community multisig will be able to failover single markets, on a per-market basis. In this scenario (as in the current architecture) the Uniswap V2 TWAP price is used as the failover. Function:
activateFailover(bytes32 symbolHash)
- The community can also reverse this failover. Function:
deactivateFailover(bytes32 symbolHash)
Price Feeds
Usually, contracts that consume price feeds read the data from an AggregatorProxy
contract, which itself reads the price from an underlying OffchainAggregator
contract. This proxy pattern is used so that the underlying aggregator can be upgraded without disruption of service for contracts that consume prices from the proxy. More information on this model in the docs: https://docs.chain.link/docs/architecture-decentralized-model/#contracts-overview
UniswapAnchoredView
's anchor mechanism relies on prices being pushed to it, not read, so reading from aggregator contracts (as shown in our initial proposal: https://github.com/compound-finance/compound-protocol/pull/105) is not feasible. However, OffchainAggregator
contracts enable a validator
to be set. Every price transmission that the aggregator receives from nodes is passed to the validator
via the validate()
function. This is the entry point for the modified UAV. Upon deployment, production aggregators will have their validator
set to point to the UAV.
Adding new markets
Given how UniswapAnchoredView
is written, any changes (like adding a new market) requires a fresh deployment with a new configuration, which then goes through governance to be set as the oracle
in the Comptroller.
An example: If the community deploys a new UAV, the OffchainAggregator
of each asset would need to have its validator changed to push prices to the new UAV. Changing the validator would mean that the old UAV no longer receives prices from the aggregator. A transition period exists where both UAVs need to have prices pushed to them so that:
- Service is not disrupted on the existing UAV.
- The new UAV can be tested and have its prices verified on-chain before being accepted by governance.
To solve this challenge, we have created the ValidatorProxy
contract to sit in between each OffchainAggregator
and the UniswapAnchoredView
. For the most part, this contract just forwards validate()
calls from the aggregator to the UAV. However, It also supports a “proposed” validator (a second UAV), which it also pushes prices to when it is set.
Simple Architecture
This image describes 4 asset prices being pushed to the UniswapAnchoredView. It does not include the anchor mechanism that is performed during the validate() call on the UAV.
Uniswap Anchor Flow
This anchor mechanism has not changed in our proposal. Here is a flowchart (might need to zoom in on this one) representation of the BAT/USD price being posted to it via the validate() function:
Mainnet Tests
To test the modifications to the UAV and the overall architecture, we deployed the contracts to mainnet and tested them using a node network providing prices for the UNI/USD market over the course of roughly 2 days. Here are the addresses:
-
UNI / USD Aggregator:
0x6235b643251401F2c1bf8cE901F09aC84fbC0FCF
-
ValidatorProxy:
0xE2093Baf575b3f71eA2a4f15aC70E0bbEeca0b36
-
UniswapAnchoredView:
0x52DF1FA8C48efeD68395602EEfAc213C20b02301
-
Proposed UniswapAnchoredView:
0xdd7294BBF8cB758B132AA3855BA1A16bdc64Acf9
Code
UniswapAnchoredView
Chainlink has forked the Compound open-oracle repo to make the proposed changes to the UniswapAnchoredView
. This PR is being used for internal reviews and can be seen here: https://github.com/smartcontractkit/open-oracle/pull/1.
Once this has been audited in the coming few days, Chainlink will open a pull request from our fork to the Compound open-oracle repo.
ValidatorProxy
Initial PR: https://github.com/smartcontractkit/chainlink/pull/4265
Second PR: https://github.com/smartcontractkit/chainlink/pull/4301
Aggregators
Chainlink aggregator code can be found in the libocr repo: https://github.com/smartcontractkit/libocr
Conclusion
This should be it with all the details for this proposal, if you have any questions please reach out here, I’ll be happy to answer it. We’re looking forward for a long term collaboration with the Compound community and making sure we can help build out the best oracle system available for Compound to keep being a leader in the money market space through the use of secure and accurate oracles. As Uniswap v3 gains momentum we will be looking to work with the community in upgrading to its oracles as a new safety net mechanism and have already started coordinating this process with their team.