CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ledgerhq--hw-transport

Ledger Hardware Wallet common interface of the communication layer

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

configuration.mddocs/

Configuration and Security

Methods for configuring transport behavior, timeouts, and security settings. This includes scramble key management for app-specific encryption, timeout configuration for communication reliability, and debug settings.

Capabilities

Scramble Key Management

Sets the encryption key used for secure communication with specific Ledger applications. Each app typically has its own scramble key for security isolation.

/**
 * Set the "scramble key" for the next exchanges with the device
 * Each App can have a different scramble key and they internally set it at instantiation
 * @param key The scramble key string
 */
setScrambleKey(key: string): void;

Usage Example:

import Transport from "@ledgerhq/hw-transport";

const transport = await MyTransport.create();

// Set scramble key for Bitcoin app
transport.setScrambleKey("BTC");

// Now all APDU exchanges will use the Bitcoin scramble key
const response = await transport.send(0xE0, 0x40, 0x00, 0x00);

// Switch to Ethereum app
transport.setScrambleKey("ETH");
const ethResponse = await transport.send(0xE0, 0x02, 0x00, 0x00);

Common Scramble Keys:

  • "BTC" - Bitcoin and Bitcoin-based cryptocurrencies
  • "ETH" - Ethereum and ERC-20 tokens
  • "XRP" - Ripple
  • "ADA" - Cardano
  • "" (empty string) - No scrambling (for system commands)

Exchange Timeout Configuration

Controls how long to wait for APDU command responses before timing out. This helps prevent hanging operations when devices become unresponsive.

/**
 * Set a timeout (in milliseconds) for the exchange call
 * Only some transport implementations might implement it (e.g. U2F)
 * @param exchangeTimeout Timeout in milliseconds
 */
setExchangeTimeout(exchangeTimeout: number): void;

Usage Example:

const transport = await MyTransport.create();

// Set 10 second timeout for slow operations
transport.setExchangeTimeout(10000);

// This command will timeout after 10 seconds if no response
try {
  const response = await transport.send(0xE0, 0x04, 0x00, 0x00, transactionData);
} catch (error) {
  // Handle timeout or other errors
  console.error("Command timed out or failed:", error);
}

// Reset to default timeout (30 seconds)
transport.setExchangeTimeout(30000);

Unresponsive Detection Timeout

Configures how long to wait before emitting "unresponsive" events when a device stops responding during operations.

/**
 * Define the delay before emitting "unresponsive" on an exchange that does not respond
 * @param unresponsiveTimeout Timeout in milliseconds
 */
setExchangeUnresponsiveTimeout(unresponsiveTimeout: number): void;

Usage Example:

const transport = await MyTransport.create();

// Monitor for unresponsiveness after 5 seconds
transport.setExchangeUnresponsiveTimeout(5000);

// Listen for unresponsive events
transport.on("unresponsive", () => {
  console.warn("Device appears unresponsive - please check connection");
  // Show user feedback about unresponsive device
});

transport.on("responsive", () => {
  console.log("Device is responding again");
  // Hide unresponsive warning
});

// Start a potentially slow operation
const signature = await transport.send(0xE0, 0x04, 0x01, 0x00, largeTransaction);

Debug Mode (Deprecated)

Legacy method for enabling debug logging. This method is deprecated and no longer emits logs.

/**
 * Enable or not logs of the binary exchange
 * @deprecated Use @ledgerhq/logs instead. No logs are emitted in this anymore.
 */
setDebugMode(): void;

Migration Example:

// Old approach (deprecated)
transport.setDebugMode();

// New approach - use @ledgerhq/logs
import { setDebugMode } from "@ledgerhq/logs";
setDebugMode(true);

Configuration Properties

Default Timeout Values

The Transport class provides default timeout configurations:

class Transport<Descriptor> {
  /** Default timeout for APDU exchanges (30 seconds) */
  exchangeTimeout: number = 30000;
  
  /** Default timeout for unresponsive detection (15 seconds) */
  unresponsiveTimeout: number = 15000;
  
  /** Connected device model information */
  deviceModel: DeviceModel | null = null;
  
  /** Internal lock to prevent concurrent app API operations */
  _appAPIlock: string | null = null;
  
  /** Promise tracking current exchange operation for race condition prevention */
  exchangeBusyPromise: Promise<void> | null = null;
}

Accessing Configuration

const transport = await MyTransport.create();

console.log("Current exchange timeout:", transport.exchangeTimeout);
console.log("Current unresponsive timeout:", transport.unresponsiveTimeout);
console.log("Connected device:", transport.deviceModel?.productName);

// Modify timeouts
transport.setExchangeTimeout(60000);  // 1 minute
transport.setExchangeUnresponsiveTimeout(10000);  // 10 seconds

console.log("New exchange timeout:", transport.exchangeTimeout);

Security Considerations

Scramble Key Best Practices

  1. App-Specific Keys: Always use the appropriate scramble key for the target application
  2. Key Management: Store scramble keys securely and don't hardcode them in public repositories
  3. Key Rotation: Some applications may require different keys for different operations
// Example: Context-aware scramble key usage
class LedgerWalletManager {
  constructor(transport) {
    this.transport = transport;
  }
  
  async switchToApp(appName) {
    const scrambleKeys = {
      'bitcoin': 'BTC',
      'ethereum': 'ETH', 
      'ripple': 'XRP'
    };
    
    const key = scrambleKeys[appName];
    if (!key) {
      throw new Error(`Unknown app: ${appName}`);
    }
    
    this.transport.setScrambleKey(key);
    return this.waitForApp(appName);
  }
}

Timeout Configuration Guidelines

  1. Exchange Timeout: Set based on expected operation complexity

    • Simple queries: 5-10 seconds
    • Transaction signing: 30-60 seconds
    • Firmware operations: 2-5 minutes
  2. Unresponsive Timeout: Balance user experience with false positives

    • Interactive operations: 5-10 seconds
    • Background operations: 15-30 seconds
// Example: Operation-specific timeout configuration
async function performComplexOperation(transport, operationType) {
  const timeouts = {
    'quick_query': { exchange: 5000, unresponsive: 3000 },
    'transaction_sign': { exchange: 30000, unresponsive: 10000 },
    'firmware_update': { exchange: 300000, unresponsive: 60000 }
  };
  
  const config = timeouts[operationType];
  if (config) {
    transport.setExchangeTimeout(config.exchange);
    transport.setExchangeUnresponsiveTimeout(config.unresponsive);
  }
  
  // Perform the operation...
}

Environment-Specific Configuration

Different transport implementations may handle configuration differently:

// WebUSB transport - timeout affects browser API calls
import TransportWebUSB from "@ledgerhq/hw-transport-webusb";
const webTransport = await TransportWebUSB.create();
webTransport.setExchangeTimeout(15000); // Browser timeout

// Node.js HID transport - timeout affects system calls  
import TransportNodeHid from "@ledgerhq/hw-transport-node-hid";
const hidTransport = await TransportNodeHid.create();
hidTransport.setExchangeTimeout(10000); // System timeout

App API Decoration Methods

Batch Method Decoration

Decorates multiple methods on an object with app API locking and scramble key management.

/**
 * Decorates multiple methods on an object with app API locking and scramble key management
 * @param self The object containing methods to decorate
 * @param methods Array of method names to decorate
 * @param scrambleKey The scramble key to use for these methods
 */
decorateAppAPIMethods(
  self: Object,
  methods: Array<string>,
  scrambleKey: string
): void;

Single Method Decoration

Decorates a single method with app API locking and scramble key management.

/**
 * Decorates a single method with app API locking and scramble key management
 * @param methodName Name of the method for error reporting
 * @param f The function to decorate
 * @param ctx The context (this) to bind the function to
 * @param scrambleKey The scramble key to use for this method
 * @returns Decorated function with locking and scramble key management
 */
decorateAppAPIMethod<R, A: any[]>(
  methodName: string,
  f: (...args: A) => Promise<R>,
  ctx: any,
  scrambleKey: string
): (...args: A) => Promise<R>;

Usage Example:

import Transport from "@ledgerhq/hw-transport";

class MyLedgerApp {
  constructor(transport) {
    this.transport = transport;
    
    // Decorate multiple methods at once
    this.transport.decorateAppAPIMethods(
      this,
      ['getVersion', 'getPublicKey', 'signTransaction'],
      'BTC'
    );
    
    // Or decorate individual methods
    this.getAddress = this.transport.decorateAppAPIMethod(
      'getAddress',
      this._getRawAddress.bind(this),
      this,
      'BTC'
    );
  }
  
  // These methods will be automatically decorated with locking
  async getVersion() {
    return await this.transport.send(0xB0, 0x01, 0x00, 0x00);
  }
  
  async getPublicKey(path) {
    return await this.transport.send(0xE0, 0x40, 0x00, 0x00, path);
  }
  
  async signTransaction(txData) {
    return await this.transport.send(0xE0, 0x44, 0x00, 0x00, txData);
  }
  
  // Raw method that gets decorated
  async _getRawAddress(path, display) {
    return await this.transport.send(0xE0, 0x42, display ? 0x01 : 0x00, 0x00, path);
  }
}

App API Lock Property

The transport maintains an internal lock to prevent concurrent app API operations.

class Transport<Descriptor> {
  /** Internal lock to prevent concurrent app API operations */
  _appAPIlock: string | null = null;
}

When methods are decorated, they automatically:

  1. Check if another operation is in progress (_appAPIlock)
  2. Set the lock with the method name
  3. Set the appropriate scramble key
  4. Execute the method
  5. Clear the lock when complete

This prevents race conditions and ensures proper scramble key isolation between different app operations.

docs

apdu-communication.md

configuration.md

device-management.md

error-handling.md

events-lifecycle.md

index.md

tile.json