Integrating the new Chainlink contracts
How to use the new price feeder oracles
By now you've probably heard of Chainlink. Maybe you are even participating the current hackathon? In any case adding their new contracts to retrieve price feed data is surprisingly simple. But how does it work?
Oracles and decentralization
If you're confused about oracles, you're not alone. The term is so overused these days for literally anything, probably because it sounds fancy. But almost anything could call itself an oracle technically. So what is an oracle?
It's nothing more than some form of bringing off-chain data on to a blockchain. Think of an external API call or the weather forecast for tomorrow. You can't have Ethereum nodes retrieve this data directly, because it has to be deterministic. Just imagine one node requesting an API to ask if it's going to rain tomorrow. The answer right now is no, but only 5 minutes later, the next node validates the transaction, requests the weather API and now it says: yes, it will rain tomorrow. That's not going to work, a transaction has to be able to be validated by anyone at anytime with the same result.
So now think of a contract that stores the weather forecast for tomorrow. In the simplest form the design would be- smart contract with functions to read and write the forecast data
- server fetching forecast from an API and regularly updating the smart contract
That's all we need for a simple oracle. By sending a transaction to our smart contract with the forecast data, it becomes available on-chain for other contracts. But only one server that updates this? You can see the problem...
So clearly with only one node an oracle wouldn't be very much decentralized. Chainlink encourages to use many sources of truth and their price feeds all have several nodes that are participating. The pick the median value (safer than the average) from all the values they receive from nodes in each round. Chainlink is a generalized oracle protocol meaning you could use it for any kind of data, but let's focus on the price feeds as they are really easy to use and often needed.
Receiving price feed data
While the Chainlink protocol is a general system for any kind of data, Chainlink specifically provides price feeds for many cryptos, fiats and stocks. The best thing about it? It's currently free to use and requires almost no setup. Simply pick a price feed and read the current price.
Let's add the USD/ETH oracle on Kovan as our example. The oracle address is 0x9326BFA02ADD2366b30bacB125260Af641031331
and you can find all available feeds at https://docs.chain.link/docs/reference-contracts.
Reading the current price
First let's install the chainlink interfaces via:
$ npm install @chainlink/contracts --save
AggregatorV3Interface
updated interface. It allows you to use the simplified functions of getLatestPrice
and getHistoricalPrice
. To get the latest price, just call the getLatestPrice
function and it will return- the current round id
- the current ETH price in USD
- the timestamp of when the current round started
- the timestamp when the current round was completed
- the id of the round in which the current ETH price was set
Most likely you just care about the current latest price and you can ignore the other values.
// SPDX-License-Identifier: MIT
pragma solidity 0.7.1;
import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";
contract EthUsdKovanOracle {
AggregatorV3Interface private priceFeed;
constructor() {
priceFeed = AggregatorV3Interface(
0x9326BFA02ADD2366b30bacB125260Af641031331
);
}
function getLatestPrice() public view returns (
uint80 roundID,
int price,
uint startedAt,
uint timeStamp,
uint80 answeredInRound
) {
(
roundID,
price,
startedAt,
timeStamp,
answeredInRound
) = priceFeed.latestRoundData();
}
}
Retrieving historical price feed data
You can also use this feed to get historical data via the getHistoricalPrice
function. Call it with the round id that you're interested in. You'll receive a similar response as before
- the current round id
- the ETH price in USD in that round
- the timestamp of when the current round started
- the timestamp when the current round was completed
- the id of the round in which the current ETH price was set
But this time you might care about the timestamp when the round was completed to figure out the exact the corresponding time for that price. You could do this off-chain in some cases to figure out the correct round id.
function getHistoricalPrice(
uint80 roundId
) public view returns (
uint80 roundID,
int price,
uint startedAt,
uint timeStamp,
uint80 answeredInRound
) {
(
roundID,
price,
startedAt,
timeStamp,
answeredInRound
) = priceFeed.getRoundData(roundId);
require(timeStamp > 0, "Round not complete");
}
Price feeder markets
A nice visual overview of price feeds is available at: https://feeds.chain.link/. For example the ETH/USD oracle at https://feeds.chain.link/eth-usd.
The respective aggregator wrapper would be 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419
(taken from the references here). You can also look at the sources for all oracles via https://market.link/. Here you will not only find price feeds, but everything that is available from Chainlink nodes. You could even setup your own requested data provided you pay for it with the LINK token.
At https://market.link/feeds/6dd8e645-0b17-4f7b-b169-bbec8abe9e29 would be our ETH/USD oracle. The contract address here is different: 0xf79d6afbb6da890132f9d7c355e3015f15f3406f
, but don't worry this is the real oracle source. Our address above is just a wrapper and is using that one under the hood. Using the new wrapper is a more convenient way to use the oracle.
We need oracles
There you have it. I think the price feeds are a great way to get started with Chainlink. You might want to combine it with some other solutions not to rely solely on Chainlink including your own price feed.
And in case I don't see you, good afternoon, good evening and good night!
Solidity Developer