-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Add Ledger hardware wallet support #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
|
Fixed the failing test in CI. The method now behaves as an idempotent operation - it won't throw an error when attempting to remove a non-existent wallet. All 715 tests are now passing locally. β |
- 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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 17 out of 18 changed files in this pull request and generated 3 comments.
π‘ Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (num < 0.0001) { | ||
| return `${num.toFixed(8)} ${currency}` | ||
| } |
Copilot
AI
Oct 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The threshold value 0.0001 should be defined as a named constant to improve maintainability and make it easier to adjust if needed.
|
|
||
| // For very small amounts, show more decimals | ||
| if (num < 0.0001) { | ||
| return `${num.toFixed(8)} ${currency}` |
Copilot
AI
Oct 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The decimal precision value 8 for very small amounts should be defined as a named constant, similar to how maxDecimals is parameterized for normal amounts.
| const cleanHash = hashStr.startsWith('0x') ? hashStr.slice(2) : hashStr | ||
| if (cleanHash.length !== 64) { | ||
| throw new SafeCLIError('Invalid hash: must be 32 bytes (64 hex characters)') | ||
| } |
Copilot
AI
Oct 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The expected hash length 64 (representing 32 bytes) should be defined as a named constant like HASH_HEX_LENGTH to improve code clarity and maintainability.
Summary
Features Implemented
Ledger Import Command
wallet import-ledgercommandm/44'/60'/0'/0/0m/44'/60'/0'/0Transaction Signing
Balance Display
Wallet Management
Technical Implementation
New Files
src/services/ledger-service.ts- Core Ledger integration with transport interfacesrc/commands/wallet/import-ledger.ts- Interactive Ledger import commandsrc/utils/balance.ts- Balance fetching utilities with parallel RPC callsModified Files
src/types/wallet.ts- Discriminated union for wallet typessrc/storage/wallet-store.ts- Ledger wallet storage and retrievalsrc/services/transaction-service.ts- Ledger signing with proper EIP-712 hash computationsrc/commands/tx/sign.ts- Ledger signing flow integrationsrc/storage/config-store.ts- Added getDefaultChain() methodsrc/ui/screens/WalletImportSuccessScreen.tsx- Balance display on importsrc/ui/screens/WalletListScreen.tsx- Balance and type display in listDependencies Added
@ledgerhq/hw-transport-node-hid- HID transport for USB connection@ledgerhq/hw-app-eth- Ethereum app communicationUsage Example
Testing
Notes
π€ Generated with Claude Code