Nethereum.Model Ethereum Core Model Class Library
$ dotnet add package Nethereum.ModelCore Ethereum data models representing transactions, blocks, accounts, and cryptographic signatures.
Nethereum.Model is a foundational package that defines the core data structures used throughout the Ethereum protocol. These models represent:
This package provides the canonical implementation of Ethereum data structures with built-in RLP encoding/decoding support.
dotnet add package Nethereum.Model
Nethereum Dependencies:
Ethereum has evolved to support multiple transaction formats:
LegacyTransaction): Original transaction format (pre-EIP-155)LegacyTransactionChainId): EIP-155 transactions preventing replay attacksTransaction2930): Transactions with access lists for gas optimizationTransaction1559): Fee market transactions with base fee and priority feeTransaction7702): Account abstraction with authorization listsAll models implement RLP (Recursive Length Prefix) encoding, the serialization format used by Ethereum for:
Ethereum uses ECDSA signatures with three components:
The Chain enum provides constants for major Ethereum networks (MainNet, Sepolia, Polygon, Arbitrum, Optimism, Base, etc.) and is used with EIP-155 to prevent cross-chain replay attacks.
using Nethereum.Model;
using System.Numerics;
// Create a simple EIP-1559 transaction
var transaction = new Transaction1559(
chainId: 1, // Ethereum Mainnet
nonce: 0,
maxPriorityFeePerGas: BigInteger.Parse("2000000000"), // 2 gwei
maxFeePerGas: BigInteger.Parse("100000000000"), // 100 gwei
gasLimit: 21000,
receiverAddress: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
amount: BigInteger.Parse("1000000000000000000"), // 1 ETH
data: "",
accessList: null
);
using Nethereum.Model;
using System.Numerics;
// Create a legacy transaction (most common pre-2021)
var legacyTx = new LegacyTransaction(
to: "0x13978aee95f38490e9769c39b2773ed763d9cd5f",
amount: new BigInteger(10000000000000000L), // 0.01 ETH
nonce: 0,
gasPrice: new BigInteger(1000000000000L), // 1000 gwei
gasLimit: 10000
);
// Transaction is ready to be signed with Nethereum.Signer
Source: tests/Nethereum.Signer.UnitTests/TransactionTests.cs
using Nethereum.Model;
using Nethereum.Hex.HexConvertors.Extensions;
// RLP-encoded signed transaction (typically from network or storage)
var rlpHex = "f86b8085e8d4a510008227109413978aee95f38490e9769c39b2773ed763d9cd5f872386f26fc10000801ba0eab47c1a49bf2fe5d40e01d313900e19ca485867d462fe06e139e3a536c6d4f4a014a569d327dcda4b29f74f93c0e9729d2f49ad726e703f9cd90dbb0fbf6649f1";
// Decode the transaction
var tx = new LegacyTransaction(rlpHex.HexToByteArray());
// Access transaction properties
var nonce = tx.Nonce.ToBigIntegerFromRLPDecoded();
var gasPrice = tx.GasPrice.ToBigIntegerFromRLPDecoded();
var value = tx.Value.ToBigIntegerFromRLPDecoded();
var to = tx.ReceiveAddress.ToHex();
// Access signature components
var v = tx.Signature.V[0]; // 27 or 28 for legacy transactions
var r = tx.Signature.R.ToHex();
var s = tx.Signature.S.ToHex();
Source: tests/Nethereum.Signer.UnitTests/TransactionTests.cs
using Nethereum.Model;
// TransactionFactory automatically detects transaction type
var rlpEncoded = GetTransactionFromNetwork(); // byte[] from RPC or P2P
ISignedTransaction transaction = TransactionFactory.CreateTransaction(rlpEncoded);
// Check the transaction type
switch (transaction.TransactionType)
{
case TransactionType.LegacyTransaction:
var legacy = (LegacyTransaction)transaction;
// Handle legacy transaction
break;
case TransactionType.EIP1559:
var eip1559 = (Transaction1559)transaction;
var maxFeePerGas = eip1559.MaxFeePerGas;
var maxPriorityFee = eip1559.MaxPriorityFeePerGas;
break;
case TransactionType.LegacyEIP2930:
var eip2930 = (Transaction2930)transaction;
var accessList = eip2930.AccessList;
break;
case TransactionType.EIP7702:
var eip7702 = (Transaction7702)transaction;
var authList = eip7702.AuthorisationList;
break;
}
Source: src/Nethereum.Model/TransactionFactory.cs
using Nethereum.Model;
using System.Numerics;
using System.Collections.Generic;
// Create an access list (EIP-2930) to reduce gas costs
var accessList = new List<AccessListItem>
{
new AccessListItem(
address: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
storageKeys: new List<byte[]>
{
"0x0000000000000000000000000000000000000000000000000000000000000001".HexToByteArray()
}
)
};
// Create an EIP-1559 transaction
var tx1559 = new Transaction1559(
chainId: (BigInteger)Chain.MainNet,
nonce: 42,
maxPriorityFeePerGas: new BigInteger(2_000_000_000), // 2 gwei tip
maxFeePerGas: new BigInteger(100_000_000_000), // 100 gwei max
gasLimit: 100_000,
receiverAddress: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
amount: BigInteger.Parse("5000000000000000000"), // 5 ETH
data: "0x",
accessList: accessList
);
// Get RLP encoding for signing
var rlpForSigning = tx1559.GetRLPEncodedRaw();
Source: src/Nethereum.Model/Transaction1559.cs, src/Nethereum.Model/AccessListItem.cs
using Nethereum.Model;
using System.Numerics;
// Create an account state object (as stored in the Ethereum state trie)
var account = new Account
{
Nonce = 42, // Number of transactions sent from this address
Balance = BigInteger.Parse("5000000000000000000000"), // 5000 ETH in wei
StateRoot = stateRootHash, // Root of the account's storage trie
CodeHash = contractCodeHash // Keccak-256 hash of the contract bytecode
};
// For EOA (Externally Owned Accounts), defaults are used:
var eoa = new Account
{
Nonce = 0,
Balance = BigInteger.Parse("1000000000000000000"), // 1 ETH
StateRoot = DefaultValues.EMPTY_TRIE_HASH, // Empty storage
CodeHash = DefaultValues.EMPTY_DATA_HASH // No code
};
Source: src/Nethereum.Model/Account.cs
using Nethereum.Model;
using Nethereum.Hex.HexConvertors.Extensions;
// Create an event log (emitted by smart contracts)
var eventData = "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000".HexToByteArray();
var topic1 = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef".HexToByteArray(); // Transfer event signature
var topic2 = "0x000000000000000000000000742d35cc6634c0532925a3b844bc9e7595f0beb".HexToByteArray(); // From address
var topic3 = "0x00000000000000000000000088e6a0c2ddd26feeb64f039a2c41296fcb3f5640".HexToByteArray(); // To address
var log = Log.Create(
data: eventData,
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // Contract address
topics: new[] { topic1, topic2, topic3 }
);
// Or create log without data
var logWithoutData = Log.Create(
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
topics: topic1, topic2, topic3
);
Source: src/Nethereum.Model/Log.cs
using Nethereum.Model;
using System.Numerics;
// Construct a block header
var blockHeader = new BlockHeader
{
ParentHash = parentBlockHash,
UnclesHash = unclesHash,
Coinbase = "0x1f9090aaE28b8a3dCeaDf281B0F12828e676c326", // Miner address
StateRoot = stateRoot,
TransactionsHash = transactionsTrieRoot,
ReceiptHash = receiptsTrieRoot,
BlockNumber = 18_000_000,
LogsBloom = logsBloomFilter,
Difficulty = 0, // Post-merge (PoS) difficulty is always 0
Timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
GasLimit = 30_000_000,
GasUsed = 12_543_210,
MixHash = mixHash,
ExtraData = extraData,
Nonce = nonce,
BaseFee = new BigInteger(15_000_000_000) // EIP-1559 base fee
};
// Encode the block header for hashing
var encoded = BlockHeaderEncoder.Current.EncodeHeader(blockHeader);
Source: src/Nethereum.Model/BlockHeader.cs
using Nethereum.Model;
using Nethereum.Signer;
using System.Numerics;
// Ethereum Mainnet transaction
var mainnetTx = new Transaction1559(
chainId: (BigInteger)Chain.MainNet, // 1
nonce: 0,
maxPriorityFeePerGas: new BigInteger(2_000_000_000),
maxFeePerGas: new BigInteger(50_000_000_000),
gasLimit: 21000,
receiverAddress: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
amount: BigInteger.Parse("1000000000000000000"),
data: "",
accessList: null
);
// Polygon transaction (lower gas fees)
var polygonTx = new Transaction1559(
chainId: (BigInteger)Chain.Polygon, // 137
nonce: 0,
maxPriorityFeePerGas: new BigInteger(30_000_000_000), // 30 gwei
maxFeePerGas: new BigInteger(200_000_000_000), // 200 gwei
gasLimit: 21000,
receiverAddress: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
amount: BigInteger.Parse("1000000000000000000"),
data: "",
accessList: null
);
// Base L2 transaction
var baseTx = new Transaction1559(
chainId: (BigInteger)Chain.Base, // 8453
nonce: 0,
maxPriorityFeePerGas: new BigInteger(100_000), // Very low on L2
maxFeePerGas: new BigInteger(1_000_000),
gasLimit: 21000,
receiverAddress: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
amount: BigInteger.Parse("1000000000000000000"),
data: "",
accessList: null
);
Source: Chain.cs enum values
using Nethereum.Model;
using Nethereum.Util.HashProviders;
using Nethereum.Hex.HexConvertors.Extensions;
var sha3Provider = new Sha3KeccackHashProvider();
// Encode a storage key for the state trie
var storageKey = "0x0000000000000000000000000000000000000000000000000000000000000001".HexToByteArray();
var encodedKey = AccountStorage.EncodeKeyForStorage(storageKey, sha3Provider);
// Encode a storage value
var storageValue = "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000".HexToByteArray();
var encodedValue = AccountStorage.EncodeValueForStorage(storageValue);
// These encoded values are used in the Patricia Merkle Trie
Source: src/Nethereum.Model/Account.cs
TransactionType EnumLegacyTransaction (-1): Pre-EIP-155 transactionsLegacyChainTransaction (-2): EIP-155 transactions with chain IDLegacyEIP2930 (0x01): Transactions with access listsEIP1559 (0x02): Fee market transactionsEIP7702 (0x04): Account abstraction with authorizationLegacyTransactionPre-EIP-155 transaction format with basic fields.
Key Properties:
byte[] Nonce: Transaction sequence numberbyte[] GasPrice: Gas price in weibyte[] GasLimit: Maximum gas unitsbyte[] ReceiveAddress: Recipient addressbyte[] Value: Amount in weibyte[] Data: Contract call data or deployment codeSignature Signature: Transaction signature (R, S, V)Key Methods:
byte[] GetRLPEncoded(): Get signed transaction RLP encodingEthECKey GetKey(): Recover signer's public key from signatureLegacyTransactionChainIdEIP-155 transaction with chain ID to prevent replay attacks.
Inherits from LegacyTransaction with added chain ID in V signature component.
Transaction1559EIP-1559 fee market transaction.
Key Properties:
BigInteger ChainId: Network chain identifierBigInteger? Nonce: Transaction sequence numberBigInteger? MaxPriorityFeePerGas: Miner tipBigInteger? MaxFeePerGas: Maximum total fee per gasBigInteger? GasLimit: Gas limitstring ReceiverAddress: RecipientBigInteger? Amount: Value to transferstring Data: Call dataList<AccessListItem> AccessList: Optional access listKey Methods:
byte[] GetRLPEncoded(): Get complete RLP-encoded transactionbyte[] GetRLPEncodedRaw(): Get RLP encoding for signing (without signature)Transaction2930EIP-2930 transaction with access list.
Similar structure to Transaction1559 but uses GasPrice instead of base/priority fees.
Transaction7702EIP-7702 account abstraction transaction.
Extends Transaction1559 with:
List<Authorisation7702Signed> AuthorisationList: Signed authorizationsTransactionFactoryFactory class for creating and decoding transactions.
Key Methods:
static ISignedTransaction CreateTransaction(byte[] rlp): Automatically detects and decodes any transaction typestatic ISignedTransaction CreateTransaction(string rlpHex): Hex string overloadstatic ISignedTransaction Create1559Transaction(...): Create EIP-1559 transactionstatic ISignedTransaction Create2930Transaction(...): Create EIP-2930 transactionstatic ISignedTransaction Create7702Transaction(...): Create EIP-7702 transactionstatic ISignedTransaction CreateLegacyTransaction(...): Create legacy transactionBlockHeaderEthereum block header structure.
Properties:
byte[] ParentHash: Hash of parent blockbyte[] UnclesHash: Hash of uncle blocks liststring Coinbase: Miner/validator addressbyte[] StateRoot: State trie root hashbyte[] TransactionsHash: Transactions trie root hashbyte[] ReceiptHash: Receipts trie root hashBigInteger BlockNumber: Block heightbyte[] LogsBloom: Bloom filter for logsBigInteger Difficulty: Mining difficulty (0 post-merge)long Timestamp: Block timestamp (Unix seconds)long GasLimit: Maximum gas for blocklong GasUsed: Total gas used in blockbyte[] MixHash: PoW mix hash (random post-merge)byte[] ExtraData: Arbitrary extra databyte[] Nonce: PoW nonce (0 post-merge)BigInteger? BaseFee: EIP-1559 base fee per gasBlockHeaderEncoderRLP encoder/decoder for block headers.
Methods:
byte[] EncodeHeader(BlockHeader header): Encode block header to RLPBlockHeader DecodeHeader(byte[] rlp): Decode RLP to block headerAccountEthereum account state.
Properties:
BigInteger Nonce: Transaction count or contract creation countBigInteger Balance: Account balance in weibyte[] StateRoot: Storage trie root (default: empty trie hash)byte[] CodeHash: Contract code hash (default: empty data hash)AccountStorageUtilities for encoding account storage.
Methods:
static byte[] EncodeKeyForStorage(byte[] key, Sha3KeccackHashProvider): Encode storage keystatic byte[] EncodeValueForStorage(byte[] value): Encode storage valueSignature : ISignatureECDSA signature components.
Properties:
byte[] R: Signature R componentbyte[] S: Signature S componentbyte[] V: Recovery identifierConstructors:
Signature(): Default constructorSignature(byte[] r, byte[] s, byte[] v): Create with componentsSignatureExtensionsExtension methods for signature operations.
Key Methods:
bool IsVSignedForChain(this Signature): Check if V indicates chain-specific signatureBigInteger GetChainFromVChain(BigInteger v): Extract chain ID from VLogSmart contract event log.
Properties:
string Address: Contract address that emitted the logbyte[] Data: Non-indexed event dataList<byte[]> Topics: Indexed event topics (event signature + indexed parameters)Static Methods:
static Log Create(byte[] data, string address, params byte[][] topics): Create log with datastatic Log Create(string address, params byte[][] topics): Create log without dataLogBloomFilterBloom filter for efficient log filtering.
AccessListItemEIP-2930 access list entry.
Properties:
string Address: Contract addressList<byte[]> StorageKeys: Storage slots to pre-warmConstructors:
AccessListItem(): Default constructorAccessListItem(string address, List<byte[]> storageKeys): Create with valuesAccessListRLPEncoderDecoderRLP encoder/decoder for access lists.
Authorisation7702SignedSigned authorization for account abstraction.
Properties:
AuthorisationListRLPEncoderDecoderRLP encoder/decoder for authorization lists.
ChainWell-known Ethereum network chain IDs.
Common Values:
MainNet = 1: Ethereum MainnetSepolia = 11155111: Sepolia testnetPolygon = 137: Polygon PoSArbitrum = 42161: Arbitrum OneOptimism = 10: OptimismBase = 8453: Base L2Avalanche = 43114: Avalanche C-ChainBinance = 56: BNB ChainSee Chain.cs for the complete list of 100+ networks
DefaultValuesDefault constant values used throughout the package.
Constants:
EMPTY_BYTE_ARRAY: Empty byte arrayEMPTY_TRIE_HASH: Keccak-256 of empty trieEMPTY_DATA_HASH: Keccak-256 of empty dataVRecoveryAndChainCalculationsUtilities for signature V value and chain ID calculations.
Methods:
static BigInteger GetChainFromVChain(BigInteger vChain): Extract chain ID from VWhen decoding transactions from RLP:
TransactionFactory.CreateTransaction() automatically detects the typeThe V value in signatures serves dual purposes:
V = CHAIN_ID * 2 + 35 + {0,1}Different transaction types use different gas pricing:
gasPrice (user pays gasPrice × gasUsed)maxFeePerGas and maxPriorityFeePerGas
Always specify the correct chain ID to prevent:
Transactions have two RLP encodings:
GetRLPEncodedRaw()): Unsigned, used for signingGetRLPEncoded()): Includes signature, used for transmissionAfter Ethereum's transition to Proof-of-Stake (The Merge):
Difficulty is always 0Nonce is 0 (no longer used for mining)MixHash contains randomness from the beacon chainCoinbase is the fee recipient (validator or pool)Account state is stored in a Patricia Merkle Trie: