Skip to content

Commit db707f3

Browse files
katspaughclaude
andauthored
feat: Add Ledger hardware wallet support (#11)
* feat: Add Ledger hardware wallet support Implemented full Ledger hardware wallet integration for Safe CLI, enabling users to import and use Ledger devices for signing Safe multisig transactions with EIP-712. Key Features: - Import Ledger wallets with flexible derivation paths (Ledger Live, Legacy MEW, Custom) - Sign Safe transactions using Ledger device with EIP-712 - Display wallet balances for both private key and Ledger wallets - Device detection and connection management - Transport layer abstraction for future migration to device-sdk-ts Technical Implementation: - Added LedgerService with transport interface pattern - Extended wallet types to discriminated union (private-key | ledger) - Integrated @ledgerhq/hw-transport-node-hid and @ledgerhq/hw-app-eth - Computed Safe transaction struct hash manually for proper EIP-712 signing - Added balance fetching utilities with parallel RPC calls - Updated UI components to show wallet types and balances Files Changed: - New: src/services/ledger-service.ts - Core Ledger integration - New: src/commands/wallet/import-ledger.ts - Interactive import command - New: src/utils/balance.ts - Balance fetching utilities - Modified: src/types/wallet.ts - Discriminated union for wallet types - Modified: src/storage/wallet-store.ts - Ledger wallet management - Modified: src/services/transaction-service.ts - Ledger signing with EIP-712 - Modified: src/commands/tx/sign.ts - Ledger signing flow - Modified: src/ui/screens/* - Display balances and wallet types - Modified: README.md - Updated documentation with Ledger instructions πŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: Make removeWallet idempotent (don't throw on non-existent wallet) * test: Add comprehensive tests for Ledger functionality - Add unit tests for LedgerService (connection, device detection, derivation paths) - Add unit tests for balance utilities (getBalance, getBalances, formatBalance) - Add integration tests for Ledger wallet import and management - Add tests for mixed wallet types (private-key + Ledger) - All 755 tests passing --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 6ce278e commit db707f3

File tree

18 files changed

+3174
-74
lines changed

18 files changed

+3174
-74
lines changed

β€ŽREADME.mdβ€Ž

Lines changed: 161 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Safe CLI provides a powerful command-line interface for:
1414
- **Interacting with smart contracts** through an intuitive transaction builder
1515
- **Automating Safe operations** in scripts and workflows
1616
- **Managing multiple Safes across different chains** from one place
17+
- **Hardware wallet support** - Use Ledger devices for maximum security
1718

1819
Perfect for developers, power users, and teams who prefer working in the terminal.
1920

@@ -22,7 +23,7 @@ Perfect for developers, power users, and teams who prefer working in the termina
2223
## ✨ Features
2324

2425
### Core Functionality
25-
- πŸ” **Secure wallet management** - Encrypted private key storage with AES-256-GCM
26+
- πŸ” **Secure wallet management** - Encrypted private key storage with AES-256-GCM + Ledger hardware wallet support
2627
- ⛓️ **Multi-chain support** - Works with Ethereum, Polygon, Arbitrum, Optimism, Base, and more
2728
- 🎨 **Beautiful interface** - Modern terminal UI with interactive prompts
2829
- πŸ“¦ **Safe lifecycle** - Create, deploy, and manage Safe accounts
@@ -59,9 +60,13 @@ This sets up your chain configurations and optional API keys.
5960

6061
**2. Import a wallet**
6162
```bash
63+
# Option A: Import from private key
6264
safe wallet import
65+
66+
# Option B: Import Ledger hardware wallet (recommended)
67+
safe wallet import-ledger
6368
```
64-
Your private key will be encrypted with a password you choose.
69+
Private keys are encrypted with a password. Ledger wallets use your hardware device for signing.
6570

6671
**3. Create your first Safe**
6772
```bash
@@ -91,7 +96,8 @@ Follow the interactive prompts to configure owners and threshold.
9196
| Command | Description |
9297
|---------|-------------|
9398
| `safe wallet import` | Import a wallet with your private key |
94-
| `safe wallet list` | View all your wallets |
99+
| `safe wallet import-ledger` | Import a Ledger hardware wallet |
100+
| `safe wallet list` | View all your wallets (shows wallet types) |
95101
| `safe wallet use` | Switch to a different wallet |
96102
| `safe wallet remove` | Delete a wallet |
97103

@@ -132,6 +138,146 @@ Follow the interactive prompts to configure owners and threshold.
132138

133139
---
134140

141+
## πŸ” Hardware Wallet Support
142+
143+
Safe CLI supports **Ledger hardware wallets** for enhanced security. Your private keys never leave the device.
144+
145+
### Prerequisites
146+
147+
1. **Ledger device** (Nano S, Nano S Plus, or Nano X)
148+
2. **Ethereum app installed** on your Ledger
149+
3. **Device firmware** up to date
150+
151+
### Importing a Ledger Wallet
152+
153+
```bash
154+
safe wallet import-ledger
155+
```
156+
157+
The CLI will guide you through:
158+
159+
1. **Device detection** - Connects to your Ledger automatically
160+
2. **Derivation path selection** - Choose your address path:
161+
- **Ledger Live** (recommended): `m/44'/60'/0'/0/0`
162+
- **Legacy MEW**: `m/44'/60'/0'/0` (for MyEtherWallet compatibility)
163+
- **Custom path**: Advanced users can specify their own BIP44 path
164+
3. **Account index** - Select which account to use (0, 1, 2, etc.)
165+
4. **Address verification** - Confirm the address matches your device screen
166+
5. **Wallet naming** - Give your wallet a friendly name
167+
168+
**Example:**
169+
```bash
170+
$ safe wallet import-ledger
171+
172+
β”Œ Import Ledger Hardware Wallet
173+
β”‚
174+
β—‡ Device detected!
175+
β”‚
176+
β—† Select derivation path
177+
β”‚ ● Ledger Live (m/44'/60'/0'/0/0) - Default for Ledger Live (recommended)
178+
β”‚ β—‹ Legacy MEW (m/44'/60'/0'/0) - Compatible with MyEtherWallet/MyCrypto
179+
β”‚ β—‹ Custom path - Advanced: specify your own BIP44 path
180+
β””
181+
β—† Enter account index
182+
β”‚ 0
183+
β””
184+
β—‡ Address: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb
185+
β”‚ Derivation path: m/44'/60'/0'/0/0
186+
β”‚
187+
β—† Does this address match what is shown on your Ledger device?
188+
β”‚ Yes
189+
β””
190+
β—† Enter a name for this wallet
191+
β”‚ My Ledger
192+
β””
193+
β—‡ Wallet imported successfully!
194+
β”‚ ID: a3f5e8c92d1b...
195+
β”‚ Address: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb
196+
β”‚ Path: m/44'/60'/0'/0/0
197+
β”‚
198+
β”” Done!
199+
```
200+
201+
### Using Your Ledger Wallet
202+
203+
Once imported, your Ledger wallet works seamlessly with all Safe CLI commands:
204+
205+
**Signing Transactions:**
206+
```bash
207+
safe tx sign
208+
209+
# The CLI automatically detects your Ledger wallet
210+
# β†’ Connecting to Ledger device...
211+
# β†’ Please confirm transaction on your Ledger device...
212+
# β†’ Transaction signed βœ“
213+
```
214+
215+
**Switching Wallets:**
216+
```bash
217+
safe wallet list # Shows: πŸ” Ledger or πŸ”‘ Private Key
218+
safe wallet use # Switch between wallets
219+
```
220+
221+
### Multiple Ledger Accounts
222+
223+
You can import multiple accounts from the same Ledger:
224+
225+
```bash
226+
# Import account 0
227+
safe wallet import-ledger
228+
# β†’ Account index: 0
229+
# β†’ Name: "Ledger Account 0"
230+
231+
# Import account 1
232+
safe wallet import-ledger
233+
# β†’ Account index: 1
234+
# β†’ Name: "Ledger Account 1"
235+
```
236+
237+
Each account is tracked separately with its own derivation path.
238+
239+
### Troubleshooting
240+
241+
**"No Ledger device found"**
242+
- Ensure device is connected via USB
243+
- Unlock your Ledger
244+
- Open the **Ethereum app** on the device
245+
246+
**"Failed to connect to Ledger"**
247+
- Close Ledger Live (it locks the device)
248+
- Try a different USB cable/port
249+
- Update Ledger firmware to latest version
250+
251+
**"Transaction signing failed"**
252+
- Make sure you approved the transaction on device
253+
- Check that **Contract data** is enabled in Ethereum app settings
254+
- Verify the device didn't time out (screen went dark)
255+
256+
**Contract Data Setting (Required for Safe):**
257+
1. Open Ethereum app on Ledger
258+
2. Navigate to Settings
259+
3. Enable "Contract data"
260+
4. Exit back to main Ethereum app
261+
262+
### Security Notes
263+
264+
βœ… **What's stored locally:**
265+
- Wallet address
266+
- Derivation path
267+
- Wallet name and metadata
268+
269+
❌ **What's NOT stored:**
270+
- Private keys (always on device)
271+
- PIN code
272+
- Recovery phrase
273+
274+
πŸ”’ **Transaction signing:**
275+
- All signatures happen on the device
276+
- You must physically approve each transaction
277+
- Address and transaction details shown on device screen
278+
279+
---
280+
135281
## πŸ’‘ Common Workflows
136282

137283
### Creating and Deploying a Safe
@@ -272,11 +418,20 @@ These are optional but recommended for enhanced functionality:
272418

273419
## πŸ” Security
274420

421+
### Private Key Wallets
275422
- **Encryption**: Private keys encrypted with AES-256-GCM
276423
- **Key derivation**: PBKDF2 with 100,000 iterations
277424
- **Local storage**: All data stored locally on your machine
278425
- **No exposure**: Keys never logged or transmitted in plain text
279426

427+
### Hardware Wallets (Ledger)
428+
- **Maximum security**: Private keys never leave the device
429+
- **Physical confirmation**: All transactions require on-device approval
430+
- **Industry standard**: BIP44 derivation paths
431+
- **Secure Element**: Military-grade chip protection
432+
433+
**Recommendation**: Use Ledger hardware wallets for production Safe accounts with significant funds.
434+
280435
---
281436

282437
## πŸ› οΈ For Developers
@@ -315,12 +470,13 @@ npm run build
315470
src/
316471
β”œβ”€β”€ commands/ # Command implementations
317472
β”‚ β”œβ”€β”€ config/ # Configuration commands
318-
β”‚ β”œβ”€β”€ wallet/ # Wallet management
473+
β”‚ β”œβ”€β”€ wallet/ # Wallet management (incl. Ledger)
319474
β”‚ β”œβ”€β”€ account/ # Safe account operations
320475
β”‚ └── tx/ # Transaction commands
321476
β”œβ”€β”€ services/ # Business logic
322477
β”‚ β”œβ”€β”€ safe-service.ts
323478
β”‚ β”œβ”€β”€ transaction-service.ts
479+
β”‚ β”œβ”€β”€ ledger-service.ts # Ledger hardware wallet integration
324480
β”‚ β”œβ”€β”€ abi-service.ts
325481
β”‚ └── validation-service.ts
326482
β”œβ”€β”€ storage/ # Persistent storage
@@ -340,6 +496,7 @@ src/
340496
- **@clack/prompts** - Interactive prompts
341497
- **Viem** - Ethereum utilities
342498
- **Safe Core SDK** - Safe protocol integration
499+
- **LedgerJS** - Hardware wallet integration
343500
- **Zod** - Runtime validation
344501

345502
---

0 commit comments

Comments
Β (0)