Skip to content

Chainlink Oracle

Chainlink Moonbeam Banner

Introduction

Developers can now use Chainlink's decentralized Oracle network to fetch data in the Moonbase Alpha TestNet. This tutorial goes through two different ways of using Chainlink Oracles:

  • Basic Request Model, where the end-user sends a request to an Oracle provider, which fetches the data through an API, and fulfils the request storing this data on-chain
  • Price Feeds, where data is continuously updated by Oracle operators in a smart contract so that other smart contracts can fetch it

Basic Request Model

Before we go into fetching the data itself, it is important to understand the basics of the "basic request model."

An Oracle node has a set of job IDs, where each corresponds to a task that can be requested by a user, for example, fetch a price feed. To do so, the user needs to send a request through a contract, we'll name it the Client contract, passing in the following information:

  • Oracle address: address of the contract deployed by the Oracle node
  • Job ID: task to be executed
  • Payment: payment in LINK tokens that the Oracle will receive for fulfiling the request

This request actually sends a transferAndCall to the LINK token contract, which handles the payment and relays the request to the Oracle contract. Here, an event is emited with the request, which is picked up by the Oracle node. Next, the node fetches the necessary data and executes the fulfilOracleRequest function, which executes a callback that stores the requested information in the Client contract. The following diagram explains this workflow.

Basic Request Diagram

The Client Contract

The Client contract is the element that starts the communication with the Oracle by sending a request. As shown in the diagram, it calls the transferAndCall method from the LINK token contract, but there is more processing that is needed to track the request to the Oracle. For this example, you can use the code in this file, and deploy it on Remix to try it out. Let's look at the core functions of the contract:

  • constructor: runs when the contract is deployed. It sets the address of the LINK token and the owner of the contract
  • requestPrice: needs the Oracle contract address, the job ID, and the payment (in LINK) tokens to the fulfiller of the request. Builds the new request that is sent using the sendChainlinkRequestTo function from the ChainlinkClient.sol import
  • fulfill: callback used by the Oracle node to fulfill the request by storing the queried information in the contract
pragma solidity ^0.6.6;

import "https://github.com/smartcontractkit/chainlink/evm-contracts/src/v0.6/ChainlinkClient.sol";

contract Client is ChainlinkClient {
  //... there is mode code here

  constructor(address _link) public {
    // Set the address for the LINK token for the network
    setChainlinkToken(_link);
    owner = msg.sender;
  }

  function requestPrice(address _oracle, string memory _jobId, uint256 _payment)
    public
    onlyOwner
  {
    // newRequest takes a JobID, a callback address, and callback function as input
    Chainlink.Request memory req = buildChainlinkRequest(stringToBytes32(_jobId), address(this), this.fulfill.selector);
    // Sends the request with the amount of payment specified to the oracle
    sendChainlinkRequestTo(_oracle, req, _payment);
  }

  function fulfill(bytes32 _requestId, uint256 _price)
    public
    recordChainlinkFulfillment(_requestId)
  {
    currentPrice = _price;
  }

  //... there is more code here
}

Note that the Client contract must have a LINK tokens balance to be able to pay for this request. However, if you deploy your setup, you can set the LINK value to 0 in your ChainlinkClient.sol contract, but you still need to have the LINK token contract deployed.

Try it on Moonbase Alpha

If you want to skip the hurdles of deploying all contracts, setting up your Oracle node, creating job IDs, and so on, we've got you covered.

A custom Client contract on Moonbase Alpha that makes all requests to our Oracle contract, with a 0 LINK token payment, is available. These requests are fulfilled by an Oracle node that we are running. You can try it out with the following interface contract and the custom Client contract deployed at 0xe88ec866D05e637074B5a0D0d931f292d7871613:

pragma solidity ^0.6.6;

/**
 * @title Simple Interface to interact with Universal Client Contract
 * @notice Client Address 0xe88ec866D05e637074B5a0D0d931f292d7871613
 */
interface ChainlinkInterface {

  /**
   * @notice Creates a Chainlink request with the job specification ID,
   * @notice and sends it to the Oracle.
   * @notice _oracle The address of the Oracle contract fixed top
   * @notice _payment For this example the PAYMENT is set to zero
   * @param _jobId The job spec ID that we want to call in string format
   */
    function requestPrice(string calldata _jobId) external;

    function currentPrice() external view returns (uint);

}

This provides two functions. requestPrice() only needs the job ID of the data you want to query. This function starts the chain of events explained before. currentPrice() is a view function that returns the latest price stored in the contract.

Currently, the Oracle node has a set of Job IDs for different price datas for the following pairs:

Base/Quote Job ID Reference
BTC to USD 82ceee2897824a0e8b014ed4ed2ab31e
ETH to USD 60160cdd0e10489681967e9d7ef4c927
DOT to USD 6f6371a780324b90aaf195a0d39c723c
KSM to USD 30a1686f657249f4b6ab01e384b2beaa
AAVE to USD 541b8f7db7374d78b38285ef1b8bfacc
ALGO to USD cdb48696e2314133a1dc8ea27922dd24
BAND to USD 6b0983e0cb6d4aca908b615302a9d672
LINK to USD aad8dbdb0c1840ab905728d85117b681
SUSHI to USD b4b07d0fc218455caaff2223a05ec208
UNI to USD 22b567acabdb419abe8136a2bab6ade8

Let's go ahead and use the interface contract with the BTC to USD Job ID in Remix.

After creating the file and compiling the contract, head to the "Deploy and Run Transactions" tab, enter the Client contract address, and click on "At Address." Make sure you have set the "Environment" to "Injected Web3" so you are connected to Moonbase Alpha. This will create an instance of the Client contract that you can interact with. Use the function requestPrice() to query the data of the corresponding Job ID. Once the transaction is confirmed, we have to wait until the whole process explained before occurs. We can check the price using the view function currentPrice().

Chainlink Basic Request on Moonbase Alpha

If there is any specific pair you want us to include, feel free to reach out to us through our Discord server.

Run your Client Contract

If you want to run your Client contract but use our Oracle node, you can do so with the following information:

Contract Type Address
Oracle Contract 0x1d693d883BeAeE16edD0D7588D6a9f7E1967E798
LINK Token 0xa36085F69e2889c224210F603D836748e7dC0088

Remember that the LINK token payment is set to zero.

Other Requests

Chainlink's Oracles can tentatively provide many different types of data feeds with the use of external adapters. However, for simplicity, our Oracle node is configured to deliver only price feeds.

If you are interested in running your own Oracle node in Moonbeam, please visit this guide. Also, we recommend going through Chainlink's documentation site.

Price Feeds

Before we go into fetching the data itself, it is important to understand the basics of price feeds.

In a standard configuration, each price feed is updated by a decentralized Oracle network. Each Oracle node is rewarded for publishing the price data to the Aggregator contract. However, the information is only updated if a minimum number of responses from Oracle nodes are received (during an aggregation round).

The end-user can retrieve price feeds with read-only operations via a Consumer contract, referencing the correct Aggregator interface (Proxy contract). The Proxy acts as a middleware to provide the Consumer with the most up-to-date Aggregator for a particular price feed.

Price Feed Diagram

Try it on Moonbase Alpha

If you want to skip the hurdles of deploying all the contracts, setting up your Oracle node, creating job IDs, and so on, we've got you covered.

We've deployed all the necessary contracts on Moonbase Alpha to simplify the process of requesting price feeds. In our current configuration, we are running only one Oracle node that fetches the price from a single API source. Price data is checked every minute and updated in the smart contracts every hour unless there is a price deviation of 1 %.

The data lives in a series of smart contracts (one per price feed) and can be fetched with the following interface:

pragma solidity ^0.6.6;

interface ConsumerV3Interface {
    /**
     * Returns the latest price
     */
    function getLatestPrice() external view returns (int);

    /**
     * Returns the decimals to offset on the getLatestPrice call
     */
    function decimals() external view returns (uint8);

    /**
     * Returns the description of the underlying price feed aggregator
     */
    function description() external view returns (string memory);
}

This provides three functions. getLatestPrice() will read the latest price data available in the Aggregator contract via the Proxy. We've added the decimals() function, which returns the number of decimals of the data and the description() function, which returns a brief description of the price feed available in the Aggregator contract being queried.

Currently, there is an Consumer contract for the the following price pairs:

Base/Quote Consumer Contract
BTC to USD 0x86f11CffCB1A86Ecb79643FCa1a3C666a61F84Fd
ETH to USD 0xE33691Ba3cF532D4025cF0f47679eFe430d4A618
DOT to USD 0x235A40b872e543b6238df7Ff55E2D8eCAE80a6bd
KSM to USD 0x9Df2E2179ddb4D9197451946104068e08eD3E49F
AAVE to USD 0xD1e52C81FD72fFc6dA3bF083297E6C37852E93DA
ALGO to USD 0x0183d1C98442510DD7aaB0E2d09863c47FFF4dF1
BAND to USD 0x124A3EE742737BC30307d1F82c5406bf79aBa4d6
LINK to USD 0xC58B34ea686Db2d567835de7AB58fC678b6f186A
SUSHI to USD 0x21B52fFF227cD9F425E817f9E1eaA0eB8cd647e1
UNI to USD 0x5Cd72748F94a8597f563D92687A8D2A5074b10E5

Let's go ahead and use the interface contract to fetch the price feed of BTC to USD using Remix.

After creating the file and compiling the contract, head to the "Deploy and Run Transactions" tab, enter the Consumer contract address corresponding to BTC to USD, and click on "At Address." Make sure you have set the "Environment" to "Injected Web3" so you are connected to Moonbase Alpha.

This will create an instance of the Consumer contract that you can interact with. Use the function getLatestPrice() to query the data of the corresponding price feed.

Chainlink Price Feeds on Moonbase Alpha

Note that to obtain the real price, you must account for the decimals of the price feed, available with the decimals() method.

If there is any specific pair you want us to include, feel free to reach out to us through our Discord server.