- 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
npm init
npm install --save-dev hardhat
npx hardhat init
npm i --save @openzeppelin/contracts
npm install --save-dev @nomicfoundation/hardhat-toolbox
- Start by creating a new directory called contracts and create a file inside the directory called Web3.sol
npx hardhat compile
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
-
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!!!)
- 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.
- 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
- 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");
// 1.
npx hardhat verify --network sepolia DEPLOYED_CONTRACT_ADDRESS
// 2.
npx hardhat ignition verify sepolia-deployment
- 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');