Skip to content

Commit d4ccae2

Browse files
Add signing guides: HD wallets, keystore, hardware wallets, cloud KMS
1 parent f1492a1 commit d4ccae2

5 files changed

Lines changed: 526 additions & 0 deletions

File tree

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
---
2+
title: Cloud KMS Signing
3+
sidebar_label: "Cloud KMS"
4+
sidebar_position: 6
5+
description: Sign Ethereum transactions with AWS KMS and Azure Key Vault HSMs
6+
---
7+
8+
# Cloud KMS Signing
9+
10+
Sign Ethereum transactions using cloud-managed HSM keys. The private key is generated inside the HSM and never leaves it — your application only receives signatures.
11+
12+
Both implementations support Legacy, EIP-1559, EIP-2930, and EIP-7702 transaction types.
13+
14+
## AWS Key Management Service
15+
16+
```bash
17+
dotnet add package Nethereum.Signer.AWSKeyManagement
18+
```
19+
20+
### Create the KMS Key
21+
22+
```bash
23+
aws kms create-key \
24+
--key-spec ECC_SECG_P256K1 \
25+
--key-usage SIGN_VERIFY \
26+
--description "Ethereum signing key"
27+
```
28+
29+
### Sign Transactions
30+
31+
```csharp
32+
using Nethereum.Signer.AWSKeyManagement;
33+
using Nethereum.Web3;
34+
using Nethereum.Web3.Accounts;
35+
36+
// Uses default AWS credentials chain (env vars, profile, IAM role)
37+
var signer = new AWSKeyManagementExternalSigner(keyId: "your-kms-key-id");
38+
39+
var externalAccount = new ExternalAccount(signer, chainId: 1);
40+
await externalAccount.InitialiseAsync();
41+
42+
var web3 = new Web3(externalAccount, "https://your-rpc-url");
43+
44+
var receipt = await web3.Eth.GetEtherTransferService()
45+
.TransferEtherAndWaitForReceiptAsync(toAddress, 0.1m);
46+
```
47+
48+
### Authentication Methods
49+
50+
```csharp
51+
// Default credentials chain (recommended for Lambda, ECS, EC2)
52+
var signer = new AWSKeyManagementExternalSigner(keyId);
53+
54+
// Explicit access key
55+
var signer = new AWSKeyManagementExternalSigner(
56+
keyId, accessKeyId: "AKIA...", secretAccessKey: "...");
57+
58+
// Specific region
59+
var signer = new AWSKeyManagementExternalSigner(
60+
keyId, region: Amazon.RegionEndpoint.EUWest1);
61+
```
62+
63+
## Azure Key Vault
64+
65+
```bash
66+
dotnet add package Nethereum.Signer.AzureKeyVault
67+
```
68+
69+
### Create the Key
70+
71+
```bash
72+
az keyvault key create \
73+
--vault-name my-vault \
74+
--name ethereum-key \
75+
--kty EC \
76+
--curve SECP256K1
77+
```
78+
79+
### Sign Transactions
80+
81+
```csharp
82+
using Nethereum.Signer.AzureKeyVault;
83+
using Nethereum.Web3;
84+
using Nethereum.Web3.Accounts;
85+
using Azure.Identity;
86+
87+
// Uses DefaultAzureCredential (managed identity, Azure CLI, etc.)
88+
var signer = new AzureKeyVaultExternalSigner(
89+
keyIdentifier: "https://my-vault.vault.azure.net/keys/ethereum-key");
90+
91+
var externalAccount = new ExternalAccount(signer, chainId: 1);
92+
await externalAccount.InitialiseAsync();
93+
94+
var web3 = new Web3(externalAccount, "https://your-rpc-url");
95+
96+
var receipt = await web3.Eth.GetEtherTransferService()
97+
.TransferEtherAndWaitForReceiptAsync(toAddress, 0.1m);
98+
```
99+
100+
### Authentication Methods
101+
102+
```csharp
103+
// DefaultAzureCredential (auto-detect — recommended)
104+
var signer = new AzureKeyVaultExternalSigner(keyIdentifier);
105+
106+
// Managed identity (Azure VMs, App Service, Functions)
107+
var signer = new AzureKeyVaultExternalSigner(
108+
keyIdentifier, new ManagedIdentityCredential());
109+
110+
// Service principal
111+
var signer = new AzureKeyVaultExternalSigner(
112+
keyIdentifier, new ClientSecretCredential(tenantId, clientId, clientSecret));
113+
```
114+
115+
## Comparison
116+
117+
| Feature | AWS KMS | Azure Key Vault |
118+
|---|---|---|
119+
| Package | `Nethereum.Signer.AWSKeyManagement` | `Nethereum.Signer.AzureKeyVault` |
120+
| Key curve | ECC_SECG_P256K1 | EC SECP256K1 |
121+
| HSM backing | Standard or CloudHSM | Standard or Premium (FIPS 140-2 Level 3) |
122+
| Transaction types | Legacy, 1559, 2930, 7702 | Legacy, 1559, 2930, 7702 |
123+
| Audit logging | CloudTrail | Azure Monitor |
124+
| Pricing model | Per-request + key storage | Per-operation + key storage |
125+
126+
:::tip Claude Code
127+
Install the Nethereum skills plugin for AI-assisted development: `/plugin install nethereum-skills`
128+
:::
129+
130+
## Next Steps
131+
132+
- [Hardware Wallets](./guide-hardware-wallets) — Ledger and Trezor signing
133+
- [Keys & Accounts](../core-foundation/guide-keys-accounts) — account types
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
---
2+
title: Hardware Wallets
3+
sidebar_label: "Hardware Wallets"
4+
sidebar_position: 5
5+
description: Sign transactions with Ledger and Trezor hardware wallets using Nethereum
6+
---
7+
8+
# Hardware Wallets
9+
10+
Sign Ethereum transactions with Ledger and Trezor devices. The private key never leaves the hardware — Nethereum sends unsigned transactions to the device and receives signatures back.
11+
12+
Both implementations use the `ExternalAccount` pattern — once initialised, they work identically to a regular `Account` with `Web3`.
13+
14+
## Ledger
15+
16+
```bash
17+
dotnet add package Nethereum.Signer.Ledger
18+
```
19+
20+
### Connect and Get Address
21+
22+
```csharp
23+
using Nethereum.Ledger;
24+
using Nethereum.Web3;
25+
using Nethereum.Web3.Accounts;
26+
27+
var ledgerManagerFactory = new NethereumLedgerManagerBrokerFactory();
28+
var signer = new LedgerExternalSigner(ledgerManagerFactory, accountIndex: 0);
29+
30+
var externalAccount = new ExternalAccount(signer, chainId: 1);
31+
await externalAccount.InitialiseAsync();
32+
33+
Console.WriteLine($"Address: {externalAccount.Address}");
34+
35+
var web3 = new Web3(externalAccount, "https://your-rpc-url");
36+
```
37+
38+
### Sign and Send Transaction
39+
40+
```csharp
41+
var receipt = await web3.Eth.GetEtherTransferService()
42+
.TransferEtherAndWaitForReceiptAsync(toAddress, 0.1m);
43+
```
44+
45+
### EIP-1559 Transaction
46+
47+
```csharp
48+
var receipt = await web3.Eth.GetEtherTransferService()
49+
.TransferEtherAndWaitForReceiptAsync(toAddress, 0.1m,
50+
maxPriorityFeePerGas: 2,
51+
maxFeePerGas: 30);
52+
```
53+
54+
### Multiple Accounts
55+
56+
```csharp
57+
var signer0 = new LedgerExternalSigner(ledgerManagerFactory, accountIndex: 0);
58+
var signer1 = new LedgerExternalSigner(ledgerManagerFactory, accountIndex: 1);
59+
```
60+
61+
### Legacy Derivation Path
62+
63+
Ledger Live uses `m/44'/60'/0'/0/x` (default). For the older Electrum/Ledger path:
64+
65+
```csharp
66+
var signer = new LedgerExternalSigner(ledgerManagerFactory, accountIndex: 0, legacyPath: true);
67+
// Uses: m/44'/60'/0'/x
68+
```
69+
70+
## Trezor
71+
72+
```bash
73+
dotnet add package Nethereum.Signer.Trezor
74+
```
75+
76+
### Connect with PIN Handler
77+
78+
Trezor requires a PIN prompt handler. The PIN is entered as a numpad position (layout: 7-8-9 / 4-5-6 / 1-2-3 matching the device display):
79+
80+
```csharp
81+
using Nethereum.Trezor;
82+
using Nethereum.Web3;
83+
using Nethereum.Web3.Accounts;
84+
85+
public class ConsolePinHandler : ITrezorPromptHandler
86+
{
87+
public Task<string> PromptPin()
88+
{
89+
Console.Write("Enter PIN (numpad positions): ");
90+
return Task.FromResult(Console.ReadLine());
91+
}
92+
93+
public Task<string> PromptPassphrase()
94+
{
95+
Console.Write("Enter passphrase (or empty): ");
96+
return Task.FromResult(Console.ReadLine());
97+
}
98+
}
99+
100+
var pinHandler = new ConsolePinHandler();
101+
var trezorManagerFactory = new NethereumTrezorManagerBrokerFactory();
102+
var signer = new TrezorExternalSigner(
103+
trezorManagerFactory, pinHandler, accountIndex: 0);
104+
105+
var externalAccount = new ExternalAccount(signer, chainId: 1);
106+
await externalAccount.InitialiseAsync();
107+
108+
var web3 = new Web3(externalAccount, "https://your-rpc-url");
109+
```
110+
111+
### Sign and Send Transaction
112+
113+
```csharp
114+
var receipt = await web3.Eth.GetEtherTransferService()
115+
.TransferEtherAndWaitForReceiptAsync(toAddress, 0.1m);
116+
```
117+
118+
### Sign Personal Message
119+
120+
```csharp
121+
var signature = await signer.SignAsync(
122+
System.Text.Encoding.UTF8.GetBytes("Hello Ethereum!"));
123+
```
124+
125+
### Sign EIP-712 Typed Data
126+
127+
Trezor supports interactive EIP-712 signing with on-device display:
128+
129+
```csharp
130+
var typedData = new TypedData<Domain>
131+
{
132+
PrimaryType = "Permit",
133+
Domain = new Domain { Name = "MyToken", Version = "1", ChainId = 1 },
134+
// ... type definitions and message
135+
};
136+
137+
var signature = await signer.SignTypedDataV4Async(typedData);
138+
```
139+
140+
### Cross-Platform Setup
141+
142+
```csharp
143+
// Windows — uses Windows.Devices.HumanInterfaceDevice (default)
144+
var factory = new NethereumTrezorManagerBrokerFactory();
145+
146+
// Linux/macOS — requires LibUSB
147+
var factory = new NethereumTrezorManagerBrokerFactory(
148+
new LibUsbHidDeviceHandler());
149+
```
150+
151+
## Comparison
152+
153+
| Feature | Ledger | Trezor |
154+
|---|---|---|
155+
| Package | `Nethereum.Signer.Ledger` | `Nethereum.Signer.Trezor` |
156+
| PIN entry | On device | Via numpad handler |
157+
| Passphrase (25th word) | Via device | Via prompt handler |
158+
| EIP-712 signing | No | Yes (interactive display) |
159+
| Personal message signing | No | Yes |
160+
| Transaction types | Legacy, EIP-1559 | Legacy, EIP-1559 |
161+
162+
:::tip Claude Code
163+
Install the Nethereum skills plugin for AI-assisted development: `/plugin install nethereum-skills`
164+
:::
165+
166+
## Next Steps
167+
168+
- [Cloud KMS](./guide-cloud-kms) — sign with AWS KMS or Azure Key Vault
169+
- [Keys & Accounts](../core-foundation/guide-keys-accounts) — account types

0 commit comments

Comments
 (0)