![]() |
VOOZH | about |
dotnet add package Nethereum.Signer.Ledger --version 6.1.0
NuGet\Install-Package Nethereum.Signer.Ledger -Version 6.1.0
<PackageReference Include="Nethereum.Signer.Ledger" Version="6.1.0" />
<PackageVersion Include="Nethereum.Signer.Ledger" Version="6.1.0" />Directory.Packages.props
<PackageReference Include="Nethereum.Signer.Ledger" />Project file
paket add Nethereum.Signer.Ledger --version 6.1.0
#r "nuget: Nethereum.Signer.Ledger, 6.1.0"
#:package Nethereum.Signer.Ledger@6.1.0
#addin nuget:?package=Nethereum.Signer.Ledger&version=6.1.0Install as a Cake Addin
#tool nuget:?package=Nethereum.Signer.Ledger&version=6.1.0Install as a Cake Tool
Ledger hardware wallet integration for Ethereum transaction signing with Nethereum.
Nethereum.Signer.Ledger provides external signing capability for Ethereum transactions and messages using Ledger Nano S, Nano S Plus, and Nano X hardware wallets. This allows secure transaction signing where private keys never leave the hardware device.
Key Features:
m/44'/60'/0'/0/x (default) and m/44'/60'/0'/x (Ledger legacy)Use Cases:
dotnet add package Nethereum.Signer.Ledger
Platform-Specific Notes:
External:
Nethereum:
using Nethereum.Ledger;
using Nethereum.Web3.Accounts;
using Ledger.Net;
// Initialize Ledger connection
var ledgerManagerBroker = NethereumLedgerManagerBrokerFactory.CreateWindowsHidUsb();
var ledgerManager = (LedgerManager)await ledgerManagerBroker.WaitForFirstDeviceAsync();
// Create external signer with Ledger (account index 0)
var ledgerSigner = new LedgerExternalSigner(ledgerManager, 0);
// Create external account
var account = new ExternalAccount(ledgerSigner, chainId: 1);
await account.InitialiseAsync();
// Use with Web3
var web3 = new Web3.Web3(account, "https://mainnet.infura.io/v3/YOUR-PROJECT-ID");
// Address is retrieved from Ledger
Console.WriteLine("Address: " + account.Address);
Before using this library, ensure your Ledger device:
using Nethereum.Ledger;
using Nethereum.Web3.Accounts;
using Ledger.Net;
// Create device broker for Windows USB HID
var ledgerManagerBroker = NethereumLedgerManagerBrokerFactory.CreateWindowsHidUsb();
// Wait for Ledger device (user must connect and unlock)
Console.WriteLine("Connect your Ledger and open the Ethereum app...");
var ledgerManager = (LedgerManager)await ledgerManagerBroker.WaitForFirstDeviceAsync();
Console.WriteLine("Ledger connected!");
// Create external signer (account 0, default path m/44'/60'/0'/0/0)
var ledgerSigner = new LedgerExternalSigner(ledgerManager, index: 0);
// Create external account
var account = new ExternalAccount(ledgerSigner, chainId: 1);
await account.InitialiseAsync();
Console.WriteLine($"Ledger Address: {account.Address}");
// Address matches Ledger Live "Ethereum 1" account
using Nethereum.Ledger;
using Nethereum.Web3;
using Nethereum.Web3.Accounts;
using Nethereum.RPC.Eth.DTOs;
using Nethereum.Hex.HexTypes;
using Ledger.Net;
// Connect to Ledger
var ledgerManagerBroker = NethereumLedgerManagerBrokerFactory.CreateWindowsHidUsb();
var ledgerManager = (LedgerManager)await ledgerManagerBroker.WaitForFirstDeviceAsync();
// Account 0 with default derivation path
var externalAccount = new ExternalAccount(
new LedgerExternalSigner(ledgerManager, 0, legacyPath: false),
chainId: 1
);
await externalAccount.InitialiseAsync();
// Initialize Web3 with RPC client
var web3 = new Web3(externalAccount);
web3.Client = new JsonRpc.Client.RpcClient(new Uri("https://mainnet.infura.io/v3/YOUR-PROJECT-ID"));
// Create transaction
var transactionInput = new TransactionInput
{
From = externalAccount.Address,
To = "0x12890d2cce102216644c59daE5baed380d848301",
Value = new HexBigInteger(100), // 100 wei
Gas = new HexBigInteger(21000),
GasPrice = new HexBigInteger(20000000000), // 20 gwei
Nonce = new HexBigInteger(1)
};
// User must approve on Ledger device
Console.WriteLine("Approve transaction on Ledger...");
var signedTransaction = await externalAccount.TransactionManager
.SignTransactionAsync(transactionInput);
Console.WriteLine($"Signed: {signedTransaction}");
// Send to network
var txHash = await web3.Eth.Transactions.SendRawTransaction.SendRequestAsync(signedTransaction);
Console.WriteLine($"Transaction hash: {txHash}");
using Nethereum.Ledger;
using Nethereum.Web3.Accounts;
using Nethereum.RPC.Eth.DTOs;
using Nethereum.Hex.HexTypes;
using Ledger.Net;
var ledgerManagerBroker = NethereumLedgerManagerBrokerFactory.CreateWindowsHidUsb();
var ledgerManager = (LedgerManager)await ledgerManagerBroker.WaitForFirstDeviceAsync();
var externalAccount = new ExternalAccount(
new LedgerExternalSigner(ledgerManager, 0),
chainId: 1
);
await externalAccount.InitialiseAsync();
// EIP-1559 transaction with MaxFeePerGas and MaxPriorityFeePerGas
var transactionInput = new TransactionInput
{
From = externalAccount.Address,
To = "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
Value = new HexBigInteger(1000000000000000), // 0.001 ETH
Gas = new HexBigInteger(21000),
MaxFeePerGas = new HexBigInteger(50000000000), // 50 gwei
MaxPriorityFeePerGas = new HexBigInteger(2000000000), // 2 gwei (tip)
Nonce = new HexBigInteger(5)
};
Console.WriteLine("Approve EIP-1559 transaction on Ledger...");
var signedTx = await externalAccount.TransactionManager.SignTransactionAsync(transactionInput);
Console.WriteLine($"Signed EIP-1559 Transaction: {signedTx}");
using Nethereum.Ledger;
using Nethereum.Web3.Accounts;
using Nethereum.Contracts;
using Nethereum.ABI.FunctionEncoding.Attributes;
using System.Numerics;
using Ledger.Net;
// ERC-20 Transfer function
[Function("transfer", "bool")]
public class TransferFunction : FunctionMessage
{
[Parameter("address", "_to", 1)]
public string To { get; set; }
[Parameter("uint256", "_value", 2)]
public BigInteger Value { get; set; }
}
// Connect to Ledger
var ledgerManagerBroker = NethereumLedgerManagerBrokerFactory.CreateWindowsHidUsb();
var ledgerManager = (LedgerManager)await ledgerManagerBroker.WaitForFirstDeviceAsync();
var externalAccount = new ExternalAccount(
new LedgerExternalSigner(ledgerManager, 0),
chainId: 1
);
await externalAccount.InitialiseAsync();
// Create contract function call
var transfer = new TransferFunction
{
To = "0x12890d2cce102216644c59daE5baed380d848301",
FromAddress = externalAccount.Address,
Value = 1000000000000000000, // 1 token (18 decimals)
Nonce = 1,
GasPrice = 100,
Gas = 100000
};
var contractAddress = "0x12890d2cce102216644c59daE5baed380d84830c";
var transactionInput = transfer.CreateTransactionInput(contractAddress);
// IMPORTANT: "Contract data" must be enabled in Ledger Ethereum app settings
Console.WriteLine("Approve contract interaction on Ledger...");
Console.WriteLine("(Ensure 'Contract data' is enabled in Ledger settings)");
var signedTransaction = await externalAccount.TransactionManager
.SignTransactionAsync(transactionInput);
Console.WriteLine($"Signed contract call: {signedTransaction}");
using Nethereum.Ledger;
using Nethereum.Web3.Accounts;
using Nethereum.Contracts;
using Nethereum.ABI.FunctionEncoding.Attributes;
using Ledger.Net;
// Contract deployment message
public class StandardTokenDeployment : ContractDeploymentMessage
{
public static string BYTECODE = "0x606060405260405160208061..."; // Full bytecode
public StandardTokenDeployment() : base(BYTECODE) { }
[Parameter("uint256", "totalSupply")]
public int TotalSupply { get; set; }
}
// Connect to Ledger
var ledgerManagerBroker = NethereumLedgerManagerBrokerFactory.CreateWindowsHidUsb();
var ledgerManager = (LedgerManager)await ledgerManagerBroker.WaitForFirstDeviceAsync();
var externalAccount = new ExternalAccount(
new LedgerExternalSigner(ledgerManager, 0),
chainId: 1
);
await externalAccount.InitialiseAsync();
// Create deployment transaction
var deployment = new StandardTokenDeployment
{
FromAddress = externalAccount.Address,
TotalSupply = 1000000,
Nonce = 1,
GasPrice = 20000000000,
Gas = 3000000
};
var transactionInput = deployment.CreateTransactionInput();
// CRITICAL: Must enable "Contract data" and possibly "Blind signing" on Ledger
Console.WriteLine("Approve contract deployment on Ledger...");
Console.WriteLine("This may require 'Blind signing' enabled for large bytecode");
externalAccount.TransactionManager.UseLegacyAsDefault = true; // Use legacy for deployment
var signedDeployment = await externalAccount.TransactionManager
.SignTransactionAsync(transactionInput);
Console.WriteLine($"Signed deployment: {signedDeployment}");
using Nethereum.Ledger;
using Nethereum.Web3.Accounts;
using Ledger.Net;
var ledgerManagerBroker = NethereumLedgerManagerBrokerFactory.CreateWindowsHidUsb();
var ledgerManager = (LedgerManager)await ledgerManagerBroker.WaitForFirstDeviceAsync();
// Legacy path: m/44'/60'/0'/x (old Ledger Live format)
var ledgerSignerLegacy = new LedgerExternalSigner(
ledgerManager,
index: 0,
legacyPath: true // Use m/44'/60'/0'/0 instead of m/44'/60'/0'/0/0
);
var account = new ExternalAccount(ledgerSignerLegacy, chainId: 1);
await account.InitialiseAsync();
Console.WriteLine($"Legacy path address: {account.Address}");
// This address matches old Ledger Live / MEW Ledger mode
using Nethereum.Ledger;
using Nethereum.Web3.Accounts;
using Ledger.Net;
var ledgerManagerBroker = NethereumLedgerManagerBrokerFactory.CreateWindowsHidUsb();
var ledgerManager = (LedgerManager)await ledgerManagerBroker.WaitForFirstDeviceAsync();
// Account 0 (Ethereum 1 in Ledger Live)
var account0 = new ExternalAccount(
new LedgerExternalSigner(ledgerManager, 0),
chainId: 1
);
await account0.InitialiseAsync();
Console.WriteLine($"Account 0: {account0.Address}");
// Account 1 (Ethereum 2 in Ledger Live)
var account1 = new ExternalAccount(
new LedgerExternalSigner(ledgerManager, 1),
chainId: 1
);
await account1.InitialiseAsync();
Console.WriteLine($"Account 1: {account1.Address}");
// Account 5 (Ethereum 6 in Ledger Live)
var account5 = new ExternalAccount(
new LedgerExternalSigner(ledgerManager, 5),
chainId: 1
);
await account5.InitialiseAsync();
Console.WriteLine($"Account 5: {account5.Address}");
using Nethereum.Ledger;
using Nethereum.Web3.Accounts;
using Ledger.Net;
var ledgerManagerBroker = NethereumLedgerManagerBrokerFactory.CreateWindowsHidUsb();
var ledgerManager = (LedgerManager)await ledgerManagerBroker.WaitForFirstDeviceAsync();
// Custom BIP44 path (e.g., for testnet or custom derivation)
string customPath = "m/44'/60'/1'/0"; // Account 1 instead of 0
var ledgerSigner = new LedgerExternalSigner(
ledgerManager,
index: 3, // Will derive m/44'/60'/1'/0/3
customPath: customPath
);
var account = new ExternalAccount(ledgerSigner, chainId: 1);
await account.InitialiseAsync();
Console.WriteLine($"Custom path address: {account.Address}");
using Nethereum.Ledger;
using Nethereum.Web3.Accounts;
using Nethereum.RPC.Eth.DTOs;
using Nethereum.Hex.HexTypes;
using Ledger.Net;
// Known test account
var addressFrom = "0x07dCc60Ec5179f30ba30a2Ec25B683d5C5276025";
var privateKey = "0x32b28a67ec29294be914a356a9f439cf1fd8c56a400d897f75f46694fb06a9c9";
// Sign with regular account
var regularAccount = new Web3.Accounts.Account(privateKey, chainId: 1);
var transactionInput = new TransactionInput
{
From = addressFrom,
To = "0x12890d2cce102216644c59daE5baed380d848301",
Value = new HexBigInteger(100),
Gas = new HexBigInteger(21000),
GasPrice = new HexBigInteger(20000000000),
Nonce = new HexBigInteger(1)
};
var regularSignature = await regularAccount.TransactionManager
.SignTransactionAsync(transactionInput);
// Sign with Ledger (assuming same account is on Ledger index 0)
var ledgerManagerBroker = NethereumLedgerManagerBrokerFactory.CreateWindowsHidUsb();
var ledgerManager = (LedgerManager)await ledgerManagerBroker.WaitForFirstDeviceAsync();
var ledgerAccount = new ExternalAccount(
new LedgerExternalSigner(ledgerManager, 0),
chainId: 1
);
await ledgerAccount.InitialiseAsync();
var ledgerSignature = await ledgerAccount.TransactionManager
.SignTransactionAsync(transactionInput);
// Signatures should match
Console.WriteLine($"Regular: {regularSignature}");
Console.WriteLine($"Ledger: {ledgerSignature}");
Console.WriteLine($"Match: {regularSignature == ledgerSignature}");
External signer implementation for Ledger hardware wallets.
public class LedgerExternalSigner : EthExternalSignerBase
{
// Constructors
public LedgerExternalSigner(LedgerManager ledgerManager, uint index, bool legacyPath = false);
public LedgerExternalSigner(LedgerManager ledgerManager, uint index, string customPath);
// Properties
public LedgerManager LedgerManager { get; }
public byte[] CurrentPublicKey { get; set; }
public override bool CalculatesV { get; protected set; } = false;
public override ExternalSignerTransactionFormat ExternalSignerTransactionFormat { get; } = ExternalSignerTransactionFormat.RLP;
public override bool Supported1559 { get; } = true;
// Methods
public byte[] GetPath();
protected override Task<byte[]> GetPublicKeyAsync();
protected override Task<ECDSASignature> SignExternallyAsync(byte[] hash);
public override Task SignAsync(LegacyTransaction transaction);
public override Task SignAsync(LegacyTransactionChainId transaction);
public override Task SignAsync(Transaction1559 transaction);
}
Factory for creating Ledger device connections.
public class NethereumLedgerManagerBrokerFactory
{
public static LedgerManagerBroker CreateWindowsHidUsb();
}
Factory for creating Ledger manager instances.
public class NethereumLedgerManagerFactory : ILedgerManagerFactory
{
public IManagesLedger GetNewLedgerManager(IDevice ledgerHidDevice, ICoinUtility coinUtility, ErrorPromptDelegate errorPrompt);
}
CRITICAL: Before using, configure Ledger Ethereum app:
1. Open Ethereum app on device
2. Go to Settings (gear icon)
3. Enable "Contract data" (required for smart contracts)
4. Enable "Blind signing" (required for complex contracts/large data)
5. Enable "Debug data" (optional, for development)
Without these settings enabled, transactions may be rejected by the device.
| Path | Format | Used By | Ledger Live Name |
|---|---|---|---|
| Default | m/44'/60'/0'/0/x |
Current standard | "Ethereum 1", "Ethereum 2", etc. |
| Legacy | m/44'/60'/0'/x |
Old Ledger Live (pre-2022) | Legacy accounts |
Note: If addresses don't match Ledger Live, you may need to use legacyPath: true.
| Type | Supported | Notes |
|---|---|---|
| Legacy | Yes | EIP-155 with chain ID |
| EIP-1559 (Type 2) | Yes | MaxFeePerGas, MaxPriorityFeePerGas |
| EIP-2930 (Type 1) | No | Not implemented |
| EIP-7702 (Type 4) | No | Not implemented |
// Always inform user of required actions
Console.WriteLine("Please connect your Ledger device");
Console.WriteLine("1. Connect via USB");
Console.WriteLine("2. Enter PIN");
Console.WriteLine("3. Open Ethereum app");
Console.WriteLine("4. Keep device unlocked during signing");
var ledgerManager = await ledgerManagerBroker.WaitForFirstDeviceAsync();
Console.WriteLine("Ledger connected! Approve transaction on device...");
Users must:
using Ledger.Net.Exceptions;
try
{
var signature = await externalAccount.TransactionManager
.SignTransactionAsync(transactionInput);
}
catch (LedgerException ex)
{
// Device not connected, app not open, or user rejected
Console.WriteLine($"Ledger error: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"Signing error: {ex.Message}");
}
Common errors:
// Ledger supports all chain IDs
var mainnetAccount = new ExternalAccount(ledgerSigner, chainId: 1); // Ethereum
var polygonAccount = new ExternalAccount(ledgerSigner, chainId: 137); // Polygon
var avalancheAccount = new ExternalAccount(ledgerSigner, chainId: 43114); // Avalanche
Note: For chainId > 109, Ledger hardware has specific handling. This is automatically managed by the library.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 is compatible. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 netstandard2.0 is compatible. netstandard2.1 netstandard2.1 was computed. |
| .NET Framework | net461 net461 is compatible. net462 net462 was computed. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 6.1.0 | 776 | 3/25/2026 |
| 6.0.4 | 173 | 3/18/2026 |
| 6.0.3 | 122 | 3/18/2026 |
| 6.0.1 | 132 | 3/17/2026 |
| 6.0.0 | 140 | 3/16/2026 |
| 5.8.0 | 180 | 1/6/2026 |
| 5.0.0 | 510 | 5/28/2025 |
| 4.29.0 | 298 | 2/10/2025 |
| 4.28.0 | 9,756 | 1/7/2025 |
| 4.27.1 | 298 | 12/24/2024 |
| 4.27.0 | 261 | 12/24/2024 |
| 4.26.0 | 3,458 | 10/1/2024 |
| 4.25.0 | 294 | 9/19/2024 |
| 4.21.4 | 336 | 8/9/2024 |
| 4.21.3 | 304 | 7/22/2024 |
| 4.21.2 | 293 | 6/26/2024 |
| 4.21.1 | 315 | 6/26/2024 |
| 4.21.0 | 324 | 6/18/2024 |
| 4.20.0 | 358 | 3/28/2024 |
| 4.19.0 | 8,870 | 2/16/2024 |