or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

apdu-communication.mdconfiguration.mddevice-management.mderror-handling.mdevents-lifecycle.mdindex.md
tile.json

tessl/npm-ledgerhq--hw-transport

Ledger Hardware Wallet common interface of the communication layer

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@ledgerhq/hw-transport@5.51.x

To install, run

npx @tessl/cli install tessl/npm-ledgerhq--hw-transport@5.51.0

index.mddocs/

Ledger Hardware Wallet Transport

@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.

Package Information

  • Package Name: @ledgerhq/hw-transport
  • Package Type: npm
  • Language: JavaScript/TypeScript (Flow types)
  • Installation: npm install @ledgerhq/hw-transport

Core Imports

import 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";

Basic Usage

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();

Architecture

The Transport class serves as an abstract base class that defines the standard interface for all Ledger hardware wallet communication:

  • Abstract Base Class: Transport provides the interface specification that concrete implementations must extend
  • Observer Pattern: Device discovery uses the observer pattern for real-time device events
  • Event-driven Communication: Built on EventEmitter for handling connection state changes
  • APDU Protocol: Implements the Application Protocol Data Unit standard for hardware wallet communication
  • Atomic Operations: Ensures thread-safe communication with race condition protection
  • Scramble Key Security: Provides encryption key management for secure app-specific communication

Capabilities

Device Discovery and Connection

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>>;

Device Management

APDU Communication

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>;

APDU Communication

Configuration and Security

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;

Configuration

Event Handling and Connection Management

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>;

Events and Lifecycle

Error Handling

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;
}

Error Handling

Types

Core Transport Types

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,
}>;

Device Model Types

// 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,
  }>,
};

Status Codes

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,
};