đˇCreate Your First dAPP using Hardhat
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
.

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 Hardhat Toolbox, a plugin that bundles all the things you need to start working with Hardhat.

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
Contract Initialization:
The
Example
contract imports the necessary modules from the Sight Oracle package.The contract uses the
RequestBuilder
library to construct requests and theResponseResolver
library to interpret the responses.
Constructor:
The constructor initializes the contract with the address of the Sight Oracle. This address is used to send requests and handle callbacks.
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.
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.
Modifiers:
onlyOracle
: Ensures that only the Sight Oracle can call thecallback
function.
View Function:
getLatestReqId
: Retrieves the request ID of the most recent request sent to theOracle
.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.
If you donât have a Sepolia RPC yet, you can click here to require one.
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 thedotenv
dependency and then import it usingrequire("dotenv").config()
inhardhat.config.js
.hardhat-deploy
is a powerful deployment plugin for Hardhat that provides a more structured and repeatable way to deploy smart contracts. Click here to learn more.
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 thedeploy
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 aModuleBuilder
, 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.
Last updated