Skip to main content
In this tutorial, you’ll fork Hedera testnet using Foundry and interact with a basic ERC-20 token on the forked network. This is an introductory guide to local fork testing with Foundry. This guide shows how to:
  • Fork Hedera testnet using Foundry
  • Deploy an ERC-20 contract to Hedera testnet
  • Run Foundry 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
References:
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-foundry repository.

Prerequisites

  • Foundry installed
  • ECDSA account from the Hedera Portal
  • Basic understanding of Solidity
  • A Hedera JSON-RPC endpoint:
    • mainnet: https://mainnet.hashio.io/api
    • testnet: https://testnet.hashio.io/api

Table of Contents

  1. Step 1: Project Setup
  2. Step 2: Create the ERC-20 Contract and Deploy to Testnet
  3. Step 3: Write Tests for the Forked Network
  4. Step 4: Run Tests on the Forked Network

Step 1: Project Setup

Initialize Project

Create a new directory and initialize the Foundry project:

Install Dependencies

Install OpenZeppelin contracts and the Hedera forking library:

Configure Remappings

Create or update remappings.txt in your project root:
remappings.txt
We need this to import prefix to a filesystem path so both Foundry(forge) and our editor can resolve short, package-like imports instead of long relative paths.
Note that we are updating the remappings.txt in our root directory of the project and not in the lib directory where the dependencies are installed.

Set Environment Variables

Create a .env file in your project root:
. env
Replace the 0x-your-private-key environment variable with the HEX Encoded Private Key for your ECDSA account. Note that this account MUST exist on testnet as we’re dealing with the testnet for this exercise. Also, ensure it has sufficient HBAR for deployment.
Note that these variables will only be used for the original deployment of the contract to the testnet. The private key is not needed for the forked tests since we will be impersonating accounts. Now, let’s load these to the terminal:

Configure Foundry

Update your foundry.toml file in the root directory of your project. Open it and add profiles for the Hedera RPC endpoints.
foundry.toml
Note that we have ffi to be true because on forked tests, the library uses curl (or PowerShell) to query Hedera Mirror Node for token state so that EVM calls like IERC721.ownerOf() can work as if the token were a normal EVM contract. We will be removing the default contracts that comes with foundry default project:

Step 2: Create the ERC-20 Contract and Deploy to Testnet

Create the Contract

Create a new file src/ERC20Token.sol:
src/ERC20Token.sol
This contract:
  • Creates a basic ERC-20 token named “MyToken” with symbol “MTK”
  • Mints 10,000 tokens to a recipient on deployment
  • Has an onlyOwner mint function for additional minting

Compile the Contract

Create Deployment Script

Create a new file script/Deploy.s.sol:
script/Deploy.s.sol

Deploy to Testnet

Deploy your contract to Hedera testnet:
You should see output similar to:
We have already deployed this ERC-20 contract on testnet at https://hashscan.io/testnet/contract/0xfC7D2FB1D5a9Be5D6182cBf3F283140d007CdcD4 so we will be using this for the remainder of this exercise.

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 file test/ERC20Token.t.sol:
Make sure to update the DEPLOYED_CONTRACT constant below with the contract address from your deployment.
test/ERC20Token.t.sol
Key points about these tests:
  • Uses deployed contract - Tests bind to the already deployed contract address
  • Impersonation with vm.prank - Uses Foundry’s cheatcode to 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

Step 4: Run Tests on the Forked Network

Run your tests against the forked Hedera testnet:
You should see output similar to:

Pin to a Specific Block

For reproducible tests, you can pin to a specific block number:
This ensures your tests always run against the same blockchain state. We are using block number 29970059 for this testing because the contract from above(i.e. 0xfC7D2FB1D5a9Be5D6182cBf3F283140d007CdcD4 was deployed on block 29970059. If we tried to run our tests with block below this, it would fail such as:
This would fail with something like:

Understanding Fork Testing with Deployed Contracts

Why Test Against Deployed Contracts?

  1. Real-world state - Test against actual balances, allowances, and state
  2. No deployment costs - Don’t spend gas deploying for every test run
  3. Impersonation - Act as any account (even the contract owner) without their private key
  4. Safe experimentation - Try anything without affecting the real network

How Impersonation Works in Foundry

Foundry provides cheatcodes for impersonation:

Funding Accounts with vm.deal

Fund test accounts with native tokens:

Local vs. Remote State


Further Learning & Next Steps

  1. How to Fork Hedera with Foundry - Advanced HTS (Part 2)
    Continue with HTS System Contracts and the hedera-forking emulation layer
  2. Forking Hedera Network for Local Testing
    Deep dive into how Hedera forking works under the hood
  3. How to Fork Hedera with Hardhat (Part 1)
    Learn fork testing with Hardhat framework
  4. How to Fork Hedera with Hardhat - Advanced HTS
    Compare the Hardhat approach to HTS fork testing
  5. hedera-forking Repository
    Explore examples and documentation

Writer: Kiran Pachhai, Developer Advocate

Editor: Krystal, Senior DX Engineer