Skip to content

Using Hardhat

Overview

Hardhat is a popular development framework for building and testing smart contracts on the Waterfall network. It is an open-source development environment that provides a wide range of tools and features for developers to write, compile, test, and deploy smart contracts.

Some of the key features of Hardhat include:

  • A built-in testing framework that allows developers to write automated tests for their smart contracts
  • A console that allows developers to interact with the Waterfall network and test their smart contracts in a sandboxed environment
  • A built-in gas profiler that helps developers optimize their smart contracts for gas usage (processing fees for transactions on the Waterfall network)
  • A scriptable deployment system that makes it easy to deploy smart contracts to multiple networks and environments
  • Integration with popular development tools and services, such as Truffle, Remix, and more.

Hardhat has become a popular choice for Waterfall developers because it provides a robust set of tools and features for developing smart contracts. It is highly customizable and extensible, allowing developers to add their own plugins and libraries to the framework. It also has a large and active community of developers who contribute to its ongoing development and provide support to other users.

Installation

  1. Refer to the installation instructions to install NodeJS.
  2. Refer to the installation instructions to install Hardhat.

Create Project

  1. Create a new directory for your Hardhat project:
    mkdir HelloWaterfall
    cd HelloWaterfall
    
  2. Create Hardhat project
    npx hardhat
    
  3. Install @nomicfoundation/hardhat-toolbox
    npm install --save-dev hardhat@2.17.2 @nomicfoundation/hardhat-toolbox@3.0.0
    
  4. Create HelloWaterfall.sol file in contracts directory and paste example contract from solidity documentation site
    // SPDX-License-Identifier: GPL-3.0
    pragma solidity ^0.8.4;
    
    contract Coin {
        // The keyword "public" makes variables
        // accessible from other contracts
        address public minter;
        mapping(address => uint) public balances;
    
        // Events allow clients to react to specific
        // contract changes you declare
        event Sent(address from, address to, uint amount);
    
        // Constructor code is only run when the contract
        // is created
        constructor() {
            minter = msg.sender;
        }
    
        // Sends an amount of newly created coins to an address
        // Can only be called by the contract creator
        function mint(address receiver, uint amount) public {
            require(msg.sender == minter);
            balances[receiver] += amount;
        }
    
        // Errors allow you to provide information about
        // why an operation failed. They are returned
        // to the caller of the function.
        error InsufficientBalance(uint requested, uint available);
    
        // Sends an amount of existing coins
        // from any caller to an address
        function send(address receiver, uint amount) public {
            if (amount > balances[msg.sender])
                revert InsufficientBalance({
                    requested: amount,
                    available: balances[msg.sender]
                });
    
            balances[msg.sender] -= amount;
            balances[receiver] += amount;
            emit Sent(msg.sender, receiver, amount);
        }
    }
    

Compile and deploy script

  1. Compile contracts
    npx hardhat compile
    
  2. Create 1-deploy.js file in scripts directory
  3. Past next code:
    // We require the Hardhat Runtime Environment explicitly here. This is optional
    // but useful for running the script in a standalone fashion through `node <script>`.
    //
    // You can also run a script with `npx hardhat run <script>`. If you do that, Hardhat
    // will compile your contracts, add the Hardhat Runtime Environment's members to the
    // global scope, and execute the script.
    const hre = require("hardhat");
    
    async function main() {
      const coin = await hre.ethers.deployContract("Coin")
      await coin.waitForDeployment();
    
       console.log(
         `Coin contract has been deployed to ${coin.target}`
       );
    }
    
    // We recommend this pattern to be able to use async/await everywhere
    // and properly handle errors.
    main().catch((error) => {
      console.error(error);
      process.exitCode = 1;
    });
    

Check contracts in console mode

Go to the develop console

npx hardhat console

  1. Deploy contract
    > const coin = await hre.ethers.deployContract("Coin");
    > await coin.waitForDeployment();
    > coin.target
    '0x5FbDB2315678afecb367f032d93F642f64180aa3'
    
  2. Check minter
    > await coin.minter()
    '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'
    
  3. Check balance
    > let balance = await coin.balances('0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266')
    0n
    
  4. Mint token
    > await coin.mint('0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', 1000)
    {
      hash: '0xfebba42b2e3b622e4bb1a29eb9af581932e82529200d5b56f94227fa215a2d02',
      type: 2,
      accessList: [],
      blockHash: '0x5f357049b83b711097bd8bdeb6dd714c150dba1fb70c952198fb9881c88570d1',
      blockNumber: 3,
      transactionIndex: 0,
      confirmations: 1,
      from: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
      gasPrice: BigNumber { value: "1672815059" },
      maxPriorityFeePerGas: BigNumber { value: "1000000000" },
      maxFeePerGas: BigNumber { value: "2345630118" },
      gasLimit: BigNumber { value: "29022936" },
      to: '0x5FbDB2315678afecb367f032d93F642f64180aa3',
      value: BigNumber { value: "0" },
      nonce: 2,
      data: '0x40c10f19000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb9226600000000000000000000000000000000000000000000000000000000000003e8',
      r: '0x9c3dc425f7af56a6bb6af270a3bdb8fc4076ae2fe60f4cc9c08c1239ded55848',
      s: '0x22de01f21695480f2e57dfd7858decc1fa17849198416b7a72d3ea1dae742f90',
      v: 1,
      creates: null,
      chainId: 31337,
      wait: [Function (anonymous)]
    }
    
  5. Check balance
    > balance = await coin.balances('0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266')
    1000n
    

Deploy to Waterfall Network

  1. Go to Networks - RPC Endpoints page and check params
  2. Add Waterfall Network to hardhat.config.js file
    require("@nomicfoundation/hardhat-toolbox"); 
    
    networks: {
      waterfall: {
        url: "https://rpc.testnet9.waterfall.network",
        chainId: 1501869,
        accounts: ['07201008f00b31de405a0af22ff04871044e027878929b7b47569ca76555ff09'], // Private key from your account
        from: '0xa7062A2Bd7270740f1d15ab70B3Dee189A87b6DE' // Your Deployer Account
      }
    }
    
  3. Deploy contract
    npx hardhat run --network waterfall scripts/1-deploy.js