# Create Your First dAPP using Hardhat

**Prerequisites**

* [NodeJS](https://nodejs.org/en)
* [Metamask](https://metamask.io/)

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:

```sh
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`.

<figure><img src="https://4239479252-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fc6n88IVs810uKFVbVyUQ%2Fuploads%2FTwOzwPR5rchUufIHC8eM%2F%E6%88%AA%E5%B1%8F2024-10-24%2013.04.13.png?alt=media&#x26;token=099440fb-c782-48bc-a151-73713cff8f8a" alt=""><figcaption></figcaption></figure>

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](https://hardhat.org/hardhat-runner/plugins/nomicfoundation-hardhat-toolbox), a plugin that bundles all the things you need to start working with Hardhat.

<figure><img src="https://4239479252-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fc6n88IVs810uKFVbVyUQ%2Fuploads%2FFDrV5IHiuO8jBQ3jbml5%2F%E6%88%AA%E5%B1%8F2024-10-24%2013.07.02.png?alt=media&#x26;token=c0500bb0-aeb2-4eb9-a179-205efe7302ed" alt=""><figcaption></figcaption></figure>

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.

<pre class="language-sh"><code class="lang-sh"><strong>npm install --save-dev @sight-oracle/contracts @openzeppelin/contracts
</strong></code></pre>

### Writing Contract

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

```solidity
// 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 <a href="#compiling-your-contracts" id="compiling-your-contracts"></a>

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

```sh
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.

<figure><img src="https://4239479252-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fc6n88IVs810uKFVbVyUQ%2Fuploads%2FKXZ53NDYhsqQRBEn8gtC%2F%E6%88%AA%E5%B1%8F2024-10-24%2014.31.37.png?alt=media&#x26;token=0b10e954-17d9-456d-bf2a-cb58da55a365" alt=""><figcaption></figcaption></figure>

### Deploy Contract with Script

#### Dependencies needed for installation when deployment.

```bash
npm i hardhat-deploy dotenv --save-dev
```

#### Set environment variables.

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

```properties
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](https://dashboard.alchemy.com/) 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:

```javascript
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`.
* `hardhat-deploy` is a powerful deployment plugin for Hardhat that provides a more structured and repeatable way to deploy smart contracts. Click [here](https://github.com/wighawag/hardhat-deploy) to learn more.

```javascript
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:

* `url` specifies the remote RPC address to interact with the blockchain. This address can be from a service provider like [Alchemy](https://dashboard.alchemy.com/) or [Infura](https://www.infura.io/).
* `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.

```javascript
 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.

```javascript
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.

```javascript
 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.

```sh
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!

<figure><img src="https://4239479252-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fc6n88IVs810uKFVbVyUQ%2Fuploads%2FNA8OMDrYrkUGRBidsb4I%2F%E6%88%AA%E5%B1%8F2024-11-16%2014.48.55.png?alt=media&#x26;token=bdbee264-f215-4fb3-9ec6-f3fa92f54eaa" alt=""><figcaption></figcaption></figure>

### 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`.

```javascript
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**

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

Then you will see the following output information.

<figure><img src="https://4239479252-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fc6n88IVs810uKFVbVyUQ%2Fuploads%2Ft3cWTqT7rTRFmN3yNL7C%2F%E6%88%AA%E5%B1%8F2024-11-16%2015.15.31.png?alt=media&#x26;token=2b188103-c9a2-443f-84fb-e5e3cdbfca61" alt=""><figcaption></figcaption></figure>

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