- Fork Hedera testnet using Hardhat
- Deploy an ERC-20 contract to Hedera testnet
- Run Hardhat tests on a fork of Hedera testnet
- Read and interact with an existing ERC-20 contract by its EVM address (e.g.,
balanceOf,name,symbol,transfer), with minimal setup - The process to set up and run tests is similar for mainnet as well
- Repo: hashgraph/hedera-forking
- Readme sections: Hardhat plugin, Running your Tests
- Examples:
examples/hardhat-hts/
For a deeper understanding of how Hedera forking works and its limitations,
see Forking Hedera Network for Local
Testing.
You can take a look at the complete code in the basic-erc20-fork-test-hardhat
repository.
Prerequisites
- Node.js (v18 or later) and npm
- ECDSA account from the Hedera Portal
- Basic understanding of Solidity and TypeScript
- A Hedera JSON-RPC endpoint:
- mainnet:
https://mainnet.hashio.io/api - testnet:
https://testnet.hashio.io/api
- mainnet:
Table of Contents
- Step 1: Project Setup
- Step 2: Create the ERC-20 Contract and Deploy to Testnet
- Step 3: Write Tests for the Forked Network
- Step 4: Run Tests on the Forked Network
Step 1: Project Setup
Initialize Project
Create a new directory and initialize the project:Install Dependencies
Create or update yourpackage.json with all required dependencies:
package.json
Create Project Structure
Create the necessary directories:Configure TypeScript
Createtsconfig.json in your project root:
tsconfig.json
Configure Hardhat
Createhardhat.config.ts in your project root. This file must exist before you can run any Hardhat commands:
hardhat.config.ts
HEDERA_RPC_URL- Loaded from Hardhat configuration variablesHEDERA_PRIVATE_KEY- Loaded securely from configuration variableshederaTestnet- Network configuration for deploying to real testnethardhat.forking- Configuration for forking testnet locallyblockNumber- Pin to a block where your deployed contract existschainId: 296- Required for testnet (295 for mainnet)workerPort: 10001- Any free port for the worker that intercepts Hardhat calls@ts-ignore- Required becausechainIdandworkerPortare custom properties not in Hardhat’s type definitions
Set Configuration Variables
Now thathardhat.config.ts exists, you can set the configuration variables. Hardhat allows you to securely store sensitive values using configuration variables:
https://testnet.hashio.io/api
Step 2: Create the ERC-20 Contract and Deploy to Testnet
Create the Contract
Create a new filecontracts/ERC20Token.sol:
contracts/ERC20Token.sol
- Creates a basic ERC-20 token named “MyToken” with symbol “MTK”
- Mints 10,000 tokens to a recipient on deployment
- Has an
onlyOwnermintfunction for additional minting
Compile the Contract
typechain-types directory.
Create Deployment Script
Create a new filescripts/deploy.ts:
scripts/deploy.ts
Deploy to Testnet
Deploy your contract to Hedera testnet:Update Hardhat Config with Deployment Block
After deployment, update yourhardhat.config.ts with the block number from the deployment output:
Step 3: Write Tests for the Forked Network
Now we’ll write tests that interact with the already deployed contract on the forked testnet. This is the real power of fork testing - you can test against real deployed contracts without spending gas or affecting the live network. Create a new filetest/ERC20Token.test.ts:
Make sure to update the
DEPLOYED_CONTRACT constant below with the
address of your deployed contract from Step 2.test/ERC20Token.test.ts
- TypeScript types - Uses generated types from
typechain-typesfor type safety - Uses deployed contract - Tests bind to the already deployed contract using
getContractAt - Impersonation - Uses
hardhat_impersonateAccountto act as the real owner - Reads real state - Token info, balances, etc. come from the actual testnet deployment
- Local modifications - All transfers, mints happen only on the local fork
- No testnet changes - The real testnet is never modified
- Uses fixtures -
loadFixtureensures each test starts with a clean state
Step 4: Run Tests on the Forked Network
Run your tests against the forked Hedera testnet:Pin to a Specific Block
For reproducible tests, make sure theblockNumber in your hardhat.config.ts is set to a block where your contract exists. If you try to fork at a block before your contract was deployed, you’ll see an error because the contract doesn’t exist yet at that block.
Understanding Fork Testing with Deployed Contracts
Why Test Against Deployed Contracts?
- Real-world state - Test against actual balances, allowances, and state
- No deployment costs - Don’t spend gas deploying for every test run
- Impersonation - Act as any account (even the contract owner) without their private key
- Safe experimentation - Try anything without affecting the real network
How Impersonation Works
Local vs. Remote State
| Action | Affects Local Fork | Affects Testnet |
|---|---|---|
| Read balances | ✅ (cached) | ❌ (read-only) |
| Transfer tokens | ✅ | ❌ |
| Mint new tokens | ✅ | ❌ |
| Deploy new contracts | ✅ | ❌ |
| Impersonate accounts | ✅ | ❌ |
| Changes persist after test | ❌ (reset) | N/A |
Next Steps
Now that you understand fork testing with deployed contracts, you can:- Test contract upgrades - Fork, deploy upgraded version, compare behavior
- Simulate user interactions - Impersonate real users to test edge cases
- Move to Part 2 - Learn how to work with HTS System Contracts
In Part
2,
you’ll learn how to interact with the Hedera Token Service (HTS) using system
contract precompiles, including interacting with existing HTS tokens and
understanding the limitations of the forking emulation layer.
Further Learning & Next Steps
-
How to Fork Hedera with Hardhat (Part 2)
Learn to work with HTS System Contracts and understand emulation limitations -
Forking Hedera Network for Local Testing
Deep dive into how Hedera forking works under the hood -
How to Fork Hedera with Foundry
Learn fork testing with Foundry framework -
hedera-forking Repository
Explore examples and documentation