Nethereum.ABI 5.8.0

Prefix Reserved
dotnet add package Nethereum.ABI --version 5.8.0
                    
NuGet\Install-Package Nethereum.ABI -Version 5.8.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Nethereum.ABI" Version="5.8.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Nethereum.ABI" Version="5.8.0" />
                    
Directory.Packages.props
<PackageReference Include="Nethereum.ABI" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Nethereum.ABI --version 5.8.0
                    
#r "nuget: Nethereum.ABI, 5.8.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Nethereum.ABI@5.8.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Nethereum.ABI&version=5.8.0
                    
Install as a Cake Addin
#tool nuget:?package=Nethereum.ABI&version=5.8.0
                    
Install as a Cake Tool

Nethereum.ABI

Encoding and decoding of ABI Types, functions, events of Ethereum contracts

NuGet

Overview

Nethereum.ABI is the core package for Ethereum's Application Binary Interface (ABI) encoding and decoding in .NET. It provides comprehensive support for encoding function calls, decoding function outputs, processing event logs, EIP-712 typed data signing, and handling all Solidity data types including complex structures like tuples and dynamic arrays.

This package is fundamental to all smart contract interactions in Nethereum, as it translates between .NET objects and the binary format Ethereum uses for contract communication.

Installation

dotnet add package Nethereum.ABI

Dependencies

Nethereum:

  • Nethereum.Hex - Hexadecimal encoding/decoding
  • Nethereum.Util - Keccak-256 hashing and utilities

Key Concepts

Application Binary Interface (ABI)

The ABI is a JSON specification that describes:

  • Functions: Input parameters, output parameters, and function signatures
  • Events: Indexed and non-indexed parameters for log filtering and decoding
  • Errors: Custom error types and their parameters
  • Types: Complete type system including elementary types, arrays, structs (tuples)

Function Encoding

Function calls are encoded as:

  1. Function Selector: First 4 bytes of Keccak-256 hash of the function signature
  2. Encoded Parameters: ABI-encoded input parameters (32-byte aligned)

Event Decoding

Events are stored in transaction logs with:

  • Topics: Up to 4 indexed parameters (including event signature hash)
  • Data: Non-indexed parameters (ABI-encoded)

EIP-712 Typed Data

Structured data hashing and signing standard that enables:

  • Human-readable signatures: Users can see what they're signing
  • Domain separation: Prevents replay attacks across different dApps
  • Typed structs: Support for complex nested data structures
  • Used by: MetaMask, Permit (EIP-2612), Uniswap, OpenSea, and many more

Type System

Nethereum.ABI supports all Solidity types:

  • Elementary: uint256, int256, address, bool, bytes, bytesN, string
  • Fixed Arrays: uint256[20], address[5]
  • Dynamic Arrays: uint256[], string[]
  • Tuples: Complex structs with nested components

Quick Start

Basic Function Encoding

using Nethereum.ABI.FunctionEncoding;
using Nethereum.ABI.Model;

// Create encoder
var functionCallEncoder = new FunctionCallEncoder();

// Define function signature and parameters
var sha3Signature = "c6888fa1";  // First 8 hex chars of Keccak-256("functionName(paramTypes)")
var parameters = new[]
{
    new Parameter("address", "recipient"),
    new Parameter("uint256", "amount")
};

// Encode function call
string encoded = functionCallEncoder.EncodeRequest(
    sha3Signature,
    parameters,
    "0x1234567890abcdef1234567890abcdef12345678",  // recipient
    1000000000000000000  // amount (1 ETH in wei)
);
// Result: "0xc6888fa10000000000000000000000001234567890abcdef1234567890abcdef12345678000000000000000000000000000000000000000000000000001e4c89d6c7e400"

Decoding Function Output

// From test: FunctionEncodingTests.cs
var functionCallDecoder = new FunctionCallDecoder();

var outputParameters = new[]
{
    new ParameterOutput()
    {
        Parameter = new Parameter("uint[]", "numbers")
        {
            DecodedType = typeof(List<int>)
        }
    }
};

var result = functionCallDecoder.DecodeOutput(
    "0x0000000000000000000000000000000000000000000000000000000000000020" +
    "0000000000000000000000000000000000000000000000000000000000000003" +
    "0000000000000000000000000000000000000000000000000000000000000000" +
    "0000000000000000000000000000000000000000000000000000000000000001" +
    "0000000000000000000000000000000000000000000000000000000000000002",
    outputParameters
);

var numbers = (List<int>)result[0].Result;
// numbers: [0, 1, 2]

Usage Examples

Example 1: Encoding Multiple Types Including Dynamic Strings

From test: FunctionEncodingTests.cs:125

using Nethereum.ABI.FunctionEncoding;
using Nethereum.ABI.Model;

var functionCallEncoder = new FunctionCallEncoder();
var sha3Signature = "c6888fa1";

var inputsParameters = new[]
{
    new Parameter("string", "greeting"),
    new Parameter("uint[20]", "numbers"),
    new Parameter("string", "farewell")
};

var array = new uint[20];
for (uint i = 0; i < 20; i++)
    array[i] = i + 234567;

string encoded = functionCallEncoder.EncodeRequest(
    sha3Signature,
    inputsParameters,
    "hello",      // Dynamic string (pointer to data)
    array,        // Fixed-size array (inline)
    "world"       // Dynamic string (pointer to data)
);

// Result starts with function selector, followed by:
// - Pointer to "hello" data
// - 20 uint256 values inline
// - Pointer to "world" data
// - Actual "hello" string data
// - Actual "world" string data

Example 2: Attribute-Based Function Encoding

From test: FunctionAttributeEncodingTests.cs:55

using Nethereum.ABI.FunctionEncoding;
using Nethereum.ABI.FunctionEncoding.Attributes;

[Function("multiply")]
public class MultiplyFunction : FunctionMessage
{
    [Parameter("uint256", "a", 1)]
    public int A { get; set; }
}

var input = new MultiplyFunction { A = 69 };
var encoder = new FunctionCallEncoder();
string encoded = encoder.EncodeRequest(input, "c6888fa1");

// Result: "0xc6888fa10000000000000000000000000000000000000000000000000000000000000045"
// 69 decimal = 0x45 hex, padded to 32 bytes

Example 3: Decoding Event Topics (Transfer Event)

From test: EventTopicDecoderTests.cs:13

using Nethereum.ABI.FunctionEncoding;
using Nethereum.ABI.FunctionEncoding.Attributes;
using System.Numerics;

[Event("Transfer")]
public class TransferEvent
{
    [Parameter("address", "_from", 1, indexed: true)]
    public string From { get; set; }

    [Parameter("address", "_to", 2, indexed: true)]
    public string To { get; set; }

    [Parameter("uint256", "_value", 3, indexed: true)]
    public BigInteger Value { get; set; }
}

var topics = new[]
{
    "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",  // Event signature
    "0x0000000000000000000000000000000000000000000000000000000000000000",  // from (zero address)
    "0x000000000000000000000000c14934679e71ef4d18b6ae927fe2b953c7fd9b91",  // to
    "0x0000000000000000000000000000000000000000000000400000402000000001"   // value
};

var data = "0x";  // No non-indexed data

var transferEvent = new TransferEvent();
new EventTopicDecoder().DecodeTopics(transferEvent, topics, data);

// transferEvent.From: "0x0000000000000000000000000000000000000000"
// transferEvent.To: "0xc14934679e71ef4d18b6ae927fe2b953c7fd9b91"
// transferEvent.Value: 1180591691223594434561

Example 4: Simple ABI Encoding with ABIEncode

From test: AbiEncodeTests.cs:12

using Nethereum.ABI;
using Nethereum.Hex.HexConvertors.Extensions;

var abiEncode = new ABIEncode();

// Encode multiple values with explicit types
byte[] encoded = abiEncode.GetABIEncoded(
    new ABIValue("string", "hello"),
    new ABIValue("int", 69),
    new ABIValue("string", "world")
);

string hexResult = encoded.ToHex(true);
// Result: "0x0000000000000000000000000000000000000000000000000000000000000060..."
// Includes pointers to dynamic data and the actual string data

Example 5: Encoding with Parameter Attributes

From test: AbiEncodeTests.cs:34

using Nethereum.ABI;
using Nethereum.ABI.FunctionEncoding.Attributes;

public class TestParamsInput
{
    [Parameter("string", 1)]
    public string First { get; set; }

    [Parameter("int256", 2)]
    public int Second { get; set; }

    [Parameter("string", 3)]
    public string Third { get; set; }
}

var abiEncode = new ABIEncode();
var input = new TestParamsInput
{
    First = "hello",
    Second = 69,
    Third = "world"
};

byte[] encoded = abiEncode.GetABIParamsEncoded(input);
// Automatically encodes based on Parameter attributes

Example 6: Deserializing Contract ABI JSON

From test: FunctionAttributeEncodingTests.cs:14

using Nethereum.ABI.ABIDeserialisation;
using System.Linq;

var abi = @"[
    {
        ""constant"": false,
        ""inputs"": [{""name"": ""a"", ""type"": ""uint256""}],
        ""name"": ""multiply"",
        ""outputs"": [{""name"": ""d"", ""type"": ""uint256""}],
        ""type"": ""function""
    }
]";

var deserializer = new ABIJsonDeserialiser();
var contract = deserializer.DeserialiseContract(abi);

var multiplyFunction = contract.Functions.FirstOrDefault(x => x.Name == "multiply");
// multiplyFunction.Sha3Signature: "c6888fa1"
// multiplyFunction.Constant: false
// multiplyFunction.InputParameters[0].Type: "uint256"

Example 7: Complex Tuples with Nested Arrays

From test: AbiDeserialiseTuplesTests.cs:22

using Nethereum.ABI.ABIDeserialisation;
using System.Linq;

// Complex ABI with nested tuple containing array of tuples
var abi = @"[{
    ""constant"": false,
    ""inputs"": [{
        ""components"": [
            {""name"": ""id"", ""type"": ""uint256""},
            {
                ""components"": [
                    {""name"": ""id"", ""type"": ""uint256""},
                    {""name"": ""productId"", ""type"": ""uint256""},
                    {""name"": ""quantity"", ""type"": ""uint256""}
                ],
                ""name"": ""lineItem"",
                ""type"": ""tuple[]""
            },
            {""name"": ""customerId"", ""type"": ""uint256""}
        ],
        ""name"": ""purchaseOrder"",
        ""type"": ""tuple""
    }],
    ""name"": ""SetPurchaseOrder"",
    ""outputs"": [],
    ""type"": ""function""
}]";

var contractAbi = new ABIJsonDeserialiser().DeserialiseContract(abi);
var functionABI = contractAbi.Functions.FirstOrDefault(e => e.Name == "SetPurchaseOrder");

// Function signature includes full tuple structure
// functionABI.Sha3Signature: "0cc400bd"

Example 8: Encoding Individual Types

From test: FunctionEncodingTests.cs:79-107

using Nethereum.ABI.FunctionEncoding;
using Nethereum.ABI.Model;

var encoder = new FunctionCallEncoder();
var signature = "c6888fa1";

// Address encoding
var addressParam = new[] { new Parameter("address", "recipient") };
string encodedAddress = encoder.EncodeRequest(
    signature,
    addressParam,
    "0x1234567890abcdef1234567890abcdef12345678"
);
// Result: "0xc6888fa10000000000000000000000001234567890abcdef1234567890abcdef12345678"

// Boolean encoding
var boolParam = new[] { new Parameter("bool", "flag") };
string encodedBool = encoder.EncodeRequest(signature, boolParam, true);
// Result: "0xc6888fa10000000000000000000000000000000000000000000000000000000000000001"

// Integer encoding
var intParam = new[] { new Parameter("int", "number") };
string encodedInt = encoder.EncodeRequest(signature, intParam, 69);
// Result: "0xc6888fa10000000000000000000000000000000000000000000000000000000000000045"
// Note: 69 decimal = 0x45 hex

Example 9: EIP-712 Typed Data with Simple Structs

From test: Eip712TypedDataSignerSimpleScenarioTest.cs:66

using Nethereum.ABI.EIP712;
using Nethereum.ABI.FunctionEncoding.Attributes;
using Nethereum.Signer.EIP712;
using System.Collections.Generic;

// Define your domain-specific structs
[Struct("Person")]
public class Person
{
    [Parameter("string", "name", 1)]
    public string Name { get; set; }

    [Parameter("address[]", "wallets", 2)]
    public List<string> Wallets { get; set; }
}

[Struct("Mail")]
public class Mail
{
    [Parameter("tuple", "from", 1, "Person")]
    public Person From { get; set; }

    [Parameter("tuple[]", "to", 2, "Person[]")]
    public List<Person> To { get; set; }

    [Parameter("string", "contents", 3)]
    public string Contents { get; set; }
}

// Create typed data definition
var typedData = new TypedData<Domain>
{
    Domain = new Domain
    {
        Name = "Ether Mail",
        Version = "1",
        ChainId = 1,
        VerifyingContract = "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
    },
    Types = MemberDescriptionFactory.GetTypesMemberDescription(typeof(Domain), typeof(Mail), typeof(Person)),
    PrimaryType = nameof(Mail),
};

// Create message
var mail = new Mail
{
    From = new Person
    {
        Name = "Cow",
        Wallets = new List<string>
        {
            "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
            "0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF"
        }
    },
    To = new List<Person>
    {
        new Person
        {
            Name = "Bob",
            Wallets = new List<string>
            {
                "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
                "0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57",
                "0xB0B0b0b0b0b0B000000000000000000000000000"
            }
        }
    },
    Contents = "Hello, Bob!"
};

// Set the message
typedData.SetMessage(mail);

// Sign using private key
var signer = new Eip712TypedDataSigner();
var key = new EthECKey("94e001d6adf3a3275d5dd45971c2a5f6637d3e9c51f9693f2e678f649e164fa5");
string signature = signer.SignTypedDataV4(mail, typedData, key);
// signature: "0x943393c998ab7e067d2875385e2218c9b3140f563694267ac9f6276a9fcc53e1..."

// Recover signer address from signature
string recoveredAddress = signer.RecoverFromSignatureV4(mail, typedData, signature);
// recoveredAddress matches key.GetPublicAddress()

Example 10: EIP-712 Typed Data from JSON

From test: Eip712TypedDataSignerTest.cs:107

using Nethereum.ABI.EIP712;
using Nethereum.Signer.EIP712;

// EIP-712 typed data as JSON (MetaMask format)
var typedDataJson = @"{
    'domain': {
        'chainId': 1,
        'name': 'Ether Mail',
        'verifyingContract': '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
        'version': '1'
    },
    'message': {
        'contents': 'Hello, Bob!',
        'from': {
            'name': 'Cow',
            'wallets': [
                '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
                '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF'
            ]
        },
        'to': [{
            'name': 'Bob',
            'wallets': [
                '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
                '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57',
                '0xB0B0b0b0b0b0B000000000000000000000000000'
            ]
        }]
    },
    'primaryType': 'Mail',
    'types': {
        'EIP712Domain': [
            {'name': 'name', 'type': 'string'},
            {'name': 'version', 'type': 'string'},
            {'name': 'chainId', 'type': 'uint256'},
            {'name': 'verifyingContract', 'type': 'address'}
        ],
        'Mail': [
            {'name': 'from', 'type': 'Person'},
            {'name': 'to', 'type': 'Person[]'},
            {'name': 'contents', 'type': 'string'}
        ],
        'Person': [
            {'name': 'name', 'type': 'string'},
            {'name': 'wallets', 'type': 'address[]'}
        ]
    }
}";

// Deserialize and encode
var rawTypedData = TypedDataRawJsonConversion.DeserialiseJsonToRawTypedData(typedDataJson);
var signer = new Eip712TypedDataSigner();
byte[] encodedTypedData = signer.EncodeTypedDataRaw(rawTypedData);

// Sign directly from JSON
var key = new EthECKey("94e001d6adf3a3275d5dd45971c2a5f6637d3e9c51f9693f2e678f649e164fa5");
string signature = signer.SignTypedDataV4(rawTypedData, key);

Example 11: EIP-712 with Complex Nested Structures

From test: EIP712TypeDataSignatureMultipleComplexInnerObjects.cs:13

using Nethereum.ABI.EIP712;
using Nethereum.ABI.FunctionEncoding.Attributes;
using System.Collections.Generic;
using System.Numerics;

[Struct("UsageLimit")]
public class UsageLimit
{
    [Parameter("uint8", "limitType", 1)]
    public byte LimitType { get; set; }

    [Parameter("uint256", "limit", 2)]
    public BigInteger Limit { get; set; }

    [Parameter("uint256", "period", 3)]
    public BigInteger Period { get; set; }
}

[Struct("Constraint")]
public class Constraint
{
    [Parameter("uint8", "condition", 1)]
    public byte Condition { get; set; }

    [Parameter("uint64", "index", 2)]
    public ulong Index { get; set; }

    [Parameter("bytes32", "refValue", 3)]
    public byte[] RefValue { get; set; }
}

[Struct("CallSpec")]
public class CallSpec
{
    [Parameter("address", "target", 1)]
    public string Target { get; set; }

    [Parameter("bytes4", "selector", 2)]
    public byte[] Selector { get; set; }

    [Parameter("uint256", "maxValuePerUse", 3)]
    public BigInteger MaxValuePerUse { get; set; }

    [Parameter("tuple", "valueLimit", 4, structTypeName: "UsageLimit")]
    public UsageLimit ValueLimit { get; set; }

    [Parameter("tuple[]", "constraints", 5, structTypeName: "Constraint[]")]
    public List<Constraint> Constraints { get; set; }
}

[Struct("SessionSpec")]
public class SessionSpec
{
    [Parameter("address", "signer", 1)]
    public string Signer { get; set; }

    [Parameter("uint256", "expiresAt", 2)]
    public BigInteger ExpiresAt { get; set; }

    [Parameter("tuple[]", "callPolicies", 3, structTypeName: "CallSpec[]")]
    public List<CallSpec> CallPolicies { get; set; }
}

// This demonstrates deep nesting: SessionSpec contains array of CallSpec,
// each CallSpec contains UsageLimit struct and array of Constraint structs
// Perfect for complex DeFi protocols, account abstraction, session keys, etc.

Example 12: EIP-712 Encoding and Hashing

From test: Eip712TypedDataEncoder.cs

using Nethereum.ABI.EIP712;
using Nethereum.Hex.HexConvertors.Extensions;

var encoder = new Eip712TypedDataEncoder();

// Encode from typed data
var mail = new Mail { /* ... */ };
var typedData = new TypedData<Domain> { /* ... */ };
byte[] encoded = encoder.EncodeTypedData(mail, typedData);

// Encode and hash in one operation (for signing)
byte[] hash = encoder.EncodeAndHashTypedData(mail, typedData);

// Encode directly from JSON
string json = /* EIP-712 JSON */;
byte[] encodedFromJson = encoder.EncodeTypedData(json);
byte[] hashFromJson = encoder.EncodeAndHashTypedData(json);

// The hash is what gets signed with ECDSA
string hashHex = hash.ToHex(true);

Example 13: Error Handling for Invalid Parameters

From test: FunctionEncodingTests.cs:161

using Nethereum.ABI.FunctionEncoding;
using Nethereum.ABI.Model;

var encoder = new FunctionCallEncoder();
var signature = "c6888fa1";
var parameters = new[] { new Parameter("address", "_address1") };

try
{
    string encoded = encoder.EncodeRequest(signature, parameters, (object)null);
}
catch (AbiEncodingException ex)
{
    // ex.Message: "An error occurred encoding abi value. Order: '1', Type: 'address',
    //              Value: 'null'. Ensure the value is valid for the abi type."
    Console.WriteLine(ex.Message);
}

API Reference

Core Classes

ABIEncode
  • GetABIEncoded(params ABIValue[] abiValues) - Encode values with explicit types
  • GetABIEncoded(params object[] values) - Encode values with automatic type detection
  • GetABIParamsEncoded<T>(T input) - Encode object using Parameter attributes
  • GetABIEncodedPacked(params ABIValue[] abiValues) - Packed encoding (no padding)
  • GetSha3ABIEncoded(...) - Encode and hash in one operation
FunctionCallEncoder
  • EncodeRequest(string sha3Signature, Parameter[] parameters, params object[] values) - Encode function call
  • EncodeRequest<T>(T functionInput, string sha3Signature) - Encode using attributes
FunctionCallDecoder
  • DecodeOutput(string output, params Parameter[] parameters) - Decode function return values
  • DecodeFunctionOutput<T>(string output) - Decode using attributes
EventTopicDecoder
  • DecodeTopics(object destination, string[] topics, string data) - Decode event log into object
  • DecodeTopics<T>(string[] topics, string data) - Decode event log to typed object
ABIJsonDeserialiser
  • DeserialiseContract(string abi) - Parse contract ABI JSON
  • DeserialiseContract(JArray abi) - Parse from JArray
  • Produces ContractABI with Functions, Events, Errors, Constructor
Eip712TypedDataEncoder
  • EncodeTypedData<T, TDomain>(T message, TypedData<TDomain> typedData) - Encode typed data with message
  • EncodeTypedData(string json) - Encode from EIP-712 JSON
  • EncodeAndHashTypedData(...) - Encode and hash for signing
  • EncodeTypedDataRaw(TypedDataRaw typedData) - Low-level encoding
Eip712TypedDataSigner (in Nethereum.Signer)
  • SignTypedDataV4<T>(T message, TypedData<Domain> typedData, EthECKey key) - Sign EIP-712 data
  • RecoverFromSignatureV4<T>(T message, TypedData<Domain> typedData, string signature) - Recover signer
  • SignTypedDataV4(TypedDataRaw typedData, EthECKey key) - Sign from raw typed data

Encoding Attributes

  • [Function("name")] - Mark class as function definition
  • [Event("name")] - Mark class as event definition
  • [Struct("name")] - Mark class as EIP-712 struct
  • [Parameter("type", "name", order, indexed)] - Mark property as parameter
  • [FunctionOutput] - Mark class can be used for output decoding

EIP-712 Classes

  • TypedData<TDomain> - Typed data with domain separation
  • Domain - EIP-712 domain (name, version, chainId, verifyingContract, salt)
  • MemberDescription - Type member definition (name, type)
  • MemberDescriptionFactory - Generate type descriptions from .NET types
  • MemberValue - Runtime value for encoding
  • TypedDataRaw - Raw typed data without generics
  • Nethereum.Hex - Hexadecimal encoding used throughout ABI operations
  • Nethereum.Util - Keccak-256 hashing for function/event signatures
  • Nethereum.Signer - EIP-712 signing and signature recovery
  • Nethereum.Contracts - High-level contract interaction built on ABI encoding
  • Nethereum.RPC - JSON-RPC calls that use ABI-encoded data

Important Notes

Function Signature Calculation

Function signatures are the first 4 bytes of Keccak-256 hash of the canonical function signature:

Keccak256("transfer(address,uint256)") → 0xa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b
Function selector: 0xa9059cbb (first 4 bytes)

Event Signature Calculation

Event signatures are the full 32 bytes of Keccak-256 hash of the canonical event signature:

Keccak256("Transfer(address,address,uint256)") → 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
Event topic[0]: Full hash (identifies the event)

EIP-712 Domain Separation

The domain separator prevents signature replay attacks across:

  • Different contracts (via verifyingContract address)
  • Different chains (via chainId)
  • Different versions (via version)
  • Different applications (via name)

Formula: Keccak256(encodeData("EIP712Domain", domain))

EIP-712 Structured Data Hash

Final hash signed by user:

Keccak256("\x19\x01" + domainSeparator + hashStruct(message))

Where:

  • \x19\x01 is the version byte for structured data
  • domainSeparator is the hash of the domain
  • hashStruct(message) is the hash of the primary message type

Dynamic vs Static Types

  • Static types (uint256, address, bool, bytesN, fixed arrays): Encoded inline
  • Dynamic types (string, bytes, dynamic arrays, tuples with dynamic members): Encoded as pointer + data

Type Canonicalization

When calculating signatures, types must be canonical:

  • uintuint256
  • intint256
  • No spaces: transfer(address,uint256) not transfer(address, uint256)

Indexed Event Parameters

  • Maximum 3 indexed parameters per event (topic[0] is always event signature)
  • Indexed parameters are searchable/filterable in logs
  • Non-indexed parameters are cheaper and stored in data field

EIP-712 Use Cases

  • MetaMask Sign-In: Authenticate users without gas
  • EIP-2612 Permit: Gasless token approvals (USDC, DAI, UNI)
  • OpenSea/NFT Marketplaces: Off-chain order signing
  • Uniswap Permit2: Advanced approval management
  • Account Abstraction: Session keys and delegated operations
  • DAO Voting: Off-chain vote collection with on-chain execution

Playground Examples

Runnable examples available at Nethereum Playground:

Human-Readable ABI:

  • Example 1069 - Deployment, calls, and transactions using human-readable ABI format

ABI Encoding:

Resources

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net451 is compatible.  net452 was computed.  net46 was computed.  net461 is compatible.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (40)

Showing the top 5 NuGet packages that depend on Nethereum.ABI:

Package Downloads
Nethereum.Signer

Nethereum signer library to sign and verify messages, RLP and transactions using an Ethereum account

Nethereum.Contracts

Nethereum Contracts is the core library to interact via RPC with Smart contracts in Ethereum

Nethereum.Web3

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

Nethereum.Signer.EIP712

Nethereum signer library to sign and encode messages according to EIP-712

Nethereum

Package Description

GitHub repositories (3)

Showing the top 3 popular GitHub repositories that depend on Nethereum.ABI:

Repository Stars
ChainSafe/web3.unity
🕹 Unity SDK for building games that interact with blockchains.
yc-l/yc.boilerplate
YC. Boilerplate is a set of loose coupling, flexible combination, complete functions, convenient development, and reduces the workload of development.
biheBlockChain/MyLinkToken
开源链克口袋,玩客币钱包
Version Downloads Last Updated
5.8.0 2,179 1/6/2026
5.0.0 312,378 5/28/2025
4.29.0 264,102 2/10/2025
4.28.0 77,507 1/7/2025
4.27.1 13,107 12/24/2024
4.27.0 1,998 12/24/2024
4.26.0 105,287 10/1/2024
4.25.0 23,725 9/19/2024
4.21.4 98,267 8/9/2024
4.21.3 14,687 7/22/2024
4.21.2 69,848 6/26/2024
4.21.1 2,968 6/26/2024
4.21.0 11,282 6/18/2024
4.20.0 319,501 3/28/2024
4.19.0 89,398 2/16/2024
4.18.0 292,935 11/21/2023
4.17.1 79,004 9/28/2023
4.17.0 17,501 9/27/2023
4.16.0 123,752 8/14/2023
4.15.2 125,125 7/11/2023
4.15.1 4,568 7/11/2023
4.15.0 5,011 7/11/2023
4.14.0 203,677 3/19/2023
4.13.0 136,311 2/18/2023
4.12.0 271,704 12/9/2022
4.11.0 176,448 10/27/2022
4.9.0 116,533 9/27/2022
4.8.0 181,391 8/24/2022
4.7.0 173,388 7/20/2022
4.6.1 129,811 6/18/2022
4.6.0 9,814 6/16/2022
4.5.0 390,303 5/13/2022
4.4.1 117,225 4/27/2022
4.4.0 13,239 4/27/2022
4.3.0 78,312 4/12/2022
4.2.0 177,359 2/18/2022
4.1.1 492,986 11/4/2021
4.1.0 30,225 10/15/2021
4.0.5 141,644 8/12/2021
4.0.4 7,903 8/10/2021
4.0.3 25,267 8/8/2021
4.0.2 6,996 8/5/2021
4.0.1 13,471 7/28/2021
4.0.0 17,709 7/26/2021
3.8.0 395,934 7/3/2020
3.7.1 116,389 2/13/2020
3.7.0 9,149 2/13/2020
3.6.0 32,297 1/27/2020
3.5.0 19,817 12/31/2019
3.4.0 149,047 7/29/2019
3.3.0 73,762 4/23/2019
3.2.0 44,065 4/8/2019
3.1.2 22,246 3/13/2019
3.1.1 4,962 3/12/2019
3.1.0 26,021 3/12/2019
3.0.0 36,834 11/28/2018
3.0.0-rc3 5,363 10/25/2018
3.0.0-rc2 3,102 10/24/2018
3.0.0-rc1 8,762 7/25/2018
2.5.1 108,033 6/5/2018
2.5.0 5,445 6/4/2018
2.4.0 52,172 3/11/2018
2.3.1 7,305 3/7/2018
2.3.0 5,729 3/6/2018
2.2.3 21,065 12/16/2017
2.2.2 5,568 12/16/2017
2.2.0 6,035 12/8/2017
2.1.0 11,445 10/23/2017
2.0.1 5,758 10/4/2017
2.0.0 6,612 9/26/2017
2.0.0-rc7 3,864 8/17/2017
2.0.0-rc6-2 3,457 7/29/2017
2.0.0-rc6.1 963 7/26/2017
2.0.0-rc6 1,571 7/26/2017
2.0.0-rc5 2,471 6/19/2017
2.0.0-rc4 3,662 6/6/2017
2.0.0-rc3 3,151 4/11/2017
2.0.0-rc2-fix 3,570 4/6/2017
2.0.0-rc2 1,198 4/5/2017
2.0.0-rc1 3,209 2/8/2017
1.0.6 5,118 2/3/2017
1.0.5 1,793 1/31/2017
1.0.4 4,923 12/10/2016
1.0.3 2,734 11/28/2016
1.0.2 2,906 11/21/2016
1.0.1 3,360 10/31/2016
1.0.0 13,944 9/14/2016
1.0.0-rc6 2,552 9/12/2016
1.0.0-rc5 5,438 8/1/2016
1.0.0-rc4 2,868 7/29/2016
1.0.0-rc1 1,928 3/30/2016
1.0.0-alpha 2,314 2/27/2016