
Introduction: Why Forking Ethereum Mainnet is Essential for Developers
Ethereum development involves deploying, testing, and optimizing smart contracts before launching them on the mainnet. However, testing on a local blockchain (like Hardhat or Ganache) is not enough when working with real-world protocols like Uniswap, Aave, and Compound.
Table of Contents
Problems Developers Face Without Forking:
- Local testnets lack real mainnet data (token balances, live contract states, etc.).
- Deploying to Ethereum testnets (like Goerli or Sepolia) is slow and costly.
- Debugging gas costs and transaction conduct is misguided on testnets.
Why Hardhat Forking is the Best Solution?
Hardhat allows you to fork the Ethereum mainnet, growing a nearby reproduction of the stay blockchain.
Test smart contract interactions with real protocols (Uniswap, Aave, Curve).
Simulate DeFi transactions without spending real ETH.
Debug gas fees and optimize transactions using actual Ethereum data.
Experiment with clever settlement enhancements and take advantage of simulations.
Now, allow’s dive deeper into what forking is, how to set it up, and the way to check effectively.
1. What is Forking?
Definition of Forking in Blockchain
Forking refers to creating an genuine replica of a blockchain’s state at a specific block. This permits builders to check transactions with out interacting with the actual mainnet.
In Hardhat, forking means:
- Cloning the Ethereum mainnet onto a local network.
- Keeping the exact balances, deployed contracts, and transaction history.
- Allowing developers to test freely without real costs.
Why Forking is Important?
- Testing with real DeFi protocols (e.g., interact with Uniswap’s smart contracts).
- Simulating attacks and security vulnerabilities before they occur on mainnet.
- Optimizing gas fees by testing transactions under real conditions.
2. How to Fork Ethereum Mainnet with Hardhat (Alchemy & Infura)
Prerequisites
Before we fork Ethereum, install these dependencies:
npm install --save-dev hardhat dotenv
Also, create an Alchemy or Infura API key (since Hardhat needs an RPC endpoint to fetch mainnet data).
Setting Up Hardhat for Forking
- Initialize a Hardhat project (if you haven’t already):
npx hardhat init
- Modify your Hardhat configuration (
hardhat.config.js
):require("dotenv").config(); module.exports = { solidity: "0.8.20", networks: { hardhat: { forking: { url: process.env.ALCHEMY_API_URL, // Or Infura URL blockNumber: 18000000, // (Optional) Set a fixed block number }, }, }, };
- Add your API key to a
.env
file:ALCHEMY_API_URL=https://eth-mainnet.alchemyapi.io/v2/YOUR_ALCHEMY_KEY
- Run a local Hardhat node with a forked Ethereum mainnet:
npx hardhat node
🎯 Now, your local Hardhat network has the entire Ethereum mainnet state!
Verifying the Fork Works
Run this script to check the latest block:
async function main() {
const latestBlock = await ethers.provider.getBlockNumber();
console.log("Forked Ethereum at block:", latestBlock);
}
main();
3. Testing Strategies with Forked Chains
Now that we’ve a forked Ethereum mainnet, allow’s discover three key checking out strategies:
(a) Smart Contract Testing with Real Mainnet Data
Example: Simulating a Token Swap on Uniswap
const { ethers } = require("hardhat");
async function main() {
const [signer] = await ethers.getSigners();
const daiAddress = "0x6B175474E89094C44Da98b954EedeAC495271d0F"; // DAI Token
const uniswapRouter = await ethers.getContractAt(
"IUniswapV2Router02",
"0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"
);
const tx = await uniswapRouter.connect(signer).swapExactETHForTokens(
0, // Min amount
[ethers.constants.AddressZero, daiAddress], // ETH → DAI path
signer.address,
Math.floor(Date.now() / 1000) + 60 * 10,
{ value: ethers.utils.parseEther("1") }
);
await tx.wait();
console.log("Swapped 1 ETH for DAI!");
}
main();
Why this is useful?
- You can test DeFi interactions without real ETH.
- Ensures your smart contract integrates correctly with external protocols.
(b) Security Testing & Exploit Simulations
Hackers often fork mainnet to test attacks before launching them. As a developer, you can do the same to harden your contracts.
Example: Simulating a Flash Loan Attack
const { ethers } = require("hardhat");
async function main() {
const attacker = await ethers.getSigner();
const aaveLendingPool = await ethers.getContractAt(
"ILendingPool",
"0x7d2768dE32b0b08056A3aF3AdEb3dDdC38218d29"
);
const tx = await aaveLendingPool.flashLoan(
attacker.address,
[DAI_ADDRESS], // Borrow DAI
[ethers.utils.parseUnits("100000", 18)], // 100,000 DAI
[0],
attacker.address,
"0x",
0
);
await tx.wait();
console.log("Executed flash loan attack simulation!");
}
main();
Why this is important?
- Helps test vulnerabilities before attackers find them.
- Can be used for bug bounty testing to fix security flaws.
(c) Gas Optimization & Transaction Debugging
Ethereum gas fees can be expensive, so testing gas efficiency is critical.
Example: Measuring Gas Costs of a Function Call
const tx = await myContract.someExpensiveFunction();
const receipt = await tx.wait();
console.log("Gas used:", receipt.gasUsed.toString());
This helps identify inefficient smart contract logic and optimize deployment costs.
4. FAQs: Common Questions About Hardhat Forking
- Why should I use Hardhat instead of Ganache?
- Hardhat allows live mainnet forking, while Ganache doesn’t support it as effectively.
- How much does forking cost?
- Free on Hardhat, but Alchemy/Infura API limits apply.
- How can I persist forked data across sessions?
- Use Hardhat’s
stateManager.dumpStorage
andstateManager.loadStorage
.
- Use Hardhat’s
- Can I fork other networks like Polygon or BSC?
- Yes, just replace the RPC URL with a Polygon/BSC node provider.
5. Conclusion & Call to Action
- Forking mainnet is essential for realistic smart contract testing.
- Enables safe, gas-free DeFi testing and security simulations.
- Try testing your own contracts today using the provided examples!
Next Steps: Learn how to debug transactions with Hardhat’s tracing tools.