com um clique
ledger-wallet-cli
// Official Ledger wallet-cli — USB-based CLI for Ledger hardware wallet flows (account discover, receive, balances, operations, send) built on the Device Management Kit (DMK)
// Official Ledger wallet-cli — USB-based CLI for Ledger hardware wallet flows (account discover, receive, balances, operations, send) built on the Device Management Kit (DMK)
Add E2E tests for new coins or update existing Playwright tests for ledger-live-desktop. Use when the user wants to add send/receive e2e tests for a new cryptocurrency, update test configurations, or work with Speculos device simulator.
Create a pull request with proper description, changeset, and all required elements
Interactive setup wizard for running desktop E2E (Playwright + Speculos) tests locally
Interactive setup wizard for running mobile E2E (Detox) tests locally
Guided feature development with codebase understanding and architecture focus
When typecheck finds an error importing from a lib in the monorepo, rebuild the lib
| name | ledger-wallet-cli |
| description | Official Ledger wallet-cli — USB-based CLI for Ledger hardware wallet flows (account discover, receive, balances, operations, send) built on the Device Management Kit (DMK) |
wallet-cli is an experimental USB-based CLI for Ledger wallet flows, built on the Device Management Kit (DMK). Supported networks: bitcoin, ethereum, base, solana (mainnet and testnets). On Ledger devices, Base uses the Ethereum app.
Device contention: Only one command can use the device at a time. Never run two device-required commands in parallel — they will conflict and fail with
[object Object]or a garbled APDU error. Run device commands sequentially.
Prerequisites: Ledger device connected via USB, with the relevant coin app open on device for commands that require it (Base requires opening the Ethereum app).
Run from repo root:
pnpm --silent wallet-cli start <command> [flags]
Sandbox: Commands that open the USB device (
account discover,receive,send) must be run withdangerouslyDisableSandbox: truein the Bash tool — the sandbox blocks USB access and causes aTimeout has occurrederror. Commands that don't need the device (balances,operations,send --dry-run) work fine in the sandbox.
| Command | Device required | Disable sandbox |
|---|---|---|
account discover | Yes | Yes |
receive | Yes (optional with --no-verify) | Yes |
send | Yes (unless --dry-run) | Yes (unless --dry-run) |
balances | No | No |
operations | No | No |
account discover outputs V1 descriptors:
account:1:<type>:<network>:<env>:<xpub_or_address>:<path>
Hardened segments use h (shell-safe). ' is also accepted for backward compatibility.
Examples:
account:1:utxo:bitcoin:main:xpub6BosfCn...:m/84h/0h/0h
account:1:address:ethereum:main:0x71C7656EC7ab88b098defB751B7401B5f6d8976F:m/44h/60h/0h/0/0
account:1:address:solana:main:7xCU4XQfL...:m/44h/501h/0h/0h
account:1:utxo:bitcoin:testnet:tpubD8Lg2g...:m/84h/1h/0h
All commands (balances, operations, receive, send) accept V1 descriptors as --account or first positional arg. Legacy V0 (js:2:bitcoin:xpub...:native_segwit:0) still accepted.
pnpm --silent wallet-cli start account discover bitcoin
pnpm --silent wallet-cli start account discover ethereum
pnpm --silent wallet-cli start account discover base
pnpm --silent wallet-cli start account discover ethereum:sepolia
pnpm --silent wallet-cli start account discover bitcoin --output json
Network forms: bitcoin (= mainnet), ethereum:mainnet (alias → main), base, ethereum:sepolia, bitcoin:testnet (env → testnet), solana:devnet (env → devnet).
Human output: one account per line with fresh address and V1 descriptor to copy.
JSON output: { "accounts": ["account:1:utxo:bitcoin:main:xpub...:m/84h/0h/0h", ...] }
pnpm --silent wallet-cli start receive account:1:utxo:bitcoin:main:xpub...:m/84h/0h/0h
pnpm --silent wallet-cli start receive account:1:address:ethereum:main:0xABC...:m/44h/60h/0h/0/0 --no-verify
Use --no-verify to skip device confirmation.
pnpm --silent wallet-cli start balances account:1:address:ethereum:main:0xABC...:m/44h/60h/0h/0/0
pnpm --silent wallet-cli start balances account:1:utxo:bitcoin:main:xpub...:m/84h/0h/0h --output json
Fetches native balance and token balances (ERC-20). JSON amounts are human-readable strings ("1.5 ETH", "100 USDT").
pnpm --silent wallet-cli start operations account:1:address:ethereum:main:0xABC...:m/44h/60h/0h/0/0
pnpm --silent wallet-cli start operations <descriptor> --limit 20 --cursor <cursor>
pnpm --silent wallet-cli start operations <descriptor> --output json
Lists transactions including internal operations (ETH contract call traces). Pagination: --limit <n> and --cursor <cursor>. Next cursor on stderr (human) or nextCursor in JSON.
JSON: value/fee are human-readable ticker strings. accountId is the V1 descriptor string.
--dry-run)# Native ETH
pnpm --silent wallet-cli start send account:1:address:ethereum:main:0xABC...:m/44h/60h/0h/0/0 \
--to 0xDEF... --amount '0.5 ETH'
# ERC-20 token — ticker resolves the token automatically
pnpm --silent wallet-cli start send account:1:address:ethereum:main:0xABC...:m/44h/60h/0h/0/0 \
--to 0xDEF... --amount '100 USDT'
# Bitcoin with custom fee
pnpm --silent wallet-cli start send account:1:utxo:bitcoin:main:xpub...:m/84h/0h/0h \
--to bc1q... --amount '0.001 BTC' --fee-per-byte 15 --rbf
# Dry run — no device needed
pnpm --silent wallet-cli start send account:1:address:ethereum:main:0xABC...:m/44h/60h/0h/0/0 \
--to 0xDEF... --amount '0.5 ETH' --dry-run
Ticker is mandatory in --amount (e.g. '0.5 ETH', '0.001 BTC'). It drives asset resolution — no --token flag.
--dry-run: prepares and validates without signing or broadcasting. No device opened.
| Flag | Description |
|---|---|
--amount '<value> <TICKER>' | Required. e.g. '0.001 BTC', '0.01 ETH', '0.4 USDT' |
--to <address> | Required. Recipient address |
--dry-run | Prepare and validate without signing or opening the device |
--output json | Machine-readable JSON output |
| Flag | Description |
|---|---|
--fee-per-byte <satoshis> | Custom fee per byte in satoshis |
--rbf | Enable Replace-By-Fee |
| Flag | Description |
|---|---|
--mode <mode> | send, stake.createAccount, stake.delegate, stake.undelegate, stake.withdraw (default: send) |
--validator <address> | Validator address (staking flows) |
--stake-account <address> | Stake account address (staking flows) |
--memo <text> | Memo/tag |
All commands: --output human (default) or --output json.
JSON envelope shape:
{
"status": "success",
"command": "balances",
"network": "ethereum:main",
"account": "account:1:address:ethereum:main:0xABC...:m/44h/60h/0h/0/0",
"timestamp": "2026-04-03T12:00:00.000Z",
"...": "command-specific fields"
}
Command-specific payloads:
account discover: { "accounts": ["account:1:...", ...] }balances: { "balances": [{ "asset": "ethereum", "amount": "1.5 ETH" }, ...] }operations: { "operations": [{ "accountId": "account:1:...", "value": "0.1 ETH", "fee": "...", ... }], "nextCursor": "..." }send: { "tx_hash": "0x...", "amount": "0.5 ETH", "fee": "0.0003 ETH" }send --dry-run: { "dry_run": true, "recipient": "0x...", "amount": "0.5 ETH", "fee": "0.0003 ETH" }Error envelope: { "status": "error", "message": "...", ... } — exit code non-zero.
| Error | Cause |
|---|---|
Amount must include a ticker, e.g. '0.5 ETH' or '0.001 BTC' | --amount given a bare number |
Ticker UNKN not found in account. Available: ETH, USDT, ... | Ticker not in account balances |
No currencyId mapping for network "x:y" | Unsupported network/env combination |
UnknownDeviceExchangeError | Device not connected or coin app not open |
[x] Transaction Cancelled: Rejected on device. No funds moved. | User rejected on device |