Skip to main content

Using HTTPS Outcalls to Fetch Exchange Rates

Exchange Rate sample dapp overview

The HTTPS outcalls feature provides a way for canisters to directly interact with web services that exist outside of the Internet Computer in the Web 2.0 world. The Exchange Rate sample dapp pulls ICP/USDC exchange rates from a single provider – Coinbase. The sample dapp provides an example of using the HTTPS outcalls API implemented in Rust and Motoko.

What does the sample dapp do

TL;DR the sample dapp is just an unbounded time series cache.

There are two parts to the sample dapp:

  1. the frontend UI canister exchange_rate_assets, which includes a time range picker and a rate chart and
  2. the backend provider canister exchange_rate that performs HTTPS outcalls, queues jobs, transforms responses, etc.

The backend canister receives an update request corresponding to the time range specified by the user at the frontend. The time range is converted into time buckets and the buckets are queued for retrival. Asynchronously at every few Internet Computer heartbeats, the backend canister makes a Coinbase API request for a single queued time bucket. Each request to Coinbase pulls at most 200 data points from Coinbase, which is less than the limit of 300 which Coinbase has. The dapp uses timeseries granularity of 60 seconds, so each HTTPS request to Coinbase covers a time bucket of at most 200 minutes. The fetched data points are then put into a global timestamp-to-rate hashmap.

If the time range the user requested is longer than a couple of years, the size of data to be returned by the backend exchange_rate canister could exceed the existing limits of the system. As a result, the exchange_rate canister may return data points with increased granularity in order to fit into the limits and cover the full requested range.

Exchange Rate sample dapp architecture

Architecture overview diagram of the Exchange Rate dapp

How to use the sample dapp

Users should be able to interact only with the frontend UI canister by selecting the start time and the end time with the datetime pickers.

The returned rates may not exactly match the user's time selection. (There could be gaps between data points or there could be a smaller range being returned). The reason is that to respect rate limiting on the remote service, we fetch data from the remote service once every few IC heartbeats. Consequently, pulling all requested rates can be a relatively long asynchronous operation.

All the previously-pulled rates are stored in memory. As the user submits their requests, the rates that are already available are returned, while the ones that are not yet available will be fetched eventually. If the user spots gaps between requested rates and returned rates, the user needs to wait for some time and retry the request, and likely the full set of rates will be available then.

Cost analysis of the exchange_rate canister

There are 2 major factors affecting the pricing when it comes to the HTTPS outcalls feature:

  • The number of requests
  • The size of each request and response

If we need to fetch a longer period of rates then the number of external HTTPS outcalls is inversely proportional to the body size of each response. This sample dapp minimizes the total number of HTTPS outcalls at the cost of bigger response bodies.

Building and deploying the sample dapp locally

Here are implementations in Rust and Motoko. Please refer to the README.md file in each directory for instrutions on building and local deployment.