In this chapter, we’ll explore how to use Chainlink to integrate smart contracts with external APIs and data sources. We’ll cover the process of setting up a Chainlink node, creating a Chainlink contract, and integrating it with external APIs using the Chainlink External Adapter.
Setting Up a Chainlink Node
Before you can start using Chainlink to integrate your smart contracts with external APIs, you’ll need to set up a Chainlink node. A Chainlink node is a server that runs the Chainlink software and connects to the Ethereum network.
To set up a Chainlink node, you’ll need to install the following software:
- Docker: Docker is a containerization platform that allows you to run the Chainlink node in a containerized environment.
- Docker Compose: Docker Compose is a tool that simplifies the process of setting up and running Docker containers.
- Git: Git is a version control system that allows you to clone the Chainlink repository from GitHub.
Once you have these tools installed, you can set up your Chainlink node by following these steps:
- Clone the Chainlink repository from GitHub:
git clone https://github.com/smartcontractkit/chainlink.git
- Change into the “chainlink” directory:
cd chainlink
- Build the Chainlink Docker image:
docker build -t chainlink .
- Run the Chainlink Docker container:
docker run -d --name chainlink -p 6688:6688 -v $PWD:/chainlink chainlink:latest
Your Chainlink node is now up and running. You can check its status by running the following command:
docker logs chainlink
Creating a Chainlink Contract
Now that you have a Chainlink node set up, you can start using Chainlink to integrate your smart contracts with external APIs. The first step is to create a Chainlink contract.
A Chainlink contract is a smart contract that defines the parameters and logic for a data request. It specifies the data that the smart contract needs, the external API to retrieve it from, and any relevant parameters.
To create a Chainlink contract, you’ll need to do the following:
- Import the ChainlinkClient contract:
import "https://github.com/smartcontractkit/chainlink/evm-contracts/src/v0.4/ChainlinkClient.sol";
- Define the ChainlinkClient contract as a public variable:
ChainlinkClient public chainlink;
- Define any variables that you’ll need to store the data that is returned by the API:
uint256 public price;
string public stockSymbol;
- Define a function that sends a data request to the Chainlink node:
function requestStockPrice(string _stockSymbol) public {
chainlink.requestData(chainlink.ORACLE_ADDRESS, jobId, _stockSymbol);
}
- Define a function that is called when the data request is fulfilled:
function onData(bytes32 _jobId, uint256 _price) public {
require(_jobId == jobId, "Invalid job ID");
price = _price;
}
Here’s the complete Chainlink contract:
import "https://github.com/smartcontractkit/chainlink/evm-contracts/src/v0.4/ChainlinkClient.sol";
contract StockPriceOracle {
ChainlinkClient public chainlink;
uint256 public price;
string public stockSymbol;
constructor(ChainlinkClient _chainlink, string _stockSymbol) public {
chainlink = _chainlink;
stockSymbol = _stockSymbol;
}
function requestStockPrice(string _stockSymbol) public {
chainlink.requestData(chainlink.ORACLE_ADDRESS, jobId, _stockSymbol);
}
function onData(bytes32 _jobId, uint256 _price) public {
require(_jobId == jobId, "Invalid job ID");
price = _price;
}
}
Integrating with External APIs Using the Chainlink External Adapter
Now that you have a Chainlink contract set up, you can use the Chainlink External Adapter to integrate it with external APIs. The Chainlink External Adapter is a piece of software that acts as an intermediary between the Chainlink contract and the external API. It sends data requests from the Chainlink contract to the API and returns the data to the contract when the request is fulfilled.
To use the Chainlink External Adapter, you’ll need to do the following:
- Install the Chainlink External Adapter:
npm install -g @chainlink/external-adapter
- Set up a configuration file for the External Adapter. The configuration file specifies the API endpoint, the data that the External Adapter should request, and any relevant parameters. Here’s an example configuration file for a stock price API:
{
"name": "stock-price-adapter",
"jobId": "stock-price-job",
"url": "https://stock-price-api.com/prices",
"params": {
"symbol": "${symbol}"
},
"resultPath": "$.price",
"responseDataType": "uint256"
}
- Run the External Adapter:
external-adapter run stock-price-adapter.json
Now, when the Chainlink contract sends a data request to the External Adapter, it will forward the request to the API and return the data to the contract when the request is fulfilled.
Conclusion
In this chapter, we’ve covered how to use Chainlink to integrate smart contracts with external APIs and data sources. We’ve set up a Chainlink node, created a Chainlink contract, and used the Chainlink External Adapter to integrate the contract with external APIs. With these tools, you can build powerful smart contracts that can access and interact with a wide range of external data sources.
Exercises
To review these concepts, we will go through a series of exercises designed to test your understanding and apply what you have learned.
Write a Chainlink contract that sends a data request to an external weather API to retrieve the current temperature for a given city. The contract should store the temperature in a variable and include a function that returns the temperature when called.
import "https://github.com/smartcontractkit/chainlink/evm-contracts/src/v0.4/ChainlinkClient.sol";
contract WeatherOracle {
ChainlinkClient public chainlink;
uint256 public temperature;
string public city;
constructor(ChainlinkClient _chainlink, string _city) public {
chainlink = _chainlink;
city = _city;
}
function requestTemperature(string _city) public {
chainlink.requestData(chainlink.ORACLE_ADDRESS, jobId, _city);
}
function onData(bytes32 _jobId, uint256 _temperature) public {
require(_jobId == jobId, "Invalid job ID");
temperature = _temperature;
}
function getTemperature() public view returns (uint256) {
return temperature;
}
}
Write a configuration file for the Chainlink External Adapter that sends a data request to an external currency exchange API to retrieve the exchange rate for a given pair of currencies. The configuration file should specify the API endpoint, the data to be requested, and any relevant parameters.
{
"name": "currency-exchange-adapter",
"jobId": "currency-exchange-job",
"url": "https://currency-exchange-api.com/rates",
"params": {
"from": "${from}",
"to": "${to}"
},
"resultPath": "$.rate",
"responseDataType": "uint256"
}
Write a function for the Chainlink contract in Exercise 1 that sends a data request to the External Adapter to retrieve the temperature for a different city.
function requestTemperatureForCity(string _city) public {
city = _city;
chainlink.requestData(chainlink.ORACLE_ADDRESS, jobId, _city);
}
Write a function for the Chainlink contract in Exercise 1 that calculates the Fahrenheit equivalent of the temperature returned by the External Adapter.
function getTemperatureInFahrenheit() public view returns (uint256) {
return temperature * 9 / 5 + 32;
}
Write a function for the Chainlink contract in Exercise 1 that sends a data request to the External Adapter if the temperature is below a certain threshold. The function should return true if the temperature is below the threshold and false if it is above or equal to the threshold.
function isTemperatureBelowThreshold(uint256 _threshold) public view returns (bool) {
if (temperature < _threshold) {
chainlink.requestData(chainlink.ORACLE_ADDRESS, jobId, city);
return true;
}
return false;
}