Make HTTP Request Using Your Solidity Smart Contract
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?
- The smart contract sends a request to the Chainlink oracle, including the URL and query string.
- The Chainlink oracle retrieves the response data from the external API or data source.
- The Chainlink oracle sends the response data back to the smart contract.
- 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.
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.
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
}
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.
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.
Step 7: Copy the address displayed and make sure you are signed into metamask.
Step 8: Choose a link token. Press the end and paste the copied address. Choose the transaction fee and click on “Next”.
Step 9: 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 req.add( "get" , "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD" ); // 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:
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.
Contact Us