Nethereum.Web3 Ethereum Web3 Class Library to interact via RPC with an Ethereum client, for example geth. Including contract interaction, deployment, transaction, encoding / decoding and event filters
$ dotnet add package Nethereum.Web3Nethereum.Web3 is the main facade and entry point for interacting with Ethereum. It provides a high-level API that combines RPC methods, contract interaction, account management, and utility functions into a single, easy-to-use interface.
dotnet add package Nethereum.Web3
Web3 uses the Facade pattern to provide a unified, simplified interface to the complex subsystems of Ethereum interaction. Instead of instantiating multiple services separately, you create a single Web3 instance that provides access to everything you need.
The main entry points are:
web3.Eth - Primary Ethereum operations (transactions, blocks, contracts)web3.TransactionManager - Transaction signing and sendingweb3.TransactionReceiptPolling - Wait for transaction confirmationsWeb3.Convert - Static utility for unit conversionsWeb3 supports two connection models:
IAccount to sign and send transactionsWeb3 provides built-in services for common standards:
From: Nethereum Playground Example 1001
using Nethereum.Web3;
// Connect to a public RPC endpoint
var web3 = new Web3("https://eth.drpc.org");
// Get account balance
var balance = await web3.Eth.GetBalance
.SendRequestAsync("0x742d35Cc6634C0532925a3b844Bc454e4438f44e");
// Convert Wei to Ether
var etherBalance = Web3.Convert.FromWei(balance.Value);
Console.WriteLine($"Balance: {etherBalance} ETH");
using Nethereum.Web3;
using Nethereum.Web3.Accounts;
// Create account from private key
var account = new Account("0xPRIVATE_KEY_HERE");
// Initialize Web3 with account
var web3 = new Web3(account, "http://localhost:8545");
// Now you can send transactions
var receipt = await web3.Eth.GetEtherTransferService()
.TransferEtherAndWaitForReceiptAsync(
"0x12890d2cce102216644c59daE5baed380d84830c",
0.01m
);
Console.WriteLine($"Transaction Hash: {receipt.TransactionHash}");
Console.WriteLine($"Block Number: {receipt.BlockNumber}");
Console.WriteLine($"Gas Used: {receipt.GasUsed}");
From: Nethereum Playground Example 1002
var web3 = new Web3("https://eth.drpc.org");
// Get latest block with transactions
var block = await web3.Eth.Blocks.GetBlockWithTransactionsByNumber
.SendRequestAsync(BlockParameter.CreateLatest());
Console.WriteLine($"Block Number: {block.Number}");
Console.WriteLine($"Block Hash: {block.BlockHash}");
Console.WriteLine($"Transactions: {block.Transactions.Length}");
Console.WriteLine($"Timestamp: {DateTimeOffset.FromUnixTimeSeconds((long)block.Timestamp.Value)}");
From: Nethereum Playground Example 1005
var web3 = new Web3("https://eth.drpc.org");
// Get ERC20 contract service (built-in support)
// Using MKR token address as example
var tokenService = web3.Eth.ERC20.GetContractService(
"0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2"
);
// Query token balance
var balance = await tokenService.BalanceOfQueryAsync(
"0x8ee7d9235e01e6b42345120b5d270bdb763624c7"
);
// Get token metadata
var name = await tokenService.NameQueryAsync();
var symbol = await tokenService.SymbolQueryAsync();
var decimals = await tokenService.DecimalsQueryAsync();
// Convert from Wei to human-readable format
var balanceInTokens = Web3.Convert.FromWei(balance, decimals);
Console.WriteLine($"{symbol} Balance: {balanceInTokens}");
Built-in ERC20 Operations:
// Transfer tokens (requires account)
var receipt = await tokenService.TransferRequestAndWaitForReceiptAsync(
toAddress,
amount
);
// Approve spending
await tokenService.ApproveRequestAndWaitForReceiptAsync(
spenderAddress,
allowance
);
// Check allowance
var allowance = await tokenService.AllowanceQueryAsync(
ownerAddress,
spenderAddress
);
// Get total supply
var totalSupply = await tokenService.TotalSupplyQueryAsync();
From: Nethereum Playground Example 1014
using Nethereum.Web3;
// Convert Ether to Wei
var weiAmount = Web3.Convert.ToWei(1.5m); // 1.5 Ether to Wei
// Convert Wei to Ether
var etherAmount = Web3.Convert.FromWei(1500000000000000000); // Wei to Ether
// Convert to/from Gwei (useful for gas prices)
var gweiAmount = Web3.Convert.FromWei(20000000000, UnitConversion.EthUnit.Gwei);
var weiFromGwei = Web3.Convert.ToWei(20, UnitConversion.EthUnit.Gwei);
// Custom decimal places (e.g., USDC with 6 decimals)
var usdcAmount = Web3.Convert.FromWei(1000000, 6); // 1 USDC
var usdcInWei = Web3.Convert.ToWei(1, 6); // 1 USDC to smallest unit
From: Nethereum Playground Example 1006
using Nethereum.Web3;
using Nethereum.Web3.Accounts;
var account = new Account("0xPRIVATE_KEY");
var web3 = new Web3(account, "http://localhost:8545");
// Using generated deployment message
var deploymentHandler = web3.Eth.GetContractDeploymentHandler<StandardTokenDeployment>();
var deploymentMessage = new StandardTokenDeployment
{
TotalSupply = 100000,
Name = "My Token",
Symbol = "MTK",
Decimals = 18
};
var receipt = await deploymentHandler.SendRequestAndWaitForReceiptAsync(deploymentMessage);
var contractAddress = receipt.ContractAddress;
Console.WriteLine($"Contract deployed at: {contractAddress}");
Console.WriteLine($"Gas used: {receipt.GasUsed}");
Alternative: Deploy with ABI and Bytecode
// For contracts without code generation
var receipt = await web3.Eth.DeployContract.SendRequestAndWaitForReceiptAsync(
abi: contractAbi,
bytecode: contractBytecode,
from: account.Address,
gas: new HexBigInteger(900000),
constructorParams: new object[] { "TokenName", "SYMBOL", 18 }
);
Console.WriteLine($"Contract Address: {receipt.ContractAddress}");
For comprehensive code generation guide, see:
var web3 = new Web3("https://eth.drpc.org");
var contractAddress = "0x...";
// Using generated function messages
var balanceHandler = web3.Eth.GetContractQueryHandler<BalanceOfFunction>();
var balanceMessage = new BalanceOfFunction
{
Owner = "0x742d35Cc6634C0532925a3b844Bc454e4438f44e"
};
// Query and return primitive type
var balance = await balanceHandler.QueryAsync<BigInteger>(
contractAddress,
balanceMessage
);
// Query and deserialize to output DTO
var balanceOutput = await balanceHandler
.QueryDeserializingToObjectAsync<BalanceOfOutputDTO>(
balanceMessage,
contractAddress
);
Console.WriteLine($"Balance: {balanceOutput.Balance}");
Alternative: Using Contract Handler
// Get contract handler for specific address
var contractHandler = web3.Eth.GetContractHandler(contractAddress);
// Query functions
var result = await contractHandler.QueryAsync<BalanceOfFunction, BigInteger>(
new BalanceOfFunction { Owner = ownerAddress }
);
var account = new Account("0xPRIVATE_KEY");
var web3 = new Web3(account, "http://localhost:8545");
var contractAddress = "0x...";
// Create transaction handler
var transferHandler = web3.Eth.GetContractTransactionHandler<TransferFunction>();
// Prepare transaction message
var transfer = new TransferFunction
{
To = "0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe",
TokenAmount = 100
};
// Send transaction and wait for receipt
var receipt = await transferHandler
.SendRequestAndWaitForReceiptAsync(contractAddress, transfer);
Console.WriteLine($"Transaction successful in block: {receipt.BlockNumber}");
Console.WriteLine($"Status: {receipt.Status}"); // 1 = success, 0 = failure
Gas Estimation:
// Estimate gas before sending
var estimatedGas = await transferHandler.EstimateGasAsync(
contractAddress,
transfer
);
transfer.Gas = estimatedGas.Value;
var receipt = await transferHandler
.SendRequestAndWaitForReceiptAsync(contractAddress, transfer);
From: Nethereum Playground Example 1008
var web3 = new Web3("https://eth.drpc.org");
var contractAddress = "0x...";
// Get event handler
var transferEvent = web3.Eth.GetEvent<TransferEventDTO>(contractAddress);
// Create filter for all Transfer events
var filterAll = transferEvent.CreateFilterInput(
fromBlock: new BlockParameter(12000000),
toBlock: new BlockParameter(12000100)
);
// Get all historical events
var allEvents = await transferEvent.GetAllChangesAsync(filterAll);
foreach (var evt in allEvents)
{
Console.WriteLine($"From: {evt.Event.From}");
Console.WriteLine($"To: {evt.Event.To}");
Console.WriteLine($"Value: {evt.Event.Value}");
Console.WriteLine($"Block: {evt.Log.BlockNumber}");
Console.WriteLine($"TxHash: {evt.Log.TransactionHash}");
}
Decode Events from Receipt:
// Decode events directly from transaction receipt
var receipt = await web3.Eth.Transactions.GetTransactionReceipt
.SendRequestAsync(txHash);
var transferEvents = receipt.DecodeAllEvents<TransferEventDTO>();
foreach (var evt in transferEvents)
{
Console.WriteLine($"Transfer: {evt.Event.From} -> {evt.Event.To}: {evt.Event.Value}");
}
Filter Events by Indexed Parameters:
// Filter by sender (first indexed parameter)
var filterBySender = transferEvent.CreateFilterInput(
fromBlock: BlockParameter.CreateEarliest(),
toBlock: BlockParameter.CreateLatest(),
filterTopic1: new object[] { senderAddress }
);
// Filter by recipient (second indexed parameter)
var filterByRecipient = transferEvent.CreateFilterInput(
fromBlock: BlockParameter.CreateEarliest(),
toBlock: BlockParameter.CreateLatest(),
filterTopic2: new object[] { recipientAddress }
);
// Multiple recipients (OR condition)
var filterMultiple = transferEvent.CreateFilterInput(
fromBlock: BlockParameter.CreateEarliest(),
toBlock: BlockParameter.CreateLatest(),
filterTopic2: new object[] { recipient1, recipient2 }
);
var events = await transferEvent.GetAllChangesAsync(filterBySender);
From: Nethereum Playground Example 1055
var web3 = new Web3("https://eth.drpc.org");
var ensService = web3.Eth.GetEnsService();
// Resolve ENS name to address
var address = await ensService.ResolveAddressAsync("nick.eth");
Console.WriteLine($"Address: {address}");
// Reverse resolve (address to ENS name)
var name = await ensService.ReverseResolveAsync(
"0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb"
);
Console.WriteLine($"ENS Name: {name}");
// Resolve text records
var url = await ensService.ResolveTextAsync("nethereum.eth", TextDataKey.url);
var email = await ensService.ResolveTextAsync("nethereum.eth", TextDataKey.email);
var avatar = await ensService.ResolveTextAsync("nethereum.eth", TextDataKey.avatar);
Console.WriteLine($"URL: {url}");
Console.WriteLine($"Email: {email}");
ENS supports emojis and special characters:
// Emoji domains work natively
var address = await ensService.ResolveAddressAsync("💩💩💩.eth");
// ENS names are automatically normalized
var normalizedName = new EnsUtil().Normalise("Foo.eth"); // Returns "foo.eth"
From: Nethereum Playground Example 1003
var account = new Account("0xPRIVATE_KEY");
var web3 = new Web3(account, "http://localhost:8545");
// Send Ether transfer
var ethSenderService = web3.Eth.GetEtherTransferService();
var transactionHash = await ethSenderService
.TransferEtherAsync("0x12890d2cce102216644c59daE5baed380d84830c", 0.01m);
Console.WriteLine($"Transaction Hash: {transactionHash}");
// Poll for receipt (with optional cancellation token)
var cancellationToken = new CancellationTokenSource().Token;
var receipt = await web3.TransactionReceiptPolling
.PollForReceiptAsync(transactionHash, cancellationToken);
if (receipt != null)
{
Console.WriteLine($"Transaction Receipt: {receipt.TransactionHash}");
Console.WriteLine($"Block Number: {receipt.BlockNumber}");
Console.WriteLine($"Gas Used: {receipt.GasUsed}");
Console.WriteLine($"Status: {receipt.Status}"); // 1 = success, 0 = failure
}
Smart contracts can throw custom errors (Solidity custom errors). Nethereum can decode these errors:
var account = new Account("0xPRIVATE_KEY");
var web3 = new Web3(account, "http://localhost:8545");
var contract = web3.Eth.GetContract(contractAbi, contractAddress);
var transferFunction = contract.GetFunction("transfer");
try
{
// This will throw a custom error
await transferFunction.SendTransactionAndWaitForReceiptAsync(
web3.TransactionManager.Account.Address,
gas: null,
value: null,
functionInput: new object[] { toAddress, 100 }
);
}
catch (SmartContractCustomErrorRevertException error)
{
// Check if it's our specific error
if (error.IsCustomErrorFor<InsufficientBalanceError>())
{
// Decode the error with parameters
var insufficientBalance = error.DecodeError<InsufficientBalanceError>();
Console.WriteLine($"Insufficient Balance!");
Console.WriteLine($"Required: {insufficientBalance.Required}");
Console.WriteLine($"Available: {insufficientBalance.Available}");
}
}
Define Custom Error:
[Error("InsufficientBalance")]
public class InsufficientBalanceError
{
[Parameter("uint256", "available", 1)]
public BigInteger Available { get; set; }
[Parameter("uint256", "required", 2)]
public BigInteger Required { get; set; }
}
using Nethereum.Web3;
using Nethereum.JsonRpc.SystemTextJsonRpcClient;
using Nethereum.JsonRpc.WebSocketClient;
// HTTP client (default) - uses Newtonsoft.Json
var web3Http = new Web3("https://eth.drpc.org");
// AOT-compatible SimpleRpcClient - uses System.Text.Json
var simpleClient = new SimpleRpcClient("https://eth.drpc.org");
var web3Simple = new Web3(simpleClient);
// WebSocket client for real-time data
var wsClient = new WebSocketClient("wss://eth.drpc.org");
var web3Ws = new Web3(wsClient);
// Enable System.Text.Json for AOT compatibility
Nethereum.ABI.ABIDeserialisation.AbiDeserializationSettings.UseSystemTextJson = true;
// Configure signature algorithm for AOT
Nethereum.Signer.EthECKey.SignRecoverable = false;
// Now use Web3 normally with AOT-compatible client
var client = new SimpleRpcClient("https://eth.drpc.org");
var web3 = new Web3(client);
var account1 = new Account("0xPRIVATE_KEY_1");
var account2 = new Account("0xPRIVATE_KEY_2");
var web3_1 = new Web3(account1, "http://localhost:8545");
var web3_2 = new Web3(account2, "http://localhost:8545");
// Or switch accounts dynamically
var web3 = new Web3("http://localhost:8545");
web3.TransactionManager.Account = account1; // Use account1
await DoSomeWork(web3);
web3.TransactionManager.Account = account2; // Switch to account2
await DoSomeMoreWork(web3);
// For frequently accessed contracts, use contract handler
var contractAddress = "0x...";
var contractHandler = web3.Eth.GetContractHandler(contractAddress);
// Query
var balance = await contractHandler.QueryAsync<BalanceOfFunction, BigInteger>(
new BalanceOfFunction { Owner = ownerAddress }
);
// Transaction
var receipt = await contractHandler.SendRequestAndWaitForReceiptAsync(
new TransferFunction { To = toAddress, TokenAmount = 100 }
);
// Estimate gas
var estimatedGas = await contractHandler.EstimateGasAsync(
new TransferFunction { To = toAddress, TokenAmount = 100 }
);
var contractHandler = web3.Eth.GetContractHandler(contractAddress);
// Query current state
var currentBalance = await contractHandler.QueryAsync<BalanceOfFunction, BigInteger>(
new BalanceOfFunction { Owner = ownerAddress }
);
// Query historical state at specific block
var historicalBalance = await contractHandler.QueryAsync<BalanceOfFunction, BigInteger>(
new BalanceOfFunction { Owner = ownerAddress },
new BlockParameter(12345678) // Block number
);
Console.WriteLine($"Balance at block 12345678: {historicalBalance}");
Console.WriteLine($"Current balance: {currentBalance}");
// Batch multiple contract queries into a single RPC call
var multiQueryHandler = web3.Eth.GetMultiQueryHandler();
// Define multiple queries
var query1 = new BalanceOfFunction { Owner = address1 };
var query2 = new BalanceOfFunction { Owner = address2 };
var query3 = new BalanceOfFunction { Owner = address3 };
// Execute all queries in one call
var results = await multiQueryHandler.MultiCallAsync(
new MultiCallInput<BalanceOfFunction, BigInteger>(contractAddress, query1),
new MultiCallInput<BalanceOfFunction, BigInteger>(contractAddress, query2),
new MultiCallInput<BalanceOfFunction, BigInteger>(contractAddress, query3)
);
Console.WriteLine($"Balance 1: {results[0]}");
Console.WriteLine($"Balance 2: {results[1]}");
Console.WriteLine($"Balance 3: {results[2]}");
var account = new Account("0xPRIVATE_KEY");
var web3 = new Web3(account, "http://localhost:8545");
// 1. Deploy contract
var deploymentHandler = web3.Eth.GetContractDeploymentHandler<MyContractDeployment>();
var deployment = new MyContractDeployment { InitialValue = 100 };
var receipt = await deploymentHandler.SendRequestAndWaitForReceiptAsync(deployment);
var contractAddress = receipt.ContractAddress;
// 2. Get contract handler
var contractHandler = web3.Eth.GetContractHandler(contractAddress);
// 3. Call functions
var value = await contractHandler.QueryAsync<GetValueFunction, int>();
await contractHandler.SendRequestAndWaitForReceiptAsync(
new SetValueFunction { NewValue = 200 }
);
var web3 = new Web3("https://eth.drpc.org");
// Work with multiple contracts
var usdcService = web3.Eth.ERC20.GetContractService(
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" // USDC
);
var uniService = web3.Eth.ERC20.GetContractService(
"0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" // UNI
);
var usdcBalance = await usdcService.BalanceOfQueryAsync(myAddress);
var uniBalance = await uniService.BalanceOfQueryAsync(myAddress);
Console.WriteLine($"USDC: {Web3.Convert.FromWei(usdcBalance, 6)}");
Console.WriteLine($"UNI: {Web3.Convert.FromWei(uniBalance, 18)}");
var web3 = new Web3("https://eth.drpc.org");
var contractAddress = "0x...";
// Get event handler
var transferEvent = web3.Eth.GetEvent<TransferEventDTO>(contractAddress);
// Create and save filter
var filterId = await transferEvent.CreateFilterAsync(
transferEvent.CreateFilterInput(fromBlock: BlockParameter.CreateLatest())
);
// Poll for new events periodically
while (true)
{
var newEvents = await transferEvent.GetFilterChangesAsync(filterId);
foreach (var evt in newEvents)
{
Console.WriteLine($"New transfer: {evt.Event.From} -> {evt.Event.To}: {evt.Event.Value}");
}
await Task.Delay(5000); // Wait 5 seconds
}
web3.Eth (IEthApiContractService) - Ethereum-related methods (transactions, blocks, contracts)web3.TransactionManager (ITransactionManager) - Transaction signing and managementweb3.TransactionReceiptPolling (ITransactionReceiptService) - Wait for transaction receiptsweb3.Processing (IBlockchainProcessingService) - Block/transaction/log processingweb3.Net (INetApiService) - Network informationweb3.Personal (IPersonalApiService) - Personal RPC methodsweb3.Debug (IDebugApiService) - Debug RPC methodsweb3.FeeSuggestion (FeeSuggestionService) - Fee estimationWeb3.Convert (UnitConversion) - Static utility for unit conversions (Wei/Gwei/Ether)web3.Eth.GetContractHandler(address) - Get contract handler for addressweb3.Eth.GetContract(abi, address) - Get dynamic contract instanceweb3.Eth.DeployContract - Deploy contract with ABI and bytecodeweb3.Eth.GetContractDeploymentHandler<T>() - Get typed deployment handlerweb3.Eth.GetContractTransactionHandler<T>() - Get typed transaction handlerweb3.Eth.GetContractQueryHandler<T>() - Get typed query handlerweb3.Eth.GetEvent<T>() - Get event handler (no address specified)web3.Eth.GetEvent<T>(address) - Get event handler for specific contractweb3.Eth.GetContractTransactionErrorReason - Decode transaction error reasonsweb3.Eth.ERC20.GetContractService(address) - ERC20 token serviceweb3.Eth.ERC721.GetContractService(address) - ERC721 NFT serviceweb3.Eth.ERC1155.GetContractService(address) - ERC1155 multi-token serviceweb3.Eth.ERC1271 - ERC1271 contract signature validation serviceweb3.Eth.ERC165 - ERC165 interface detection serviceweb3.Eth.ERC2535Diamond - ERC2535 Diamond standard serviceweb3.Eth.ERC6492 - ERC6492 pre-deployed contract signature validationweb3.Eth.EIP3009 - EIP-3009 transfer with authorization (USDC)web3.Eth.GetEnsService() - ENS resolver serviceweb3.Eth.GetEnsEthTlsService() - ENS .eth TLD serviceweb3.Eth.GetEtherTransferService() - Simple Ether transfer serviceweb3.Eth.ProofOfHumanity - Proof of Humanity registry serviceweb3.Eth.Create2DeterministicDeploymentProxyService - CREATE2 deployment serviceweb3.Eth.GetMultiQueryHandler(multiCallAddress) - Multicall contract-based batchingweb3.Eth.GetMultiQueryBatchRpcHandler() - RPC batch request handlerWeb3.Convert.ToWei(amount, unit) - Convert to WeiWeb3.Convert.FromWei(amount, unit) - Convert from WeiWeb3.IsChecksumAddress(address) - Validate EIP-55 checksum addressWeb3.ToChecksumAddress(address) - Convert to EIP-55 checksum addressWeb3.ToValid20ByteAddress(address) - Normalize to 20-byte addressWeb3.Sha3(value) - Calculate Keccak-256 hashWeb3.GetAddressFromPrivateKey(privateKey) - Derive address from private keyweb3.GetEIP7022SponsorAuthorisation() - EIP-7022 sponsor authorization serviceRunnable examples available at Nethereum Playground:
Basic Operations:
Transactions:
Smart Contracts:
Events:
ENS:
For in-depth documentation:
Always check receipt.Status after waiting for receipt:
Status = 1 (or 0x1) - Transaction succeededStatus = 0 (or 0x0) - Transaction failed (reverted)Web3 supports multiple gas price strategies:
GasPrice fieldMaxFeePerGas and MaxPriorityFeePerGas fieldsweb3.FeeSuggestion service for optimal fee estimationNever hardcode private keys in production code: