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

# Forking Hedera Network for Local Testing

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>
