One of the most significant internal refactors in Foundry 2.0 is the introduction of FoundryEvmNetwork, a supertrait that makes Foundry's entire EVM execution stack generic.
This refactor was originally driven by the need to bring Tempo support upstream into Foundry itself. But the architecture that emerged is intentionally general: any custom chain can plug into Foundry's full execution and testing infrastructure, cheatcodes, forking, fuzzing, coverage, gas snapshots, as long as it implements FoundryEvmNetwork, Alloy's Network, and FoundryEvmFactory. The pattern is deliberately similar to Reth's SDK model, where the node itself becomes an extension point rather than a monolith. In Foundry 2.0, the same philosophy applies to its evm crate: it is an SDK, not a fixed implementation.
Foundry's executor, database backend, and cheatcode inspector were historically written against Ethereum-specific types. As the ecosystem expanded to Layer-2 networks with their own transaction formats, block environments, and EVM variants, this created a recurring problem: every network integration required patching through multiple layers of hardcoded types, accumulating tech debt and making new network support error-prone.
The solution is FoundryEvmNetwork, a single marker trait that pairs a network with its EVM factory:
pub trait FoundryEvmNetwork: Copy + Debug + Default + 'static {
type Network: Network<TxEnvelope: ..., TransactionRequest: ..., ReceiptResponse: ...>;
type EvmFactory: FoundryEvmFactory<Tx: FromRecoveredTx<...>>;
}Concrete implementations are zero-cost marker types:
impl FoundryEvmNetwork for EthEvmNetwork {
type Network = Ethereum;
type EvmFactory = EthEvmFactory;
}
impl FoundryEvmNetwork for TempoEvmNetwork {
type Network = TempoNetwork;
type EvmFactory = TempoEvmFactory;
}A companion set of type aliases: TxEnvFor<FEN>, BlockEnvFor<FEN>, EvmEnvFor<FEN>, TransactionRequestFor<FEN>, lets generic code reference evm and network-specific types without spelling out long trait projections everywhere.
Every major component in the execution pipeline is now generic over FEN: FoundryEvmNetwork:
Executor<FEN>: the top-level test executor, previously fully hardcoded onEthereumBackend<FEN>: the in-memory and forked state databaseDatabaseExt<F: FoundryEvmFactory>: the trait governing state snapshots and fork management, parameterized over the factory'sSpecandBlockEnvInspectorStack<FEN>andCheatcodes<FEN>: the full cheatcode and inspection infrastructure, including broadcastable transactions and block overrides
The result: code written generically over FEN automatically supports any network without modification. Adding a new network means implementing two traits, FoundryEvmNetwork and FoundryEvmFactory, and the rest of the stack compiles in.
Cheatcodes were the hardest part to generalize. Cheatcodes<FEN> is now fully generic: EVM context manipulation flows through revm's FoundryContextExt extension, transaction decoding, and broadcasting are handled Network-agnostic way, and nested EVM execution is dispatched through the network's own EVM factory:
fn with_nested_evm(&mut self, cheats: &mut Cheatcodes<FEN>, ecx: &mut FoundryContextFor<'_, FEN>, ...) {
let mut evm = FEN::EvmFactory::default()
.create_foundry_evm_with_inspector(db, evm_env, cheats);
// ...
}For most users, this refactor is invisible, existing tests and scripts continue to work unchanged. For toolchain builders and chain teams, the benefit is concrete: Foundry's execution engine is now an extension point, not a patchwork. New EVM variants slot in without forking or monkey-patching the core.