Difference between revisions of "Exchange rate canister"

From Internet Computer Wiki
Jump to: navigation, search
Line 73: Line 73:
 
This additional information can be used to determine the trustworthiness of the received rate, for example by checking the number of rates that went into the computation of the rate and the standard deviation.
 
This additional information can be used to determine the trustworthiness of the received rate, for example by checking the number of rates that went into the computation of the rate and the standard deviation.
 
If the XRC receives largely inconsistent rates from exchanges, it returns an <code>ExchangeRateError::InconsistentRatesReceived</code> itself.
 
If the XRC receives largely inconsistent rates from exchanges, it returns an <code>ExchangeRateError::InconsistentRatesReceived</code> itself.
 +
 +
The ckBTC minter provides the following endpoints:
 +
 +
* <code>get_btc_address</code>: Returns a specific Bitcoin address that the caller can use to obtain ckBTC by sending BTC to this address.
 +
* <code>track_balance</code>: Instructs the ckBTC minter to track a certain Bitcoin address until funds are added, which will trigger the minting of the equivalent amount in ckBTC.
 +
* <code>update_balance</code>: Instructs the ckBTC minter to check the balance of a Bitcoin address and potentially mint ckBTC right away.
 +
* <code>get_withdrawal_account</code>: Returns a specific ckBTC account where the owner must transfer ckBTC before being able to retrieve BTC.
 +
* <code>retrieve_btc</code>: Instructs the ckBTC minter to burn a certain ckBTC amount and send the corresponding BTC amount to a provided Bitcoin address.
 +
* <code>retrieve_btc_status</code>: Returns the status of a previous retrieve_btc call.
 +
* <code>get_events</code>: Returns a set of events at the ckBTC minter.
 +
 +
The endpoints are discussed in more detail in the following.

Revision as of 21:57, 3 February 2023

Overview

The exchange rate canister (XRC) is a canister running on the uzr34 system subnet that provides exchange rates to requesting canisters. A request comprises a base asset, a quote asset, and an optional (UNIX epoch) timestamp. The base and quote asset can be any combination of cryptocurrency and fiat currency assets, for example, BTC/ICP, ICP/USD, or USD/EUR. The timestamp parameter makes it possible to request historic rates. If no timestamp is provided in the request, the rate for the current time is returned.

The XRC constitutes an on-chain oracle for exchange rates, which is particularly useful for DeFi applications but can further add value to any application that requires exchange rate information.

The cycle minting canister of the NNS will make use of the XRC to obtain up-to-date ICP/XDR rates, which it requires for the conversion of ICP to cycles.

Usage

The canister ID of the XRC is uf6dk-hyaaa-aaaaq-qaaaq-cai. A request of the form

type GetExchangeRateRequest = record {
   base_asset: Asset;
   quote_asset: Asset;
   timestamp: opt nat64;
}; 

can be sent to the XRC, which replies with the following result:

type GetExchangeRateResult = variant {
   Ok: ExchangeRate;
   Err: ExchangeRateError;
};

An Asset is a record consisting of a symbol (for example, "ICP") and a class (either Cryptocurrency or FiatCurrency). The full candid file can be found here. The optional timestamp in the request must be a UNIX timestamp in seconds when provided. If no timestamp is provided, the timestamp corresponding to the start of the current minute is used. Note that the granularity for requests is 1 minute, so seconds in a timestamp are ignored.

It is further worth nothing that some exchanges may not always have exchange rates available for the current minute. Depending on the use case, it may be advisable to use the start of the previous minute to increase the chance to get a response based on rates collected from all queried exchanges.

For every request, 10B cycles need to be sent along, otherwise an ExchangeRateError::NotEnoughCycles error is returned. The actual cost of the call depends on two factors, the requested asset types and the state of the internal exchange rate cache, as follows:

  • If the request can be served from the cache, the actual cost is 200M cycles.
  • If both assets are fiat currencies, the cost is 200M cycles as well.
  • If one of the assets is a fiat currency or the cryptocurrency USDT, the cost is 2.6B cycles.
  • If both assets are cryptocurrencies, the cost is 5B cycles.

The remaining cycles are returned to the requesting canister. Note that at least 10M cycles are charged even in case of an error in order to mitigate the risk of a denial-of-service attack.

Technical Details

The following figure depicts the work flow when receiving a request.

Overview of the exchange rate canister work flow (bank icon from flaticon.com).

After receiving a request (step 1), the exchange rate for each cryptocurrency asset in the request with respect to the quote asset USDT is queried (for the timestamp in the request) from all supported exchanges using HTTPS outcalls if this rate is not already cached (step 2). If a rate can be computed based on the query results received from the exchanges, it is inserted in the cache and returned to the requesting canister (step 3). The median rate of all received rates is returned as it is not susceptible to outliers (unlike the average rate).

If a cryptocurrency/cryptocurrency base-quote pair B/Q was requested, the B/Q rate is derived from the queried B/USDT and Q/USDT rates.

The XRC queries daily foreign exchange (forex) rates from forex data providers automatically on a fixed schedule. Furthermore, the XRC queries multiple stablecoin rates automatically to derive the USD/USDT rate as follows. Given SC1/USDT, SC2/USDT, ... rates for a set of stablecoins SC1, SC2, ..., it uses the median of these rates as the USD/USDT rate. This rule is based on the assumption that at least half of the stablecoins in the set keep their peg to USD at any time, in which case the median rate is an adequate estimate for the USD/USDT rate. Given the USD/USDT rate and the forex rates for fiat currencies other than USD, the requested rate can be computed for the case when one or more assets in the request are fiat currencies.

Since more requests to exchanges are required for cryptocurrency/cryptocurrency pairs, more cycles are charged for such requests.

As indicated in the figure above, the response to a successful request contains metadata in addition to the rate. The metadata contains the following fields:

  • decimals: The rate is returned as a scaled 64-bit integer. The scaling factor is 10 to the power of decimals.
  • base_asset_num_received_rates: The number of received rates for the base asset from all queried exchanges.
  • base_asset_num_queried_sources: The number of queried exchanges for the base asset.
  • quote_asset_num_received_rates: The number of received rates for the quote asset from all queried exchanges.
  • quote_asset_num_queried_sources: The number of queried exchanges for the quote asset.
  • standard_deviation: The standard deviation of all received rates for this request. Note that the standard deviation is scaled by the same factor as the rate itself.
  • forex_timestamp: The timestamp of the beginning of the day for which the forex rates were retrieved, if any.

This additional information can be used to determine the trustworthiness of the received rate, for example by checking the number of rates that went into the computation of the rate and the standard deviation. If the XRC receives largely inconsistent rates from exchanges, it returns an ExchangeRateError::InconsistentRatesReceived itself.

The ckBTC minter provides the following endpoints:

  • get_btc_address: Returns a specific Bitcoin address that the caller can use to obtain ckBTC by sending BTC to this address.
  • track_balance: Instructs the ckBTC minter to track a certain Bitcoin address until funds are added, which will trigger the minting of the equivalent amount in ckBTC.
  • update_balance: Instructs the ckBTC minter to check the balance of a Bitcoin address and potentially mint ckBTC right away.
  • get_withdrawal_account: Returns a specific ckBTC account where the owner must transfer ckBTC before being able to retrieve BTC.
  • retrieve_btc: Instructs the ckBTC minter to burn a certain ckBTC amount and send the corresponding BTC amount to a provided Bitcoin address.
  • retrieve_btc_status: Returns the status of a previous retrieve_btc call.
  • get_events: Returns a set of events at the ckBTC minter.

The endpoints are discussed in more detail in the following.