Unleashing the Potential of Decentralized Oracles: An Insight into ChainLink

Using ChainLink Data Feeds to Connect Off-chain Data With The Blockchain

One of the most challenging parts of managing any blockchain is handling the division between off-chain and on-chain data. An oracle is a useful tool that makes it easier to connect real-world information with blockchain activities. With oracles, users have countless ways to make blockchains useful in their day-to-day life. In this article, we will learn how to use Chainlink oracles to communicate with our smart contract.

Types of Oracles

To set up most smart contracts on Blockchain we need a connecting bridge — thus an oracle — that translates needed information between the off-chain and on-chain world. Different oracles differentiate in terms of source and direction of information and degree of trustworthiness. Generally, Oracles can be categorized into two based on their architecture.

Centralized Oracles

A centralized oracle is an entity that is operated by a single authority and is the only provider of information for a smart contract. Therefore, it is one of the most secure oracles you can use. Note, however, that they’re not flawless and can be subject to hacking or corruption. What’s more, being a single provider of information leads to the problem that if the oracle fails there is no other source to fall back on.

Nonetheless, centralized oracles are cheaper since their architecture is by far simpler than their counterpart’s architecture. Also, keep in mind that since the architecture is simpler, the cost of its infrastructure and maintenance can be kept low. Therefore, this is a point to consider when choosing between oracle types.

Decentralized Oracles

Contrary to centralized oracles, decentralized ones do not rely on a single source of information. Instead, they collect data from multiple external sources that independently gather data that fortifies the authenticity of the information. Still, this jeopardizes the information’s trustworthiness because the independent sources are reporting data uncoordinated with each other. Consequently, these oracles require higher investments in their architecture and maintenance and are prone to various problems such as signaling and bribing. The decentralized oracle is only as good as its consensus algorithm.

Simply explained, centralized oracles are secure but rather slow while decentralized oracles are faster yet prone to manipulation.

The "Oracle Problem"

Usually, the “oracle problem” comes up anytime the value of oracles is discussed. The uniqueness of building on a blockchain is that a consensus on the state of the blockchain between the nodes must be reached. This means each node must be able to take the same transactions and events and get the same result as all other nodes.

An attacker could change the off-chain data that an oracle retrieves or the data could change over time.

For example, the value of the US Dollar can change frequently in just a day. If a smart contract executes based on this value, the price could change by the time another node performs the computation. This would break the consensus between the nodes, as the expected result is not the actual result anymore.

Not only are there potential issues of whether the data provided by oracle is accurate, but a centralized source can also be hacked or experience downtime. In these situations, the smart contract will either be operating with corrupted data or no data at all. Since smart contracts cannot be changed and are self-executing, this can lead to irreversible damage for the parties involved. Oracles must address these issues if they are to be secure and trusted providers of data to smart contracts.

The "Oracle Solution"

A popular method of solving the oracle problem is by using a blockchain itself. This approach is called a Decentralized Oracle Network (DON).

In a DON, instead of nodes coming to a consensus on a ledger of transactions, each node is an oracle. The nodes are then tasked with retrieving independent data from separate off-chain sources. The data from the nodes are then aggregated together and a value of truth is decided on.

This also solves the issue of the uptime of a data source as the smart contract will still be able to function since there are multiple sources of data. You can see a DON in action here.

Oracle Services

The most common way developers can use oracles is through a third-party service. The first and most popular service for this is Chainlink. Through Chainlink, developers and API providers can become participating node operators by connecting their API to the Chainlink network.

ChainLink is a decentralized network of nodes that uses Oracles to provide data from off-blockchain sources to on-blockchain smart contracts. Chainlink replaces the concept of a centralized oracle with a decentralized network of oracles so that real-world data verification can be done in a way that aligns with the smart contracts’ characteristics of decentralization and trustlessness.

Chainlink gives providers operating these oracles, on-chain identifiers, which they can use to manage and reward the reputation of the oracles. Using an ERC677 token incentivizes providers to give well-formatted and accurate data as well as any off-chain computation performed. Oracles used by smart contracts on various blockchains (e.g. Ethereum) are primarily for data feeds. Oracles, like that provided by Chainlink, provide real-time data feeds for more accurate digital asset prices that are taken from sources like digital exchanges. The data are then aggregated by a decentralized network of Chainlink node operators and made available to smart contracts.

Each of the data feeds is on-chain addresses that allow smart contracts to read data. An example of this is the ETH / USD feed. These oracles are being used by DeFi protocols like Aave to get the latest and most accurate prices to offset what would otherwise be losses if the data has not been updated.

Connecting To Data

Accessing data outside of a smart contract is available on EVM (Ethereum Virtual Machine) compatible networks. Using Solidity, developers can import what is called an interface contract to access functions that allow external data like price feeds.

Chainlink provides a contract called the AggregatorV3Interface. This defines the external functions that can be called by other smart contracts. Developers can specifically indicate the network (for Ethereum Data Feeds) they are using, either on the mainnet or development test network (e.g. Goerli, Sepolia). The interface contract address must be indicated.

Get the latest Price Feed

The following code is written in Solidity (compiler version 0.8.17). This is the raw version:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

contract PriceFeed
{
    AggregatorV3Interface internal priceFeed;

    constructor()
    {
        priceFeed = AggregatorV3Interface(
            0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e
        );
    }

    function getLatestPrice() public view returns (int)
    {
        ( , int price, , , ) = priceFeed.latestRoundData();
        return price;
    }
}

In the contract called PriceFeed, we import the interface contract AggregatorV3Interface.sol. Remix will automatically pull the contract (this section does not cover the technique when used with a simulated development environment outside of Remix).

Now that we have access to AggregatorV3Interface.sol, we can specify an internal variable called priceFeed. We will initialize it to connect to the Goerli test network contract address at:

0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e

This will be included in the constructor section of the contract, where it can be accessed by our function. This contract only has one function, and that is getLatestPrice() to return the latest value of ETH (ether) in USD (US Dollar).

You will notice the commas in the getPrice() function. That is intentional because if we reference that function from AggregatorV3Interface it is specified in this format:

function getLatestPrice() public view returns (int)
        (
            uint80 roundID,
            int price,
            uint startedAt,
            uint timeStamp,
            uint80 answeredInRound
        ) = priceFeed.latestRoundData();
       return price;

It doesn’t have to return the result in this exact format, but if there is no data to report then it should indicate no answer by a comma. In this case, the int price is the result that needs to be returned to get the latest Ethereum price (for more information refer to the Chainlink documentation).

Deploying the Contract

This contract will be deployed on the Goerli testnet. It can also be deployed locally on Remix, using the Javascript VM instead of an actual EVM. For Goerli, the Injected Web3 environment must be selected. This switches to network 5 (the Chain ID of the Goerli testnet) and you will be charged for gas to deploy the contract on your Ethereum wallet (e.g. Metamask).

Deployed smart contract to Goerli testnet

Once deployment is confirmed, you can see that there is one function call button called getLatestPrice. When you click it, the latest ETH price is returned. You will notice that the result appears to be one large number that might not make sense at first. That is supposed to be the USD conversion from ETH. This is normally how the result is returned on the Ethereum network.

Ethereum does not return results with decimal numbers. The result is written in wei, which is the smallest denomination of ETH. It is 1 * 10¹⁸ wei for 1 ether. 1 wei is thus 0.000000000000000001 ether.

If the value of ETH returned was 163162983291, it is denominated in wei as 1631629832910000000000, but the trailing zeroes will not be displayed. Count 18 decimal places from the right going to the left. The decimal is placed when you reach the 18th place, or 1631.629832910000000000. By default, unless specified, the value conversion for ETH to USD used is in wei.

Developers will need to format the result using other tools available from frameworks like Web3.js, Ether.js. Using Ether.js, the result can be formatted like in the following example to return the balance of an account in ether:

const ethers = require('ethers');
const network = 'goerli';
const provider = ethers.getDefaultProvider(network);
const address = '0x59900d8696efEafD21A42ab0029BA7b500BA5611';
provider.getBalance(address).then((balance) => {
    const balanceInEth = ethers.utils.formatEther(balance)
     console.log(`balance: ${balanceInEth} ETH`)
})

The provider (can only read) is calling the getBalance function and taking the address as an input, and if successful returning the balance in wei. And finally the ethers.utils.formatEther converting the balance in ETH and console logging in the terminal.

Conclusion

Getting price feeds with the latest data is important for smart contracts. Developers can use oracles like Chainlink to connect to external sources from a decentralized network of aggregator nodes. Oracles provide an abstraction that allows smart contracts to easily access external functions that return results like prices. This helps offset any divergent losses or inconsistencies due to the volatility of prices in the cryptocurrency market.

What's Next?

Congratulations! You've just learned how to use ChainLink Data Feeds provided by blockchain oracles in your smart contract to interact with the off-chain data. You can use this contract in your hardhat project and use it in the frontend to make some cool projects! How about using a WeatherAPI to make a smart contract trigger and warn the fishermen if the current climate is rough on the shore? Sounds Amazing right? Sky is the limit!

If you need some help in using the contract in Hardhat environment, here's my GitHub repo of this tutorial.

Hi there, I'm Biswarghya Biswas! If you enjoyed this post, feel free to share. And make sure to follow me on Twitter and also connect on LinkedIn👋