Integrating Celo Oracles into your dApp

Integrating Celo Oracles into your dApp https://celo.academy/uploads/default/optimized/2X/8/86eeb2ca8f5843b32e3a33f9e35289118986fae5_2_1024x576.png
none 0.0 0

Introduction

Decentralized applications, or dApps, have taken the blockchain industry by storm, offering users decentralized, permissionless, and trustless services in a variety of areas, from finance to gaming and beyond. One key to building successful dApps is the use of oracle services, which bring external data into the blockchain environment. In this tutorial, we will explore how to integrate Celo oracles into your dApp to obtain current and historical price data for various assets.

Prerequisites

A proper understanding of Solidity and JavaScript is needed for this tutorial.

Before you continue, read this article for basic understanding on Celo Consensus Mechanism

Requirements

Before you get started, you’ll need the following:

  • Node.js and Node Package Manager(NPM) installed on your machine.
  • A Celo wallet with testnet faucets. Create your Celo wallet here and get your faucet here.

Step 1: Setting up our Integrated Development Environment

Firstly, you’ll use Hardhat as your development environment for Solidity contracts, you need to have it installed in your project.

Here’s how you can install Hardhat:

  1. First, make sure you have Node.js (version 10.16.0 or later) and npm installed on your machine. You can download Node.js from the official website, and it comes with npm (node package manager) included.

  2. Create a new directory for your project, navigate to it via the terminal, and then initialize a new Node.js project by running:

mkdir CeloOracle
cd CeloOracle
npm init -y

The -y flag is used to accept all default configurations.

  1. After initializing your Node.js project, you can install Hardhat by running:
npm install --save-dev hardhat

This command will install Hardhat as a development dependency in your project.

  1. To create a new Hardhat project, run:
npx hardhat

You will be prompted to create a sample project. You will choose Create a JavaScript Project, then for your add .gitignore, choose y.

  1. Then install ethers.js
npm install --save ethers
  1. We configure our hardhat.config.js to the Celo network. Hardhat’s configuration is done through the hardhat.config.js file located in the root directory of your project.

CeloOrace_dir

// Include the Hardhat-Celo plugin which provides tasks, helpers and tools to work with the Celo network.
require("hardhat-celo");

networks: {
    // Define the alfajores test network settings.
    alfajores: {
        // The URL of the RPC provider.
        // Replace this with the RPC URL of your choice if not using the public alfajores testnet node.
        url: "https://alfajores-forno.celo-testnet.org",
        // List of accounts that hardhat will use.
        // Replace "<YOUR_PRIVATE_KEY>" with your actual private key.
        accounts: [
            "<YOUR_PRIVATE_KEY>"
        ],
    },
    // Define the main Celo network settings.
    celo: {
        // The URL of the RPC provider.
        // Replace this with the RPC URL of your choice if not using the public mainnet node.
        url: "https://forno.celo.org",
        // List of accounts that hardhat will use.
        // Replace "<YOUR_PRIVATE_KEY>" with your actual private key.
        accounts: [
            "<YOUR_PRIVATE_KEY>"
        ],
    }
},
// Define the etherscan configuration.
etherscan: {
    // The API keys for etherscan (block explorer).
    // Replace "<CELOSCAN_API_KEY>" with your actual API keys for each network.
    apiKey: {
        alfajores: "<CELOSCAN_API_KEY>",
        celo: "<CELOSCAN_API_KEY>"
    },
},

In this configuration:

Make sure to replace <YOUR_PRIVATE_KEY> with your actual private key, or better yet, use an .env file to keep your private key secure. Never expose your private key in your code or version control system.

Now, you should have a fully functional Hardhat setup ready to go!

Step 2: Setting up our Smart Contract

Then we’ll be creating a Solidity smart contract called CeloOracle.sol in your contracts folder. This interacts with the Celo oracle. In this contract, we’ll define a function to fetch the price of a particular asset from the oracle.

// SPDX-License-Identifier: MIT
// Specifies the license for the source code, which is MIT

pragma solidity ^0.8.0;
// This indicates the version of Solidity that the contract is written in.

import "@openzeppelin/contracts/access/Ownable.sol";
// This imports the Ownable contract from the OpenZeppelin library, which provides basic authorization control functions.

import "@celo/contractkit/contracts/stabletoken/IStableToken.sol";
// This imports the IStableToken interface from the Celo ContractKit library, which describes the functions of the Celo stable tokens.

contract CeloOracle is Ownable {
    // Defines a new contract named CeloOracle, which inherits the functionality of the Ownable contract.

    address public stableTokenAddress;
    // This public variable stores the Ethereum address of the stable token.

    constructor(address _stableTokenAddress) {
        // The constructor function is called once when the contract is deployed.
        // It takes the address of the stable token as an argument.
        
        stableTokenAddress = _stableTokenAddress;
        // Sets the stable token's address to the passed-in address.
    }

    function getAssetPrice() public view returns (uint256) {
        // This is a public function that returns the price of the asset.

        IStableToken stableToken = IStableToken(stableTokenAddress);
        // Creates an instance of IStableToken for the stored stable token address.

        return stableToken.inflationFactor();
        // Returns the inflation factor of the stable token, which can be used as an indicator of its price.
    }
}

This contract imports the OpenZeppelin Ownable contract, which provides basic authorization control functions, and the Celo IStableToken interface, which contains the inflationFactor function that returns the current price of the token.

Step 3: Writing the JavaScript Code

Next, we’ll write the JavaScript code in a file called index.js in your test folder that interacts with our smart contract.

// Import the ethers.js library, a complete Ethereum wallet implementation and utilities in JavaScript and TypeScript.
const ethers = require("ethers");

// Import the ABI (Application Binary Interface) from the local CeloOracle contract artifact
// ABI is a JSON object that describes how to interact with the contract, including all of its functions and their parameters.
const contractABI = require("./artifacts/contracts/CeloOracle.sol/CeloOracle.json").abi;

// Set up the connection to the Celo testnet (Alfajores) using a JSON-RPC provider
// The provider allows us to interact and communicate with the blockchain.
const provider = new ethers.providers.JsonRpcProvider("https://alfajores-forno.celo-testnet.org");

// Set the contract address that we are going to interact with
// You should replace the "0x..." with your own contract's address.
const contractAddress = "0x..."; // Replace with your contract address

// Define an async function that fetches the asset price from the contract
async function fetchPrice() {
  // Create a random wallet and connect it to the provider
  // In a real-world situation, you would likely use a specific wallet instead of a random one.
  const wallet = ethers.Wallet.createRandom().connect(provider); 

  // Instantiate a new ethers.js contract object that we can use to interact with our contract
  // The contract object needs the contract address, the contract ABI, and a connected wallet to work.
  const contract = new ethers.Contract(contractAddress, contractABI, wallet);

  // Try to call the getAssetPrice function of the contract
  try {
    // Call the getAssetPrice() function of the contract, which is an async operation
    const price = await contract.getAssetPrice();

    // Log the received price to the console
    console.log(`Price: ${price}`);
  } catch (err) {
    // If there was an error calling the function or processing the result, log the error to the console
    console.error(err);
  }
}

// Call the fetchPrice function to start the process
fetchPrice();

This code initializes a web3 instance with the Celo network configuration, retrieves the accounts from the provider, and then calls the fetchPrice function from the smart contract.

Step 4: Deploying the Contract

We’ll write a deployment scripts for our contracts now.

First, install the Hardhat ethers plugin:

npm install --save-dev @nomiclabs/hardhat-ethers 'ethers@^5.0.0'
//You can check the latest command [here](https://hardhat.org/hardhat-runner/plugins/nomiclabs-hardhat-ethers)

Next, create a deployment deploy.js file in the scripts directory:

// Define an async function named main
async function main() {
  // Get the list of signers (accounts) from the ethers object and take the first one as the deployer
  const [deployer] = await ethers.getSigners();
  // Log the deployer's address
  console.log(`Deploying contracts with the account: ${deployer.address}`);

  // Get the contract factory for the CeloOracle contract
  const CeloOracle = await ethers.getContractFactory("CeloOracle");
  // Define the address for the stable token
  const stableTokenAddress = "0x..."; // Replace with your stable token address
  // Deploy the CeloOracle contract with the stable token address as a parameter
  const oracle = await CeloOracle.deploy(stableTokenAddress);

  // Log the address of the newly deployed CeloOracle contract
  console.log(`CeloOracle contract address: ${oracle.address}`);
}

// Invoke the main function
main()
  // If the main function executes successfully, then exit the process with status code 0 (no error)
  .then(() => process.exit(0))
  // If an error is caught during the execution of the main function, log the error and exit the process with status code 1 (indicates an error)
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

To deploy your contract using Hardhat, use the following command:

npx hardhat run --network celo scripts/deploy.js

hardhat compile

Step 5: Testing the Contract

After deploying, you can run your JavaScript code to test the contract:

node script.js

If everything is set up correctly, you should see the current price of the asset printed to the console.

Conclusion

This tutorial provided a high-level overview of how to integrate Celo oracles into your dApp to fetch current and historical price data for various assets. This knowledge is a powerful tool for developers building dApps on the Celo platform, especially those dealing with financial transactions.

Remember that the use of oracles comes with trust assumptions, so it’s important to understand the risks and potential failure modes associated with using an oracle service. Always ensure that your dApp has mechanisms in place to handle potential oracle failures or manipulations.

Next Steps

By harnessing the power of Celo oracles, you can build more dynamic and responsive dApps with our tutorials here.

About the Author

Joshua Obafemi

I’m a Web3 Fullstack Developer and Technical Writer. You can connect with me on GitHub, Twitter, Linkedin.

References

2 Likes

Approved for you to get started. You can manage the tutorial here by changing the category to Proposals > In Progress then Proposals > Review as you complete the tutorial. Thanks!

@joenyzio

Hello, I’m done with the article but I don’t know how I’ll move it to the review section

1 Like

Hey @Jorshimayor I just made you owner so you should be able to change the category now to review.

i will be reviewing this.

can you add some details about how these functions working and how celo oracle is been getting used , some images of code running will make the post more readable.

1 Like

Yeah, I have issues with uploading images for the code snippets

what issues you have regarding uploading?

Thanks, I was able to figure it out. Are the inline codes too much or I should explain less

just describe little about it so reader will have context about it.

ANy updates? i am still waiting

Yeah, I think the codes are more explanatory now. Then I’ve added images of the files directory