Help users run a local Ethereum dev chain, write integration tests, fork networks, debug transactions, or replace Hardhat/Anvil with Nethereum DevChain (.NET). Use this skill when the user mentions local Ethereum node, dev chain, test chain, Hardhat replacement, Anvil replacement, in-process blockchain, snapshot/revert, debug_traceTransaction, account impersonation, or anything involving a local EVM for development and testing with C# or .NET.
DevChain is a complete in-process Ethereum node for .NET. It runs the full EVM (up to Prague), mines blocks instantly, and needs no external dependencies — no Docker, no Geth, no Hardhat, no Anvil.
dotnet add package Nethereum.DevChain # Core in-process node
dotnet add package Nethereum.DevChain.Server # HTTP JSON-RPC server
using Nethereum.DevChain;
using Nethereum.Web3;
using Nethereum.Web3.Accounts;
var account = new Account("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80");
var devChain = new DevChainNode();
await devChain.StartAsync(account); // Pre-funds with 10,000 ETH
var web3 = devChain.CreateWeb3(account); // In-process, no HTTP
// Standard Nethereum APIs work as-is
var receipt = await web3.Eth.GetEtherTransferService()
.TransferEtherAndWaitForReceiptAsync("0x70997970C51812dc3A010C7d01b50e0d17dc79C8", 1.0m);
devChain.Dispose();
| Class | Package | Purpose |
|---|---|---|
DevChainNode | Nethereum.DevChain | Main in-process node |
DevChainConfig | Nethereum.DevChain | Chain configuration (ChainId, AutoMine, BlockGasLimit, etc.) |
DevChainServerConfig | Nethereum.DevChain.Server | HTTP server configuration |
DevAccountManager | Nethereum.DevChain.Server | HD wallet account management |
DevChainHostedService | Nethereum.DevChain.Server | ASP.NET Core hosted service |
var config = new DevChainConfig
{
ChainId = 1337, // Default: 1337 (Hardhat preset: 31337)
BlockGasLimit = 30_000_000,
AutoMine = true, // Mine instantly on each tx
InitialBalance = BigInteger.Parse("10000000000000000000000") // 10,000 ETH
};
var devChain = new DevChainNode(config);
Presets: DevChainConfig.Default (1337), DevChainConfig.Hardhat (31337), DevChainConfig.Anvil (31337).
// One-liner
var devChain = await DevChainNode.CreateAndStartAsync(account);
// In-memory (no SQLite)
var devChain = DevChainNode.CreateInMemory();
// Multiple accounts
var devChain = new DevChainNode();
await devChain.StartAsync(alice, bob);
var accounts = await devChain.GenerateAndFundAccountsAsync(10);
var snapshot = await devChain.TakeSnapshotAsync();
// ... transactions ...
await devChain.RevertToSnapshotAsync(snapshot); // Undo all changes
await devChain.SetBalanceAsync(address, Web3.Convert.ToWei(1_000_000));
await devChain.SetNonceAsync(address, 100);
await devChain.SetCodeAsync(address, bytecode);
await devChain.SetStorageAtAsync(address, slot, value);
Via RPC: hardhat_setBalance, hardhat_setCode, hardhat_setNonce, hardhat_setStorageAt (also anvil_* aliases).
var config = new DevChainConfig
{
ForkUrl = "https://eth.llamarpc.com",
ForkBlockNumber = 19000000
};
var devChain = new DevChainNode(config);
await devChain.StartAsync(account);
CLI: nethereum-devchain -f https://eth.llamarpc.com --fork-block 19000000
devChain.DevConfig.AddTimeOffset(3600); // Advance 1 hour
devChain.DevConfig.SetNextBlockTimestamp(1700000000); // Exact timestamp
await devChain.MineBlockAsync();
using Nethereum.CoreChain.Tracing;
var traceConfig = new OpcodeTraceConfig
{
DisableMemory = true,
DisableStack = false,
DisableStorage = false
};
var trace = await devChain.TraceTransactionAsync(txHash, traceConfig);
nethereum-devchain # Defaults: port 8545, 10 accounts, auto-mine
nethereum-devchain -p 8546 -a 20 # Custom port and accounts
nethereum-devchain -f <url> # Fork mode
nethereum-devchain --persist ./data # Persistent storage
using Nethereum.DevChain.Server.Configuration;
using Nethereum.DevChain.Server.Hosting;
using Nethereum.DevChain.Server.Server;
var config = new DevChainServerConfig { ChainId = 31337, Storage = "memory" };
builder.Services.AddDevChainServer(config);
builder.Services.AddHostedService<DevChainHostedService>();
public class DevChainFixture : IAsyncLifetime
{
public DevChainNode Node { get; private set; }
public Account Alice { get; private set; }
public async Task InitializeAsync()
{
Alice = new Account("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80");
Node = new DevChainNode(new DevChainConfig { ChainId = 31337 });
await Node.StartAsync(Alice);
}
public Task DisposeAsync() { Node?.Dispose(); return Task.CompletedTask; }
}
// In test class: snapshot before each test, revert after
public async Task InitializeAsync() => _snapshot = await _fixture.Node.TakeSnapshotAsync();
public async Task DisposeAsync() => await _fixture.Node.RevertToSnapshotAsync(_snapshot);
Standard Ethereum (eth_*, net_*, web3_*), plus:
evm_mine, evm_snapshot, evm_revert, evm_increaseTime, evm_setNextBlockTimestamphardhat_setBalance, hardhat_setCode, hardhat_setNonce, hardhat_setStorageAt, hardhat_impersonateAccount, hardhat_stopImpersonatingAccountanvil_setBalance, anvil_setCode, anvil_setNonce, anvil_setStorageAt, anvil_mine, anvil_snapshot, anvil_revertdebug_traceTransaction, debug_traceCallSame default mnemonic (test test test test test test test test test test test junk), same derivation path (m/44'/60'/0'/0/{index}), same RPC methods, same chain ID (31337 with Hardhat/Anvil presets). Existing test scripts work without changes.
For full documentation, see: https://docs.nethereum.com/docs/devchain/overview