This guide walks through the complete process of building, deploying, and interacting with a simple Ethereum smart contract using Hardhat. We will cover everything from environment setup to writing a deployment and interaction script. This is a great starting point for developers looking to build decentralized applications on EVM-compatible chains such as Ethereum or LazAI Testnet. If you prefer video format you can watch the full workshop on Youtube here.
Hardhat is a powerful development environment for compiling, testing, and deploying smart contracts. With robust plugin support, a local testnet, and integration with tools like Ethers.js, it provides everything needed to develop full-stack Web3 applications.
Before starting, ensure the following are installed:
Create a new project directory and initialize npm:
mkdir counter-project
cd counter-project
npm init -y
Install Hardhat and its recommended plugins:
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox dotenv
npm install --save-dev @nomicfoundation/hardhat-ignition
When prompted, select “Create a JavaScript project.”
You should see the following structure:
contracts/
scripts/
test/
hardhat.config.js
Create Counter.sol under the contracts/ directory:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Counter {
uint256 private count;
function increment() public {
count += 1;
}
function decrement() public {
count -= 1;
}
function getCount() public view returns (uint256) {
return count;
}
}
Compile the contract:
npx hardhat compile
Hardhat Ignition provides a structured way to manage deployment modules. Create a new file ignition/modules/Counters.js:
const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules");
module.exports = buildModule("CounterModule", (m) => {
const counter = m.contract("Counter");
return { counter };
});
Create a .env file in the root directory and add your private key:
PRIVATE_KEY=your_private_key_here
Update hardhat.config.js to include the LazAI testnet configuration:
require("@nomicfoundation/hardhat-toolbox");
require("dotenv").config();
module.exports = {
solidity: "0.8.28",
networks: {
lazai: {
url: "https://testnet.lazai.network",
chainId: 133718,
accounts: [process.env.PRIVATE_KEY],
},
},
};
To deploy locally:
npx hardhat node
npx hardhat ignition deploy ignition/modules/Counters.js --network localhost
To deploy on LazAI testnet:
npx hardhat ignition deploy ignition/modules/Counters.js --network lazai
To interact with the deployed contract, create scripts/interact.js:
const { ethers } = require("hardhat");
const CONTRACT_ADDRESS = "YOUR_DEPLOYED_CONTRACT_ADDRESS_HERE";
const ABI = [
{
"inputs": [],
"name": "decrement",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "increment",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "getCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
];
async function main() {
const provider = new ethers.JsonRpcProvider("https://testnet.lazai.network");
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
const contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, wallet);
const count = await contract.getCount();
console.log("Current Count:", count.toString());
const tx1 = await contract.increment();
await tx1.wait();
console.log("Incremented.");
const tx2 = await contract.decrement();
await tx2.wait();
console.log("Decremented.");
const newCount = await contract.getCount();
console.log("Updated Count:", newCount.toString());
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Run the script:
npx hardhat run scripts/interact.js --network lazai
This project demonstrates the end-to-end process of developing a simple smart contract with Hardhat, deploying it to a test network, and interacting with it using Ethers.js. With this foundation, you can expand into more complex contracts, integrate frontend interfaces, or deploy to Mainnets.