# Hardhat Setup Guide — Professional Solidity Development
Hardhat modern Ethereum development का industry standard बन गया है। TypeScript support, powerful testing framework, और rich plugin ecosystem के साथ, यह professional teams और solo developers दोनों के लिए ideal है। इस comprehensive guide में, हम scratch से Hardhat project setup करेंगे, tests लिखेंगे, और contracts deploy करेंगे।
Hardhat क्यों चुनें?
Hardhat के फायदे:
- ✅ TypeScript-first — Type safety और better IDE support
- ✅ Fast compilation — Incremental compilation smart contracts के लिए
- ✅ Rich testing — Mocha, Chai, और Waffle के साथ
- ✅ Debugging — Console.log directly Solidity में
- ✅ Plugin ecosystem — Etherscan verification, gas reporting, coverage, etc.
- ✅ Local network — Built-in Ethereum node testing के लिए
- ✅ Mainnet forking — Test against live blockchain state
- ✅ Active development — Regular updates और improvements
Prerequisites
आपको चाहिए:
- Node.js (v16+ recommended)
- npm या yarn
- Basic command line knowledge
- Text editor (VS Code recommended)
Installation Check
node --version # Should be v16 or higher
npm --version # Should be 8 or higher
Project Setup
Step 1: नया Project बनाएं
mkdir my-hardhat-project
cd my-hardhat-project
npm init -y
Step 2: Hardhat Install करें
npm install --save-dev hardhat
Step 3: Hardhat Project Initialize करें
npx hardhat init
Prompts:
? What do you want to do?
> Create a JavaScript project
Create a TypeScript project
Create an empty hardhat.config.js
? Do you want to install dependencies? Yes
TypeScript project चुनें (recommended):
npm install --save-dev @nomicfoundation/hardhat-toolbox
Step 4: Project Structure
Initialization के बाद:
my-hardhat-project/
├── contracts/ # Solidity contracts
│ └── Lock.sol # Sample contract
├── scripts/ # Deployment scripts
│ └── deploy.ts
├── test/ # Test files
│ └── Lock.ts
├── hardhat.config.ts # Hardhat configuration
├── package.json
└── tsconfig.json
अपना पहला Contract लिखना
Contract: SimpleToken.sol
contracts/SimpleToken.sol में नई file बनाएं:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
contract SimpleToken {
string public name = "Simple Token";
string public symbol = "SMP";
uint8 public decimals = 18;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
constructor(uint256 _initialSupply) {
totalSupply = _initialSupply * 10**uint256(decimals);
balanceOf[msg.sender] = totalSupply;
}
function transfer(address _to, uint256 _value) public returns (bool) {
require(_to != address(0), "Invalid address");
require(balanceOf[msg.sender] >= _value, "Insufficient balance");
balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;
emit Transfer(msg.sender, _to, _value);
return true;
}
function approve(address _spender, uint256 _value) public returns (bool) {
allowance[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
require(_to != address(0), "Invalid address");
require(balanceOf[_from] >= _value, "Insufficient balance");
require(allowance[_from][msg.sender] >= _value, "Allowance exceeded");
balanceOf[_from] -= _value;
balanceOf[_to] += _value;
allowance[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
return true;
}
}
Compile करें
npx hardhat compile
Output:
Compiling 1 file with 0.8.19
Compilation finished successfully
Artifacts artifacts/ folder में generate होते हैं।
Tests लिखना
Test File: SimpleToken.test.ts
test/SimpleToken.test.ts में:
import { expect } from "chai";
import { ethers } from "hardhat";
import { SimpleToken } from "../typechain-types";
import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers";
describe("SimpleToken", function () {
let token: SimpleToken;
let owner: SignerWithAddress;
let addr1: SignerWithAddress;
let addr2: SignerWithAddress;
beforeEach(async function () {
// Get signers
[owner, addr1, addr2] = await ethers.getSigners();
// Deploy contract
const Token = await ethers.getContractFactory("SimpleToken");
token = await Token.deploy(1000); // 1000 tokens initial supply
await token.waitForDeployment();
});
describe("Deployment", function () {
it("Should set the correct name and symbol", async function () {
expect(await token.name()).to.equal("Simple Token");
expect(await token.symbol()).to.equal("SMP");
});
it("Should assign total supply to owner", async function () {
const ownerBalance = await token.balanceOf(owner.address);
expect(await token.totalSupply()).to.equal(ownerBalance);
});
});
describe("Transactions", function () {
it("Should transfer tokens between accounts", async function () {
// Transfer 50 tokens from owner to addr1
await token.transfer(addr1.address, 50);
expect(await token.balanceOf(addr1.address)).to.equal(50);
// Transfer 50 tokens from addr1 to addr2
await token.connect(addr1).transfer(addr2.address, 50);
expect(await token.balanceOf(addr2.address)).to.equal(50);
});
it("Should fail if sender doesn't have enough tokens", async function () {
const initialOwnerBalance = await token.balanceOf(owner.address);
// Try to send more than balance
await expect(
token.connect(addr1).transfer(owner.address, 1)
).to.be.revertedWith("Insufficient balance");
// Owner balance shouldn't have changed
expect(await token.balanceOf(owner.address)).to.equal(initialOwnerBalance);
});
it("Should emit Transfer event", async function () {
await expect(token.transfer(addr1.address, 50))
.to.emit(token, "Transfer")
.withArgs(owner.address, addr1.address, 50);
});
});
describe("Allowances", function () {
it("Should approve and transferFrom", async function () {
// Owner approves addr1 to spend 100 tokens
await token.approve(addr1.address, 100);
expect(await token.allowance(owner.address, addr1.address)).to.equal(100);
// addr1 transfers 50 from owner to addr2
await token.connect(addr1).transferFrom(owner.address, addr2.address, 50);
expect(await token.balanceOf(addr2.address)).to.equal(50);
expect(await token.allowance(owner.address, addr1.address)).to.equal(50);
});
it("Should fail if allowance is exceeded", async function () {
await token.approve(addr1.address, 50);
await expect(
token.connect(addr1).transferFrom(owner.address, addr2.address, 100)
).to.be.revertedWith("Allowance exceeded");
});
});
});
Tests Run करें
npx hardhat test
Output:
SimpleToken
Deployment
✓ Should set the correct name and symbol
✓ Should assign total supply to owner
Transactions
✓ Should transfer tokens between accounts
✓ Should fail if sender doesn't have enough tokens
✓ Should emit Transfer event
Allowances
✓ Should approve and transferFrom
✓ Should fail if allowance is exceeded
7 passing (2s)
Gas Reporting
Gas costs analyze करें:
npm install --save-dev hardhat-gas-reporter
hardhat.config.ts में:
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
import "hardhat-gas-reporter";
const config: HardhatUserConfig = {
solidity: "0.8.19",
gasReporter: {
enabled: true,
currency: "USD",
coinmarketcap: process.env.COINMARKETCAP_API_KEY, // Optional
},
};
export default config;
Tests run करें:
npx hardhat test
Output:
·-----------------------|---------------------------|-------------|-----------------------------·
| Solc version: 0.8.19 · Optimizer enabled: true · Runs: 200 · Block limit: 30000000 gas │
·························|···························|·············|······························
| Methods │
·············|··········|·············|·············|·············|···············|··············
| Contract · Method · Min · Max · Avg · # calls · usd (avg) │
·············|··········|·············|·············|·············|···············|··············
| SimpleToken · transfer · 51000 · 66000 · 58500 · 4 · - │
·············|··········|·············|·············|·············|···············|··············
| SimpleToken · approve · 46000 · 46100 · 46050 · 2 · - │
·············|··········|·············|·············|·············|···············|··············
Deployment Scripts
Local Deployment
scripts/deploy.ts में:
import { ethers } from "hardhat";
async function main() {
const [deployer] = await ethers.getSigners();
console.log("Deploying contracts with account:", deployer.address);
console.log("Account balance:", (await ethers.provider.getBalance(deployer.address)).toString());
const Token = await ethers.getContractFactory("SimpleToken");
const token = await Token.deploy(1000000); // 1M tokens
await token.waitForDeployment();
console.log("SimpleToken deployed to:", await token.getAddress());
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
Local network start करें:
npx hardhat node
यह 20 pre-funded accounts के साथ local Ethereum node start करेगा।
Deploy करें:
npx hardhat run scripts/deploy.ts --network localhost
Testnet Deployment
.env file बनाएं:
SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/YOUR_INFURA_KEY
PRIVATE_KEY=your_private_key_here
ETHERSCAN_API_KEY=your_etherscan_api_key
hardhat.config.ts update करें:
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
import * as dotenv from "dotenv";
dotenv.config();
const config: HardhatUserConfig = {
solidity: "0.8.19",
networks: {
sepolia: {
url: process.env.SEPOLIA_RPC_URL || "",
accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [],
},
},
etherscan: {
apiKey: process.env.ETHERSCAN_API_KEY,
},
};
export default config;
Deploy करें:
npx hardhat run scripts/deploy.ts --network sepolia
Etherscan Verification
npx hardhat verify --network sepolia DEPLOYED_CONTRACT_ADDRESS 1000000
Advanced Features
Console.log in Solidity
Hardhat आपको Solidity में directly console.log use करने देता है!
import "hardhat/console.sol";
contract Debug {
function transfer(address to, uint256 amount) public {
console.log("Transferring", amount, "to", to);
// ... rest of logic
}
}
Tests run करने पर console output दिखेगा।
Mainnet Forking
Live blockchain state के against test करें:
hardhat.config.ts:
networks: {
hardhat: {
forking: {
url: process.env.MAINNET_RPC_URL || "",
blockNumber: 18000000, // Optional: specific block
},
},
},
अब आप real mainnet contracts के साथ interact कर सकते हैं:
const USDC_ADDRESS = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
const usdc = await ethers.getContractAt("IERC20", USDC_ADDRESS);
const balance = await usdc.balanceOf(WHALE_ADDRESS);
Coverage Reporting
Code coverage check करें:
npx hardhat coverage
Output:
--------------------|----------|----------|----------|----------|----------------|
File | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines |
--------------------|----------|----------|----------|----------|----------------|
contracts/ | 100 | 100 | 100 | 100 | |
SimpleToken.sol | 100 | 100 | 100 | 100 | |
--------------------|----------|----------|----------|----------|----------------|
All files | 100 | 100 | 100 | 100 | |
--------------------|----------|----------|----------|----------|----------------|
Useful Plugins
1. Hardhat-Ethers
Contract interactions को simplify करता है:
import { ethers } from "hardhat";
const [owner] = await ethers.getSigners();
const Token = await ethers.getContractFactory("SimpleToken");
const token = await Token.deploy(1000);
2. Hardhat-Etherscan
Automatic contract verification:
npx hardhat verify --network sepolia <address> <constructor-args>
3. Hardhat-Gas-Reporter
हर test में gas costs show करता है।
4. Solidity-Coverage
Code coverage reports generate करता है।
VS Code Setup
Extensions
Install करें:
- Solidity by Juan Blanco
- Hardhat Solidity by Nomic Foundation
- ESLint
- Prettier
Settings
.vscode/settings.json:
{
"solidity.compileUsingRemoteVersion": "v0.8.19",
"solidity.defaultCompiler": "remote",
"editor.formatOnSave": true,
"solidity.formatter": "prettier"
}
Common Tasks
Clean Artifacts
npx hardhat clean
Run Specific Test
npx hardhat test test/SimpleToken.test.ts
Run Single Test Case
npx hardhat test --grep "Should transfer tokens"
Check Contract Size
npx hardhat size-contracts
Flatten Contract
npx hardhat flatten contracts/SimpleToken.sol > SimpleToken_flat.sol
Best Practices
1. TypeScript Types
TypeChain automatically types generate करता है:
import { SimpleToken } from "../typechain-types";
const token: SimpleToken = await Token.deploy(1000);
// Full type safety!
2. Test Organization
test/
├── SimpleToken.test.ts
├── Staking.test.ts
├── helpers/
│ ├── time.ts
│ └── fixtures.ts
└── utils.ts
3. Environment Variables
Never commit private keys — always use .env:
# .gitignore
.env
node_modules/
artifacts/
cache/
typechain-types/
coverage/
4. Deployment Verification
Always verify contracts on Etherscan:
- Users को code read करने देता है
- Trust बढ़ाता है
- Contract के साथ interact करना easier बनाता है
Hardhat vs. Foundry vs. Remix
| Feature | Hardhat | Foundry | Remix |
|---------|---------|---------|-------|
| Language | TypeScript/JS | Solidity | Browser |
| Speed | Medium | Very Fast | Medium |
| Testing | Mocha/Chai | Solidity | Limited |
| Plugins | Rich | Growing | Built-in |
| Learning Curve | Medium | Medium | Easy |
| Best For | Production | Testing | Learning |
Conclusion
Hardhat professional smart contract development का industry standard है। TypeScript support, comprehensive testing framework, और rich plugin ecosystem इसे teams और solo developers दोनों के लिए ideal बनाते हैं।
Key takeaways:
- Hardhat TypeScript-first modern development framework है
- Built-in testing, debugging, और deployment tools
- Rich plugin ecosystem (gas reporting, coverage, verification)
- Mainnet forking real blockchain state के against testing के लिए
- Professional teams industry में Hardhat use करती हैं
Solingo पर, हम Hardhat workflows integrate करते हैं advanced challenges में। Production-grade development practices सीखें।
अभी शुरू करें: solingo.io/tools/hardhat