Oracles bring off-chain information on-chain, making that information accessible to the Smart Contracts. The Celo Protocol contains a Smart Contract called "SortedOracles". This Smart Contract receives price reports from Oracles, keeps track of the median value of these price reports, and references these price reports against a list of addresses that are permitted to provide price reports. One significant function of Oracles on Celo is supporting the stability mechanism. Oracles provide the price of CELO in the fiat currency to which a stable value asset is linked, such as cUSD (stable value asset) to the fiat currency to which it is linked (US Dollar).
This Oracle application does the off-chain work of determining the current exchange rate of a given currency pair. It does this by aggregating data across multiple exchanges where these currencies are traded, and reporting the results of this processing to the aforementioned SortedOracles contract.
Before running the Oracle, you'll need to configure it. Configuration is done with Environment Variables. See the Configuration Guide for the full list of options.
To run using the defaults, the only thing you will need to set up the Oracle is the oracle's identity. This means you must ensure that the Oracle has access to a private key for an address that is allowed to act as an Oracle.
There are two ways to do this:
- When using an HSM (Azure or AWS)
This method assumes that you're using an HSM (Hardware Security Module) on Azure or AWS, and have already generated a private key and address in that setup.
Set the relevant EnvVars:
ADDRESS
: the address associated with HSM private key
AZURE_KEY_VAULT_NAME
: if using Azure, the name of the Azure Key Vault. Omit if using AWS. - Reading a private key from a file (this is not recommended in production)
Make sure the private key is accessible to the running oracle application, and set the following EnvVar:
PRIVATE_KEY_PATH
: path to the file
Dependencies must be installed:
pnpm
Before running or testing, the TypeScript must be re-built:
pnpm build
Bunyan is used for structured logging. To start the oracle with JSON formatted logs (how it should be run in production), run:
pnpm start
For a friendlier developer experience, the bunayn CLI can be used to output prettier logs:
pnpm start | npx bunyan
Docker images are pushed to a public container registry upon every release. The latest price sources and data aggregation parameters can be found as helm charts in the celo monorepo.
The recommended configuration at the moment is 6787997.
Each ExchangeAdapter is responsible for querying information from a specific exchange's API, and transforming the response into the standard format expected by ExchangePriceSource.
Currently supported exchanges are: Binance, Bittrex, Coinbase, and OKCoin.
PriceSource is an interface representing an entity capable of fetching a price and an associated weight.
Currently the only implemented price source is ExchangePriceSource which calculates an implied rate from a sequence of pairs, where each pair is a symbol traded on an exchange.
The DataAggregator orchestrates the collection of data via a set of PriceSources. Using this collected data, it calculates the price for the current moment. If using Ticker data, it takes a volume-weighted mean across all exchanges.
This component is also responsible for validating the data, and determining whether there is enough certainty in the data in order to calculate anything.
The Reporter takes the current price determined by the DataAggregator and reports it to the SortedOracles contract on a regular schedule. The ideal reporting schedule is one which results in a set reports from all participating oracles, spread out evenly over a period of time defined by the expiration period. For example, if the maximum age of a report is 5 minutes and there are 10 participating oracles, every 30 seconds, an oracle should send a report.
The MetricCollector collects information from a running oracle application instance. Its purpose is to provide insight into the health and behavior of an Oracle.
If extreme market volatility is detected, the “circuit breaker” will shut down the Oracle. The current implementation assumes that all participating Oracles are operating with a circuit breaker and using the same configuration. The coordinated shutdown of all Oracles prevents the on-chain exchange rate from being updated. Until the circuit breakers are reset, the on-chain exchange rate adjusts dynamically. One-sided trading with the reserve will push the exchange rate towards the current market price, while limiting the effect on the reserve of having a rate that is "wrong".
The concept here: the more exchanges contributing data, the more accurate the final price. The minimum number of exchanges is a configurable threshold. If the number of exchanges with usable data is below this threshold, the Oracle application does not try to calculate the current price and will not report.
Ticker data contains the current bid and ask on that exchange. Bid is the price buyers are willing to pay, and the ask is the price at which sellers are willing to sell. There is generally a gap, or a "spread", between these, and the actual price is somewhere in between. If the spread is small, the Oracle can be relatively certain of the price. If it is large, it may be less certain.
Using this safeguard, the Oracle ignores tickers with a spread that is deemed too large.
The current price calculation is volume-weighted. This means that the price on an exchange with high trading volume has a larger effect on the price calculation than an exchange with lower trading volume.
This configurable threshold allows setting a cap on how much weight any one exchange can have in the calculation.
If the prices from different sources (i.e. exchanges) deviate too much, it suggests there is too much uncertainty in the current market conditions. When a set threshold is exceeded, the Oracle will avoid reporting a new value until the sources are in closer agreement.
Feel free to jump on the Celo 🚂🚋🚋🚋. Improvements and contributions are highly encouraged! 🙏👊
See the contributing guide for details on how to participate.
Not yet ready to contribute but do like the project? Support Celo with a ⭐ or share the love in a