Skip to content

Use API3 To Request Off-Chain Data on Moonbeam

Introduction

API3 is a decentralized solution for delivering traditional API services to smart contract platforms in an easily accessible and scalable way. It is governed by a Decentralized Autonomous Organization (DAO), known as the API3 DAO. API3 enables developers to access off-chain resources from within their smart contracts without worrying about security implications. API3 makes this possible through Airnodes, which are first-party oracles, and on-chain data feeds sourced from these oracles.

Developers can use Airnode to request off-chain data inside their smart contracts on Moonbeam networks. An Airnode is a first-party oracle that pushes off-chain API data to your on-chain contract. Airnode lets API providers easily run their own first-party oracle nodes. That way, they can provide data to any on-chain dApp that's interested in their services, all without an intermediary.

An on-chain smart contract makes a request in the RRP (Request Response Protocol) contract (AirnodeRrpV0.sol) that adds the request to the event logs. The Airnode then accesses the event logs, fetches the API data and performs a callback to the requester with the requested data.

API3 Airnode

The information presented herein is for informational purposes only and has been provided by third parties. Moonbeam does not endorse any project listed and described on the Moonbeam docs website (https://docs.moonbeam.network/).

Request Off-Chain Data From an Airnode

Requesting off-chain data essentially involves triggering an Airnode and getting its response through your smart contract. The smart contract in this case would be the requester contract, which will make a request to the desired off-chain Airnode and then capture its response.

The requester calling an Airnode primarily focuses on two tasks:

  • Make the request
  • Accept and decode the response

API3 Airnode

Here is an example of a basic requester contract to request data from an Airnode:

pragma solidity 0.8.9;

import "@api3/airnode-protocol/contracts/rrp/requesters/RrpRequesterV0.sol";

// A Requester that will return the requested data by calling the specified airnode.
// Make sure you specify the right _rrpAddress for your chain.

contract Requester is RrpRequesterV0 {
    mapping(bytes32 => bool) public incomingFulfillments;
    mapping(bytes32 => int256) public fulfilledData;

    constructor(address _rrpAddress) RrpRequesterV0(_rrpAddress) {}

    /**
     * The main makeRequest function that will trigger the Airnode request
     * airnode: Airnode address
     * endpointId: The endpoint ID for the specific endpoint
     * sponsor: The requester contract itself (in this case)
     * sponsorWallet: The wallet that will make the actual request (needs to be funded)
     * parameters: encoded API parameters
     */
    function makeRequest(
        address airnode,
        bytes32 endpointId,
        address sponsor,
        address sponsorWallet,
        bytes calldata parameters

    ) external {
        bytes32 requestId = airnodeRrp.makeFullRequest(
            airnode,
            endpointId,
            sponsor,
            sponsorWallet,
            address(this),
            this.fulfill.selector,
            parameters
        );
        incomingFulfillments[requestId] = true;
    }

    // The callback function with the requested data
    function fulfill(bytes32 requestId, bytes calldata data)
        external
        onlyAirnodeRrp
    {
        require(incomingFulfillments[requestId], "No such request made");
        delete incomingFulfillments[requestId];
        int256 decodedData = abi.decode(data, (int256));
        fulfilledData[requestId] = decodedData;
    }
}

You can also try deploying the example contract on Remix.

Contract Addresses

The _rrpAddress is the main airnodeRrpAddress. The RRP Contracts have already been deployed on-chain. The addresses for the _rrpcAddress on Moonbeam networks are as follows:

Contract Addresses
AirnodeRrpV0 0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd
Contract Addresses
AirnodeRrpV0 0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd
Contract Addresses
AirnodeRrpV0 0xa0AD79D995DdeeB18a14eAef56A549A04e3Aa1Bd

Request Parameters

The makeRequest() function expects the following parameters to make a valid request:

Response Parameters

The callback to the requester contract contains two parameters:

  • requestId - first acquired when making the request and passed here as a reference to identify the request for which the response is intended.
  • data - in case of a successful response, this is the requested data which has been encoded and contains a timestamp in addition to other response data. Decode it using the decode() function from the abi object

Note

Sponsors should not fund a sponsorWallet with more then they can trust the Airnode with, as the Airnode controls the private key to the sponsorWallet. The deployer of such Airnode undertakes no custody obligations, and the risk of loss or misuse of any excess funds sent to the sponsorWallet remains with the sponsor.

Using dAPIs - API3 Datafeeds

dAPIs are continuously updated streams of off-chain data, such as the latest cryptocurrency, stock, and commodity prices. They can power various decentralized applications such as DeFi lending, synthetic assets, stablecoins, derivatives, NFTs, and more.

The data feeds are continuously updated by first-party oracles using signed data. DApp owners can read the on-chain value of any dAPI in realtime.

Due to being composed of first-party data feeds, dAPIs offer security, transparency, cost-efficiency, and scalability in a turn-key package.

API3 Remix deploy

To learn more about how dAPIs work, please refer to API3's documentation*.

Types of dAPIs

There are two types of dAPIs: self-funded and managed. Managed dAPIs are only available on MainNets, and self-funded dAPIs are available on both MainNets and TestNets. The process to read from a dAPI proxy remains the same for both self-funded and managed dAPIs.

Self-funded dAPIs

Self-funded dAPIs are single-source data feeds that are funded by the users with their own funds. They offer developers the opportunity to experience data feeds with minimal up-front commitment, providing a low-risk option prior to using managed dAPIs.

With self-funded dAPIs, you can fund the dAPI with your own funds. The amount of gas you supply will determine how long your dAPI will be available for use. If you run out of gas, you can fund the dAPI again to keep it available for use.

You can read more about self-funded dAPIs on API3's documentation site.

Managed dAPIs

Managed dAPIs are sourced directly from multiple first-party data providers running an Airnode and aggregated using Airnode's signed data using a median function. The gas costs and availability of managed dAPIs are managed by the API3 DAO.

You can read more about managed dAPIs on API3's documentation site.

Access Self-Funded dAPIs

The process for accessing self-funded data feeds is as follows:

  1. Explore the API3 Market and select a dAPI
  2. Fund a sponsor wallet
  3. Deploy a proxy contract to acess the data feed
  4. Read data from the dAPI

API3 Remix deploy

Select a dAPI From the API3 Market

The API3 Market enables users to connect to a dAPI and access the associated data feed services. It provides a list of all of the dAPIs available across multiple chains including testnets. You can filter the list by chains and data providers. You can also search for a specific dAPI by name. You can click on a dAPI to land on the details page where you can find more information about the dAPI.

You can then decide if you want to use self-funded or managed dAPIs.

API3 Dapi Page

Fund a Sponsor Wallet

Once you have selected your dAPI, you can activate it by using the API3 Market to send funds (DEV, MOVR, or GLMR) to the sponsorWallet. Make sure your:

  • Wallet is connected to the Market and is the same network as the dAPI you are funding
  • The balance of your wallet should be greater than the amount you are sending to the sponsorWallet

To fund the dAPI, you need to click on the Fund Gas button. Depending upon if a proxy contract is already deployed, you will see a different UI.

API3 Remix deploy

Use the gas estimator to select how much gas is needed by the dAPI. Click on Send DEV to send the entered amount to the sponsor wallet of the respective dAPI.

API3 Remix deploy

Once the transaction is broadcasted & confirmed on the blockchain a transaction confirmation screen will appear.

Deploy a Proxy Contract to Access The dAPI

Smart contracts can interact and read values from contracts that are already deployed on the blockchain. By deploying a proxy contract via the API3 Market, a dApp can interact and read values from a dAPI like ETH/USD.

Note

If a proxy is already deployed for a self-funded dAPI, the dApp can read the dAPI without having to deploy a proxy contract. They do this by using the address of the already deployed proxy contract which will be visible on the API3 Market.

If you are deploying a proxy contract during the funding process, clicking on the Get proxy button will initiate a transaction to your wallet that will deploy a proxy contract.

API3 Remix deploy

Once the transaction is broadcasted & confirmed on the blockchain, the proxy contract address will be shown on the UI.

Access Managed dAPIs

If you are trying to access managed dAPIs, once you have selected your dAPI, you will then be presented with the option to choose from either Managed or Self-funded. Select Managed dAPIs.

Managed dAPIs give you the option to configure the dAPI's devation threshold and heartbeat. For managed dAPIs, you will have the following options to choose from:

Deviation Heartbeat
0.25% 2 minutes
0.25% 24 hours
0.5% 24 hours
1% 24 hours

Note

Not all dAPIs support all the configurations. It depends on the asset and chain. Check the API3 Market for more information.

After selecting the required deviation threshold and heartbeat, check the final price, and select Add to Cart. You can add more dAPIs on the same network to your cart. Once you are done, click on Checkout. Make sure you check the order details and the final price on the payment page. Once you are ready, connect your wallet and pay for the order.

After placing the order, you will have to wait for the dAPI to get updated. It usually takes five business days for the dAPI team to update the dAPI for the requested configuration. Once the dAPI is updated, you can start using it in your dApp.

Read From a dAPI

Here's an example of a basic contract that reads from a dAPI:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@api3/contracts/v0.8/interfaces/IProxy.sol";

contract DataFeedReaderExample is Ownable {
    // This contract reads from a single proxy. Your contract can read from multiple proxies.
    address public proxy;

    // Updating the proxy address is a security-critical action. In this example, only
    // the owner is allowed to do so.
    function setProxy(address _proxy) public onlyOwner {
        proxy = _proxy;
    }

    function readDataFeed()
        external
        view
        returns (int224 value, uint256 timestamp)
    {
        (value, timestamp) = IProxy(proxy).read();
        // If you have any assumptions about `value` and `timestamp`, make sure
        // to validate them right after reading from the proxy.
    }
}

The example contract contains two functions:

  • setProxy() - used to set the address of the dAPI Proxy Contract
  • readDataFeed() - a view function that returns the latest price of the set dAPI

Try deploying it on Remix!

You can read more about dAPIs on API3's documentation site.

API3 QRNG

API3 QRNG is a public utility we provide with the courtesy of Australian National University (ANU). It is powered by an Airnode hosted by ANU Quantum Random Numbers, meaning that it is a first-party service. It is served as a public good and is free of charge (apart from the gas costs), and it provides ‘true’ quantum randomness via an easy-to-use solution when requiring RNG on-chain.

To request randomness on-chain, the requester submits a request for a random number to AirnodeRrpV0. The ANU Airnode gathers the request from the AirnodeRrpV0 protocol contract, retrieves the random number off-chain, and sends it back to AirnodeRrpV0. Once received, it performs a callback to the requester with the random number.

Here is an example of a basic QrngRequester that requests a random number:

//SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
import "@api3/airnode-protocol/contracts/rrp/requesters/RrpRequesterV0.sol";

contract RemixQrngExample is RrpRequesterV0 {
    event RequestedUint256(bytes32 indexed requestId);
    event ReceivedUint256(bytes32 indexed requestId, uint256 response);

    address public airnode;
    bytes32 public endpointIdUint256;
    address public sponsorWallet;
    mapping(bytes32 => bool) public waitingFulfillment;

    // These are for Remix demonstration purposes, their use is not practical.
    struct LatestRequest { 
      bytes32 requestId;
      uint256 randomNumber;
    }
    LatestRequest public latestRequest;

    constructor(address _airnodeRrp) RrpRequesterV0(_airnodeRrp) {}

    // Normally, this function should be protected, as in:
    // require(msg.sender == owner, "Sender not owner");
    function setRequestParameters(
        address _airnode,
        bytes32 _endpointIdUint256,
        address _sponsorWallet
    ) external {
        airnode = _airnode;
        endpointIdUint256 = _endpointIdUint256;
        sponsorWallet = _sponsorWallet;
    }

    function makeRequestUint256() external {
        bytes32 requestId = airnodeRrp.makeFullRequest(
            airnode,
            endpointIdUint256,
            address(this),
            sponsorWallet,
            address(this),
            this.fulfillUint256.selector,
            ""
        );
        waitingFulfillment[requestId] = true;
        latestRequest.requestId = requestId;
        latestRequest.randomNumber = 0;
        emit RequestedUint256(requestId);
    }

    function fulfillUint256(bytes32 requestId, bytes calldata data)
        external
        onlyAirnodeRrp
    {
        require(
            waitingFulfillment[requestId],
            "Request ID not known"
        );
        waitingFulfillment[requestId] = false;
        uint256 qrngUint256 = abi.decode(data, (uint256));
        // Do what you want with `qrngUint256` here...
        latestRequest.randomNumber = qrngUint256;
        emit ReceivedUint256(requestId, qrngUint256);
    }
}

The example contract contains these three functions:

  • setRequestParameters - accepts and sets the following three request parameters:
    • airnode - address of an Airnode that will be called to retrieve QRNG data
    • endpointIdUint256 - the endpoint ID of the Airnode
    • sponsorWallet - the address of the sponsor wallet
  • makeRequestUint256 - calls the airnodeRrp.makeFullRequest() function of the AirnodeRrpV0.sol protocol contract which adds the request to its storage and returns a requestId
  • fulfillUint256 - accepts and decodes the requested random number

Note

You can get the airnode address and endpointIdUint256 from the QRNG Providers section below.

Try deploying it on Remix!

QRNG Airnode and Endpoint Providers

You can try QRNG using the following Airnodes and endpoints:

Variable Value
ANU QRNG Airnode Address 0x9d3C147cA16DB954873A498e0af5852AB39139f2
ANU QRNG Airnode xpub xpub6DXSDTZBd4aPVXnv6Q3SmnGUweFv6j24SK77W4qrSFuhGgi666awUiXakjXruUSCDQhhctVG7AQt67gMdaRAsDnDXv23bBRKsMWvRzo6kbf
ANU Endpoint ID (uint256) 0xfb6d017bb87991b7495f563db3c8cf59ff87b09781947bb1e417006ad7f55a78
ANU Endpoint ID (uint256[]) 0x27cc2713e7f968e4e86ed274a051a5c8aaee9cca66946f23af6f29ecea9704c3
Variable Value
ANU QRNG Airnode Address 0x9d3C147cA16DB954873A498e0af5852AB39139f2
ANU QRNG Airnode xpub xpub6DXSDTZBd4aPVXnv6Q3SmnGUweFv6j24SK77W4qrSFuhGgi666awUiXakjXruUSCDQhhctVG7AQt67gMdaRAsDnDXv23bBRKsMWvRzo6kbf
ANU Endpoint ID (uint256) 0xfb6d017bb87991b7495f563db3c8cf59ff87b09781947bb1e417006ad7f55a78
ANU Endpoint ID (uint256[]) 0x27cc2713e7f968e4e86ed274a051a5c8aaee9cca66946f23af6f29ecea9704c3
Variable Value
Nodary QRNG Airnode Address 0x6238772544f029ecaBfDED4300f13A3c4FE84E1D
Nodary QRNG Airnode xpub xpub6CuDdF9zdWTRuGybJPuZUGnU4suZowMmgu15bjFZT2o6PUtk4Lo78KGJUGBobz3pPKRaN9sLxzj21CMe6StP3zUsd8tWEJPgZBesYBMY7Wo
Nodary Endpoint ID (uint256) 0xfb6d017bb87991b7495f563db3c8cf59ff87b09781947bb1e417006ad7f55a78
Nodary Endpoint ID (uint256[]) 0x27cc2713e7f968e4e86ed274a051a5c8aaee9cca66946f23af6f29ecea9704c3

For a complete list of all the QRNG Providers, please refer to API3's documentation.

Additional Resources

Here are some additional developer resources:

The information presented herein has been provided by third parties and is made available solely for general information purposes. Moonbeam does not endorse any project listed and described on the Moonbeam Doc Website (https://docs.moonbeam.network/). Moonbeam Foundation does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Moonbeam Foundation disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Moonbeam Foundation. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Moonbeam Foundation has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Moonbeam Foundation harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
Last update: January 25, 2024
| Created: January 3, 2023