Nethereum.Metamask 5.8.0

Prefix Reserved
dotnet add package Nethereum.Metamask --version 5.8.0
                    
NuGet\Install-Package Nethereum.Metamask -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.Metamask" Version="5.8.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Nethereum.Metamask" Version="5.8.0" />
                    
Directory.Packages.props
<PackageReference Include="Nethereum.Metamask" />
                    
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.Metamask --version 5.8.0
                    
#r "nuget: Nethereum.Metamask, 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.Metamask@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.Metamask&version=5.8.0
                    
Install as a Cake Addin
#tool nuget:?package=Nethereum.Metamask&version=5.8.0
                    
Install as a Cake Tool

Nethereum.Metamask

Core MetaMask integration abstractions for Nethereum. Provides platform-agnostic interfaces and request interceptors for integrating MetaMask wallet into .NET applications.

Overview

Nethereum.Metamask is the foundation package for MetaMask integration. It defines the core abstractions (IMetamaskInterop) and request interceptor logic needed to route Ethereum RPC calls through the MetaMask browser extension. Platform-specific implementations (Blazor, desktop, mobile) build on top of these abstractions.

Key Features:

  • IMetamaskInterop interface for platform-specific implementations
  • MetamaskHostProvider implementing IEthereumHostProvider
  • MetamaskInterceptor for routing RPC requests through MetaMask
  • Support for all MetaMask-specific methods (personal_sign, eth_signTypedData_v4, wallet_*)
  • Automatic account injection into transactions
  • Two operating modes: all requests or signing-only

Use Cases:

  • Building Blazor dApps with MetaMask
  • Creating custom MetaMask integrations for other platforms
  • Routing transaction signing through MetaMask while using custom RPC
  • Implementing wallet connection flows

Installation

dotnet add package Nethereum.Metamask

Note: This is the core abstraction package. For Blazor applications, use Nethereum.Metamask.Blazor which provides the JavaScript interop implementation.

Dependencies

  • Nethereum.UI
  • Nethereum.Web3

Architecture

Platform Implementations

┌─────────────────────┐  ┌──────────────────┐  ┌─────────────────┐
│ Nethereum.Metamask  │  │ Nethereum.Unity  │  │ Desktop/Mobile  │
│      .Blazor        │  │   .Metamask      │  │ Implementations │
│                     │  │                  │  │                 │
│ MetamaskBlazer-     │  │ Unity-specific   │  │ Platform-       │
│ Interop (JS)        │  │ implementation   │  │ specific impl   │
└─────────────────────┘  └──────────────────┘  └─────────────────┘
         │                       │                      │
         └───────────────────────┴──────────────────────┘
                                 │
                    implements IMetamaskInterop
                                 │
                                 ▼
┌─────────────────────────────────────────────────────────────┐
│              Nethereum.Metamask (This Package)               │
│                     Core Abstractions                        │
│                                                              │
│  ┌──────────────────────┐      ┌────────────────────────┐  │
│  │ IMetamaskInterop     │      │ MetamaskHostProvider   │  │
│  │ (Platform Interface) │      │ (Wallet Provider)      │  │
│  └──────────────────────┘      └────────────────────────┘  │
│                                                              │
│  ┌──────────────────────┐      ┌────────────────────────┐  │
│  │ MetamaskInterceptor  │      │ MetamaskRpcRequest-    │  │
│  │ (Request Router)     │      │ Message                │  │
│  └──────────────────────┘      └────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘
                                 │
                                 ▼
┌─────────────────────────────────────────────────────────────┐
│                     Nethereum.Web3                           │
│                  (Ethereum Interaction)                      │
└─────────────────────────────────────────────────────────────┘

IMetamaskInterop

Platform-specific interface that must be implemented by each platform (Blazor, Unity, desktop):

public interface IMetamaskInterop
{
    Task<string> EnableEthereumAsync();
    Task<bool> CheckMetamaskAvailability();
    Task<string> GetSelectedAddress();
    Task<RpcResponseMessage> SendAsync(RpcRequestMessage rpcRequestMessage);
    Task<RpcResponseMessage> SendTransactionAsync(MetamaskRpcRequestMessage rpcRequestMessage);
    Task<string> SignAsync(string utf8Hex);
}

MetamaskHostProvider

Implements IEthereumHostProvider for MetaMask:

public class MetamaskHostProvider : IEthereumHostProvider
{
    public string Name { get; } // "Metamask"
    public bool Available { get; }
    public string SelectedAccount { get; }
    public long SelectedNetworkChainId { get; }
    public bool Enabled { get; }

    // Events
    event Func<string, Task> SelectedAccountChanged;
    event Func<long, Task> NetworkChanged;
    event Func<bool, Task> AvailabilityChanged;
    event Func<bool, Task> EnabledChanged;

    // Methods
    Task<bool> CheckProviderAvailabilityAsync();
    Task<string> EnableProviderAsync();
    Task<IWeb3> GetWeb3Async();
    Task<string> SignMessageAsync(string message);
}

MetamaskInterceptor

Intercepts Web3 requests and routes appropriate methods through MetaMask:

public class MetamaskInterceptor : RequestInterceptor
{
    // Methods routed through MetaMask
    public static List<string> SigningWalletTransactionsMethods { get; } = new List<string>
    {
        "eth_sendTransaction",
        "eth_signTransaction",
        "eth_sign",
        "personal_sign",
        "eth_signTypedData",
        "eth_signTypedData_v3",
        "eth_signTypedData_v4",
        "wallet_watchAsset",
        "wallet_addEthereumChain",
        "wallet_switchEthereumChain"
    };
}

Usage Examples

Example 1: Basic Setup (Requires Platform Implementation)

using Nethereum.Metamask;
using Nethereum.UI;

// Platform-specific interop implementation
// In Blazor: MetamaskBlazorInterop
// In other platforms: implement IMetamaskInterop
IMetamaskInterop metamaskInterop = GetPlatformSpecificInterop();

// Create MetaMask provider
var metamaskProvider = new MetamaskHostProvider(metamaskInterop);

// Check if MetaMask is available
bool isAvailable = await metamaskProvider.CheckProviderAvailabilityAsync();
if (!isAvailable)
{
    Console.WriteLine("MetaMask extension not detected");
    return;
}

// Request connection
string account = await metamaskProvider.EnableProviderAsync();
Console.WriteLine($"Connected to MetaMask: {account}");

// Get Web3 instance
var web3 = await metamaskProvider.GetWeb3Async();

// All transactions will be signed by MetaMask
var balance = await web3.Eth.GetBalance.SendRequestAsync(account);
Console.WriteLine($"Balance: {Web3.Convert.FromWei(balance)} ETH");

Example 2: Listening to Account Changes

using Nethereum.Metamask;

var metamaskProvider = new MetamaskHostProvider(metamaskInterop);

// Subscribe to account changes
metamaskProvider.SelectedAccountChanged += async (newAccount) =>
{
    Console.WriteLine($"Account changed to: {newAccount}");

    // Update UI, reload balances, etc.
    var web3 = await metamaskProvider.GetWeb3Async();
    var balance = await web3.Eth.GetBalance.SendRequestAsync(newAccount);
    Console.WriteLine($"New balance: {Web3.Convert.FromWei(balance)} ETH");
};

// Subscribe to network changes
metamaskProvider.NetworkChanged += async (chainId) =>
{
    Console.WriteLine($"Network changed to chain ID: {chainId}");

    if (chainId == 1)
        Console.WriteLine("Connected to Ethereum Mainnet");
    else if (chainId == 137)
        Console.WriteLine("Connected to Polygon");
    else
        Console.WriteLine($"Connected to unknown network: {chainId}");
};

// Enable provider
await metamaskProvider.EnableProviderAsync();

Example 3: Sending Transactions Through MetaMask

using Nethereum.Metamask;
using Nethereum.Web3;
using Nethereum.Hex.HexTypes;

var metamaskProvider = new MetamaskHostProvider(metamaskInterop);
await metamaskProvider.EnableProviderAsync();

var web3 = await metamaskProvider.GetWeb3Async();

// Send ETH (MetaMask will prompt for signature)
var toAddress = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb";
var amountInWei = Web3.Convert.ToWei(0.1);

var txHash = await web3.Eth.GetEtherTransferService()
    .TransferEtherAndWaitForReceiptAsync(toAddress, 0.1m);

Console.WriteLine($"Transaction sent: {txHash}");

Example 4: Signing Messages with MetaMask

using Nethereum.Metamask;
using Nethereum.Signer;

var metamaskProvider = new MetamaskHostProvider(metamaskInterop);
await metamaskProvider.EnableProviderAsync();

// Sign message (MetaMask popup will appear)
string message = "Sign this message to authenticate";
string signature = await metamaskProvider.SignMessageAsync(message);

Console.WriteLine($"Signature: {signature}");

// Verify signature
var signer = new EthereumMessageSigner();
var recoveredAddress = signer.EncodeUTF8AndEcRecover(message, signature);

Console.WriteLine($"Recovered address: {recoveredAddress}");
Console.WriteLine($"Matches selected account: {recoveredAddress.Equals(metamaskProvider.SelectedAccount, StringComparison.OrdinalIgnoreCase)}");

Example 5: Hybrid Mode - MetaMask for Signing, Custom RPC for Queries

using Nethereum.Metamask;
using Nethereum.JsonRpc.Client;
using Nethereum.Web3;

// Custom RPC client for queries (faster, no MetaMask popups)
var customRpcClient = new RpcClient(new Uri("https://mainnet.infura.io/v3/YOUR-PROJECT-ID"));

// MetaMask provider with custom RPC client
// useOnlySigningWalletTransactionMethods = true means:
// - Queries go through custom RPC
// - Signatures go through MetaMask
var metamaskProvider = new MetamaskHostProvider(
    metamaskInterop,
    client: customRpcClient,
    useOnlySigningWalletTransactionMethods: true);

await metamaskProvider.EnableProviderAsync();

var web3 = await metamaskProvider.GetWeb3Async();

// This query goes through Infura (fast, no MetaMask popup)
var blockNumber = await web3.Eth.Blocks.GetBlockNumber.SendRequestAsync();
Console.WriteLine($"Current block: {blockNumber.Value}");

// This transaction goes through MetaMask (user signature required)
var txHash = await web3.Eth.GetEtherTransferService()
    .TransferEtherAsync("0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", 0.01m);

Console.WriteLine($"Transaction sent via MetaMask: {txHash}");

Example 6: Typed Data Signing (EIP-712)

using Nethereum.Metamask;
using Nethereum.ABI.FunctionEncoding.Attributes;
using Nethereum.Signer.EIP712;

var metamaskProvider = new MetamaskHostProvider(metamaskInterop);
await metamaskProvider.EnableProviderAsync();

var web3 = await metamaskProvider.GetWeb3Async();

// Define typed data
var typedData = new
{
    types = new
    {
        EIP712Domain = new[]
        {
            new { name = "name", type = "string" },
            new { name = "version", type = "string" },
            new { name = "chainId", type = "uint256" }
        },
        Person = new[]
        {
            new { name = "name", type = "string" },
            new { name = "wallet", type = "address" }
        }
    },
    primaryType = "Person",
    domain = new
    {
        name = "MyDApp",
        version = "1",
        chainId = 1
    },
    message = new
    {
        name = "Alice",
        wallet = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
    }
};

// Sign typed data (MetaMask will show structured data)
var signature = await web3.Eth.AccountSigning.SignTypedDataV4.SendRequestAsync(
    System.Text.Json.JsonSerializer.Serialize(typedData));

Console.WriteLine($"EIP-712 Signature: {signature}");

Example 7: Adding Token to MetaMask (wallet_watchAsset)

using Nethereum.Metamask;
using Nethereum.Web3;

var metamaskProvider = new MetamaskHostProvider(metamaskInterop);
await metamaskProvider.EnableProviderAsync();

var web3 = await metamaskProvider.GetWeb3Async();

// Prepare token details
var tokenDetails = new
{
    type = "ERC20",
    options = new
    {
        address = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
        symbol = "USDC",
        decimals = 6,
        image = "https://example.com/usdc.png"
    }
};

// Request to add token to MetaMask
// Note: This requires using the interceptor
var result = await web3.Client.SendRequestAsync<bool>(
    "wallet_watchAsset",
    null,
    tokenDetails);

if (result)
{
    Console.WriteLine("Token added to MetaMask successfully");
}

Example 8: Switching Networks in MetaMask

using Nethereum.Metamask;
using Nethereum.Web3;
using Nethereum.Hex.HexTypes;

var metamaskProvider = new MetamaskHostProvider(metamaskInterop);
await metamaskProvider.EnableProviderAsync();

var web3 = await metamaskProvider.GetWeb3Async();

// Switch to Polygon network
var switchParams = new
{
    chainId = "0x89" // Polygon chain ID in hex (137 in decimal)
};

try
{
    await web3.Client.SendRequestAsync<object>(
        "wallet_switchEthereumChain",
        null,
        new[] { switchParams });

    Console.WriteLine("Switched to Polygon network");
}
catch (RpcResponseException ex) when (ex.RpcError.Code == 4902)
{
    // Network not added to MetaMask, add it first
    var addChainParams = new
    {
        chainId = "0x89",
        chainName = "Polygon Mainnet",
        nativeCurrency = new
        {
            name = "MATIC",
            symbol = "MATIC",
            decimals = 18
        },
        rpcUrls = new[] { "https://polygon-rpc.com/" },
        blockExplorerUrls = new[] { "https://polygonscan.com/" }
    };

    await web3.Client.SendRequestAsync<object>(
        "wallet_addEthereumChain",
        null,
        new[] { addChainParams });

    Console.WriteLine("Added and switched to Polygon network");
}

API Reference

MetamaskHostProvider

public class MetamaskHostProvider : IEthereumHostProvider
{
    // Constructor
    public MetamaskHostProvider(
        IMetamaskInterop metamaskInterop,
        IClient client = null,
        bool useOnlySigningWalletTransactionMethods = false);

    // Properties
    public static MetamaskHostProvider Current { get; }
    public string Name { get; }
    public bool Available { get; }
    public string SelectedAccount { get; }
    public long SelectedNetworkChainId { get; }
    public bool Enabled { get; }
    public IClient Client { get; }

    // Events
    public event Func<string, Task> SelectedAccountChanged;
    public event Func<long, Task> NetworkChanged;
    public event Func<bool, Task> AvailabilityChanged;
    public event Func<bool, Task> EnabledChanged;

    // Methods
    public Task<bool> CheckProviderAvailabilityAsync();
    public Task<string> EnableProviderAsync();
    public Task<IWeb3> GetWeb3Async();
    public Task<string> GetProviderSelectedAccountAsync();
    public Task<string> SignMessageAsync(string message);

    // State change methods (called by platform layer)
    public Task ChangeSelectedAccountAsync(string selectedAccount);
    public Task ChangeSelectedNetworkAsync(long chainId);
    public Task ChangeMetamaskAvailableAsync(bool available);
    public Task ChangeMetamaskEnabledAsync(bool enabled);
}

IMetamaskInterop

public interface IMetamaskInterop
{
    Task<string> EnableEthereumAsync();
    Task<bool> CheckMetamaskAvailability();
    Task<string> GetSelectedAddress();
    Task<RpcResponseMessage> SendAsync(RpcRequestMessage rpcRequestMessage);
    Task<RpcResponseMessage> SendTransactionAsync(MetamaskRpcRequestMessage rpcRequestMessage);
    Task<string> SignAsync(string utf8Hex);
}

MetamaskInterceptor

public class MetamaskInterceptor : RequestInterceptor
{
    public MetamaskInterceptor(
        IMetamaskInterop metamaskInterop,
        bool useOnlySigningWalletTransactionMethods = false);

    public static List<string> SigningWalletTransactionsMethods { get; }
    public string SelectedAccount { get; set; }
}

MetamaskRpcRequestMessage

public class MetamaskRpcRequestMessage : RpcRequestMessage
{
    public MetamaskRpcRequestMessage(
        object id,
        string method,
        string from,
        params object[] parameterList);

    public string From { get; }
}

Important Notes

Platform-Specific Implementation Required

This package provides abstractions only. You must implement IMetamaskInterop for your platform:

  • Blazor: Use Nethereum.Metamask.Blazor (provides JavaScript interop)
  • Desktop/Mobile: Implement IMetamaskInterop with embedded browser control
  • Unity: Implement IMetamaskInterop with WebGL or mobile wallet integration

Two Operating Modes

// Mode 1: All requests through MetaMask (default)
var provider = new MetamaskHostProvider(interop);
// Queries and transactions both use MetaMask
// Slower but everything goes through wallet

// Mode 2: Signing only through MetaMask (hybrid)
var provider = new MetamaskHostProvider(
    interop,
    client: customRpcClient,
    useOnlySigningWalletTransactionMethods: true);
// Queries use custom RPC (faster)
// Transactions use MetaMask (secure)

Automatically Handled Methods

The MetamaskInterceptor automatically routes these methods through MetaMask:

  • eth_sendTransaction - Sends transactions (user approval required)
  • eth_signTransaction - Signs transactions without sending
  • eth_sign - Personal message signing
  • personal_sign - EIP-191 personal message signing
  • eth_signTypedData - Typed data signing (EIP-712)
  • eth_signTypedData_v3 - Typed data signing v3
  • eth_signTypedData_v4 - Typed data signing v4 (recommended)
  • wallet_watchAsset - Add token to MetaMask
  • wallet_addEthereumChain - Add custom network
  • wallet_switchEthereumChain - Switch network

All other methods (queries like eth_call, eth_getBalance, etc.) use the configured RPC client.

Account Injection

The interceptor automatically injects the selected MetaMask account into transactions:

var web3 = await provider.GetWeb3Async();

// No need to specify 'from' - automatically uses MetaMask account
await web3.Eth.GetEtherTransferService()
    .TransferEtherAsync(toAddress, amount);

Static Current Property

For convenience, the last created MetamaskHostProvider is available via:

var provider = new MetamaskHostProvider(interop);
// Later, anywhere in code:
var currentProvider = MetamaskHostProvider.Current;

Error Handling

MetaMask interactions can fail for various reasons:

try
{
    var txHash = await web3.Eth.GetEtherTransferService()
        .TransferEtherAsync(toAddress, amount);
}
catch (RpcResponseException ex)
{
    // User rejected transaction
    if (ex.RpcError.Code == 4001)
    {
        Console.WriteLine("User rejected the transaction");
    }
    // Insufficient funds
    else if (ex.RpcError.Message.Contains("insufficient funds"))
    {
        Console.WriteLine("Insufficient funds");
    }
    else
    {
        Console.WriteLine($"Transaction failed: {ex.Message}");
    }
}

ValueTask Support

On .NET Core 3.1+, IMetamaskInterop uses ValueTask<T> for better performance. On earlier frameworks, it uses Task<T>.

Platform Implementations

  • Nethereum.Metamask.Blazor - Blazor WebAssembly implementation with JavaScript interop

Dependencies

  • Nethereum.UI - Ethereum host provider abstractions
  • Nethereum.Web3 - Web3 client and RPC functionality
  • Nethereum.Blazor - Blazor components and services
  • Nethereum.EIP6963WalletInterop - Multi-wallet discovery
  • Nethereum.WalletConnect - WalletConnect integration
  • Nethereum.Reown.AppKit.Blazor - Reown AppKit integration

Additional 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 net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 is compatible.  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 (3)

Showing the top 3 NuGet packages that depend on Nethereum.Metamask:

Package Downloads
Nethereum.Metamask.Blazor

Nethereum.Metamask.Blazor Nethereum Metamask integration with Blazor including Control and EthereumAuthenticationProvider

Nethereum.Blazor

Nethereum.Blazor Nethereum integration with Blazor including EIP6963WalletInterop and EthereumAuthenticationProvider

Conclave.Nethereum.Metamask.Blazor

Nethereum.Metamask.Blazor Nethereum Metamask integration with Blazor including Control and EthereumAuthenticationProvider

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
5.8.0 305 1/6/2026
5.0.0 936 5/28/2025
4.29.0 445 2/10/2025
4.28.0 386 1/7/2025
4.27.1 255 12/24/2024
4.27.0 238 12/24/2024
4.26.0 463 10/1/2024
4.25.0 322 9/19/2024
4.21.4 336 8/9/2024
4.21.3 433 7/22/2024
4.21.2 452 6/26/2024
4.21.1 257 6/26/2024
4.21.0 618 6/18/2024
4.20.0 1,756 3/28/2024
4.19.0 609 2/16/2024
4.18.0 679 11/21/2023
4.17.1 417 9/28/2023
4.17.0 259 9/27/2023
4.16.0 380 8/14/2023
4.15.2 485 7/11/2023
Loading failed