> ## Documentation Index
> Fetch the complete documentation index at: https://hedera-0c6e0218-mintlify-bc559771.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Forking Hedera Network for Local Testing

> Use the hedera-forking library with Foundry or Hardhat to fork Hedera mainnet or testnet locally and test against HTS system contracts.

This guide explains how fork testing works on Hedera, how it differs from traditional EVM chains, and how the [hedera-forking](https://github.com/hashgraph/hedera-forking) library enables local development with Hedera System Contracts.

***

## What is Fork Testing?

**Fork Testing** (also known as **Fixtures**) is an Ethereum Development Environment feature that optimizes test execution for smart contracts. It enables:

* **Snapshotting blockchain state** - Avoiding recreation of the entire blockchain state for each test
* **Using remote state locally** - Any modifications only affect the local (forked) network
* **No private key requirements** - Test against remote network state without managing keys
* **Debugging tools** - Use `console.log` and other debugging features during testing

Popular Ethereum development environments that support fork testing include:

* [Foundry](https://book.getfoundry.sh/forge/fork-testing) (using Anvil)
* [Hardhat](https://hardhat.org/hardhat-network/docs/overview#mainnet-forking) (using EDR/EthereumJS)

***

## Why is Hedera Different?

### Standard EVM Contracts Work Out-of-the-Box

Fork testing works seamlessly for standard EVM smart contracts that don't involve Hedera-specific services. The local test networks provided by development environments are replicas of the Ethereum network.

### Hedera System Contracts Require Emulation

Fork testing does not work out-of-the-box for contracts that use Hedera-specific services like:

* **Hedera Token Service (HTS)** at address `0x167`
* **Exchange Rate** at address `0x168`
* **PRNG** at address `0x169`
* **Hedera Account Service** at address `0x16a`

This is because when the development environment tries to fetch the code at these addresses, the JSON-RPC Relay returns `0xfe` (invalid opcode):

```console theme={null}
$ cast code --rpc-url https://mainnet.hashio.io/api 0x0000000000000000000000000000000000000167
0xfe
```

This leads to the error `EvmError: InvalidFEOpcode` when running tests. This is precisely where the hedera-forking library comes in to provide an emulation layer for Hedera System Contracts. For example, with Hardhat, the plugin intercepts JSON-RPC calls to return the appropriate bytecode and state for HTS and for Foundry, the library uses `ffi` to fetch state from the Mirror Node. This is explained in detail below.

***

## How Hedera Forking Works

The [hedera-forking](https://github.com/hashgraph/hedera-forking) project provides an emulation layer for Hedera System Contracts written in Solidity. Since it's written in Solidity, it can be executed in any development network environment.

### Architecture Overview

The project consists of two main components:

1. **Solidity Contracts** - Provide HTS emulation designed for forked networks
2. **JS Package** - Hooks into JSON-RPC layer to fetch appropriate data when HTS or Hedera Tokens are invoked (used by Hardhat)

Both the Foundry library and the Hardhat plugin use the main `HtsSystemContract` implementation. This contract provides the behavior of HTS, but it is state agnostic - meaning the HTS and token state must be provided elsewhere.

**Given Foundry and Hardhat provide different capabilities, they differ significantly in how the state is provided to HTS.**

***

## How Token State is Retrieved

<Info>
  Foundry and Hardhat use different mechanisms to retrieve token state from the
  Mirror Node. Understanding these differences is important for troubleshooting
  and optimizing your fork testing workflow.
</Info>

### Foundry Library Approach

The Foundry library uses a proactive prefetch approach where token state is fetched within Solidity contracts before it's needed.

**Key Components:**

* `HtsSystemContractJson` - Extends `HtsSystemContract` with JSON data source support
* `MirrorNodeFFI` - Fetches data from Mirror Node using Foundry's `ffi` cheatcode

**How it works:**

1. When your test calls `Hsc.htsSetup()`, the library deploys `HtsSystemContractJson` at address `0x167`
2. When you access token state (e.g., `balanceOf`), `HtsSystemContractJson` overrides the slot access
3. The contract calls `MirrorNodeFFI` which uses `ffi` to execute `curl` (or PowerShell on Windows) to fetch data from the Mirror Node
4. The fetched data is written to storage using `vm.store` cheatcode (not `sstore`) to avoid `StateChangeDuringStaticCall` errors
5. The data is then returned to your test

```mermaid theme={null}
sequenceDiagram
    autonumber
    box Local (Foundry)
    actor user as User Test
    participant anvil as Anvil (Local Network)
    participant hts as HtsSystemContractJson<br/>(at 0x167)
    participant ffi as MirrorNodeFFI<br/>(via ffi/curl)
    end
    box Remote
    participant mirror as Mirror Node
    end

    user->>+anvil: address(Token).balanceOf(account)
    Note over anvil:  Token Proxy delegates to 0x167
    anvil->>+hts: balanceOf(account)
    hts->>+ffi: fetchBalance(token, accountNum)
    ffi->>+mirror:  curl:  GET /api/v1/tokens/{id}/balances
    mirror-->>-ffi:  { balances: [... ] }
    ffi-->>-hts:  JSON response
    Note over hts: Parse JSON and store via vm.store
    hts-->>-anvil:  balance value
    anvil-->>-user: balance value
```

**Why FFI is Required:**

* Foundry does not allow creating a JSON-RPC forwarder like Hardhat
* However, Foundry allows hooking into internal contract calls via cheatcodes
* The `ffi` cheatcode enables executing external commands (like `curl`) from Solidity

### Hardhat Plugin Approach

The Hardhat plugin uses a reactive interception approach where a Worker thread intercepts JSON-RPC calls made by Hardhat.

**Key Components:**

* **JSON-RPC Forwarder** - A Worker thread that intercepts `eth_getCode` and `eth_getStorageAt` calls
* **MirrorNodeClient** (JavaScript) - Fetches data from Mirror Node using the `fetch` API

**How it works:**

1. When your test runs, Hardhat makes JSON-RPC calls to fetch remote state
2. The Hardhat plugin's Worker intercepts `eth_getCode` and `eth_getStorageAt` calls
3. For `eth_getCode(0x167)`: Returns the compiled `HtsSystemContract` bytecode
4. For `eth_getCode(tokenAddress)`: Returns the HIP-719 Token Proxy bytecode
5. For `eth_getStorageAt(token, slot)`: Uses the storage layout to map the slot to a field, then fetches the value from Mirror Node
6. The fetched data is returned to Hardhat's local network

```mermaid theme={null}
sequenceDiagram
    autonumber
    box Local (Hardhat)
    actor user as User Test
    participant edr as EDR (Local Network)
    participant plugin as Hardhat Forking Plugin<br/>(JSON-RPC Forwarder)
    end
    box Remote
    participant mirror as Mirror Node
    end

    user->>+edr: address(Token).totalSupply()
    edr->>+plugin: eth_getCode(Token)
    plugin->>+mirror: GET /api/v1/tokens/{tokenId}
    mirror-->>-plugin: Token {}
    plugin-->>-edr: HIP-719 Token Proxy bytecode<br/>(delegate calls to 0x167)

    edr->>+plugin: eth_getCode(0x167)
    plugin-->>-edr:  HtsSystemContract bytecode

    edr->>+plugin: eth_getStorageAt(Token, slot<totalSupply>)
    Note over plugin: Map slot to field using storage layout
    plugin->>+mirror:  GET /api/v1/tokens/{tokenId}
    mirror-->>-plugin: Token{}
    plugin-->>-edr: Token{}. totalSupply

    edr-->>-user: Token{}.totalSupply
```

**Why a Worker Thread is Required:**

* Hardhat does not allow hooking into internal contract calls (see [issue #56](https://github.com/hashgraph/hedera-forking/issues/56))
* The plugin must intercept at the JSON-RPC level before Hardhat processes the requests
* The Worker thread runs asynchronously to handle the interception

### Comparison: Foundry vs Hardhat Approaches

| Aspect             | Foundry Library                        | Hardhat Plugin                          |
| ------------------ | -------------------------------------- | --------------------------------------- |
| **State Fetching** | Proactive (prefetch in Solidity)       | Reactive (intercept JSON-RPC)           |
| **Data Fetcher**   | `MirrorNodeFFI` (Solidity + curl)      | `MirrorNodeClient` (JavaScript + fetch) |
| **Hook Point**     | Internal contract calls via cheatcodes | JSON-RPC layer via Worker thread        |
| **Requirement**    | `ffi = true` in foundry. toml          | `chainId` and `workerPort` in config    |
| **OS Dependency**  | curl (Unix) or PowerShell (Windows)    | Node.js fetch API                       |
| **Storage Writes** | `vm.store` cheatcode                   | Returned via JSON-RPC response          |

***

## HTS Supported Methods

The emulation layer supports a subset of HTS functionality. Refer to [https://github.com/hashgraph/hedera-forking#hedera-token-service-supported-methods](https://github.com/hashgraph/hedera-forking#hedera-token-service-supported-methods) for the latest list.

***

## Limitations and Important Notes

<Warning>
  The HTS emulation contract **SHOULD ONLY** be used to ease development workflow when working with Hedera Tokens. The HTS emulation contract **DOES NOT** replicate Hedera Token Services fully.  Behavior might differ when switching from local development to a real Hedera network.

  **Always test your contracts against a real Hedera network before launching your contracts.**
</Warning>

### Key Limitations

1. **Behavior differences** - Some edge cases may behave differently in emulation vs. the real Hedera network.

2. **Block number considerations** - When forking from a specific block, ensure your deployed contracts exist at that block number.

3. **Rate limiting** - When running many tests (especially fuzz tests), you may hit RPC rate limits. Consider lowering fuzz run counts.

4. **Storage layout constraints** - Solidity `mapping`s compute storage slots that are not reversible, which required special handling in the emulation layer.

5. **Foundry `ffi` requirement** - The Foundry library requires `ffi = true` which allows executing external commands. This is necessary for `curl` calls to the Mirror Node.

6. **Hardhat async limitations** - The Hardhat plugin requires manual configuration of `chainId` and `workerPort` because Hardhat plugin loading is synchronous.

***

## Development Framework Support

### Foundry

The Foundry library uses `ffi` (Foreign Function Interface) to fetch remote state from the Mirror Node using `curl` (or PowerShell on Windows).

**Key setup:**

* Enable `ffi = true` in `foundry.toml`
* Call `Hsc.htsSetup()` in your test setup

**How it fetches data:**

```solidity theme={null}
import {Hsc} from "hedera-forking/Hsc.sol";

function setUp() public {
    Hsc.htsSetup(); // Deploys HtsSystemContractJson at 0x167
}
```

When you access token state, the library:

1. Intercepts the storage slot access
2. Uses `MirrorNodeFFI` to call `curl` via `ffi`
3. Parses the JSON response
4. Writes data using `vm.store` cheatcode

### Hardhat

The Hardhat plugin intercepts JSON-RPC calls (`eth_getCode` and `eth_getStorageAt`) to provide HTS emulation.

**Key setup:**

* Install `@hashgraph/system-contracts-forking`
* Import the plugin in `hardhat.config.ts`
* Configure `chainId` and `workerPort` in forking config

**Configuration example:**

```typescript theme={null}
import "@hashgraph/system-contracts-forking/plugin";

// In your hardhat.config.ts
hardhat:  {
  forking: {
    url: "https://mainnet.hashio.io/api",
    blockNumber: 70531900,
    // @ts-ignore - custom properties for hedera-forking plugin
    chainId:  295, // Required: 295 (mainnet), 296 (testnet), 297 (previewnet)
    // @ts-ignore
    workerPort:  1235 // Required: Any free port
  }
}
```

***

## Learn How to Fork the Hedera Network for Local Testing

<Card title="How to Fork the Hedera Network with Hardhat - Basic ERC-20 Tutorial" href="/evm/tools/hardhat/forking-basic" />

<Card title="How to Fork the Hedera Network with Hardhat - Advanced HTS Tutorial" href="/evm/tools/hardhat/forking-advanced" />

<Card title="How to Fork the Hedera Network with Foundry - Basic ERC-20 Tutorial" href="/evm/tools/foundry/forking" />

<Card title="How to Fork the Hedera Network with Foundry - Advanced HTS Tutorial" href="/evm/tools/foundry/forking-advanced-hts" />

***

## Further Resources

* [hedera-forking GitHub Repository](https://github.com/hashgraph/hedera-forking)
* [Internals Documentation](https://github.com/hashgraph/hedera-forking/blob/main/INTERNALS.md)
* [FAQ](https://github.com/hashgraph/hedera-forking/blob/main/FAQ.md)
* [HIP-719: Token Proxy Contract](https://hips.hedera.com/hip/hip-719)
* [Foundry Fork Testing Documentation](https://book.getfoundry.sh/forge/fork-testing)
* [Hardhat Mainnet Forking Documentation](https://hardhat.org/hardhat-network/docs/overview#mainnet-forking)

<Columns cols={1}>
  <Card title="Writer: Kiran Pachhai, Developer Advocate" arrow>
    [GitHub](https://github.com/kpachhai) |
    [LinkedIn](https://www.linkedin.com/in/kiranpachhai/)
  </Card>
</Columns>
