Skip to main content

@faremeter/wallet-ledger

@faremeter/wallet-ledger integrates Ledger hardware wallets into Faremeter payment flows. It provides:
  • High-level factories that expose the same interfaces as the local wallet adapters (@faremeter/wallet-evm, @faremeter/wallet-solana).
  • Utilities for interactive account selection and CLI prompts.
  • Transport helpers that work in both Node.js and browser environments while translating common Ledger error codes into actionable messages.

Quick start

import {
  createLedgerEvmWallet,
  createLedgerSolanaWallet,
  selectLedgerAccount,
  createReadlineInterface,
} from "@faremeter/wallet-ledger";

const ui = await createReadlineInterface({
  stdin: process.stdin,
  stdout: process.stdout,
});

const account = await selectLedgerAccount(ui, "evm");
if (!account) throw new Error("No account selected");

const wallet = await createLedgerEvmWallet(
  ui,
  baseMainnet,
  account.path,
);

// Use with payment handlers just like a local wallet.
const handler = createPaymentHandler(wallet);

API surface

Wallet factories

createLedgerEvmWallet(ui, chain, derivationPath)

  • ui: object implementing { message, question, close } (UserInterface).
  • chain: ChainInfo for the target EVM network.
  • derivationPath: Ledger derivation path (e.g., m/44'/60'/0'/0/0).
Returns a LedgerEvmWallet with:
  • chain, address, client: compatible with @faremeter/payment-evm.
  • signTransaction(tx): signs a serialized transaction via Ledger.
  • signTypedData(params): supports EIP-712 hashed message signing.
  • disconnect(): closes the underlying transport.
Internally uses @ledgerhq/hw-app-eth, calculates domain/message hashes with viem, and guides the user via ui.message.

createLedgerSolanaWallet(network, derivationPath)

  • Returns a LedgerSolanaWallet exposing { network, publicKey, updateTransaction, disconnect }.
  • updateTransaction(tx) adds the Ledger signature to a VersionedTransaction.
  • Works out of the box with @faremeter/payment-solana handlers.

User interaction helpers

createReadlineInterface({ stdin, stdout })

Produces a CLI UserInterface using Node’s readline module. Useful for quick scripts; replace with your own implementation for GUIs.

selectLedgerAccount(ui, type, numAccounts = 5)

Scans the first numAccounts derivation paths (m/44'/60'/i'/0/0 for EVM, 44'/501'/i' for Solana), prints them via ui.message, prompts the user, and returns { path, address } or null if the selection is invalid.

Transport utilities

createTransport(maxRetries = 3)

Attempts to open a Ledger connection in browser (WebUSB) or Node (HID) contexts, retrying transient USB errors. Uses translateLedgerError to map common status codes to friendly messages and logs warnings via @logtape/logtape namespace ["faremeter","wallet-ledger"].

translateLedgerError(error)

Converts raw Ledger errors (status codes like 0x5515) into descriptive Error objects (“Ledger is locked”, “Wrong app open”, etc.). Also handles common connection issues (NoDevice, Device busy).

Types (./types)

  • LedgerEvmWallet, LedgerSolanaWallet: exported TypeScript interfaces for consumers who want to type-check their adapters.
  • LedgerTransportWrapper, UserInterface: supporting contracts for custom UIs/transports.

Usage patterns

  • Browser flows: createTransport auto-switches to WebUSB when window exists. Ensure your app is served over HTTPS and request the WebUSB permission from the user.
  • Clean shutdown: Always call disconnect() (or ui.close()) when your program exits to release USB handles.
  • Custom UI: Implement the UserInterface contract to integrate with React, Ink, or other UI frameworks while reusing the wallet factories.
  • Error messaging: Wrap calls in try/catch and surface the translateLedgerError message to users; it already handles the majority of Ledger App status codes.
  • @faremeter/payment-evm / @faremeter/payment-solana: consume the returned wallet objects.
  • @faremeter/wallet-evm / @faremeter/wallet-solana: software-only alternatives with the same shape.
  • Source: GitHub › packages/wallet-ledger