Building an Oracle
To build a price oracle on Capricorn, you must first understand the requirements for your use case. Once you understand the kind of price average you require, it is a matter of storing the cumulative price variable from the pair as often as necessary, and computing the average price using two or more observations of the cumulative price variables.
To understand your requirements, you should first research the answer to the following questions:
- Is data freshness important? I.e.: must the price average include the current price?
- Are recent prices more important than historical prices? I.e.: is the current price given more weight than historical prices?
In the case where data freshness is not important and recent prices are weighted equally with historical prices, it is enough to store the cumulative price once per period (e.g. once per 24 hours.)
Computing the average price over these data points gives you 'fixed windows', which can be updated after the lapse of each period.
This example does not limit the maximum size of the fixed window, i.e. it only requires that the window size is greater than 1 period (e.g. 24 hours).
In the case where data freshness is important, you can use a sliding window in which the cumulative price variable is measured more often than once per period.
There are at least two kinds of moving averages that you can compute using the Capricorn cumulative price variable.
Simple moving averages give equal weight to each price measurement. We have built an example of a sliding window oracle here.
Exponential moving averages give more weight to the most recent price measurements. We do not yet have an example written for this type of oracle.
You may wish to use exponential moving averages where recent prices are more important than historical prices, e.g. in case of liquidations. However, note that putting more weight on recent prices makes the oracle cheaper to manipulate than weighting all price measurements equally.
To compute the average price given two cumulative price observations, take the difference between the cumulative price at the beginning and end of the period, and divide by the elapsed time between them in seconds. This will produce a fixed point unsigned Q112x112 number that represents the price of one asset relative to the other. This number is represented as a uint224 where the upper 112 bits represent the integer amount, and the lower 112 bits represent the fractional amount.
Pairs contain both price0CumulativeLast and price1CumulativeLast, which are ratios of reserves of token1/token0 and token0/token1 respectively. I.e. the price of token0 is expressed in terms of token1/token0, while the price of token1 is expressed in terms of token0/token1.
If you wish to compute the average price between a historical price cumulative observation and the current cumulative price, you should use the cumulative price values from the current block. If the cumulative price has not been updated in the current block, e.g. because there has not been any liquidity event (mint/burn/swap) on the pair in the current block, you can compute the cumulative price counterfactually.
The Capricorn-Pair cumulative price variables are designed to eventually overflow, i.e. price0CumulativeLast and price1CumulativeLast and blockTimestampLast will overflow through 0.