Deploy a contract with Hardhat

Hardhat is one of the popular smart contract development frameworks. It is the ZKFair’s preferred framework, and therefore used in the ZKFair as a default for deploying and automatically verifying smart contracts.

This document is a guide on how to deploy a smart contract on the ZKFair network using Hardhat.

Hardhat smart contract

  • mkdir <project-name>;cd <project-name>

  • Initialize a project with Hardhat: npx hardhat.

  • Next, (… To avoid failure … please go slow with this cli dialogue…),

    So then,

  • Press <ENTER> to set the project root.

  • Press <ENTER> again to accept addition of .gitignore.

  • Type n to reject installing sample project's dependencies.

    The idea here is to postpone installing dependencies to later steps due to a possible version-related bug.

  • Open the hardhat.config.js file and paste the below code:

    /** @type import('hardhat/config').HardhatUserConfig */
    module.exports = {
    solidity: "0.8.9",
    paths: {
        artifacts: "./src",
    networks: {
        zkEVM: {
        url: ``,
        accounts: [process.env.ACCOUNT_PRIVATE_KEY],

    Note that a different path to artifacts is added so that the React app will be able to read the contract ABI within the src folder.

Add scripts

  • Create a new file, in the contracts folder, named Counter.sol: touch contracts/Counter.sol.

  • Copy the below code and paste it in the Counter contract code:

    //SPDX-License-Identifier: MIT
    pragma solidity ^0.8.9;
    contract Counter {
    uint256 currentCount = 0;
        function increment() public {
            currentCount = currentCount + 1;
        function retrieve() public view returns (uint256){
            return currentCount;
  • Create a new file in the scripts folder deploy-counter.js: touch scripts/deploy-counter.js.

  • Add the code below to the deploy-counter.js file:

    const hre = require("hardhat");
    async function main() {
        const deployedContract = await hre.ethers.deployContract("Counter");
        await deployedContract.waitForDeployment();
            `Counter contract deployed to${}`
    main().catch((error) => {
        process.exitCode = 1;
  • Before compiling the contract, you need to install the toolbox. You may need to change directory to install outside the project. Use this command:

    npm install --save-dev @nomicfoundation/hardhat-toolbox
  • Compile your contract code (i.e., go back to the project root in the CLI):

    npx hardhat compile
  • Now run the scripts:

    npx hardhat run scripts/deploy-counter.js --network zkEVM

    ​Here’s an output example:

    Counter contract deployed to

Update frontend

The next step is to turn Counter.sol into a dApp by importing the ethers and the Counter file, as well as logging the contract’s ABI.

  • Include the below code in the App.js file:

    import { ethers } from "ethers";
    import Counter from "./contracts/Counter.sol/Counter.json";
    const counterAddress = "your-contract-address"
    console.log(counterAddress, "Counter ABI: ", Counter.abi);
  • Update the counterAddress to your deployed address.

    • It is the hexadecimal number found at the tail-end of the output of the last npx hardhat run ... command and looks like this 0x5FbDB2315678afecb367f032d93F642f64180aa3.

    • It must be pasted in the App.js to replace your-contract-address. Be sure to use the deployed address from your own implementation!

  • Update frontend counter to read from blockchain. Include the below code in the App.js file:

    useEffect(() => {
        // declare the data fetching function
        const fetchCount = async () => {
        const data = await readCounterValue();
        return data;
    }, []);
    async function readCounterValue() {
        if (typeof window.ethereum !== "undefined") {
            const provider = new ethers.providers.Web3Provider(window.ethereum);
            console.log("provider", provider);
            const contract = new ethers.Contract(
            console.log("contract", contract);
            try {
                const data = await contract.retrieve();
                console.log("data: ", parseInt(data.toString()));
            } catch (err) {
                console.log("Error: ", err);
                    "Switch your MetaMask network to ZKFair Testnet and refresh this page!"
  • Also, to import useEffect, insert it like this:

    import { useState, useEffect } from "react";
  • To be able to track a loader, add this to your state:

    const [isLoading, setIsLoading] = useState(false);
    • This is within the App() function.

  • Let frontend counter write to the blockchain by adding the below requestAccount and updateCounter functions:

    async function requestAccount() {
    await window.ethereum.request({ method: "eth_requestAccounts" });
    async function updateCounter() {
    if (typeof window.ethereum !== "undefined") {
        await requestAccount();
        const provider = new ethers.providers.Web3Provider(window.ethereum);
        console.log({ provider });
        const signer = provider.getSigner();
        const contract = new ethers.Contract(counterAddress, Counter.abi, signer);
        const transaction = await contract.increment();
        await transaction.wait();

    Place these two functions above the readCounterValue() function in the App.js file.

  • Replace the incrementCounter function with this one:

    const incrementCounter = async () => {
    await updateCounter();
  • Update the increment button code to:

    {isLoading ? "loading..." : "+1"}

Now, run the Counter dApp by simply using npm start in CLI at the project root.

Congratulations for reaching this far. You have successfully deployed a dApp on the ZKFair testnet.

Last updated