Sight AI
  • 👋Overview
    • đŸĨFHE
    • 🍍The Problem
  • 🍇Sight Oracle
    • 💡Concepts
      • 🍉Architecture
      • 📔Contract
      • 🟠Decentralized Oracle Node Network
      • 📠FHE Compute Execution Virtual Machine
      • 📃RequestBuilder
    • ⏊Supported Networks
  • Sight Contracts
    • Getting Started
    • Understanding Request Model
  • SIGHT.JS
    • Getting Started
    • Make an encrypt value - CLI
    • Make an encrypt value - Frontend
  • â„šī¸Tutorial
    • Environment Setup
      • Prerequisite
      • Setup Local Development Environment
      • Fund Local Wallet
    • 👷Create Your First dAPP using Hardhat
    • đŸ› ī¸Create Your First dAPP using Foundry
    • 🎲Create a Crypto Pusher Game
      • Contract
      • Interface
    • 📄Remix FHE Demo Local Deployment Tutorial- Preparation
    • 📄Remix FHE Demo Local Deployment Tutorial- Deploying Contracts Using Remix
    • 📄Remix FHE Demo Local Deployment Tutorial- Contracts Explanation&Interaction
  • 🔎Research
    • ✅Verifiable FHE
    • 🌟SPARC
    • 📅Research Updates
  • 🍓Innovative Use Cases and dApps
    • đŸĨĨFHE On-Chain Game
    • A Fairer Prediction Markets with Sight Oracle
  • đŸģRoadmap
  • 🎨Community
    • Website
    • Twitter
    • Telegram
    • Github
  • Sight Incentive Plan - Season 1
  • Sight Incentive Plan - Season 2
Powered by GitBook
On this page
  • Create a new Hardhat Project
  • Writing Contract
  • Compile Contract
  • Deploy Contract with Script
  • Deploy Contract with Ignition
  1. Tutorial

Create Your First dAPP using Hardhat

PreviousFund Local WalletNextCreate Your First dAPP using Foundry

Last updated 6 months ago

Prerequisites

Hardhat projects are Node.js projects with the hardhat package installed and a hardhat.config.js file.

Create a new Hardhat Project

Download hardhat

npm install --save-dev hardhat

After the installation is successful, next, create a simple Hardhat project. Run the following commands:

mkdir my_contract
cd my_contact
npx hardhat init

Let’s choose create a JavaScript or TypeScript project. We recommend choosing TypeScript, but if you’re not familiar with it, simply select JavaScript.

The initialized project has the following structure:

contracts/
ignition/modules/
test/
hardhat.config.js

These are the default paths for a Hardhat project.

  • contracts/ is where the source files for your contracts should be.

  • ignition/modules/ is where the Ignition modules that handle contract deployments should be.

  • test/ is where your tests should go.

  • hardhat.config.js is used for project configuration, such as blockchain network settings, contract compilation version settings, and more.

Install Sight Oracle and openzeppelin dependency.

npm install --save-dev @sight-oracle/contracts @openzeppelin/contracts

Writing Contract

In the src directory, create a new file named Example.sol, and copy the example contract code below into contracts/Example.sol.

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import "@sight-oracle/contracts/Oracle/Types.sol";
import "@sight-oracle/contracts/Oracle/Oracle.sol";
import "@sight-oracle/contracts/Oracle/RequestBuilder.sol";
import "@sight-oracle/contracts/Oracle/ResponseResolver.sol";

contract Example {
    // Use Sight Oracle's RequestBuilder and ResponseResolver to interact with Sight Oracle
    using RequestBuilder for Request;
    using ResponseResolver for CapsulatedValue;

    event OracleCallback(bytes32 indexed reqId);

    bytes32 latestReqId;
    Oracle public oracle;
    CapsulatedValue private _target;

    constructor(address oracle_) payable {
        oracle = Oracle(payable(oracle_));
    }

    function makeRequest() public payable {
        // Initialize new FHE computation request of a single step.
        Request memory r = RequestBuilder.newRequest(
            msg.sender,
            1,
            address(this),
            this.callback.selector, // specify the callback for Oracle
            ""
        );

        // Generate a random encrypted value and store in Sight Network
        r.rand();

        // Send the request via Sight FHE Oracle
        latestReqId = oracle.send(r);
    }

    // only Oracle can call this
    function callback(
        bytes32 reqId,
        CapsulatedValue[] memory values
    ) public onlyOracle {
        // Decode value from Oracle callback
        CapsulatedValue memory result = values[0];

        // Keep this encrypted target value
        _target = result;
        emit OracleCallback(reqId);
    }

    function getLatestReqId() public view returns (bytes32) {
        return latestReqId;
    }

    function getTarget() public view returns (CapsulatedValue memory) {
        return _target;
    }

    modifier onlyOracle() {
        require(msg.sender == address(oracle), "Only Oracle Can Do This");
        _;
    }
}

Explanation

  1. Contract Initialization:

    • The Example contract imports the necessary modules from the Sight Oracle package.

    • The contract uses the RequestBuilder library to construct requests and the ResponseResolver library to interpret the responses.

  2. Constructor:

    • The constructor initializes the contract with the address of the Sight Oracle. This address is used to send requests and handle callbacks.

  3. makeRequest Function:

    • This function initiates a new request to the Sight Oracle.

    • A new request is created using RequestBuilder.newRequest, specifying the sender, the number of steps in the computation, the address to which the callback should be sent, and the callback function.

    • The rand function is called to generate a random encrypted value and store it in the Sight Network.

    • The send function sends the request to the Sight Oracle.

  4. callback Function:

    • This function is called by the Sight Oracle once the computation is complete.

    • It decodes the returned value using the ResponseResolver and stores the encrypted target value in the _target variable.

  5. Modifiers:

    • onlyOracle: Ensures that only the Sight Oracle can call the callback function.

  6. View Function:

    • getLatestReqId: Retrieves the request ID of the most recent request sent to the Oracle.

    • getTarget: Retrieves the target value of the most recent request.

Compile Contract

To compile Example contracts in your Hardhat project, use the built-in compile task:

npx hardhat compile

After a successful compilation, some new files will be generated in our project directory. The cache/ directory contains cache files. The artifacts/ directory’s build-info folder stores information about the build process. The artifacts/contracts folder contains the ABI interface information for each compiled contract.

Deploy Contract with Script

Dependencies needed for installation when deployment.

npm i hardhat-deploy dotenv --save-dev

Set environment variables.

Create a .env file in the root directory and set the following environment variables:

PRIVATE_KEY=<YOUR_PRIVATE_KEY>
SEPOLIA_RPC_URL=<SEPOLIA_RPC_URL>
SEPOLIA_ORACLE_CONTRACT_ADDRESS=0xC5ac65f17Ce781E9F325634b6218Dc75a5CF9abF

SEPOLIA_ORACLE_CONTRACT_ADDRESS is the Oracle address we have deployed on the Sepolia test network.

Note: You can get the private key through MetaMask by going to Account Details => Export Private Key (Please use a test wallet, as leaking the private key poses a risk of account theft!).

network configuration

Add the following code to the hardhat.config.js file:

require("@nomicfoundation/hardhat-toolbox");
require("dotenv/config");
require("hardhat-deploy");

/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
  solidity: {
    version: "0.8.27",
  },
  defaultNetwork: "hardhat",
  networks: {
    hardhat: {},
    sepolia: {
      url: process.env.SEPOLIA_RPC_URL,
      accounts: [process.env.PRIVATE_KEY],
      chainId: 11155111,
    },
  },
  namedAccounts: {
    deployer: {
      default: 0,
    },
  },
};

Explanation:

The first three lines import the necessary dependencies:

  • @nomicfoundation/hardhat-toolbox is the toolkit recommended by Hardhat officially.

  • To use .env environment variables, you must first install the dotenv dependency and then import it using require("dotenv").config() in hardhat.config.js.

defaultNetwork: "hardhat",
  networks: {
    hardhat: {},
    sepolia: {
      url: process.env.SEPOLIA_RPC_URL,
      accounts: [process.env.PRIVATE_KEY],
      chainId: 11155111,
    },
  },

This code sets the default network to the hardhat local simulation network, and we also additionally configure the sepolia network:

  • accounts can be an array of multiple private keys, used for blockchain access and interaction.

  • chainId is a unique ID for the Sepolia test network, used to identify the network.

 namedAccounts: {
    deployer: {
      default: 0,
    },
  },

This section defines an account named deployer, which by default uses the first account (index 0) from the account list.

Write a deployment script.

Create a file named deploy/deploy-example.js in the root directory.

module.exports = async ({ getNamedAccounts, deployments }) => {
  const { deploy, log } = deployments;
  const { deployer } = await getNamedAccounts();

  log("------------------- deploying ------------------");
  const example = await deploy("Example", {
    from: deployer,
    args: [process.env.SEPOLIA_ORACLE_CONTRACT_ADDRESS],
    log: true,
    waitConfirmations: 1,
  });
  log("Example deployed, address is: ", example.address);
};

module.exports.tags = ["all", "example"];
  • getNamedAccounts is a function used to retrieve named accounts (such as deployer), which are typically specified in the Hardhat configuration file.

  • deployments provides various deployment-related functionalities (like the deploy function), which can be used to deploy contracts and record deployment information.

 const example = await deploy("Example", {
    from: deployer,
    args: [process.env.SEPOLIA_ORACLE_CONTRACT_ADDRESS],
    log: true,
    waitConfirmations: 1,
 });

This code use the address of the Oracle contract as a parameter for the Example contract. deploy() function is used to deploy contracts, where the first parameter is the name of the contract, which must already exist in the project. The second parameter is an object, and its properties are as follows:

  • from: Specifies which account to use for deploying the contract.

  • args: []: The constructor arguments for the contract.

  • log: Indicates whether to print deployment logs.

  • waitConfirmations: Waits for 1 block confirmation to ensure the deployment is on-chain.

Then execute hardhat deploy to carry out the deployment.

npx hardhat deploy --network sepolia

Wait for about a minute, and you should see the printed information as below. Congratulations! You have successfully deployed a Example contracts on the Sepolia test network in Hardhat!

Deploy Contract with Ignition

In this section, we’ll using Hardhat Ignition to deploy a smart contract. Ignition is a deployment manager provided by Hardhat that simplifies contract deployment and configuration.

You can copy this code in /ignition/modules/Example.js.

const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules");
const hre = require("hardhat");

const ExampleModule = buildModule("ExampleModule", (m) => {
  const networkName = hre.network.name;
  console.log(`Deploying to network: ${networkName}`);
  const oracleContractAddress = process.env.SEPOLIA_ORACLE_CONTRACT_ADDRESS;

  const Example = m.contract("Example", [oracleContractAddress]);

  m.call(Example, "makeRequest");

  return { Example };
});

module.exports = ExampleModule;

Explanation

  • buildModule: The first aspect to note is that modules are created by calling the buildModule function, which requires a module ID and a callback function. Our module will be identified as "ExampleModule".

  • m: The m parameter being passed into the callback is an instance of a ModuleBuilder, which is an object with methods to define and configure your smart contract instances.

  • m.contract("Example", [oracleContractAddress]): Deploys the Example contract and passes the Oracle address as a constructor parameter.

  • m.call(Example, "makeRequest"): It will invoke the makeRequest function within the Example contract.

Run the deployment script

npx hardhat ignition deploy ignition/modules/Example.js --network sepolia

Then you will see the following output information.

Congratulations, you have successfully deployed the contract and sent a request to the Oracle.

Select Create a JavaScript project, a simple project creation wizard will ask you some questions. After that, the wizard will create some directories and files and install the necessary dependencies. The most important of these dependencies is the , a plugin that bundles all the things you need to start working with Hardhat.

If you don’t have a Sepolia RPC yet, you can click to require one.

hardhat-deploy is a powerful deployment plugin for Hardhat that provides a more structured and repeatable way to deploy smart contracts. Click to learn more.

url specifies the remote RPC address to interact with the blockchain. This address can be from a service provider like or .

â„šī¸
👷
Hardhat Toolbox
here
here
Alchemy
Infura
NodeJS
Metamask