Skip to content

Latest commit

 

History

History
284 lines (197 loc) · 7.64 KB

Hardhat.md

File metadata and controls

284 lines (197 loc) · 7.64 KB

HARDHAT️‍🔥

  • artifacts folder in our root directory contains our smart contract abi array.
  • Hardhat comes built-in with Hardhat Network, a local Ethereum network designed for development.
  • It allows you to deploy your contracts, run your tests and debug your code, all within the confines of your local machine

INSTALLING HARDHAT AND INITIALLIZING PROJECT

npm init
npm install --save-dev hardhat
npx hardhat init
npm i --save @openzeppelin/contracts
npm install --save-dev @nomicfoundation/hardhat-toolbox

Compiling contracts

  • Start by creating a new directory called contracts and create a file inside the directory called Web3.sol
npx hardhat compile

Testing contracts

Note : Hardhat will run every *.js file in test/

  • Start the testing using following command :
npx hardhat test
  • We will use Ether.js and Mocha-Chai for our testing.
  • Mocha-Chai is popular JavaScript assertion library
// installing ether.js and mocha
npm install ethers
npm install --save-dev mocha
  • Create a new directory called test inside our project root directory and create a new file in there called web3test.js
  • To test our contract, we are going to use Hardhat Network, a local Ethereum network designed for development.
//  test/web3test.cjs
const { expect } = require("chai");
const { ethers } = require("hardhat");
const assert = require("assert");

describe("Token contract", function () {
  // first test check
  it("Deployment should assign the total supply of tokens to the owner", async function () {
    // RETURNS THE ETHEREUM ACCOUNT.
    // And, this account will execute the deployment
    const [owner, addr1, addr2] = await ethers.getSigners();

    // start the deployment of our token contract
    // return a Promise that resolves to a Contract
    // This is the contract intance that has a method for each of your smart contract functions.
    const token = await ethers.deployContract("Web3");

    // Once contract is deployed, we can call contract methods using contract instance(token).
    // the account in the owner variable executed the deployment,
    const ownerBalance = await token.balanceOf(owner.address);

    // Here, the token's supply amount and we're checking that it's equal to ownerBalance, as it should be.
    // We have used expect(...) function from Mocha-chai to compare
    expect(await token.totalSupply()).to.equal(ownerBalance);

    //   either we can use expect(...) method or assert.equal(...) method
    assert.equal(await toke.totalSupply(), ownerBalance);
  });
});
  • Above, we can use either use expect(...) or assert.equal(...) method
Reusing common test setups with fixtures
  • This setup could involve multiple deployments and other transactions.

  • Doing that in every test means a lot of code duplication.

  • Plus, executing many transactions at the beginning of each test can make the test suite much slower.

  • To can avoid code duplication and improve the performance of your test suite we can use fixtures

  • A fixture is a setup function that is run only the first time it's invoked.

  • On every invocationshardhat will reset the state of networks.

const {
  loadFixture,
} = require("@nomicfoundation/hardhat-toolbox/network-helpers");
const { expect } = require("chai");
const assert = require("assert");
const { ethers } = require("hardhat");

describe("Token contract", function () {
  // deploy token fixtures
  async function deployTokenFixture() {
    const [owner, addr1, addr2] = await ethers.getSigners();

    const token = await ethers.deployContract("Token");
    await token.waitForDeployment();

    // Fixtures can return anything you consider useful for your tests
    return { token, owner, addr1, addr2 };
  }

  // first test check
  it("Deployment should assign the total supply of tokens to the owner", async function () {
    // for every test now we can use fixture instead of redepolying contract.
    const { token, owner } = await loadFixture(deployTokenFixture);

    const ownerBalance = await token.balanceOf(owner.address);
    expect(await token.totalSupply()).to.equal(ownerBalance);
    assert.equal(await token.name(), "ERC721");
  });

  // second test check
  it("Test function", async function () {
    const { token, owner } = await loadFixture(deployTokenFixture);
    // ...rest of code
  });
});

Note : To know more testing methods read hardhat testing docs (you know!!!)

Debugging with Hardhat Network

  • For debugging we will use console.log() in soilidity similar to JS.
  • you can print logging messages and contract variables from your Solidity code.
// contract/Web3.sol
import "hardhat/console.sol";

contract TestContract {
    // some code ...
    function publicMint() public payable{
        console.log("Amount transfer :", msg.value);
        // rest of code...
    }
}
  • Lastly, run npx hardhat test to seee the result of debugging in terminal.

Deploying to a live network

  • To run deploy our smart contract use following code:
// THIS INITITALIZE AN RPC SERVER
npx hardhat node

// DEPLOYING ON LOCALHOST
npx hardhat ignition deploy ./ignition/modules/deploy.cjs --network localhost

// DEPLOYING ON TESTNET
npx hardhat ignition deploy ./ignition/modules/deploy.cjs --network sepolia
  • In Hardhat, deployments are defined through Ignition Modules.
  • Ignition modules are written inside ./ignition/modules directory.
// ./ignition/modules/deploy.js
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules");

const TokenModule = buildModule("TokenModule", (m) => {
    // constructor params
    const entranceFee = 1_000_000_000n; // 0.01 ETH
    const interval = 30; // 30 seconds
    const initialOwner = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"; 

    const token = m.contract("Web3",[entranceFee,interval,initialOwner]);

  return { token };
});

module.exports = TokenModule;
  • Now to deploy our smart contract we will initialize an RPC server locally in our terminal(port:8545)
  • We need to modify our hardhat.config.js file.
// hardhat.config.js

require("@nomicfoundation/hardhat-toolbox");
const { vars } = require("hardhat/config");

// SET YOUR API KEY IN VARS AND NOT IN .ENV
// npx hardhat vars set API_KEY_NAME

const INFURA_API_KEY = vars.get("INFURA_API_KEY");
const PRIVATE_KEY = vars.get("PRIVATE_KEY");

module.exports = {
  solidity: "0.8.27",
  networks: {
    sepolia: {
      url: `https://sepolia.infura.io/v3/${INFURA_API_KEY}`,
      accounts: [PRIVATE_KEY],
    },
  },
  etherscan: {
    apiKey: vars.get("ETHERSCAN_ID"),
  },
  sourcify: {
    enabled: true,
  },
};
  • Here, we are using Infura blockchain node provider

Store your API_KEY

  • We will store our API_KEY, private_key and seed-phrase in var and not in .env/.env.local
// RUN THE FOLLOWING COMMAND TO STORE THE KEY IN VAR
npx hardhat vars set API_KEY_NAME


// hardhat.config.cjs
const { vars } = require("hardhat/config");
const INFURA_API_KEY = vars.get("INFURA_API_KEY");
const PRIVATE_KEY = vars.get("PRIVATE_KEY");

Verify Smart Contract on etherscan

// 1.
npx hardhat verify --network sepolia DEPLOYED_CONTRACT_ADDRESS
// 2.
npx hardhat ignition verify sepolia-deployment

SENDING ETH FROM FRONTEND

  • On frontend, if we need to send ether to contract :
await lottery.methods.sendSomeEthToContract().send({
    from:account,
    value:web3.utils.toWei('0.001','ether'),
    gas:"300000",
    gasPrice:undefined
});
  • Always, the balance is returned in wei(10^18). To convert in ETH:
// this will convert wei -> eth
const weiToEth = web3.utils.toWei('0.01','ether');