Contracts
Overview
Our smart contracts work by making continuous observations of the current on-chain state of various decentralized exchanges (DEXs). Specifically, our contracts track prices and liquidity levels across various DEXs, then aggregates the data to produce secure and reliable data feeds.
We define three types of contracts to provide secure data feeds:
- Accumulators: At the lowest level, accumulators collect observations from various DEXs.
- Intermediate oracles: Intermediate oracles use data from accumulators to collect, produce, and store derived data such as time-weighted average price and liquidity at a single source.
- Aggregator oracles: Aggregators combine data from multiple sources and reduce them to singular data points.
At a high level, this flow chart explains how the three types of contracts interact:
Components
Accumulators
Accumulators are designed to track changing values such as prices and liquidities, allowing for time-weighted averages to be calculated from two unique accumulations. They also have a dual function of being spot oracles - that is, oracles that provide current values for whatever is being consulted. These spot oracles are more secure than reading straight from the DEX through the use of off-chain validation prior to observations being stored.
Accumulators all extend AbstractAccumulator
, providing functionality to calculate relative changes and to store new observations when the relative change surpasses the defined update threshold.
There are two distinct types of accumulators: price accumulators and liquidity accumulators.
Price accumulators
Price accumulators track prices across various DEXs with each different price accumulator tracking the prices at a specific DEX against a specific quote token. When the price at the DEX changes relative to the accumulator's stored (observed) price by more than the set update threshold, it's the responsibility of an updater bot to call the accumulator's update function to make a new observation.
We noted earlier that consulting accumulators is more secure than directly consulting the DEX. This is because our updater bots provide a price to validate against before storing the observed price. This validation price is the price observed at the DEX as of a few blocks prior and is additionally validated off-chain against the price at Binance. The updater bot submits an update transaction only if the off-chain validation passes. See the updaters page for more information.
If the on-chain price validation passes, the price at the DEX is stored on-chain for later consultation. The DEX price is calculated as follows, depending on the specific DEX.
Liquidity accumulators
Liquidity accumulators track liquidity levels across various DEXs with each different accumulator tracking the liquidity levels at a specific DEX in terms of token and quote token liquidity. When the liquidity at the DEX changes relative to the accumulator's stored (observed) liquidity by more than the set update threshold, it's the responsibility of an updater bot to call the accumulator's update function to make a new observation.
We noted earlier that consulting accumulators is more secure than directly consulting the DEX. This is because our updater bots provide liquidity levels to validate against before storing the observed liquidity. This validation liquidity is the liquidity observed at the DEX as of a few blocks prior. See the updaters page for more information.
If the on-chain liquidity validation passes, the liquidity at the DEX is stored on-chain for later consultation. The DEX liquidity is calculated as follows, depending on the specific DEX.
Intermediate oracles
Intermediate oracles use data from accumulators to collect, produce, and store derived data such as time-weighted average price and liquidity at a single source.
The sole intermediate oracle contract in use is PeriodicAccumulationOracle
. This contract takes a price accumulator, a liquidity accumulator, a quote token, and a period as arguments. Every period
number of seconds, the update
function is called by an updater bot. Upon update, as long as the underlying accumulators are up-to-date, cumulative price and liquidity is taken from the respective accumulators and stored. Using the last cumulative values and the new ones, a time-weighted average price and liquidity levels are calculated and stored for later consultations.
Aggregator oracles
Aggregators combine data from multiple sources and reduce them to singular data points.
The sole aggregator oracle contract in use is AggregatedOracle
. This contract takes a set of underlying (intermediate) oracles, quote token information, a period, and minimum required liquidity values as arguments. Every period
number of seconds, the update
function is called by an updater bot. Upon update, all underlying oracles are updated and then consulted. As long as the required minimum number of valid consultations (currently just one) is met, the price and liquidity from the valid consultations is aggregated and a final price and liquidity levels are stored for later consultation.
An underlying oracle consultation is considered valid if:
- The consultation's observational age is less than the
AggregatedOracle
's period, and - The price and quote token liquidity are not zero, and
- The quote token liquidity is at least the minimum required, and
- The token liquidity value (denominated in the quote token) is at least the minimum required, and
- The ratio of the liquidity value distribution is within the range of 10:1 and 1:10
As long as the number of valid underlying oracle consultations meets the required number (currently just one), a harmonic mean price is calculated, weighted by quote token liquidity. This mean price as well as the summation of token liquidity and quote token liquidity are all stored for later consultation.
The harmonic mean is used as it produces more accurate averages when used with rates. The harmonic mean is weighted by quote token liquidity as prices are more accurate where liquidity is higher (less slippage).
A high level overview of the AggregatedOracle
contract is as follows: