Ledger Hardware Wallet common interface of the communication layer
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Core functionality for discovering available Ledger devices and establishing transport connections. This includes both one-time device listing and continuous monitoring of device availability through the observer pattern.
Determines if the transport implementation is supported on the current platform/browser environment.
/**
* Statically check if a transport is supported on the user's platform/browser
* @returns Promise resolving to true if supported, false otherwise
*/
static isSupported(): Promise<boolean>;Usage Example:
import MyTransport from "./my-transport";
const supported = await MyTransport.isSupported();
if (!supported) {
throw new Error("This transport is not supported on your platform");
}Lists all currently available device descriptors in a single snapshot. For real-time device monitoring, use listen() instead.
/**
* List once all available descriptors. For better granularity, use listen()
* @returns Promise of array of descriptors that can be passed to open()
*/
static list(): Promise<Array<Descriptor>>;Usage Example:
import MyTransport from "./my-transport";
// Get all currently connected devices
const descriptors = await MyTransport.list();
console.log(`Found ${descriptors.length} devices`);
for (const descriptor of descriptors) {
try {
const transport = await MyTransport.open(descriptor);
// Use transport...
await transport.close();
} catch (error) {
console.error("Failed to open device:", error);
}
}Continuously monitors for device connection and disconnection events using the observer pattern. This is the recommended approach for responsive device management.
/**
* Listen to all device events for a given Transport using observer pattern
* @param observer Object with next, error, and complete functions
* @returns Subscription object to unsubscribe from events
*/
static listen(observer: Observer<DescriptorEvent<Descriptor>>): Subscription;Usage Example:
import MyTransport from "./my-transport";
const subscription = MyTransport.listen({
next: (event) => {
if (event.type === "add") {
console.log("Device connected:", event.deviceModel?.productName);
// Open the device
MyTransport.open(event.descriptor).then(transport => {
// Device is ready to use
console.log("Transport opened successfully");
});
} else if (event.type === "remove") {
console.log("Device disconnected");
}
},
error: (error) => {
console.error("Device monitoring error:", error);
},
complete: () => {
console.log("Device monitoring completed");
}
});
// Stop listening after 30 seconds
setTimeout(() => {
subscription.unsubscribe();
}, 30000);Opens a transport connection to a specific device using its descriptor.
/**
* Attempt to create a Transport instance with a descriptor
* @param descriptor The descriptor to open the transport with
* @param timeout Optional timeout in milliseconds
* @returns Promise of Transport instance
*/
static open(descriptor: Descriptor, timeout?: number): Promise<Transport<Descriptor>>;Usage Example:
import MyTransport from "./my-transport";
// Assuming you have a descriptor from list() or listen()
const transport = await MyTransport.open(descriptor, 5000); // 5 second timeout
try {
// Set up the transport
transport.setScrambleKey("BTC");
// Use the transport for communication
const response = await transport.send(0xB0, 0x01, 0x00, 0x00);
} finally {
// Always close the transport
await transport.close();
}Convenience method that combines listening and opening the first available device. This is a simplified alternative to manually using listen() and open().
/**
* Create transport by opening the first descriptor available or throw if none found
* @param openTimeout Timeout for opening the device (default: 3000ms)
* @param listenTimeout Timeout for finding a device (optional)
* @returns Promise of Transport instance
*/
static create(openTimeout?: number = 3000, listenTimeout?: number): Promise<Transport<Descriptor>>;Usage Example:
import MyTransport from "./my-transport";
try {
// Wait up to 10 seconds to find a device, then 5 seconds to open it
const transport = await MyTransport.create(5000, 10000);
console.log("Connected to device:", transport.deviceModel?.productName);
// Use the transport
transport.setScrambleKey("BTC");
const response = await transport.send(0xB0, 0x01, 0x00, 0x00);
await transport.close();
} catch (error) {
if (error.id === "NoDeviceFound") {
console.error("No Ledger device found");
} else if (error.id === "ListenTimeout") {
console.error("Timeout waiting for device");
} else {
console.error("Failed to create transport:", error);
}
}interface DescriptorEvent<Descriptor> {
/** Event type: "add" when device connects, "remove" when disconnects */
type: "add" | "remove";
/** Descriptor that can be passed to open() */
descriptor: Descriptor;
/** Device model information (Nano S, Nano X, Blue) */
deviceModel?: DeviceModel | null;
/** Transport-specific device information */
device?: Device;
}interface Observer<Event> {
/** Called when a new event occurs */
next(event: Event): void;
/** Called when an error occurs */
error(e: any): void;
/** Called when observation completes */
complete(): void;
}interface Subscription {
/** Stop listening to events */
unsubscribe(): void;
}The Transport class provides predefined error messages for common scenarios:
class Transport<Descriptor> {
/** Error message for device not found scenarios */
static ErrorMessage_NoDeviceFound: "No Ledger device found";
/** Error message for listen timeout scenarios */
static ErrorMessage_ListenTimeout: "No Ledger device found (timeout)";
}Device management operations may throw various errors:
create()