Nethereum.RPC Ethereum Core RPC Class Library to interact via RPC with an Ethereum client, for example geth.
$ dotnet add package Nethereum.RPCNethereum.RPC is the core package providing Ethereum JSON-RPC method implementations. It contains all standard Ethereum RPC methods organized into logical categories (Eth, Net, Web3, Personal, etc.) and provides both direct RPC access and service-based APIs.
dotnet add package Nethereum.RPC
Nethereum.JsonRpc.Client - RPC client abstractionNethereum.Hex - Hex encoding/decodingNethereum.Util - UtilitiesNethereum.Model - Data modelsNethereum.Merkle.Patricia - Merkle proof supportMost users interact with RPC methods through the Web3 API, which provides a higher-level interface:
using Nethereum.Web3;
var web3 = new Web3("https://mainnet.infura.io/v3/YOUR-PROJECT-ID");
// All RPC methods are available through web3.Eth
var blockNumber = await web3.Eth.Blocks.GetBlockNumber.SendRequestAsync();
var balance = await web3.Eth.GetBalance.SendRequestAsync("0x742d35Cc6634C0532925a3b844Bc454e4438f44e");
For advanced scenarios, you can use RPC methods directly:
using Nethereum.JsonRpc.Client;
using Nethereum.RPC.Eth.Blocks;
using Nethereum.RPC.Eth;
var client = new RpcClient(new Uri("https://mainnet.infura.io/v3/YOUR-PROJECT-ID"));
// Direct RPC method instantiation
var ethBlockNumber = new EthBlockNumber(client);
var blockNumber = await ethBlockNumber.SendRequestAsync();
var ethGetBalance = new EthGetBalance(client);
var balance = await ethGetBalance.SendRequestAsync("0x742d35Cc6634C0532925a3b844Bc454e4438f44e");
The package is organized by RPC method category:
Nethereum.RPC/
├── Eth/ # Ethereum methods (eth_*)
│ ├── Blocks/ # Block-related methods
│ ├── Transactions/ # Transaction methods
│ ├── Filters/ # Event filtering
│ ├── Services/ # Block services
│ └── DTOs/ # Data transfer objects
├── Net/ # Network methods (net_*)
├── Web3/ # Web3 methods (web3_*)
├── Personal/ # Personal methods (personal_*)
├── Shh/ # Whisper methods (shh_*)
├── DebugNode/ # Debug methods (debug_*)
├── Chain/ # Chain-specific methods
├── TransactionManagers/ # Transaction management
├── NonceServices/ # Nonce tracking
├── Fee1559Suggestions/ # EIP-1559 fee estimation
├── EthApiService.cs # Service wrapper for Eth methods
├── NetApiService.cs # Service wrapper for Net methods
└── PersonalApiService.cs # Service wrapper for Personal methods
using Nethereum.JsonRpc.Client;
using Nethereum.RPC.Eth.Blocks;
using Nethereum.RPC.Eth.DTOs;
var client = new RpcClient(new Uri("https://mainnet.infura.io/v3/YOUR-PROJECT-ID"));
// Get current block number
var ethBlockNumber = new EthBlockNumber(client);
var blockNumber = await ethBlockNumber.SendRequestAsync();
Console.WriteLine($"Current block: {blockNumber.Value}");
// Get block by number
var ethGetBlockByNumber = new EthGetBlockByNumber(client);
var block = await ethGetBlockByNumber.SendRequestAsync(
new BlockParameter(blockNumber),
returnFullTransactionObjects: false
);
Console.WriteLine($"Block hash: {block.BlockHash}");
Console.WriteLine($"Block timestamp: {block.Timestamp.Value}");
Console.WriteLine($"Transaction count: {block.TransactionHashes.Length}");
Output:
Current block: 18500000
Block hash: 0x1234...
Block timestamp: 1697000000
Transaction count: 150
using Nethereum.JsonRpc.Client;
using Nethereum.RPC.Eth;
using Nethereum.RPC.Eth.DTOs;
var client = new RpcClient(new Uri("https://mainnet.infura.io/v3/YOUR-PROJECT-ID"));
var ethGetBalance = new EthGetBalance(client);
// Get balance at latest block
var balance = await ethGetBalance.SendRequestAsync(
"0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
BlockParameter.CreateLatest()
);
// Convert from Wei to Ether
var etherBalance = Web3.Convert.FromWei(balance.Value);
Console.WriteLine($"Balance: {etherBalance} ETH");
// Get balance at specific block
var blockNumber = new BlockParameter(18000000);
var historicalBalance = await ethGetBalance.SendRequestAsync(
"0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
blockNumber
);
Console.WriteLine($"Historical balance: {Web3.Convert.FromWei(historicalBalance.Value)} ETH");
Source: tests/Nethereum.RPC.IntegrationTests/Testers/EthGetBalanceTester.cs
using Nethereum.JsonRpc.Client;
using Nethereum.RPC.Eth.Transactions;
using Nethereum.RPC.Eth.DTOs;
var client = new RpcClient(new Uri("https://mainnet.infura.io/v3/YOUR-PROJECT-ID"));
// Example: Call a contract method (e.g., balanceOf)
var ethCall = new EthCall(client);
var callInput = new CallInput
{
To = "0x32eb97b8ad202b072fd9066c03878892426320ed",
From = "0x12890D2cce102216644c59daE5baed380d84830c",
// Function signature + encoded parameters
Data = "0xc6888fa10000000000000000000000000000000000000000000000000000000000000045"
};
var result = await ethCall.SendRequestAsync(callInput, BlockParameter.CreateLatest());
Console.WriteLine($"Call result: {result}");
// For typed contract interactions, use Nethereum.Contracts instead
Source: tests/Nethereum.RPC.IntegrationTests/Testers/EthCallTester.cs
using Nethereum.JsonRpc.Client;
using Nethereum.RPC.Eth.Transactions;
using Nethereum.RPC.Eth.DTOs;
var client = new RpcClient(new Uri("https://mainnet.infura.io/v3/YOUR-PROJECT-ID"));
var ethEstimateGas = new EthEstimateGas(client);
var transactionInput = new CallInput
{
From = "0x12890D2cce102216644c59daE5baed380d84830c",
To = "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
Value = new Nethereum.Hex.HexTypes.HexBigInteger(1000000000000000000), // 1 ETH
};
var gasEstimate = await ethEstimateGas.SendRequestAsync(transactionInput);
Console.WriteLine($"Estimated gas: {gasEstimate.Value}");
// Use the estimate with a buffer for actual transaction
var gasLimit = gasEstimate.Value * 110 / 100; // 10% buffer
Console.WriteLine($"Recommended gas limit: {gasLimit}");
using Nethereum.JsonRpc.Client;
using Nethereum.RPC.Eth;
var client = new RpcClient(new Uri("https://mainnet.infura.io/v3/YOUR-PROJECT-ID"));
var ethChainId = new EthChainId(client);
var chainId = await ethChainId.SendRequestAsync();
Console.WriteLine($"Chain ID: {chainId.Value}");
// Common chain IDs:
// 1 = Ethereum Mainnet
// 5 = Goerli
// 11155111 = Sepolia
// 137 = Polygon
// 42161 = Arbitrum
Source: tests/Nethereum.RPC.IntegrationTests/Testers/EthChainIdTester.cs
using Nethereum.JsonRpc.WebSocketClient;
using Nethereum.JsonRpc.IpcClient;
using Nethereum.RPC.Eth.Blocks;
using Nethereum.Web3;
using Nethereum.Web3.Accounts.Managed;
// WebSocket client
var clientWs = new WebSocketClient("ws://127.0.0.1:8546");
var web3Ws = new Web3(clientWs);
var blockNumberWs = await web3Ws.Eth.Blocks.GetBlockNumber.SendRequestAsync();
Console.WriteLine($"Block number (WebSocket): {blockNumberWs.Value}");
// IPC client (Unix socket or named pipe)
var clientIpc = new IpcClient("jsonrpc.ipc");
var web3Ipc = new Web3(clientIpc);
var blockNumberIpc = await web3Ipc.Eth.Blocks.GetBlockNumber.SendRequestAsync();
Console.WriteLine($"Block number (IPC): {blockNumberIpc.Value}");
// With managed account
var account = new ManagedAccount("0x12890d2cce102216644c59daE5baed380d84830c", "password");
var web3WithAccount = new Web3(account, clientWs);
Source: consoletests/Nethereum.Parity.Reactive.ConsoleTest/Program.cs
using Nethereum.RPC.Eth;
using Nethereum.RPC.Eth.DTOs;
// Build request without sending it (useful for batching or custom handling)
var ethGetBalance = new EthGetBalance();
var request = ethGetBalance.BuildRequest(
"0x12890d2cce102216644c59daE5baed380d84830c",
BlockParameter.CreateLatest()
);
Console.WriteLine($"Method: {request.Method}");
Console.WriteLine($"Params: {string.Join(", ", request.RawParameters)}");
// You can now send this request through any client
// Or batch multiple requests together
var ethBlockNumber = new EthBlockNumber();
var request2 = ethBlockNumber.BuildRequest();
// Both requests can be sent in a batch
Source: consoletests/Nethereum.Parity.Reactive.ConsoleTest/Program.cs
using Nethereum.JsonRpc.Client;
using Nethereum.RPC.Net;
var client = new RpcClient(new Uri("https://mainnet.infura.io/v3/YOUR-PROJECT-ID"));
// Get network version (chain ID as string)
var netVersion = new NetVersion(client);
var version = await netVersion.SendRequestAsync();
Console.WriteLine($"Network version: {version}");
// Check if node is listening for network connections
var netListening = new NetListening(client);
var isListening = await netListening.SendRequestAsync();
Console.WriteLine($"Node listening: {isListening}");
// Get peer count
var netPeerCount = new NetPeerCount(client);
var peerCount = await netPeerCount.SendRequestAsync();
Console.WriteLine($"Peer count: {peerCount.Value}");
using Nethereum.JsonRpc.Client;
using Nethereum.RPC.Eth.Transactions;
using Nethereum.RPC.Eth.DTOs;
var client = new RpcClient(new Uri("https://mainnet.infura.io/v3/YOUR-PROJECT-ID"));
var ethGetTransactionReceipt = new EthGetTransactionReceipt(client);
var txHash = "0x1234..."; // Your transaction hash
var receipt = await ethGetTransactionReceipt.SendRequestAsync(txHash);
if (receipt != null)
{
Console.WriteLine($"Transaction status: {(receipt.Status.Value == 1 ? "Success" : "Failed")}");
Console.WriteLine($"Block number: {receipt.BlockNumber.Value}");
Console.WriteLine($"Gas used: {receipt.GasUsed.Value}");
Console.WriteLine($"Contract address: {receipt.ContractAddress}"); // If contract creation
// Decode events (logs)
foreach (var log in receipt.Logs)
{
Console.WriteLine($"Log address: {log.Address}");
Console.WriteLine($"Log topics: {string.Join(", ", log.Topics)}");
}
}
else
{
Console.WriteLine("Transaction not found or pending");
}
using Nethereum.JsonRpc.Client;
using Nethereum.RPC.Eth;
using Nethereum.RPC.Eth.DTOs;
var client = new RpcClient(new Uri("https://mainnet.infura.io/v3/YOUR-PROJECT-ID"));
// Get max priority fee per gas (tip to miner)
var ethMaxPriorityFeePerGas = new EthMaxPriorityFeePerGas(client);
var maxPriorityFee = await ethMaxPriorityFeePerGas.SendRequestAsync();
Console.WriteLine($"Max priority fee: {maxPriorityFee.Value} wei");
// Get base fee from latest block
var ethGetBlockByNumber = new EthGetBlockByNumber(client);
var block = await ethGetBlockByNumber.SendRequestAsync(
BlockParameter.CreateLatest(),
false
);
var baseFee = block.BaseFeePerGas;
Console.WriteLine($"Base fee: {baseFee.Value} wei");
// Calculate max fee per gas (base fee + priority fee + buffer)
var maxFeePerGas = baseFee.Value + (maxPriorityFee.Value * 2);
Console.WriteLine($"Recommended max fee: {maxFeePerGas} wei");
// Use in EIP-1559 transaction
var tx1559 = new TransactionInput
{
From = "0x12890D2cce102216644c59daE5baed380d84830c",
To = "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
Value = new Nethereum.Hex.HexTypes.HexBigInteger(1000000000000000000),
MaxPriorityFeePerGas = maxPriorityFee,
MaxFeePerGas = new Nethereum.Hex.HexTypes.HexBigInteger(maxFeePerGas),
Type = new Nethereum.Hex.HexTypes.HexBigInteger(2) // EIP-1559 transaction type
};
The package provides service classes that group related RPC methods:
Provides access to all Ethereum RPC methods:
using Nethereum.JsonRpc.Client;
using Nethereum.RPC;
var client = new RpcClient(new Uri("https://mainnet.infura.io/v3/YOUR-PROJECT-ID"));
var ethApi = new EthApiService(client);
// Access any Eth method through the service
var blockNumber = await ethApi.Blocks.GetBlockNumber.SendRequestAsync();
var balance = await ethApi.GetBalance.SendRequestAsync("0x742d35Cc6634C0532925a3b844Bc454e4438f44e");
var gasPrice = await ethApi.GasPrice.SendRequestAsync();
Provides access to network RPC methods:
var netApi = new NetApiService(client);
var version = await netApi.Version.SendRequestAsync();
var peerCount = await netApi.PeerCount.SendRequestAsync();
var isListening = await netApi.Listening.SendRequestAsync();
Provides access to personal/account RPC methods:
var personalApi = new PersonalApiService(client);
// Note: Most nodes disable personal API methods for security
var accounts = await personalApi.ListAccounts.SendRequestAsync();
Many RPC methods accept a BlockParameter to specify which block to query:
using Nethereum.RPC.Eth.DTOs;
// Latest block
var latest = BlockParameter.CreateLatest();
// Earliest block (genesis)
var earliest = BlockParameter.CreateEarliest();
// Pending block
var pending = BlockParameter.CreatePending();
// Specific block number
var specific = new BlockParameter(18000000);
// Use with any method that accepts block parameter
var balance = await ethGetBalance.SendRequestAsync(address, latest);
The package supports all Ethereum transaction types:
using Nethereum.RPC.Eth.DTOs;
using Nethereum.Hex.HexTypes;
// Legacy transaction (Type 0)
var legacyTx = new TransactionInput
{
From = "0x...",
To = "0x...",
Value = new HexBigInteger(1000000000000000000),
Gas = new HexBigInteger(21000),
GasPrice = new HexBigInteger(20000000000) // 20 gwei
};
// EIP-2930 transaction (Type 1) - with access list
var eip2930Tx = new TransactionInput
{
From = "0x...",
To = "0x...",
Type = new HexBigInteger(1),
AccessList = new AccessListItem[]
{
new AccessListItem
{
Address = "0x...",
StorageKeys = new[] { "0x..." }
}
}
};
// EIP-1559 transaction (Type 2) - with dynamic fees
var eip1559Tx = new TransactionInput
{
From = "0x...",
To = "0x...",
Type = new HexBigInteger(2),
MaxPriorityFeePerGas = new HexBigInteger(2000000000), // 2 gwei tip
MaxFeePerGas = new HexBigInteger(50000000000) // 50 gwei max
};
The package includes comprehensive DTOs for all RPC requests and responses:
BlockWithTransactions / Block - Block informationTransaction - Transaction detailsTransactionReceipt - Transaction receipt with logsFilterInput - Event filter configurationLog - Event log entryCallInput / TransactionInput - Transaction/call inputSyncStatus - Node sync statusAccessListItem - EIP-2930 access listAll DTOs are in the Nethereum.RPC.Eth.DTOs namespace.
using Nethereum.JsonRpc.Client;
using Nethereum.RPC.Eth;
var client = new RpcClient(new Uri("https://mainnet.infura.io/v3/YOUR-PROJECT-ID"));
var ethGetBalance = new EthGetBalance(client);
try
{
var balance = await ethGetBalance.SendRequestAsync(
"0xinvalid-address",
BlockParameter.CreateLatest()
);
}
catch (RpcResponseException ex)
{
Console.WriteLine($"RPC Error: {ex.Message}");
Console.WriteLine($"RPC Error Code: {ex.RpcError?.Code}");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
Use Web3 for Most Scenarios: Unless you need direct RPC access, use the Web3 API which provides a more convenient interface
Reuse Client Instances: Create one client and reuse it across multiple RPC method instances
Handle Null Responses: Some methods return null (e.g., pending transactions, receipts for pending txs)
Use BlockParameter Appropriately:
Latest - Most recent block (may reorganize)Finalized - Finalized block (after merge, more stable)Batch Requests When Possible: For multiple independent queries, use batch requests to reduce round trips
Choose the Right Client:
EIP-1559 Gas Estimation: Always query eth_maxPriorityFeePerGas and base fee from latest block for accurate EIP-1559 transactions
Error Handling: Always handle RpcResponseException for RPC-level errors (invalid params, execution reverted, etc.)
The package includes transaction manager infrastructure for handling nonce tracking and transaction lifecycle:
using Nethereum.RPC.TransactionManagers;
using Nethereum.RPC.NonceServices;
// Custom nonce management
var nonceService = new InMemoryNonceService(address, client);
var currentNonce = await nonceService.GetNextNonceAsync();
For dynamic gas fee estimation:
using Nethereum.RPC.Fee1559Suggestions;
var feeSuggestionService = new Fee1559SuggestionService(client);
var suggestion = await feeSuggestionService.SuggestFeeAsync();
Console.WriteLine($"Suggested base fee: {suggestion.BaseFee}");
Console.WriteLine($"Suggested max priority fee: {suggestion.MaxPriorityFeePerGas}");
Console.WriteLine($"Suggested max fee: {suggestion.MaxFeePerGas}");
The package includes comprehensive integration tests demonstrating all RPC methods:
tests/Nethereum.RPC.IntegrationTests/Testers/
├── EthGetBalanceTester.cs
├── EthBlockNumberTester.cs
├── EthCallTester.cs
├── EthChainIdTester.cs
├── EthSendTransactionTester.cs
└── ... (50+ test classes)