@bytezhang/ledger-adapter 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -62,7 +62,24 @@ declare class LedgerAdapter implements IHardwareWallet {
62
62
  * - If ANY session exists (Ledger IDs are ephemeral), reuse it.
63
63
  * - Otherwise: search → 1 device: auto-connect, multiple: ask user, 0: throw.
64
64
  */
65
+ private static readonly MAX_DEVICE_RETRY;
66
+ private _deviceConnectResolve;
67
+ private static readonly DEVICE_CONNECT_TIMEOUT_MS;
68
+ /**
69
+ * Wait for user to connect and unlock device.
70
+ * Emits 'ui-request' event via the adapter's own emitter.
71
+ * The consumer (monorepo adapter wrapper) listens for this and shows UI.
72
+ * When user confirms, they call adapter.deviceConnectResponse() which resolves this promise.
73
+ * Times out after 60 seconds if no response is received.
74
+ */
75
+ private _waitForDeviceConnect;
76
+ /**
77
+ * Called by consumer to respond to ui-request-device-connect.
78
+ * type='confirm' → retry search, type='cancel' → abort.
79
+ */
80
+ deviceConnectResponse(type: 'confirm' | 'cancel'): void;
65
81
  private ensureConnected;
82
+ private _connectFirstOrSelect;
66
83
  /**
67
84
  * Call the connector with automatic session resolution and disconnect retry.
68
85
  *
package/dist/index.d.ts CHANGED
@@ -62,7 +62,24 @@ declare class LedgerAdapter implements IHardwareWallet {
62
62
  * - If ANY session exists (Ledger IDs are ephemeral), reuse it.
63
63
  * - Otherwise: search → 1 device: auto-connect, multiple: ask user, 0: throw.
64
64
  */
65
+ private static readonly MAX_DEVICE_RETRY;
66
+ private _deviceConnectResolve;
67
+ private static readonly DEVICE_CONNECT_TIMEOUT_MS;
68
+ /**
69
+ * Wait for user to connect and unlock device.
70
+ * Emits 'ui-request' event via the adapter's own emitter.
71
+ * The consumer (monorepo adapter wrapper) listens for this and shows UI.
72
+ * When user confirms, they call adapter.deviceConnectResponse() which resolves this promise.
73
+ * Times out after 60 seconds if no response is received.
74
+ */
75
+ private _waitForDeviceConnect;
76
+ /**
77
+ * Called by consumer to respond to ui-request-device-connect.
78
+ * type='confirm' → retry search, type='cancel' → abort.
79
+ */
80
+ deviceConnectResponse(type: 'confirm' | 'cancel'): void;
65
81
  private ensureConnected;
82
+ private _connectFirstOrSelect;
66
83
  /**
67
84
  * Call the connector with automatic session resolution and disconnect retry.
68
85
  *
package/dist/index.js CHANGED
@@ -158,7 +158,7 @@ function stripHex(hex) {
158
158
  function padHex64(hex) {
159
159
  return `0x${stripHex(hex).padStart(64, "0")}`;
160
160
  }
161
- var LedgerAdapter = class {
161
+ var _LedgerAdapter = class _LedgerAdapter {
162
162
  constructor(connector) {
163
163
  this.vendor = "ledger";
164
164
  this.emitter = new import_hardware_wallet_core2.TypedEventEmitter();
@@ -167,6 +167,8 @@ var LedgerAdapter = class {
167
167
  this._discoveredDevices = /* @__PURE__ */ new Map();
168
168
  // Session tracking: maps connectId -> sessionId
169
169
  this._sessions = /* @__PURE__ */ new Map();
170
+ // Pending device-connect resolve — set by _waitForDeviceConnect, resolved by uiResponse
171
+ this._deviceConnectResolve = null;
170
172
  // ---------------------------------------------------------------------------
171
173
  // Event translation
172
174
  // ---------------------------------------------------------------------------
@@ -490,16 +492,53 @@ var LedgerAdapter = class {
490
492
  async solSignMessage(_connectId, _deviceId, _params) {
491
493
  return (0, import_hardware_wallet_core2.failure)(import_hardware_wallet_core2.HardwareErrorCode.MethodNotSupported, "Solana signMessage is not supported on Ledger yet");
492
494
  }
493
- // ---------------------------------------------------------------------------
494
- // Private helpers
495
- // ---------------------------------------------------------------------------
496
495
  /**
497
- * Ensure at least one device is connected and return a valid connectId.
498
- *
499
- * - If a session already exists for the given connectId, reuse it.
500
- * - If ANY session exists (Ledger IDs are ephemeral), reuse it.
501
- * - Otherwise: search 1 device: auto-connect, multiple: ask user, 0: throw.
496
+ * Wait for user to connect and unlock device.
497
+ * Emits 'ui-request' event via the adapter's own emitter.
498
+ * The consumer (monorepo adapter wrapper) listens for this and shows UI.
499
+ * When user confirms, they call adapter.deviceConnectResponse() which resolves this promise.
500
+ * Times out after 60 seconds if no response is received.
501
+ */
502
+ _waitForDeviceConnect(attempt) {
503
+ return new Promise((resolve, reject) => {
504
+ let settled = false;
505
+ const timer = setTimeout(() => {
506
+ if (!settled) {
507
+ settled = true;
508
+ this._deviceConnectResolve = null;
509
+ reject(new Error("Ledger device connect timed out after 60 seconds"));
510
+ }
511
+ }, _LedgerAdapter.DEVICE_CONNECT_TIMEOUT_MS);
512
+ this._deviceConnectResolve = (cancelled) => {
513
+ if (settled) return;
514
+ settled = true;
515
+ clearTimeout(timer);
516
+ this._deviceConnectResolve = null;
517
+ if (cancelled) {
518
+ reject(new Error("User cancelled Ledger connection"));
519
+ } else {
520
+ resolve();
521
+ }
522
+ };
523
+ this.emitter.emit("ui-request-device-connect", {
524
+ type: "ui-request-device-connect",
525
+ payload: {
526
+ message: "Please connect and unlock your Ledger device",
527
+ retryCount: attempt,
528
+ maxRetries: _LedgerAdapter.MAX_DEVICE_RETRY
529
+ }
530
+ });
531
+ });
532
+ }
533
+ /**
534
+ * Called by consumer to respond to ui-request-device-connect.
535
+ * type='confirm' → retry search, type='cancel' → abort.
502
536
  */
537
+ deviceConnectResponse(type) {
538
+ if (this._deviceConnectResolve) {
539
+ this._deviceConnectResolve(type === "cancel");
540
+ }
541
+ }
503
542
  async ensureConnected(connectId) {
504
543
  if (connectId && this._sessions.has(connectId)) {
505
544
  return connectId;
@@ -507,13 +546,21 @@ var LedgerAdapter = class {
507
546
  if (this._sessions.size > 0) {
508
547
  return this._sessions.keys().next().value;
509
548
  }
510
- const devices = await this.searchDevices();
511
- if (devices.length === 0) {
512
- throw Object.assign(
513
- new Error("No Ledger device found. Make sure the device is connected via USB and ready."),
514
- { _tag: "DeviceNotRecognizedError" }
515
- );
549
+ for (let attempt = 0; attempt < _LedgerAdapter.MAX_DEVICE_RETRY; attempt++) {
550
+ const devices = await this.searchDevices();
551
+ if (devices.length > 0) {
552
+ return this._connectFirstOrSelect(devices);
553
+ }
554
+ if (attempt < _LedgerAdapter.MAX_DEVICE_RETRY - 1) {
555
+ await this._waitForDeviceConnect(attempt + 1);
556
+ }
516
557
  }
558
+ throw Object.assign(
559
+ new Error("No Ledger device found after multiple attempts. Please connect and unlock your device."),
560
+ { _tag: "DeviceNotRecognizedError" }
561
+ );
562
+ }
563
+ async _connectFirstOrSelect(devices) {
517
564
  if (devices.length === 1) {
518
565
  const result2 = await this.connectDevice(devices[0].connectId);
519
566
  if (!result2.success) {
@@ -699,6 +746,19 @@ var LedgerAdapter = class {
699
746
  };
700
747
  }
701
748
  };
749
+ // ---------------------------------------------------------------------------
750
+ // Private helpers
751
+ // ---------------------------------------------------------------------------
752
+ /**
753
+ * Ensure at least one device is connected and return a valid connectId.
754
+ *
755
+ * - If a session already exists for the given connectId, reuse it.
756
+ * - If ANY session exists (Ledger IDs are ephemeral), reuse it.
757
+ * - Otherwise: search → 1 device: auto-connect, multiple: ask user, 0: throw.
758
+ */
759
+ _LedgerAdapter.MAX_DEVICE_RETRY = 3;
760
+ _LedgerAdapter.DEVICE_CONNECT_TIMEOUT_MS = 6e4;
761
+ var LedgerAdapter = _LedgerAdapter;
702
762
 
703
763
  // src/device/LedgerDeviceManager.ts
704
764
  var LedgerDeviceManager = class {
@@ -718,8 +778,8 @@ var LedgerDeviceManager = class {
718
778
  enumerate() {
719
779
  return new Promise((resolve) => {
720
780
  let resolved = false;
721
- let sub = null;
722
- sub = this._dmk.listenToAvailableDevices().subscribe({
781
+ let syncResult = null;
782
+ const sub = this._dmk.listenToAvailableDevices().subscribe({
723
783
  next: (devices) => {
724
784
  if (resolved) return;
725
785
  resolved = true;
@@ -727,25 +787,20 @@ var LedgerDeviceManager = class {
727
787
  for (const d of devices) {
728
788
  this._discovered.set(d.id, d);
729
789
  }
730
- if (sub) {
731
- sub.unsubscribe();
732
- } else {
733
- Promise.resolve().then(() => sub?.unsubscribe());
734
- }
735
- console.log("[LedgerDeviceManager] enumerate devices:", JSON.stringify(devices.map((d) => ({
736
- id: d.id,
737
- deviceModel: d.deviceModel,
738
- name: d.name
739
- }))));
740
- resolve(devices.map((d) => ({ path: d.id, type: d.deviceModel.name })));
790
+ syncResult = devices;
741
791
  },
742
792
  error: () => {
743
- if (resolved) return;
744
- resolved = true;
745
- sub?.unsubscribe();
746
- resolve([]);
793
+ if (!resolved) {
794
+ resolved = true;
795
+ resolve([]);
796
+ }
747
797
  }
748
798
  });
799
+ if (syncResult !== null) {
800
+ sub.unsubscribe();
801
+ const devices = syncResult;
802
+ resolve(devices.map((d) => ({ path: d.id, type: d.deviceModel.name })));
803
+ }
749
804
  });
750
805
  }
751
806
  /**
@@ -861,6 +916,8 @@ function deviceActionToPromise(action, onInteraction) {
861
916
  const interaction = state.intermediateValue?.requiredUserInteraction;
862
917
  if (interaction && interaction !== "none") {
863
918
  onInteraction(interaction);
919
+ } else if (interaction === "none") {
920
+ onInteraction("interaction-complete");
864
921
  }
865
922
  }
866
923
  },
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/adapter/LedgerAdapter.ts","../src/errors.ts","../src/device/LedgerDeviceManager.ts","../src/signer/deviceActionToPromise.ts","../src/signer/SignerEth.ts","../src/signer/SignerManager.ts","../src/signer/SignerBtc.ts","../src/transport/registry.ts","../src/app/AppManager.ts"],"sourcesContent":["// Adapter\nexport { LedgerAdapter } from './adapter/LedgerAdapter';\n\n// Device management (used by connectors)\nexport { LedgerDeviceManager } from './device/LedgerDeviceManager';\n\n// Signer (used by connectors)\nexport { SignerManager } from './signer/SignerManager';\nexport { SignerEth } from './signer/SignerEth';\nexport { SignerBtc } from './signer/SignerBtc';\nexport { deviceActionToPromise } from './signer/deviceActionToPromise';\n\n// Transport registry\nexport { registerTransport, unregisterTransport, getTransportProvider, listRegisteredTransports, clearRegistry } from './transport/registry';\n\n// App management\nexport { AppManager } from './app/AppManager';\n\n// Types\nexport type { IDmk, DmkDiscoveredDevice, DeviceActionState, SignerEvmAddress, SignerEvmSignature, SignerBtcAddress, TransportProvider, TransportProviderInstance, TransportProviderOptions } from './types';\n\n// Errors\nexport { isDeviceLockedError, mapLedgerError } from './errors';\n","import type {\n IHardwareWallet,\n IUiHandler,\n IConnector,\n ConnectorDevice,\n DeviceInfo,\n HardwareEventMap,\n DeviceEventListener,\n TransportType,\n ConnectionType,\n Response,\n EvmGetAddressParams,\n EvmAddress,\n EvmGetPublicKeyParams,\n EvmPublicKey,\n EvmSignTxParams,\n EvmSignedTx,\n EvmSignMsgParams,\n EvmSignTypedDataParams,\n EvmSignature,\n ProgressCallback,\n BtcGetAddressParams,\n BtcAddress,\n BtcGetPublicKeyParams,\n BtcPublicKey,\n BtcSignTxParams,\n BtcSignedTx,\n BtcSignMsgParams,\n BtcSignature,\n SolGetAddressParams,\n SolAddress,\n SolGetPublicKeyParams,\n SolPublicKey,\n SolSignTxParams,\n SolSignedTx,\n SolSignMsgParams,\n SolSignature,\n ChainCapability,\n} from '@bytezhang/hardware-wallet-core';\nimport {\n success,\n failure,\n HardwareErrorCode,\n TypedEventEmitter,\n DEVICE,\n UI_REQUEST,\n} from '@bytezhang/hardware-wallet-core';\nimport { mapLedgerError, isDeviceDisconnectedError } from '../errors';\n\n/** Ensure a hex string has the `0x` prefix. */\nfunction ensure0x(hex: string): string {\n return hex.startsWith('0x') ? hex : `0x${hex}`;\n}\n\n/** Remove `0x` prefix from a hex string if present. */\nfunction stripHex(hex: string): string {\n return hex.startsWith('0x') ? hex.slice(2) : hex;\n}\n\n/** Ensure a hex string is `0x`-prefixed and zero-padded to 64 hex chars (32 bytes). */\nfunction padHex64(hex: string): string {\n return `0x${stripHex(hex).padStart(64, '0')}`;\n}\n\n/**\n * Ledger hardware wallet adapter that delegates to an IConnector.\n *\n * This is a thin translation layer that:\n * - Accepts a pre-configured IConnector (transport decisions are made at connector creation time)\n * - Translates IHardwareWallet method calls to connector.call() invocations\n * - Maps connector results/errors to our Response<T> format with enriched error messages\n * - Translates connector events to HardwareEventMap events\n * - Integrates with IUiHandler for permission flows\n */\nexport class LedgerAdapter implements IHardwareWallet {\n readonly vendor = 'ledger' as const;\n\n private readonly connector: IConnector;\n private readonly emitter = new TypedEventEmitter<HardwareEventMap>();\n\n private _uiHandler: Partial<IUiHandler> | null = null;\n\n // Device cache: tracks discovered devices from connector events\n private _discoveredDevices = new Map<string, DeviceInfo>();\n\n // Session tracking: maps connectId -> sessionId\n private _sessions = new Map<string, string>();\n\n constructor(connector: IConnector) {\n this.connector = connector;\n this.registerEventListeners();\n }\n\n // ---------------------------------------------------------------------------\n // Transport\n // ---------------------------------------------------------------------------\n // Transport is decided at connector creation time. These methods\n // satisfy the IHardwareWallet interface with sensible defaults.\n\n get activeTransport(): TransportType | null {\n return 'hid';\n }\n\n getAvailableTransports(): TransportType[] {\n return ['hid'];\n }\n\n async switchTransport(_type: TransportType): Promise<void> {\n // Transport is fixed at connector creation time.\n // To switch transport, create a new LedgerAdapter with a different connector.\n }\n\n // ---------------------------------------------------------------------------\n // UI handler\n // ---------------------------------------------------------------------------\n\n setUiHandler(handler: Partial<IUiHandler>): void {\n this._uiHandler = handler;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n async init(_config?: unknown): Promise<void> {\n // Connector is injected via constructor, already initialized.\n // Nothing to do here.\n }\n\n async dispose(): Promise<void> {\n this.unregisterEventListeners();\n this.connector.reset();\n this._uiHandler = null;\n this._discoveredDevices.clear();\n this._sessions.clear();\n this.emitter.removeAllListeners();\n }\n\n // ---------------------------------------------------------------------------\n // Device management\n // ---------------------------------------------------------------------------\n\n async searchDevices(): Promise<DeviceInfo[]> {\n await this._ensureDevicePermission();\n\n const devices = await this.connector.searchDevices();\n console.log('[LedgerAdapter] connector.searchDevices raw:', JSON.stringify(devices));\n\n for (const d of devices) {\n if (d.connectId && !this._discoveredDevices.has(d.connectId)) {\n this._discoveredDevices.set(d.connectId, this.connectorDeviceToDeviceInfo(d));\n }\n }\n\n // If no devices found, ensure permission (no connectId = search context)\n if (this._discoveredDevices.size === 0) {\n await this._ensureDevicePermission();\n }\n\n return Array.from(this._discoveredDevices.values());\n }\n\n async connectDevice(connectId: string): Promise<Response<string>> {\n await this._ensureDevicePermission(connectId);\n try {\n const session = await this.connector.connect(connectId);\n this._sessions.set(connectId, session.sessionId);\n\n // Update device cache with richer info from session\n if (session.deviceInfo) {\n this._discoveredDevices.set(connectId, session.deviceInfo);\n }\n\n return success(connectId);\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async disconnectDevice(connectId: string): Promise<void> {\n const sessionId = this._sessions.get(connectId);\n if (sessionId) {\n await this.connector.disconnect(sessionId);\n this._sessions.delete(connectId);\n }\n }\n\n async getDeviceInfo(\n connectId: string,\n deviceId: string,\n ): Promise<Response<DeviceInfo>> {\n await this._ensureDevicePermission(connectId, deviceId);\n\n // Look up the device in the cache populated by event handlers / searchDevices.\n // Try connectId first (the USB path), then fall back to scanning by deviceId.\n const cached =\n this._discoveredDevices.get(connectId) ??\n Array.from(this._discoveredDevices.values()).find(\n (d) => d.deviceId === deviceId,\n );\n\n if (cached) {\n return success(cached);\n }\n\n return failure(\n HardwareErrorCode.DeviceNotFound,\n 'Device not found in cache. Call searchDevices() or wait for a device-connected event first.',\n );\n }\n\n getSupportedChains(): ChainCapability[] {\n return ['evm', 'btc', 'sol'];\n }\n\n // ---------------------------------------------------------------------------\n // Events\n // ---------------------------------------------------------------------------\n\n on<K extends keyof HardwareEventMap>(event: K, listener: (event: HardwareEventMap[K]) => void): void;\n on(event: string, listener: DeviceEventListener): void;\n on(event: string, listener: (event: any) => void): void {\n this.emitter.on(event, listener);\n }\n\n off<K extends keyof HardwareEventMap>(event: K, listener: (event: HardwareEventMap[K]) => void): void;\n off(event: string, listener: DeviceEventListener): void;\n off(event: string, listener: (event: any) => void): void {\n this.emitter.off(event, listener);\n }\n\n cancel(connectId: string): void {\n const sessionId = this._sessions.get(connectId) ?? connectId;\n void this.connector.cancel(sessionId);\n }\n\n // ---------------------------------------------------------------------------\n // EVM methods\n // ---------------------------------------------------------------------------\n\n async evmGetAddress(\n connectId: string,\n _deviceId: string,\n params: EvmGetAddressParams,\n ): Promise<Response<EvmAddress>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'evmGetAddress', {\n path: params.path,\n showOnDevice: params.showOnDevice,\n chainId: params.chainId,\n }) as { address: string; publicKey?: string; path?: string };\n\n return success({\n address: result.address,\n path: params.path,\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async evmGetAddresses(\n connectId: string,\n deviceId: string,\n params: EvmGetAddressParams[],\n onProgress?: ProgressCallback,\n ): Promise<Response<EvmAddress[]>> {\n return this.batchCall(\n params,\n (p) => this.evmGetAddress(connectId, deviceId, p),\n onProgress,\n );\n }\n\n async evmGetPublicKey(\n connectId: string,\n _deviceId: string,\n params: EvmGetPublicKeyParams,\n ): Promise<Response<EvmPublicKey>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'evmGetAddress', {\n path: params.path,\n showOnDevice: params.showOnDevice,\n }) as { address: string; publicKey: string; path?: string };\n\n return success({\n publicKey: result.publicKey,\n path: params.path,\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async evmSignTransaction(\n connectId: string,\n _deviceId: string,\n params: EvmSignTxParams,\n ): Promise<Response<EvmSignedTx>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'evmSignTransaction', {\n path: params.path,\n transaction: {\n to: params.to,\n value: params.value,\n chainId: params.chainId,\n nonce: params.nonce,\n gasLimit: params.gasLimit,\n gasPrice: params.gasPrice,\n maxFeePerGas: params.maxFeePerGas,\n maxPriorityFeePerGas: params.maxPriorityFeePerGas,\n accessList: params.accessList,\n data: params.data,\n },\n }) as { v: string; r: string; s: string; serializedTx?: string };\n\n return success({\n v: ensure0x(result.v),\n r: padHex64(result.r),\n s: padHex64(result.s),\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async evmSignMessage(\n connectId: string,\n _deviceId: string,\n params: EvmSignMsgParams,\n ): Promise<Response<EvmSignature>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'evmSignMessage', {\n path: params.path,\n message: params.message,\n }) as { signature: string; address?: string };\n\n return success({\n signature: ensure0x(result.signature),\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async evmSignTypedData(\n connectId: string,\n _deviceId: string,\n params: EvmSignTypedDataParams,\n ): Promise<Response<EvmSignature>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n // Ledger requires full EIP-712 structure — hash mode is not supported.\n if (params.mode === 'hash') {\n return failure(\n HardwareErrorCode.MethodNotSupported,\n 'Ledger does not support hash-only EIP-712 signing. Use mode \"full\" with the complete typed data structure.',\n );\n }\n\n try {\n const result = await this.connectorCall(connectId, 'evmSignTypedData', {\n path: params.path,\n data: params.data,\n }) as { signature: string; address?: string };\n\n return success({\n signature: ensure0x(result.signature),\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n // ---------------------------------------------------------------------------\n // BTC methods\n // ---------------------------------------------------------------------------\n\n async btcGetAddress(\n connectId: string,\n _deviceId: string,\n params: BtcGetAddressParams,\n ): Promise<Response<BtcAddress>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'btcGetAddress', {\n path: params.path,\n coin: params.coin,\n showOnDevice: params.showOnDevice,\n scriptType: params.scriptType,\n }) as { address: string; path: string };\n\n return success({\n address: result.address,\n path: params.path,\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async btcGetAddresses(\n connectId: string,\n deviceId: string,\n params: BtcGetAddressParams[],\n onProgress?: ProgressCallback,\n ): Promise<Response<BtcAddress[]>> {\n return this.batchCall(\n params,\n (p) => this.btcGetAddress(connectId, deviceId, p),\n onProgress,\n );\n }\n\n async btcGetPublicKey(\n connectId: string,\n _deviceId: string,\n params: BtcGetPublicKeyParams,\n ): Promise<Response<BtcPublicKey>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'btcGetPublicKey', {\n path: params.path,\n coin: params.coin,\n showOnDevice: params.showOnDevice,\n }) as {\n xpub: string;\n publicKey: string;\n fingerprint: number;\n chainCode: string;\n path: string;\n depth: number;\n };\n\n return success({\n xpub: result.xpub,\n publicKey: result.publicKey ?? '',\n fingerprint: result.fingerprint ?? 0,\n chainCode: result.chainCode ?? '',\n path: params.path,\n depth: result.depth ?? 0,\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async btcSignTransaction(\n connectId: string,\n _deviceId: string,\n params: BtcSignTxParams,\n ): Promise<Response<BtcSignedTx>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n if (!params.psbt) {\n return failure(\n HardwareErrorCode.InvalidParams,\n 'Ledger requires PSBT format for BTC transaction signing. Provide params.psbt.',\n );\n }\n // TODO: Implement PSBT signing when the Ledger BTC signer kit supports it.\n return failure(\n HardwareErrorCode.MethodNotSupported,\n 'BTC transaction signing via PSBT is not yet implemented for Ledger.',\n );\n }\n\n async btcSignMessage(\n _connectId: string,\n _deviceId: string,\n _params: BtcSignMsgParams,\n ): Promise<Response<BtcSignature>> {\n return failure(\n HardwareErrorCode.MethodNotSupported,\n 'BTC message signing is not yet supported on Ledger.',\n );\n }\n\n // ---------------------------------------------------------------------------\n // Device fingerprint\n // ---------------------------------------------------------------------------\n\n async btcGetMasterFingerprint(\n connectId: string,\n _deviceId: string,\n params?: { skipOpenApp?: boolean },\n ): Promise<Response<{ masterFingerprint: string }>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'btcGetMasterFingerprint', {\n skipOpenApp: params?.skipOpenApp,\n }) as { masterFingerprint: string };\n\n return success({ masterFingerprint: result.masterFingerprint });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Solana methods (stubs -- not yet supported)\n // ---------------------------------------------------------------------------\n\n async solGetAddress(\n _connectId: string,\n _deviceId: string,\n _params: SolGetAddressParams,\n ): Promise<Response<SolAddress>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana not supported on Ledger yet');\n }\n\n async solGetAddresses(\n _connectId: string,\n _deviceId: string,\n _params: SolGetAddressParams[],\n _onProgress?: ProgressCallback,\n ): Promise<Response<SolAddress[]>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana not supported on Ledger yet');\n }\n\n async solGetPublicKey(\n _connectId: string,\n _deviceId: string,\n _params: SolGetPublicKeyParams,\n ): Promise<Response<SolPublicKey>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana not supported on Ledger yet');\n }\n\n async solSignTransaction(\n _connectId: string,\n _deviceId: string,\n _params: SolSignTxParams,\n ): Promise<Response<SolSignedTx>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana not supported on Ledger yet');\n }\n\n async solSignMessage(\n _connectId: string,\n _deviceId: string,\n _params: SolSignMsgParams,\n ): Promise<Response<SolSignature>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana signMessage is not supported on Ledger yet');\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Ensure at least one device is connected and return a valid connectId.\n *\n * - If a session already exists for the given connectId, reuse it.\n * - If ANY session exists (Ledger IDs are ephemeral), reuse it.\n * - Otherwise: search → 1 device: auto-connect, multiple: ask user, 0: throw.\n */\n private async ensureConnected(connectId?: string): Promise<string> {\n // 1. Exact match\n if (connectId && this._sessions.has(connectId)) {\n return connectId;\n }\n\n // 2. Any existing session (Ledger IDs are temporary, any session is fine)\n if (this._sessions.size > 0) {\n return this._sessions.keys().next().value!;\n }\n\n // 3. No session — search and connect\n const devices = await this.searchDevices();\n\n if (devices.length === 0) {\n throw Object.assign(\n new Error('No Ledger device found. Make sure the device is connected via USB and ready.'),\n { _tag: 'DeviceNotRecognizedError' },\n );\n }\n\n if (devices.length === 1) {\n const result = await this.connectDevice(devices[0].connectId);\n if (!result.success) {\n throw Object.assign(\n new Error(result.payload.error),\n { _tag: 'DeviceNotRecognizedError' },\n );\n }\n return devices[0].connectId;\n }\n\n // Multiple devices — ask user via UI handler\n if (this._uiHandler?.onSelectDevice) {\n const selectedConnectId = await this._uiHandler.onSelectDevice(devices);\n const result = await this.connectDevice(selectedConnectId);\n if (!result.success) {\n throw Object.assign(\n new Error(result.payload.error),\n { _tag: 'DeviceNotRecognizedError' },\n );\n }\n return selectedConnectId;\n }\n\n // No UI handler — fall back to first device\n const result = await this.connectDevice(devices[0].connectId);\n if (!result.success) {\n throw Object.assign(\n new Error(result.payload.error),\n { _tag: 'DeviceNotRecognizedError' },\n );\n }\n return devices[0].connectId;\n }\n\n /**\n * Call the connector with automatic session resolution and disconnect retry.\n *\n * 1. Resolves a valid connectId via ensureConnected()\n * 2. Looks up sessionId from _sessions\n * 3. Calls connector.call()\n * 4. On disconnect error: clears stale session, re-connects, retries once\n */\n private async connectorCall(\n connectId: string,\n method: string,\n params: unknown,\n ): Promise<unknown> {\n const resolvedConnectId = await this.ensureConnected(connectId);\n const sessionId = this._sessions.get(resolvedConnectId);\n if (!sessionId) {\n throw Object.assign(\n new Error('Auto-connect succeeded but no session found'),\n { _tag: 'DeviceSessionNotFound' },\n );\n }\n\n try {\n return await this.connector.call(sessionId, method, params);\n } catch (err) {\n if (isDeviceDisconnectedError(err)) {\n // Clear stale session and retry with fresh connection\n this._sessions.delete(resolvedConnectId);\n this._discoveredDevices.clear();\n const retryConnectId = await this.ensureConnected();\n const retrySessionId = this._sessions.get(retryConnectId);\n if (!retrySessionId) {\n throw err;\n }\n return this.connector.call(retrySessionId, method, params);\n }\n throw err;\n }\n }\n\n /**\n * Ensure device permission before proceeding.\n * - No connectId (searchDevices): check environment-level permission\n * - With connectId (business methods): check device-level permission\n * If not granted, calls onDevicePermission so the consumer can request access.\n */\n private async _ensureDevicePermission(connectId?: string, deviceId?: string): Promise<void> {\n const transportType: TransportType = 'hid';\n let granted = false;\n let context: Record<string, unknown> | undefined;\n\n if (this._uiHandler?.checkDevicePermission) {\n try {\n const result = await this._uiHandler.checkDevicePermission({ transportType, connectId, deviceId });\n granted = result.granted;\n context = result.context;\n } catch {\n granted = false;\n }\n }\n\n if (!granted) {\n try {\n await this._uiHandler?.onDevicePermission?.({ transportType, context });\n } catch {\n // UI handler cancelled or failed\n }\n }\n }\n\n /**\n * Convert a thrown error to a Response failure.\n * Uses mapLedgerError to parse Ledger DMK error codes into HardwareErrorCode values.\n */\n private errorToFailure<T>(err: unknown): Response<T> {\n console.error('[LedgerAdapter] error:', err);\n const mapped = mapLedgerError(err);\n\n // Emit a UI event for locked-device so callers can prompt the user\n if (mapped.code === HardwareErrorCode.DeviceLocked) {\n this.emitter.emit(UI_REQUEST.REQUEST_BUTTON, {\n type: UI_REQUEST.REQUEST_BUTTON,\n payload: {\n device: this.unknownDevice(),\n code: 'ButtonRequest_Other',\n },\n });\n }\n\n return failure(mapped.code, mapped.message);\n }\n\n /**\n * Generic batch call with progress reporting.\n * If any single call fails, returns the failure immediately.\n */\n private async batchCall<TParam, TResult>(\n params: TParam[],\n callFn: (p: TParam) => Promise<Response<TResult>>,\n onProgress?: ProgressCallback,\n ): Promise<Response<TResult[]>> {\n const results: TResult[] = [];\n for (let i = 0; i < params.length; i++) {\n const result = await callFn(params[i]);\n if (!result.success) {\n return result;\n }\n results.push(result.payload);\n onProgress?.({ index: i, total: params.length });\n }\n return success(results);\n }\n\n // ---------------------------------------------------------------------------\n // Event translation\n // ---------------------------------------------------------------------------\n\n private deviceConnectHandler = (data: { device: ConnectorDevice }): void => {\n const deviceInfo = this.connectorDeviceToDeviceInfo(data.device);\n this._discoveredDevices.set(deviceInfo.connectId, deviceInfo);\n this.emitter.emit(DEVICE.CONNECT, {\n type: DEVICE.CONNECT,\n payload: deviceInfo,\n });\n };\n\n private deviceDisconnectHandler = (data: { connectId: string }): void => {\n this._discoveredDevices.delete(data.connectId);\n this._sessions.delete(data.connectId);\n this.emitter.emit(DEVICE.DISCONNECT, {\n type: DEVICE.DISCONNECT,\n payload: { connectId: data.connectId },\n });\n };\n\n private uiRequestHandler = (data: { type: string; payload?: unknown }): void => {\n this.handleUiEvent(data);\n };\n\n private uiEventHandler = (data: { type: string; payload?: unknown }): void => {\n this.handleUiEvent(data);\n };\n\n private registerEventListeners(): void {\n this.connector.on('device-connect', this.deviceConnectHandler);\n this.connector.on('device-disconnect', this.deviceDisconnectHandler);\n this.connector.on('ui-request', this.uiRequestHandler);\n this.connector.on('ui-event', this.uiEventHandler);\n }\n\n private unregisterEventListeners(): void {\n this.connector.off('device-connect', this.deviceConnectHandler);\n this.connector.off('device-disconnect', this.deviceDisconnectHandler);\n this.connector.off('ui-request', this.uiRequestHandler);\n this.connector.off('ui-event', this.uiEventHandler);\n }\n\n private handleUiEvent(event: { type: string; payload?: unknown }): void {\n if (!event.type) return;\n\n const payload = event.payload as Record<string, unknown> | undefined;\n const deviceInfo = payload\n ? this.extractDeviceInfoFromPayload(payload)\n : this.unknownDevice();\n\n switch (event.type) {\n case 'ui-request_confirmation':\n this.emitter.emit(UI_REQUEST.REQUEST_BUTTON, {\n type: UI_REQUEST.REQUEST_BUTTON,\n payload: { device: deviceInfo },\n });\n break;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Device info mapping\n // ---------------------------------------------------------------------------\n\n private connectorDeviceToDeviceInfo(device: ConnectorDevice): DeviceInfo {\n return {\n vendor: 'ledger',\n model: device.model ?? 'unknown',\n firmwareVersion: '',\n deviceId: device.deviceId,\n connectId: device.connectId,\n label: device.name,\n connectionType: 'usb' as ConnectionType,\n capabilities: device.capabilities,\n };\n }\n\n private extractDeviceInfoFromPayload(payload: Record<string, unknown>): DeviceInfo {\n return {\n vendor: 'ledger',\n model: (payload['model'] as string) ?? 'unknown',\n firmwareVersion: '',\n deviceId: (payload['deviceId'] as string) ?? (payload['id'] as string) ?? '',\n connectId: (payload['connectId'] as string) ?? (payload['path'] as string) ?? '',\n label: (payload['label'] as string),\n connectionType: 'usb' as ConnectionType,\n };\n }\n\n private unknownDevice(): DeviceInfo {\n return {\n vendor: 'ledger',\n model: 'unknown',\n firmwareVersion: '',\n deviceId: '',\n connectId: '',\n connectionType: 'usb',\n };\n }\n}\n","import { HardwareErrorCode } from '@bytezhang/hardware-wallet-core';\n\n/**\n * DMK locked device status codes:\n * 0x5515 (21781) — primary locked response\n * 0x6982 (27010) — security status not satisfied\n * 0x5303 (21251) — tertiary locked response\n */\nconst LOCKED_ERROR_CODES = new Set(['5515', '21781', '6982', '27010', '5303', '21251']);\n\n/**\n * DMK user-rejected status codes:\n * 0x6985 (27013) — conditions of use not satisfied (user denied on device)\n */\nconst USER_REJECTED_CODES = new Set(['6985', '27013']);\n\n/**\n * DMK wrong-app / CLA-not-supported status codes:\n * 0x6e00 (28160) — CLA not supported (wrong app open)\n * 0x6d00 (27904) — INS not supported (wrong app or outdated app)\n */\nconst WRONG_APP_CODES = new Set(['6e00', '28160', '6d00', '27904']);\n\n/** Check if an error (or any error in its chain) represents a locked Ledger device. */\nexport function isDeviceLockedError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e.errorCode != null && LOCKED_ERROR_CODES.has(String(e.errorCode))) return true;\n if (e.statusCode != null && LOCKED_ERROR_CODES.has(String(e.statusCode))) return true;\n if (e._tag === 'DeviceLockedError') return true;\n if (typeof e.message === 'string' && /locked/i.test(e.message)) return true;\n if (e.originalError != null && isDeviceLockedError(e.originalError)) return true;\n if (e.error != null && e._tag && isDeviceLockedError(e.error)) return true;\n return false;\n}\n\n/** Check if a status/error code exists in the given set, crawling the error chain. */\nfunction hasStatusCode(err: unknown, codeSet: Set<string>): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e.errorCode != null && codeSet.has(String(e.errorCode))) return true;\n if (e.statusCode != null && codeSet.has(String(e.statusCode))) return true;\n if (e.originalError != null && hasStatusCode(e.originalError, codeSet)) return true;\n if (e.error != null && e._tag && hasStatusCode(e.error, codeSet)) return true;\n return false;\n}\n\n/** Check for user rejection (denied on device). */\nexport function isUserRejectedError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e._tag === 'UserRefusedOnDevice') return true;\n if (typeof e.message === 'string' && /denied|rejected|refused/i.test(e.message)) return true;\n if (hasStatusCode(err, USER_REJECTED_CODES)) return true;\n return false;\n}\n\n/** Check for wrong app open on the device. */\nexport function isWrongAppError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e._tag === 'WrongAppOpenedError' || e._tag === 'InvalidStatusWordError') {\n if (hasStatusCode(err, WRONG_APP_CODES)) return true;\n }\n if (typeof e.message === 'string' && /wrong app|open the .* app|CLA not supported/i.test(e.message)) return true;\n if (hasStatusCode(err, WRONG_APP_CODES)) return true;\n return false;\n}\n\n/** Check for device disconnected errors. */\nexport function isDeviceDisconnectedError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e._tag === 'DeviceNotRecognizedError' || e._tag === 'DeviceSessionNotFound') return true;\n if (typeof e.message === 'string' && /disconnected|not found|no device|unplugged|session.*not.*found/i.test(e.message)) return true;\n return false;\n}\n\n/** Check for timeout errors. */\nexport function isTimeoutError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (typeof e.message === 'string' && /timeout|timed?\\s*out/i.test(e.message)) return true;\n if (e._tag === 'DeviceExchangeTimeoutError') return true;\n return false;\n}\n\n/**\n * Map a Ledger DMK error to a HardwareErrorCode and human-readable message\n * with actionable recovery information for the caller.\n */\nexport function mapLedgerError(err: unknown): { code: HardwareErrorCode; message: string } {\n // Order matters: check more specific errors first\n\n if (isDeviceLockedError(err)) {\n return {\n code: HardwareErrorCode.DeviceLocked,\n message: 'Device is locked. Please unlock your Ledger device and try again.',\n };\n }\n\n if (isUserRejectedError(err)) {\n return {\n code: HardwareErrorCode.UserRejected,\n message: 'User rejected the request on the device.',\n };\n }\n\n if (isWrongAppError(err)) {\n return {\n code: HardwareErrorCode.WrongApp,\n message: 'Wrong app is open on the Ledger device. Please open the correct app (e.g. Ethereum) and try again.',\n };\n }\n\n if (isDeviceDisconnectedError(err)) {\n return {\n code: HardwareErrorCode.DeviceDisconnected,\n message: 'Ledger device was disconnected. Please reconnect the device and try again.',\n };\n }\n\n if (isTimeoutError(err)) {\n return {\n code: HardwareErrorCode.OperationTimeout,\n message: 'Operation timed out. Please ensure the Ledger device is connected and responsive.',\n };\n }\n\n // Fallback: extract whatever message we can\n let message = 'Unknown Ledger error';\n if (err instanceof Error) {\n message = err.message;\n } else if (err && typeof err === 'object') {\n const e = err as Record<string, unknown>;\n message = String(e.message ?? e._tag ?? e.type ?? JSON.stringify(err));\n }\n return { code: HardwareErrorCode.UnknownError, message };\n}\n","import type { DeviceDescriptor, DeviceChangeEvent } from '@bytezhang/hardware-wallet-core';\nimport type { IDmk, DmkDiscoveredDevice } from '../types';\n\n/**\n * Manages device discovery, connection, and session tracking.\n * Wraps DMK's Observable APIs into simpler imperative calls.\n */\nexport class LedgerDeviceManager {\n private readonly _dmk: IDmk;\n private readonly _discovered = new Map<string, DmkDiscoveredDevice>();\n private readonly _sessions = new Map<string, string>(); // deviceId → sessionId\n private readonly _sessionToDevice = new Map<string, string>(); // sessionId → deviceId\n private _listenSub: { unsubscribe: () => void } | null = null;\n\n constructor(dmk: IDmk) {\n this._dmk = dmk;\n }\n\n /**\n * One-shot enumeration: subscribe to listenToAvailableDevices,\n * take the first emission, unsubscribe, return DeviceDescriptors.\n */\n enumerate(): Promise<DeviceDescriptor[]> {\n return new Promise<DeviceDescriptor[]>((resolve) => {\n let resolved = false;\n let sub: { unsubscribe: () => void } | null = null;\n\n sub = this._dmk.listenToAvailableDevices().subscribe({\n next: (devices) => {\n if (resolved) return;\n resolved = true;\n this._discovered.clear();\n for (const d of devices) {\n this._discovered.set(d.id, d);\n }\n if (sub) {\n sub.unsubscribe();\n } else {\n // BehaviorSubject fires synchronously before subscribe() returns\n Promise.resolve().then(() => sub?.unsubscribe());\n }\n console.log('[LedgerDeviceManager] enumerate devices:', JSON.stringify(devices.map(d => ({\n id: d.id,\n deviceModel: d.deviceModel,\n name: (d as any).name,\n }))));\n resolve(devices.map(d => ({ path: d.id, type: d.deviceModel.name })));\n },\n error: () => {\n if (resolved) return;\n resolved = true;\n sub?.unsubscribe();\n resolve([]);\n },\n });\n });\n }\n\n /**\n * Continuous listening: tracks device connect/disconnect via diffing.\n */\n listen(onChange: (event: DeviceChangeEvent) => void): void {\n this.stopListening();\n let previousIds = new Set<string>();\n\n this._listenSub = this._dmk.listenToAvailableDevices().subscribe({\n next: (devices) => {\n const currentIds = new Set(devices.map(d => d.id));\n\n for (const d of devices) {\n this._discovered.set(d.id, d);\n console.log('[LedgerDeviceManager] listen device:', JSON.stringify({\n id: d.id,\n deviceModel: d.deviceModel,\n name: (d as any).name,\n }));\n if (!previousIds.has(d.id)) {\n onChange({ type: 'device-connected', descriptor: { path: d.id, type: d.deviceModel.name } });\n }\n }\n for (const id of previousIds) {\n if (!currentIds.has(id)) {\n this._discovered.delete(id);\n onChange({ type: 'device-disconnected', descriptor: { path: id } });\n }\n }\n previousIds = currentIds;\n },\n });\n }\n\n stopListening(): void {\n this._listenSub?.unsubscribe();\n this._listenSub = null;\n }\n\n /**\n * Trigger browser device selection (WebHID requestDevice).\n * Starts discovery for a short period, then stops.\n */\n requestDevice(timeoutMs = 3000): Promise<void> {\n return new Promise<void>((resolve) => {\n const sub = this._dmk.startDiscovering().subscribe({\n next: (d) => { this._discovered.set(d.id, d); },\n error: () => { sub.unsubscribe(); resolve(); },\n });\n setTimeout(() => {\n sub.unsubscribe();\n this._dmk.stopDiscovering();\n resolve();\n }, timeoutMs);\n });\n }\n\n /** Connect to a previously discovered device. Returns sessionId. */\n async connect(deviceId: string): Promise<string> {\n const device = this._discovered.get(deviceId);\n if (!device) {\n throw new Error(`Device \"${deviceId}\" not found. Call enumerate() or listen() first.`);\n }\n const sessionId = await this._dmk.connect({ device });\n this._sessions.set(deviceId, sessionId);\n this._sessionToDevice.set(sessionId, deviceId);\n return sessionId;\n }\n\n /** Disconnect a session. */\n async disconnect(sessionId: string): Promise<void> {\n await this._dmk.disconnect({ sessionId });\n const deviceId = this._sessionToDevice.get(sessionId);\n if (deviceId) this._sessions.delete(deviceId);\n this._sessionToDevice.delete(sessionId);\n }\n\n getSessionId(deviceId: string): string | undefined {\n return this._sessions.get(deviceId);\n }\n\n getDeviceId(sessionId: string): string | undefined {\n return this._sessionToDevice.get(sessionId);\n }\n\n /** Get the underlying DMK instance (needed by SignerManager). */\n getDmk(): IDmk {\n return this._dmk;\n }\n\n dispose(): void {\n this.stopListening();\n this._discovered.clear();\n this._sessions.clear();\n this._sessionToDevice.clear();\n this._dmk.close?.();\n }\n}\n","/** DeviceAction state emitted by DMK signer operations. */\ninterface DeviceActionState<T> {\n status: 'pending' | 'completed' | 'error';\n output?: T;\n error?: unknown;\n intermediateValue?: {\n requiredUserInteraction?: string;\n [key: string]: unknown;\n };\n}\n\n/**\n * Convert a DMK DeviceAction (Observable-based) into a Promise.\n * Handles pending → completed/error state transitions and interaction callbacks.\n */\nexport function deviceActionToPromise<T>(\n action: {\n observable: {\n subscribe(observer: {\n next: (value: DeviceActionState<T>) => void;\n error?: (err: unknown) => void;\n complete?: () => void;\n }): { unsubscribe: () => void };\n };\n },\n onInteraction?: (interaction: string) => void,\n): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n let settled = false;\n let sub: { unsubscribe: () => void };\n\n sub = action.observable.subscribe({\n next: (state) => {\n if (settled) return;\n if (state.status === 'completed') {\n settled = true;\n sub?.unsubscribe();\n resolve(state.output as T);\n } else if (state.status === 'error') {\n settled = true;\n sub?.unsubscribe();\n reject(state.error);\n } else if (state.status === 'pending' && onInteraction) {\n const interaction = state.intermediateValue?.requiredUserInteraction;\n if (interaction && interaction !== 'none') {\n onInteraction(interaction);\n }\n }\n },\n error: (err: unknown) => {\n if (!settled) {\n settled = true;\n sub?.unsubscribe();\n reject(err);\n }\n },\n complete: () => {\n if (!settled) {\n settled = true;\n reject(new Error('Device action completed without result'));\n }\n },\n });\n });\n}\n","import type { SignerEvmAddress, SignerEvmSignature } from '../types';\nimport { deviceActionToPromise } from './deviceActionToPromise';\n\n/**\n * SDK signer interface — duck-typed to avoid hard dependency on\n * @ledgerhq/device-signer-kit-ethereum.\n */\nexport interface ISdkSignerEth {\n getAddress(derivationPath: string, options?: { checkOnDevice?: boolean }): unknown;\n signTransaction(derivationPath: string, transaction: Uint8Array, options?: unknown): unknown;\n signMessage(derivationPath: string, message: string): unknown;\n signTypedData(derivationPath: string, data: unknown): unknown;\n}\n\n/** Convert hex string (with or without 0x) to Uint8Array. */\nfunction hexToBytes(hex: string): Uint8Array {\n const h = hex.startsWith('0x') ? hex.slice(2) : hex;\n const bytes = new Uint8Array(h.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(h.substring(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\n/**\n * Wraps Ledger's SDK signer (Observable-based DeviceActions) into\n * a simple async interface returning plain serializable data.\n */\nexport class SignerEth {\n onInteraction?: (interaction: string) => void;\n\n constructor(private readonly _sdk: ISdkSignerEth) {}\n\n async getAddress(\n derivationPath: string,\n options?: { checkOnDevice?: boolean }\n ): Promise<SignerEvmAddress> {\n const action = this._sdk.getAddress(derivationPath, {\n checkOnDevice: options?.checkOnDevice ?? false,\n });\n return deviceActionToPromise<SignerEvmAddress>(action as any, this.onInteraction);\n }\n\n async signTransaction(\n derivationPath: string,\n serializedTxHex: string\n ): Promise<SignerEvmSignature> {\n const action = this._sdk.signTransaction(derivationPath, hexToBytes(serializedTxHex));\n return deviceActionToPromise<SignerEvmSignature>(action as any, this.onInteraction);\n }\n\n async signMessage(derivationPath: string, message: string): Promise<SignerEvmSignature> {\n const action = this._sdk.signMessage(derivationPath, message);\n return deviceActionToPromise<SignerEvmSignature>(action as any, this.onInteraction);\n }\n\n async signTypedData(derivationPath: string, data: unknown): Promise<SignerEvmSignature> {\n const action = this._sdk.signTypedData(derivationPath, data);\n return deviceActionToPromise<SignerEvmSignature>(action as any, this.onInteraction);\n }\n}\n","import type { IDmk } from '../types';\nimport { SignerEth } from './SignerEth';\n\ntype SignerEthBuilderFn = (args: { dmk: IDmk; sessionId: string }) => { build(): unknown } | Promise<{ build(): unknown }>;\n\n/**\n * Manages per-sessionId SignerEth instances.\n * Creates on demand, caches for reuse, invalidates on session change.\n */\nexport class SignerManager {\n private readonly _cache = new Map<string, SignerEth>();\n private readonly _dmk: IDmk;\n private readonly _builderFn: SignerEthBuilderFn;\n\n constructor(dmk: IDmk, builderFn?: SignerEthBuilderFn) {\n this._dmk = dmk;\n this._builderFn = builderFn ?? SignerManager._defaultBuilder();\n }\n\n async getOrCreate(sessionId: string): Promise<SignerEth> {\n let signer = this._cache.get(sessionId);\n if (signer) return signer;\n\n const builder = await this._builderFn({ dmk: this._dmk, sessionId });\n const sdkSigner = builder.build();\n signer = new SignerEth(sdkSigner as any);\n this._cache.set(sessionId, signer);\n return signer;\n }\n\n invalidate(sessionId: string): void {\n this._cache.delete(sessionId);\n }\n\n clearAll(): void {\n this._cache.clear();\n }\n\n private static _defaultBuilder(): SignerEthBuilderFn {\n let BuilderClass: any = null;\n return async (args) => {\n if (!BuilderClass) {\n const mod = await import('@ledgerhq/device-signer-kit-ethereum');\n BuilderClass = mod.SignerEthBuilder;\n }\n return new BuilderClass(args);\n };\n }\n}\n","import type { SignerBtcAddress } from '../types';\nimport { deviceActionToPromise } from './deviceActionToPromise';\n\n/**\n * SDK BTC signer interface — duck-typed to avoid hard dependency on\n * @ledgerhq/device-signer-kit-bitcoin.\n */\nexport interface ISdkSignerBtc {\n getExtendedPublicKey(derivationPath: string, options?: { checkOnDevice?: boolean }): unknown;\n getWalletAddress(wallet: unknown, addressIndex: number, options?: { checkOnDevice?: boolean; change?: boolean }): unknown;\n getMasterFingerprint(options?: { skipOpenApp?: boolean }): unknown;\n}\n\n/**\n * Wraps Ledger's BTC SDK signer (Observable-based DeviceActions) into\n * a simple async interface returning plain serializable data.\n */\nexport class SignerBtc {\n onInteraction?: (interaction: string) => void;\n\n constructor(private readonly _sdk: ISdkSignerBtc) {}\n\n async getWalletAddress(\n wallet: unknown,\n addressIndex: number,\n options?: { checkOnDevice?: boolean; change?: boolean },\n ): Promise<SignerBtcAddress> {\n const action = this._sdk.getWalletAddress(wallet, addressIndex, {\n checkOnDevice: options?.checkOnDevice ?? false,\n change: options?.change ?? false,\n });\n return deviceActionToPromise<SignerBtcAddress>(action as any, this.onInteraction);\n }\n\n async getExtendedPublicKey(\n derivationPath: string,\n options?: { checkOnDevice?: boolean },\n ): Promise<string> {\n const action = this._sdk.getExtendedPublicKey(derivationPath, {\n checkOnDevice: options?.checkOnDevice ?? false,\n });\n return deviceActionToPromise<string>(action as any, this.onInteraction);\n }\n\n async getMasterFingerprint(\n options?: { skipOpenApp?: boolean },\n ): Promise<Uint8Array> {\n const action = this._sdk.getMasterFingerprint(options);\n const result = await deviceActionToPromise<{ masterFingerprint: Uint8Array }>(action as any, this.onInteraction);\n return result.masterFingerprint;\n }\n}\n","import type { TransportProvider } from '../types';\n\nconst registry = new Map<string, TransportProvider>();\n\nfunction normalizeType(type: string): string {\n return type.trim().toLowerCase();\n}\n\nexport function registerTransport(type: string, provider: TransportProvider): void {\n const key = normalizeType(type);\n if (!key) throw new Error('Transport type must be a non-empty string');\n registry.set(key, provider);\n}\n\nexport function unregisterTransport(type: string): void {\n registry.delete(normalizeType(type));\n}\n\nexport function getTransportProvider(type: string): TransportProvider | null {\n return registry.get(normalizeType(type)) ?? null;\n}\n\nexport function listRegisteredTransports(): string[] {\n return Array.from(registry.keys());\n}\n\nexport function clearRegistry(): void {\n registry.clear();\n}\n","import type { IDmk } from '../types';\n\n/**\n * Map of chain ticker symbols to the Ledger app name\n * that must be open to sign transactions for that chain.\n */\nexport const APP_NAME_MAP: Record<string, string> = {\n ETH: 'Ethereum',\n BTC: 'Bitcoin',\n SOL: 'Solana',\n TRX: 'Tron',\n XRP: 'XRP',\n ADA: 'Cardano',\n DOT: 'Polkadot',\n ATOM: 'Cosmos',\n};\n\n/** The name reported by the Ledger when it sits on the home screen. */\nconst DASHBOARD_APP_NAME = 'BOLOS';\n\ninterface AppManagerOptions {\n waitMs?: number;\n maxRetries?: number;\n}\n\n/**\n * Orchestrates opening / closing Ledger on-device apps so that the\n * correct signer application is running before any signing call.\n */\nexport class AppManager {\n private readonly _dmk: IDmk;\n private readonly _waitMs: number;\n private readonly _maxRetries: number;\n\n constructor(dmk: IDmk, options?: AppManagerOptions) {\n this._dmk = dmk;\n this._waitMs = options?.waitMs ?? 1000;\n this._maxRetries = options?.maxRetries ?? 10;\n }\n\n /**\n * Return the Ledger app name for a given chain ticker,\n * or undefined if the chain is not supported.\n */\n static getAppName(chain: string): string | undefined {\n return APP_NAME_MAP[chain];\n }\n\n /**\n * Ensure the target app is open on the device identified by `sessionId`.\n *\n * Flow:\n * 1. Check the currently running app.\n * 2. If it is already the target, return immediately.\n * 3. If a different app is running (not dashboard), close it first.\n * 4. Open the target app.\n * 5. Poll until the device confirms the target app is running.\n */\n async ensureAppOpen(sessionId: string, targetAppName: string): Promise<void> {\n const currentApp = await this._getCurrentApp(sessionId);\n\n if (currentApp === targetAppName) {\n return;\n }\n\n // If we're not on the dashboard, close the current app first\n if (!this._isDashboard(currentApp)) {\n await this._closeCurrentApp(sessionId);\n // Wait for dashboard to become active\n await this._waitForApp(sessionId, DASHBOARD_APP_NAME);\n }\n\n // Open the target app\n await this._openApp(sessionId, targetAppName);\n\n // Poll until the target app is confirmed open\n await this._waitForApp(sessionId, targetAppName);\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private async _getCurrentApp(sessionId: string): Promise<string> {\n const result = (await this._dmk.sendCommand({\n sessionId,\n command: { type: 'get-app-and-version' },\n })) as { name: string };\n return result.name;\n }\n\n private async _openApp(sessionId: string, appName: string): Promise<void> {\n await this._dmk.sendCommand({\n sessionId,\n command: { type: 'open-app', appName },\n });\n }\n\n private async _closeCurrentApp(sessionId: string): Promise<void> {\n await this._dmk.sendCommand({\n sessionId,\n command: { type: 'close-app' },\n });\n }\n\n /**\n * Poll the device until the expected app is reported as running,\n * or throw after `_maxRetries` attempts.\n */\n private async _waitForApp(sessionId: string, expectedAppName: string): Promise<void> {\n for (let i = 0; i < this._maxRetries; i++) {\n await this._wait();\n const current = await this._getCurrentApp(sessionId);\n if (current === expectedAppName) {\n return;\n }\n }\n throw new Error(\n `Ledger: failed to open \"${expectedAppName}\" after ${this._maxRetries} retries`\n );\n }\n\n private _isDashboard(appName: string): boolean {\n return appName === DASHBOARD_APP_NAME;\n }\n\n private _wait(): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, this._waitMs));\n }\n}\n"],"mappings":"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","names":["import_hardware_wallet_core","result"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/adapter/LedgerAdapter.ts","../src/errors.ts","../src/device/LedgerDeviceManager.ts","../src/signer/deviceActionToPromise.ts","../src/signer/SignerEth.ts","../src/signer/SignerManager.ts","../src/signer/SignerBtc.ts","../src/transport/registry.ts","../src/app/AppManager.ts"],"sourcesContent":["// Adapter\nexport { LedgerAdapter } from './adapter/LedgerAdapter';\n\n// Device management (used by connectors)\nexport { LedgerDeviceManager } from './device/LedgerDeviceManager';\n\n// Signer (used by connectors)\nexport { SignerManager } from './signer/SignerManager';\nexport { SignerEth } from './signer/SignerEth';\nexport { SignerBtc } from './signer/SignerBtc';\nexport { deviceActionToPromise } from './signer/deviceActionToPromise';\n\n// Transport registry\nexport { registerTransport, unregisterTransport, getTransportProvider, listRegisteredTransports, clearRegistry } from './transport/registry';\n\n// App management\nexport { AppManager } from './app/AppManager';\n\n// Types\nexport type { IDmk, DmkDiscoveredDevice, DeviceActionState, SignerEvmAddress, SignerEvmSignature, SignerBtcAddress, TransportProvider, TransportProviderInstance, TransportProviderOptions } from './types';\n\n// Errors\nexport { isDeviceLockedError, mapLedgerError } from './errors';\n","import type {\n IHardwareWallet,\n IUiHandler,\n IConnector,\n ConnectorDevice,\n DeviceInfo,\n HardwareEventMap,\n DeviceEventListener,\n TransportType,\n ConnectionType,\n Response,\n EvmGetAddressParams,\n EvmAddress,\n EvmGetPublicKeyParams,\n EvmPublicKey,\n EvmSignTxParams,\n EvmSignedTx,\n EvmSignMsgParams,\n EvmSignTypedDataParams,\n EvmSignature,\n ProgressCallback,\n BtcGetAddressParams,\n BtcAddress,\n BtcGetPublicKeyParams,\n BtcPublicKey,\n BtcSignTxParams,\n BtcSignedTx,\n BtcSignMsgParams,\n BtcSignature,\n SolGetAddressParams,\n SolAddress,\n SolGetPublicKeyParams,\n SolPublicKey,\n SolSignTxParams,\n SolSignedTx,\n SolSignMsgParams,\n SolSignature,\n ChainCapability,\n} from '@bytezhang/hardware-wallet-core';\nimport {\n success,\n failure,\n HardwareErrorCode,\n TypedEventEmitter,\n DEVICE,\n UI_REQUEST,\n} from '@bytezhang/hardware-wallet-core';\nimport { mapLedgerError, isDeviceDisconnectedError } from '../errors';\n\n/** Ensure a hex string has the `0x` prefix. */\nfunction ensure0x(hex: string): string {\n return hex.startsWith('0x') ? hex : `0x${hex}`;\n}\n\n/** Remove `0x` prefix from a hex string if present. */\nfunction stripHex(hex: string): string {\n return hex.startsWith('0x') ? hex.slice(2) : hex;\n}\n\n/** Ensure a hex string is `0x`-prefixed and zero-padded to 64 hex chars (32 bytes). */\nfunction padHex64(hex: string): string {\n return `0x${stripHex(hex).padStart(64, '0')}`;\n}\n\n/**\n * Ledger hardware wallet adapter that delegates to an IConnector.\n *\n * This is a thin translation layer that:\n * - Accepts a pre-configured IConnector (transport decisions are made at connector creation time)\n * - Translates IHardwareWallet method calls to connector.call() invocations\n * - Maps connector results/errors to our Response<T> format with enriched error messages\n * - Translates connector events to HardwareEventMap events\n * - Integrates with IUiHandler for permission flows\n */\nexport class LedgerAdapter implements IHardwareWallet {\n readonly vendor = 'ledger' as const;\n\n private readonly connector: IConnector;\n private readonly emitter = new TypedEventEmitter<HardwareEventMap>();\n\n private _uiHandler: Partial<IUiHandler> | null = null;\n\n // Device cache: tracks discovered devices from connector events\n private _discoveredDevices = new Map<string, DeviceInfo>();\n\n // Session tracking: maps connectId -> sessionId\n private _sessions = new Map<string, string>();\n\n constructor(connector: IConnector) {\n this.connector = connector;\n this.registerEventListeners();\n }\n\n // ---------------------------------------------------------------------------\n // Transport\n // ---------------------------------------------------------------------------\n // Transport is decided at connector creation time. These methods\n // satisfy the IHardwareWallet interface with sensible defaults.\n\n get activeTransport(): TransportType | null {\n return 'hid';\n }\n\n getAvailableTransports(): TransportType[] {\n return ['hid'];\n }\n\n async switchTransport(_type: TransportType): Promise<void> {\n // Transport is fixed at connector creation time.\n // To switch transport, create a new LedgerAdapter with a different connector.\n }\n\n // ---------------------------------------------------------------------------\n // UI handler\n // ---------------------------------------------------------------------------\n\n setUiHandler(handler: Partial<IUiHandler>): void {\n this._uiHandler = handler;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n async init(_config?: unknown): Promise<void> {\n // Connector is injected via constructor, already initialized.\n // Nothing to do here.\n }\n\n async dispose(): Promise<void> {\n this.unregisterEventListeners();\n this.connector.reset();\n this._uiHandler = null;\n this._discoveredDevices.clear();\n this._sessions.clear();\n this.emitter.removeAllListeners();\n }\n\n // ---------------------------------------------------------------------------\n // Device management\n // ---------------------------------------------------------------------------\n\n async searchDevices(): Promise<DeviceInfo[]> {\n await this._ensureDevicePermission();\n\n const devices = await this.connector.searchDevices();\n console.log('[LedgerAdapter] connector.searchDevices raw:', JSON.stringify(devices));\n\n for (const d of devices) {\n if (d.connectId && !this._discoveredDevices.has(d.connectId)) {\n this._discoveredDevices.set(d.connectId, this.connectorDeviceToDeviceInfo(d));\n }\n }\n\n // If no devices found, ensure permission (no connectId = search context)\n if (this._discoveredDevices.size === 0) {\n await this._ensureDevicePermission();\n }\n\n return Array.from(this._discoveredDevices.values());\n }\n\n async connectDevice(connectId: string): Promise<Response<string>> {\n await this._ensureDevicePermission(connectId);\n try {\n const session = await this.connector.connect(connectId);\n this._sessions.set(connectId, session.sessionId);\n\n // Update device cache with richer info from session\n if (session.deviceInfo) {\n this._discoveredDevices.set(connectId, session.deviceInfo);\n }\n\n return success(connectId);\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async disconnectDevice(connectId: string): Promise<void> {\n const sessionId = this._sessions.get(connectId);\n if (sessionId) {\n await this.connector.disconnect(sessionId);\n this._sessions.delete(connectId);\n }\n }\n\n async getDeviceInfo(\n connectId: string,\n deviceId: string,\n ): Promise<Response<DeviceInfo>> {\n await this._ensureDevicePermission(connectId, deviceId);\n\n // Look up the device in the cache populated by event handlers / searchDevices.\n // Try connectId first (the USB path), then fall back to scanning by deviceId.\n const cached =\n this._discoveredDevices.get(connectId) ??\n Array.from(this._discoveredDevices.values()).find(\n (d) => d.deviceId === deviceId,\n );\n\n if (cached) {\n return success(cached);\n }\n\n return failure(\n HardwareErrorCode.DeviceNotFound,\n 'Device not found in cache. Call searchDevices() or wait for a device-connected event first.',\n );\n }\n\n getSupportedChains(): ChainCapability[] {\n return ['evm', 'btc', 'sol'];\n }\n\n // ---------------------------------------------------------------------------\n // Events\n // ---------------------------------------------------------------------------\n\n on<K extends keyof HardwareEventMap>(event: K, listener: (event: HardwareEventMap[K]) => void): void;\n on(event: string, listener: DeviceEventListener): void;\n on(event: string, listener: (event: any) => void): void {\n this.emitter.on(event, listener);\n }\n\n off<K extends keyof HardwareEventMap>(event: K, listener: (event: HardwareEventMap[K]) => void): void;\n off(event: string, listener: DeviceEventListener): void;\n off(event: string, listener: (event: any) => void): void {\n this.emitter.off(event, listener);\n }\n\n cancel(connectId: string): void {\n const sessionId = this._sessions.get(connectId) ?? connectId;\n void this.connector.cancel(sessionId);\n }\n\n // ---------------------------------------------------------------------------\n // EVM methods\n // ---------------------------------------------------------------------------\n\n async evmGetAddress(\n connectId: string,\n _deviceId: string,\n params: EvmGetAddressParams,\n ): Promise<Response<EvmAddress>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'evmGetAddress', {\n path: params.path,\n showOnDevice: params.showOnDevice,\n chainId: params.chainId,\n }) as { address: string; publicKey?: string; path?: string };\n\n return success({\n address: result.address,\n path: params.path,\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async evmGetAddresses(\n connectId: string,\n deviceId: string,\n params: EvmGetAddressParams[],\n onProgress?: ProgressCallback,\n ): Promise<Response<EvmAddress[]>> {\n return this.batchCall(\n params,\n (p) => this.evmGetAddress(connectId, deviceId, p),\n onProgress,\n );\n }\n\n async evmGetPublicKey(\n connectId: string,\n _deviceId: string,\n params: EvmGetPublicKeyParams,\n ): Promise<Response<EvmPublicKey>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'evmGetAddress', {\n path: params.path,\n showOnDevice: params.showOnDevice,\n }) as { address: string; publicKey: string; path?: string };\n\n return success({\n publicKey: result.publicKey,\n path: params.path,\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async evmSignTransaction(\n connectId: string,\n _deviceId: string,\n params: EvmSignTxParams,\n ): Promise<Response<EvmSignedTx>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'evmSignTransaction', {\n path: params.path,\n transaction: {\n to: params.to,\n value: params.value,\n chainId: params.chainId,\n nonce: params.nonce,\n gasLimit: params.gasLimit,\n gasPrice: params.gasPrice,\n maxFeePerGas: params.maxFeePerGas,\n maxPriorityFeePerGas: params.maxPriorityFeePerGas,\n accessList: params.accessList,\n data: params.data,\n },\n }) as { v: string; r: string; s: string; serializedTx?: string };\n\n return success({\n v: ensure0x(result.v),\n r: padHex64(result.r),\n s: padHex64(result.s),\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async evmSignMessage(\n connectId: string,\n _deviceId: string,\n params: EvmSignMsgParams,\n ): Promise<Response<EvmSignature>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'evmSignMessage', {\n path: params.path,\n message: params.message,\n }) as { signature: string; address?: string };\n\n return success({\n signature: ensure0x(result.signature),\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async evmSignTypedData(\n connectId: string,\n _deviceId: string,\n params: EvmSignTypedDataParams,\n ): Promise<Response<EvmSignature>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n // Ledger requires full EIP-712 structure — hash mode is not supported.\n if (params.mode === 'hash') {\n return failure(\n HardwareErrorCode.MethodNotSupported,\n 'Ledger does not support hash-only EIP-712 signing. Use mode \"full\" with the complete typed data structure.',\n );\n }\n\n try {\n const result = await this.connectorCall(connectId, 'evmSignTypedData', {\n path: params.path,\n data: params.data,\n }) as { signature: string; address?: string };\n\n return success({\n signature: ensure0x(result.signature),\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n // ---------------------------------------------------------------------------\n // BTC methods\n // ---------------------------------------------------------------------------\n\n async btcGetAddress(\n connectId: string,\n _deviceId: string,\n params: BtcGetAddressParams,\n ): Promise<Response<BtcAddress>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'btcGetAddress', {\n path: params.path,\n coin: params.coin,\n showOnDevice: params.showOnDevice,\n scriptType: params.scriptType,\n }) as { address: string; path: string };\n\n return success({\n address: result.address,\n path: params.path,\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async btcGetAddresses(\n connectId: string,\n deviceId: string,\n params: BtcGetAddressParams[],\n onProgress?: ProgressCallback,\n ): Promise<Response<BtcAddress[]>> {\n return this.batchCall(\n params,\n (p) => this.btcGetAddress(connectId, deviceId, p),\n onProgress,\n );\n }\n\n async btcGetPublicKey(\n connectId: string,\n _deviceId: string,\n params: BtcGetPublicKeyParams,\n ): Promise<Response<BtcPublicKey>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'btcGetPublicKey', {\n path: params.path,\n coin: params.coin,\n showOnDevice: params.showOnDevice,\n }) as {\n xpub: string;\n publicKey: string;\n fingerprint: number;\n chainCode: string;\n path: string;\n depth: number;\n };\n\n return success({\n xpub: result.xpub,\n publicKey: result.publicKey ?? '',\n fingerprint: result.fingerprint ?? 0,\n chainCode: result.chainCode ?? '',\n path: params.path,\n depth: result.depth ?? 0,\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async btcSignTransaction(\n connectId: string,\n _deviceId: string,\n params: BtcSignTxParams,\n ): Promise<Response<BtcSignedTx>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n if (!params.psbt) {\n return failure(\n HardwareErrorCode.InvalidParams,\n 'Ledger requires PSBT format for BTC transaction signing. Provide params.psbt.',\n );\n }\n // TODO: Implement PSBT signing when the Ledger BTC signer kit supports it.\n return failure(\n HardwareErrorCode.MethodNotSupported,\n 'BTC transaction signing via PSBT is not yet implemented for Ledger.',\n );\n }\n\n async btcSignMessage(\n _connectId: string,\n _deviceId: string,\n _params: BtcSignMsgParams,\n ): Promise<Response<BtcSignature>> {\n return failure(\n HardwareErrorCode.MethodNotSupported,\n 'BTC message signing is not yet supported on Ledger.',\n );\n }\n\n // ---------------------------------------------------------------------------\n // Device fingerprint\n // ---------------------------------------------------------------------------\n\n async btcGetMasterFingerprint(\n connectId: string,\n _deviceId: string,\n params?: { skipOpenApp?: boolean },\n ): Promise<Response<{ masterFingerprint: string }>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'btcGetMasterFingerprint', {\n skipOpenApp: params?.skipOpenApp,\n }) as { masterFingerprint: string };\n\n return success({ masterFingerprint: result.masterFingerprint });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Solana methods (stubs -- not yet supported)\n // ---------------------------------------------------------------------------\n\n async solGetAddress(\n _connectId: string,\n _deviceId: string,\n _params: SolGetAddressParams,\n ): Promise<Response<SolAddress>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana not supported on Ledger yet');\n }\n\n async solGetAddresses(\n _connectId: string,\n _deviceId: string,\n _params: SolGetAddressParams[],\n _onProgress?: ProgressCallback,\n ): Promise<Response<SolAddress[]>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana not supported on Ledger yet');\n }\n\n async solGetPublicKey(\n _connectId: string,\n _deviceId: string,\n _params: SolGetPublicKeyParams,\n ): Promise<Response<SolPublicKey>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana not supported on Ledger yet');\n }\n\n async solSignTransaction(\n _connectId: string,\n _deviceId: string,\n _params: SolSignTxParams,\n ): Promise<Response<SolSignedTx>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana not supported on Ledger yet');\n }\n\n async solSignMessage(\n _connectId: string,\n _deviceId: string,\n _params: SolSignMsgParams,\n ): Promise<Response<SolSignature>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana signMessage is not supported on Ledger yet');\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Ensure at least one device is connected and return a valid connectId.\n *\n * - If a session already exists for the given connectId, reuse it.\n * - If ANY session exists (Ledger IDs are ephemeral), reuse it.\n * - Otherwise: search → 1 device: auto-connect, multiple: ask user, 0: throw.\n */\n private static readonly MAX_DEVICE_RETRY = 3;\n\n // Pending device-connect resolve — set by _waitForDeviceConnect, resolved by uiResponse\n private _deviceConnectResolve: ((cancelled: boolean) => void) | null = null;\n\n private static readonly DEVICE_CONNECT_TIMEOUT_MS = 60_000;\n\n /**\n * Wait for user to connect and unlock device.\n * Emits 'ui-request' event via the adapter's own emitter.\n * The consumer (monorepo adapter wrapper) listens for this and shows UI.\n * When user confirms, they call adapter.deviceConnectResponse() which resolves this promise.\n * Times out after 60 seconds if no response is received.\n */\n private _waitForDeviceConnect(attempt: number): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n let settled = false;\n\n const timer = setTimeout(() => {\n if (!settled) {\n settled = true;\n this._deviceConnectResolve = null;\n reject(new Error('Ledger device connect timed out after 60 seconds'));\n }\n }, LedgerAdapter.DEVICE_CONNECT_TIMEOUT_MS);\n\n this._deviceConnectResolve = (cancelled: boolean) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n this._deviceConnectResolve = null;\n if (cancelled) {\n reject(new Error('User cancelled Ledger connection'));\n } else {\n resolve();\n }\n };\n\n // Emit ui-request event — consumer should show \"connect and unlock\" prompt\n this.emitter.emit('ui-request-device-connect' as any, {\n type: 'ui-request-device-connect',\n payload: {\n message: 'Please connect and unlock your Ledger device',\n retryCount: attempt,\n maxRetries: LedgerAdapter.MAX_DEVICE_RETRY,\n },\n });\n });\n }\n\n /**\n * Called by consumer to respond to ui-request-device-connect.\n * type='confirm' → retry search, type='cancel' → abort.\n */\n deviceConnectResponse(type: 'confirm' | 'cancel'): void {\n if (this._deviceConnectResolve) {\n this._deviceConnectResolve(type === 'cancel');\n }\n }\n\n private async ensureConnected(connectId?: string): Promise<string> {\n // 1. Exact match\n if (connectId && this._sessions.has(connectId)) {\n return connectId;\n }\n\n // 2. Any existing session (Ledger IDs are temporary, any session is fine)\n if (this._sessions.size > 0) {\n return this._sessions.keys().next().value!;\n }\n\n // 3. No session — search with retry + UI prompt\n for (let attempt = 0; attempt < LedgerAdapter.MAX_DEVICE_RETRY; attempt++) {\n const devices = await this.searchDevices();\n\n if (devices.length > 0) {\n // Found device(s), continue to connection below\n return this._connectFirstOrSelect(devices);\n }\n\n // No device found — prompt user (except on last attempt)\n if (attempt < LedgerAdapter.MAX_DEVICE_RETRY - 1) {\n await this._waitForDeviceConnect(attempt + 1);\n }\n }\n\n throw Object.assign(\n new Error('No Ledger device found after multiple attempts. Please connect and unlock your device.'),\n { _tag: 'DeviceNotRecognizedError' },\n );\n }\n\n private async _connectFirstOrSelect(devices: DeviceInfo[]): Promise<string> {\n if (devices.length === 1) {\n const result = await this.connectDevice(devices[0].connectId);\n if (!result.success) {\n throw Object.assign(\n new Error(result.payload.error),\n { _tag: 'DeviceNotRecognizedError' },\n );\n }\n return devices[0].connectId;\n }\n\n // Multiple devices — ask user via UI handler\n if (this._uiHandler?.onSelectDevice) {\n const selectedConnectId = await this._uiHandler.onSelectDevice(devices);\n const result = await this.connectDevice(selectedConnectId);\n if (!result.success) {\n throw Object.assign(\n new Error(result.payload.error),\n { _tag: 'DeviceNotRecognizedError' },\n );\n }\n return selectedConnectId;\n }\n\n // No UI handler — fall back to first device\n const result = await this.connectDevice(devices[0].connectId);\n if (!result.success) {\n throw Object.assign(\n new Error(result.payload.error),\n { _tag: 'DeviceNotRecognizedError' },\n );\n }\n return devices[0].connectId;\n }\n\n /**\n * Call the connector with automatic session resolution and disconnect retry.\n *\n * 1. Resolves a valid connectId via ensureConnected()\n * 2. Looks up sessionId from _sessions\n * 3. Calls connector.call()\n * 4. On disconnect error: clears stale session, re-connects, retries once\n */\n private async connectorCall(\n connectId: string,\n method: string,\n params: unknown,\n ): Promise<unknown> {\n const resolvedConnectId = await this.ensureConnected(connectId);\n const sessionId = this._sessions.get(resolvedConnectId);\n if (!sessionId) {\n throw Object.assign(\n new Error('Auto-connect succeeded but no session found'),\n { _tag: 'DeviceSessionNotFound' },\n );\n }\n\n try {\n return await this.connector.call(sessionId, method, params);\n } catch (err) {\n if (isDeviceDisconnectedError(err)) {\n // Clear stale session and retry with fresh connection\n this._sessions.delete(resolvedConnectId);\n this._discoveredDevices.clear();\n const retryConnectId = await this.ensureConnected();\n const retrySessionId = this._sessions.get(retryConnectId);\n if (!retrySessionId) {\n throw err;\n }\n return this.connector.call(retrySessionId, method, params);\n }\n throw err;\n }\n }\n\n /**\n * Ensure device permission before proceeding.\n * - No connectId (searchDevices): check environment-level permission\n * - With connectId (business methods): check device-level permission\n * If not granted, calls onDevicePermission so the consumer can request access.\n */\n private async _ensureDevicePermission(connectId?: string, deviceId?: string): Promise<void> {\n const transportType: TransportType = 'hid';\n let granted = false;\n let context: Record<string, unknown> | undefined;\n\n if (this._uiHandler?.checkDevicePermission) {\n try {\n const result = await this._uiHandler.checkDevicePermission({ transportType, connectId, deviceId });\n granted = result.granted;\n context = result.context;\n } catch {\n granted = false;\n }\n }\n\n if (!granted) {\n try {\n await this._uiHandler?.onDevicePermission?.({ transportType, context });\n } catch {\n // UI handler cancelled or failed\n }\n }\n }\n\n /**\n * Convert a thrown error to a Response failure.\n * Uses mapLedgerError to parse Ledger DMK error codes into HardwareErrorCode values.\n */\n private errorToFailure<T>(err: unknown): Response<T> {\n console.error('[LedgerAdapter] error:', err);\n const mapped = mapLedgerError(err);\n\n // Emit a UI event for locked-device so callers can prompt the user\n if (mapped.code === HardwareErrorCode.DeviceLocked) {\n this.emitter.emit(UI_REQUEST.REQUEST_BUTTON, {\n type: UI_REQUEST.REQUEST_BUTTON,\n payload: {\n device: this.unknownDevice(),\n code: 'ButtonRequest_Other',\n },\n });\n }\n\n return failure(mapped.code, mapped.message);\n }\n\n /**\n * Generic batch call with progress reporting.\n * If any single call fails, returns the failure immediately.\n */\n private async batchCall<TParam, TResult>(\n params: TParam[],\n callFn: (p: TParam) => Promise<Response<TResult>>,\n onProgress?: ProgressCallback,\n ): Promise<Response<TResult[]>> {\n const results: TResult[] = [];\n for (let i = 0; i < params.length; i++) {\n const result = await callFn(params[i]);\n if (!result.success) {\n return result;\n }\n results.push(result.payload);\n onProgress?.({ index: i, total: params.length });\n }\n return success(results);\n }\n\n // ---------------------------------------------------------------------------\n // Event translation\n // ---------------------------------------------------------------------------\n\n private deviceConnectHandler = (data: { device: ConnectorDevice }): void => {\n const deviceInfo = this.connectorDeviceToDeviceInfo(data.device);\n this._discoveredDevices.set(deviceInfo.connectId, deviceInfo);\n this.emitter.emit(DEVICE.CONNECT, {\n type: DEVICE.CONNECT,\n payload: deviceInfo,\n });\n };\n\n private deviceDisconnectHandler = (data: { connectId: string }): void => {\n this._discoveredDevices.delete(data.connectId);\n this._sessions.delete(data.connectId);\n this.emitter.emit(DEVICE.DISCONNECT, {\n type: DEVICE.DISCONNECT,\n payload: { connectId: data.connectId },\n });\n };\n\n private uiRequestHandler = (data: { type: string; payload?: unknown }): void => {\n this.handleUiEvent(data);\n };\n\n private uiEventHandler = (data: { type: string; payload?: unknown }): void => {\n this.handleUiEvent(data);\n };\n\n private registerEventListeners(): void {\n this.connector.on('device-connect', this.deviceConnectHandler);\n this.connector.on('device-disconnect', this.deviceDisconnectHandler);\n this.connector.on('ui-request', this.uiRequestHandler);\n this.connector.on('ui-event', this.uiEventHandler);\n }\n\n private unregisterEventListeners(): void {\n this.connector.off('device-connect', this.deviceConnectHandler);\n this.connector.off('device-disconnect', this.deviceDisconnectHandler);\n this.connector.off('ui-request', this.uiRequestHandler);\n this.connector.off('ui-event', this.uiEventHandler);\n }\n\n private handleUiEvent(event: { type: string; payload?: unknown }): void {\n if (!event.type) return;\n\n const payload = event.payload as Record<string, unknown> | undefined;\n const deviceInfo = payload\n ? this.extractDeviceInfoFromPayload(payload)\n : this.unknownDevice();\n\n switch (event.type) {\n case 'ui-request_confirmation':\n this.emitter.emit(UI_REQUEST.REQUEST_BUTTON, {\n type: UI_REQUEST.REQUEST_BUTTON,\n payload: { device: deviceInfo },\n });\n break;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Device info mapping\n // ---------------------------------------------------------------------------\n\n private connectorDeviceToDeviceInfo(device: ConnectorDevice): DeviceInfo {\n return {\n vendor: 'ledger',\n model: device.model ?? 'unknown',\n firmwareVersion: '',\n deviceId: device.deviceId,\n connectId: device.connectId,\n label: device.name,\n connectionType: 'usb' as ConnectionType,\n capabilities: device.capabilities,\n };\n }\n\n private extractDeviceInfoFromPayload(payload: Record<string, unknown>): DeviceInfo {\n return {\n vendor: 'ledger',\n model: (payload['model'] as string) ?? 'unknown',\n firmwareVersion: '',\n deviceId: (payload['deviceId'] as string) ?? (payload['id'] as string) ?? '',\n connectId: (payload['connectId'] as string) ?? (payload['path'] as string) ?? '',\n label: (payload['label'] as string),\n connectionType: 'usb' as ConnectionType,\n };\n }\n\n private unknownDevice(): DeviceInfo {\n return {\n vendor: 'ledger',\n model: 'unknown',\n firmwareVersion: '',\n deviceId: '',\n connectId: '',\n connectionType: 'usb',\n };\n }\n}\n","import { HardwareErrorCode } from '@bytezhang/hardware-wallet-core';\n\n/**\n * DMK locked device status codes:\n * 0x5515 (21781) — primary locked response\n * 0x6982 (27010) — security status not satisfied\n * 0x5303 (21251) — tertiary locked response\n */\nconst LOCKED_ERROR_CODES = new Set(['5515', '21781', '6982', '27010', '5303', '21251']);\n\n/**\n * DMK user-rejected status codes:\n * 0x6985 (27013) — conditions of use not satisfied (user denied on device)\n */\nconst USER_REJECTED_CODES = new Set(['6985', '27013']);\n\n/**\n * DMK wrong-app / CLA-not-supported status codes:\n * 0x6e00 (28160) — CLA not supported (wrong app open)\n * 0x6d00 (27904) — INS not supported (wrong app or outdated app)\n */\nconst WRONG_APP_CODES = new Set(['6e00', '28160', '6d00', '27904']);\n\n/** Check if an error (or any error in its chain) represents a locked Ledger device. */\nexport function isDeviceLockedError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e.errorCode != null && LOCKED_ERROR_CODES.has(String(e.errorCode))) return true;\n if (e.statusCode != null && LOCKED_ERROR_CODES.has(String(e.statusCode))) return true;\n if (e._tag === 'DeviceLockedError') return true;\n if (typeof e.message === 'string' && /locked/i.test(e.message)) return true;\n if (e.originalError != null && isDeviceLockedError(e.originalError)) return true;\n if (e.error != null && e._tag && isDeviceLockedError(e.error)) return true;\n return false;\n}\n\n/** Check if a status/error code exists in the given set, crawling the error chain. */\nfunction hasStatusCode(err: unknown, codeSet: Set<string>): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e.errorCode != null && codeSet.has(String(e.errorCode))) return true;\n if (e.statusCode != null && codeSet.has(String(e.statusCode))) return true;\n if (e.originalError != null && hasStatusCode(e.originalError, codeSet)) return true;\n if (e.error != null && e._tag && hasStatusCode(e.error, codeSet)) return true;\n return false;\n}\n\n/** Check for user rejection (denied on device). */\nexport function isUserRejectedError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e._tag === 'UserRefusedOnDevice') return true;\n if (typeof e.message === 'string' && /denied|rejected|refused/i.test(e.message)) return true;\n if (hasStatusCode(err, USER_REJECTED_CODES)) return true;\n return false;\n}\n\n/** Check for wrong app open on the device. */\nexport function isWrongAppError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e._tag === 'WrongAppOpenedError' || e._tag === 'InvalidStatusWordError') {\n if (hasStatusCode(err, WRONG_APP_CODES)) return true;\n }\n if (typeof e.message === 'string' && /wrong app|open the .* app|CLA not supported/i.test(e.message)) return true;\n if (hasStatusCode(err, WRONG_APP_CODES)) return true;\n return false;\n}\n\n/** Check for device disconnected errors. */\nexport function isDeviceDisconnectedError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e._tag === 'DeviceNotRecognizedError' || e._tag === 'DeviceSessionNotFound') return true;\n if (typeof e.message === 'string' && /disconnected|not found|no device|unplugged|session.*not.*found/i.test(e.message)) return true;\n return false;\n}\n\n/** Check for timeout errors. */\nexport function isTimeoutError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (typeof e.message === 'string' && /timeout|timed?\\s*out/i.test(e.message)) return true;\n if (e._tag === 'DeviceExchangeTimeoutError') return true;\n return false;\n}\n\n/**\n * Map a Ledger DMK error to a HardwareErrorCode and human-readable message\n * with actionable recovery information for the caller.\n */\nexport function mapLedgerError(err: unknown): { code: HardwareErrorCode; message: string } {\n // Order matters: check more specific errors first\n\n if (isDeviceLockedError(err)) {\n return {\n code: HardwareErrorCode.DeviceLocked,\n message: 'Device is locked. Please unlock your Ledger device and try again.',\n };\n }\n\n if (isUserRejectedError(err)) {\n return {\n code: HardwareErrorCode.UserRejected,\n message: 'User rejected the request on the device.',\n };\n }\n\n if (isWrongAppError(err)) {\n return {\n code: HardwareErrorCode.WrongApp,\n message: 'Wrong app is open on the Ledger device. Please open the correct app (e.g. Ethereum) and try again.',\n };\n }\n\n if (isDeviceDisconnectedError(err)) {\n return {\n code: HardwareErrorCode.DeviceDisconnected,\n message: 'Ledger device was disconnected. Please reconnect the device and try again.',\n };\n }\n\n if (isTimeoutError(err)) {\n return {\n code: HardwareErrorCode.OperationTimeout,\n message: 'Operation timed out. Please ensure the Ledger device is connected and responsive.',\n };\n }\n\n // Fallback: extract whatever message we can\n let message = 'Unknown Ledger error';\n if (err instanceof Error) {\n message = err.message;\n } else if (err && typeof err === 'object') {\n const e = err as Record<string, unknown>;\n message = String(e.message ?? e._tag ?? e.type ?? JSON.stringify(err));\n }\n return { code: HardwareErrorCode.UnknownError, message };\n}\n","import type { DeviceDescriptor, DeviceChangeEvent } from '@bytezhang/hardware-wallet-core';\nimport type { IDmk, DmkDiscoveredDevice } from '../types';\n\n/**\n * Manages device discovery, connection, and session tracking.\n * Wraps DMK's Observable APIs into simpler imperative calls.\n */\nexport class LedgerDeviceManager {\n private readonly _dmk: IDmk;\n private readonly _discovered = new Map<string, DmkDiscoveredDevice>();\n private readonly _sessions = new Map<string, string>(); // deviceId → sessionId\n private readonly _sessionToDevice = new Map<string, string>(); // sessionId → deviceId\n private _listenSub: { unsubscribe: () => void } | null = null;\n\n constructor(dmk: IDmk) {\n this._dmk = dmk;\n }\n\n /**\n * One-shot enumeration: subscribe to listenToAvailableDevices,\n * take the first emission, unsubscribe, return DeviceDescriptors.\n */\n enumerate(): Promise<DeviceDescriptor[]> {\n return new Promise<DeviceDescriptor[]>((resolve) => {\n let resolved = false;\n // BehaviorSubject fires next synchronously during subscribe(),\n // so 'sub' is not yet assigned when the callback runs.\n // Capture result synchronously, unsubscribe after assignment.\n let syncResult: { id: string; deviceModel: { name: string }; [k: string]: unknown }[] | null = null;\n\n const sub = this._dmk.listenToAvailableDevices().subscribe({\n next: (devices) => {\n if (resolved) return;\n resolved = true;\n this._discovered.clear();\n for (const d of devices) {\n this._discovered.set(d.id, d);\n }\n syncResult = devices;\n },\n error: () => {\n if (!resolved) {\n resolved = true;\n resolve([]);\n }\n },\n });\n\n // If BehaviorSubject fired synchronously, sub is now assigned\n if (syncResult !== null) {\n sub.unsubscribe();\n const devices = syncResult as { id: string; deviceModel: { name: string } }[];\n resolve(devices.map(d => ({ path: d.id, type: d.deviceModel.name })));\n }\n });\n }\n\n /**\n * Continuous listening: tracks device connect/disconnect via diffing.\n */\n listen(onChange: (event: DeviceChangeEvent) => void): void {\n this.stopListening();\n let previousIds = new Set<string>();\n\n this._listenSub = this._dmk.listenToAvailableDevices().subscribe({\n next: (devices) => {\n const currentIds = new Set(devices.map(d => d.id));\n\n for (const d of devices) {\n this._discovered.set(d.id, d);\n console.log('[LedgerDeviceManager] listen device:', JSON.stringify({\n id: d.id,\n deviceModel: d.deviceModel,\n name: (d as any).name,\n }));\n if (!previousIds.has(d.id)) {\n onChange({ type: 'device-connected', descriptor: { path: d.id, type: d.deviceModel.name } });\n }\n }\n for (const id of previousIds) {\n if (!currentIds.has(id)) {\n this._discovered.delete(id);\n onChange({ type: 'device-disconnected', descriptor: { path: id } });\n }\n }\n previousIds = currentIds;\n },\n });\n }\n\n stopListening(): void {\n this._listenSub?.unsubscribe();\n this._listenSub = null;\n }\n\n /**\n * Trigger browser device selection (WebHID requestDevice).\n * Starts discovery for a short period, then stops.\n */\n requestDevice(timeoutMs = 3000): Promise<void> {\n return new Promise<void>((resolve) => {\n const sub = this._dmk.startDiscovering().subscribe({\n next: (d) => { this._discovered.set(d.id, d); },\n error: () => { sub.unsubscribe(); resolve(); },\n });\n setTimeout(() => {\n sub.unsubscribe();\n this._dmk.stopDiscovering();\n resolve();\n }, timeoutMs);\n });\n }\n\n /** Connect to a previously discovered device. Returns sessionId. */\n async connect(deviceId: string): Promise<string> {\n const device = this._discovered.get(deviceId);\n if (!device) {\n throw new Error(`Device \"${deviceId}\" not found. Call enumerate() or listen() first.`);\n }\n const sessionId = await this._dmk.connect({ device });\n this._sessions.set(deviceId, sessionId);\n this._sessionToDevice.set(sessionId, deviceId);\n return sessionId;\n }\n\n /** Disconnect a session. */\n async disconnect(sessionId: string): Promise<void> {\n await this._dmk.disconnect({ sessionId });\n const deviceId = this._sessionToDevice.get(sessionId);\n if (deviceId) this._sessions.delete(deviceId);\n this._sessionToDevice.delete(sessionId);\n }\n\n getSessionId(deviceId: string): string | undefined {\n return this._sessions.get(deviceId);\n }\n\n getDeviceId(sessionId: string): string | undefined {\n return this._sessionToDevice.get(sessionId);\n }\n\n /** Get the underlying DMK instance (needed by SignerManager). */\n getDmk(): IDmk {\n return this._dmk;\n }\n\n dispose(): void {\n this.stopListening();\n this._discovered.clear();\n this._sessions.clear();\n this._sessionToDevice.clear();\n this._dmk.close?.();\n }\n}\n","/** DeviceAction state emitted by DMK signer operations. */\ninterface DeviceActionState<T> {\n status: 'pending' | 'completed' | 'error';\n output?: T;\n error?: unknown;\n intermediateValue?: {\n requiredUserInteraction?: string;\n [key: string]: unknown;\n };\n}\n\n/**\n * Convert a DMK DeviceAction (Observable-based) into a Promise.\n * Handles pending → completed/error state transitions and interaction callbacks.\n */\nexport function deviceActionToPromise<T>(\n action: {\n observable: {\n subscribe(observer: {\n next: (value: DeviceActionState<T>) => void;\n error?: (err: unknown) => void;\n complete?: () => void;\n }): { unsubscribe: () => void };\n };\n },\n onInteraction?: (interaction: string) => void,\n): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n let settled = false;\n let sub: { unsubscribe: () => void };\n\n sub = action.observable.subscribe({\n next: (state) => {\n if (settled) return;\n if (state.status === 'completed') {\n settled = true;\n sub?.unsubscribe();\n resolve(state.output as T);\n } else if (state.status === 'error') {\n settled = true;\n sub?.unsubscribe();\n reject(state.error);\n } else if (state.status === 'pending' && onInteraction) {\n const interaction = state.intermediateValue?.requiredUserInteraction;\n if (interaction && interaction !== 'none') {\n onInteraction(interaction);\n } else if (interaction === 'none') {\n // Previous interaction resolved (e.g., user opened the app)\n onInteraction('interaction-complete');\n }\n }\n },\n error: (err: unknown) => {\n if (!settled) {\n settled = true;\n sub?.unsubscribe();\n reject(err);\n }\n },\n complete: () => {\n if (!settled) {\n settled = true;\n reject(new Error('Device action completed without result'));\n }\n },\n });\n });\n}\n","import type { SignerEvmAddress, SignerEvmSignature } from '../types';\nimport { deviceActionToPromise } from './deviceActionToPromise';\n\n/**\n * SDK signer interface — duck-typed to avoid hard dependency on\n * @ledgerhq/device-signer-kit-ethereum.\n */\nexport interface ISdkSignerEth {\n getAddress(derivationPath: string, options?: { checkOnDevice?: boolean }): unknown;\n signTransaction(derivationPath: string, transaction: Uint8Array, options?: unknown): unknown;\n signMessage(derivationPath: string, message: string): unknown;\n signTypedData(derivationPath: string, data: unknown): unknown;\n}\n\n/** Convert hex string (with or without 0x) to Uint8Array. */\nfunction hexToBytes(hex: string): Uint8Array {\n const h = hex.startsWith('0x') ? hex.slice(2) : hex;\n const bytes = new Uint8Array(h.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(h.substring(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\n/**\n * Wraps Ledger's SDK signer (Observable-based DeviceActions) into\n * a simple async interface returning plain serializable data.\n */\nexport class SignerEth {\n onInteraction?: (interaction: string) => void;\n\n constructor(private readonly _sdk: ISdkSignerEth) {}\n\n async getAddress(\n derivationPath: string,\n options?: { checkOnDevice?: boolean }\n ): Promise<SignerEvmAddress> {\n const action = this._sdk.getAddress(derivationPath, {\n checkOnDevice: options?.checkOnDevice ?? false,\n });\n return deviceActionToPromise<SignerEvmAddress>(action as any, this.onInteraction);\n }\n\n async signTransaction(\n derivationPath: string,\n serializedTxHex: string\n ): Promise<SignerEvmSignature> {\n const action = this._sdk.signTransaction(derivationPath, hexToBytes(serializedTxHex));\n return deviceActionToPromise<SignerEvmSignature>(action as any, this.onInteraction);\n }\n\n async signMessage(derivationPath: string, message: string): Promise<SignerEvmSignature> {\n const action = this._sdk.signMessage(derivationPath, message);\n return deviceActionToPromise<SignerEvmSignature>(action as any, this.onInteraction);\n }\n\n async signTypedData(derivationPath: string, data: unknown): Promise<SignerEvmSignature> {\n const action = this._sdk.signTypedData(derivationPath, data);\n return deviceActionToPromise<SignerEvmSignature>(action as any, this.onInteraction);\n }\n}\n","import type { IDmk } from '../types';\nimport { SignerEth } from './SignerEth';\n\ntype SignerEthBuilderFn = (args: { dmk: IDmk; sessionId: string }) => { build(): unknown } | Promise<{ build(): unknown }>;\n\n/**\n * Manages per-sessionId SignerEth instances.\n * Creates on demand, caches for reuse, invalidates on session change.\n */\nexport class SignerManager {\n private readonly _cache = new Map<string, SignerEth>();\n private readonly _dmk: IDmk;\n private readonly _builderFn: SignerEthBuilderFn;\n\n constructor(dmk: IDmk, builderFn?: SignerEthBuilderFn) {\n this._dmk = dmk;\n this._builderFn = builderFn ?? SignerManager._defaultBuilder();\n }\n\n async getOrCreate(sessionId: string): Promise<SignerEth> {\n let signer = this._cache.get(sessionId);\n if (signer) return signer;\n\n const builder = await this._builderFn({ dmk: this._dmk, sessionId });\n const sdkSigner = builder.build();\n signer = new SignerEth(sdkSigner as any);\n this._cache.set(sessionId, signer);\n return signer;\n }\n\n invalidate(sessionId: string): void {\n this._cache.delete(sessionId);\n }\n\n clearAll(): void {\n this._cache.clear();\n }\n\n private static _defaultBuilder(): SignerEthBuilderFn {\n let BuilderClass: any = null;\n return async (args) => {\n if (!BuilderClass) {\n const mod = await import('@ledgerhq/device-signer-kit-ethereum');\n BuilderClass = mod.SignerEthBuilder;\n }\n return new BuilderClass(args);\n };\n }\n}\n","import type { SignerBtcAddress } from '../types';\nimport { deviceActionToPromise } from './deviceActionToPromise';\n\n/**\n * SDK BTC signer interface — duck-typed to avoid hard dependency on\n * @ledgerhq/device-signer-kit-bitcoin.\n */\nexport interface ISdkSignerBtc {\n getExtendedPublicKey(derivationPath: string, options?: { checkOnDevice?: boolean }): unknown;\n getWalletAddress(wallet: unknown, addressIndex: number, options?: { checkOnDevice?: boolean; change?: boolean }): unknown;\n getMasterFingerprint(options?: { skipOpenApp?: boolean }): unknown;\n}\n\n/**\n * Wraps Ledger's BTC SDK signer (Observable-based DeviceActions) into\n * a simple async interface returning plain serializable data.\n */\nexport class SignerBtc {\n onInteraction?: (interaction: string) => void;\n\n constructor(private readonly _sdk: ISdkSignerBtc) {}\n\n async getWalletAddress(\n wallet: unknown,\n addressIndex: number,\n options?: { checkOnDevice?: boolean; change?: boolean },\n ): Promise<SignerBtcAddress> {\n const action = this._sdk.getWalletAddress(wallet, addressIndex, {\n checkOnDevice: options?.checkOnDevice ?? false,\n change: options?.change ?? false,\n });\n return deviceActionToPromise<SignerBtcAddress>(action as any, this.onInteraction);\n }\n\n async getExtendedPublicKey(\n derivationPath: string,\n options?: { checkOnDevice?: boolean },\n ): Promise<string> {\n const action = this._sdk.getExtendedPublicKey(derivationPath, {\n checkOnDevice: options?.checkOnDevice ?? false,\n });\n return deviceActionToPromise<string>(action as any, this.onInteraction);\n }\n\n async getMasterFingerprint(\n options?: { skipOpenApp?: boolean },\n ): Promise<Uint8Array> {\n const action = this._sdk.getMasterFingerprint(options);\n const result = await deviceActionToPromise<{ masterFingerprint: Uint8Array }>(action as any, this.onInteraction);\n return result.masterFingerprint;\n }\n}\n","import type { TransportProvider } from '../types';\n\nconst registry = new Map<string, TransportProvider>();\n\nfunction normalizeType(type: string): string {\n return type.trim().toLowerCase();\n}\n\nexport function registerTransport(type: string, provider: TransportProvider): void {\n const key = normalizeType(type);\n if (!key) throw new Error('Transport type must be a non-empty string');\n registry.set(key, provider);\n}\n\nexport function unregisterTransport(type: string): void {\n registry.delete(normalizeType(type));\n}\n\nexport function getTransportProvider(type: string): TransportProvider | null {\n return registry.get(normalizeType(type)) ?? null;\n}\n\nexport function listRegisteredTransports(): string[] {\n return Array.from(registry.keys());\n}\n\nexport function clearRegistry(): void {\n registry.clear();\n}\n","import type { IDmk } from '../types';\n\n/**\n * Map of chain ticker symbols to the Ledger app name\n * that must be open to sign transactions for that chain.\n */\nexport const APP_NAME_MAP: Record<string, string> = {\n ETH: 'Ethereum',\n BTC: 'Bitcoin',\n SOL: 'Solana',\n TRX: 'Tron',\n XRP: 'XRP',\n ADA: 'Cardano',\n DOT: 'Polkadot',\n ATOM: 'Cosmos',\n};\n\n/** The name reported by the Ledger when it sits on the home screen. */\nconst DASHBOARD_APP_NAME = 'BOLOS';\n\ninterface AppManagerOptions {\n waitMs?: number;\n maxRetries?: number;\n}\n\n/**\n * Orchestrates opening / closing Ledger on-device apps so that the\n * correct signer application is running before any signing call.\n */\nexport class AppManager {\n private readonly _dmk: IDmk;\n private readonly _waitMs: number;\n private readonly _maxRetries: number;\n\n constructor(dmk: IDmk, options?: AppManagerOptions) {\n this._dmk = dmk;\n this._waitMs = options?.waitMs ?? 1000;\n this._maxRetries = options?.maxRetries ?? 10;\n }\n\n /**\n * Return the Ledger app name for a given chain ticker,\n * or undefined if the chain is not supported.\n */\n static getAppName(chain: string): string | undefined {\n return APP_NAME_MAP[chain];\n }\n\n /**\n * Ensure the target app is open on the device identified by `sessionId`.\n *\n * Flow:\n * 1. Check the currently running app.\n * 2. If it is already the target, return immediately.\n * 3. If a different app is running (not dashboard), close it first.\n * 4. Open the target app.\n * 5. Poll until the device confirms the target app is running.\n */\n async ensureAppOpen(sessionId: string, targetAppName: string): Promise<void> {\n const currentApp = await this._getCurrentApp(sessionId);\n\n if (currentApp === targetAppName) {\n return;\n }\n\n // If we're not on the dashboard, close the current app first\n if (!this._isDashboard(currentApp)) {\n await this._closeCurrentApp(sessionId);\n // Wait for dashboard to become active\n await this._waitForApp(sessionId, DASHBOARD_APP_NAME);\n }\n\n // Open the target app\n await this._openApp(sessionId, targetAppName);\n\n // Poll until the target app is confirmed open\n await this._waitForApp(sessionId, targetAppName);\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private async _getCurrentApp(sessionId: string): Promise<string> {\n const result = (await this._dmk.sendCommand({\n sessionId,\n command: { type: 'get-app-and-version' },\n })) as { name: string };\n return result.name;\n }\n\n private async _openApp(sessionId: string, appName: string): Promise<void> {\n await this._dmk.sendCommand({\n sessionId,\n command: { type: 'open-app', appName },\n });\n }\n\n private async _closeCurrentApp(sessionId: string): Promise<void> {\n await this._dmk.sendCommand({\n sessionId,\n command: { type: 'close-app' },\n });\n }\n\n /**\n * Poll the device until the expected app is reported as running,\n * or throw after `_maxRetries` attempts.\n */\n private async _waitForApp(sessionId: string, expectedAppName: string): Promise<void> {\n for (let i = 0; i < this._maxRetries; i++) {\n await this._wait();\n const current = await this._getCurrentApp(sessionId);\n if (current === expectedAppName) {\n return;\n }\n }\n throw new Error(\n `Ledger: failed to open \"${expectedAppName}\" after ${this._maxRetries} retries`\n );\n }\n\n private _isDashboard(appName: string): boolean {\n return appName === DASHBOARD_APP_NAME;\n }\n\n private _wait(): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, this._waitMs));\n }\n}\n"],"mappings":"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","names":["import_hardware_wallet_core","result"]}
package/dist/index.mjs CHANGED
@@ -124,7 +124,7 @@ function stripHex(hex) {
124
124
  function padHex64(hex) {
125
125
  return `0x${stripHex(hex).padStart(64, "0")}`;
126
126
  }
127
- var LedgerAdapter = class {
127
+ var _LedgerAdapter = class _LedgerAdapter {
128
128
  constructor(connector) {
129
129
  this.vendor = "ledger";
130
130
  this.emitter = new TypedEventEmitter();
@@ -133,6 +133,8 @@ var LedgerAdapter = class {
133
133
  this._discoveredDevices = /* @__PURE__ */ new Map();
134
134
  // Session tracking: maps connectId -> sessionId
135
135
  this._sessions = /* @__PURE__ */ new Map();
136
+ // Pending device-connect resolve — set by _waitForDeviceConnect, resolved by uiResponse
137
+ this._deviceConnectResolve = null;
136
138
  // ---------------------------------------------------------------------------
137
139
  // Event translation
138
140
  // ---------------------------------------------------------------------------
@@ -456,16 +458,53 @@ var LedgerAdapter = class {
456
458
  async solSignMessage(_connectId, _deviceId, _params) {
457
459
  return failure(HardwareErrorCode2.MethodNotSupported, "Solana signMessage is not supported on Ledger yet");
458
460
  }
459
- // ---------------------------------------------------------------------------
460
- // Private helpers
461
- // ---------------------------------------------------------------------------
462
461
  /**
463
- * Ensure at least one device is connected and return a valid connectId.
464
- *
465
- * - If a session already exists for the given connectId, reuse it.
466
- * - If ANY session exists (Ledger IDs are ephemeral), reuse it.
467
- * - Otherwise: search 1 device: auto-connect, multiple: ask user, 0: throw.
462
+ * Wait for user to connect and unlock device.
463
+ * Emits 'ui-request' event via the adapter's own emitter.
464
+ * The consumer (monorepo adapter wrapper) listens for this and shows UI.
465
+ * When user confirms, they call adapter.deviceConnectResponse() which resolves this promise.
466
+ * Times out after 60 seconds if no response is received.
467
+ */
468
+ _waitForDeviceConnect(attempt) {
469
+ return new Promise((resolve, reject) => {
470
+ let settled = false;
471
+ const timer = setTimeout(() => {
472
+ if (!settled) {
473
+ settled = true;
474
+ this._deviceConnectResolve = null;
475
+ reject(new Error("Ledger device connect timed out after 60 seconds"));
476
+ }
477
+ }, _LedgerAdapter.DEVICE_CONNECT_TIMEOUT_MS);
478
+ this._deviceConnectResolve = (cancelled) => {
479
+ if (settled) return;
480
+ settled = true;
481
+ clearTimeout(timer);
482
+ this._deviceConnectResolve = null;
483
+ if (cancelled) {
484
+ reject(new Error("User cancelled Ledger connection"));
485
+ } else {
486
+ resolve();
487
+ }
488
+ };
489
+ this.emitter.emit("ui-request-device-connect", {
490
+ type: "ui-request-device-connect",
491
+ payload: {
492
+ message: "Please connect and unlock your Ledger device",
493
+ retryCount: attempt,
494
+ maxRetries: _LedgerAdapter.MAX_DEVICE_RETRY
495
+ }
496
+ });
497
+ });
498
+ }
499
+ /**
500
+ * Called by consumer to respond to ui-request-device-connect.
501
+ * type='confirm' → retry search, type='cancel' → abort.
468
502
  */
503
+ deviceConnectResponse(type) {
504
+ if (this._deviceConnectResolve) {
505
+ this._deviceConnectResolve(type === "cancel");
506
+ }
507
+ }
469
508
  async ensureConnected(connectId) {
470
509
  if (connectId && this._sessions.has(connectId)) {
471
510
  return connectId;
@@ -473,13 +512,21 @@ var LedgerAdapter = class {
473
512
  if (this._sessions.size > 0) {
474
513
  return this._sessions.keys().next().value;
475
514
  }
476
- const devices = await this.searchDevices();
477
- if (devices.length === 0) {
478
- throw Object.assign(
479
- new Error("No Ledger device found. Make sure the device is connected via USB and ready."),
480
- { _tag: "DeviceNotRecognizedError" }
481
- );
515
+ for (let attempt = 0; attempt < _LedgerAdapter.MAX_DEVICE_RETRY; attempt++) {
516
+ const devices = await this.searchDevices();
517
+ if (devices.length > 0) {
518
+ return this._connectFirstOrSelect(devices);
519
+ }
520
+ if (attempt < _LedgerAdapter.MAX_DEVICE_RETRY - 1) {
521
+ await this._waitForDeviceConnect(attempt + 1);
522
+ }
482
523
  }
524
+ throw Object.assign(
525
+ new Error("No Ledger device found after multiple attempts. Please connect and unlock your device."),
526
+ { _tag: "DeviceNotRecognizedError" }
527
+ );
528
+ }
529
+ async _connectFirstOrSelect(devices) {
483
530
  if (devices.length === 1) {
484
531
  const result2 = await this.connectDevice(devices[0].connectId);
485
532
  if (!result2.success) {
@@ -665,6 +712,19 @@ var LedgerAdapter = class {
665
712
  };
666
713
  }
667
714
  };
715
+ // ---------------------------------------------------------------------------
716
+ // Private helpers
717
+ // ---------------------------------------------------------------------------
718
+ /**
719
+ * Ensure at least one device is connected and return a valid connectId.
720
+ *
721
+ * - If a session already exists for the given connectId, reuse it.
722
+ * - If ANY session exists (Ledger IDs are ephemeral), reuse it.
723
+ * - Otherwise: search → 1 device: auto-connect, multiple: ask user, 0: throw.
724
+ */
725
+ _LedgerAdapter.MAX_DEVICE_RETRY = 3;
726
+ _LedgerAdapter.DEVICE_CONNECT_TIMEOUT_MS = 6e4;
727
+ var LedgerAdapter = _LedgerAdapter;
668
728
 
669
729
  // src/device/LedgerDeviceManager.ts
670
730
  var LedgerDeviceManager = class {
@@ -684,8 +744,8 @@ var LedgerDeviceManager = class {
684
744
  enumerate() {
685
745
  return new Promise((resolve) => {
686
746
  let resolved = false;
687
- let sub = null;
688
- sub = this._dmk.listenToAvailableDevices().subscribe({
747
+ let syncResult = null;
748
+ const sub = this._dmk.listenToAvailableDevices().subscribe({
689
749
  next: (devices) => {
690
750
  if (resolved) return;
691
751
  resolved = true;
@@ -693,25 +753,20 @@ var LedgerDeviceManager = class {
693
753
  for (const d of devices) {
694
754
  this._discovered.set(d.id, d);
695
755
  }
696
- if (sub) {
697
- sub.unsubscribe();
698
- } else {
699
- Promise.resolve().then(() => sub?.unsubscribe());
700
- }
701
- console.log("[LedgerDeviceManager] enumerate devices:", JSON.stringify(devices.map((d) => ({
702
- id: d.id,
703
- deviceModel: d.deviceModel,
704
- name: d.name
705
- }))));
706
- resolve(devices.map((d) => ({ path: d.id, type: d.deviceModel.name })));
756
+ syncResult = devices;
707
757
  },
708
758
  error: () => {
709
- if (resolved) return;
710
- resolved = true;
711
- sub?.unsubscribe();
712
- resolve([]);
759
+ if (!resolved) {
760
+ resolved = true;
761
+ resolve([]);
762
+ }
713
763
  }
714
764
  });
765
+ if (syncResult !== null) {
766
+ sub.unsubscribe();
767
+ const devices = syncResult;
768
+ resolve(devices.map((d) => ({ path: d.id, type: d.deviceModel.name })));
769
+ }
715
770
  });
716
771
  }
717
772
  /**
@@ -827,6 +882,8 @@ function deviceActionToPromise(action, onInteraction) {
827
882
  const interaction = state.intermediateValue?.requiredUserInteraction;
828
883
  if (interaction && interaction !== "none") {
829
884
  onInteraction(interaction);
885
+ } else if (interaction === "none") {
886
+ onInteraction("interaction-complete");
830
887
  }
831
888
  }
832
889
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/adapter/LedgerAdapter.ts","../src/errors.ts","../src/device/LedgerDeviceManager.ts","../src/signer/deviceActionToPromise.ts","../src/signer/SignerEth.ts","../src/signer/SignerManager.ts","../src/signer/SignerBtc.ts","../src/app/AppManager.ts"],"sourcesContent":["import type {\n IHardwareWallet,\n IUiHandler,\n IConnector,\n ConnectorDevice,\n DeviceInfo,\n HardwareEventMap,\n DeviceEventListener,\n TransportType,\n ConnectionType,\n Response,\n EvmGetAddressParams,\n EvmAddress,\n EvmGetPublicKeyParams,\n EvmPublicKey,\n EvmSignTxParams,\n EvmSignedTx,\n EvmSignMsgParams,\n EvmSignTypedDataParams,\n EvmSignature,\n ProgressCallback,\n BtcGetAddressParams,\n BtcAddress,\n BtcGetPublicKeyParams,\n BtcPublicKey,\n BtcSignTxParams,\n BtcSignedTx,\n BtcSignMsgParams,\n BtcSignature,\n SolGetAddressParams,\n SolAddress,\n SolGetPublicKeyParams,\n SolPublicKey,\n SolSignTxParams,\n SolSignedTx,\n SolSignMsgParams,\n SolSignature,\n ChainCapability,\n} from '@bytezhang/hardware-wallet-core';\nimport {\n success,\n failure,\n HardwareErrorCode,\n TypedEventEmitter,\n DEVICE,\n UI_REQUEST,\n} from '@bytezhang/hardware-wallet-core';\nimport { mapLedgerError, isDeviceDisconnectedError } from '../errors';\n\n/** Ensure a hex string has the `0x` prefix. */\nfunction ensure0x(hex: string): string {\n return hex.startsWith('0x') ? hex : `0x${hex}`;\n}\n\n/** Remove `0x` prefix from a hex string if present. */\nfunction stripHex(hex: string): string {\n return hex.startsWith('0x') ? hex.slice(2) : hex;\n}\n\n/** Ensure a hex string is `0x`-prefixed and zero-padded to 64 hex chars (32 bytes). */\nfunction padHex64(hex: string): string {\n return `0x${stripHex(hex).padStart(64, '0')}`;\n}\n\n/**\n * Ledger hardware wallet adapter that delegates to an IConnector.\n *\n * This is a thin translation layer that:\n * - Accepts a pre-configured IConnector (transport decisions are made at connector creation time)\n * - Translates IHardwareWallet method calls to connector.call() invocations\n * - Maps connector results/errors to our Response<T> format with enriched error messages\n * - Translates connector events to HardwareEventMap events\n * - Integrates with IUiHandler for permission flows\n */\nexport class LedgerAdapter implements IHardwareWallet {\n readonly vendor = 'ledger' as const;\n\n private readonly connector: IConnector;\n private readonly emitter = new TypedEventEmitter<HardwareEventMap>();\n\n private _uiHandler: Partial<IUiHandler> | null = null;\n\n // Device cache: tracks discovered devices from connector events\n private _discoveredDevices = new Map<string, DeviceInfo>();\n\n // Session tracking: maps connectId -> sessionId\n private _sessions = new Map<string, string>();\n\n constructor(connector: IConnector) {\n this.connector = connector;\n this.registerEventListeners();\n }\n\n // ---------------------------------------------------------------------------\n // Transport\n // ---------------------------------------------------------------------------\n // Transport is decided at connector creation time. These methods\n // satisfy the IHardwareWallet interface with sensible defaults.\n\n get activeTransport(): TransportType | null {\n return 'hid';\n }\n\n getAvailableTransports(): TransportType[] {\n return ['hid'];\n }\n\n async switchTransport(_type: TransportType): Promise<void> {\n // Transport is fixed at connector creation time.\n // To switch transport, create a new LedgerAdapter with a different connector.\n }\n\n // ---------------------------------------------------------------------------\n // UI handler\n // ---------------------------------------------------------------------------\n\n setUiHandler(handler: Partial<IUiHandler>): void {\n this._uiHandler = handler;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n async init(_config?: unknown): Promise<void> {\n // Connector is injected via constructor, already initialized.\n // Nothing to do here.\n }\n\n async dispose(): Promise<void> {\n this.unregisterEventListeners();\n this.connector.reset();\n this._uiHandler = null;\n this._discoveredDevices.clear();\n this._sessions.clear();\n this.emitter.removeAllListeners();\n }\n\n // ---------------------------------------------------------------------------\n // Device management\n // ---------------------------------------------------------------------------\n\n async searchDevices(): Promise<DeviceInfo[]> {\n await this._ensureDevicePermission();\n\n const devices = await this.connector.searchDevices();\n console.log('[LedgerAdapter] connector.searchDevices raw:', JSON.stringify(devices));\n\n for (const d of devices) {\n if (d.connectId && !this._discoveredDevices.has(d.connectId)) {\n this._discoveredDevices.set(d.connectId, this.connectorDeviceToDeviceInfo(d));\n }\n }\n\n // If no devices found, ensure permission (no connectId = search context)\n if (this._discoveredDevices.size === 0) {\n await this._ensureDevicePermission();\n }\n\n return Array.from(this._discoveredDevices.values());\n }\n\n async connectDevice(connectId: string): Promise<Response<string>> {\n await this._ensureDevicePermission(connectId);\n try {\n const session = await this.connector.connect(connectId);\n this._sessions.set(connectId, session.sessionId);\n\n // Update device cache with richer info from session\n if (session.deviceInfo) {\n this._discoveredDevices.set(connectId, session.deviceInfo);\n }\n\n return success(connectId);\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async disconnectDevice(connectId: string): Promise<void> {\n const sessionId = this._sessions.get(connectId);\n if (sessionId) {\n await this.connector.disconnect(sessionId);\n this._sessions.delete(connectId);\n }\n }\n\n async getDeviceInfo(\n connectId: string,\n deviceId: string,\n ): Promise<Response<DeviceInfo>> {\n await this._ensureDevicePermission(connectId, deviceId);\n\n // Look up the device in the cache populated by event handlers / searchDevices.\n // Try connectId first (the USB path), then fall back to scanning by deviceId.\n const cached =\n this._discoveredDevices.get(connectId) ??\n Array.from(this._discoveredDevices.values()).find(\n (d) => d.deviceId === deviceId,\n );\n\n if (cached) {\n return success(cached);\n }\n\n return failure(\n HardwareErrorCode.DeviceNotFound,\n 'Device not found in cache. Call searchDevices() or wait for a device-connected event first.',\n );\n }\n\n getSupportedChains(): ChainCapability[] {\n return ['evm', 'btc', 'sol'];\n }\n\n // ---------------------------------------------------------------------------\n // Events\n // ---------------------------------------------------------------------------\n\n on<K extends keyof HardwareEventMap>(event: K, listener: (event: HardwareEventMap[K]) => void): void;\n on(event: string, listener: DeviceEventListener): void;\n on(event: string, listener: (event: any) => void): void {\n this.emitter.on(event, listener);\n }\n\n off<K extends keyof HardwareEventMap>(event: K, listener: (event: HardwareEventMap[K]) => void): void;\n off(event: string, listener: DeviceEventListener): void;\n off(event: string, listener: (event: any) => void): void {\n this.emitter.off(event, listener);\n }\n\n cancel(connectId: string): void {\n const sessionId = this._sessions.get(connectId) ?? connectId;\n void this.connector.cancel(sessionId);\n }\n\n // ---------------------------------------------------------------------------\n // EVM methods\n // ---------------------------------------------------------------------------\n\n async evmGetAddress(\n connectId: string,\n _deviceId: string,\n params: EvmGetAddressParams,\n ): Promise<Response<EvmAddress>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'evmGetAddress', {\n path: params.path,\n showOnDevice: params.showOnDevice,\n chainId: params.chainId,\n }) as { address: string; publicKey?: string; path?: string };\n\n return success({\n address: result.address,\n path: params.path,\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async evmGetAddresses(\n connectId: string,\n deviceId: string,\n params: EvmGetAddressParams[],\n onProgress?: ProgressCallback,\n ): Promise<Response<EvmAddress[]>> {\n return this.batchCall(\n params,\n (p) => this.evmGetAddress(connectId, deviceId, p),\n onProgress,\n );\n }\n\n async evmGetPublicKey(\n connectId: string,\n _deviceId: string,\n params: EvmGetPublicKeyParams,\n ): Promise<Response<EvmPublicKey>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'evmGetAddress', {\n path: params.path,\n showOnDevice: params.showOnDevice,\n }) as { address: string; publicKey: string; path?: string };\n\n return success({\n publicKey: result.publicKey,\n path: params.path,\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async evmSignTransaction(\n connectId: string,\n _deviceId: string,\n params: EvmSignTxParams,\n ): Promise<Response<EvmSignedTx>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'evmSignTransaction', {\n path: params.path,\n transaction: {\n to: params.to,\n value: params.value,\n chainId: params.chainId,\n nonce: params.nonce,\n gasLimit: params.gasLimit,\n gasPrice: params.gasPrice,\n maxFeePerGas: params.maxFeePerGas,\n maxPriorityFeePerGas: params.maxPriorityFeePerGas,\n accessList: params.accessList,\n data: params.data,\n },\n }) as { v: string; r: string; s: string; serializedTx?: string };\n\n return success({\n v: ensure0x(result.v),\n r: padHex64(result.r),\n s: padHex64(result.s),\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async evmSignMessage(\n connectId: string,\n _deviceId: string,\n params: EvmSignMsgParams,\n ): Promise<Response<EvmSignature>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'evmSignMessage', {\n path: params.path,\n message: params.message,\n }) as { signature: string; address?: string };\n\n return success({\n signature: ensure0x(result.signature),\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async evmSignTypedData(\n connectId: string,\n _deviceId: string,\n params: EvmSignTypedDataParams,\n ): Promise<Response<EvmSignature>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n // Ledger requires full EIP-712 structure — hash mode is not supported.\n if (params.mode === 'hash') {\n return failure(\n HardwareErrorCode.MethodNotSupported,\n 'Ledger does not support hash-only EIP-712 signing. Use mode \"full\" with the complete typed data structure.',\n );\n }\n\n try {\n const result = await this.connectorCall(connectId, 'evmSignTypedData', {\n path: params.path,\n data: params.data,\n }) as { signature: string; address?: string };\n\n return success({\n signature: ensure0x(result.signature),\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n // ---------------------------------------------------------------------------\n // BTC methods\n // ---------------------------------------------------------------------------\n\n async btcGetAddress(\n connectId: string,\n _deviceId: string,\n params: BtcGetAddressParams,\n ): Promise<Response<BtcAddress>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'btcGetAddress', {\n path: params.path,\n coin: params.coin,\n showOnDevice: params.showOnDevice,\n scriptType: params.scriptType,\n }) as { address: string; path: string };\n\n return success({\n address: result.address,\n path: params.path,\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async btcGetAddresses(\n connectId: string,\n deviceId: string,\n params: BtcGetAddressParams[],\n onProgress?: ProgressCallback,\n ): Promise<Response<BtcAddress[]>> {\n return this.batchCall(\n params,\n (p) => this.btcGetAddress(connectId, deviceId, p),\n onProgress,\n );\n }\n\n async btcGetPublicKey(\n connectId: string,\n _deviceId: string,\n params: BtcGetPublicKeyParams,\n ): Promise<Response<BtcPublicKey>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'btcGetPublicKey', {\n path: params.path,\n coin: params.coin,\n showOnDevice: params.showOnDevice,\n }) as {\n xpub: string;\n publicKey: string;\n fingerprint: number;\n chainCode: string;\n path: string;\n depth: number;\n };\n\n return success({\n xpub: result.xpub,\n publicKey: result.publicKey ?? '',\n fingerprint: result.fingerprint ?? 0,\n chainCode: result.chainCode ?? '',\n path: params.path,\n depth: result.depth ?? 0,\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async btcSignTransaction(\n connectId: string,\n _deviceId: string,\n params: BtcSignTxParams,\n ): Promise<Response<BtcSignedTx>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n if (!params.psbt) {\n return failure(\n HardwareErrorCode.InvalidParams,\n 'Ledger requires PSBT format for BTC transaction signing. Provide params.psbt.',\n );\n }\n // TODO: Implement PSBT signing when the Ledger BTC signer kit supports it.\n return failure(\n HardwareErrorCode.MethodNotSupported,\n 'BTC transaction signing via PSBT is not yet implemented for Ledger.',\n );\n }\n\n async btcSignMessage(\n _connectId: string,\n _deviceId: string,\n _params: BtcSignMsgParams,\n ): Promise<Response<BtcSignature>> {\n return failure(\n HardwareErrorCode.MethodNotSupported,\n 'BTC message signing is not yet supported on Ledger.',\n );\n }\n\n // ---------------------------------------------------------------------------\n // Device fingerprint\n // ---------------------------------------------------------------------------\n\n async btcGetMasterFingerprint(\n connectId: string,\n _deviceId: string,\n params?: { skipOpenApp?: boolean },\n ): Promise<Response<{ masterFingerprint: string }>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'btcGetMasterFingerprint', {\n skipOpenApp: params?.skipOpenApp,\n }) as { masterFingerprint: string };\n\n return success({ masterFingerprint: result.masterFingerprint });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Solana methods (stubs -- not yet supported)\n // ---------------------------------------------------------------------------\n\n async solGetAddress(\n _connectId: string,\n _deviceId: string,\n _params: SolGetAddressParams,\n ): Promise<Response<SolAddress>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana not supported on Ledger yet');\n }\n\n async solGetAddresses(\n _connectId: string,\n _deviceId: string,\n _params: SolGetAddressParams[],\n _onProgress?: ProgressCallback,\n ): Promise<Response<SolAddress[]>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana not supported on Ledger yet');\n }\n\n async solGetPublicKey(\n _connectId: string,\n _deviceId: string,\n _params: SolGetPublicKeyParams,\n ): Promise<Response<SolPublicKey>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana not supported on Ledger yet');\n }\n\n async solSignTransaction(\n _connectId: string,\n _deviceId: string,\n _params: SolSignTxParams,\n ): Promise<Response<SolSignedTx>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana not supported on Ledger yet');\n }\n\n async solSignMessage(\n _connectId: string,\n _deviceId: string,\n _params: SolSignMsgParams,\n ): Promise<Response<SolSignature>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana signMessage is not supported on Ledger yet');\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Ensure at least one device is connected and return a valid connectId.\n *\n * - If a session already exists for the given connectId, reuse it.\n * - If ANY session exists (Ledger IDs are ephemeral), reuse it.\n * - Otherwise: search → 1 device: auto-connect, multiple: ask user, 0: throw.\n */\n private async ensureConnected(connectId?: string): Promise<string> {\n // 1. Exact match\n if (connectId && this._sessions.has(connectId)) {\n return connectId;\n }\n\n // 2. Any existing session (Ledger IDs are temporary, any session is fine)\n if (this._sessions.size > 0) {\n return this._sessions.keys().next().value!;\n }\n\n // 3. No session — search and connect\n const devices = await this.searchDevices();\n\n if (devices.length === 0) {\n throw Object.assign(\n new Error('No Ledger device found. Make sure the device is connected via USB and ready.'),\n { _tag: 'DeviceNotRecognizedError' },\n );\n }\n\n if (devices.length === 1) {\n const result = await this.connectDevice(devices[0].connectId);\n if (!result.success) {\n throw Object.assign(\n new Error(result.payload.error),\n { _tag: 'DeviceNotRecognizedError' },\n );\n }\n return devices[0].connectId;\n }\n\n // Multiple devices — ask user via UI handler\n if (this._uiHandler?.onSelectDevice) {\n const selectedConnectId = await this._uiHandler.onSelectDevice(devices);\n const result = await this.connectDevice(selectedConnectId);\n if (!result.success) {\n throw Object.assign(\n new Error(result.payload.error),\n { _tag: 'DeviceNotRecognizedError' },\n );\n }\n return selectedConnectId;\n }\n\n // No UI handler — fall back to first device\n const result = await this.connectDevice(devices[0].connectId);\n if (!result.success) {\n throw Object.assign(\n new Error(result.payload.error),\n { _tag: 'DeviceNotRecognizedError' },\n );\n }\n return devices[0].connectId;\n }\n\n /**\n * Call the connector with automatic session resolution and disconnect retry.\n *\n * 1. Resolves a valid connectId via ensureConnected()\n * 2. Looks up sessionId from _sessions\n * 3. Calls connector.call()\n * 4. On disconnect error: clears stale session, re-connects, retries once\n */\n private async connectorCall(\n connectId: string,\n method: string,\n params: unknown,\n ): Promise<unknown> {\n const resolvedConnectId = await this.ensureConnected(connectId);\n const sessionId = this._sessions.get(resolvedConnectId);\n if (!sessionId) {\n throw Object.assign(\n new Error('Auto-connect succeeded but no session found'),\n { _tag: 'DeviceSessionNotFound' },\n );\n }\n\n try {\n return await this.connector.call(sessionId, method, params);\n } catch (err) {\n if (isDeviceDisconnectedError(err)) {\n // Clear stale session and retry with fresh connection\n this._sessions.delete(resolvedConnectId);\n this._discoveredDevices.clear();\n const retryConnectId = await this.ensureConnected();\n const retrySessionId = this._sessions.get(retryConnectId);\n if (!retrySessionId) {\n throw err;\n }\n return this.connector.call(retrySessionId, method, params);\n }\n throw err;\n }\n }\n\n /**\n * Ensure device permission before proceeding.\n * - No connectId (searchDevices): check environment-level permission\n * - With connectId (business methods): check device-level permission\n * If not granted, calls onDevicePermission so the consumer can request access.\n */\n private async _ensureDevicePermission(connectId?: string, deviceId?: string): Promise<void> {\n const transportType: TransportType = 'hid';\n let granted = false;\n let context: Record<string, unknown> | undefined;\n\n if (this._uiHandler?.checkDevicePermission) {\n try {\n const result = await this._uiHandler.checkDevicePermission({ transportType, connectId, deviceId });\n granted = result.granted;\n context = result.context;\n } catch {\n granted = false;\n }\n }\n\n if (!granted) {\n try {\n await this._uiHandler?.onDevicePermission?.({ transportType, context });\n } catch {\n // UI handler cancelled or failed\n }\n }\n }\n\n /**\n * Convert a thrown error to a Response failure.\n * Uses mapLedgerError to parse Ledger DMK error codes into HardwareErrorCode values.\n */\n private errorToFailure<T>(err: unknown): Response<T> {\n console.error('[LedgerAdapter] error:', err);\n const mapped = mapLedgerError(err);\n\n // Emit a UI event for locked-device so callers can prompt the user\n if (mapped.code === HardwareErrorCode.DeviceLocked) {\n this.emitter.emit(UI_REQUEST.REQUEST_BUTTON, {\n type: UI_REQUEST.REQUEST_BUTTON,\n payload: {\n device: this.unknownDevice(),\n code: 'ButtonRequest_Other',\n },\n });\n }\n\n return failure(mapped.code, mapped.message);\n }\n\n /**\n * Generic batch call with progress reporting.\n * If any single call fails, returns the failure immediately.\n */\n private async batchCall<TParam, TResult>(\n params: TParam[],\n callFn: (p: TParam) => Promise<Response<TResult>>,\n onProgress?: ProgressCallback,\n ): Promise<Response<TResult[]>> {\n const results: TResult[] = [];\n for (let i = 0; i < params.length; i++) {\n const result = await callFn(params[i]);\n if (!result.success) {\n return result;\n }\n results.push(result.payload);\n onProgress?.({ index: i, total: params.length });\n }\n return success(results);\n }\n\n // ---------------------------------------------------------------------------\n // Event translation\n // ---------------------------------------------------------------------------\n\n private deviceConnectHandler = (data: { device: ConnectorDevice }): void => {\n const deviceInfo = this.connectorDeviceToDeviceInfo(data.device);\n this._discoveredDevices.set(deviceInfo.connectId, deviceInfo);\n this.emitter.emit(DEVICE.CONNECT, {\n type: DEVICE.CONNECT,\n payload: deviceInfo,\n });\n };\n\n private deviceDisconnectHandler = (data: { connectId: string }): void => {\n this._discoveredDevices.delete(data.connectId);\n this._sessions.delete(data.connectId);\n this.emitter.emit(DEVICE.DISCONNECT, {\n type: DEVICE.DISCONNECT,\n payload: { connectId: data.connectId },\n });\n };\n\n private uiRequestHandler = (data: { type: string; payload?: unknown }): void => {\n this.handleUiEvent(data);\n };\n\n private uiEventHandler = (data: { type: string; payload?: unknown }): void => {\n this.handleUiEvent(data);\n };\n\n private registerEventListeners(): void {\n this.connector.on('device-connect', this.deviceConnectHandler);\n this.connector.on('device-disconnect', this.deviceDisconnectHandler);\n this.connector.on('ui-request', this.uiRequestHandler);\n this.connector.on('ui-event', this.uiEventHandler);\n }\n\n private unregisterEventListeners(): void {\n this.connector.off('device-connect', this.deviceConnectHandler);\n this.connector.off('device-disconnect', this.deviceDisconnectHandler);\n this.connector.off('ui-request', this.uiRequestHandler);\n this.connector.off('ui-event', this.uiEventHandler);\n }\n\n private handleUiEvent(event: { type: string; payload?: unknown }): void {\n if (!event.type) return;\n\n const payload = event.payload as Record<string, unknown> | undefined;\n const deviceInfo = payload\n ? this.extractDeviceInfoFromPayload(payload)\n : this.unknownDevice();\n\n switch (event.type) {\n case 'ui-request_confirmation':\n this.emitter.emit(UI_REQUEST.REQUEST_BUTTON, {\n type: UI_REQUEST.REQUEST_BUTTON,\n payload: { device: deviceInfo },\n });\n break;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Device info mapping\n // ---------------------------------------------------------------------------\n\n private connectorDeviceToDeviceInfo(device: ConnectorDevice): DeviceInfo {\n return {\n vendor: 'ledger',\n model: device.model ?? 'unknown',\n firmwareVersion: '',\n deviceId: device.deviceId,\n connectId: device.connectId,\n label: device.name,\n connectionType: 'usb' as ConnectionType,\n capabilities: device.capabilities,\n };\n }\n\n private extractDeviceInfoFromPayload(payload: Record<string, unknown>): DeviceInfo {\n return {\n vendor: 'ledger',\n model: (payload['model'] as string) ?? 'unknown',\n firmwareVersion: '',\n deviceId: (payload['deviceId'] as string) ?? (payload['id'] as string) ?? '',\n connectId: (payload['connectId'] as string) ?? (payload['path'] as string) ?? '',\n label: (payload['label'] as string),\n connectionType: 'usb' as ConnectionType,\n };\n }\n\n private unknownDevice(): DeviceInfo {\n return {\n vendor: 'ledger',\n model: 'unknown',\n firmwareVersion: '',\n deviceId: '',\n connectId: '',\n connectionType: 'usb',\n };\n }\n}\n","import { HardwareErrorCode } from '@bytezhang/hardware-wallet-core';\n\n/**\n * DMK locked device status codes:\n * 0x5515 (21781) — primary locked response\n * 0x6982 (27010) — security status not satisfied\n * 0x5303 (21251) — tertiary locked response\n */\nconst LOCKED_ERROR_CODES = new Set(['5515', '21781', '6982', '27010', '5303', '21251']);\n\n/**\n * DMK user-rejected status codes:\n * 0x6985 (27013) — conditions of use not satisfied (user denied on device)\n */\nconst USER_REJECTED_CODES = new Set(['6985', '27013']);\n\n/**\n * DMK wrong-app / CLA-not-supported status codes:\n * 0x6e00 (28160) — CLA not supported (wrong app open)\n * 0x6d00 (27904) — INS not supported (wrong app or outdated app)\n */\nconst WRONG_APP_CODES = new Set(['6e00', '28160', '6d00', '27904']);\n\n/** Check if an error (or any error in its chain) represents a locked Ledger device. */\nexport function isDeviceLockedError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e.errorCode != null && LOCKED_ERROR_CODES.has(String(e.errorCode))) return true;\n if (e.statusCode != null && LOCKED_ERROR_CODES.has(String(e.statusCode))) return true;\n if (e._tag === 'DeviceLockedError') return true;\n if (typeof e.message === 'string' && /locked/i.test(e.message)) return true;\n if (e.originalError != null && isDeviceLockedError(e.originalError)) return true;\n if (e.error != null && e._tag && isDeviceLockedError(e.error)) return true;\n return false;\n}\n\n/** Check if a status/error code exists in the given set, crawling the error chain. */\nfunction hasStatusCode(err: unknown, codeSet: Set<string>): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e.errorCode != null && codeSet.has(String(e.errorCode))) return true;\n if (e.statusCode != null && codeSet.has(String(e.statusCode))) return true;\n if (e.originalError != null && hasStatusCode(e.originalError, codeSet)) return true;\n if (e.error != null && e._tag && hasStatusCode(e.error, codeSet)) return true;\n return false;\n}\n\n/** Check for user rejection (denied on device). */\nexport function isUserRejectedError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e._tag === 'UserRefusedOnDevice') return true;\n if (typeof e.message === 'string' && /denied|rejected|refused/i.test(e.message)) return true;\n if (hasStatusCode(err, USER_REJECTED_CODES)) return true;\n return false;\n}\n\n/** Check for wrong app open on the device. */\nexport function isWrongAppError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e._tag === 'WrongAppOpenedError' || e._tag === 'InvalidStatusWordError') {\n if (hasStatusCode(err, WRONG_APP_CODES)) return true;\n }\n if (typeof e.message === 'string' && /wrong app|open the .* app|CLA not supported/i.test(e.message)) return true;\n if (hasStatusCode(err, WRONG_APP_CODES)) return true;\n return false;\n}\n\n/** Check for device disconnected errors. */\nexport function isDeviceDisconnectedError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e._tag === 'DeviceNotRecognizedError' || e._tag === 'DeviceSessionNotFound') return true;\n if (typeof e.message === 'string' && /disconnected|not found|no device|unplugged|session.*not.*found/i.test(e.message)) return true;\n return false;\n}\n\n/** Check for timeout errors. */\nexport function isTimeoutError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (typeof e.message === 'string' && /timeout|timed?\\s*out/i.test(e.message)) return true;\n if (e._tag === 'DeviceExchangeTimeoutError') return true;\n return false;\n}\n\n/**\n * Map a Ledger DMK error to a HardwareErrorCode and human-readable message\n * with actionable recovery information for the caller.\n */\nexport function mapLedgerError(err: unknown): { code: HardwareErrorCode; message: string } {\n // Order matters: check more specific errors first\n\n if (isDeviceLockedError(err)) {\n return {\n code: HardwareErrorCode.DeviceLocked,\n message: 'Device is locked. Please unlock your Ledger device and try again.',\n };\n }\n\n if (isUserRejectedError(err)) {\n return {\n code: HardwareErrorCode.UserRejected,\n message: 'User rejected the request on the device.',\n };\n }\n\n if (isWrongAppError(err)) {\n return {\n code: HardwareErrorCode.WrongApp,\n message: 'Wrong app is open on the Ledger device. Please open the correct app (e.g. Ethereum) and try again.',\n };\n }\n\n if (isDeviceDisconnectedError(err)) {\n return {\n code: HardwareErrorCode.DeviceDisconnected,\n message: 'Ledger device was disconnected. Please reconnect the device and try again.',\n };\n }\n\n if (isTimeoutError(err)) {\n return {\n code: HardwareErrorCode.OperationTimeout,\n message: 'Operation timed out. Please ensure the Ledger device is connected and responsive.',\n };\n }\n\n // Fallback: extract whatever message we can\n let message = 'Unknown Ledger error';\n if (err instanceof Error) {\n message = err.message;\n } else if (err && typeof err === 'object') {\n const e = err as Record<string, unknown>;\n message = String(e.message ?? e._tag ?? e.type ?? JSON.stringify(err));\n }\n return { code: HardwareErrorCode.UnknownError, message };\n}\n","import type { DeviceDescriptor, DeviceChangeEvent } from '@bytezhang/hardware-wallet-core';\nimport type { IDmk, DmkDiscoveredDevice } from '../types';\n\n/**\n * Manages device discovery, connection, and session tracking.\n * Wraps DMK's Observable APIs into simpler imperative calls.\n */\nexport class LedgerDeviceManager {\n private readonly _dmk: IDmk;\n private readonly _discovered = new Map<string, DmkDiscoveredDevice>();\n private readonly _sessions = new Map<string, string>(); // deviceId → sessionId\n private readonly _sessionToDevice = new Map<string, string>(); // sessionId → deviceId\n private _listenSub: { unsubscribe: () => void } | null = null;\n\n constructor(dmk: IDmk) {\n this._dmk = dmk;\n }\n\n /**\n * One-shot enumeration: subscribe to listenToAvailableDevices,\n * take the first emission, unsubscribe, return DeviceDescriptors.\n */\n enumerate(): Promise<DeviceDescriptor[]> {\n return new Promise<DeviceDescriptor[]>((resolve) => {\n let resolved = false;\n let sub: { unsubscribe: () => void } | null = null;\n\n sub = this._dmk.listenToAvailableDevices().subscribe({\n next: (devices) => {\n if (resolved) return;\n resolved = true;\n this._discovered.clear();\n for (const d of devices) {\n this._discovered.set(d.id, d);\n }\n if (sub) {\n sub.unsubscribe();\n } else {\n // BehaviorSubject fires synchronously before subscribe() returns\n Promise.resolve().then(() => sub?.unsubscribe());\n }\n console.log('[LedgerDeviceManager] enumerate devices:', JSON.stringify(devices.map(d => ({\n id: d.id,\n deviceModel: d.deviceModel,\n name: (d as any).name,\n }))));\n resolve(devices.map(d => ({ path: d.id, type: d.deviceModel.name })));\n },\n error: () => {\n if (resolved) return;\n resolved = true;\n sub?.unsubscribe();\n resolve([]);\n },\n });\n });\n }\n\n /**\n * Continuous listening: tracks device connect/disconnect via diffing.\n */\n listen(onChange: (event: DeviceChangeEvent) => void): void {\n this.stopListening();\n let previousIds = new Set<string>();\n\n this._listenSub = this._dmk.listenToAvailableDevices().subscribe({\n next: (devices) => {\n const currentIds = new Set(devices.map(d => d.id));\n\n for (const d of devices) {\n this._discovered.set(d.id, d);\n console.log('[LedgerDeviceManager] listen device:', JSON.stringify({\n id: d.id,\n deviceModel: d.deviceModel,\n name: (d as any).name,\n }));\n if (!previousIds.has(d.id)) {\n onChange({ type: 'device-connected', descriptor: { path: d.id, type: d.deviceModel.name } });\n }\n }\n for (const id of previousIds) {\n if (!currentIds.has(id)) {\n this._discovered.delete(id);\n onChange({ type: 'device-disconnected', descriptor: { path: id } });\n }\n }\n previousIds = currentIds;\n },\n });\n }\n\n stopListening(): void {\n this._listenSub?.unsubscribe();\n this._listenSub = null;\n }\n\n /**\n * Trigger browser device selection (WebHID requestDevice).\n * Starts discovery for a short period, then stops.\n */\n requestDevice(timeoutMs = 3000): Promise<void> {\n return new Promise<void>((resolve) => {\n const sub = this._dmk.startDiscovering().subscribe({\n next: (d) => { this._discovered.set(d.id, d); },\n error: () => { sub.unsubscribe(); resolve(); },\n });\n setTimeout(() => {\n sub.unsubscribe();\n this._dmk.stopDiscovering();\n resolve();\n }, timeoutMs);\n });\n }\n\n /** Connect to a previously discovered device. Returns sessionId. */\n async connect(deviceId: string): Promise<string> {\n const device = this._discovered.get(deviceId);\n if (!device) {\n throw new Error(`Device \"${deviceId}\" not found. Call enumerate() or listen() first.`);\n }\n const sessionId = await this._dmk.connect({ device });\n this._sessions.set(deviceId, sessionId);\n this._sessionToDevice.set(sessionId, deviceId);\n return sessionId;\n }\n\n /** Disconnect a session. */\n async disconnect(sessionId: string): Promise<void> {\n await this._dmk.disconnect({ sessionId });\n const deviceId = this._sessionToDevice.get(sessionId);\n if (deviceId) this._sessions.delete(deviceId);\n this._sessionToDevice.delete(sessionId);\n }\n\n getSessionId(deviceId: string): string | undefined {\n return this._sessions.get(deviceId);\n }\n\n getDeviceId(sessionId: string): string | undefined {\n return this._sessionToDevice.get(sessionId);\n }\n\n /** Get the underlying DMK instance (needed by SignerManager). */\n getDmk(): IDmk {\n return this._dmk;\n }\n\n dispose(): void {\n this.stopListening();\n this._discovered.clear();\n this._sessions.clear();\n this._sessionToDevice.clear();\n this._dmk.close?.();\n }\n}\n","/** DeviceAction state emitted by DMK signer operations. */\ninterface DeviceActionState<T> {\n status: 'pending' | 'completed' | 'error';\n output?: T;\n error?: unknown;\n intermediateValue?: {\n requiredUserInteraction?: string;\n [key: string]: unknown;\n };\n}\n\n/**\n * Convert a DMK DeviceAction (Observable-based) into a Promise.\n * Handles pending → completed/error state transitions and interaction callbacks.\n */\nexport function deviceActionToPromise<T>(\n action: {\n observable: {\n subscribe(observer: {\n next: (value: DeviceActionState<T>) => void;\n error?: (err: unknown) => void;\n complete?: () => void;\n }): { unsubscribe: () => void };\n };\n },\n onInteraction?: (interaction: string) => void,\n): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n let settled = false;\n let sub: { unsubscribe: () => void };\n\n sub = action.observable.subscribe({\n next: (state) => {\n if (settled) return;\n if (state.status === 'completed') {\n settled = true;\n sub?.unsubscribe();\n resolve(state.output as T);\n } else if (state.status === 'error') {\n settled = true;\n sub?.unsubscribe();\n reject(state.error);\n } else if (state.status === 'pending' && onInteraction) {\n const interaction = state.intermediateValue?.requiredUserInteraction;\n if (interaction && interaction !== 'none') {\n onInteraction(interaction);\n }\n }\n },\n error: (err: unknown) => {\n if (!settled) {\n settled = true;\n sub?.unsubscribe();\n reject(err);\n }\n },\n complete: () => {\n if (!settled) {\n settled = true;\n reject(new Error('Device action completed without result'));\n }\n },\n });\n });\n}\n","import type { SignerEvmAddress, SignerEvmSignature } from '../types';\nimport { deviceActionToPromise } from './deviceActionToPromise';\n\n/**\n * SDK signer interface — duck-typed to avoid hard dependency on\n * @ledgerhq/device-signer-kit-ethereum.\n */\nexport interface ISdkSignerEth {\n getAddress(derivationPath: string, options?: { checkOnDevice?: boolean }): unknown;\n signTransaction(derivationPath: string, transaction: Uint8Array, options?: unknown): unknown;\n signMessage(derivationPath: string, message: string): unknown;\n signTypedData(derivationPath: string, data: unknown): unknown;\n}\n\n/** Convert hex string (with or without 0x) to Uint8Array. */\nfunction hexToBytes(hex: string): Uint8Array {\n const h = hex.startsWith('0x') ? hex.slice(2) : hex;\n const bytes = new Uint8Array(h.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(h.substring(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\n/**\n * Wraps Ledger's SDK signer (Observable-based DeviceActions) into\n * a simple async interface returning plain serializable data.\n */\nexport class SignerEth {\n onInteraction?: (interaction: string) => void;\n\n constructor(private readonly _sdk: ISdkSignerEth) {}\n\n async getAddress(\n derivationPath: string,\n options?: { checkOnDevice?: boolean }\n ): Promise<SignerEvmAddress> {\n const action = this._sdk.getAddress(derivationPath, {\n checkOnDevice: options?.checkOnDevice ?? false,\n });\n return deviceActionToPromise<SignerEvmAddress>(action as any, this.onInteraction);\n }\n\n async signTransaction(\n derivationPath: string,\n serializedTxHex: string\n ): Promise<SignerEvmSignature> {\n const action = this._sdk.signTransaction(derivationPath, hexToBytes(serializedTxHex));\n return deviceActionToPromise<SignerEvmSignature>(action as any, this.onInteraction);\n }\n\n async signMessage(derivationPath: string, message: string): Promise<SignerEvmSignature> {\n const action = this._sdk.signMessage(derivationPath, message);\n return deviceActionToPromise<SignerEvmSignature>(action as any, this.onInteraction);\n }\n\n async signTypedData(derivationPath: string, data: unknown): Promise<SignerEvmSignature> {\n const action = this._sdk.signTypedData(derivationPath, data);\n return deviceActionToPromise<SignerEvmSignature>(action as any, this.onInteraction);\n }\n}\n","import type { IDmk } from '../types';\nimport { SignerEth } from './SignerEth';\n\ntype SignerEthBuilderFn = (args: { dmk: IDmk; sessionId: string }) => { build(): unknown } | Promise<{ build(): unknown }>;\n\n/**\n * Manages per-sessionId SignerEth instances.\n * Creates on demand, caches for reuse, invalidates on session change.\n */\nexport class SignerManager {\n private readonly _cache = new Map<string, SignerEth>();\n private readonly _dmk: IDmk;\n private readonly _builderFn: SignerEthBuilderFn;\n\n constructor(dmk: IDmk, builderFn?: SignerEthBuilderFn) {\n this._dmk = dmk;\n this._builderFn = builderFn ?? SignerManager._defaultBuilder();\n }\n\n async getOrCreate(sessionId: string): Promise<SignerEth> {\n let signer = this._cache.get(sessionId);\n if (signer) return signer;\n\n const builder = await this._builderFn({ dmk: this._dmk, sessionId });\n const sdkSigner = builder.build();\n signer = new SignerEth(sdkSigner as any);\n this._cache.set(sessionId, signer);\n return signer;\n }\n\n invalidate(sessionId: string): void {\n this._cache.delete(sessionId);\n }\n\n clearAll(): void {\n this._cache.clear();\n }\n\n private static _defaultBuilder(): SignerEthBuilderFn {\n let BuilderClass: any = null;\n return async (args) => {\n if (!BuilderClass) {\n const mod = await import('@ledgerhq/device-signer-kit-ethereum');\n BuilderClass = mod.SignerEthBuilder;\n }\n return new BuilderClass(args);\n };\n }\n}\n","import type { SignerBtcAddress } from '../types';\nimport { deviceActionToPromise } from './deviceActionToPromise';\n\n/**\n * SDK BTC signer interface — duck-typed to avoid hard dependency on\n * @ledgerhq/device-signer-kit-bitcoin.\n */\nexport interface ISdkSignerBtc {\n getExtendedPublicKey(derivationPath: string, options?: { checkOnDevice?: boolean }): unknown;\n getWalletAddress(wallet: unknown, addressIndex: number, options?: { checkOnDevice?: boolean; change?: boolean }): unknown;\n getMasterFingerprint(options?: { skipOpenApp?: boolean }): unknown;\n}\n\n/**\n * Wraps Ledger's BTC SDK signer (Observable-based DeviceActions) into\n * a simple async interface returning plain serializable data.\n */\nexport class SignerBtc {\n onInteraction?: (interaction: string) => void;\n\n constructor(private readonly _sdk: ISdkSignerBtc) {}\n\n async getWalletAddress(\n wallet: unknown,\n addressIndex: number,\n options?: { checkOnDevice?: boolean; change?: boolean },\n ): Promise<SignerBtcAddress> {\n const action = this._sdk.getWalletAddress(wallet, addressIndex, {\n checkOnDevice: options?.checkOnDevice ?? false,\n change: options?.change ?? false,\n });\n return deviceActionToPromise<SignerBtcAddress>(action as any, this.onInteraction);\n }\n\n async getExtendedPublicKey(\n derivationPath: string,\n options?: { checkOnDevice?: boolean },\n ): Promise<string> {\n const action = this._sdk.getExtendedPublicKey(derivationPath, {\n checkOnDevice: options?.checkOnDevice ?? false,\n });\n return deviceActionToPromise<string>(action as any, this.onInteraction);\n }\n\n async getMasterFingerprint(\n options?: { skipOpenApp?: boolean },\n ): Promise<Uint8Array> {\n const action = this._sdk.getMasterFingerprint(options);\n const result = await deviceActionToPromise<{ masterFingerprint: Uint8Array }>(action as any, this.onInteraction);\n return result.masterFingerprint;\n }\n}\n","import type { IDmk } from '../types';\n\n/**\n * Map of chain ticker symbols to the Ledger app name\n * that must be open to sign transactions for that chain.\n */\nexport const APP_NAME_MAP: Record<string, string> = {\n ETH: 'Ethereum',\n BTC: 'Bitcoin',\n SOL: 'Solana',\n TRX: 'Tron',\n XRP: 'XRP',\n ADA: 'Cardano',\n DOT: 'Polkadot',\n ATOM: 'Cosmos',\n};\n\n/** The name reported by the Ledger when it sits on the home screen. */\nconst DASHBOARD_APP_NAME = 'BOLOS';\n\ninterface AppManagerOptions {\n waitMs?: number;\n maxRetries?: number;\n}\n\n/**\n * Orchestrates opening / closing Ledger on-device apps so that the\n * correct signer application is running before any signing call.\n */\nexport class AppManager {\n private readonly _dmk: IDmk;\n private readonly _waitMs: number;\n private readonly _maxRetries: number;\n\n constructor(dmk: IDmk, options?: AppManagerOptions) {\n this._dmk = dmk;\n this._waitMs = options?.waitMs ?? 1000;\n this._maxRetries = options?.maxRetries ?? 10;\n }\n\n /**\n * Return the Ledger app name for a given chain ticker,\n * or undefined if the chain is not supported.\n */\n static getAppName(chain: string): string | undefined {\n return APP_NAME_MAP[chain];\n }\n\n /**\n * Ensure the target app is open on the device identified by `sessionId`.\n *\n * Flow:\n * 1. Check the currently running app.\n * 2. If it is already the target, return immediately.\n * 3. If a different app is running (not dashboard), close it first.\n * 4. Open the target app.\n * 5. Poll until the device confirms the target app is running.\n */\n async ensureAppOpen(sessionId: string, targetAppName: string): Promise<void> {\n const currentApp = await this._getCurrentApp(sessionId);\n\n if (currentApp === targetAppName) {\n return;\n }\n\n // If we're not on the dashboard, close the current app first\n if (!this._isDashboard(currentApp)) {\n await this._closeCurrentApp(sessionId);\n // Wait for dashboard to become active\n await this._waitForApp(sessionId, DASHBOARD_APP_NAME);\n }\n\n // Open the target app\n await this._openApp(sessionId, targetAppName);\n\n // Poll until the target app is confirmed open\n await this._waitForApp(sessionId, targetAppName);\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private async _getCurrentApp(sessionId: string): Promise<string> {\n const result = (await this._dmk.sendCommand({\n sessionId,\n command: { type: 'get-app-and-version' },\n })) as { name: string };\n return result.name;\n }\n\n private async _openApp(sessionId: string, appName: string): Promise<void> {\n await this._dmk.sendCommand({\n sessionId,\n command: { type: 'open-app', appName },\n });\n }\n\n private async _closeCurrentApp(sessionId: string): Promise<void> {\n await this._dmk.sendCommand({\n sessionId,\n command: { type: 'close-app' },\n });\n }\n\n /**\n * Poll the device until the expected app is reported as running,\n * or throw after `_maxRetries` attempts.\n */\n private async _waitForApp(sessionId: string, expectedAppName: string): Promise<void> {\n for (let i = 0; i < this._maxRetries; i++) {\n await this._wait();\n const current = await this._getCurrentApp(sessionId);\n if (current === expectedAppName) {\n return;\n }\n }\n throw new Error(\n `Ledger: failed to open \"${expectedAppName}\" after ${this._maxRetries} retries`\n );\n }\n\n private _isDashboard(appName: string): boolean {\n return appName === DASHBOARD_APP_NAME;\n }\n\n private _wait(): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, this._waitMs));\n }\n}\n"],"mappings":"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","names":["HardwareErrorCode","HardwareErrorCode","result"]}
1
+ {"version":3,"sources":["../src/adapter/LedgerAdapter.ts","../src/errors.ts","../src/device/LedgerDeviceManager.ts","../src/signer/deviceActionToPromise.ts","../src/signer/SignerEth.ts","../src/signer/SignerManager.ts","../src/signer/SignerBtc.ts","../src/app/AppManager.ts"],"sourcesContent":["import type {\n IHardwareWallet,\n IUiHandler,\n IConnector,\n ConnectorDevice,\n DeviceInfo,\n HardwareEventMap,\n DeviceEventListener,\n TransportType,\n ConnectionType,\n Response,\n EvmGetAddressParams,\n EvmAddress,\n EvmGetPublicKeyParams,\n EvmPublicKey,\n EvmSignTxParams,\n EvmSignedTx,\n EvmSignMsgParams,\n EvmSignTypedDataParams,\n EvmSignature,\n ProgressCallback,\n BtcGetAddressParams,\n BtcAddress,\n BtcGetPublicKeyParams,\n BtcPublicKey,\n BtcSignTxParams,\n BtcSignedTx,\n BtcSignMsgParams,\n BtcSignature,\n SolGetAddressParams,\n SolAddress,\n SolGetPublicKeyParams,\n SolPublicKey,\n SolSignTxParams,\n SolSignedTx,\n SolSignMsgParams,\n SolSignature,\n ChainCapability,\n} from '@bytezhang/hardware-wallet-core';\nimport {\n success,\n failure,\n HardwareErrorCode,\n TypedEventEmitter,\n DEVICE,\n UI_REQUEST,\n} from '@bytezhang/hardware-wallet-core';\nimport { mapLedgerError, isDeviceDisconnectedError } from '../errors';\n\n/** Ensure a hex string has the `0x` prefix. */\nfunction ensure0x(hex: string): string {\n return hex.startsWith('0x') ? hex : `0x${hex}`;\n}\n\n/** Remove `0x` prefix from a hex string if present. */\nfunction stripHex(hex: string): string {\n return hex.startsWith('0x') ? hex.slice(2) : hex;\n}\n\n/** Ensure a hex string is `0x`-prefixed and zero-padded to 64 hex chars (32 bytes). */\nfunction padHex64(hex: string): string {\n return `0x${stripHex(hex).padStart(64, '0')}`;\n}\n\n/**\n * Ledger hardware wallet adapter that delegates to an IConnector.\n *\n * This is a thin translation layer that:\n * - Accepts a pre-configured IConnector (transport decisions are made at connector creation time)\n * - Translates IHardwareWallet method calls to connector.call() invocations\n * - Maps connector results/errors to our Response<T> format with enriched error messages\n * - Translates connector events to HardwareEventMap events\n * - Integrates with IUiHandler for permission flows\n */\nexport class LedgerAdapter implements IHardwareWallet {\n readonly vendor = 'ledger' as const;\n\n private readonly connector: IConnector;\n private readonly emitter = new TypedEventEmitter<HardwareEventMap>();\n\n private _uiHandler: Partial<IUiHandler> | null = null;\n\n // Device cache: tracks discovered devices from connector events\n private _discoveredDevices = new Map<string, DeviceInfo>();\n\n // Session tracking: maps connectId -> sessionId\n private _sessions = new Map<string, string>();\n\n constructor(connector: IConnector) {\n this.connector = connector;\n this.registerEventListeners();\n }\n\n // ---------------------------------------------------------------------------\n // Transport\n // ---------------------------------------------------------------------------\n // Transport is decided at connector creation time. These methods\n // satisfy the IHardwareWallet interface with sensible defaults.\n\n get activeTransport(): TransportType | null {\n return 'hid';\n }\n\n getAvailableTransports(): TransportType[] {\n return ['hid'];\n }\n\n async switchTransport(_type: TransportType): Promise<void> {\n // Transport is fixed at connector creation time.\n // To switch transport, create a new LedgerAdapter with a different connector.\n }\n\n // ---------------------------------------------------------------------------\n // UI handler\n // ---------------------------------------------------------------------------\n\n setUiHandler(handler: Partial<IUiHandler>): void {\n this._uiHandler = handler;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n async init(_config?: unknown): Promise<void> {\n // Connector is injected via constructor, already initialized.\n // Nothing to do here.\n }\n\n async dispose(): Promise<void> {\n this.unregisterEventListeners();\n this.connector.reset();\n this._uiHandler = null;\n this._discoveredDevices.clear();\n this._sessions.clear();\n this.emitter.removeAllListeners();\n }\n\n // ---------------------------------------------------------------------------\n // Device management\n // ---------------------------------------------------------------------------\n\n async searchDevices(): Promise<DeviceInfo[]> {\n await this._ensureDevicePermission();\n\n const devices = await this.connector.searchDevices();\n console.log('[LedgerAdapter] connector.searchDevices raw:', JSON.stringify(devices));\n\n for (const d of devices) {\n if (d.connectId && !this._discoveredDevices.has(d.connectId)) {\n this._discoveredDevices.set(d.connectId, this.connectorDeviceToDeviceInfo(d));\n }\n }\n\n // If no devices found, ensure permission (no connectId = search context)\n if (this._discoveredDevices.size === 0) {\n await this._ensureDevicePermission();\n }\n\n return Array.from(this._discoveredDevices.values());\n }\n\n async connectDevice(connectId: string): Promise<Response<string>> {\n await this._ensureDevicePermission(connectId);\n try {\n const session = await this.connector.connect(connectId);\n this._sessions.set(connectId, session.sessionId);\n\n // Update device cache with richer info from session\n if (session.deviceInfo) {\n this._discoveredDevices.set(connectId, session.deviceInfo);\n }\n\n return success(connectId);\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async disconnectDevice(connectId: string): Promise<void> {\n const sessionId = this._sessions.get(connectId);\n if (sessionId) {\n await this.connector.disconnect(sessionId);\n this._sessions.delete(connectId);\n }\n }\n\n async getDeviceInfo(\n connectId: string,\n deviceId: string,\n ): Promise<Response<DeviceInfo>> {\n await this._ensureDevicePermission(connectId, deviceId);\n\n // Look up the device in the cache populated by event handlers / searchDevices.\n // Try connectId first (the USB path), then fall back to scanning by deviceId.\n const cached =\n this._discoveredDevices.get(connectId) ??\n Array.from(this._discoveredDevices.values()).find(\n (d) => d.deviceId === deviceId,\n );\n\n if (cached) {\n return success(cached);\n }\n\n return failure(\n HardwareErrorCode.DeviceNotFound,\n 'Device not found in cache. Call searchDevices() or wait for a device-connected event first.',\n );\n }\n\n getSupportedChains(): ChainCapability[] {\n return ['evm', 'btc', 'sol'];\n }\n\n // ---------------------------------------------------------------------------\n // Events\n // ---------------------------------------------------------------------------\n\n on<K extends keyof HardwareEventMap>(event: K, listener: (event: HardwareEventMap[K]) => void): void;\n on(event: string, listener: DeviceEventListener): void;\n on(event: string, listener: (event: any) => void): void {\n this.emitter.on(event, listener);\n }\n\n off<K extends keyof HardwareEventMap>(event: K, listener: (event: HardwareEventMap[K]) => void): void;\n off(event: string, listener: DeviceEventListener): void;\n off(event: string, listener: (event: any) => void): void {\n this.emitter.off(event, listener);\n }\n\n cancel(connectId: string): void {\n const sessionId = this._sessions.get(connectId) ?? connectId;\n void this.connector.cancel(sessionId);\n }\n\n // ---------------------------------------------------------------------------\n // EVM methods\n // ---------------------------------------------------------------------------\n\n async evmGetAddress(\n connectId: string,\n _deviceId: string,\n params: EvmGetAddressParams,\n ): Promise<Response<EvmAddress>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'evmGetAddress', {\n path: params.path,\n showOnDevice: params.showOnDevice,\n chainId: params.chainId,\n }) as { address: string; publicKey?: string; path?: string };\n\n return success({\n address: result.address,\n path: params.path,\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async evmGetAddresses(\n connectId: string,\n deviceId: string,\n params: EvmGetAddressParams[],\n onProgress?: ProgressCallback,\n ): Promise<Response<EvmAddress[]>> {\n return this.batchCall(\n params,\n (p) => this.evmGetAddress(connectId, deviceId, p),\n onProgress,\n );\n }\n\n async evmGetPublicKey(\n connectId: string,\n _deviceId: string,\n params: EvmGetPublicKeyParams,\n ): Promise<Response<EvmPublicKey>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'evmGetAddress', {\n path: params.path,\n showOnDevice: params.showOnDevice,\n }) as { address: string; publicKey: string; path?: string };\n\n return success({\n publicKey: result.publicKey,\n path: params.path,\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async evmSignTransaction(\n connectId: string,\n _deviceId: string,\n params: EvmSignTxParams,\n ): Promise<Response<EvmSignedTx>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'evmSignTransaction', {\n path: params.path,\n transaction: {\n to: params.to,\n value: params.value,\n chainId: params.chainId,\n nonce: params.nonce,\n gasLimit: params.gasLimit,\n gasPrice: params.gasPrice,\n maxFeePerGas: params.maxFeePerGas,\n maxPriorityFeePerGas: params.maxPriorityFeePerGas,\n accessList: params.accessList,\n data: params.data,\n },\n }) as { v: string; r: string; s: string; serializedTx?: string };\n\n return success({\n v: ensure0x(result.v),\n r: padHex64(result.r),\n s: padHex64(result.s),\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async evmSignMessage(\n connectId: string,\n _deviceId: string,\n params: EvmSignMsgParams,\n ): Promise<Response<EvmSignature>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'evmSignMessage', {\n path: params.path,\n message: params.message,\n }) as { signature: string; address?: string };\n\n return success({\n signature: ensure0x(result.signature),\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async evmSignTypedData(\n connectId: string,\n _deviceId: string,\n params: EvmSignTypedDataParams,\n ): Promise<Response<EvmSignature>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n // Ledger requires full EIP-712 structure — hash mode is not supported.\n if (params.mode === 'hash') {\n return failure(\n HardwareErrorCode.MethodNotSupported,\n 'Ledger does not support hash-only EIP-712 signing. Use mode \"full\" with the complete typed data structure.',\n );\n }\n\n try {\n const result = await this.connectorCall(connectId, 'evmSignTypedData', {\n path: params.path,\n data: params.data,\n }) as { signature: string; address?: string };\n\n return success({\n signature: ensure0x(result.signature),\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n // ---------------------------------------------------------------------------\n // BTC methods\n // ---------------------------------------------------------------------------\n\n async btcGetAddress(\n connectId: string,\n _deviceId: string,\n params: BtcGetAddressParams,\n ): Promise<Response<BtcAddress>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'btcGetAddress', {\n path: params.path,\n coin: params.coin,\n showOnDevice: params.showOnDevice,\n scriptType: params.scriptType,\n }) as { address: string; path: string };\n\n return success({\n address: result.address,\n path: params.path,\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async btcGetAddresses(\n connectId: string,\n deviceId: string,\n params: BtcGetAddressParams[],\n onProgress?: ProgressCallback,\n ): Promise<Response<BtcAddress[]>> {\n return this.batchCall(\n params,\n (p) => this.btcGetAddress(connectId, deviceId, p),\n onProgress,\n );\n }\n\n async btcGetPublicKey(\n connectId: string,\n _deviceId: string,\n params: BtcGetPublicKeyParams,\n ): Promise<Response<BtcPublicKey>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'btcGetPublicKey', {\n path: params.path,\n coin: params.coin,\n showOnDevice: params.showOnDevice,\n }) as {\n xpub: string;\n publicKey: string;\n fingerprint: number;\n chainCode: string;\n path: string;\n depth: number;\n };\n\n return success({\n xpub: result.xpub,\n publicKey: result.publicKey ?? '',\n fingerprint: result.fingerprint ?? 0,\n chainCode: result.chainCode ?? '',\n path: params.path,\n depth: result.depth ?? 0,\n });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n async btcSignTransaction(\n connectId: string,\n _deviceId: string,\n params: BtcSignTxParams,\n ): Promise<Response<BtcSignedTx>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n if (!params.psbt) {\n return failure(\n HardwareErrorCode.InvalidParams,\n 'Ledger requires PSBT format for BTC transaction signing. Provide params.psbt.',\n );\n }\n // TODO: Implement PSBT signing when the Ledger BTC signer kit supports it.\n return failure(\n HardwareErrorCode.MethodNotSupported,\n 'BTC transaction signing via PSBT is not yet implemented for Ledger.',\n );\n }\n\n async btcSignMessage(\n _connectId: string,\n _deviceId: string,\n _params: BtcSignMsgParams,\n ): Promise<Response<BtcSignature>> {\n return failure(\n HardwareErrorCode.MethodNotSupported,\n 'BTC message signing is not yet supported on Ledger.',\n );\n }\n\n // ---------------------------------------------------------------------------\n // Device fingerprint\n // ---------------------------------------------------------------------------\n\n async btcGetMasterFingerprint(\n connectId: string,\n _deviceId: string,\n params?: { skipOpenApp?: boolean },\n ): Promise<Response<{ masterFingerprint: string }>> {\n await this._ensureDevicePermission(connectId, _deviceId);\n try {\n const result = await this.connectorCall(connectId, 'btcGetMasterFingerprint', {\n skipOpenApp: params?.skipOpenApp,\n }) as { masterFingerprint: string };\n\n return success({ masterFingerprint: result.masterFingerprint });\n } catch (err) {\n return this.errorToFailure(err);\n }\n }\n\n // ---------------------------------------------------------------------------\n // Solana methods (stubs -- not yet supported)\n // ---------------------------------------------------------------------------\n\n async solGetAddress(\n _connectId: string,\n _deviceId: string,\n _params: SolGetAddressParams,\n ): Promise<Response<SolAddress>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana not supported on Ledger yet');\n }\n\n async solGetAddresses(\n _connectId: string,\n _deviceId: string,\n _params: SolGetAddressParams[],\n _onProgress?: ProgressCallback,\n ): Promise<Response<SolAddress[]>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana not supported on Ledger yet');\n }\n\n async solGetPublicKey(\n _connectId: string,\n _deviceId: string,\n _params: SolGetPublicKeyParams,\n ): Promise<Response<SolPublicKey>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana not supported on Ledger yet');\n }\n\n async solSignTransaction(\n _connectId: string,\n _deviceId: string,\n _params: SolSignTxParams,\n ): Promise<Response<SolSignedTx>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana not supported on Ledger yet');\n }\n\n async solSignMessage(\n _connectId: string,\n _deviceId: string,\n _params: SolSignMsgParams,\n ): Promise<Response<SolSignature>> {\n return failure(HardwareErrorCode.MethodNotSupported, 'Solana signMessage is not supported on Ledger yet');\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Ensure at least one device is connected and return a valid connectId.\n *\n * - If a session already exists for the given connectId, reuse it.\n * - If ANY session exists (Ledger IDs are ephemeral), reuse it.\n * - Otherwise: search → 1 device: auto-connect, multiple: ask user, 0: throw.\n */\n private static readonly MAX_DEVICE_RETRY = 3;\n\n // Pending device-connect resolve — set by _waitForDeviceConnect, resolved by uiResponse\n private _deviceConnectResolve: ((cancelled: boolean) => void) | null = null;\n\n private static readonly DEVICE_CONNECT_TIMEOUT_MS = 60_000;\n\n /**\n * Wait for user to connect and unlock device.\n * Emits 'ui-request' event via the adapter's own emitter.\n * The consumer (monorepo adapter wrapper) listens for this and shows UI.\n * When user confirms, they call adapter.deviceConnectResponse() which resolves this promise.\n * Times out after 60 seconds if no response is received.\n */\n private _waitForDeviceConnect(attempt: number): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n let settled = false;\n\n const timer = setTimeout(() => {\n if (!settled) {\n settled = true;\n this._deviceConnectResolve = null;\n reject(new Error('Ledger device connect timed out after 60 seconds'));\n }\n }, LedgerAdapter.DEVICE_CONNECT_TIMEOUT_MS);\n\n this._deviceConnectResolve = (cancelled: boolean) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n this._deviceConnectResolve = null;\n if (cancelled) {\n reject(new Error('User cancelled Ledger connection'));\n } else {\n resolve();\n }\n };\n\n // Emit ui-request event — consumer should show \"connect and unlock\" prompt\n this.emitter.emit('ui-request-device-connect' as any, {\n type: 'ui-request-device-connect',\n payload: {\n message: 'Please connect and unlock your Ledger device',\n retryCount: attempt,\n maxRetries: LedgerAdapter.MAX_DEVICE_RETRY,\n },\n });\n });\n }\n\n /**\n * Called by consumer to respond to ui-request-device-connect.\n * type='confirm' → retry search, type='cancel' → abort.\n */\n deviceConnectResponse(type: 'confirm' | 'cancel'): void {\n if (this._deviceConnectResolve) {\n this._deviceConnectResolve(type === 'cancel');\n }\n }\n\n private async ensureConnected(connectId?: string): Promise<string> {\n // 1. Exact match\n if (connectId && this._sessions.has(connectId)) {\n return connectId;\n }\n\n // 2. Any existing session (Ledger IDs are temporary, any session is fine)\n if (this._sessions.size > 0) {\n return this._sessions.keys().next().value!;\n }\n\n // 3. No session — search with retry + UI prompt\n for (let attempt = 0; attempt < LedgerAdapter.MAX_DEVICE_RETRY; attempt++) {\n const devices = await this.searchDevices();\n\n if (devices.length > 0) {\n // Found device(s), continue to connection below\n return this._connectFirstOrSelect(devices);\n }\n\n // No device found — prompt user (except on last attempt)\n if (attempt < LedgerAdapter.MAX_DEVICE_RETRY - 1) {\n await this._waitForDeviceConnect(attempt + 1);\n }\n }\n\n throw Object.assign(\n new Error('No Ledger device found after multiple attempts. Please connect and unlock your device.'),\n { _tag: 'DeviceNotRecognizedError' },\n );\n }\n\n private async _connectFirstOrSelect(devices: DeviceInfo[]): Promise<string> {\n if (devices.length === 1) {\n const result = await this.connectDevice(devices[0].connectId);\n if (!result.success) {\n throw Object.assign(\n new Error(result.payload.error),\n { _tag: 'DeviceNotRecognizedError' },\n );\n }\n return devices[0].connectId;\n }\n\n // Multiple devices — ask user via UI handler\n if (this._uiHandler?.onSelectDevice) {\n const selectedConnectId = await this._uiHandler.onSelectDevice(devices);\n const result = await this.connectDevice(selectedConnectId);\n if (!result.success) {\n throw Object.assign(\n new Error(result.payload.error),\n { _tag: 'DeviceNotRecognizedError' },\n );\n }\n return selectedConnectId;\n }\n\n // No UI handler — fall back to first device\n const result = await this.connectDevice(devices[0].connectId);\n if (!result.success) {\n throw Object.assign(\n new Error(result.payload.error),\n { _tag: 'DeviceNotRecognizedError' },\n );\n }\n return devices[0].connectId;\n }\n\n /**\n * Call the connector with automatic session resolution and disconnect retry.\n *\n * 1. Resolves a valid connectId via ensureConnected()\n * 2. Looks up sessionId from _sessions\n * 3. Calls connector.call()\n * 4. On disconnect error: clears stale session, re-connects, retries once\n */\n private async connectorCall(\n connectId: string,\n method: string,\n params: unknown,\n ): Promise<unknown> {\n const resolvedConnectId = await this.ensureConnected(connectId);\n const sessionId = this._sessions.get(resolvedConnectId);\n if (!sessionId) {\n throw Object.assign(\n new Error('Auto-connect succeeded but no session found'),\n { _tag: 'DeviceSessionNotFound' },\n );\n }\n\n try {\n return await this.connector.call(sessionId, method, params);\n } catch (err) {\n if (isDeviceDisconnectedError(err)) {\n // Clear stale session and retry with fresh connection\n this._sessions.delete(resolvedConnectId);\n this._discoveredDevices.clear();\n const retryConnectId = await this.ensureConnected();\n const retrySessionId = this._sessions.get(retryConnectId);\n if (!retrySessionId) {\n throw err;\n }\n return this.connector.call(retrySessionId, method, params);\n }\n throw err;\n }\n }\n\n /**\n * Ensure device permission before proceeding.\n * - No connectId (searchDevices): check environment-level permission\n * - With connectId (business methods): check device-level permission\n * If not granted, calls onDevicePermission so the consumer can request access.\n */\n private async _ensureDevicePermission(connectId?: string, deviceId?: string): Promise<void> {\n const transportType: TransportType = 'hid';\n let granted = false;\n let context: Record<string, unknown> | undefined;\n\n if (this._uiHandler?.checkDevicePermission) {\n try {\n const result = await this._uiHandler.checkDevicePermission({ transportType, connectId, deviceId });\n granted = result.granted;\n context = result.context;\n } catch {\n granted = false;\n }\n }\n\n if (!granted) {\n try {\n await this._uiHandler?.onDevicePermission?.({ transportType, context });\n } catch {\n // UI handler cancelled or failed\n }\n }\n }\n\n /**\n * Convert a thrown error to a Response failure.\n * Uses mapLedgerError to parse Ledger DMK error codes into HardwareErrorCode values.\n */\n private errorToFailure<T>(err: unknown): Response<T> {\n console.error('[LedgerAdapter] error:', err);\n const mapped = mapLedgerError(err);\n\n // Emit a UI event for locked-device so callers can prompt the user\n if (mapped.code === HardwareErrorCode.DeviceLocked) {\n this.emitter.emit(UI_REQUEST.REQUEST_BUTTON, {\n type: UI_REQUEST.REQUEST_BUTTON,\n payload: {\n device: this.unknownDevice(),\n code: 'ButtonRequest_Other',\n },\n });\n }\n\n return failure(mapped.code, mapped.message);\n }\n\n /**\n * Generic batch call with progress reporting.\n * If any single call fails, returns the failure immediately.\n */\n private async batchCall<TParam, TResult>(\n params: TParam[],\n callFn: (p: TParam) => Promise<Response<TResult>>,\n onProgress?: ProgressCallback,\n ): Promise<Response<TResult[]>> {\n const results: TResult[] = [];\n for (let i = 0; i < params.length; i++) {\n const result = await callFn(params[i]);\n if (!result.success) {\n return result;\n }\n results.push(result.payload);\n onProgress?.({ index: i, total: params.length });\n }\n return success(results);\n }\n\n // ---------------------------------------------------------------------------\n // Event translation\n // ---------------------------------------------------------------------------\n\n private deviceConnectHandler = (data: { device: ConnectorDevice }): void => {\n const deviceInfo = this.connectorDeviceToDeviceInfo(data.device);\n this._discoveredDevices.set(deviceInfo.connectId, deviceInfo);\n this.emitter.emit(DEVICE.CONNECT, {\n type: DEVICE.CONNECT,\n payload: deviceInfo,\n });\n };\n\n private deviceDisconnectHandler = (data: { connectId: string }): void => {\n this._discoveredDevices.delete(data.connectId);\n this._sessions.delete(data.connectId);\n this.emitter.emit(DEVICE.DISCONNECT, {\n type: DEVICE.DISCONNECT,\n payload: { connectId: data.connectId },\n });\n };\n\n private uiRequestHandler = (data: { type: string; payload?: unknown }): void => {\n this.handleUiEvent(data);\n };\n\n private uiEventHandler = (data: { type: string; payload?: unknown }): void => {\n this.handleUiEvent(data);\n };\n\n private registerEventListeners(): void {\n this.connector.on('device-connect', this.deviceConnectHandler);\n this.connector.on('device-disconnect', this.deviceDisconnectHandler);\n this.connector.on('ui-request', this.uiRequestHandler);\n this.connector.on('ui-event', this.uiEventHandler);\n }\n\n private unregisterEventListeners(): void {\n this.connector.off('device-connect', this.deviceConnectHandler);\n this.connector.off('device-disconnect', this.deviceDisconnectHandler);\n this.connector.off('ui-request', this.uiRequestHandler);\n this.connector.off('ui-event', this.uiEventHandler);\n }\n\n private handleUiEvent(event: { type: string; payload?: unknown }): void {\n if (!event.type) return;\n\n const payload = event.payload as Record<string, unknown> | undefined;\n const deviceInfo = payload\n ? this.extractDeviceInfoFromPayload(payload)\n : this.unknownDevice();\n\n switch (event.type) {\n case 'ui-request_confirmation':\n this.emitter.emit(UI_REQUEST.REQUEST_BUTTON, {\n type: UI_REQUEST.REQUEST_BUTTON,\n payload: { device: deviceInfo },\n });\n break;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Device info mapping\n // ---------------------------------------------------------------------------\n\n private connectorDeviceToDeviceInfo(device: ConnectorDevice): DeviceInfo {\n return {\n vendor: 'ledger',\n model: device.model ?? 'unknown',\n firmwareVersion: '',\n deviceId: device.deviceId,\n connectId: device.connectId,\n label: device.name,\n connectionType: 'usb' as ConnectionType,\n capabilities: device.capabilities,\n };\n }\n\n private extractDeviceInfoFromPayload(payload: Record<string, unknown>): DeviceInfo {\n return {\n vendor: 'ledger',\n model: (payload['model'] as string) ?? 'unknown',\n firmwareVersion: '',\n deviceId: (payload['deviceId'] as string) ?? (payload['id'] as string) ?? '',\n connectId: (payload['connectId'] as string) ?? (payload['path'] as string) ?? '',\n label: (payload['label'] as string),\n connectionType: 'usb' as ConnectionType,\n };\n }\n\n private unknownDevice(): DeviceInfo {\n return {\n vendor: 'ledger',\n model: 'unknown',\n firmwareVersion: '',\n deviceId: '',\n connectId: '',\n connectionType: 'usb',\n };\n }\n}\n","import { HardwareErrorCode } from '@bytezhang/hardware-wallet-core';\n\n/**\n * DMK locked device status codes:\n * 0x5515 (21781) — primary locked response\n * 0x6982 (27010) — security status not satisfied\n * 0x5303 (21251) — tertiary locked response\n */\nconst LOCKED_ERROR_CODES = new Set(['5515', '21781', '6982', '27010', '5303', '21251']);\n\n/**\n * DMK user-rejected status codes:\n * 0x6985 (27013) — conditions of use not satisfied (user denied on device)\n */\nconst USER_REJECTED_CODES = new Set(['6985', '27013']);\n\n/**\n * DMK wrong-app / CLA-not-supported status codes:\n * 0x6e00 (28160) — CLA not supported (wrong app open)\n * 0x6d00 (27904) — INS not supported (wrong app or outdated app)\n */\nconst WRONG_APP_CODES = new Set(['6e00', '28160', '6d00', '27904']);\n\n/** Check if an error (or any error in its chain) represents a locked Ledger device. */\nexport function isDeviceLockedError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e.errorCode != null && LOCKED_ERROR_CODES.has(String(e.errorCode))) return true;\n if (e.statusCode != null && LOCKED_ERROR_CODES.has(String(e.statusCode))) return true;\n if (e._tag === 'DeviceLockedError') return true;\n if (typeof e.message === 'string' && /locked/i.test(e.message)) return true;\n if (e.originalError != null && isDeviceLockedError(e.originalError)) return true;\n if (e.error != null && e._tag && isDeviceLockedError(e.error)) return true;\n return false;\n}\n\n/** Check if a status/error code exists in the given set, crawling the error chain. */\nfunction hasStatusCode(err: unknown, codeSet: Set<string>): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e.errorCode != null && codeSet.has(String(e.errorCode))) return true;\n if (e.statusCode != null && codeSet.has(String(e.statusCode))) return true;\n if (e.originalError != null && hasStatusCode(e.originalError, codeSet)) return true;\n if (e.error != null && e._tag && hasStatusCode(e.error, codeSet)) return true;\n return false;\n}\n\n/** Check for user rejection (denied on device). */\nexport function isUserRejectedError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e._tag === 'UserRefusedOnDevice') return true;\n if (typeof e.message === 'string' && /denied|rejected|refused/i.test(e.message)) return true;\n if (hasStatusCode(err, USER_REJECTED_CODES)) return true;\n return false;\n}\n\n/** Check for wrong app open on the device. */\nexport function isWrongAppError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e._tag === 'WrongAppOpenedError' || e._tag === 'InvalidStatusWordError') {\n if (hasStatusCode(err, WRONG_APP_CODES)) return true;\n }\n if (typeof e.message === 'string' && /wrong app|open the .* app|CLA not supported/i.test(e.message)) return true;\n if (hasStatusCode(err, WRONG_APP_CODES)) return true;\n return false;\n}\n\n/** Check for device disconnected errors. */\nexport function isDeviceDisconnectedError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (e._tag === 'DeviceNotRecognizedError' || e._tag === 'DeviceSessionNotFound') return true;\n if (typeof e.message === 'string' && /disconnected|not found|no device|unplugged|session.*not.*found/i.test(e.message)) return true;\n return false;\n}\n\n/** Check for timeout errors. */\nexport function isTimeoutError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as Record<string, unknown>;\n if (typeof e.message === 'string' && /timeout|timed?\\s*out/i.test(e.message)) return true;\n if (e._tag === 'DeviceExchangeTimeoutError') return true;\n return false;\n}\n\n/**\n * Map a Ledger DMK error to a HardwareErrorCode and human-readable message\n * with actionable recovery information for the caller.\n */\nexport function mapLedgerError(err: unknown): { code: HardwareErrorCode; message: string } {\n // Order matters: check more specific errors first\n\n if (isDeviceLockedError(err)) {\n return {\n code: HardwareErrorCode.DeviceLocked,\n message: 'Device is locked. Please unlock your Ledger device and try again.',\n };\n }\n\n if (isUserRejectedError(err)) {\n return {\n code: HardwareErrorCode.UserRejected,\n message: 'User rejected the request on the device.',\n };\n }\n\n if (isWrongAppError(err)) {\n return {\n code: HardwareErrorCode.WrongApp,\n message: 'Wrong app is open on the Ledger device. Please open the correct app (e.g. Ethereum) and try again.',\n };\n }\n\n if (isDeviceDisconnectedError(err)) {\n return {\n code: HardwareErrorCode.DeviceDisconnected,\n message: 'Ledger device was disconnected. Please reconnect the device and try again.',\n };\n }\n\n if (isTimeoutError(err)) {\n return {\n code: HardwareErrorCode.OperationTimeout,\n message: 'Operation timed out. Please ensure the Ledger device is connected and responsive.',\n };\n }\n\n // Fallback: extract whatever message we can\n let message = 'Unknown Ledger error';\n if (err instanceof Error) {\n message = err.message;\n } else if (err && typeof err === 'object') {\n const e = err as Record<string, unknown>;\n message = String(e.message ?? e._tag ?? e.type ?? JSON.stringify(err));\n }\n return { code: HardwareErrorCode.UnknownError, message };\n}\n","import type { DeviceDescriptor, DeviceChangeEvent } from '@bytezhang/hardware-wallet-core';\nimport type { IDmk, DmkDiscoveredDevice } from '../types';\n\n/**\n * Manages device discovery, connection, and session tracking.\n * Wraps DMK's Observable APIs into simpler imperative calls.\n */\nexport class LedgerDeviceManager {\n private readonly _dmk: IDmk;\n private readonly _discovered = new Map<string, DmkDiscoveredDevice>();\n private readonly _sessions = new Map<string, string>(); // deviceId → sessionId\n private readonly _sessionToDevice = new Map<string, string>(); // sessionId → deviceId\n private _listenSub: { unsubscribe: () => void } | null = null;\n\n constructor(dmk: IDmk) {\n this._dmk = dmk;\n }\n\n /**\n * One-shot enumeration: subscribe to listenToAvailableDevices,\n * take the first emission, unsubscribe, return DeviceDescriptors.\n */\n enumerate(): Promise<DeviceDescriptor[]> {\n return new Promise<DeviceDescriptor[]>((resolve) => {\n let resolved = false;\n // BehaviorSubject fires next synchronously during subscribe(),\n // so 'sub' is not yet assigned when the callback runs.\n // Capture result synchronously, unsubscribe after assignment.\n let syncResult: { id: string; deviceModel: { name: string }; [k: string]: unknown }[] | null = null;\n\n const sub = this._dmk.listenToAvailableDevices().subscribe({\n next: (devices) => {\n if (resolved) return;\n resolved = true;\n this._discovered.clear();\n for (const d of devices) {\n this._discovered.set(d.id, d);\n }\n syncResult = devices;\n },\n error: () => {\n if (!resolved) {\n resolved = true;\n resolve([]);\n }\n },\n });\n\n // If BehaviorSubject fired synchronously, sub is now assigned\n if (syncResult !== null) {\n sub.unsubscribe();\n const devices = syncResult as { id: string; deviceModel: { name: string } }[];\n resolve(devices.map(d => ({ path: d.id, type: d.deviceModel.name })));\n }\n });\n }\n\n /**\n * Continuous listening: tracks device connect/disconnect via diffing.\n */\n listen(onChange: (event: DeviceChangeEvent) => void): void {\n this.stopListening();\n let previousIds = new Set<string>();\n\n this._listenSub = this._dmk.listenToAvailableDevices().subscribe({\n next: (devices) => {\n const currentIds = new Set(devices.map(d => d.id));\n\n for (const d of devices) {\n this._discovered.set(d.id, d);\n console.log('[LedgerDeviceManager] listen device:', JSON.stringify({\n id: d.id,\n deviceModel: d.deviceModel,\n name: (d as any).name,\n }));\n if (!previousIds.has(d.id)) {\n onChange({ type: 'device-connected', descriptor: { path: d.id, type: d.deviceModel.name } });\n }\n }\n for (const id of previousIds) {\n if (!currentIds.has(id)) {\n this._discovered.delete(id);\n onChange({ type: 'device-disconnected', descriptor: { path: id } });\n }\n }\n previousIds = currentIds;\n },\n });\n }\n\n stopListening(): void {\n this._listenSub?.unsubscribe();\n this._listenSub = null;\n }\n\n /**\n * Trigger browser device selection (WebHID requestDevice).\n * Starts discovery for a short period, then stops.\n */\n requestDevice(timeoutMs = 3000): Promise<void> {\n return new Promise<void>((resolve) => {\n const sub = this._dmk.startDiscovering().subscribe({\n next: (d) => { this._discovered.set(d.id, d); },\n error: () => { sub.unsubscribe(); resolve(); },\n });\n setTimeout(() => {\n sub.unsubscribe();\n this._dmk.stopDiscovering();\n resolve();\n }, timeoutMs);\n });\n }\n\n /** Connect to a previously discovered device. Returns sessionId. */\n async connect(deviceId: string): Promise<string> {\n const device = this._discovered.get(deviceId);\n if (!device) {\n throw new Error(`Device \"${deviceId}\" not found. Call enumerate() or listen() first.`);\n }\n const sessionId = await this._dmk.connect({ device });\n this._sessions.set(deviceId, sessionId);\n this._sessionToDevice.set(sessionId, deviceId);\n return sessionId;\n }\n\n /** Disconnect a session. */\n async disconnect(sessionId: string): Promise<void> {\n await this._dmk.disconnect({ sessionId });\n const deviceId = this._sessionToDevice.get(sessionId);\n if (deviceId) this._sessions.delete(deviceId);\n this._sessionToDevice.delete(sessionId);\n }\n\n getSessionId(deviceId: string): string | undefined {\n return this._sessions.get(deviceId);\n }\n\n getDeviceId(sessionId: string): string | undefined {\n return this._sessionToDevice.get(sessionId);\n }\n\n /** Get the underlying DMK instance (needed by SignerManager). */\n getDmk(): IDmk {\n return this._dmk;\n }\n\n dispose(): void {\n this.stopListening();\n this._discovered.clear();\n this._sessions.clear();\n this._sessionToDevice.clear();\n this._dmk.close?.();\n }\n}\n","/** DeviceAction state emitted by DMK signer operations. */\ninterface DeviceActionState<T> {\n status: 'pending' | 'completed' | 'error';\n output?: T;\n error?: unknown;\n intermediateValue?: {\n requiredUserInteraction?: string;\n [key: string]: unknown;\n };\n}\n\n/**\n * Convert a DMK DeviceAction (Observable-based) into a Promise.\n * Handles pending → completed/error state transitions and interaction callbacks.\n */\nexport function deviceActionToPromise<T>(\n action: {\n observable: {\n subscribe(observer: {\n next: (value: DeviceActionState<T>) => void;\n error?: (err: unknown) => void;\n complete?: () => void;\n }): { unsubscribe: () => void };\n };\n },\n onInteraction?: (interaction: string) => void,\n): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n let settled = false;\n let sub: { unsubscribe: () => void };\n\n sub = action.observable.subscribe({\n next: (state) => {\n if (settled) return;\n if (state.status === 'completed') {\n settled = true;\n sub?.unsubscribe();\n resolve(state.output as T);\n } else if (state.status === 'error') {\n settled = true;\n sub?.unsubscribe();\n reject(state.error);\n } else if (state.status === 'pending' && onInteraction) {\n const interaction = state.intermediateValue?.requiredUserInteraction;\n if (interaction && interaction !== 'none') {\n onInteraction(interaction);\n } else if (interaction === 'none') {\n // Previous interaction resolved (e.g., user opened the app)\n onInteraction('interaction-complete');\n }\n }\n },\n error: (err: unknown) => {\n if (!settled) {\n settled = true;\n sub?.unsubscribe();\n reject(err);\n }\n },\n complete: () => {\n if (!settled) {\n settled = true;\n reject(new Error('Device action completed without result'));\n }\n },\n });\n });\n}\n","import type { SignerEvmAddress, SignerEvmSignature } from '../types';\nimport { deviceActionToPromise } from './deviceActionToPromise';\n\n/**\n * SDK signer interface — duck-typed to avoid hard dependency on\n * @ledgerhq/device-signer-kit-ethereum.\n */\nexport interface ISdkSignerEth {\n getAddress(derivationPath: string, options?: { checkOnDevice?: boolean }): unknown;\n signTransaction(derivationPath: string, transaction: Uint8Array, options?: unknown): unknown;\n signMessage(derivationPath: string, message: string): unknown;\n signTypedData(derivationPath: string, data: unknown): unknown;\n}\n\n/** Convert hex string (with or without 0x) to Uint8Array. */\nfunction hexToBytes(hex: string): Uint8Array {\n const h = hex.startsWith('0x') ? hex.slice(2) : hex;\n const bytes = new Uint8Array(h.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(h.substring(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\n/**\n * Wraps Ledger's SDK signer (Observable-based DeviceActions) into\n * a simple async interface returning plain serializable data.\n */\nexport class SignerEth {\n onInteraction?: (interaction: string) => void;\n\n constructor(private readonly _sdk: ISdkSignerEth) {}\n\n async getAddress(\n derivationPath: string,\n options?: { checkOnDevice?: boolean }\n ): Promise<SignerEvmAddress> {\n const action = this._sdk.getAddress(derivationPath, {\n checkOnDevice: options?.checkOnDevice ?? false,\n });\n return deviceActionToPromise<SignerEvmAddress>(action as any, this.onInteraction);\n }\n\n async signTransaction(\n derivationPath: string,\n serializedTxHex: string\n ): Promise<SignerEvmSignature> {\n const action = this._sdk.signTransaction(derivationPath, hexToBytes(serializedTxHex));\n return deviceActionToPromise<SignerEvmSignature>(action as any, this.onInteraction);\n }\n\n async signMessage(derivationPath: string, message: string): Promise<SignerEvmSignature> {\n const action = this._sdk.signMessage(derivationPath, message);\n return deviceActionToPromise<SignerEvmSignature>(action as any, this.onInteraction);\n }\n\n async signTypedData(derivationPath: string, data: unknown): Promise<SignerEvmSignature> {\n const action = this._sdk.signTypedData(derivationPath, data);\n return deviceActionToPromise<SignerEvmSignature>(action as any, this.onInteraction);\n }\n}\n","import type { IDmk } from '../types';\nimport { SignerEth } from './SignerEth';\n\ntype SignerEthBuilderFn = (args: { dmk: IDmk; sessionId: string }) => { build(): unknown } | Promise<{ build(): unknown }>;\n\n/**\n * Manages per-sessionId SignerEth instances.\n * Creates on demand, caches for reuse, invalidates on session change.\n */\nexport class SignerManager {\n private readonly _cache = new Map<string, SignerEth>();\n private readonly _dmk: IDmk;\n private readonly _builderFn: SignerEthBuilderFn;\n\n constructor(dmk: IDmk, builderFn?: SignerEthBuilderFn) {\n this._dmk = dmk;\n this._builderFn = builderFn ?? SignerManager._defaultBuilder();\n }\n\n async getOrCreate(sessionId: string): Promise<SignerEth> {\n let signer = this._cache.get(sessionId);\n if (signer) return signer;\n\n const builder = await this._builderFn({ dmk: this._dmk, sessionId });\n const sdkSigner = builder.build();\n signer = new SignerEth(sdkSigner as any);\n this._cache.set(sessionId, signer);\n return signer;\n }\n\n invalidate(sessionId: string): void {\n this._cache.delete(sessionId);\n }\n\n clearAll(): void {\n this._cache.clear();\n }\n\n private static _defaultBuilder(): SignerEthBuilderFn {\n let BuilderClass: any = null;\n return async (args) => {\n if (!BuilderClass) {\n const mod = await import('@ledgerhq/device-signer-kit-ethereum');\n BuilderClass = mod.SignerEthBuilder;\n }\n return new BuilderClass(args);\n };\n }\n}\n","import type { SignerBtcAddress } from '../types';\nimport { deviceActionToPromise } from './deviceActionToPromise';\n\n/**\n * SDK BTC signer interface — duck-typed to avoid hard dependency on\n * @ledgerhq/device-signer-kit-bitcoin.\n */\nexport interface ISdkSignerBtc {\n getExtendedPublicKey(derivationPath: string, options?: { checkOnDevice?: boolean }): unknown;\n getWalletAddress(wallet: unknown, addressIndex: number, options?: { checkOnDevice?: boolean; change?: boolean }): unknown;\n getMasterFingerprint(options?: { skipOpenApp?: boolean }): unknown;\n}\n\n/**\n * Wraps Ledger's BTC SDK signer (Observable-based DeviceActions) into\n * a simple async interface returning plain serializable data.\n */\nexport class SignerBtc {\n onInteraction?: (interaction: string) => void;\n\n constructor(private readonly _sdk: ISdkSignerBtc) {}\n\n async getWalletAddress(\n wallet: unknown,\n addressIndex: number,\n options?: { checkOnDevice?: boolean; change?: boolean },\n ): Promise<SignerBtcAddress> {\n const action = this._sdk.getWalletAddress(wallet, addressIndex, {\n checkOnDevice: options?.checkOnDevice ?? false,\n change: options?.change ?? false,\n });\n return deviceActionToPromise<SignerBtcAddress>(action as any, this.onInteraction);\n }\n\n async getExtendedPublicKey(\n derivationPath: string,\n options?: { checkOnDevice?: boolean },\n ): Promise<string> {\n const action = this._sdk.getExtendedPublicKey(derivationPath, {\n checkOnDevice: options?.checkOnDevice ?? false,\n });\n return deviceActionToPromise<string>(action as any, this.onInteraction);\n }\n\n async getMasterFingerprint(\n options?: { skipOpenApp?: boolean },\n ): Promise<Uint8Array> {\n const action = this._sdk.getMasterFingerprint(options);\n const result = await deviceActionToPromise<{ masterFingerprint: Uint8Array }>(action as any, this.onInteraction);\n return result.masterFingerprint;\n }\n}\n","import type { IDmk } from '../types';\n\n/**\n * Map of chain ticker symbols to the Ledger app name\n * that must be open to sign transactions for that chain.\n */\nexport const APP_NAME_MAP: Record<string, string> = {\n ETH: 'Ethereum',\n BTC: 'Bitcoin',\n SOL: 'Solana',\n TRX: 'Tron',\n XRP: 'XRP',\n ADA: 'Cardano',\n DOT: 'Polkadot',\n ATOM: 'Cosmos',\n};\n\n/** The name reported by the Ledger when it sits on the home screen. */\nconst DASHBOARD_APP_NAME = 'BOLOS';\n\ninterface AppManagerOptions {\n waitMs?: number;\n maxRetries?: number;\n}\n\n/**\n * Orchestrates opening / closing Ledger on-device apps so that the\n * correct signer application is running before any signing call.\n */\nexport class AppManager {\n private readonly _dmk: IDmk;\n private readonly _waitMs: number;\n private readonly _maxRetries: number;\n\n constructor(dmk: IDmk, options?: AppManagerOptions) {\n this._dmk = dmk;\n this._waitMs = options?.waitMs ?? 1000;\n this._maxRetries = options?.maxRetries ?? 10;\n }\n\n /**\n * Return the Ledger app name for a given chain ticker,\n * or undefined if the chain is not supported.\n */\n static getAppName(chain: string): string | undefined {\n return APP_NAME_MAP[chain];\n }\n\n /**\n * Ensure the target app is open on the device identified by `sessionId`.\n *\n * Flow:\n * 1. Check the currently running app.\n * 2. If it is already the target, return immediately.\n * 3. If a different app is running (not dashboard), close it first.\n * 4. Open the target app.\n * 5. Poll until the device confirms the target app is running.\n */\n async ensureAppOpen(sessionId: string, targetAppName: string): Promise<void> {\n const currentApp = await this._getCurrentApp(sessionId);\n\n if (currentApp === targetAppName) {\n return;\n }\n\n // If we're not on the dashboard, close the current app first\n if (!this._isDashboard(currentApp)) {\n await this._closeCurrentApp(sessionId);\n // Wait for dashboard to become active\n await this._waitForApp(sessionId, DASHBOARD_APP_NAME);\n }\n\n // Open the target app\n await this._openApp(sessionId, targetAppName);\n\n // Poll until the target app is confirmed open\n await this._waitForApp(sessionId, targetAppName);\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private async _getCurrentApp(sessionId: string): Promise<string> {\n const result = (await this._dmk.sendCommand({\n sessionId,\n command: { type: 'get-app-and-version' },\n })) as { name: string };\n return result.name;\n }\n\n private async _openApp(sessionId: string, appName: string): Promise<void> {\n await this._dmk.sendCommand({\n sessionId,\n command: { type: 'open-app', appName },\n });\n }\n\n private async _closeCurrentApp(sessionId: string): Promise<void> {\n await this._dmk.sendCommand({\n sessionId,\n command: { type: 'close-app' },\n });\n }\n\n /**\n * Poll the device until the expected app is reported as running,\n * or throw after `_maxRetries` attempts.\n */\n private async _waitForApp(sessionId: string, expectedAppName: string): Promise<void> {\n for (let i = 0; i < this._maxRetries; i++) {\n await this._wait();\n const current = await this._getCurrentApp(sessionId);\n if (current === expectedAppName) {\n return;\n }\n }\n throw new Error(\n `Ledger: failed to open \"${expectedAppName}\" after ${this._maxRetries} retries`\n );\n }\n\n private _isDashboard(appName: string): boolean {\n return appName === DASHBOARD_APP_NAME;\n }\n\n private _wait(): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, this._waitMs));\n }\n}\n"],"mappings":"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","names":["HardwareErrorCode","HardwareErrorCode","result"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytezhang/ledger-adapter",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "Ledger hardware wallet adapter for OneKey",
5
5
  "author": "OneKey",
6
6
  "license": "MIT",