Open In App

Make HTTP Request Using Your Solidity Smart Contract

Last Updated : 27 Mar, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Smart contracts are self-executing digital programs that are designed to automate the enforcement of the terms of a contract. Solidity is a programming language used to write these smart contracts on the Ethereum blockchain. 

One of the challenges with smart contracts is their inability to interact with the outside world, including making HTTP requests. Smart contracts are often limited in their ability to interact with external systems, which is a major limitation when building decentralized applications. The inability to make HTTP requests is a significant challenge for smart contract developers, as it limits their ability to access external data and services that are necessary to create more advanced and complex decentralized applications.

Problem Statement

To be able to make an HTTP request using a Solidity smart contract, in order to interact with external APIs and retrieve data from web services. However, since Solidity is a low-level programming language and runs on the Ethereum blockchain, it does not have built-in support for making HTTP requests. Therefore, we need to find a way to integrate an HTTP client into our smart contract so that it can communicate with external servers and fetch data that our contract can use in its logic.

Oracles and Chainlinks

Oracles are third-party services that act as intermediaries between smart contracts and external systems. They can provide smart contracts with access to external data and services, including the ability to make HTTP requests. Additionally, the use of oracles can increase the security of smart contracts, as they act as a buffer between the smart contract and external systems, reducing the risk of security vulnerabilities.

To implement this solution, we will use Chainlink as our oracle provider. Chainlink is a decentralized oracle network that connects smart contracts with off-chain data sources, APIs, and payment systems. Chainlink nodes will act as oracles, providing smart contracts with access to external APIs and data sources.

Create a Solidity smart contract that interacts with the Chainlink oracle network to make HTTP requests. The contract will define a function that takes a URL and a query string as input parameters and returns the result of the HTTP request as a string. The function will use the Chainlink oracle to make the HTTP request and retrieve the response data.

How the Smart Contract Works?

  1. The smart contract sends a request to the Chainlink oracle, including the URL and query string.
  2. The Chainlink oracle retrieves the response data from the external API or data source.
  3. The Chainlink oracle sends the response data back to the smart contract.
  4. The smart contract returns the response data to the calling application.

Approach

1. Create a New Solidity Smart Contract

Create a new solidity smart contract that will interact with the Chainlink oracle. This smart contract will need to inherit from the ChainlinkClient contract, which can be found in the Chainlink documentation.

2. Define a Function

Define a function in your smart contract that will make the HTTP request. This function will need to call the requestOracleData() function from the ChainlinkClient contract. The requestOracleData() function takes several parameters, including the URL of the API endpoint you want to call, the HTTP method to use, and the data format to expect.

3. Specify Chainlink Oracle 

Before calling the requestOracleData() function, you will need to specify the Chainlink oracle contract that will handle the request. This can be done by calling the setChainlinkOracle() function and passing in the address of the oracle contract.

4. Specify the Chainlink Job ID 

Specify the chainlink job ID that corresponds to the API endpoint you want to call. This can be done by calling the setChainlinkJobID() function and passing in the job ID.

5. Call requestOracleData() Function

Once you have specified the oracle contract and job ID, you can call the requestOracleData() function to make the HTTP request. This function will return a request ID that you can use to track the status of the request.

6. Upon Request Completion Oracle Call Callback Function

Once the request is complete, the oracle will call a callback function in your smart contract with the response data. You can define this callback function to do whatever you need with the response data.

7. Use Response Data to Perform Operations

You can use the response data in your smart contract to perform various operations, such as updating storage variables or triggering other functions in the contract.

Prerequisites

1. Install Node.js: Download and install the latest version of Node.js from the official website.

Install Node.js

 

2. Solidity development environment: You should have a Solidity development environment set up on your computer. This includes a code editor, a Solidity compiler, and a local blockchain for testing your smart contracts. You can use an online IDE like Remix.org.

3. Install Oracle or API Service: You can choose an Oracle or API service that meets your needs. Some popular services include Chainlink, Provable, and Band Protocol. Follow the documentation provided by the chosen service to set up an account and get an API endpoint.

4. Install the Chainlink client library: Install chainlink client library in your project using the command:

npm install @chainlink/contracts

Implementation

Step 1: We need to import the chainlink contract from the chainlink library as follows – 

import “https://raw.githubusercontent.com/smartcontractkit/chainlink/develop/evm-contracts/src/v0.6/ChainlinkClient.sol”;

This provides us with the necessary functions to interact with Chainlink. The following GitHub code is being imported from chainlink.

GitHub code imported from Chainlink

 

Step 2: The contract defines the constructor function, which initializes the oracle, jobId, and fee variables to values specific to the testnet. It also calls the setPublicChainlinkToken() function from the ChainlinkClient contract, which sets the public Chainlink token as the token used for paying the fee.

    constructor() public {
       setPublicChainlinkToken();
       oracle = 0x2f90A6D021db21e1B2A077c5a37B3C7E75D15b7e;
       jobId = “29fa9aa13bf1468788b7cc4a500a45b8”;
       fee = 0.1 * 10 ** 18; // 0.1 LINK
   }

Chainlink Market

 

Step 3: The contract defines the requestEthereumPrice function, which sends a request to the external API to retrieve the current Ethereum price in US dollars. The function first creates a new Chainlink request by calling the buildChainlinkRequest function with the jobId, the address of the current contract instance (address(this)), and the fulfill function selector (which specifies the function to call when the request is fulfilled).

function requestEthereumPrice() public returns (bytes32 requestId) {
       Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);
       request.add(“get”, “https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD”);
       request.add(“path”, “USD”);
       request.addInt(“times”, 100);
       return sendChainlinkRequestTo(oracle, request, fee);
   }

Step 4: The function then adds the URL of the external API to the Chainlink request by calling the add function with the “get” parameter and the URL value. 

  • It also adds the path to the data in the API response that contains the Ethereum price in US dollars by calling the add function with the “path” parameter and the path value. 
  • The function multiplies the retrieved value by 100 to remove the decimals by calling the addInt function with the “times” parameter and the value of 100. 
  • Finally, the function sends the Chainlink request to the oracle by calling the sendChainlinkRequestTo function with the oracle, the request object, and the fee, and returns a requestId.
Etherscan

 

Step 5: When the oracle receives the request and retrieves the data from the external API, it triggers the fulfill function in the contract, passing in the requestId and the retrieved uint256 value. The fulfill function updates the value of the ethereumPrice variable with the retrieved value.

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

 

Step 6: Deploy your contract to a local blockchain or testnet. 

Deploy contract

 

Step 7: Copy the address displayed and make sure you are signed into metamask.

Copy the address

 

Step 8: Choose a link token. Press the end and paste the copied address. Choose the transaction fee and click on “Next”.

Choose link token

 

Step 9: Confirm the transaction.

Confirm the transaction

 

Step 10: If you were to now check the currentPrice column the price of Ethereum will be updated. Overall, this smart contract demonstrates how to use Chainlink to securely retrieve data from external APIs and use it in a smart contract.

Solidity




pragma solidity ^0.6.0;
 
import "github.com/smartcontractkit/chainlink/evm-contracts/src/v0.6/ChainlinkClient.sol";
 
// MyContract inherits the ChainlinkClient contract to gain the
// functionality of creating Chainlink requests
contract ChainlinkExample is ChainlinkClient {
  // Stores the answer from the Chainlink oracle
  uint256 public currentPrice;
  address public owner;
   
  // The address of an oracle - you can find node addresses on https://market.link/search/nodes
  address ORACLE_ADDRESS = 0xB36d3709e22F7c708348E225b20b13eA546E6D9c;
   
  // The address of the http get job - you can find job IDs on https://market.link/search/jobs
  string constant JOBID = "628eded7db7f4f799dbf69538dec7ff2";
   
  // 17 0s = 0.1 LINK
  // 18 0s = 1 LINK
  uint256 constant private ORACLE_PAYMENT = 100000000000000000;
 
  constructor() public {
    // Set the address for the LINK token for the network
    setPublicChainlinkToken();
    owner = msg.sender;
  }
 
  // Creates a Chainlink request with the uint256 multiplier job
  // Ideally, you'd want to pass the oracle payment, address, and jobID as
  function requestEthereumPrice()
    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);
    // Adds a URL with the key "get" to the request parameters
    // Uses input param (dot-delimited string) as the "path" in the request parameters
    req.add("path", "USD");
    // Adds an integer with the key "times" to the request parameters
    req.addInt("times", 100);
    // Sends the request with the amount of payment specified to the oracle
    sendChainlinkRequestTo(ORACLE_ADDRESS, req, ORACLE_PAYMENT);
  }
 
  // fulfill receives a uint256 data type
  function fulfill(bytes32 _requestId, uint256 _price)
    public
    // Use recordChainlinkFulfillment to ensure only the requesting oracle can fulfill
    recordChainlinkFulfillment(_requestId)
  {
    currentPrice = _price;
  }
   
  // cancelRequest allows the owner to cancel an unfulfilled request
  function cancelRequest(
    bytes32 _requestId,
    uint256 _payment,
    bytes4 _callbackFunctionId,
    uint256 _expiration
  )
    public
    onlyOwner
  {
    cancelChainlinkRequest(_requestId, _payment, _callbackFunctionId, _expiration);
  }
 
   
  // withdrawLink allows the owner to withdraw any extra LINK on the contract
  function withdrawLink()
    public
    onlyOwner
  {
    LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
    require(link.transfer(msg.sender, link.balanceOf(address(this))), "Unable to transfer");
  }
   
  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }
   
   // A helper function to make the string a bytes32
  function stringToBytes32(string memory source) private pure returns (bytes32 result) {
    bytes memory tempEmptyStringTest = bytes(source);
    if (tempEmptyStringTest.length == 0) {
      return 0x0;
    }
    assembly { // solhint-disable-line no-inline-assembly
      result := mload(add(source, 32))
    }
  }
}


Output: 

Output

 

Functions

The contract imports the ChainlinkClient contract from “@chainlink/contracts/src/v0.8/ChainlinkClient.sol” to inherit from it. The contract defines a public uint256 variable ‘result’ and two public functions: ‘makeHttpRequest’ and ‘fulfill’.

  • makeHttpRequest Function: The ‘makeHttpRequest’ function is a public function that sends a GET request to a specified URL. It builds the Chainlink request using the buildChainlinkRequest function and adds a parameter to the request using the ‘add’ function. Finally, it sends the request using the ‘sendChainlinkRequestTo’ function, which specifies the oracle address and job ID to use.
  • fulfill Function: The ‘fulfill’ function is a public function that is called when the Chainlink request is fulfilled. It takes the request ID and the result of the request as parameters and stores the result in the ‘result’ variable.

Conclusion 

In conclusion, Chainlink is a valuable tool for interacting with external APIs in a secure and decentralized way within Solidity smart contracts. By using Chainlink, we can easily make HTTP requests to external data sources and receive the results back in a reliable and efficient manner. Its integration with Solidity is straightforward, which makes it an accessible option for developers looking to incorporate off-chain data into their on-chain applications to create more advanced and complex decentralized applications. 



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads