Cookies are used for the best experience on my website.

Accept Cookie Policy

No internet detected

Check your connection and try again.

Logo Image

No match found

Buy a coffee

I launched this blog in 1995. Since then, we have published 1603 articles. It's all free and means a lot of work in my spare time. I enjoy sharing knowledge and experiences with you.

Your support

Have you learned something new by reading, listening, or watching my content? With your help, I can spend enough time to keep publishing great content in the future.

Or, select an option below:

A small slice of my data processing time each month

It's ongoing work running this site and what's really great is ongoing support. Here's a sense of what goes into this site: research topics for discussion. Manage the Tech stuff: website, SEO, graphics, email, back-end servers, DNS routing, edge servers. Create advertisements and load the campaigns in Google Ads. Manage the social media forums (Facebook, Reddit, Twitter). Write updates to the blog. Keep GitHub up-to-date.

$4.50 — A large cappuccino at my local

Things just work better with coffee! I like to take the kids to school then grab a cappuccino from my local on the way home before beginning the things that take mental energy.

$8.99 — A month of Netflix for some quiet nights in

A lot of the work on this happens after hours when I should be relaxing on the couch. Help me make it so and I promise to keep off the devices for a bit!

$11.50 — Fund a month of email delivery

This site sends out thousands of emails every month. For that volume and to ensure deliverability, I need to pay MailChimp.

$20 — Pay for one month of AWS storage fees

Websites are not free. The storage alone takes some cash. If you are willing to lighten the burden, we can keep this site up online.

$30 — One hour's pay for a graphics artist

Art doesn't create itself without a hand to guide it. I can't draw, so I need to pay others to help.

$45 — Pay a full-stack web developer for one hour

Much of the work on this site happens on weekends which means giving up time with the kids. Help me pay the developers so I can give my kids more time.

Call Any API From a Solidity Smart Contract

Deploying an Airnode to get off-chain data in your smart ⋯

Author

Vanash WASSAN


  • 2551

  • 17122

  • 38

  • 0

  • 10

As we all know that it is not possible by a Smart Contract to directly access external APIs outside of a blockchain. Interacting with off-chain data while working with Smart Contracts is a real problem for a lot of dApps.

The Ethereum blockchain was designed to be entirely deterministic while the Internet was not. Calling an API directly sounds easy but on a blockchain, it would require all the nodes to call the same endpoint at the same time and expect to get the same data in order to come to a consensus. Plus, the core concept of a blockchain is its security, that is derived from a decentralized network of independent validators that purposefully limit their connection to the outside world.

However, with API3, you can have first-party oracles that are directly operated by the API Providers, called Airnodes that provides data to any on-chain dApp. As a result, you can easily make any REST API accessible to a Smart Contract.

Say Hello to ChainAPI 🔗

ChainAPI is a platform that enables you to integrate and deploy the open-source Airnode with its step-by-step integration and deployment tools.

To get started, go to ChainAPI and log in by connecting your MetaMask.

You will be prompted to confirm and sign the transaction through your MetaMask extension.

Make sure you’re using a new MetaMask Wallet with a fresh mnemonic. Your mnemonic will later be used to deploy the Airnode. You need to keep it extremely safe as this will serve as the “private key” of your deployed Airnode.

Each time you return to ChainAPI you will connect again, using MetaMask, to identify yourself by signing a message for the same account.

Complete the signup process and name your workspace.

Workspaces provides you with a way to invite other users to help or collaborate with integrations and deployments. This makes it easy to manage your Airnodes as a team or to outsource the process while still maintaining control over your integrations and deployments.

To change the name of your workspace in the future, click on name on the top-left of the dashboard

Within ChainAPI you will be able to create and manage your integrations or Airnode deployments by navigating to the “Integrations” or “Deploy” dashboards on the left hand navigation panel.

Integrating your Airnode 🔗

For this tutorial, I am going to use dxFeed’s public REST API endpoints to retrieve stock data.

To get started select the “Integrate API” option in the top right hand of the dashboard.

Enter the details about the API you want to Integrate.

You need to enter the base URL of your API along with all the endpoints that you want to integrate. If your API requires any security scheme (API Key, Basic HTTP Auth) you have the option to add that too.

As it’s a public API, it doesn’t have any security schemes.

You can now start by adding all your endpoints.

Here, the dxFeed REST API has one GET endpoint /events.json with some query parameters. You can add all the parameters that your API requires.

The parameters that are required by dxFeed’s API are:

  • events — Query Parameter — Takes in the market event. It will be user defined.
  • symbols — Query Parameter — Takes in the stock ticker symbol. It will be user defined.

For more information about dxFeed’s API and how it works, click here to test out their API.

Now you need to add all the parameters and define where they go (query/header/path/cookie). You can also decide if you want their values fixed or not.

Here, the dxFeed REST API has one GET endpoint /events.json with some query parameters. You can add all the parameters that your API requires.

Reserved parameters define what part of the response is to be picked and encoded before fulfillment. It can be defined by the requester but we can also hardcode it in the Airnode configuration.

You can also add pre and post-processing snippets for your Airnode. Although we won’t be using this feature with this integration.

  • Pre-processing snippets are executed before making the request to the Airnode.
  • Post-processing snippets are executed after receiving the response from the Airnode.

After adding all the required endpoints, you can now press finish and get ready to deploy your Airnode.

Deploying your Airnode 🔗

To deploy the Airnode, go to the deploy section on the menu. Name your deployment and select the integration that you want to use with it.

Select your Cloud Provider where you want your Airnode to be deployed.

Now select the Chains for your deployment. You can also select multiple networks and providers if you want it on multiple Chains.

Here, we are going to have our Airnode on the Polygon Mumbai Testnet.

Authorizer contracts allow you to specify which smart contracts can make requests to your Airnode’s endpoints. For this tutorial, we are just going to set it as Public.

When an Airnode receives a request, it can use on-chain authorizer contracts to verify if a response is warranted. This allows the Airnode to implement a wide variety of policies and to authorize requester contract access to its underlying API.

  • Public Authorizers will allow any smart contract to make requests to your Airnode.
  • Restricted Authorizers will only allow smart contract addresses that have been granted access to make requests to your Airnode.

Review your configuration for one final time. If everything seems correct, click on next.

Download all the Airnode configuration files and extract them.

This is what your Airnode config directory should look like:

config contains config.json and secrets.env.

  • The config.json file is used during the deployment/redeployment of an Airnode to configure its behavior and to provide mappings of API operations.
  • The secrets.env file holds values for config.json that must be kept secret.

The output directory will have the receipt.json that will be generated after you successfully deploy the Airnode.

The aws.env file holds AWS credentials for deployments targeted to AWS.

As we are using AWS as our cloud provider, we need to add our AWS IAM Access Keys with the Administrator Access policy. You can refer to this video if you are not sure how to obtain them.

The README.md contains all the steps to deploy the Airnode provided in a markdown format.

Open aws.env and add your AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY that you just created.

Open config/secrets.env and add your wallet mnemonic. Make sure you keep it extremely safe as this will serve as the “private key” of your deployed Airnode. From the mnemonic phrase, Airnode is able to assign wallet addresses to both the Airnode instance and its users.

You also need to add your Blockchain Provider URL. Here, we are going to use Alchemy for a free Polygon Mumbai Testnet Provider URL. You can use any blockchain provider that supports your network.

You can also set-up your HttpGateway credentials. It’s an optional service that allows authenticated users to make HTTP requests to your deployed Airnode instance for testing. ChainAPI has already generated these keys for you but you can change them if you want.

One final step before deploying your Airnode is to set Authorizers in the config.json file.

When an Airnode receives a request, it can use on-chain authorizer contracts to verify if a response is warranted. This allows the Airnode to implement a wide variety of policies and to authorize requester contract access to its underlying API.

For the scope of this tutorial, we can set the authorizer array empty in config.json so that any requester contract can access the Airnode.

Now you’re ready to deploy your Airnode. Make sure you have Docker installed on your system.

Copy and paste the commands below to your terminal at the root directory of your deployment package.

Windows 🔗

docker run -it --rm ^
      --env-file aws.env ^
      -v "%cd%/config:/app/config" ^
      -v "%cd%/output:/app/output" ^
      api3/airnode-deployer:0.7.3 deploy

OSX 🔗

docker run -it --rm \
      --env-file aws.env \
      -e USER_ID=$(id -u) -e GROUP_ID=$(id -g) \
      -v "$(pwd)/config:/app/config" \
      -v "$(pwd)/output:/app/output" \
      api3/airnode-deployer:0.7.3 deploy

Linux 🔗

docker run -it --rm \
      --env-file aws.env \
      -e USER_ID=$(id -u) -e GROUP_ID=$(id -g) \
      -v "$(pwd)/config:/app/config" \
      -v "$(pwd)/output:/app/output" \
      api3/airnode-deployer:0.7.3 deploy

Your Airnode should now be deployed. You can check its status in the deployment section.

Check out the GitHub Repo for this guide here:

Before continuing, make sure you set up the Airnode Monorepo on your system. Follow through the Readme to install and build all the dependencies and packages to be able to access the Airnode CLI.

Clone the Airnode Monorepo.

$ git clone https://github.com/api3dao/airnode.git .

To install the dependencies,

$ yarn run bootstrap

To build all the packages,

$ yarn run build
An Airnode is a first-party oracle that pushes off-chain API data to your on-chain contract. It makes a request to the on-chain RRP protocol contract (AirnodeRrpV0.sol) that adds the request to the event logs. The off-chain Airnode then accesses the event logs, gets the API data and performs a callback to the requester.

https://docs.api3.org/airnode/v0.8/grp-developers/

A Requester is a contract that triggers an Airnode request. To do so, the requester needs to be sponsored and make the request using a matching sponsor wallet.

The Requester then calls the protocol contract, which emits a blockchain event with the request parameters. Airnode listens to the events emitted by the AirnodeRrpV0 contract. During the next run cycle, Airnode gets the request parameters from the emitted event.

Coding Requester.sol 🔗

The Requester Contract will have two main functions, makeRequest() and fulfill(). The makeRequest() function will call the makeFullRequest() function of the AirnodeRrpV0.sol protocol contract which adds the request to its storage. The targeted off-chain Airnode gathers the request from AirnodeRrpV0.sol’s storage and responds using the fulFill() function of AirnodeRrpV0.sol.

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

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

// A requester that will return the Tesla Stock Price by calling the dxFeed airnode.

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.

    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;
    }

    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;
    }
}

Request Parameters 🔗

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

  • airnode (address) and endpointId specify the endpoint.
  • sponsor and sponsorWallet (addresses) specify which wallet will be used to fulfill the request.
  • parameters specify the API and Reserved Parameters (see Airnode ABI specifications for how these are encoded) We will encode the parameters off-chain using @airnode-abi library.

Response Parameters 🔗

The callback to the Requester 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 function decode() from the abi object.

Compiling the Contract 🔗

To deploy the Requester Contract, we are going to use Remix IDE. It’s an online IDE that allows developing, deploying and administering smart contracts for EVM Compatible Blockchains.

Make a contract and paste in the Requester.sol code.

Now hit compile on the right side of the dashboard and compile the Smart Contract.

Now we are all set to deploy our Requester.

Deploying the Requester 🔗

As we are going to deploy the contract on Polygon Mumbai Testnet, make sure you have enough MATIC in your wallet to deploy the Requester and then fund the sponsorWallet later. You can get some from the Mumbai Faucet.

Head to Deploy and run Transactions and select Injected Provider — MetaMask option under Environment. Connect your MetaMask. Make sure you’re on Mumbai Testnet.

The _rrpAddressis the main airnodeRrpAddress. The RRP Contracts have already been deployed on-chain. You can check for your specific chain here.

Fill in the _rrpAddress and click on Deploy. Confirm the transaction on your MetaMask and wait for it to deploy the Requester Contract.

Make sure you’re on the Polygon Mumbai Testnet

Calling the Requester 🔗

When your Contract gets deployed, head to Deploy & run transactions and click on the dropdown for your Requester under Deployed Contracts.

Now select the makeRequest dropdown to see all the parameters you need to pass in order to make a full request to the Airnode.

Here, you need to pass in your airnode(Airnode address), endpointID, sponsor(The Requester itself), sponsorWallet and parameters in order to call the makeRequest() function.

We can find the airnode in the receipt.json under the output directory obtained when we deployed our Airnode.

The endpointID can be found under the config.json file.

We need to derive the sponsorWallet through the Airnode CLI command that will make the actual call. We also need to fund it with some MATIC to cover the gas cost.

After you’ve setup the Airnode CLI and installed and built all the dependencies and packages, run the following command to derive your sponsorWallet:

Linux 🔗

npx @api3/airnode-admin derive-sponsor-wallet-address \
  --airnode-xpub xpub6CUGRUo... \
  --airnode-address 0xe1...dF05s \
  --sponsor-address 0xF4...dDyu9

Windows 🔗

npx @api3/airnode-admin derive-sponsor-wallet-address ^
  --airnode-xpub xpub6CUGRUo... ^
  --airnode-address 0xe1...dF05s ^
  --sponsor-address 0xF4...dDyu9

Your airnode-address and airnode-xpub (The Airnode’s extended public key) can be found in the same receipt.json. The sponsor-address will be the address of the Requester contract itself (the one that you just deployed).

Run the command to obtain your sponsorWallet.

Fund the sponsorWallet with some test MATIC.

The parameters are required to be encoded in bytes32 before you send it. We are going to use the @airnode-abi library for encoding the parameters off-chain and then sending it to the Requester.

You can set it up by cloning this tutorial’s repository.

Run the following command to get your encoded parameters :

Linux 🔗

node .\src\encodeParams.js

Now you have all the parameters that you require to run the makeRequest function. Populate all the fields and click on Transact.

The sponsor here will be the address of the Requester Contract that you just deployed.

Click on transact, confirm the transaction on MetaMask and wait for the transaction to complete.

Now you can head over to https://mumbai.polygonscan.com and check your sponsorWallet for any new transactions.

You might need to wait for a while as the Airnode calls the fulfill() function in AirnodeRrpV0.sol that will in turn call back the requester contract at fulfillAddress using function fulfillFunctionId to deliver data.

Here, we can see the latest Fulfill transaction.

Now go back on Remix and check for requestId under logs for the latest transaction.

You can also find your requestId under logs in the Polygon Mumbai Block Explorer.

Copy your requestId and paste it on under the fulfilledData method to decode the response. Click on call and you will see the API response. Here, we requested Tesla’s Stock price.

Finish 🔗

Now you successfully deployed an Airnode and made a Requester Contract to read data from it. You can also refer to this Repo for all the code that I’ve used for this tutorial.

Check out API3’s Discord Server and drop your queries there!

This license allows reusers to distribute, remix, adapt, and build upon the material in any medium or format, so long as attribution is given to the creator. The license allows for commercial use. If you remix, adapt, or build upon the material, you must license the modified material under identical terms.