Ledger Hardware Wallet common interface of the communication layer
npx @tessl/cli install tessl/npm-ledgerhq--hw-transport@5.51.0@ledgerhq/hw-transport provides the foundational transport layer interface for Ledger Hardware Wallet communication, serving as the base abstraction that enables different transport implementations (USB, Bluetooth, WebUSB, etc.) to communicate with Ledger devices. It defines the core Transport class with essential methods for device discovery, connection management, and APDU (Application Protocol Data Unit) exchange, including features like event-driven device detection, timeout management, debug logging, and scramble key handling for secure communication.
npm install @ledgerhq/hw-transportimport Transport, {
TransportError,
TransportStatusError,
StatusCodes,
getAltStatusMessage
} from "@ledgerhq/hw-transport";For Flow projects:
import Transport, {
TransportError,
TransportStatusError,
StatusCodes,
getAltStatusMessage,
type Subscription,
type Device,
type DescriptorEvent,
type Observer
} from "@ledgerhq/hw-transport";import Transport from "@ledgerhq/hw-transport";
// Example with a hypothetical USB transport implementation
class MyUSBTransport extends Transport {
// Implementation would provide specific transport logic
}
// Check if transport is supported
const isSupported = await MyUSBTransport.isSupported();
if (!isSupported) {
throw new Error("Transport not supported");
}
// Create transport instance
const transport = await MyUSBTransport.create();
// Set scramble key for secure communication
transport.setScrambleKey("BTC");
// Send APDU command (example: get app version)
const response = await transport.send(0xB0, 0x01, 0x00, 0x00);
// Listen for disconnect events
transport.on("disconnect", () => {
console.log("Device disconnected");
});
// Close when done
await transport.close();The Transport class serves as an abstract base class that defines the standard interface for all Ledger hardware wallet communication:
Core functionality for discovering available Ledger devices and establishing transport connections. Includes both one-time listing and continuous monitoring of device availability.
static isSupported(): Promise<boolean>;
static list(): Promise<Array<Descriptor>>;
static listen(observer: Observer<DescriptorEvent<Descriptor>>): Subscription;
static open(descriptor: Descriptor, timeout?: number): Promise<Transport<Descriptor>>;
static create(openTimeout?: number = 3000, listenTimeout?: number): Promise<Transport<Descriptor>>;Low-level and high-level methods for sending Application Protocol Data Units to the Ledger device, including error handling and status code management.
exchange(apdu: Buffer): Promise<Buffer>;
send(cla: number, ins: number, p1: number, p2: number, data?: Buffer, statusList?: Array<number>): Promise<Buffer>;Methods for configuring transport behavior, timeouts, and security settings including scramble key management for app-specific encryption.
setScrambleKey(key: string): void;
setExchangeTimeout(exchangeTimeout: number): void;
setExchangeUnresponsiveTimeout(unresponsiveTimeout: number): void;
setDebugMode(): void;Event-driven architecture for handling device state changes, connection management, and cleanup operations.
on(eventName: string, cb: Function): void;
off(eventName: string, cb: Function): void;
close(): Promise<void>;Comprehensive error classes for handling transport-specific and device status errors with detailed error codes and messages.
class TransportError extends Error {
constructor(message: string, id: string);
}
class TransportStatusError extends Error {
constructor(statusCode: number);
statusCode: number;
statusText: string;
}type Subscription = { unsubscribe: () => void };
type Device = Object;
type DescriptorEvent<Descriptor> = {
type: "add" | "remove",
descriptor: Descriptor,
deviceModel?: ?DeviceModel,
device?: Device,
};
type Observer<Event> = $ReadOnly<{
next: (event: Event) => mixed,
error: (e: any) => mixed,
complete: () => mixed,
}>;// DeviceModelId represents the keys of the devices object: "blue", "nanoS", "nanoX"
type DeviceModelId = $Keys<typeof devices>;
type DeviceModel = {
id: DeviceModelId,
productName: string,
productIdMM: number,
legacyUsbProductId: number,
usbOnly: boolean,
memorySize: number,
getBlockSize: (firmwareVersion: string) => number,
bluetoothSpec?: Array<{
serviceUuid: string,
writeUuid: string,
notifyUuid: string,
}>,
};const StatusCodes = {
PIN_REMAINING_ATTEMPTS: 0x63c0,
INCORRECT_LENGTH: 0x6700,
MISSING_CRITICAL_PARAMETER: 0x6800,
COMMAND_INCOMPATIBLE_FILE_STRUCTURE: 0x6981,
SECURITY_STATUS_NOT_SATISFIED: 0x6982,
CONDITIONS_OF_USE_NOT_SATISFIED: 0x6985,
INCORRECT_DATA: 0x6a80,
NOT_ENOUGH_MEMORY_SPACE: 0x6a84,
REFERENCED_DATA_NOT_FOUND: 0x6a88,
FILE_ALREADY_EXISTS: 0x6a89,
INCORRECT_P1_P2: 0x6b00,
INS_NOT_SUPPORTED: 0x6d00,
CLA_NOT_SUPPORTED: 0x6e00,
TECHNICAL_PROBLEM: 0x6f00,
OK: 0x9000,
MEMORY_PROBLEM: 0x9240,
NO_EF_SELECTED: 0x9400,
INVALID_OFFSET: 0x9402,
FILE_NOT_FOUND: 0x9404,
INCONSISTENT_FILE: 0x9408,
ALGORITHM_NOT_SUPPORTED: 0x9484,
INVALID_KCV: 0x9485,
CODE_NOT_INITIALIZED: 0x9802,
ACCESS_CONDITION_NOT_FULFILLED: 0x9804,
CONTRADICTION_SECRET_CODE_STATUS: 0x9808,
CONTRADICTION_INVALIDATION: 0x9810,
CODE_BLOCKED: 0x9840,
MAX_VALUE_REACHED: 0x9850,
GP_AUTH_FAILED: 0x6300,
LICENSING: 0x6f42,
HALTED: 0x6faa,
};