Decentralized Oracle

The oracle problem and it's solution.

Decentralized Oracle

Blockchain is a technology to store data in a very secure and decentralized manner. It works by a consensus algorithm that adds a piece of data on the blockchain with every block that needs to be validated. The validation happens through many different nodes without relying on a central entity. Due to this architecture it comes with some challenges.

In this blog we will discuss one such key challenge and its solution without which we can’t achieve complete decentralization.

What is an Oracle ?

In medieval times oracles were people with magical abilities or objects who could provide wise and reliable guidance to those in need. Typical conversation between an oracle and peoples would be like:

Ancient one (not from marvel): What would the future look like ?
Oracle (waving over a crystal ball): In future the world will work on chain of blocks :p

Similarly in the technology space servers have the data we can fetch them when needed. We use apis as an oracle to fetch data from the server and apis are powered by magical spells that we call code.

An example would be when a developer needs weather data or currency exchange rates we rely on third party apis which we can call over an http request. So here, the apis are your oracle.

Blockchain can leverage these apis too but that comes with a big risk. It will also shatter the core principle of blockchain completely. Let's see why.

The Oracle Problem

Using traditional APIs in blockchain environment can lead to some serious failures because

  1. Fundamentally blockchain can't use apis because blockchain needs to be deterministic. In the real world, the value of currencies or weather fluctuates really fast. So with variable data, blockchain nodes may get different values while validating the transactions. Hence the nodes may be able to build a consensus. Hence the entire chain will fail.

  2. Generally apis are hosted on a server which is controlled by a centralized entity so if we use traditional apis we are introducing centralized data to a decentralized network. Which deviates from the main purpose of blockchain i.e decentralization. It will introduce a single point of failure if the centralized source is compromised, if it goes offline or sends faulty data to an on-chain network then the outcome of smart contacts will not be reliable.

Solution

Decentralized oracles provide a way for blockchain and smart contracts to extract data from the real world. They leverage blockchain to establish a network of nodes whose job is to aggregate real world data from various sources then filter it for inaccuracies and come to a consensus of a deterministic value. Then that data gets stored in the blockchain which can be used by other smart contracts.

By interacting with real world data we can truly unlock the full potential of blockchain hence projects like chainlink, Band Protocol (BAND) , api3 are developing decentralized oracles to eliminate the oracle problem in the web3 space.

Implementation

Imagine you are developing a funding smart contract to receive ethereum in your crypto wallet. And you decided that the minimum amount would be 1 USD.

To apply that constraint,you need to know what's the current exchange rate of ethereum in USD is. As we require real world data here we can use one of the decentralized oracles like Chainlink - which currently is the most decentralized oracle network out there. Lets see a step by step guide to implement the chainlink oracle.

Complete code is at the end of this article

Lets create a smart contract first

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

contract ETHtoUSD {
uint256 minimumValue = 1 \* 1e18;

    function receiveFund() public payable {
        require( msg.value >  minimalValue, "Please send minimum 1 USD.");
    }

}

Here inside ETHtoUSD contract we declared receveFund function with payable keyword which will enable the function to play with ETH transactions.

The require statement is like a “if then” function where we are saying that if received value is less than minimumValue then throw a message.

We are reading the value of ETH sent to our smart contract using a global keyword msg.value which gives us the amount in terms of WEI.

1 ETH = 1^18 WEI

And that's why we taking our minimumValue as 1 * 1e18

To get current rate of ETH in real world we will interact with chainlink smart contract and to interact with any smart contract we need 2 things:

  • Address of that smart contract
  • ABI of smart contract

First we can get the address easily using chainlink documentation

chainlink doc

We will use address of ETH/USD. For testing we are using the Goerli Testnet.

Second, to get the ABI we can import the file from their github.

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

Next, we will create a function to fetch data from oracle.

function getPrice() public view returns (uint){
    AggregatorV3Interface Price = AggregatorV3Interface(0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e);
    (,int256 price,,,) = Price.latestRoundData();
    return uint (price * 1e10);
}

Using AggredatorV3nterface we are getting the contract functionalities. Then we are using latestRoundData() to get the price result.

latestRoundData returns 5 values (roundID, price, startedAt, timeStamp, answeredInRound.) We just need the price data here so we can skip other information using a comma.

Finally this function will give us a price with 8 decimal places but in msg.value we received the amount in 18 decimal places so to match them up we need to multiply the price with 1e10 and return that.

Congratulations! You just learned how to use decentralized oracles.

We got the latest price information and now we need to convert that into USD.

function convertETHtoUSD(uint _ethAmount) public view returns(uint){
    uint valuePrice = getPrice();
    uint amountinDollars =(valuePrice * _ethAmount) /1e18;
    return amountinDollars;
}

This function receives _ethAmount which is the amount the user will send. In next line we are getting the currency value using our getPrice() function then we are converting it into USD using formula (ValuePrice * _ethAmount) /1e18;

Perfect!

Now we can wrap this function around msg.value like this

require( convertETHtoUSD(msg.value) >  minimalValue, "Please send minimum 1 USD.");

Here is the final code.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";


contract ETHtoUSD {
    uint256 minimumValue = 1 * 1e18;

    function receiveFund() public payable {
        require( convertETHtoUSD(msg.value) >  minimalValue, "Please send minimum 1 USD.");
    }

    function getPrice() public view returns (uint){
        AggregatorV3Interface price = AggregatorV3Interface(0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e);
        (,int256 price,,,) = price.latestRoundData();
        return uint (price * 1e18);
    }


    function convertETHtoUSD(uint _ethAmount) public view returns(uint){
        uint valuePrice = GetLastestPrice();
        uint amountinDollars =(valuePrice * _ethAmount) /1e18;
        return amountinDollars;
    }

}

Conclusion

The Oracle problem is not new to the tech world. We have already seen this in web2 and now are facing the same in web3 but with some extra challenges like decentralization and deterministic values. In this article we saw how to solve this problem, we received real world ETH price using chainlink and converted into USD. Now it's your turn to go ahead and build something amazing using real world data.

Decentralized Oracle

Know about the author

Love to bring ideas into reality by programming.

- Udit Tarini

At itmtb, we are reliable provider of cloud, virtual reality, technology consulting and software and IT development services to businesses and startups across the globe. We have the right expertise to help your business with the right technologies. Write to us at hello@itmtb.com if you think we can help.

Stay tuned for more technology updates.