Simulated Networks by EDR
This page provides a reference for Hardhat’s simulated networks, powered by the Ethereum Development Runtime (EDR). Here you’ll find detailed information about all available features and behaviors of EDR-based local blockchains.
If you’re looking for a conceptual overview, see the explanation instead.
Developer-focused features
Section titled “Developer-focused features”Simulated networks include features specifically designed for testing and debugging smart contracts. Unlike production blockchains, EDR is aware of your Solidity code and understands what’s running.
EDR also aims to precisely simulate the blockchains you’ll deploy your contracts to, both when running TypeScript and Solidity tests.
Multichain support
Section titled “Multichain support”EDR has native support for simulating different types of blockchains. You can specify the chain type in your Network Config:
// ... imports ...
export default defineConfig({ // ... other config ... networks: { // ... other networks ... hardhatMainnet: { type: "edr-simulated", chainType: "l1", // Ethereum mainnet and its testnets }, hardhatOptimism: { type: "edr-simulated", chainType: "op", // OP Mainnet and its testnets }, other: { type: "edr-simulated", chainType: "generic", // Default value, which is a permissive approximation to mainnet }, },});Solidity stack traces
Section titled “Solidity stack traces”When a transaction or call fails, EDR provides Solidity stack traces. These traces include both the TypeScript test code where the transaction or call originated and the full Solidity call stack, making it easy to understand exactly where and why your code failed.
console.log support
Section titled “console.log support”You can use console.log() in your Solidity code to print debugging information. Simply import hardhat/console.sol and call it like you would in JavaScript:
import "hardhat/console.sol";
contract MyContract { function myFunction(uint256 value) public { console.log("Processing value: %d", value); }}The logs appear in your test output, helping you understand what’s happening inside your contracts. Learn more in the console.log reference.
Clear error messages
Section titled “Clear error messages”EDR detects common error situations and reports clear error messages. For example, it will tell you if you’re:
- Calling a non-payable function with ETH
- Sending ETH to a contract without a payable fallback or receive function
- Calling a non-existent function when there’s no fallback function
- Calling a function with incorrect parameters
- Calling an external function that doesn’t return the right amount of data
- Calling an external function on a non-contract account
- Failing to execute an external call because of its parameters (for example, trying to send too much ETH)
- Calling a library without
DELEGATECALL - Incorrectly calling a precompiled contract
- Trying to deploy a contract that exceeds the bytecode size limit imposed by EIP-170
Development-only JSON-RPC methods
Section titled “Development-only JSON-RPC methods”EDR provides additional JSON-RPC methods that are useful for development and testing. These methods allow you to do things like manipulate the blockchain state or control mining behavior.
We don’t recommend using these methods directly. Instead, use Hardhat’s network helpers, which wrap them in a more user-friendly way.
Initial blockchain state
Section titled “Initial blockchain state”The initial state of a simulated network depends on whether you’re using forking mode and your Network Config.
Default state
Section titled “Default state”By default, simulated networks start with an empty blockchain that includes:
- Standard precompiled contracts (like
ecrecover,sha256, etc.) - Any predeployed contracts specified by your chain type (for example, Optimism’s predeploys)
- The accounts configured in your Network Config, each with the specified balance and no code
Forking mode
Section titled “Forking mode”In forking mode, the simulated network starts as a copy of a remote blockchain at a specific block. The state is lazy-loaded from the remote network as needed, which means you don’t have to wait for the entire blockchain to download.
When forking, there are some differences from the remote network:
- Accounts in your Network Config have their balance and code overwritten (removing EIP-7702 delegations if present)
- The
chainIdis taken from your Network Config, not the remote chain, for security reasons (though this can be configured)
You can configure forking in your Network Config like this:
// ... imports ...
export default defineConfig({ // ... other config ... networks: { // ... other networks ... mainnetFork: { type: "edr-simulated", forking: { url: "https://mainnet.infura.io/v3/YOUR_API_KEY", blockNumber: 14390000, // optional }, }, },});Mining modes
Section titled “Mining modes”EDR supports different mining modes that control when and how new blocks are created.
Automine mode
Section titled “Automine mode”By default, automine is enabled. In this mode, a new block is mined immediately whenever a transaction is received. This makes tests fast because you don’t have to wait for blocks to be mined.
Interval mining
Section titled “Interval mining”You can enable interval mining to mine new blocks periodically, regardless of whether there are pending transactions. This is useful for testing time-dependent contract behavior.
You can configure interval mining to use a fixed interval or a random interval between two values:
// ... imports ...
export default defineConfig({ // ... other config ... networks: { // ... other networks ... intervalMined: { type: "edr-simulated", mining: { auto: false, // disable automining interval: 5000, // mine a new block every 5 seconds }, }, },});Or with a random interval:
// ... imports ...
export default defineConfig({ // ... other config ... networks: { // ... other networks ... intervalMined: { type: "edr-simulated", mining: { auto: false, // disable automining interval: [3000, 6000], // mine blocks at random intervals between 3-6 seconds }, }, },});Manual mining
Section titled “Manual mining”If you disable both automine and interval mining, transactions will accumulate in the mempool without being mined. You can manually mine blocks using the evm_mine RPC method:
import { network } from "hardhat";
const { networkHelpers } = await network.connect();await networkHelpers.mine();This is useful when you need precise control over when blocks are mined.
Combining mining modes
Section titled “Combining mining modes”You can use automine and interval mining together. In this case, blocks are mined both when transactions arrive and at regular intervals.
You can also decide not to use either mode and rely solely on manual mining.
Mempool behavior
Section titled “Mempool behavior”When automine is disabled, transactions are added to the mempool before being included in a block. By default, EDR’s mempool follows the same rules as Geth:
- Transactions with a higher gas price are included first
- If two transactions offer the same total fees, the one received first is included first
- Invalid transactions (for example, with an incorrect nonce) are dropped
FIFO mode
Section titled “FIFO mode”You can configure the mempool to use FIFO (first-in, first-out) instead of priority ordering. In FIFO mode, transactions are included in blocks in the exact order they were received:
// ... imports ...
export default defineConfig({ // ... other config ... networks: { // ... other networks ... fifoNetwork: { type: "edr-simulated", mining: { auto: false, interval: 2000, mempool: { order: "fifo", }, }, }, },});This is useful for recreating blocks from other networks where the transaction order is known.
Configuration
Section titled “Configuration”To learn more about configuring simulated networks, read the configuration reference.