How to Build a Custom Oracle

945G...fRid
21 Jun 2024
4

In this tutorial, we'll guide you through building a custom Web3 oracle using Tenderly Web3 Actions. An oracle collects data from real-world systems and sends it to the blockchain, acting as an entry point for streaming data from Web2 applications to smart contracts.
Using oracles, we can access external data sources (e.g., exchanges, traffic and weather data, gas rates, oil prices, etc.) from within our smart contracts.
The entire code is available in this GitHub repo.

Project Overview

This project aims to teach you how to build a Web3 Action that fetches data from a Web2 API whenever a smart contract requests it through an on-chain event. This data will then be sent to the requesting contract.
Project Flow:

  1. Create a Consumer – a smart contract that requests the ETH price from an Oracle Contract.
  2. The Oracle Contract requests a new coin price from the CoinGecko API using the RequestCoinPrice event.
  3. Once the price request is observed, the Web3 Action fetches the value.
  4. The price value is pushed back to the Oracle Contract.

We will use a pre-made smart contract for this project. Feel free to explore the code and play around with it in the Tenderly Sandbox and check out the Sandbox Docs.
Note: The SimpleConsumer contract accepts the coinPrice only from the CoinOracle it was assigned when deployed. Additionally, CoinOracle accepts updates only if signed by the same Wallet that deployed it (owner).

The Plan

Here are the steps to build our oracle:

  1. Deploy the CoinOracle and SimpleCoinConsumer smart contracts.
  2. Get the API key and other information needed to use an Ethereum provider. We'll store this data in the Web3 Actions Secrets.
  3. Get the Private Key of the account that deployed the Oracle Contract (owner) and store it in the Web3 Actions Secrets.
  4. Initialize Tenderly’s Web3 Actions directory on your development environment and add npm dependencies.
  5. Create a Web3 Action that will send price updates to the oracle.

Steps to Build Your Oracle

1. Deploy the Smart Contracts: Both CoinOracle and SimpleCoinConsumer contracts are stored in the same file: CoinOracle.sol. Check out the source code in our GitHub repo. The CoinOracle contract must be deployed first, followed by the SimpleCoinConsumer contract, preferably using a different Wallet. Make sure to pass the CoinOracle address as the constructor parameter. For this tutorial, we'll deploy to the Ropsten test network (ID is 3), but you can use a different one.
2. Initialize Web3 Actions: You'll need access to the Tenderly Dashboard. If you don't have an account, sign up for free. Install the Tenderly CLI following the installation guide. With the Tenderly CLI installed, create a new directory tdly-actions and initialize your Web3 Actions using the tenderly actions init command.

bash
复制代码
$ cd tdly-actions
$ tenderly actions init

When prompted, select your Tenderly project. List out the contents of the directory to explore the files created by the CLI:

bash
复制代码
ls actions
example.ts
tsconfig.json
package.json

Install npm dependencies (Axios and Ethers) to make requests to an external API and interact with the blockchain:

bash
复制代码
cd actions && npm install --save-dev axios ethers @types/node && cd ..

3. Create Your Web3 Action: Copy the CoinOracleContract.json file to the actions directory. You can find this JSON file in Remix or the GitHub repo. Set the CONTRACT_ADDRESS variable to the address of your deployed Oracle:

typescript
复制代码
import { ActionFn, Context, Event, TransactionEvent } from '@tenderly/actions';
import { ethers } from 'ethers';
import CoinOracleContract from './CoinOracleContract.json';

const CONTRACT_ADDRESS = '...'; // replace with contract address

export const coinPrice: ActionFn = async (context: Context, event: Event) => {
  let transactionEvent = event as TransactionEvent;

  const ifc = new ethers.utils.Interface(CoinOracleContract.abi);

  const { data, topics } = transactionEvent.logs[0];
  const priceRequest = ifc.decodeEventLog('RequestCoinPrice', data, topics);
  const price = await getPrice();

  const oc = await oracleContract(context, ifc);

  await oc.update(priceRequest.reqId, price, {
    gasLimit: 250000,
    gasPrice: ethers.utils.parseUnits('100', 'gwei'),
  });
  console.log(`Processed: ${priceRequest.reqId} with price in cents: ${price}`);
};

const getPrice = async (coin: string) => {
  const coinInfo = await axios.get(`https://api.coingecko.com/api/v3/coins/${coin}`);
  return coinInfo.data.market_data.current_price.usd * 100;
};

const oracleContract = async (context: Context, contractInterface: ethers.utils.Interface) => {
  const etherscanApiKey = await context.secrets.get('oracle.providerApiKey');

  const provider = ethers.getDefaultProvider(ethers.providers.getNetwork(3), {
    etherscan: etherscanApiKey,
  });

  const oracleWallet = new ethers.Wallet(
    await context.secrets.get('oracle.addressPrivateKey'),
    provider,
  );

  const contract = new ethers.Contract(CONTRACT_ADDRESS, contractInterface, oracleWallet);
  return contract;
};

Our Web3 Action will call the CoinGecko API using Axios in getPrice. The result will be the price in cents, which we'll send back to our smart contract.
4. Specify When Your Web3 Action Gets Executed: We want to execute the transaction every time the RequestCoinPrice event is fired by the OracleContract on the Ropsten network. Replace YOUR_USERNAME and YOUR_PROJECT_SLUG with your Tenderly username and project slug, and CONTRACT_ADDRESS with the address of your deployed Oracle Contract:

yaml
复制代码
account_id: ''
actions:YOUR_USERNAME/YOUR_PROJECT_SLUG:runtime: v1sources: actionsspecs:coinOracle:description: Swapitfunction: coinOracle:coinPricetrigger:type: transactiontransaction:status:- minedfilters:- network: 3eventEmitted:contract:address: CONTRACT_ADDRESSname: RequestCoinPrice
project_slug: ''

5. Create Web3 Action Secrets: For Web3 Actions to perform operations on the deployed OracleContract, we need a way to access the contract. Choose any provider service (Infura, QuickNode, Alchemy, Etherscan, etc.). Since we're using Etherscan as the provider, we only need the API key, which will be stored in Web3 Actions Secrets.
Head over to your Tenderly Dashboard to place the private key in Web3 Actions Secrets. From the sidebar, go to "Actions," click "Secrets," and then "Add New." Name the secret oracle.providerApiKey and paste the API token and any other sensitive information you need.
Store the Oracle Wallet Private Key in a new Secret called w3_oracle.oracle_address_private_key and paste the private key.
6. Deploy Your Web3 Action: Go to the root of your project (folder containing the tenderly.yaml file) and run:

bash
复制代码
tenderly actions deploy

After the CLI shows a successful deployment, check the Tenderly Dashboard to see your Web3 Action deployment.
7. Execute the Project: To check if everything is working, head back to Remix and invoke the doSomethingSmart function of the SimpleCoinConsumer contract. After a while, you should see an execution in the Execution tab in your Tenderly Dashboard and a new transaction from the oracle's address by your Web3 Action, calling the update function of the OracleContract.

Conclusion

Building a custom Web3 oracle using Tenderly Web3 Actions is a powerful way to bridge real-world data with blockchain applications. Through this tutorial, you have learned how to:

  1. Deploy Smart Contracts: Set up and deploy the CoinOracle and SimpleCoinConsumer contracts.
  2. Initialize Web3 Actions: Use Tenderly CLI to create and configure a project directory for Web3 Actions.
  3. Create Web3 Actions: Develop a function that fetches data from an external API and sends it to a smart contract.
  4. Configure Execution Triggers: Set up your Web3 Action to respond to specific blockchain events.
  5. Secure Sensitive Data: Manage secrets securely within the Tenderly Dashboard.
  6. Deploy and Test: Deploy your Web3 Action and verify its functionality through the Tenderly Dashboard.

By following these steps, you have created an oracle capable of fetching and sending real-time data to your smart contracts, enabling dynamic and responsive blockchain applications. This setup can be extended and customized to integrate various data sources, enhancing the functionality and intelligence of your decentralized applications.

You can earn more by using the best exchange: Binance, Gate.io, and OKX.

BULB: The Future of Social Media in Web3

Learn more

Enjoy this blog? Subscribe to 666

1 Comment