@onekeyfe/hwk-ledger-adapter 1.2.3-alpha.8 → 1.2.3

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.js CHANGED
@@ -39,7 +39,6 @@ __export(index_exports, {
39
39
  SignerEth: () => SignerEth,
40
40
  SignerManager: () => SignerManager,
41
41
  SignerSol: () => SignerSol,
42
- SignerZcash: () => SignerZcash,
43
42
  debugLog: () => debugLog,
44
43
  deviceActionToPromise: () => deviceActionToPromise,
45
44
  isDeviceLockedError: () => isDeviceLockedError,
@@ -58,14 +57,17 @@ var import_hwk_adapter_core3 = require("@onekeyfe/hwk-adapter-core");
58
57
 
59
58
  // src/errors.ts
60
59
  var import_hwk_adapter_core = require("@onekeyfe/hwk-adapter-core");
61
- function ledgerFailure(code, error, appName, tag, params, origin, recovery) {
60
+ var MULTIPLE_USB_LEDGER_DEVICES_ERROR_MESSAGE = "Multiple Ledger USB devices are connected. Please connect only one Ledger device and try again.";
61
+ function createMultipleUsbLedgerDevicesError() {
62
+ return Object.assign(new Error(MULTIPLE_USB_LEDGER_DEVICES_ERROR_MESSAGE), {
63
+ code: import_hwk_adapter_core.HardwareErrorCode.DeviceOneDeviceOnly
64
+ });
65
+ }
66
+ function ledgerFailure(code, error, appName, tag, params) {
62
67
  const payload = { error, code };
63
68
  if (appName !== void 0) payload.appName = appName;
64
69
  if (tag !== void 0) payload._tag = tag;
65
70
  if (params !== void 0) payload.params = params;
66
- const resolvedOrigin = origin ?? (0, import_hwk_adapter_core.defaultOriginForCode)(code);
67
- if (resolvedOrigin !== void 0) payload.origin = resolvedOrigin;
68
- payload.recovery = recovery ?? (0, import_hwk_adapter_core.defaultRecoveryForCode)(code);
69
71
  return { success: false, payload };
70
72
  }
71
73
  var LOCKED_ERROR_CODES = /* @__PURE__ */ new Set(["5515", "21781", "6982", "27010", "5303", "21251"]);
@@ -206,12 +208,7 @@ var ERROR_TAG = {
206
208
  UnknownDevice: "UnknownDeviceError",
207
209
  DeviceSessionRefresher: "DeviceSessionRefresherError",
208
210
  DeviceNotInitialized: "DeviceNotInitializedError",
209
- // DMK's class is named OpeningConnectionError but its `_tag` reads
210
- // "ConnectionOpeningError" — and its typings widen `_tag` to `string`, which
211
- // is why the class name looked authoritative. Both spellings are kept so a
212
- // DMK version that aligns them does not silently drop back to UnknownError.
213
- OpeningConnection: "ConnectionOpeningError",
214
- OpeningConnectionLegacy: "OpeningConnectionError",
211
+ OpeningConnection: "OpeningConnectionError",
215
212
  DeviceDisconnectedBeforeSendingApdu: "DeviceDisconnectedBeforeSendingApdu",
216
213
  DeviceDisconnectedWhileSending: "DeviceDisconnectedWhileSendingError",
217
214
  Disconnect: "DisconnectError",
@@ -224,18 +221,7 @@ var ERROR_TAG = {
224
221
  // DMK remote-network failures (manager-api HTTP / secure-channel WS).
225
222
  WebSocketConnection: "WebSocketConnectionError",
226
223
  HttpFetch: "FetchError",
227
- NetworkDA: "NetworkDAError",
228
- InvalidFirmwareMetadataResponse: "InvalidGetFirmwareMetadataResponseError",
229
- ApplicationsMetadataTask: "GetApplicationsMetadataTaskError",
230
- // DMK OS/secure-channel device actions. `SecureChannelError` is the residual
231
- // bucket left by SecureChannelError.mapInstallDAErrors() after the locked /
232
- // refused / already-installed / OOM cases have been split out, so it means
233
- // "the relay itself broke", not "the device answered".
234
- SecureChannel: "SecureChannelError",
235
- RefusedByUserDA: "RefusedByUserDAError",
236
- AppAlreadyInstalledDA: "AppAlreadyInstalledDAError",
237
- OutOfMemoryDA: "OutOfMemoryDAError",
238
- DeviceNotOnboarded: "DeviceNotOnboardedError"
224
+ InvalidFirmwareMetadataResponse: "InvalidGetFirmwareMetadataResponseError"
239
225
  };
240
226
  function isDeviceLockedError(err) {
241
227
  if (!err || typeof err !== "object") return false;
@@ -265,6 +251,7 @@ function isBlePairingFailureError(err) {
265
251
  return false;
266
252
  }
267
253
  var CONNECTION_LEVEL_TAGS = /* @__PURE__ */ new Set([
254
+ ERROR_TAG.DeviceLocked,
268
255
  ERROR_TAG.DeviceNotAdvertising,
269
256
  ERROR_TAG.BlePairingTimeout,
270
257
  ERROR_TAG.BleGattBondingFailed,
@@ -276,7 +263,6 @@ var CONNECTION_LEVEL_TAGS = /* @__PURE__ */ new Set([
276
263
  ERROR_TAG.DeviceSessionRefresher,
277
264
  ERROR_TAG.DeviceNotInitialized,
278
265
  ERROR_TAG.OpeningConnection,
279
- ERROR_TAG.OpeningConnectionLegacy,
280
266
  ERROR_TAG.DeviceDisconnectedBeforeSendingApdu,
281
267
  ERROR_TAG.DeviceDisconnectedWhileSending,
282
268
  ERROR_TAG.Disconnect,
@@ -291,10 +277,7 @@ var DEVICE_NOT_FOUND_TAGS = /* @__PURE__ */ new Set([
291
277
  // Map to DeviceNotFound so non-BLE-direct paths get a sensible error code.
292
278
  ERROR_TAG.DeviceNotInDiscoveryCache
293
279
  ]);
294
- var DEVICE_BUSY_TAGS = /* @__PURE__ */ new Set([
295
- ERROR_TAG.OpeningConnection,
296
- ERROR_TAG.OpeningConnectionLegacy
297
- ]);
280
+ var DEVICE_BUSY_TAGS = /* @__PURE__ */ new Set([ERROR_TAG.OpeningConnection]);
298
281
  var DEVICE_DISCONNECTED_TAGS = /* @__PURE__ */ new Set([
299
282
  ERROR_TAG.DeviceNotRecognized,
300
283
  ERROR_TAG.DeviceSessionNotFound,
@@ -317,13 +300,6 @@ function isConnectionLevelError(err) {
317
300
  function isKnownConnectionTag(tag) {
318
301
  return typeof tag === "string" && CONNECTION_LEVEL_TAGS.has(tag);
319
302
  }
320
- var CONNECTION_OPENING_TAGS = /* @__PURE__ */ new Set([
321
- ERROR_TAG.OpeningConnection,
322
- ERROR_TAG.OpeningConnectionLegacy
323
- ]);
324
- function isConnectionOpeningTag(tag) {
325
- return typeof tag === "string" && CONNECTION_OPENING_TAGS.has(tag);
326
- }
327
303
  function hasStatusCode(err, codeSet) {
328
304
  if (!err || typeof err !== "object") return false;
329
305
  const e = err;
@@ -359,14 +335,6 @@ function hasInvalidArgumentCode(err) {
359
335
  if (e.error != null && e._tag && hasInvalidArgumentCode(e.error)) return true;
360
336
  return false;
361
337
  }
362
- function hasErrorTag(err, tags) {
363
- if (!err || typeof err !== "object") return false;
364
- const e = err;
365
- if (typeof e._tag === "string" && tags.has(e._tag)) return true;
366
- if (e.originalError != null && hasErrorTag(e.originalError, tags)) return true;
367
- if (e.error != null && e._tag && hasErrorTag(e.error, tags)) return true;
368
- return false;
369
- }
370
338
  function isDeviceNotFoundError(err) {
371
339
  if (!err || typeof err !== "object") return false;
372
340
  const tag = err._tag;
@@ -385,14 +353,10 @@ function isDeviceBusyError(err) {
385
353
  if (e.error != null && e._tag && isDeviceBusyError(e.error)) return true;
386
354
  return false;
387
355
  }
388
- var USER_REJECTED_TAGS = /* @__PURE__ */ new Set([
389
- ERROR_TAG.UserRefusedOnDevice,
390
- ERROR_TAG.RefusedByUserDA
391
- ]);
392
356
  function isUserRejectedError(err) {
393
357
  if (!err || typeof err !== "object") return false;
394
358
  const e = err;
395
- if (hasErrorTag(err, USER_REJECTED_TAGS)) return true;
359
+ if (e._tag === ERROR_TAG.UserRefusedOnDevice) return true;
396
360
  if (typeof e.message === "string" && /denied|rejected|refused/i.test(e.message)) return true;
397
361
  if (hasStatusCode(err, USER_REJECTED_CODES)) return true;
398
362
  return false;
@@ -423,37 +387,15 @@ function isAppNotInstalledError(err) {
423
387
  if (hasStatusCode(err, APP_NOT_INSTALLED_CODES)) return true;
424
388
  return false;
425
389
  }
426
- var OUT_OF_MEMORY_TAGS = /* @__PURE__ */ new Set([ERROR_TAG.OutOfMemoryDA]);
427
390
  function isOutOfMemoryError(err) {
428
- return hasErrorTag(err, OUT_OF_MEMORY_TAGS);
429
- }
430
- var APP_ALREADY_INSTALLED_TAGS = /* @__PURE__ */ new Set([
431
- ERROR_TAG.AppAlreadyInstalledDA
432
- ]);
433
- function isAppAlreadyInstalledError(err) {
434
- return hasErrorTag(err, APP_ALREADY_INSTALLED_TAGS);
435
- }
436
- var DEVICE_NOT_ONBOARDED_TAGS = /* @__PURE__ */ new Set([
437
- ERROR_TAG.DeviceNotOnboarded
438
- ]);
439
- function isDeviceNotOnboardedError(err) {
440
- return hasErrorTag(err, DEVICE_NOT_ONBOARDED_TAGS);
441
- }
442
- var FIRMWARE_METADATA_TAGS = /* @__PURE__ */ new Set([
443
- ERROR_TAG.InvalidFirmwareMetadataResponse,
444
- ERROR_TAG.ApplicationsMetadataTask
445
- ]);
446
- function isFirmwareMetadataError(err) {
447
- return hasErrorTag(err, FIRMWARE_METADATA_TAGS);
448
- }
449
- var SECURE_CHANNEL_TAGS = /* @__PURE__ */ new Set([ERROR_TAG.SecureChannel]);
450
- function isSecureChannelError(err) {
451
- return hasErrorTag(err, SECURE_CHANNEL_TAGS);
391
+ if (!err || typeof err !== "object") return false;
392
+ const e = err;
393
+ return e._tag === "OutOfMemoryDAError";
452
394
  }
453
395
  var NETWORK_ERROR_TAGS = /* @__PURE__ */ new Set([
454
396
  ERROR_TAG.WebSocketConnection,
455
397
  ERROR_TAG.HttpFetch,
456
- ERROR_TAG.NetworkDA
398
+ ERROR_TAG.InvalidFirmwareMetadataResponse
457
399
  ]);
458
400
  function isNetworkError(err) {
459
401
  if (!err || typeof err !== "object") return false;
@@ -503,34 +445,23 @@ function isTransportStuck(err) {
503
445
  function isStuckAppStateError(err) {
504
446
  return isAppStuckByApdu(err) || isTransportStuck(err);
505
447
  }
506
- var DMK_PLACEHOLDER_MESSAGE = "Unknown error.";
507
- function nestedErrorMessage(nested) {
508
- if (!nested || typeof nested !== "object") return void 0;
509
- const { message } = nested;
510
- if (typeof message !== "string") return void 0;
511
- const trimmed = message.trim();
512
- if (!trimmed || trimmed === DMK_PLACEHOLDER_MESSAGE) return void 0;
513
- return message;
514
- }
515
448
  function mapLedgerError(err, opts) {
516
449
  let originalMessage = "Unknown Ledger error";
517
450
  if (err instanceof Error) {
518
451
  originalMessage = err.message;
519
452
  } else if (err && typeof err === "object") {
520
453
  const e = err;
521
- originalMessage = String(
522
- e.message ?? nestedErrorMessage(e.originalError) ?? e._tag ?? e.type ?? JSON.stringify(err)
523
- );
454
+ originalMessage = String(e.message ?? e._tag ?? e.type ?? JSON.stringify(err));
524
455
  }
525
456
  let code;
526
457
  if (isDeviceLockedError(err)) {
527
458
  code = import_hwk_adapter_core.HardwareErrorCode.DeviceLocked;
528
459
  } else if (isDeviceNotAdvertisingError(err) || isDeviceNotFoundError(err)) {
529
460
  code = import_hwk_adapter_core.HardwareErrorCode.DeviceNotFound;
530
- } else if (isBlePairingFailureError(err)) {
531
- code = import_hwk_adapter_core.HardwareErrorCode.BlePairingTimeout;
532
461
  } else if (isDeviceBusyError(err)) {
533
462
  code = import_hwk_adapter_core.HardwareErrorCode.DeviceBusy;
463
+ } else if (isBlePairingFailureError(err)) {
464
+ code = import_hwk_adapter_core.HardwareErrorCode.BlePairingTimeout;
534
465
  } else if (isUserAbortedError(err)) {
535
466
  code = import_hwk_adapter_core.HardwareErrorCode.UserAborted;
536
467
  } else if (isUserRejectedError(err)) {
@@ -539,18 +470,10 @@ function mapLedgerError(err, opts) {
539
470
  code = import_hwk_adapter_core.HardwareErrorCode.WrongApp;
540
471
  } else if (isAppNotInstalledError(err)) {
541
472
  code = import_hwk_adapter_core.HardwareErrorCode.AppNotInstalled;
542
- } else if (isAppAlreadyInstalledError(err)) {
543
- code = import_hwk_adapter_core.HardwareErrorCode.AppAlreadyInstalled;
544
473
  } else if (isOutOfMemoryError(err)) {
545
474
  code = import_hwk_adapter_core.HardwareErrorCode.DeviceOutOfMemory;
546
- } else if (isDeviceNotOnboardedError(err)) {
547
- code = import_hwk_adapter_core.HardwareErrorCode.DeviceNotInitialized;
548
- } else if (isFirmwareMetadataError(err)) {
549
- code = import_hwk_adapter_core.HardwareErrorCode.LedgerFirmwareMetadataError;
550
475
  } else if (isNetworkError(err)) {
551
476
  code = import_hwk_adapter_core.HardwareErrorCode.NetworkError;
552
- } else if (isSecureChannelError(err)) {
553
- code = import_hwk_adapter_core.HardwareErrorCode.LedgerSecureChannelError;
554
477
  } else if (isDeviceDisconnectedError(err)) {
555
478
  code = import_hwk_adapter_core.HardwareErrorCode.DeviceDisconnected;
556
479
  } else if (isTimeoutError(err)) {
@@ -563,21 +486,7 @@ function mapLedgerError(err, opts) {
563
486
  }
564
487
  const errAppName = err && typeof err === "object" ? err.appName : void 0;
565
488
  const appName = errAppName ?? opts?.defaultAppName;
566
- return {
567
- code,
568
- message: (0, import_hwk_adapter_core.enrichErrorMessage)(code, originalMessage),
569
- origin: (0, import_hwk_adapter_core.defaultOriginForCode)(code),
570
- appName
571
- };
572
- }
573
-
574
- // src/utils/queueKey.ts
575
- var LEDGER_DEFAULT_QUEUE_KEY = "__ledger_default__";
576
- function ledgerQueueKey({
577
- operationId,
578
- connectId
579
- }) {
580
- return (operationId ?? connectId) || LEDGER_DEFAULT_QUEUE_KEY;
489
+ return { code, message: (0, import_hwk_adapter_core.enrichErrorMessage)(code, originalMessage), appName };
581
490
  }
582
491
 
583
492
  // src/adapter/methods/allNetworkGetAddress.ts
@@ -638,102 +547,65 @@ var LEDGER_BTC_NETWORK_COIN_MAP = {
638
547
  var LEDGER_UNSUPPORTED_ALLNETWORK_NETWORKS = /* @__PURE__ */ new Set(["doge", "dogecoin"]);
639
548
  function createAllNetworkGetAddress({
640
549
  callChain,
641
- getChainFingerprint,
642
- retainOperation,
643
- errorToFailure,
644
- createCancelScope
550
+ getChainFingerprint
645
551
  }) {
646
552
  return async function allNetworkGetAddress(connectId, _deviceId, params) {
647
- debugLog("[LedgerAdapter][REQ]", {
648
- method: "allNetworkGetAddress",
649
- connectId,
650
- itemCount: params.bundle.length
651
- });
652
- const target = (0, import_hwk_adapter_core2.resolveHardwareOperationTarget)(connectId, params.operationId, "ledger");
653
- if (!target.success) return target;
654
- const effectiveTargetId = target.payload.targetId ?? "";
655
- let releaseOperationRetention;
656
- try {
657
- releaseOperationRetention = target.payload.operationId ? retainOperation(target.payload.operationId) : void 0;
658
- } catch (error) {
659
- return errorToFailure(error);
660
- }
661
- const cancelScope = createCancelScope(
662
- ledgerQueueKey({ operationId: target.payload.operationId, connectId: effectiveTargetId })
663
- );
553
+ debugLog("[LedgerAdapter][REQ]", { method: "allNetworkGetAddress", connectId, params });
664
554
  const installContext = {};
665
555
  const commonParams = {
666
- autoInstallApp: params.autoInstallApp,
667
- operationId: target.payload.operationId,
668
- knownConnections: params.knownConnections,
669
- extra: params.extra,
670
- allowDeviceSelection: params.allowDeviceSelection
556
+ autoInstallApp: params.autoInstallApp
671
557
  };
672
558
  const chainFingerprints = /* @__PURE__ */ new Map();
673
- try {
674
- const result = await (0, import_hwk_adapter_core2.runAllNetworkGetAddress)({
675
- connectId: effectiveTargetId,
676
- deviceId: _deviceId,
677
- params,
678
- normalizeItem: normalizeLedgerAllNetworkItem,
679
- buildUnsupportedNetworkResponse: (item) => isUnsupportedLedgerAllNetworkNetwork(item) ? buildUnsupportedNetworkResponse(item) : void 0,
680
- callItem: async ({ method, chain, item }) => {
681
- if (cancelScope.signal.aborted) return buildCancelledFailure(cancelScope.signal);
682
- const itemDeviceId = getItemDeviceId(item) ?? chainFingerprints.get(chain) ?? "";
683
- return callAllNetworkMethod(
684
- callChain,
685
- effectiveTargetId,
686
- itemDeviceId,
687
- method,
688
- item,
689
- commonParams,
690
- installContext
691
- );
692
- },
693
- attachIdentity: async ({ item, chain, payload }) => attachLedgerIdentity(
694
- getChainFingerprint,
695
- effectiveTargetId,
559
+ const result = await (0, import_hwk_adapter_core2.runAllNetworkGetAddress)({
560
+ connectId,
561
+ deviceId: _deviceId,
562
+ params,
563
+ normalizeItem: normalizeLedgerAllNetworkItem,
564
+ buildUnsupportedNetworkResponse: (item) => isUnsupportedLedgerAllNetworkNetwork(item) ? buildUnsupportedNetworkResponse(item) : void 0,
565
+ callItem: async ({ method, chain, item }) => {
566
+ const itemDeviceId = getItemDeviceId(item) ?? chainFingerprints.get(chain) ?? "";
567
+ return callAllNetworkMethod(
568
+ callChain,
569
+ connectId,
570
+ itemDeviceId,
571
+ method,
696
572
  item,
697
- chain,
698
- payload,
699
- chainFingerprints,
700
- installContext,
701
- cancelScope.signal
702
- ),
703
- shouldAbortBundle: isTopLevelAllNetworkFailure,
704
- buildTopLevelFailure: (response) => {
705
- const code = response.payload?.code ?? import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch;
706
- return (0, import_hwk_adapter_core2.failure)(
707
- code,
708
- response.payload?.error ?? "All-network get-address aborted",
709
- response.payload?.params
710
- );
711
- }
712
- });
713
- debugLog("[LedgerAdapter][RES]", {
714
- method: "allNetworkGetAddress",
715
- success: result.success,
716
- payload: result
717
- });
718
- return result;
719
- } finally {
720
- cancelScope.release();
721
- releaseOperationRetention?.();
722
- }
573
+ commonParams,
574
+ installContext
575
+ );
576
+ },
577
+ attachIdentity: async ({ item, chain, payload }) => attachLedgerIdentity(
578
+ getChainFingerprint,
579
+ connectId,
580
+ item,
581
+ chain,
582
+ payload,
583
+ chainFingerprints
584
+ ),
585
+ shouldAbortBundle: isTopLevelAllNetworkFailure,
586
+ buildTopLevelFailure: (response) => {
587
+ const code = response.payload?.code ?? import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch;
588
+ return (0, import_hwk_adapter_core2.failure)(
589
+ code,
590
+ response.payload?.error ?? "All-network get-address aborted",
591
+ response.payload?.params
592
+ );
593
+ }
594
+ });
595
+ debugLog("[LedgerAdapter][RES]", {
596
+ method: "allNetworkGetAddress",
597
+ success: result.success,
598
+ payload: result
599
+ });
600
+ return result;
723
601
  };
724
602
  }
725
- function buildCancelledFailure(signal) {
726
- const reason = signal.reason;
727
- const code = typeof reason?.code === "number" ? reason.code : import_hwk_adapter_core2.HardwareErrorCode.UserAborted;
728
- const message = typeof reason?.message === "string" ? reason.message : "";
729
- return (0, import_hwk_adapter_core2.failure)(code, message || "All-network get-address cancelled");
730
- }
731
603
  function isTopLevelAllNetworkFailure(response) {
732
604
  if (response.success) {
733
605
  return false;
734
606
  }
735
607
  const code = response.payload?.code;
736
- return code === import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch || (0, import_hwk_adapter_core2.isUserRefusal)(code) || (0, import_hwk_adapter_core2.isConnectionLost)(code);
608
+ return code === import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch || code === import_hwk_adapter_core2.HardwareErrorCode.UserAborted || code === import_hwk_adapter_core2.HardwareErrorCode.UserRejected;
737
609
  }
738
610
  function getItemDeviceId(item) {
739
611
  const { deviceId } = item;
@@ -763,18 +635,8 @@ function normalizeLedgerAllNetworkItem(method, item) {
763
635
  const coin = LEDGER_BTC_NETWORK_COIN_MAP[item.network];
764
636
  return coin ? { ...item, coin } : item;
765
637
  }
766
- async function attachLedgerIdentity(getChainFingerprint, connectId, item, chain, payload, chainFingerprints, context, cancelSignal) {
767
- const knownFingerprint = getItemDeviceId(item) || chainFingerprints.get(chain) || "";
768
- if (!knownFingerprint && cancelSignal.aborted) {
769
- const cancelled = buildCancelledFailure(cancelSignal);
770
- return { ...item, success: false, payload: cancelled.payload };
771
- }
772
- const fingerprint = knownFingerprint || await bootstrapChainFingerprint(
773
- getChainFingerprint,
774
- context.connection?.connectId ?? connectId,
775
- chain,
776
- context
777
- );
638
+ async function attachLedgerIdentity(getChainFingerprint, connectId, item, chain, payload, chainFingerprints) {
639
+ const fingerprint = getItemDeviceId(item) || chainFingerprints.get(chain) || await bootstrapChainFingerprint(getChainFingerprint, connectId, chain);
778
640
  if (!fingerprint) {
779
641
  return buildFingerprintBootstrapFailure(item, chain);
780
642
  }
@@ -795,8 +657,8 @@ async function attachLedgerIdentity(getChainFingerprint, connectId, item, chain,
795
657
  }
796
658
  };
797
659
  }
798
- async function bootstrapChainFingerprint(getChainFingerprint, connectId, chain, context) {
799
- const response = await getChainFingerprint(connectId, chain, context);
660
+ async function bootstrapChainFingerprint(getChainFingerprint, connectId, chain) {
661
+ const response = await getChainFingerprint(connectId, chain);
800
662
  return response.success ? response.payload : "";
801
663
  }
802
664
  function buildFingerprintBootstrapFailure(item, chain) {
@@ -900,32 +762,9 @@ function btcAccountIndexFromPath(path) {
900
762
  var _LedgerAdapter = class _LedgerAdapter {
901
763
  constructor(connector, options) {
902
764
  this.vendor = "ledger";
903
- // A cancel releases the DMK device action and its intent-queue slot, so the
904
- // next call is not blocked behind it. It still cannot retract a confirmation
905
- // screen the device is already showing.
906
- this.cancelCapability = "stops-waiting";
907
765
  this.emitter = new import_hwk_adapter_core3.TypedEventEmitter();
908
- this._operations = new import_hwk_adapter_core3.OperationRegistry({
909
- vendor: "ledger",
910
- onEnded: (operation, reason) => {
911
- const binding = this._pendingOperationBindings.get(operation.operationId);
912
- if (binding?.selectedConnection?.requestId === this._bindingSelectionRequestId) {
913
- this._finishBleBinding("cancelled");
914
- }
915
- this._pendingOperationBindings.delete(operation.operationId);
916
- this.emitter.emit(import_hwk_adapter_core3.SDK.OPERATION_ENDED, {
917
- type: import_hwk_adapter_core3.SDK.OPERATION_ENDED,
918
- payload: { operationId: operation.operationId, reason }
919
- });
920
- if (reason === "timeout") {
921
- void this._releaseOperationConnection(operation);
922
- }
923
- }
924
- });
925
766
  this._discoveredDevices = /* @__PURE__ */ new Map();
926
767
  this._sessions = /* @__PURE__ */ new Map();
927
- this._pendingOperationBindings = /* @__PURE__ */ new Map();
928
- this._verifiedBleReconnectTargets = /* @__PURE__ */ new Map();
929
768
  this._uiRegistry = new import_hwk_adapter_core3.UiRequestRegistry();
930
769
  // BTC App rejects account index >= 100 unless display=true. Cached per
931
770
  // adapter instance: first 100+ path asks the user once via UI request,
@@ -939,31 +778,10 @@ var _LedgerAdapter = class _LedgerAdapter {
939
778
  this._deviceAuthenticityQueueTail = Promise.resolve();
940
779
  // Shared across concurrent callers — only `cancel()` aborts.
941
780
  this._doConnectAbortController = null;
942
- this._unsettledConnectorOperations = /* @__PURE__ */ new Map();
943
- this._connectorIdleWaiters = /* @__PURE__ */ new Set();
944
- this._resetPromise = null;
945
- this._stateGeneration = 0;
946
- this._connectorTeardownTail = Promise.resolve();
947
- this._pendingConnectorTeardowns = 0;
948
- this._activeOperationJobs = /* @__PURE__ */ new Set();
949
- this._pendingOperationDisconnects = /* @__PURE__ */ new Set();
950
781
  this._installProgressLastEmittedValue = -Infinity;
951
782
  this.allNetworkGetAddress = createAllNetworkGetAddress({
952
783
  callChain: this.callChain.bind(this),
953
- getChainFingerprint: async (connectId, chain, context) => {
954
- try {
955
- const fingerprint = await this._computeChainFingerprint(
956
- chain,
957
- (method, params) => this.connectorCall(connectId, method, params, void 0, void 0, void 0, context)
958
- );
959
- return (0, import_hwk_adapter_core3.success)(fingerprint);
960
- } catch (error) {
961
- return this.errorToFailure(error);
962
- }
963
- },
964
- retainOperation: (operationId) => this._operations.retain(operationId),
965
- errorToFailure: (error) => this.errorToFailure(error),
966
- createCancelScope: (queueKey) => this._jobQueue.createCancelScope(queueKey)
784
+ getChainFingerprint: (connectId, chain) => this.getChainFingerprint(connectId, "", chain)
967
785
  });
968
786
  // ---------------------------------------------------------------------------
969
787
  // Private helpers
@@ -973,7 +791,7 @@ var _LedgerAdapter = class _LedgerAdapter {
973
791
  *
974
792
  * - If a session already exists for the given connectId, reuse it.
975
793
  * - If ANY session exists (Ledger IDs are ephemeral), reuse it.
976
- * - Otherwise: search → one USB device auto-connects; multiple asks the host to choose.
794
+ * - Otherwise: search → exactly 1 USB device auto-connects; multiple or none throws.
977
795
  */
978
796
  // Mutex for ensureConnected — prevents concurrent calls from establishing duplicate connections
979
797
  this._connectingPromise = null;
@@ -990,12 +808,6 @@ var _LedgerAdapter = class _LedgerAdapter {
990
808
  });
991
809
  };
992
810
  this.deviceDisconnectHandler = (data) => {
993
- const activeOperation = this._operations.findActiveByConnectionKey(data.connectId);
994
- if (activeOperation && this._activeOperationJobs.has(activeOperation.operationId)) {
995
- this._pendingOperationDisconnects.add(activeOperation.operationId);
996
- } else {
997
- this._operations.endByConnectionKey(data.connectId, "disconnect");
998
- }
999
811
  this._discoveredDevices.delete(data.connectId);
1000
812
  this._sessions.delete(data.connectId);
1001
813
  this.emitter.emit(import_hwk_adapter_core3.DEVICE.DISCONNECT, {
@@ -1052,28 +864,11 @@ var _LedgerAdapter = class _LedgerAdapter {
1052
864
  this._jobQueue = new import_hwk_adapter_core3.DeviceJobQueue();
1053
865
  this.registerEventListeners();
1054
866
  }
1055
- _finishBleBinding(status) {
1056
- const selectionRequestId = this._bindingSelectionRequestId;
1057
- this._bindingSelectionRequestId = void 0;
1058
- if (selectionRequestId)
1059
- this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.DEVICE_BINDING_STATUS, {
1060
- type: import_hwk_adapter_core3.UI_REQUEST.DEVICE_BINDING_STATUS,
1061
- payload: { selectionRequestId, status }
1062
- });
1063
- }
1064
- _isBleConnection() {
1065
- return isLedgerBleConnectionType(this._activeConnectionType ?? this.connector.connectionType);
1066
- }
1067
867
  // Transport
1068
868
  get activeTransport() {
1069
- return this._isBleConnection() ? "ble" : "hid";
869
+ return isLedgerBleConnectionType(this.connector.connectionType) ? "ble" : "hid";
1070
870
  }
1071
871
  getAvailableTransports() {
1072
- if (this.connector.availableTransports) {
1073
- return this.connector.availableTransports.map(
1074
- (transport) => transport === "ble" ? "ble" : "hid"
1075
- );
1076
- }
1077
872
  return this.activeTransport ? [this.activeTransport] : [];
1078
873
  }
1079
874
  // Connector is bound at construction; switching requires a new adapter.
@@ -1090,39 +885,21 @@ var _LedgerAdapter = class _LedgerAdapter {
1090
885
  * The next operation will re-discover and re-connect automatically.
1091
886
  */
1092
887
  resetState() {
1093
- void this._resetStateAndDisconnectSessions();
1094
- }
1095
- _resetStateAndDisconnectSessions() {
1096
- if (this._resetPromise) return this._resetPromise;
1097
- const sessionIds = new Set(this._sessions.values());
1098
- this._stateGeneration += 1;
1099
- this._finishBleBinding("cancelled");
1100
- this._operations.endAll("runtime-reset");
1101
- this._doConnectAbortController?.abort();
1102
888
  this._discoveredDevices.clear();
1103
889
  this._sessions.clear();
1104
- this._verifiedBleReconnectTargets.clear();
1105
890
  this._connectingPromise = null;
1106
- this._doConnectAbortController = null;
1107
891
  this._uiRegistry.reset();
1108
892
  this._jobQueue.clear();
1109
893
  this._btcHighIndexConfirmedThisSession = false;
1110
- const resetPromise = this._runConnectorTeardown(async () => {
1111
- for (const sessionId of sessionIds) {
1112
- await this.connector.disconnect(sessionId).catch(() => void 0);
1113
- }
1114
- });
1115
- this._resetPromise = resetPromise;
1116
- return resetPromise.finally(() => {
1117
- if (this._resetPromise === resetPromise) {
1118
- this._resetPromise = null;
1119
- }
1120
- });
1121
894
  }
1122
895
  async dispose() {
1123
- await this._resetStateAndDisconnectSessions();
896
+ this._uiRegistry.reset();
897
+ this._jobQueue.clear();
1124
898
  this.unregisterEventListeners();
1125
899
  this.connector.reset();
900
+ this._discoveredDevices.clear();
901
+ this._sessions.clear();
902
+ this._btcHighIndexConfirmedThisSession = false;
1126
903
  this.emitter.removeAllListeners();
1127
904
  }
1128
905
  uiResponse(response) {
@@ -1132,32 +909,17 @@ var _LedgerAdapter = class _LedgerAdapter {
1132
909
  // Device management
1133
910
  // ---------------------------------------------------------------------------
1134
911
  async searchDevices(options) {
1135
- return this._searchDevices(options);
1136
- }
1137
- async _searchDevices(options, signal) {
1138
912
  debugLog("[LedgerAdapter][REQ]", { method: "searchDevices", params: options });
1139
913
  try {
1140
914
  if (options?.resetSession) {
1141
- await this._resetStateAndDisconnectSessions();
1142
- } else {
1143
- await this._connectorTeardownTail;
1144
- }
1145
- await this._ensureDevicePermission(void 0, void 0, signal);
1146
- if (signal) _LedgerAdapter._throwIfAborted(signal);
1147
- const stateGeneration = this._stateGeneration;
1148
- const devices = await this.connector.searchDevices(
1149
- options?.transportType ? {
1150
- transportType: options.transportType,
1151
- waitForAll: options.waitForAllTransports
1152
- } : void 0
1153
- );
1154
- if (signal) _LedgerAdapter._throwIfAborted(signal);
1155
- if (stateGeneration !== this._stateGeneration) {
1156
- throw (0, import_hwk_adapter_core3.createHwkError)({
1157
- code: import_hwk_adapter_core3.HardwareErrorCode.UserAborted,
1158
- message: "Ledger discovery was reset"
1159
- });
915
+ this._doConnectAbortController?.abort();
916
+ this._sessions.clear();
917
+ this._connectingPromise = null;
918
+ this._doConnectAbortController = null;
919
+ this._btcHighIndexConfirmedThisSession = false;
1160
920
  }
921
+ await this._ensureDevicePermission();
922
+ const devices = await this.connector.searchDevices();
1161
923
  this._discoveredDevices.clear();
1162
924
  for (const d of devices) {
1163
925
  if (d.connectId) {
@@ -1165,7 +927,7 @@ var _LedgerAdapter = class _LedgerAdapter {
1165
927
  }
1166
928
  }
1167
929
  if (this._discoveredDevices.size === 0) {
1168
- await this._ensureDevicePermission(void 0, void 0, signal);
930
+ await this._ensureDevicePermission();
1169
931
  }
1170
932
  const result = Array.from(this._discoveredDevices.values());
1171
933
  debugLog("[LedgerAdapter][RES]", {
@@ -1184,287 +946,41 @@ var _LedgerAdapter = class _LedgerAdapter {
1184
946
  throw err;
1185
947
  }
1186
948
  }
1187
- async searchDeviceTargets(options) {
1188
- const devices = await this.searchDevices(options);
1189
- return devices.map((device) => ({
1190
- searchTargetId: device.connectId,
1191
- searchTargetReusePolicy: (0, import_hwk_adapter_core3.resolveSearchTargetReusePolicy)(device),
1192
- vendor: "ledger",
1193
- connectionType: device.connectionType,
1194
- kind: "physical",
1195
- label: device.label,
1196
- model: device.model,
1197
- modelName: device.modelName,
1198
- serialNumber: device.serialNumber
1199
- }));
1200
- }
1201
- async listConnectionTargets(options) {
1202
- const targets = await this.searchDeviceTargets(options);
1203
- return targets.map(({ searchTargetId, ...target }) => ({
1204
- ...target,
1205
- targetId: searchTargetId
1206
- }));
1207
- }
1208
949
  // USB single-session invariant: evict all sessions, best-effort (see connectDevice).
1209
- async _evictAllSessions(preserveOperationId) {
1210
- this._operations.endAll("explicit", preserveOperationId);
950
+ async _evictAllSessions() {
1211
951
  if (this._sessions.size === 0) return;
1212
952
  const stale = [...this._sessions.values()];
1213
953
  this._sessions.clear();
1214
- await this._runConnectorTeardown(async () => {
1215
- for (const sid of stale) {
1216
- try {
1217
- await this.connector.disconnect(sid);
1218
- } catch {
1219
- }
954
+ for (const sid of stale) {
955
+ try {
956
+ await this.connector.disconnect(sid);
957
+ } catch {
1220
958
  }
1221
- });
959
+ }
1222
960
  }
1223
961
  static _createDeviceBusyError(method) {
1224
962
  return Object.assign(new Error(`Ledger device is busy while calling ${method}`), {
1225
963
  code: import_hwk_adapter_core3.HardwareErrorCode.DeviceBusy
1226
964
  });
1227
965
  }
1228
- async connectDevice(searchTargetId) {
1229
- try {
1230
- return await this._jobQueue.enqueue(
1231
- searchTargetId || "__ledger_connect__",
1232
- async () => {
1233
- const connected = await this._connectTarget(searchTargetId);
1234
- if (!connected.success) return connected;
1235
- return this._createOperation(searchTargetId, connected.payload);
1236
- },
1237
- {
1238
- label: "connectDevice",
1239
- rejectIfBusy: true,
1240
- busyError: _LedgerAdapter._createDeviceBusyError("connectDevice")
1241
- }
1242
- );
1243
- } catch (error) {
1244
- return this.errorToFailure(error);
1245
- }
1246
- }
1247
- async bindBleDevice(params) {
1248
- if (params.identity.vendor !== "ledger" || !params.identity.value) {
1249
- return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "Ledger wallet identity is required");
1250
- }
1251
- const { chain, value: expectedFingerprint } = params.identity;
1252
- try {
1253
- return await this._jobQueue.enqueue(
1254
- expectedFingerprint,
1255
- async (signal) => {
1256
- if (!this.getAvailableTransports().includes("ble")) {
1257
- throw (0, import_hwk_adapter_core3.createHwkError)({
1258
- code: import_hwk_adapter_core3.HardwareErrorCode.TransportNotAvailable,
1259
- message: "Ledger Bluetooth transport is not available"
1260
- });
1261
- }
1262
- this._activeConnectionType = "ble";
1263
- await this._ensureDevicePermission(void 0, void 0, signal);
1264
- const attempt = {
1265
- extra: params.extra,
1266
- bindingReason: "manual-rebind"
1267
- };
1268
- try {
1269
- for (; ; ) {
1270
- const connectId = await this._connectFirstOrSelect(
1271
- [],
1272
- void 0,
1273
- true,
1274
- void 0,
1275
- attempt,
1276
- signal
1277
- );
1278
- const sessionId = this._sessions.get(connectId);
1279
- if (!sessionId) {
1280
- throw (0, import_hwk_adapter_core3.createHwkError)({
1281
- code: import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
1282
- message: "Selected Ledger connection ended"
1283
- });
1284
- }
1285
- let saved = false;
1286
- try {
1287
- const installContext = {
1288
- connection: { connectId, sessionId }
1289
- };
1290
- const fingerprint = await this._computeChainFingerprint(
1291
- chain,
1292
- (method, callParams) => this._runConnectorCall(
1293
- connectId,
1294
- method,
1295
- callParams,
1296
- signal,
1297
- void 0,
1298
- void 0,
1299
- { autoInstallApp: true },
1300
- installContext
1301
- )
1302
- );
1303
- if (fingerprint !== expectedFingerprint) {
1304
- attempt.rejectedConnectIds ?? (attempt.rejectedConnectIds = /* @__PURE__ */ new Set());
1305
- attempt.rejectedConnectIds.add(connectId);
1306
- attempt.rejectedConnectId = connectId;
1307
- } else {
1308
- const persisted = await this._publishVerifiedBleBinding(
1309
- connectId,
1310
- chain,
1311
- fingerprint,
1312
- attempt,
1313
- void 0,
1314
- signal
1315
- );
1316
- if (!persisted) {
1317
- throw (0, import_hwk_adapter_core3.createHwkError)({
1318
- code: import_hwk_adapter_core3.HardwareErrorCode.UnknownError,
1319
- message: "Bluetooth binding could not be saved",
1320
- origin: "host"
1321
- });
1322
- }
1323
- saved = true;
1324
- return (0, import_hwk_adapter_core3.success)(connectId);
1325
- }
1326
- } finally {
1327
- if (!saved && this._sessions.get(connectId) === sessionId) {
1328
- this._sessions.delete(connectId);
1329
- const teardown = this._runConnectorTeardown(
1330
- () => this.connector.disconnect(sessionId)
1331
- ).catch(() => void 0);
1332
- if (!signal.aborted) await teardown;
1333
- }
1334
- }
1335
- }
1336
- } catch (error) {
1337
- this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
1338
- throw error;
1339
- }
1340
- },
1341
- {
1342
- label: "bindBleDevice",
1343
- rejectIfBusy: true,
1344
- busyError: _LedgerAdapter._createDeviceBusyError("bindBleDevice")
1345
- }
1346
- );
1347
- } catch (error) {
1348
- return this.errorToFailure(error);
1349
- }
1350
- }
1351
- async acquireOperation(connectId, context) {
1352
- try {
1353
- return await this._jobQueue.enqueue(
1354
- connectId || "__ledger_acquire__",
1355
- async (signal) => {
1356
- const transport = this._isBleConnection() ? "ble" : "usb";
1357
- const hint = context.knownConnections?.find(
1358
- (connection) => connection.transport === transport
1359
- );
1360
- const target = hint && hint.transport !== "qr" ? hint.connectId : connectId;
1361
- await this._ensureDevicePermission(target, void 0, signal);
1362
- const attempt = {
1363
- ...context,
1364
- extra: context.extra ? { ...context.extra } : void 0
1365
- };
1366
- try {
1367
- const resolvedConnectId = await this.ensureConnected(
1368
- target,
1369
- signal,
1370
- true,
1371
- void 0,
1372
- attempt
1373
- );
1374
- _LedgerAdapter._throwIfAborted(signal);
1375
- const result = this._createOperation(connectId, resolvedConnectId);
1376
- if (result.success && attempt.selectedConnection) {
1377
- this._pendingOperationBindings.set(result.payload, attempt);
1378
- }
1379
- return result;
1380
- } catch (error) {
1381
- this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
1382
- throw error;
1383
- }
1384
- },
1385
- {
1386
- label: "acquireOperation",
1387
- rejectIfBusy: true,
1388
- busyError: _LedgerAdapter._createDeviceBusyError("acquireOperation")
1389
- }
1390
- );
1391
- } catch (error) {
1392
- return this.errorToFailure(error);
1393
- }
1394
- }
1395
- _createOperation(searchTargetId, resolvedConnectId) {
1396
- this._operations.endByConnectionKey(resolvedConnectId, "explicit");
1397
- const sessionId = this._sessions.get(resolvedConnectId);
1398
- if (sessionId) this._operations.endByConnectionKey(sessionId, "explicit");
1399
- const connectionType = this._isBleConnection() ? "ble" : "usb";
1400
- const device = this._discoveredDevices.get(resolvedConnectId) ?? {
1401
- vendor: "ledger",
1402
- model: "unknown",
1403
- firmwareVersion: "",
1404
- deviceId: "",
1405
- connectId: resolvedConnectId,
1406
- connectionType
1407
- };
1408
- const operation = this._operations.create({
1409
- searchTargetId,
1410
- connectId: resolvedConnectId,
1411
- device,
1412
- connectionType,
1413
- connectionKeys: [this._sessions.get(resolvedConnectId) ?? ""]
1414
- });
1415
- return (0, import_hwk_adapter_core3.success)(operation.operationId);
1416
- }
1417
- async _connectTarget(connectId, preserveOperationId, signal) {
966
+ async connectDevice(connectId) {
1418
967
  debugLog("[LedgerAdapter][REQ]", { method: "connectDevice", connectId, params: { connectId } });
1419
968
  try {
1420
- this._assertConnectorReady("connectDevice");
1421
- const discoveredType = this._discoveredDevices.get(connectId)?.connectionType;
1422
- if (discoveredType === "usb" || discoveredType === "ble") {
1423
- this._activeConnectionType = discoveredType;
1424
- }
1425
- if (this._isBleConnection() && !connectId) {
969
+ if (isLedgerBleConnectionType(this.connector.connectionType) && !connectId) {
1426
970
  throw Object.assign(new Error("Ledger BLE connectId is required."), {
1427
971
  code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
1428
972
  });
1429
973
  }
1430
- await this._ensureDevicePermission(connectId, void 0, signal);
1431
- if (signal) _LedgerAdapter._throwIfAborted(signal);
1432
- if (this.connector.availableTransports && this.connector.availableTransports.length > 1) {
1433
- await this._evictAllSessions(preserveOperationId);
1434
- } else if (this._isBleConnection()) {
1435
- const previousSessionId = this._sessions.get(connectId);
1436
- this._operations.endByConnectionKey(connectId, "explicit", preserveOperationId);
1437
- if (previousSessionId) {
1438
- this._operations.endByConnectionKey(previousSessionId, "explicit", preserveOperationId);
1439
- this._sessions.delete(connectId);
1440
- await this.connector.disconnect(previousSessionId).catch(() => void 0);
1441
- }
1442
- } else {
1443
- await this._evictAllSessions(preserveOperationId);
1444
- }
1445
- if (signal) _LedgerAdapter._throwIfAborted(signal);
1446
- const stateGeneration = this._stateGeneration;
1447
- const releaseOperation = this._retainConnectorOperation(`connect:${connectId}`);
1448
- let session;
1449
- try {
1450
- session = this.connector.availableTransports?.length ? await this.connector.connect(connectId, {
1451
- transportType: this._activeConnectionType ?? "usb"
1452
- }) : await this.connector.connect(connectId);
1453
- if (signal?.aborted || stateGeneration !== this._stateGeneration) {
1454
- await this.connector.disconnect(session.sessionId).catch(() => void 0);
1455
- throw Object.assign(new Error("Ledger connection aborted"), {
1456
- code: import_hwk_adapter_core3.HardwareErrorCode.UserAborted
1457
- });
1458
- }
1459
- } finally {
1460
- releaseOperation();
974
+ if (!isLedgerBleConnectionType(this.connector.connectionType)) {
975
+ await this._evictAllSessions();
1461
976
  }
1462
- const resolvedConnectId = session.deviceInfo?.connectId || connectId;
1463
- this._sessions.set(resolvedConnectId, session.sessionId);
977
+ await this._ensureDevicePermission(connectId);
978
+ const session = await this.connector.connect(connectId);
979
+ this._sessions.set(connectId, session.sessionId);
1464
980
  if (session.deviceInfo) {
1465
- this._discoveredDevices.set(resolvedConnectId, session.deviceInfo);
981
+ this._discoveredDevices.set(connectId, session.deviceInfo);
1466
982
  }
1467
- const result = (0, import_hwk_adapter_core3.success)(resolvedConnectId);
983
+ const result = (0, import_hwk_adapter_core3.success)(connectId);
1468
984
  debugLog("[LedgerAdapter][RES]", { method: "connectDevice", success: true, payload: result });
1469
985
  return result;
1470
986
  } catch (err) {
@@ -1477,60 +993,30 @@ var _LedgerAdapter = class _LedgerAdapter {
1477
993
  return failureResult;
1478
994
  }
1479
995
  }
1480
- async releaseOperation(operationId) {
1481
- const operation = this._operations.find(operationId);
1482
- if (!operation) {
1483
- this._operations.resolve(operationId);
1484
- return;
1485
- }
1486
- const endedOperation = this._operations.end(operationId, "explicit");
1487
- if (!endedOperation) return;
1488
- const { connectId } = operation;
996
+ async disconnectDevice(connectId) {
1489
997
  debugLog("[LedgerAdapter][REQ]", {
1490
- method: "releaseOperation",
998
+ method: "disconnectDevice",
1491
999
  connectId,
1492
1000
  params: { connectId }
1493
1001
  });
1494
1002
  try {
1495
- await this._releaseOperationConnection(endedOperation);
1496
- debugLog("[LedgerAdapter][RES]", { method: "releaseOperation", success: true });
1003
+ const sessionId = this._sessions.get(connectId);
1004
+ if (sessionId) {
1005
+ await this.connector.disconnect(sessionId);
1006
+ this._sessions.delete(connectId);
1007
+ }
1008
+ debugLog("[LedgerAdapter][RES]", { method: "disconnectDevice", success: true });
1497
1009
  } catch (err) {
1498
1010
  const e = err;
1499
1011
  debugLog("[LedgerAdapter][RES]", {
1500
- method: "releaseOperation",
1012
+ method: "disconnectDevice",
1501
1013
  success: false,
1502
1014
  error: { message: e?.message, _tag: e?._tag, code: e?.code ?? e?.errorCode }
1503
1015
  });
1504
1016
  throw err;
1505
1017
  }
1506
1018
  }
1507
- async _releaseOperationConnection(operation) {
1508
- const sessionIds = /* @__PURE__ */ new Set();
1509
- for (const [connectId, sessionId] of this._sessions) {
1510
- if (connectId === operation.connectId || operation.connectionKeys.includes(connectId) || operation.connectionKeys.includes(sessionId)) {
1511
- this._sessions.delete(connectId);
1512
- sessionIds.add(sessionId);
1513
- }
1514
- }
1515
- for (const sessionId of sessionIds) {
1516
- await this._runConnectorTeardown(
1517
- () => this.connector.disconnect(sessionId).catch(() => void 0)
1518
- );
1519
- }
1520
- }
1521
- async _releaseLostOperationConnection(operationId) {
1522
- const endedOperation = this._operations.end(operationId, "disconnect");
1523
- if (!endedOperation) return;
1524
- this._discoveredDevices.delete(endedOperation.connectId);
1525
- await this._releaseOperationConnection(endedOperation);
1526
- }
1527
- async getDeviceInfo(connectIdOrOperationId, deviceId) {
1528
- let connectId;
1529
- try {
1530
- connectId = (0, import_hwk_adapter_core3.isHardwareOperationId)(connectIdOrOperationId) ? this._operations.resolve(connectIdOrOperationId).connectId : connectIdOrOperationId;
1531
- } catch (error) {
1532
- return this.errorToFailure(error);
1533
- }
1019
+ async getDeviceInfo(connectId, deviceId) {
1534
1020
  debugLog("[LedgerAdapter][REQ]", {
1535
1021
  method: "getDeviceInfo",
1536
1022
  connectId,
@@ -1568,6 +1054,9 @@ var _LedgerAdapter = class _LedgerAdapter {
1568
1054
  throw err;
1569
1055
  }
1570
1056
  }
1057
+ getSupportedChains() {
1058
+ return ["evm", "btc", "sol", "tron"];
1059
+ }
1571
1060
  // ---------------------------------------------------------------------------
1572
1061
  // Chain call helper
1573
1062
  // ---------------------------------------------------------------------------
@@ -1602,21 +1091,13 @@ var _LedgerAdapter = class _LedgerAdapter {
1602
1091
  if (params && typeof params === "object") {
1603
1092
  const {
1604
1093
  autoInstallApp,
1605
- operationId,
1606
1094
  passphraseState: _passphraseState,
1607
1095
  useEmptyPassphrase: _useEmptyPassphrase,
1608
- knownConnections,
1609
- extra,
1610
- allowDeviceSelection,
1611
1096
  ...rest
1612
1097
  } = params;
1613
1098
  return {
1614
1099
  commonParams: {
1615
- autoInstallApp: typeof autoInstallApp === "boolean" ? autoInstallApp : void 0,
1616
- operationId: typeof operationId === "string" ? operationId : void 0,
1617
- knownConnections,
1618
- extra,
1619
- allowDeviceSelection: typeof allowDeviceSelection === "boolean" ? allowDeviceSelection : void 0
1100
+ autoInstallApp: typeof autoInstallApp === "boolean" ? autoInstallApp : void 0
1620
1101
  },
1621
1102
  rest
1622
1103
  };
@@ -1792,27 +1273,6 @@ var _LedgerAdapter = class _LedgerAdapter {
1792
1273
  );
1793
1274
  }
1794
1275
  // ---------------------------------------------------------------------------
1795
- // Zcash chain methods (viewing key + shielded address reads; Zcash app >= 3.8.0)
1796
- // ---------------------------------------------------------------------------
1797
- zcashGetFullViewingKey(connectId, deviceId, params) {
1798
- return this.callChainWithMergedParams(
1799
- connectId,
1800
- deviceId,
1801
- "zcash",
1802
- "zcashGetFullViewingKey",
1803
- params
1804
- );
1805
- }
1806
- zcashGetShieldedAddress(connectId, deviceId, params) {
1807
- return this.callChainWithMergedParams(
1808
- connectId,
1809
- deviceId,
1810
- "zcash",
1811
- "zcashGetShieldedAddress",
1812
- params
1813
- );
1814
- }
1815
- // ---------------------------------------------------------------------------
1816
1276
  // App management — OS-level Ledger app install / list. Bypasses fingerprint
1817
1277
  // and chain-handler dispatch; installApp progress is forwarded to the adapter
1818
1278
  // emitter via 'ui-event' AppInstallProgress events.
@@ -1901,7 +1361,7 @@ var _LedgerAdapter = class _LedgerAdapter {
1901
1361
  );
1902
1362
  }
1903
1363
  await this.connector.configure({ ledgerGenuineCheckWebSocketUrl: relayUrl });
1904
- await this._resetStateAndDisconnectSessions();
1364
+ this.resetState();
1905
1365
  }
1906
1366
  const result = await this.connectorCall(connectId, "getDeviceGenuineCheck", {});
1907
1367
  if (!result.isGenuine) {
@@ -1927,10 +1387,10 @@ var _LedgerAdapter = class _LedgerAdapter {
1927
1387
  if (relayUrl) {
1928
1388
  try {
1929
1389
  await this.connector.configure?.({ ledgerGenuineCheckWebSocketUrl: void 0 });
1930
- await this._resetStateAndDisconnectSessions();
1390
+ this.resetState();
1931
1391
  } catch {
1932
1392
  this.connector.reset();
1933
- await this._resetStateAndDisconnectSessions();
1393
+ this.resetState();
1934
1394
  }
1935
1395
  }
1936
1396
  }
@@ -1942,20 +1402,6 @@ var _LedgerAdapter = class _LedgerAdapter {
1942
1402
  this.emitter.off(event, listener);
1943
1403
  }
1944
1404
  cancel(connectId) {
1945
- const namedOperationIsLive = (id) => {
1946
- try {
1947
- this._operations.resolve(id);
1948
- return true;
1949
- } catch {
1950
- return false;
1951
- }
1952
- };
1953
- if ((0, import_hwk_adapter_core3.isHardwareOperationId)(connectId) && !namedOperationIsLive(connectId)) {
1954
- debugLog("[LedgerAdapter] cancel target already ended; nothing to cancel", {
1955
- connectId
1956
- });
1957
- return;
1958
- }
1959
1405
  const userAbortReason = Object.assign(new Error("User aborted operation"), {
1960
1406
  code: import_hwk_adapter_core3.HardwareErrorCode.UserAborted,
1961
1407
  _tag: ERROR_TAG.UserAborted
@@ -1966,50 +1412,14 @@ var _LedgerAdapter = class _LedgerAdapter {
1966
1412
  this._lastCancelReason = void 0;
1967
1413
  }
1968
1414
  }, 2e3);
1969
- const activeJobId = this._jobQueue.getActiveJob()?.deviceId;
1970
- let operationId;
1971
- if ((0, import_hwk_adapter_core3.isHardwareOperationId)(connectId)) {
1972
- operationId = connectId;
1973
- } else if (!connectId && (0, import_hwk_adapter_core3.isHardwareOperationId)(activeJobId)) {
1974
- operationId = activeJobId;
1975
- }
1976
- let resolvedConnectId = connectId;
1977
- if (operationId) {
1978
- try {
1979
- resolvedConnectId = this._operations.resolve(operationId).connectId;
1980
- } catch {
1981
- resolvedConnectId = void 0;
1982
- }
1983
- }
1984
- const interactionForPhysicalId = !operationId && connectId ? this._operations.findActiveByConnectionKey(connectId) : void 0;
1985
- const pendingOperationId = operationId ?? interactionForPhysicalId?.operationId;
1986
- if (!connectId) {
1987
- this._uiRegistry.cancel();
1988
- } else if (pendingOperationId) {
1989
- this._uiRegistry.cancel(void 0, void 0, pendingOperationId);
1990
- }
1991
- this._finishBleBinding("cancelled");
1992
- if (!connectId) this._pendingOperationBindings.clear();
1993
- else if (pendingOperationId) {
1994
- this._pendingOperationBindings.delete(pendingOperationId);
1995
- }
1996
- const queueKeys = /* @__PURE__ */ new Set();
1997
- if (connectId) queueKeys.add(ledgerQueueKey({ connectId }));
1998
- if (pendingOperationId) queueKeys.add(ledgerQueueKey({ operationId: pendingOperationId }));
1999
- if (queueKeys.size) {
2000
- let cancelledAnyJob = false;
2001
- for (const key of queueKeys) {
2002
- cancelledAnyJob = this._jobQueue.cancelActiveAndPending(key, userAbortReason) || cancelledAnyJob;
2003
- }
2004
- debugLog("[LedgerAdapter] cancel routed to queue keys", {
2005
- queueKeys: [...queueKeys],
2006
- cancelledAnyJob
2007
- });
1415
+ this._uiRegistry.cancel();
1416
+ if (connectId) {
1417
+ this._jobQueue.cancelActiveAndPending(connectId, userAbortReason);
2008
1418
  } else {
2009
1419
  this._jobQueue.cancelActiveAndPending(void 0, userAbortReason);
2010
1420
  }
2011
- if (resolvedConnectId) {
2012
- const sessionId = this._sessions.get(resolvedConnectId) ?? resolvedConnectId;
1421
+ if (connectId) {
1422
+ const sessionId = this._sessions.get(connectId) ?? connectId;
2013
1423
  void this.connector.cancel(sessionId);
2014
1424
  } else {
2015
1425
  for (const sid of this._sessions.values()) void this.connector.cancel(sid);
@@ -2021,99 +1431,41 @@ var _LedgerAdapter = class _LedgerAdapter {
2021
1431
  // ---------------------------------------------------------------------------
2022
1432
  // Chain fingerprint
2023
1433
  // ---------------------------------------------------------------------------
2024
- /** A non-empty deviceId is an expected chain fingerprint, not a transport identifier. */
2025
1434
  async getChainFingerprint(connectId, deviceId, chain) {
2026
1435
  try {
2027
1436
  const fingerprint = await this._computeChainFingerprint(
2028
1437
  chain,
2029
1438
  (method, params) => this.connectorCall(connectId, method, params, void 0, deviceId)
2030
1439
  );
2031
- if (deviceId) {
2032
- if (fingerprint !== deviceId) {
2033
- return (0, import_hwk_adapter_core3.failure)(
2034
- import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch,
2035
- formatDeviceMismatchError(deviceId, fingerprint)
2036
- );
2037
- }
2038
- if ((0, import_hwk_adapter_core3.isHardwareOperationId)(connectId)) {
2039
- const operation = this._operations.resolve(connectId);
2040
- await this._publishVerifiedBleBinding(
2041
- operation.connectId,
2042
- chain,
2043
- fingerprint,
2044
- void 0,
2045
- connectId
2046
- );
2047
- }
2048
- }
2049
1440
  return (0, import_hwk_adapter_core3.success)(fingerprint);
2050
1441
  } catch (err) {
2051
1442
  debugError("[LedgerAdapter] getChainFingerprint error:", chain, err);
2052
1443
  return this.errorToFailure(err);
2053
1444
  }
2054
1445
  }
2055
- /** Discovery may select a BLE target before a later call verifies its wallet. */
2056
- async _publishVerifiedBleBinding(connectId, chain, fingerprint, attempt, operationId, signal) {
2057
- const binding = operationId ? this._pendingOperationBindings.get(operationId) : attempt;
2058
- if (!this._isBleConnection() || binding?.selectedConnection?.connectId !== connectId) {
2059
- return false;
2060
- }
1446
+ /**
1447
+ * Verify fingerprint using an existing sessionId directly.
1448
+ * Safe to call inside connectorCall without causing queue deadlock.
1449
+ */
1450
+ async _verifyDeviceFingerprintWithSession(sessionId, deviceId, chain) {
1451
+ if (!deviceId) return { success: true };
2061
1452
  try {
2062
- const outcome = await (0, import_hwk_adapter_core3.requestSaveDeviceBinding)(
2063
- this.emitter,
2064
- this._uiRegistry,
2065
- {
2066
- selectionRequestId: binding.selectedConnection.requestId,
2067
- connection: { transport: "ble", connectId },
2068
- identity: { vendor: "ledger", type: "chainFingerprint", chain, value: fingerprint },
2069
- extra: binding.extra,
2070
- operationId
2071
- },
2072
- signal
1453
+ const fingerprint = await this._computeChainFingerprint(
1454
+ chain,
1455
+ (method, params) => this._callConnector(sessionId, method, params)
2073
1456
  );
2074
- if (operationId) this._operations.resolve(operationId);
2075
- if (!outcome.saved) {
2076
- debugLog("[LedgerAdapter] BLE binding not persisted by host", {
2077
- connectId,
2078
- reason: outcome.reason
2079
- });
2080
- }
2081
- return outcome.saved;
2082
- } catch (error) {
2083
- if (operationId) {
2084
- this._pendingOperationBindings.delete(operationId);
2085
- this._operations.end(operationId, "explicit");
2086
- }
2087
- const sessionId = this._sessions.get(connectId);
2088
- this._sessions.delete(connectId);
2089
- if (sessionId) {
2090
- const teardown = this._runConnectorTeardown(
2091
- () => this.connector.disconnect(sessionId)
2092
- ).catch(() => void 0);
2093
- if (!signal?.aborted) await teardown;
2094
- }
2095
- throw error;
2096
- } finally {
2097
- if (this._bindingSelectionRequestId === binding.selectedConnection.requestId) {
2098
- this._bindingSelectionRequestId = void 0;
1457
+ if (fingerprint === deviceId) {
1458
+ return { success: true };
2099
1459
  }
2100
- if (operationId) {
2101
- this._pendingOperationBindings.delete(operationId);
1460
+ return { success: false, expected: deviceId, actual: fingerprint };
1461
+ } catch (err) {
1462
+ const mapped = mapLedgerError(err);
1463
+ if (mapped.code === import_hwk_adapter_core3.HardwareErrorCode.WrongApp || mapped.code === import_hwk_adapter_core3.HardwareErrorCode.DeviceLocked) {
1464
+ return { success: true };
2102
1465
  }
1466
+ throw err;
2103
1467
  }
2104
1468
  }
2105
- /** Verify on the acquired session without re-entering the job queue. */
2106
- async _verifyDeviceFingerprintWithSession(sessionId, deviceId, chain) {
2107
- if (!deviceId) return { success: true };
2108
- const fingerprint = await this._computeChainFingerprint(
2109
- chain,
2110
- (method, params) => this._callConnector(sessionId, method, params)
2111
- );
2112
- if (fingerprint === deviceId) {
2113
- return { success: true };
2114
- }
2115
- return { success: false, expected: deviceId, actual: fingerprint };
2116
- }
2117
1469
  /**
2118
1470
  * Compute the chain fingerprint via a caller-supplied call strategy.
2119
1471
  *
@@ -2141,27 +1493,12 @@ var _LedgerAdapter = class _LedgerAdapter {
2141
1493
  address = (await callMethod("solGetAddress", { path, showOnDevice: false })).address;
2142
1494
  } else if (chain === "tron") {
2143
1495
  address = (await callMethod("tronGetAddress", { path, showOnDevice: false })).address;
2144
- } else if (chain === "zcash") {
2145
- address = (await callMethod("zcashGetShieldedAddress", { path, showOnDevice: false })).address;
2146
1496
  } else {
2147
1497
  throw new Error(`Unsupported chain for fingerprint: ${chain}`);
2148
1498
  }
2149
1499
  return (0, import_hwk_adapter_core3.deriveDeviceFingerprint)(address);
2150
1500
  }
2151
1501
  // Ledger WebUSB won't expose a locked device, so we can't auto-detect unlock.
2152
- /**
2153
- * The operation the running device job belongs to, so a UI request raised
2154
- * mid-call can name it. A call pinned to an operation queues under its id
2155
- * (`ledgerQueueKey`); a call without one queues under the connectId, and the
2156
- * live operation on that connection is still the owner. Only work with no
2157
- * operation at all (cold start) comes back undefined.
2158
- */
2159
- _activeOperationId() {
2160
- const activeJobId = this._jobQueue.getActiveJob()?.deviceId;
2161
- if (!activeJobId) return void 0;
2162
- if ((0, import_hwk_adapter_core3.isHardwareOperationId)(activeJobId)) return activeJobId;
2163
- return this._operations.findActiveByConnectionKey(activeJobId)?.operationId;
2164
- }
2165
1502
  // The user must press Confirm after unlocking, which triggers a search retry.
2166
1503
  // If `signal` is provided, an abort cancels the pending UI request so the
2167
1504
  // registry slot is released and a stale RECEIVE_DEVICE_CONNECT won't land in
@@ -2170,18 +1507,15 @@ var _LedgerAdapter = class _LedgerAdapter {
2170
1507
  if (signal?.aborted) {
2171
1508
  _LedgerAdapter._throwIfAborted(signal);
2172
1509
  }
2173
- const operationId = this._activeOperationId();
2174
1510
  const waitPromise = this._uiRegistry.wait(
2175
- import_hwk_adapter_core3.UI_REQUEST.REQUEST_DEVICE_CONNECT,
2176
- { operationId }
1511
+ import_hwk_adapter_core3.UI_REQUEST.REQUEST_DEVICE_CONNECT
2177
1512
  );
2178
1513
  this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.REQUEST_DEVICE_CONNECT, {
2179
1514
  type: import_hwk_adapter_core3.UI_REQUEST.REQUEST_DEVICE_CONNECT,
2180
1515
  payload: {
2181
1516
  vendor: "ledger",
2182
1517
  reason: "device-not-found",
2183
- message: "Please connect and unlock your Ledger device",
2184
- operationId
1518
+ message: "Please connect and unlock your Ledger device"
2185
1519
  }
2186
1520
  });
2187
1521
  let payload;
@@ -2242,18 +1576,15 @@ var _LedgerAdapter = class _LedgerAdapter {
2242
1576
  return { ...params, showOnDevice: true };
2243
1577
  }
2244
1578
  async _waitForBtcHighIndexConfirm(path, accountIndex) {
2245
- const operationId = this._activeOperationId();
2246
1579
  const waitPromise = this._uiRegistry.wait(
2247
- import_hwk_adapter_core3.UI_REQUEST.REQUEST_BTC_HIGH_INDEX_CONFIRM,
2248
- { operationId }
1580
+ import_hwk_adapter_core3.UI_REQUEST.REQUEST_BTC_HIGH_INDEX_CONFIRM
2249
1581
  );
2250
1582
  this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.REQUEST_BTC_HIGH_INDEX_CONFIRM, {
2251
1583
  type: import_hwk_adapter_core3.UI_REQUEST.REQUEST_BTC_HIGH_INDEX_CONFIRM,
2252
1584
  payload: {
2253
1585
  vendor: "ledger",
2254
1586
  path,
2255
- accountIndex,
2256
- operationId
1587
+ accountIndex
2257
1588
  }
2258
1589
  });
2259
1590
  try {
@@ -2270,14 +1601,12 @@ var _LedgerAdapter = class _LedgerAdapter {
2270
1601
  // Ask the user whether to install a missing app (autoInstallApp flow).
2271
1602
  // Same register-then-emit ordering as the BTC high-index gate.
2272
1603
  async _waitForInstallAppConfirm(appName) {
2273
- const operationId = this._activeOperationId();
2274
1604
  const waitPromise = this._uiRegistry.wait(
2275
- import_hwk_adapter_core3.UI_REQUEST.REQUEST_INSTALL_APP,
2276
- { operationId }
1605
+ import_hwk_adapter_core3.UI_REQUEST.REQUEST_INSTALL_APP
2277
1606
  );
2278
1607
  this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.REQUEST_INSTALL_APP, {
2279
1608
  type: import_hwk_adapter_core3.UI_REQUEST.REQUEST_INSTALL_APP,
2280
- payload: { vendor: "ledger", appName, operationId }
1609
+ payload: { vendor: "ledger", appName }
2281
1610
  });
2282
1611
  try {
2283
1612
  const payload = await waitPromise;
@@ -2293,17 +1622,16 @@ var _LedgerAdapter = class _LedgerAdapter {
2293
1622
  // Layer 1 entry. Caller signal only races the outer awaiter; the shared
2294
1623
  // `_doConnect` runs under its own internal controller so caller A's cancel
2295
1624
  // doesn't kill caller B's await.
2296
- async ensureConnected(connectId, signal, allowUsbEphemeralFallback = false, preserveOperationId, context) {
1625
+ async ensureConnected(connectId, signal, allowUsbEphemeralFallback = false) {
2297
1626
  if (signal.aborted) _LedgerAdapter._throwIfAborted(signal);
2298
- this._assertConnectorReady("connectDevice");
2299
- if (this._isBleConnection() && !connectId && !allowUsbEphemeralFallback) {
1627
+ if (isLedgerBleConnectionType(this.connector.connectionType) && !connectId) {
2300
1628
  throw Object.assign(new Error("Ledger BLE connectId is required."), {
2301
1629
  code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
2302
1630
  });
2303
1631
  }
2304
1632
  if (connectId && this._sessions.has(connectId)) return connectId;
2305
1633
  if (!connectId && this._sessions.size > 0) {
2306
- if (!this._isBleConnection() && this._sessions.size > 1) {
1634
+ if (!isLedgerBleConnectionType(this.connector.connectionType) && this._sessions.size > 1) {
2307
1635
  throw Object.assign(
2308
1636
  new Error(
2309
1637
  "Ledger USB session invariant violated: more than one session is active. Please reconnect the device."
@@ -2313,24 +1641,15 @@ var _LedgerAdapter = class _LedgerAdapter {
2313
1641
  }
2314
1642
  return this._sessions.keys().next().value;
2315
1643
  }
2316
- if (!this._connectingPromise || this._doConnectAbortController?.signal.aborted) {
2317
- const controller = new AbortController();
2318
- this._doConnectAbortController = controller;
2319
- const innerSignal = controller.signal;
1644
+ if (!this._connectingPromise) {
1645
+ this._doConnectAbortController = new AbortController();
1646
+ const innerSignal = this._doConnectAbortController.signal;
2320
1647
  this._connectingPromise = (async () => {
2321
1648
  try {
2322
- return await this._doConnect(
2323
- innerSignal,
2324
- connectId,
2325
- allowUsbEphemeralFallback,
2326
- preserveOperationId,
2327
- context
2328
- );
1649
+ return await this._doConnect(innerSignal, connectId, allowUsbEphemeralFallback);
2329
1650
  } finally {
2330
- if (this._doConnectAbortController === controller) {
2331
- this._connectingPromise = null;
2332
- this._doConnectAbortController = null;
2333
- }
1651
+ this._connectingPromise = null;
1652
+ this._doConnectAbortController = null;
2334
1653
  }
2335
1654
  })();
2336
1655
  }
@@ -2339,51 +1658,22 @@ var _LedgerAdapter = class _LedgerAdapter {
2339
1658
  // Layer 1 main loop — the ONLY place in SDK that emits unlock dialog.
2340
1659
  // Bounded by MAX_DOCONNECT_CONFIRMS — after N Confirms with no progress,
2341
1660
  // throw DeviceNotFound so the user is kicked out of the loop.
2342
- async _doConnect(internalSignal, targetConnectId, allowUsbEphemeralFallback = false, preserveOperationId, context) {
2343
- _LedgerAdapter._throwIfAborted(internalSignal);
2344
- if (this.connector.availableTransports?.includes("usb") && this.connector.availableTransports.includes("ble")) {
2345
- this._activeConnectionType = "usb";
2346
- const usbDevices = await this._searchDevices({ transportType: "usb" }, internalSignal);
2347
- _LedgerAdapter._throwIfAborted(internalSignal);
2348
- if (usbDevices.length > 0) {
2349
- const knownUsb = context?.knownConnections?.find(
2350
- (connection) => connection.transport === "usb"
2351
- );
2352
- const usbTarget = knownUsb?.transport === "usb" ? knownUsb.connectId : usbDevices.find((device) => device.connectId === targetConnectId)?.connectId;
2353
- return this._connectFirstOrSelect(
2354
- usbDevices,
2355
- usbTarget,
2356
- allowUsbEphemeralFallback,
2357
- preserveOperationId,
2358
- context,
2359
- internalSignal
2360
- );
2361
- }
2362
- this._activeConnectionType = "ble";
2363
- const knownBle = context?.knownConnections?.find(
2364
- (connection) => connection.transport === "ble"
2365
- );
2366
- if (knownBle?.transport === "ble") {
2367
- return this._connectDeviceOrThrow(knownBle.connectId, preserveOperationId, internalSignal);
2368
- }
2369
- if (targetConnectId && context?.knownConnections === void 0) {
2370
- throw (0, import_hwk_adapter_core3.createHwkError)({
2371
- code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound,
2372
- message: "Ledger connection metadata is required before starting Bluetooth binding"
2373
- });
1661
+ async _doConnect(internalSignal, targetConnectId, allowUsbEphemeralFallback = false) {
1662
+ if (isLedgerBleConnectionType(this.connector.connectionType) && targetConnectId) {
1663
+ try {
1664
+ return await this._connectDeviceOrThrow(targetConnectId);
1665
+ } catch (err) {
1666
+ if (!isDeviceLockedError(err) && !isDeviceNotAdvertisingError(err) && !isDeviceDisconnectedError(err)) {
1667
+ throw err;
1668
+ }
1669
+ this._discoveredDevices.delete(targetConnectId);
1670
+ if (isDeviceDisconnectedError(err)) {
1671
+ try {
1672
+ this.connector.reset?.();
1673
+ } catch {
1674
+ }
1675
+ }
2374
1676
  }
2375
- const bleDevices = await this._searchDevices({ transportType: "ble" }, internalSignal);
2376
- return this._connectFirstOrSelect(
2377
- bleDevices,
2378
- void 0,
2379
- allowUsbEphemeralFallback,
2380
- preserveOperationId,
2381
- context,
2382
- internalSignal
2383
- );
2384
- }
2385
- if (this._isBleConnection() && targetConnectId) {
2386
- return this._connectDeviceOrThrow(targetConnectId, preserveOperationId, internalSignal);
2387
1677
  }
2388
1678
  let confirms = 0;
2389
1679
  while (!internalSignal.aborted) {
@@ -2391,28 +1681,22 @@ var _LedgerAdapter = class _LedgerAdapter {
2391
1681
  type: import_hwk_adapter_core3.EConnectorInteraction.Searching,
2392
1682
  payload: { sessionId: "" }
2393
1683
  });
2394
- let devices = await this._searchDevices(void 0, internalSignal);
2395
- _LedgerAdapter._throwIfAborted(internalSignal);
1684
+ let devices = await this.searchDevices();
2396
1685
  if (devices.length === 0) {
2397
1686
  for (let i = 0; i < 3 && !internalSignal.aborted; i += 1) {
2398
1687
  await new Promise((resolve) => {
2399
1688
  setTimeout(resolve, import_hwk_adapter_core3.DEVICE_CONNECT_RETRY_DELAY_MS);
2400
1689
  });
2401
- _LedgerAdapter._throwIfAborted(internalSignal);
2402
- devices = await this._searchDevices(void 0, internalSignal);
2403
- _LedgerAdapter._throwIfAborted(internalSignal);
1690
+ devices = await this.searchDevices();
2404
1691
  if (devices.length > 0) break;
2405
1692
  }
2406
1693
  }
2407
- if (devices.length > 0 || this._isBleConnection() && allowUsbEphemeralFallback) {
1694
+ if (devices.length > 0) {
2408
1695
  try {
2409
1696
  return await this._connectFirstOrSelect(
2410
1697
  devices,
2411
1698
  targetConnectId,
2412
- allowUsbEphemeralFallback,
2413
- preserveOperationId,
2414
- context,
2415
- internalSignal
1699
+ allowUsbEphemeralFallback
2416
1700
  );
2417
1701
  } catch (err) {
2418
1702
  if (!isDeviceLockedError(err) && !isDeviceNotAdvertisingError(err) && !isDeviceDisconnectedError(err)) {
@@ -2441,136 +1725,45 @@ var _LedgerAdapter = class _LedgerAdapter {
2441
1725
  _LedgerAdapter._throwIfAborted(internalSignal);
2442
1726
  throw new Error("_doConnect aborted");
2443
1727
  }
2444
- async _connectFirstOrSelect(devices, targetConnectId, allowUsbEphemeralFallback, preserveOperationId, context, signal) {
2445
- _LedgerAdapter._throwIfAborted(signal);
1728
+ async _connectFirstOrSelect(devices, targetConnectId, allowUsbEphemeralFallback = false) {
2446
1729
  if (targetConnectId) {
2447
1730
  const target = devices.find(
2448
1731
  (d) => d.connectId === targetConnectId || d.deviceId === targetConnectId
2449
1732
  );
2450
1733
  if (target) {
2451
- return this._connectDeviceOrThrow(target.connectId, preserveOperationId, signal);
1734
+ return this._connectDeviceOrThrow(target.connectId);
2452
1735
  }
2453
- if (!this._isBleConnection() && devices.length === 1 && allowUsbEphemeralFallback) {
1736
+ if (!isLedgerBleConnectionType(this.connector.connectionType) && devices.length === 1 && allowUsbEphemeralFallback) {
2454
1737
  debugLog(
2455
1738
  `[LedgerAdapter] target ${targetConnectId} not in fresh enumeration; accepting sole USB device ${devices[0].connectId} for fingerprint-verified recovery`
2456
1739
  );
2457
- return this._connectDeviceOrThrow(devices[0].connectId, preserveOperationId, signal);
1740
+ return this._connectDeviceOrThrow(devices[0].connectId);
2458
1741
  }
2459
- if (!this._isBleConnection() || !allowUsbEphemeralFallback) {
2460
- const err = Object.assign(new Error(`Target Ledger unavailable: ${targetConnectId}`), {
2461
- code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
2462
- });
2463
- if (this._isBleConnection()) {
2464
- err._tag = ERROR_TAG.DeviceNotAdvertising;
2465
- }
2466
- throw err;
1742
+ const err = Object.assign(new Error(`Target Ledger unavailable: ${targetConnectId}`), {
1743
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
1744
+ });
1745
+ if (isLedgerBleConnectionType(this.connector.connectionType)) {
1746
+ err._tag = ERROR_TAG.DeviceNotAdvertising;
2467
1747
  }
1748
+ throw err;
2468
1749
  }
2469
- const requiresBleSelection = this._isBleConnection();
2470
- if (requiresBleSelection && !allowUsbEphemeralFallback) {
1750
+ if (isLedgerBleConnectionType(this.connector.connectionType)) {
2471
1751
  throw Object.assign(new Error("Ledger BLE connectId is required."), {
2472
1752
  code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
2473
1753
  });
2474
1754
  }
2475
- if (requiresBleSelection && context?.allowDeviceSelection !== false) {
2476
- const bindingSessionId = context?.bindingSessionId ?? this._uiRegistry.createRequestId();
2477
- if (context) context.bindingSessionId = bindingSessionId;
2478
- const allowUsbFallback = context?.bindingReason !== "manual-rebind" && Boolean(this.connector.availableTransports?.includes("usb"));
2479
- const knownUsb = context?.knownConnections?.find(
2480
- (connection) => connection.transport === "usb"
2481
- );
2482
- const usbConnectId = knownUsb?.transport === "usb" ? knownUsb.connectId : targetConnectId;
2483
- const { device, requestId } = await (0, import_hwk_adapter_core3.requestBleDeviceSelection)({
2484
- emitter: this.emitter,
2485
- registry: this._uiRegistry,
2486
- signal,
2487
- allowUsbFallback,
2488
- scan: async () => {
2489
- if (allowUsbFallback) {
2490
- const usbDevices = await this._searchDevices({ transportType: "usb" }, signal);
2491
- const candidate = usbDevices.find(
2492
- (device2) => device2.connectionType === "usb" && device2.connectId === usbConnectId
2493
- ) ?? (usbDevices.length === 1 && usbDevices[0].connectionType === "usb" ? usbDevices[0] : void 0);
2494
- if (candidate) return [candidate];
2495
- }
2496
- return (await this._searchDevices({ transportType: "ble", waitForAllTransports: true }, signal)).filter((device2) => !context?.rejectedConnectIds?.has(device2.connectId));
2497
- },
2498
- request: {
2499
- devices: devices.filter((device2) => !context?.rejectedConnectIds?.has(device2.connectId)),
2500
- bindingSessionId,
2501
- rejectedConnectId: context?.rejectedConnectId,
2502
- context: {
2503
- kind: "bind-connection",
2504
- transport: "ble",
2505
- reason: context?.bindingReason ?? (targetConnectId ? "known-connection-unavailable" : "missing-binding")
2506
- },
2507
- extra: context?.extra,
2508
- operationId: preserveOperationId
2509
- }
2510
- });
2511
- if (device.connectionType === "usb") {
2512
- this._activeConnectionType = "usb";
2513
- if (context) context.selectedConnection = void 0;
2514
- if (preserveOperationId) this._pendingOperationBindings.delete(preserveOperationId);
2515
- this._bindingSelectionRequestId = void 0;
2516
- this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.DEVICE_BINDING_STATUS, {
2517
- type: import_hwk_adapter_core3.UI_REQUEST.DEVICE_BINDING_STATUS,
2518
- payload: { selectionRequestId: requestId, status: "cancelled" }
2519
- });
2520
- return this._connectDeviceOrThrow(device.connectId, preserveOperationId, signal);
2521
- }
2522
- if (context) context.selectedConnection = { connectId: device.connectId, requestId };
2523
- this._bindingSelectionRequestId = requestId;
2524
- return this._connectDeviceOrThrow(device.connectId, preserveOperationId, signal);
2525
- }
2526
- if (devices.length > 0 && (devices.length > 1 || requiresBleSelection)) {
2527
- if (context?.allowDeviceSelection === false || !this.emitter.listenerCount(import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE)) {
2528
- throw (0, import_hwk_adapter_core3.createHwkError)({
2529
- code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound,
2530
- message: "Select a Ledger device before continuing"
2531
- });
2532
- }
2533
- const requestId = this._uiRegistry.createRequestId();
2534
- const operationId = this._activeOperationId();
2535
- const waitPromise = this._uiRegistry.wait(
2536
- import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE,
2537
- { requestId, operationId }
2538
- );
2539
- this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE, {
2540
- type: import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE,
2541
- payload: {
2542
- devices,
2543
- requestId,
2544
- operationId,
2545
- context: requiresBleSelection ? {
2546
- kind: "bind-connection",
2547
- transport: "ble",
2548
- reason: targetConnectId ? "known-connection-unavailable" : "missing-binding"
2549
- } : { kind: "select-device", transport: "usb", reason: "multiple-candidates" },
2550
- extra: context?.extra
2551
- }
2552
- });
2553
- const { sdkConnectId } = await (signal ? this._abortable(signal, waitPromise) : waitPromise);
2554
- if (signal) _LedgerAdapter._throwIfAborted(signal);
2555
- const selected = devices.find((device) => device.connectId === sdkConnectId);
2556
- if (!selected) {
2557
- throw Object.assign(new Error("Selected Ledger is no longer available"), {
2558
- code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
2559
- });
2560
- }
2561
- if (context && requiresBleSelection)
2562
- context.selectedConnection = { connectId: selected.connectId, requestId };
2563
- return this._connectDeviceOrThrow(selected.connectId, preserveOperationId, signal);
1755
+ if (devices.length > 1) {
1756
+ throw createMultipleUsbLedgerDevicesError();
2564
1757
  }
2565
1758
  if (devices.length !== 1) {
2566
1759
  throw Object.assign(new Error("Ledger device not found."), {
2567
1760
  code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
2568
1761
  });
2569
1762
  }
2570
- return this._connectDeviceOrThrow(devices[0].connectId, preserveOperationId, signal);
1763
+ return this._connectDeviceOrThrow(devices[0].connectId);
2571
1764
  }
2572
- async _connectDeviceOrThrow(chosenConnectId, preserveOperationId, signal) {
2573
- const result = await this._connectTarget(chosenConnectId, preserveOperationId, signal);
1765
+ async _connectDeviceOrThrow(chosenConnectId) {
1766
+ const result = await this.connectDevice(chosenConnectId);
2574
1767
  if (!result.success) {
2575
1768
  const payload = result.payload;
2576
1769
  const rethrow = Object.assign(new Error(payload.error), {
@@ -2581,7 +1774,7 @@ var _LedgerAdapter = class _LedgerAdapter {
2581
1774
  }
2582
1775
  throw rethrow;
2583
1776
  }
2584
- return result.payload;
1777
+ return chosenConnectId;
2585
1778
  }
2586
1779
  /**
2587
1780
  * Call the connector with automatic session resolution and disconnect retry.
@@ -2611,122 +1804,26 @@ var _LedgerAdapter = class _LedgerAdapter {
2611
1804
  * lives in one place.
2612
1805
  */
2613
1806
  async _callConnector(sessionId, method, params, signal) {
2614
- this._assertConnectorReady(method);
2615
- if (signal?.aborted) throw this._abortReason(signal);
2616
- const releaseOperation = this._retainConnectorOperation(`call:${sessionId}`);
2617
- let promise;
2618
- try {
2619
- promise = this.connector.call(sessionId, method, params).finally(releaseOperation);
2620
- } catch (error) {
2621
- releaseOperation();
2622
- throw error;
2623
- }
1807
+ const promise = this.connector.call(sessionId, method, params);
2624
1808
  const result = signal ? await this._abortable(signal, promise) : await promise;
2625
1809
  return this._unwrapConnectorResult(result);
2626
1810
  }
2627
- _assertConnectorReady(method) {
2628
- if (this._resetPromise || this._pendingConnectorTeardowns > 0 || this._unsettledConnectorOperations.size > 0) {
2629
- throw _LedgerAdapter._createDeviceBusyError(method);
2630
- }
2631
- }
2632
- _runConnectorTeardown(task) {
2633
- const previous = this._connectorTeardownTail;
2634
- let releaseTail = () => void 0;
2635
- this._connectorTeardownTail = new Promise((resolve) => {
2636
- releaseTail = resolve;
2637
- });
2638
- this._pendingConnectorTeardowns += 1;
2639
- return (async () => {
2640
- try {
2641
- await previous;
2642
- await this._waitForConnectorOperationsToDrain();
2643
- await task();
2644
- } finally {
2645
- this._pendingConnectorTeardowns -= 1;
2646
- releaseTail();
2647
- }
2648
- })();
2649
- }
2650
- _waitForConnectorOperationsToDrain() {
2651
- if (this._unsettledConnectorOperations.size === 0) {
2652
- return Promise.resolve();
2653
- }
2654
- return new Promise((resolve) => {
2655
- this._connectorIdleWaiters.add(resolve);
2656
- });
2657
- }
2658
- _retainConnectorOperation(key) {
2659
- this._unsettledConnectorOperations.set(
2660
- key,
2661
- (this._unsettledConnectorOperations.get(key) ?? 0) + 1
2662
- );
2663
- let released = false;
2664
- return () => {
2665
- if (released) return;
2666
- released = true;
2667
- const remaining = (this._unsettledConnectorOperations.get(key) ?? 1) - 1;
2668
- if (remaining > 0) {
2669
- this._unsettledConnectorOperations.set(key, remaining);
2670
- } else {
2671
- this._unsettledConnectorOperations.delete(key);
2672
- }
2673
- if (this._unsettledConnectorOperations.size === 0) {
2674
- for (const resolve of this._connectorIdleWaiters) resolve();
2675
- this._connectorIdleWaiters.clear();
2676
- }
2677
- };
2678
- }
2679
1811
  async connectorCall(connectId, method, params, fingerprint, permissionDeviceId, commonParams, installContext) {
2680
- const positionalOperationId = (0, import_hwk_adapter_core3.isHardwareOperationId)(connectId) ? connectId : void 0;
2681
- if (positionalOperationId && commonParams?.operationId && positionalOperationId !== commonParams.operationId) {
2682
- throw (0, import_hwk_adapter_core3.createHwkError)({
2683
- code: import_hwk_adapter_core3.HardwareErrorCode.InvalidParams,
2684
- message: "Conflicting Ledger operation ids",
2685
- params: {
2686
- positionalOperationId,
2687
- commonOperationId: commonParams.operationId
2688
- }
2689
- });
2690
- }
2691
- const operationId = commonParams?.operationId ?? positionalOperationId;
2692
- const operation = operationId ? this._operations.resolve(operationId) : void 0;
2693
- const releaseOperationRetention = operationId ? this._operations.retain(operationId) : void 0;
2694
- const effectiveConnectId = operation?.connectId ?? connectId;
2695
- debugLog("[LedgerAdapter][REQ]", {
2696
- method,
2697
- connectId: effectiveConnectId || "(empty)",
2698
- params
2699
- });
2700
- const queueKey = ledgerQueueKey({ operationId, connectId: effectiveConnectId });
1812
+ debugLog("[LedgerAdapter][REQ]", { method, connectId: connectId || "(empty)", params });
1813
+ const queueKey = connectId || "__ledger_default__";
2701
1814
  try {
2702
1815
  const result = await this._jobQueue.enqueue(
2703
1816
  queueKey,
2704
- async (signal) => {
2705
- if (operationId) this._activeOperationJobs.add(operationId);
2706
- try {
2707
- return await this._runConnectorCall(
2708
- effectiveConnectId,
2709
- method,
2710
- params,
2711
- signal,
2712
- fingerprint,
2713
- permissionDeviceId,
2714
- commonParams,
2715
- installContext ?? {},
2716
- operationId
2717
- );
2718
- } catch (error) {
2719
- this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
2720
- throw error;
2721
- } finally {
2722
- if (operationId) {
2723
- this._activeOperationJobs.delete(operationId);
2724
- if (this._pendingOperationDisconnects.delete(operationId)) {
2725
- await this._releaseLostOperationConnection(operationId);
2726
- }
2727
- }
2728
- }
2729
- },
1817
+ async (signal) => this._runConnectorCall(
1818
+ connectId,
1819
+ method,
1820
+ params,
1821
+ signal,
1822
+ fingerprint,
1823
+ permissionDeviceId,
1824
+ commonParams,
1825
+ installContext
1826
+ ),
2730
1827
  {
2731
1828
  label: method,
2732
1829
  rejectIfBusy: true,
@@ -2747,22 +1844,15 @@ var _LedgerAdapter = class _LedgerAdapter {
2747
1844
  }
2748
1845
  });
2749
1846
  throw err;
2750
- } finally {
2751
- releaseOperationRetention?.();
2752
1847
  }
2753
1848
  }
2754
1849
  /**
2755
1850
  * Race a promise against an abort signal. On abort, rejects with
2756
1851
  * signal.reason → instance _lastCancelReason → generic Error('Aborted').
2757
1852
  */
2758
- /** Hermes/RN polyfills don't always populate signal.reason; fall back. */
2759
- _abortReason(signal) {
2760
- return signal.reason ?? this._lastCancelReason ?? new Error("Aborted");
2761
- }
2762
1853
  _abortable(signal, promise) {
2763
- const getAbortReason = () => this._abortReason(signal);
1854
+ const getAbortReason = () => signal.reason ?? this._lastCancelReason ?? new Error("Aborted");
2764
1855
  if (signal.aborted) {
2765
- void promise.catch(() => void 0);
2766
1856
  return Promise.reject(getAbortReason());
2767
1857
  }
2768
1858
  return new Promise((resolve, reject) => {
@@ -2789,15 +1879,13 @@ var _LedgerAdapter = class _LedgerAdapter {
2789
1879
  }
2790
1880
  }
2791
1881
  /** Actual work done under the job queue — connection, fingerprint, call, and recovery. */
2792
- async _runConnectorCall(connectId, method, params, signal, fingerprint, permissionDeviceId, commonParams, installContext, operationId, lockedRetryBudget = _LedgerAdapter.MAX_BUSINESS_RETRY_BUDGET) {
1882
+ async _runConnectorCall(connectId, method, params, signal, fingerprint, permissionDeviceId, commonParams, installContext) {
2793
1883
  _LedgerAdapter._throwIfAborted(signal);
2794
- if (!operationId) {
2795
- await this._ensureDevicePermission(
2796
- connectId,
2797
- permissionDeviceId ?? fingerprint?.deviceId,
2798
- signal
2799
- );
2800
- }
1884
+ await this._ensureDevicePermission(
1885
+ connectId,
1886
+ permissionDeviceId ?? fingerprint?.deviceId,
1887
+ signal
1888
+ );
2801
1889
  _LedgerAdapter._throwIfAborted(signal);
2802
1890
  let effectiveParams = params;
2803
1891
  if (method === "btcGetPublicKey") {
@@ -2811,135 +1899,36 @@ var _LedgerAdapter = class _LedgerAdapter {
2811
1899
  effectiveParams = gatedParams;
2812
1900
  }
2813
1901
  const allowUsbEphemeralFallback = !!fingerprint?.deviceId && !fingerprint.skipFingerprint;
2814
- let businessCallStarted = false;
2815
- const verifiedBleTarget = connectId ? this._verifiedBleReconnectTargets.get(connectId) : void 0;
2816
- const knownTransport = this._isBleConnection() ? "ble" : "usb";
2817
- const hintedConnectId = commonParams?.knownConnections?.find(
2818
- (connection) => connection.transport === knownTransport
2819
- );
2820
- const inputConnectId = hintedConnectId && hintedConnectId.transport !== "qr" ? hintedConnectId.connectId : connectId;
2821
- const preferredConnectId = fingerprint && !fingerprint.skipFingerprint && verifiedBleTarget?.chain === fingerprint.chain && verifiedBleTarget.fingerprint === fingerprint.deviceId ? verifiedBleTarget.connectId : inputConnectId;
2822
- const connectionAttempt = { ...commonParams };
2823
- const bundleConnection = installContext?.connection;
2824
- if (bundleConnection && this._sessions.get(bundleConnection.connectId) !== bundleConnection.sessionId) {
2825
- throw (0, import_hwk_adapter_core3.createHwkError)({
2826
- code: import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
2827
- message: "Ledger all-network connection ended"
2828
- });
2829
- }
2830
- let resolvedConnectId = operationId ? this._operations.resolve(operationId).connectId : bundleConnection?.connectId ?? await this.ensureConnected(
2831
- preferredConnectId,
1902
+ const resolvedConnectId = await this.ensureConnected(
1903
+ connectId,
2832
1904
  signal,
2833
- allowUsbEphemeralFallback,
2834
- void 0,
2835
- connectionAttempt
1905
+ allowUsbEphemeralFallback
2836
1906
  );
2837
- let sessionId = this._sessions.get(resolvedConnectId);
2838
- if (sessionId && installContext && !installContext.connection) {
2839
- installContext.connection = { connectId: resolvedConnectId, sessionId };
2840
- }
1907
+ const sessionId = this._sessions.get(resolvedConnectId);
2841
1908
  if (!sessionId) {
2842
- if (operationId) {
2843
- this._operations.end(operationId, "disconnect");
2844
- throw (0, import_hwk_adapter_core3.createHwkError)({
2845
- code: import_hwk_adapter_core3.HardwareErrorCode.OperationEnded,
2846
- message: "Ledger operation connection is no longer active",
2847
- params: { operationId, reason: "disconnect" }
2848
- });
2849
- }
2850
1909
  throw Object.assign(new Error("Auto-connect succeeded but no session found"), {
2851
1910
  _tag: ERROR_TAG.DeviceSessionNotFound
2852
1911
  });
2853
1912
  }
2854
1913
  try {
2855
1914
  if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId) {
2856
- for (; ; ) {
2857
- const fp = await this._abortable(
2858
- signal,
2859
- this._verifyDeviceFingerprintWithSession(
2860
- sessionId,
2861
- fingerprint.deviceId,
2862
- fingerprint.chain
2863
- )
2864
- );
2865
- if (fp.success) break;
2866
- const binding = operationId ? this._pendingOperationBindings.get(operationId) : connectionAttempt;
2867
- if (!this._isBleConnection() || binding?.selectedConnection?.connectId !== resolvedConnectId) {
2868
- throw Object.assign(new Error(formatDeviceMismatchError(fp.expected, fp.actual)), {
2869
- code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch
2870
- });
2871
- }
2872
- binding.rejectedConnectIds ?? (binding.rejectedConnectIds = /* @__PURE__ */ new Set());
2873
- binding.rejectedConnectIds.add(resolvedConnectId);
2874
- binding.rejectedConnectId = resolvedConnectId;
2875
- this._sessions.delete(resolvedConnectId);
2876
- await this.connector.disconnect(sessionId);
2877
- if (operationId) this._pendingOperationDisconnects.delete(operationId);
2878
- _LedgerAdapter._throwIfAborted(signal);
2879
- resolvedConnectId = await this._connectFirstOrSelect(
2880
- [],
2881
- void 0,
2882
- true,
2883
- operationId,
2884
- binding,
2885
- signal
2886
- );
2887
- const selectedSession = this._sessions.get(resolvedConnectId);
2888
- const selectedDevice = this._discoveredDevices.get(resolvedConnectId);
2889
- if (!selectedSession || !selectedDevice)
2890
- throw (0, import_hwk_adapter_core3.createHwkError)({
2891
- code: import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
2892
- message: "Selected Ledger connection ended"
2893
- });
2894
- sessionId = selectedSession;
2895
- if (operationId)
2896
- this._operations.rebind(operationId, {
2897
- connectId: resolvedConnectId,
2898
- device: selectedDevice,
2899
- // Same source as `_createOperation`: the selected transport, not
2900
- // the device snapshot a session connect overwrote.
2901
- connectionType: this._isBleConnection() ? "ble" : "usb",
2902
- connectionKeys: [sessionId]
2903
- });
2904
- if (installContext)
2905
- installContext.connection = { connectId: resolvedConnectId, sessionId };
2906
- }
2907
- await this._publishVerifiedBleBinding(
2908
- resolvedConnectId,
2909
- fingerprint.chain,
2910
- fingerprint.deviceId,
2911
- connectionAttempt,
2912
- operationId,
2913
- signal
1915
+ const fp = await this._abortable(
1916
+ signal,
1917
+ this._verifyDeviceFingerprintWithSession(
1918
+ sessionId,
1919
+ fingerprint.deviceId,
1920
+ fingerprint.chain
1921
+ )
2914
1922
  );
2915
- if (!operationId && connectionAttempt.selectedConnection?.connectId === resolvedConnectId && this._isBleConnection()) {
2916
- this._verifiedBleReconnectTargets.set(connectId, {
2917
- connectId: resolvedConnectId,
2918
- chain: fingerprint.chain,
2919
- fingerprint: fingerprint.deviceId
1923
+ if (!fp.success) {
1924
+ throw Object.assign(new Error(formatDeviceMismatchError(fp.expected, fp.actual)), {
1925
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch
2920
1926
  });
2921
1927
  }
2922
1928
  }
2923
- businessCallStarted = true;
2924
1929
  return await this._callConnector(sessionId, method, effectiveParams, signal);
2925
1930
  } catch (err) {
2926
1931
  if (signal.aborted) throw err;
2927
- if (isDeviceDisconnectedError(err) || isDeviceNotAdvertisingError(err) || isTimeoutError(err) || isConnectionLevelError(err)) {
2928
- this._discoveredDevices.delete(resolvedConnectId);
2929
- if (operationId) await this._releaseLostOperationConnection(operationId);
2930
- else {
2931
- this._sessions.delete(resolvedConnectId);
2932
- await this.connector.disconnect(sessionId).catch(() => void 0);
2933
- }
2934
- const ambiguous = businessCallStarted && !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method);
2935
- const interactionParams = operationId ? { operationId, reason: "disconnect" } : void 0;
2936
- throw (0, import_hwk_adapter_core3.createHwkError)({
2937
- code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : mapLedgerError(err).code,
2938
- message: "Ledger operation connection was lost; start a new operation",
2939
- params: ambiguous ? (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(method, { operationId }) : interactionParams,
2940
- recovery: ambiguous ? { scope: "unknown" } : void 0
2941
- });
2942
- }
2943
1932
  const errObj = err;
2944
1933
  debugLog("[LedgerAdapter] connectorCall error:", method, {
2945
1934
  message: errObj?.message,
@@ -2951,65 +1940,6 @@ var _LedgerAdapter = class _LedgerAdapter {
2951
1940
  isNotAdvertising: isDeviceNotAdvertisingError(err),
2952
1941
  isStuckApp: isStuckAppStateError(err)
2953
1942
  });
2954
- if ((isDeviceLockedError(err) || errObj?.code === import_hwk_adapter_core3.HardwareErrorCode.DeviceLocked) && lockedRetryBudget > 0) {
2955
- await this._waitForDeviceConnect(signal);
2956
- if (this._sessions.get(resolvedConnectId) !== sessionId) {
2957
- throw (0, import_hwk_adapter_core3.createHwkError)({
2958
- code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
2959
- message: "Ledger connection ended while waiting for unlock"
2960
- });
2961
- }
2962
- return this._runConnectorCall(
2963
- resolvedConnectId,
2964
- method,
2965
- effectiveParams,
2966
- signal,
2967
- fingerprint,
2968
- permissionDeviceId,
2969
- commonParams,
2970
- installContext,
2971
- operationId,
2972
- lockedRetryBudget - 1
2973
- );
2974
- }
2975
- if (businessCallStarted && isStuckAppStateError(err)) {
2976
- await this._sleepAbortable(_LedgerAdapter.STUCK_APP_RETRY_DELAY_MS, signal);
2977
- if (this._sessions.get(resolvedConnectId) !== sessionId) {
2978
- throw (0, import_hwk_adapter_core3.createHwkError)({
2979
- code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
2980
- message: "Ledger connection ended during the app transition"
2981
- });
2982
- }
2983
- try {
2984
- return await this._callConnector(sessionId, method, effectiveParams, signal);
2985
- } catch (retryErr) {
2986
- if (isStuckAppStateError(retryErr)) throw err;
2987
- if (isDeviceDisconnectedError(retryErr) || isDeviceNotAdvertisingError(retryErr) || isTimeoutError(retryErr) || isConnectionLevelError(retryErr)) {
2988
- if (operationId) await this._releaseLostOperationConnection(operationId);
2989
- else {
2990
- this._sessions.delete(resolvedConnectId);
2991
- this._discoveredDevices.delete(resolvedConnectId);
2992
- await this.connector.disconnect(sessionId).catch(() => void 0);
2993
- }
2994
- throw (0, import_hwk_adapter_core3.createHwkError)({
2995
- code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : mapLedgerError(retryErr).code,
2996
- message: `Ledger ${method} may have completed before the connection was lost`,
2997
- params: !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method) ? (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(method, {
2998
- operationId,
2999
- reason: "disconnect"
3000
- }) : { operationId, reason: "disconnect" },
3001
- recovery: !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method) ? { scope: "unknown" } : void 0
3002
- });
3003
- }
3004
- throw retryErr;
3005
- }
3006
- }
3007
- if (!operationId && err?.code === import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch) {
3008
- this._sessions.delete(resolvedConnectId);
3009
- this._discoveredDevices.delete(resolvedConnectId);
3010
- await this.connector.disconnect(sessionId).catch(() => void 0);
3011
- throw err;
3012
- }
3013
1943
  const autoInstallApp = commonParams?.autoInstallApp ?? this._defaultAutoInstallApp;
3014
1944
  const isAppMissing = isAppNotInstalledError(err) || err?.code === import_hwk_adapter_core3.HardwareErrorCode.AppNotInstalled;
3015
1945
  if (autoInstallApp && isAppMissing) {
@@ -3065,14 +1995,157 @@ var _LedgerAdapter = class _LedgerAdapter {
3065
1995
  fingerprint,
3066
1996
  permissionDeviceId,
3067
1997
  commonParams,
3068
- installContext,
3069
- operationId
1998
+ installContext
1999
+ );
2000
+ }
2001
+ }
2002
+ if (isStuckAppStateError(err)) {
2003
+ try {
2004
+ this._sessions.delete(resolvedConnectId);
2005
+ this._discoveredDevices.delete(resolvedConnectId);
2006
+ this.connector.reset?.();
2007
+ } catch {
2008
+ }
2009
+ debugLog(
2010
+ "[LedgerAdapter] stuck-app retry: method=",
2011
+ method,
2012
+ "delayMs=",
2013
+ _LedgerAdapter.STUCK_APP_RETRY_DELAY_MS,
2014
+ "_tag=",
2015
+ err?._tag
2016
+ );
2017
+ try {
2018
+ const retryResult = await this._retryAfterStuckApp(
2019
+ resolvedConnectId,
2020
+ method,
2021
+ effectiveParams,
2022
+ signal,
2023
+ err,
2024
+ fingerprint
2025
+ );
2026
+ debugLog("[LedgerAdapter] stuck-app retry succeeded: method=", method);
2027
+ return retryResult;
2028
+ } catch (retryErr) {
2029
+ if (signal.aborted) throw retryErr;
2030
+ if (isStuckAppStateError(retryErr)) {
2031
+ debugLog("[LedgerAdapter] stuck-app retry exhausted (2nd 6901): method=", method);
2032
+ throw err;
2033
+ }
2034
+ debugLog(
2035
+ "[LedgerAdapter] stuck-app retry threw non-stuck error: method=",
2036
+ method,
2037
+ "retryErrTag=",
2038
+ retryErr?._tag
3070
2039
  );
2040
+ throw retryErr;
2041
+ }
2042
+ }
2043
+ if (isDeviceLockedError(err) || isDeviceNotAdvertisingError(err) || isDeviceDisconnectedError(err)) {
2044
+ let lastErr = err;
2045
+ for (let attempt = 0; attempt < _LedgerAdapter.MAX_BUSINESS_RETRY_BUDGET; attempt += 1) {
2046
+ if (signal.aborted) throw lastErr;
2047
+ try {
2048
+ this._sessions.delete(resolvedConnectId);
2049
+ this._discoveredDevices.delete(resolvedConnectId);
2050
+ if (isDeviceDisconnectedError(lastErr)) {
2051
+ try {
2052
+ this.connector.reset?.();
2053
+ } catch {
2054
+ }
2055
+ }
2056
+ const reConnectId = await this.ensureConnected(
2057
+ resolvedConnectId,
2058
+ signal,
2059
+ allowUsbEphemeralFallback
2060
+ );
2061
+ const reSessionId = this._sessions.get(reConnectId);
2062
+ if (!reSessionId) throw lastErr;
2063
+ if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId) {
2064
+ const fp = await this._abortable(
2065
+ signal,
2066
+ this._verifyDeviceFingerprintWithSession(
2067
+ reSessionId,
2068
+ fingerprint.deviceId,
2069
+ fingerprint.chain
2070
+ )
2071
+ );
2072
+ if (!fp.success) {
2073
+ throw Object.assign(new Error(formatDeviceMismatchError(fp.expected, fp.actual)), {
2074
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch
2075
+ });
2076
+ }
2077
+ }
2078
+ return await this._callConnector(reSessionId, method, effectiveParams, signal);
2079
+ } catch (retryErr) {
2080
+ if (signal.aborted) throw retryErr;
2081
+ lastErr = retryErr;
2082
+ const canRetry = attempt < _LedgerAdapter.MAX_BUSINESS_RETRY_BUDGET - 1 && (isDeviceLockedError(retryErr) || isDeviceNotAdvertisingError(retryErr) || isDeviceDisconnectedError(retryErr));
2083
+ if (!canRetry) {
2084
+ throw retryErr;
2085
+ }
2086
+ }
3071
2087
  }
2088
+ throw lastErr;
2089
+ }
2090
+ if (isTimeoutError(err)) {
2091
+ debugLog("[LedgerAdapter] timeout, retrying with fresh connection...");
2092
+ this._discoveredDevices.delete(resolvedConnectId);
2093
+ return this._retryWithFreshConnection(
2094
+ resolvedConnectId,
2095
+ method,
2096
+ effectiveParams,
2097
+ signal,
2098
+ err,
2099
+ fingerprint
2100
+ );
2101
+ }
2102
+ if (isConnectionLevelError(err)) {
2103
+ debugLog("[LedgerAdapter] connection-level fail-closed reset");
2104
+ this._sessions.delete(resolvedConnectId);
2105
+ this._discoveredDevices.delete(resolvedConnectId);
2106
+ this.connector.reset();
2107
+ const codeNum = err?.code;
2108
+ throw Object.assign(err, {
2109
+ code: codeNum ?? import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected
2110
+ });
3072
2111
  }
3073
2112
  throw err;
3074
2113
  }
3075
2114
  }
2115
+ /**
2116
+ * Stuck-app recovery: pause for the device's UI transition, then retry once.
2117
+ *
2118
+ * Caller has already cleared the session + reset connector. We wait so Stax
2119
+ * finishes its post-CloseApp animation, then go through ensureConnected +
2120
+ * fingerprint check + call exactly once. Caller decides what to do on a
2121
+ * second stuck-app hit.
2122
+ */
2123
+ async _retryAfterStuckApp(resolvedConnectId, method, params, signal, originalErr, fingerprint) {
2124
+ await this._sleepAbortable(_LedgerAdapter.STUCK_APP_RETRY_DELAY_MS, signal);
2125
+ const retryConnectId = await this.ensureConnected(
2126
+ resolvedConnectId,
2127
+ signal,
2128
+ !!fingerprint?.deviceId && !fingerprint.skipFingerprint
2129
+ );
2130
+ const retrySessionId = this._sessions.get(retryConnectId);
2131
+ if (!retrySessionId) throw originalErr;
2132
+ if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId) {
2133
+ const fp = await this._abortable(
2134
+ signal,
2135
+ this._verifyDeviceFingerprintWithSession(
2136
+ retrySessionId,
2137
+ fingerprint.deviceId,
2138
+ fingerprint.chain
2139
+ )
2140
+ );
2141
+ if (!fp.success) {
2142
+ throw Object.assign(new Error(formatDeviceMismatchError(fp.expected, fp.actual)), {
2143
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch
2144
+ });
2145
+ }
2146
+ }
2147
+ return this._callConnector(retrySessionId, method, params, signal);
2148
+ }
3076
2149
  _sleepAbortable(ms, signal) {
3077
2150
  return new Promise((resolve, reject) => {
3078
2151
  if (signal.aborted) {
@@ -3090,6 +2163,88 @@ var _LedgerAdapter = class _LedgerAdapter {
3090
2163
  signal.addEventListener("abort", onAbort, { once: true });
3091
2164
  });
3092
2165
  }
2166
+ /**
2167
+ * Clear stale session, reconnect, and retry the call.
2168
+ *
2169
+ * Timeout recovery starts with a full connector reset. After an APDU
2170
+ * timeout, DMK/transport state may still emit malformed responses; retrying
2171
+ * on the same DMK can poison the next chain switch.
2172
+ */
2173
+ async _retryWithFreshConnection(targetConnectId, method, params, signal, originalErr, fingerprint) {
2174
+ this.connector.reset();
2175
+ this._sessions.clear();
2176
+ this._discoveredDevices.clear();
2177
+ this._connectingPromise = null;
2178
+ const allowUsbEphemeralFallback = !!fingerprint?.deviceId && !fingerprint.skipFingerprint;
2179
+ const retryConnectId = await this.ensureConnected(
2180
+ targetConnectId,
2181
+ signal,
2182
+ allowUsbEphemeralFallback
2183
+ );
2184
+ const retrySessionId = this._sessions.get(retryConnectId);
2185
+ if (!retrySessionId) {
2186
+ throw originalErr;
2187
+ }
2188
+ try {
2189
+ if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId) {
2190
+ const fp = await this._abortable(
2191
+ signal,
2192
+ this._verifyDeviceFingerprintWithSession(
2193
+ retrySessionId,
2194
+ fingerprint.deviceId,
2195
+ fingerprint.chain
2196
+ )
2197
+ );
2198
+ if (!fp.success) {
2199
+ throw Object.assign(new Error(formatDeviceMismatchError(fp.expected, fp.actual)), {
2200
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch
2201
+ });
2202
+ }
2203
+ }
2204
+ return await this._callConnector(retrySessionId, method, params, signal);
2205
+ } catch (retryErr) {
2206
+ if (signal.aborted) throw retryErr;
2207
+ this.connector.reset();
2208
+ this._sessions.clear();
2209
+ this._discoveredDevices.clear();
2210
+ this._connectingPromise = null;
2211
+ if (!isDeviceDisconnectedError(retryErr) && !isTimeoutError(retryErr)) {
2212
+ throw retryErr;
2213
+ }
2214
+ debugLog(
2215
+ "[LedgerAdapter] fresh-session retry still failed; resetting connector and rebuilding DMK"
2216
+ );
2217
+ this.connector.reset();
2218
+ this._sessions.clear();
2219
+ this._discoveredDevices.clear();
2220
+ this._connectingPromise = null;
2221
+ const finalConnectId = await this.ensureConnected(
2222
+ targetConnectId,
2223
+ signal,
2224
+ allowUsbEphemeralFallback
2225
+ );
2226
+ const finalSessionId = this._sessions.get(finalConnectId);
2227
+ if (!finalSessionId) {
2228
+ throw originalErr;
2229
+ }
2230
+ if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId) {
2231
+ const fp = await this._abortable(
2232
+ signal,
2233
+ this._verifyDeviceFingerprintWithSession(
2234
+ finalSessionId,
2235
+ fingerprint.deviceId,
2236
+ fingerprint.chain
2237
+ )
2238
+ );
2239
+ if (!fp.success) {
2240
+ throw Object.assign(new Error(formatDeviceMismatchError(fp.expected, fp.actual)), {
2241
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch
2242
+ });
2243
+ }
2244
+ }
2245
+ return this._callConnector(finalSessionId, method, params, signal);
2246
+ }
2247
+ }
3093
2248
  /**
3094
2249
  * Ensure OS-level device permission (Bluetooth / USB) before proceeding.
3095
2250
  *
@@ -3107,14 +2262,13 @@ var _LedgerAdapter = class _LedgerAdapter {
3107
2262
  _LedgerAdapter._throwIfAborted(signal);
3108
2263
  }
3109
2264
  const transportType = this.activeTransport ?? "hid";
3110
- const operationId = this._activeOperationId();
3111
2265
  const waitPromise = this._uiRegistry.wait(
3112
2266
  import_hwk_adapter_core3.UI_REQUEST.REQUEST_DEVICE_PERMISSION,
3113
- { timeoutMs: 6e4, operationId }
2267
+ { timeoutMs: 6e4 }
3114
2268
  );
3115
2269
  this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.REQUEST_DEVICE_PERMISSION, {
3116
2270
  type: import_hwk_adapter_core3.UI_REQUEST.REQUEST_DEVICE_PERMISSION,
3117
- payload: { transportType, connectId, deviceId, operationId }
2271
+ payload: { transportType, connectId, deviceId }
3118
2272
  });
3119
2273
  let response;
3120
2274
  const onAbort = () => {
@@ -3160,15 +2314,7 @@ var _LedgerAdapter = class _LedgerAdapter {
3160
2314
  if (err && typeof err === "object" && "code" in err && typeof err.code === "number") {
3161
2315
  const e = err;
3162
2316
  const params = e.code === import_hwk_adapter_core3.HardwareErrorCode.DevicePermissionDenied && e.reason ? { permissionDeniedReason: e.reason } : e.params;
3163
- return ledgerFailure(
3164
- e.code,
3165
- e.message ?? "Unknown error",
3166
- e.appName,
3167
- tag,
3168
- params,
3169
- void 0,
3170
- (0, import_hwk_adapter_core3.isHwkRecoveryHint)(e.recovery) ? e.recovery : void 0
3171
- );
2317
+ return ledgerFailure(e.code, e.message ?? "Unknown error", e.appName, tag, params);
3172
2318
  }
3173
2319
  const mapped = mapLedgerError(err);
3174
2320
  return ledgerFailure(mapped.code, mapped.message, mapped.appName, tag);
@@ -3195,7 +2341,7 @@ var _LedgerAdapter = class _LedgerAdapter {
3195
2341
  deviceId: device.deviceId,
3196
2342
  connectId: device.connectId,
3197
2343
  label: device.name,
3198
- connectionType: device.connectionType ?? this.connector.connectionType,
2344
+ connectionType: this.connector.connectionType,
3199
2345
  rssi: device.rssi,
3200
2346
  isConnectable: device.isConnectable,
3201
2347
  serialNumber: device.serialNumber,
@@ -3220,7 +2366,7 @@ _LedgerAdapter.APP_INSTALL_PROGRESS_MIN_DELTA = 0.05;
3220
2366
  var LedgerAdapter = _LedgerAdapter;
3221
2367
 
3222
2368
  // src/connector/LedgerConnectorBase.ts
3223
- var import_hwk_adapter_core12 = require("@onekeyfe/hwk-adapter-core");
2369
+ var import_hwk_adapter_core13 = require("@onekeyfe/hwk-adapter-core");
3224
2370
 
3225
2371
  // src/device/LedgerDeviceManager.ts
3226
2372
  var LedgerDeviceManager = class {
@@ -3756,7 +2902,7 @@ var SignerManager = class _SignerManager {
3756
2902
  return (args) => new import_device_signer_kit_ethereum.SignerEthBuilder(args);
3757
2903
  }
3758
2904
  static _createContextModule() {
3759
- const contextModule = new import_context_module.ContextModuleBuilder({}).setChain(import_context_module.ContextModuleChainID.Ethereum).removeDefaultLoaders().build();
2905
+ const contextModule = new import_context_module.ContextModuleBuilder({}).removeDefaultLoaders().build();
3760
2906
  return _SignerManager.wrapBlindSigningReportNonBlocking(contextModule);
3761
2907
  }
3762
2908
  static wrapBlindSigningReportNonBlocking(contextModule) {
@@ -4227,7 +3373,6 @@ function _applySignaturesToPsbt(psbtHex, signatures) {
4227
3373
 
4228
3374
  // src/connector/chains/sol.ts
4229
3375
  var import_hwk_adapter_core9 = require("@onekeyfe/hwk-adapter-core");
4230
- var import_bs58 = __toESM(require("bs58"));
4231
3376
 
4232
3377
  // src/signer/SignerSol.ts
4233
3378
  var SignerSol = class {
@@ -4311,21 +3456,8 @@ async function solSignMessage(ctx, sessionId, params) {
4311
3456
  const path = normalizePath(params.path);
4312
3457
  const messageBytes = (0, import_hwk_adapter_core9.hexToBytes)(params.message);
4313
3458
  try {
4314
- if (params.messageVersion === 1) {
4315
- const preparedMessage = (0, import_hwk_adapter_core9.prepareSolanaOffchainMessageV1)({
4316
- message: messageBytes,
4317
- requiredSigners: params.requiredSigners
4318
- });
4319
- const { SignMessageVersion } = await ctx.importLedgerKit(
4320
- "@ledgerhq/device-signer-kit-solana"
4321
- );
4322
- const result2 = await solSigner.signMessage(path, preparedMessage.serializedMessage, {
4323
- version: SignMessageVersion.Raw
4324
- });
4325
- return { signature: decodeBase58Signature(result2.signature) };
4326
- }
4327
3459
  const result = await solSigner.signMessage(path, messageBytes);
4328
- return { signature: decodeBase58EnvelopeSignature(result.signature) };
3460
+ return { signature: result.signature };
4329
3461
  } catch (err) {
4330
3462
  ctx.invalidateSession(sessionId);
4331
3463
  throw ctx.wrapError(err);
@@ -4333,27 +3465,11 @@ async function solSignMessage(ctx, sessionId, params) {
4333
3465
  ctx.clearCanceller(sessionId);
4334
3466
  }
4335
3467
  }
4336
- function decodeBase58Signature(signature) {
4337
- const bytes = import_bs58.default.decode(signature);
4338
- if (bytes.length !== 64) {
4339
- throw new Error(`Ledger Solana signature must be 64 bytes, received ${bytes.length}`);
4340
- }
4341
- return (0, import_hwk_adapter_core9.bytesToHex)(bytes);
4342
- }
4343
- function decodeBase58EnvelopeSignature(envelope) {
4344
- const bytes = import_bs58.default.decode(envelope);
4345
- if (bytes.length < 65 || bytes[0] !== 1) {
4346
- throw new Error("Ledger Solana signature envelope is invalid");
4347
- }
4348
- return (0, import_hwk_adapter_core9.bytesToHex)(bytes.subarray(1, 65));
4349
- }
4350
3468
  async function _createSolSigner(ctx, sessionId) {
4351
3469
  const dmk = await ctx.getOrCreateDmk();
4352
- const { ContextModuleBuilder: ContextModuleBuilder2, ContextModuleChainID: ContextModuleChainID2 } = await ctx.importLedgerKit(
4353
- "@ledgerhq/context-module"
4354
- );
3470
+ const { ContextModuleBuilder: ContextModuleBuilder2 } = await ctx.importLedgerKit("@ledgerhq/context-module");
4355
3471
  const { SignerSolanaBuilder } = await ctx.importLedgerKit("@ledgerhq/device-signer-kit-solana");
4356
- const contextModule = new ContextModuleBuilder2({}).setChain(ContextModuleChainID2.Solana).removeDefaultLoaders().build();
3472
+ const contextModule = new ContextModuleBuilder2({}).removeDefaultLoaders().build();
4357
3473
  const sdkSigner = new SignerSolanaBuilder({ dmk, sessionId }).withContextModule(contextModule).build();
4358
3474
  const signer = new SignerSol(sdkSigner);
4359
3475
  signer.onInteraction = (interaction) => {
@@ -4369,196 +3485,360 @@ async function _createSolSigner(ctx, sessionId) {
4369
3485
  return signer;
4370
3486
  }
4371
3487
 
4372
- // src/connector/chains/zcash.ts
4373
- var import_hwk_adapter_core10 = require("@onekeyfe/hwk-adapter-core");
3488
+ // src/connector/chains/tron.ts
3489
+ var import_hwk_adapter_core12 = require("@onekeyfe/hwk-adapter-core");
3490
+ var import_hw_app_trx = __toESM(require("@ledgerhq/hw-app-trx"));
4374
3491
 
4375
- // src/signer/SignerZcash.ts
4376
- var SignerZcash = class {
4377
- // eslint-disable-next-line no-useless-constructor, no-empty-function
4378
- constructor(_sdk) {
4379
- this._sdk = _sdk;
3492
+ // src/connector/chains/legacyChainCall.ts
3493
+ var import_hwk_adapter_core11 = require("@onekeyfe/hwk-adapter-core");
3494
+
3495
+ // src/app/AppManager.ts
3496
+ var import_device_management_kit2 = require("@ledgerhq/device-management-kit");
3497
+ var import_hwk_adapter_core10 = require("@onekeyfe/hwk-adapter-core");
3498
+ var APP_NAME_MAP = {
3499
+ ETH: "Ethereum",
3500
+ BTC: "Bitcoin",
3501
+ SOL: "Solana",
3502
+ TRX: "Tron",
3503
+ XRP: "XRP",
3504
+ ADA: "Cardano",
3505
+ DOT: "Polkadot",
3506
+ ATOM: "Cosmos"
3507
+ };
3508
+ var DASHBOARD_APP_NAME = "BOLOS";
3509
+ var AppManager = class {
3510
+ constructor(dmk, options) {
3511
+ this._dmk = dmk;
3512
+ this._waitMs = options?.waitMs ?? 1e3;
3513
+ this._maxRetries = options?.maxRetries ?? 10;
4380
3514
  }
4381
- /** GET_VK: UFVK string (default) or raw 96-byte Orchard FVK. */
4382
- async getFullViewingKey(derivationPath, options) {
4383
- const action = this._sdk.getFullViewingKey(derivationPath, options);
4384
- return deviceActionToPromise(
4385
- action,
4386
- this.onInteraction,
4387
- void 0,
4388
- this.onRegisterCanceller
3515
+ /**
3516
+ * Return the Ledger app name for a given chain ticker,
3517
+ * or undefined if the chain is not supported.
3518
+ */
3519
+ static getAppName(chain) {
3520
+ return APP_NAME_MAP[chain];
3521
+ }
3522
+ /**
3523
+ * Ensure the target app is open on the device identified by `sessionId`.
3524
+ *
3525
+ * Flow:
3526
+ * 1. Check the currently running app.
3527
+ * 2. If it is already the target, return immediately.
3528
+ * 3. If a different app is running (not dashboard), close it first.
3529
+ * 4. Open the target app.
3530
+ * 5. Poll until the device confirms the target app is running.
3531
+ */
3532
+ /**
3533
+ * @param onConfirmOnDevice Called BEFORE OpenAppCommand is issued — the
3534
+ * device is about to display "Open <app>" on screen and wait for the
3535
+ * user's button press. UI consumers should show their "open app" prompt
3536
+ * in response. NOT called when the target app is already open (no user
3537
+ * interaction needed in that case).
3538
+ *
3539
+ * Important: OpenAppCommand is blocking. It does not resolve until the user
3540
+ * has physically confirmed on the device, so anything that runs AFTER
3541
+ * `await this._openApp(...)` lands AFTER the prompt is already gone.
3542
+ * Hence the callback must fire BEFORE that await.
3543
+ */
3544
+ async ensureAppOpen(sessionId, targetAppName, onConfirmOnDevice) {
3545
+ const currentApp = await this._getCurrentApp(sessionId);
3546
+ if (currentApp === targetAppName) {
3547
+ return;
3548
+ }
3549
+ if (!this._isDashboard(currentApp)) {
3550
+ await this._closeCurrentApp(sessionId);
3551
+ await this._waitForApp(sessionId, DASHBOARD_APP_NAME);
3552
+ }
3553
+ onConfirmOnDevice?.();
3554
+ await this._openApp(sessionId, targetAppName);
3555
+ await this._waitForApp(sessionId, targetAppName);
3556
+ }
3557
+ // ---------------------------------------------------------------------------
3558
+ // Private helpers
3559
+ // ---------------------------------------------------------------------------
3560
+ async _getCurrentApp(sessionId) {
3561
+ const result = await this._dmk.sendCommand({
3562
+ sessionId,
3563
+ command: new import_device_management_kit2.GetAppAndVersionCommand()
3564
+ });
3565
+ if ((0, import_device_management_kit2.isSuccessCommandResult)(result)) {
3566
+ debugLog("[AppManager] currentApp:", result.data.name);
3567
+ return result.data.name;
3568
+ }
3569
+ const errResult = result;
3570
+ const dmkErr = errResult.error ?? {};
3571
+ const original = dmkErr.originalError;
3572
+ debugLog(
3573
+ "[AppManager] _getCurrentApp failed sessionId=",
3574
+ sessionId,
3575
+ "tag=",
3576
+ dmkErr._tag,
3577
+ "errorCode=",
3578
+ dmkErr.errorCode,
3579
+ "message=",
3580
+ dmkErr.message,
3581
+ "originalErrorMessage=",
3582
+ original?.message ?? String(original ?? "")
3583
+ );
3584
+ throw Object.assign(
3585
+ new Error(
3586
+ dmkErr.message ?? "Failed to get current app from device"
3587
+ ),
3588
+ {
3589
+ _tag: dmkErr._tag,
3590
+ errorCode: dmkErr.errorCode,
3591
+ originalError: original
3592
+ }
4389
3593
  );
4390
3594
  }
4391
- /** GET_SHIELDED_ADDRESS: single-Orchard-receiver UA for a 5-level transparent path. */
4392
- async getShieldedAddress(derivationPath, options) {
4393
- const action = this._sdk.getShieldedAddress(derivationPath, options);
4394
- return deviceActionToPromise(
4395
- action,
4396
- this.onInteraction,
4397
- void 0,
4398
- this.onRegisterCanceller
3595
+ async _openApp(sessionId, appName) {
3596
+ const result = await this._dmk.sendCommand({
3597
+ sessionId,
3598
+ command: new import_device_management_kit2.OpenAppCommand({ appName })
3599
+ });
3600
+ if (!(0, import_device_management_kit2.isSuccessCommandResult)(result)) {
3601
+ const dmkErr = result.error;
3602
+ const errorCode = "errorCode" in dmkErr && dmkErr.errorCode != null ? String(dmkErr.errorCode) : "";
3603
+ const message = "message" in dmkErr && typeof dmkErr.message === "string" ? dmkErr.message : "";
3604
+ debugLog(
3605
+ "[AppManager] openApp failed:",
3606
+ appName,
3607
+ "errorCode:",
3608
+ errorCode,
3609
+ "tag:",
3610
+ dmkErr._tag
3611
+ );
3612
+ let code;
3613
+ if (errorCode === "6807" || /unknown application/i.test(message)) {
3614
+ code = import_hwk_adapter_core10.HardwareErrorCode.AppNotInstalled;
3615
+ } else if (errorCode === "5501" || dmkErr._tag === "ActionRefusedError") {
3616
+ code = import_hwk_adapter_core10.HardwareErrorCode.UserRejected;
3617
+ }
3618
+ throw Object.assign(new Error(`Failed to open "${appName}"`), {
3619
+ _tag: ERROR_TAG.OpenAppCommand,
3620
+ code,
3621
+ errorCode,
3622
+ statusCode: errorCode,
3623
+ appName,
3624
+ originalError: dmkErr
3625
+ });
3626
+ }
3627
+ }
3628
+ async _closeCurrentApp(sessionId) {
3629
+ debugLog("[AppManager] closeCurrentApp");
3630
+ await this._dmk.sendCommand({
3631
+ sessionId,
3632
+ command: new import_device_management_kit2.CloseAppCommand()
3633
+ });
3634
+ }
3635
+ /**
3636
+ * Poll the device until the expected app is reported as running,
3637
+ * or throw after `_maxRetries` attempts.
3638
+ */
3639
+ async _waitForApp(sessionId, expectedAppName) {
3640
+ let lastSeen = "";
3641
+ for (let i = 0; i < this._maxRetries; i++) {
3642
+ await this._wait();
3643
+ const current = await this._getCurrentApp(sessionId);
3644
+ lastSeen = current;
3645
+ if (current === expectedAppName) {
3646
+ return;
3647
+ }
3648
+ }
3649
+ debugLog(
3650
+ "[AppManager] waitForApp exhausted: expected=",
3651
+ expectedAppName,
3652
+ "lastSeen=",
3653
+ lastSeen
3654
+ );
3655
+ throw new Error(
3656
+ `Ledger: failed to open "${expectedAppName}" after ${this._maxRetries} retries (last seen: ${lastSeen})`
4399
3657
  );
4400
3658
  }
3659
+ _isDashboard(appName) {
3660
+ return appName === DASHBOARD_APP_NAME;
3661
+ }
3662
+ _wait() {
3663
+ return new Promise((resolve) => setTimeout(resolve, this._waitMs));
3664
+ }
4401
3665
  };
4402
3666
 
4403
- // src/connector/chains/zcash.ts
4404
- async function zcashGetFullViewingKey(ctx, sessionId, params) {
4405
- const signer = await _createZcashSigner(ctx, sessionId);
4406
- const path = normalizePath(params.path);
4407
- const mode = params.mode ?? "ufvk";
4408
- try {
4409
- const result = await signer.getFullViewingKey(path, { mode });
4410
- if (result.mode === "ufvk") {
4411
- return { path: params.path, mode, ufvk: result.fullViewingKey };
3667
+ // src/connector/chains/legacyChainCall.ts
3668
+ function isLegacyWrongAppError(err, _appName) {
3669
+ return isWrongAppError(err);
3670
+ }
3671
+ async function withLegacyChainCall(ctx, sessionId, options, action) {
3672
+ const { appName, needsConfirmation } = options;
3673
+ let openAppPromptShown = false;
3674
+ const onAppOpenPrompt = () => {
3675
+ openAppPromptShown = true;
3676
+ ctx.emit("ui-event", {
3677
+ type: import_hwk_adapter_core11.EConnectorInteraction.ConfirmOpenApp,
3678
+ payload: { sessionId }
3679
+ });
3680
+ };
3681
+ const closeOpenAppUiIfShown = () => {
3682
+ if (openAppPromptShown) {
3683
+ ctx.emit("ui-event", {
3684
+ type: import_hwk_adapter_core11.EConnectorInteraction.InteractionComplete,
3685
+ payload: { sessionId }
3686
+ });
3687
+ openAppPromptShown = false;
4412
3688
  }
4413
- return { path: params.path, mode, orchardFvk: (0, import_hwk_adapter_core10.bytesToHex)(result.fullViewingKey) };
3689
+ };
3690
+ try {
3691
+ await _ensureAppOpen(ctx, sessionId, appName, onAppOpenPrompt);
4414
3692
  } catch (err) {
4415
- ctx.invalidateSession(sessionId);
4416
- throw ctx.wrapError(err);
4417
- } finally {
4418
- ctx.clearCanceller(sessionId);
4419
- }
4420
- }
4421
- async function zcashGetShieldedAddress(ctx, sessionId, params) {
4422
- const signer = await _createZcashSigner(ctx, sessionId);
4423
- const path = normalizePath(params.path);
3693
+ debugLog(
3694
+ "[LegacyChainCall] pre-flight ensureAppOpen failed:",
3695
+ appName,
3696
+ err?.message
3697
+ );
3698
+ closeOpenAppUiIfShown();
3699
+ throw ctx.wrapError(err, { defaultAppName: appName });
3700
+ }
3701
+ const runOnce = async () => {
3702
+ let confirmEmitted = false;
3703
+ if (needsConfirmation) {
3704
+ ctx.emit("ui-event", {
3705
+ type: import_hwk_adapter_core11.EConnectorInteraction.ConfirmOnDevice,
3706
+ payload: { sessionId }
3707
+ });
3708
+ confirmEmitted = true;
3709
+ }
3710
+ try {
3711
+ return await action(sessionId);
3712
+ } finally {
3713
+ if (confirmEmitted || openAppPromptShown) {
3714
+ ctx.emit("ui-event", {
3715
+ type: import_hwk_adapter_core11.EConnectorInteraction.InteractionComplete,
3716
+ payload: { sessionId }
3717
+ });
3718
+ openAppPromptShown = false;
3719
+ }
3720
+ }
3721
+ };
4424
3722
  try {
4425
- const result = await signer.getShieldedAddress(path, {
4426
- checkOnDevice: params.showOnDevice ?? false
4427
- });
4428
- return { address: result.address, path: params.path };
3723
+ return await runOnce();
4429
3724
  } catch (err) {
4430
- ctx.invalidateSession(sessionId);
4431
- throw ctx.wrapError(err);
4432
- } finally {
4433
- ctx.clearCanceller(sessionId);
3725
+ if (!isLegacyWrongAppError(err, appName)) {
3726
+ debugLog("[LegacyChainCall] non-wrong-app failure:", appName, err?.message);
3727
+ ctx.invalidateSession(sessionId);
3728
+ throw ctx.wrapError(err, { defaultAppName: appName });
3729
+ }
3730
+ debugLog("[LegacyChainCall] wrong-app detected, retrying:", appName);
3731
+ try {
3732
+ await _ensureAppOpen(ctx, sessionId, appName, onAppOpenPrompt);
3733
+ } catch (switchErr) {
3734
+ debugLog(
3735
+ "[LegacyChainCall] retry ensureAppOpen failed:",
3736
+ appName,
3737
+ switchErr?.message
3738
+ );
3739
+ closeOpenAppUiIfShown();
3740
+ throw ctx.wrapError(switchErr, { defaultAppName: appName });
3741
+ }
3742
+ ctx.clearAllSigners();
3743
+ const result = await runOnce();
3744
+ debugLog("[LegacyChainCall] retry succeeded:", appName);
3745
+ return result;
4434
3746
  }
4435
3747
  }
4436
- async function _createZcashSigner(ctx, sessionId) {
3748
+ async function _ensureAppOpen(ctx, sessionId, appName, onPrompt) {
4437
3749
  const dmk = await ctx.getOrCreateDmk();
4438
- const { SignerZcashBuilder } = await ctx.importLedgerKit("@ledgerhq/device-signer-kit-zcash");
4439
- const sdkSigner = new SignerZcashBuilder({ dmk, sessionId }).build();
4440
- const signer = new SignerZcash(sdkSigner);
4441
- signer.onInteraction = (interaction) => {
4442
- debugLog("[LedgerConnector] zcash.onInteraction:", interaction);
4443
- ctx.emit("ui-event", {
4444
- type: collapseSignerInteraction(interaction),
4445
- payload: { sessionId }
4446
- });
4447
- };
4448
- signer.onRegisterCanceller = (cancel) => ctx.registerCanceller(sessionId, cancel);
4449
- return signer;
3750
+ const appManager = new AppManager(dmk);
3751
+ await appManager.ensureAppOpen(sessionId, appName, onPrompt);
4450
3752
  }
4451
3753
 
4452
- // src/connector/chains/tron.ts
4453
- var import_hwk_adapter_core11 = require("@onekeyfe/hwk-adapter-core");
4454
-
4455
- // src/signer/SignerTron.ts
4456
- var SignerTron = class {
4457
- // eslint-disable-next-line no-useless-constructor, no-empty-function
4458
- constructor(_sdk) {
4459
- this._sdk = _sdk;
4460
- }
4461
- /** Base58 Tron address plus the uncompressed public key at `derivationPath`. */
4462
- async getAddress(derivationPath, options) {
4463
- const action = this._sdk.getAddress(derivationPath, options);
4464
- const result = await deviceActionToPromise(
4465
- action,
4466
- this.onInteraction,
4467
- void 0,
4468
- this.onRegisterCanceller
4469
- );
4470
- return { address: result.address, publicKey: result.publicKey };
3754
+ // src/transport/DmkTransport.ts
3755
+ var import_hw_transport = __toESM(require("@ledgerhq/hw-transport"));
3756
+ var DmkTransport = class extends import_hw_transport.default {
3757
+ constructor(dmk, sessionId) {
3758
+ super();
3759
+ this._dmk = dmk;
3760
+ this._sessionId = sessionId;
4471
3761
  }
4472
- /** Sign a protobuf-encoded raw transaction. */
4473
- async signTransaction(derivationPath, transaction, options) {
4474
- const action = this._sdk.signTransaction(derivationPath, transaction, options);
4475
- return deviceActionToPromise(
4476
- action,
4477
- this.onInteraction,
4478
- void 0,
4479
- this.onRegisterCanceller
4480
- );
3762
+ async exchange(apdu) {
3763
+ const response = await this._dmk.sendApdu({
3764
+ sessionId: this._sessionId,
3765
+ apdu: new Uint8Array(apdu)
3766
+ });
3767
+ const { data, statusCode } = response;
3768
+ const result = Buffer.alloc(data.length + 2);
3769
+ if (data.length > 0) {
3770
+ result.set(data, 0);
3771
+ }
3772
+ result.set(statusCode, data.length);
3773
+ return result;
4481
3774
  }
4482
- /** Sign a personal message (TIP-191). */
4483
- async signPersonalMessage(derivationPath, message, options) {
4484
- const action = this._sdk.signPersonalMessage(derivationPath, message, options);
4485
- return deviceActionToPromise(
4486
- action,
4487
- this.onInteraction,
4488
- void 0,
4489
- this.onRegisterCanceller
4490
- );
3775
+ async close() {
4491
3776
  }
4492
3777
  };
4493
3778
 
4494
3779
  // src/connector/chains/tron.ts
4495
3780
  async function tronGetAddress(ctx, sessionId, params) {
4496
- const tronSigner = await _createTronSigner(ctx, sessionId);
4497
3781
  const path = normalizePath(params.path);
4498
- try {
4499
- const result = await tronSigner.getAddress(path, {
4500
- checkOnDevice: params.showOnDevice ?? false
4501
- });
4502
- return { address: result.address, publicKey: result.publicKey, path: params.path };
4503
- } catch (err) {
4504
- ctx.invalidateSession(sessionId);
4505
- throw ctx.wrapError(err);
4506
- } finally {
4507
- ctx.clearCanceller(sessionId);
4508
- }
3782
+ const showOnDevice = params.showOnDevice ?? false;
3783
+ return withLegacyChainCall(
3784
+ ctx,
3785
+ sessionId,
3786
+ {
3787
+ appName: "Tron",
3788
+ // Only show "confirm on device" UI when the device is actually going
3789
+ // to display the address for the user to verify.
3790
+ needsConfirmation: showOnDevice
3791
+ },
3792
+ async (sid) => {
3793
+ const trx = await _createTrx(ctx, sid);
3794
+ const result = await trx.getAddress(path, showOnDevice);
3795
+ return { address: result.address, publicKey: result.publicKey, path: params.path };
3796
+ }
3797
+ );
4509
3798
  }
4510
3799
  async function tronSignTransaction(ctx, sessionId, params) {
4511
3800
  if (!params.rawTxHex) {
4512
3801
  throw Object.assign(
4513
3802
  new Error("TRON signing requires a protobuf-encoded raw transaction hex (rawTxHex)."),
4514
- { code: import_hwk_adapter_core11.HardwareErrorCode.InvalidParams }
3803
+ { code: import_hwk_adapter_core12.HardwareErrorCode.InvalidParams }
4515
3804
  );
4516
3805
  }
4517
- const tronSigner = await _createTronSigner(ctx, sessionId);
4518
3806
  const path = normalizePath(params.path);
4519
- try {
4520
- const signature = await tronSigner.signTransaction(path, (0, import_hwk_adapter_core11.hexToBytes)(params.rawTxHex));
4521
- return { signature: (0, import_hwk_adapter_core11.bytesToHex)(signature) };
4522
- } catch (err) {
4523
- ctx.invalidateSession(sessionId);
4524
- throw ctx.wrapError(err);
4525
- } finally {
4526
- ctx.clearCanceller(sessionId);
4527
- }
3807
+ return withLegacyChainCall(
3808
+ ctx,
3809
+ sessionId,
3810
+ { appName: "Tron", needsConfirmation: true },
3811
+ async (sid) => {
3812
+ const trx = await _createTrx(ctx, sid);
3813
+ const signature = await trx.signTransaction(
3814
+ path,
3815
+ params.rawTxHex,
3816
+ params.tokenSignatures ?? []
3817
+ );
3818
+ return { signature };
3819
+ }
3820
+ );
4528
3821
  }
4529
3822
  async function tronSignMessage(ctx, sessionId, params) {
4530
- const tronSigner = await _createTronSigner(ctx, sessionId);
4531
3823
  const path = normalizePath(params.path);
4532
- try {
4533
- const signature = await tronSigner.signPersonalMessage(path, (0, import_hwk_adapter_core11.hexToBytes)(params.messageHex));
4534
- return { signature: (0, import_hwk_adapter_core11.bytesToHex)(signature) };
4535
- } catch (err) {
4536
- ctx.invalidateSession(sessionId);
4537
- throw ctx.wrapError(err);
4538
- } finally {
4539
- ctx.clearCanceller(sessionId);
4540
- }
3824
+ return withLegacyChainCall(
3825
+ ctx,
3826
+ sessionId,
3827
+ { appName: "Tron", needsConfirmation: true },
3828
+ async (sid) => {
3829
+ const trx = await _createTrx(ctx, sid);
3830
+ const signature = await trx.signPersonalMessage(path, params.messageHex);
3831
+ return { signature };
3832
+ }
3833
+ );
4541
3834
  }
4542
- async function _createTronSigner(ctx, sessionId) {
3835
+ async function _createTrx(ctx, sessionId) {
4543
3836
  const dmk = await ctx.getOrCreateDmk();
4544
- const { SignerTrxBuilder } = await ctx.importLedgerKit("@ledgerhq/device-signer-kit-tron");
4545
- const sdkSigner = new SignerTrxBuilder({ dmk, sessionId }).build();
4546
- const signer = new SignerTron(sdkSigner);
4547
- signer.onInteraction = (interaction) => {
4548
- debugLog("[LedgerConnector] tron.onInteraction:", interaction);
4549
- ctx.emit("ui-event", {
4550
- type: collapseSignerInteraction(interaction),
4551
- payload: { sessionId }
4552
- });
4553
- };
4554
- signer.onRegisterCanceller = (cancel) => {
4555
- ctx.registerCanceller(sessionId, cancel);
4556
- };
4557
- return signer;
3837
+ return new import_hw_app_trx.default(new DmkTransport(dmk, sessionId));
4558
3838
  }
4559
3839
 
4560
3840
  // src/device-apps/customActions.ts
4561
- var import_device_management_kit2 = require("@ledgerhq/device-management-kit");
3841
+ var import_device_management_kit3 = require("@ledgerhq/device-management-kit");
4562
3842
  var import_rxjs = require("rxjs");
4563
3843
  var GetOsVersionDeviceAction = class {
4564
3844
  // eslint-disable-next-line no-useless-constructor, no-empty-function
@@ -4572,7 +3852,7 @@ var GetOsVersionDeviceAction = class {
4572
3852
  (async () => {
4573
3853
  try {
4574
3854
  subject.next({
4575
- status: import_device_management_kit2.DeviceActionStatus.Pending,
3855
+ status: import_device_management_kit3.DeviceActionStatus.Pending,
4576
3856
  intermediateValue: { requiredUserInteraction: "none" }
4577
3857
  });
4578
3858
  const result = await internalApi.sendCommand(new this._deps.GetOsVersionCommand());
@@ -4581,11 +3861,11 @@ var GetOsVersionDeviceAction = class {
4581
3861
  const errObj = result?.error;
4582
3862
  throw new Error(errObj?.message ?? "GetOsVersionCommand failed");
4583
3863
  }
4584
- subject.next({ status: import_device_management_kit2.DeviceActionStatus.Completed, output: result.data });
3864
+ subject.next({ status: import_device_management_kit3.DeviceActionStatus.Completed, output: result.data });
4585
3865
  subject.complete();
4586
3866
  } catch (err) {
4587
3867
  if (cancelled) return;
4588
- subject.next({ status: import_device_management_kit2.DeviceActionStatus.Error, error: err });
3868
+ subject.next({ status: import_device_management_kit3.DeviceActionStatus.Error, error: err });
4589
3869
  subject.complete();
4590
3870
  }
4591
3871
  })();
@@ -4593,7 +3873,7 @@ var GetOsVersionDeviceAction = class {
4593
3873
  observable: subject.asObservable(),
4594
3874
  cancel: () => {
4595
3875
  cancelled = true;
4596
- subject.next({ status: import_device_management_kit2.DeviceActionStatus.Stopped });
3876
+ subject.next({ status: import_device_management_kit3.DeviceActionStatus.Stopped });
4597
3877
  subject.complete();
4598
3878
  }
4599
3879
  };
@@ -4611,7 +3891,7 @@ var ListAvailableAppsDeviceAction = class {
4611
3891
  (async () => {
4612
3892
  try {
4613
3893
  subject.next({
4614
- status: import_device_management_kit2.DeviceActionStatus.Pending,
3894
+ status: import_device_management_kit3.DeviceActionStatus.Pending,
4615
3895
  intermediateValue: { requiredUserInteraction: "none" }
4616
3896
  });
4617
3897
  const osVersionResult = await internalApi.sendCommand(new this._GetOsVersionCommand());
@@ -4628,11 +3908,11 @@ var ListAvailableAppsDeviceAction = class {
4628
3908
  throw new Error(httpErr?.message ?? "Manager API getAppList failed");
4629
3909
  }
4630
3910
  const apps = either.extract();
4631
- subject.next({ status: import_device_management_kit2.DeviceActionStatus.Completed, output: apps });
3911
+ subject.next({ status: import_device_management_kit3.DeviceActionStatus.Completed, output: apps });
4632
3912
  subject.complete();
4633
3913
  } catch (err) {
4634
3914
  if (cancelled) return;
4635
- subject.next({ status: import_device_management_kit2.DeviceActionStatus.Error, error: err });
3915
+ subject.next({ status: import_device_management_kit3.DeviceActionStatus.Error, error: err });
4636
3916
  subject.complete();
4637
3917
  }
4638
3918
  })();
@@ -4640,7 +3920,7 @@ var ListAvailableAppsDeviceAction = class {
4640
3920
  observable: subject.asObservable(),
4641
3921
  cancel: () => {
4642
3922
  cancelled = true;
4643
- subject.next({ status: import_device_management_kit2.DeviceActionStatus.Stopped });
3923
+ subject.next({ status: import_device_management_kit3.DeviceActionStatus.Stopped });
4644
3924
  subject.complete();
4645
3925
  }
4646
3926
  };
@@ -4733,7 +4013,7 @@ var DeviceApps = class {
4733
4013
  seTargetId: v.seTargetId,
4734
4014
  mcuTargetId: v.mcuTargetId,
4735
4015
  seVersion: v.seVersion,
4736
- seFlagsHex: bytesToHex4(v.seFlags),
4016
+ seFlagsHex: bytesToHex2(v.seFlags),
4737
4017
  mcuSephVersion: v.mcuSephVersion,
4738
4018
  mcuBootloaderVersion: v.mcuBootloaderVersion,
4739
4019
  hwVersion: v.hwVersion
@@ -4807,7 +4087,7 @@ var DeviceApps = class {
4807
4087
  }
4808
4088
  }
4809
4089
  };
4810
- function bytesToHex4(bytes) {
4090
+ function bytesToHex2(bytes) {
4811
4091
  if (!bytes) return "";
4812
4092
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
4813
4093
  }
@@ -4850,11 +4130,10 @@ var METHOD_PREFIX_TO_APP_NAME = {
4850
4130
  evm: "Ethereum",
4851
4131
  btc: "Bitcoin",
4852
4132
  sol: "Solana",
4853
- tron: "Tron",
4854
- zcash: "Zcash"
4133
+ tron: "Tron"
4855
4134
  };
4856
4135
  var HARDWARE_ERROR_CODE_VALUES = new Set(
4857
- Object.values(import_hwk_adapter_core12.HardwareErrorCode).filter((value) => typeof value === "number")
4136
+ Object.values(import_hwk_adapter_core13.HardwareErrorCode).filter((value) => typeof value === "number")
4858
4137
  );
4859
4138
  var BLE_CONNECT_SCAN_TIMEOUT_MS = 1500;
4860
4139
  var LEDGER_RELAY_ALLOWED_ROOT_DOMAINS = ["onekeytest.com", "onekey.com"];
@@ -4891,10 +4170,6 @@ async function defaultLedgerKitImporter(pkg) {
4891
4170
  return import("@ledgerhq/device-signer-kit-bitcoin");
4892
4171
  case "@ledgerhq/device-signer-kit-solana":
4893
4172
  return import("@ledgerhq/device-signer-kit-solana");
4894
- case "@ledgerhq/device-signer-kit-tron":
4895
- return import("@ledgerhq/device-signer-kit-tron");
4896
- case "@ledgerhq/device-signer-kit-zcash":
4897
- return import("@ledgerhq/device-signer-kit-zcash");
4898
4173
  case "@ledgerhq/context-module":
4899
4174
  return import("@ledgerhq/context-module");
4900
4175
  default:
@@ -4954,7 +4229,6 @@ var LedgerConnectorBase = class {
4954
4229
  this._ctx = {
4955
4230
  emit: (event, data) => this._emit(event, data),
4956
4231
  invalidateSession: (sid) => this._invalidateSession(sid),
4957
- teardownSecureChannelSession: (sid) => this._teardownSecureChannelSession(sid),
4958
4232
  wrapError: (err, opts) => this._wrapError(err, opts),
4959
4233
  getOrCreateDmk: () => this._getOrCreateDmk(),
4960
4234
  getDeviceManager: () => this._getDeviceManager(),
@@ -5006,7 +4280,7 @@ var LedgerConnectorBase = class {
5006
4280
  async searchDevices() {
5007
4281
  const dm = await this._getDeviceManager();
5008
4282
  const descriptors = await this._discoverDescriptors(dm);
5009
- const resolvedDescriptors = descriptors.filter((d) => !(0, import_hwk_adapter_core12.isKnownNonTargetHardwareVendor)(d, "ledger")).map((d) => ({
4283
+ const resolvedDescriptors = descriptors.filter((d) => !(0, import_hwk_adapter_core13.isKnownNonTargetHardwareVendor)(d, "ledger")).map((d) => ({
5010
4284
  descriptor: d,
5011
4285
  connectId: this._resolveConnectId(d)
5012
4286
  }));
@@ -5054,7 +4328,7 @@ var LedgerConnectorBase = class {
5054
4328
  `Ledger BLE connect did not return within ${HANG_CEILING_MS / 6e4}min \u2014 DMK hang fallback.`
5055
4329
  );
5056
4330
  err._tag = ERROR_TAG.BlePairingTimeout;
5057
- err.code = import_hwk_adapter_core12.HardwareErrorCode.BlePairingTimeout;
4331
+ err.code = import_hwk_adapter_core13.HardwareErrorCode.BlePairingTimeout;
5058
4332
  reject(err);
5059
4333
  }, HANG_CEILING_MS);
5060
4334
  });
@@ -5087,7 +4361,7 @@ var LedgerConnectorBase = class {
5087
4361
  "Ledger device is not currently advertising. Wake up and unlock the device, keep it nearby, then try again."
5088
4362
  );
5089
4363
  err._tag = ERROR_TAG.DeviceNotAdvertising;
5090
- err.code = import_hwk_adapter_core12.HardwareErrorCode.DeviceNotFound;
4364
+ err.code = import_hwk_adapter_core13.HardwareErrorCode.DeviceNotFound;
5091
4365
  throw err;
5092
4366
  };
5093
4367
  const doConnect = async (path) => {
@@ -5144,14 +4418,14 @@ var LedgerConnectorBase = class {
5144
4418
  this._resetSignersAndSessions();
5145
4419
  if (isLedgerBleConnectionType(this.connectionType)) {
5146
4420
  const tag = err?._tag;
5147
- if (isKnownConnectionTag(tag) && !isConnectionOpeningTag(tag)) {
4421
+ if (isKnownConnectionTag(tag)) {
5148
4422
  throw err;
5149
4423
  }
5150
4424
  const wrapped = new Error(
5151
4425
  "Ledger Bluetooth pairing failed. Make sure the device is unlocked and nearby, then try again."
5152
4426
  );
5153
4427
  wrapped._tag = ERROR_TAG.BleGattBondingFailed;
5154
- wrapped.code = import_hwk_adapter_core12.HardwareErrorCode.BlePairingTimeout;
4428
+ wrapped.code = import_hwk_adapter_core13.HardwareErrorCode.BlePairingTimeout;
5155
4429
  wrapped.originalError = err;
5156
4430
  throw wrapped;
5157
4431
  }
@@ -5229,7 +4503,7 @@ var LedgerConnectorBase = class {
5229
4503
  this._unwatchSessionState(sessionId);
5230
4504
  this._signerManager?.invalidate(sessionId);
5231
4505
  this._cancellers.get(sessionId)?.({
5232
- code: import_hwk_adapter_core12.HardwareErrorCode.DeviceDisconnected,
4506
+ code: import_hwk_adapter_core13.HardwareErrorCode.DeviceDisconnected,
5233
4507
  tag: "DeviceDisconnected",
5234
4508
  message: "Device disconnected"
5235
4509
  });
@@ -5253,9 +4527,9 @@ var LedgerConnectorBase = class {
5253
4527
  if (isAppStuckByApdu(err)) {
5254
4528
  return {
5255
4529
  success: false,
5256
- error: (0, import_hwk_adapter_core12.serializeConnectorError)(
4530
+ error: (0, import_hwk_adapter_core13.serializeConnectorError)(
5257
4531
  Object.assign(new Error("Ledger app is unresponsive"), {
5258
- code: import_hwk_adapter_core12.HardwareErrorCode.DeviceAppStuck,
4532
+ code: import_hwk_adapter_core13.HardwareErrorCode.DeviceAppStuck,
5259
4533
  _tag: ERROR_TAG.DeviceAppStuck,
5260
4534
  originalError: err
5261
4535
  })
@@ -5265,16 +4539,16 @@ var LedgerConnectorBase = class {
5265
4539
  if (isTransportStuck(err)) {
5266
4540
  return {
5267
4541
  success: false,
5268
- error: (0, import_hwk_adapter_core12.serializeConnectorError)(
4542
+ error: (0, import_hwk_adapter_core13.serializeConnectorError)(
5269
4543
  Object.assign(new Error("Device communication interrupted, please retry"), {
5270
- code: import_hwk_adapter_core12.HardwareErrorCode.TransportError,
4544
+ code: import_hwk_adapter_core13.HardwareErrorCode.TransportError,
5271
4545
  _tag: ERROR_TAG.DeviceTransportStuck,
5272
4546
  originalError: err
5273
4547
  })
5274
4548
  )
5275
4549
  };
5276
4550
  }
5277
- return { success: false, error: (0, import_hwk_adapter_core12.serializeConnectorError)(err) };
4551
+ return { success: false, error: (0, import_hwk_adapter_core13.serializeConnectorError)(err) };
5278
4552
  }
5279
4553
  }
5280
4554
  async _dispatch(sessionId, method, params) {
@@ -5313,11 +4587,6 @@ var LedgerConnectorBase = class {
5313
4587
  return solSignTransaction(ctx, sessionId, params);
5314
4588
  case "solSignMessage":
5315
4589
  return solSignMessage(ctx, sessionId, params);
5316
- // ZCASH
5317
- case "zcashGetFullViewingKey":
5318
- return zcashGetFullViewingKey(ctx, sessionId, params);
5319
- case "zcashGetShieldedAddress":
5320
- return zcashGetShieldedAddress(ctx, sessionId, params);
5321
4590
  // TRON
5322
4591
  case "tronGetAddress":
5323
4592
  return tronGetAddress(ctx, sessionId, params);
@@ -5342,7 +4611,7 @@ var LedgerConnectorBase = class {
5342
4611
  try {
5343
4612
  return await apps.install(p.appName, ({ progress }) => {
5344
4613
  ctx.emit("ui-event", {
5345
- type: import_hwk_adapter_core12.EConnectorInteraction.AppInstallProgress,
4614
+ type: import_hwk_adapter_core13.EConnectorInteraction.AppInstallProgress,
5346
4615
  payload: {
5347
4616
  sessionId,
5348
4617
  appName: p.appName,
@@ -5351,7 +4620,7 @@ var LedgerConnectorBase = class {
5351
4620
  });
5352
4621
  });
5353
4622
  } catch (err) {
5354
- ctx.teardownSecureChannelSession(sessionId);
4623
+ ctx.invalidateSession(sessionId);
5355
4624
  throw ctx.wrapError(err);
5356
4625
  } finally {
5357
4626
  ctx.clearCanceller(sessionId);
@@ -5441,7 +4710,7 @@ var LedgerConnectorBase = class {
5441
4710
  );
5442
4711
  return { isGenuine: output.isGenuine, deviceId };
5443
4712
  } catch (err) {
5444
- ctx.teardownSecureChannelSession(sessionId);
4713
+ ctx.invalidateSession(sessionId);
5445
4714
  throw ctx.wrapError(err);
5446
4715
  } finally {
5447
4716
  ctx.clearCanceller(sessionId);
@@ -5560,34 +4829,9 @@ var LedgerConnectorBase = class {
5560
4829
  }
5561
4830
  return this._deviceAppsManager;
5562
4831
  }
5563
- // DeviceAppsManager is intentionally absent here: it is a per-call factory
5564
- // with no cached session state, so there is nothing to invalidate. Cancelling
5565
- // the device action is what closes the secure channel.
5566
4832
  _invalidateSession(sessionId) {
5567
4833
  this._signerManager?.invalidate(sessionId);
5568
4834
  }
5569
- /**
5570
- * Teardown for the OS-level actions that open a manager-api secure channel
5571
- * (install, uninstall, genuine check). Cancelling the device action is what
5572
- * stops DMK's xstate actor, which unsubscribes the secure-channel observable
5573
- * and closes its WebSocket; dropping the canceller without firing it leaves
5574
- * that teardown to run only if the action settled on its own.
5575
- *
5576
- * The DMK device session is deliberately kept: the secure channel is a
5577
- * separate WebSocket per call, and disconnecting here would break the bounded
5578
- * unlock/retry recovery the adapter runs on the original session.
5579
- */
5580
- _teardownSecureChannelSession(sessionId) {
5581
- const cancel = this._cancellers.get(sessionId);
5582
- this._cancellers.delete(sessionId);
5583
- if (cancel) {
5584
- try {
5585
- cancel();
5586
- } catch {
5587
- }
5588
- }
5589
- this._invalidateSession(sessionId);
5590
- }
5591
4835
  /**
5592
4836
  * Replace an old session with a new one after app switch.
5593
4837
  * Emits device-connect so the adapter updates its _sessions Map.
@@ -5672,7 +4916,7 @@ var LedgerConnectorBase = class {
5672
4916
  * at every catch site. Falls through unchanged for unknown methods.
5673
4917
  */
5674
4918
  _ctxForMethod(method) {
5675
- const prefix = /^(evm|btc|sol|tron|zcash)/.exec(method)?.[1];
4919
+ const prefix = /^(evm|btc|sol|tron)/.exec(method)?.[1];
5676
4920
  const defaultAppName = prefix ? METHOD_PREFIX_TO_APP_NAME[prefix] : void 0;
5677
4921
  if (!defaultAppName) return this._ctx;
5678
4922
  return {
@@ -5706,204 +4950,6 @@ var LedgerConnectorBase = class {
5706
4950
  return error;
5707
4951
  }
5708
4952
  };
5709
-
5710
- // src/transport/DmkTransport.ts
5711
- var import_hw_transport = __toESM(require("@ledgerhq/hw-transport"));
5712
- var DmkTransport = class extends import_hw_transport.default {
5713
- constructor(dmk, sessionId) {
5714
- super();
5715
- this._dmk = dmk;
5716
- this._sessionId = sessionId;
5717
- }
5718
- async exchange(apdu) {
5719
- const response = await this._dmk.sendApdu({
5720
- sessionId: this._sessionId,
5721
- apdu: new Uint8Array(apdu)
5722
- });
5723
- const { data, statusCode } = response;
5724
- const result = Buffer.alloc(data.length + 2);
5725
- if (data.length > 0) {
5726
- result.set(data, 0);
5727
- }
5728
- result.set(statusCode, data.length);
5729
- return result;
5730
- }
5731
- async close() {
5732
- }
5733
- };
5734
-
5735
- // src/app/AppManager.ts
5736
- var import_device_management_kit3 = require("@ledgerhq/device-management-kit");
5737
- var import_hwk_adapter_core13 = require("@onekeyfe/hwk-adapter-core");
5738
- var APP_NAME_MAP = {
5739
- ETH: "Ethereum",
5740
- BTC: "Bitcoin",
5741
- SOL: "Solana",
5742
- TRX: "Tron",
5743
- ZEC: "Zcash",
5744
- XRP: "XRP",
5745
- ADA: "Cardano",
5746
- DOT: "Polkadot",
5747
- ATOM: "Cosmos"
5748
- };
5749
- var DASHBOARD_APP_NAME = "BOLOS";
5750
- var AppManager = class {
5751
- constructor(dmk, options) {
5752
- this._dmk = dmk;
5753
- this._waitMs = options?.waitMs ?? 1e3;
5754
- this._maxRetries = options?.maxRetries ?? 10;
5755
- }
5756
- /**
5757
- * Return the Ledger app name for a given chain ticker,
5758
- * or undefined if the chain is not supported.
5759
- */
5760
- static getAppName(chain) {
5761
- return APP_NAME_MAP[chain];
5762
- }
5763
- /**
5764
- * Ensure the target app is open on the device identified by `sessionId`.
5765
- *
5766
- * Flow:
5767
- * 1. Check the currently running app.
5768
- * 2. If it is already the target, return immediately.
5769
- * 3. If a different app is running (not dashboard), close it first.
5770
- * 4. Open the target app.
5771
- * 5. Poll until the device confirms the target app is running.
5772
- */
5773
- /**
5774
- * @param onConfirmOnDevice Called BEFORE OpenAppCommand is issued — the
5775
- * device is about to display "Open <app>" on screen and wait for the
5776
- * user's button press. UI consumers should show their "open app" prompt
5777
- * in response. NOT called when the target app is already open (no user
5778
- * interaction needed in that case).
5779
- *
5780
- * Important: OpenAppCommand is blocking. It does not resolve until the user
5781
- * has physically confirmed on the device, so anything that runs AFTER
5782
- * `await this._openApp(...)` lands AFTER the prompt is already gone.
5783
- * Hence the callback must fire BEFORE that await.
5784
- */
5785
- async ensureAppOpen(sessionId, targetAppName, onConfirmOnDevice) {
5786
- const currentApp = await this._getCurrentApp(sessionId);
5787
- if (currentApp === targetAppName) {
5788
- return;
5789
- }
5790
- if (!this._isDashboard(currentApp)) {
5791
- await this._closeCurrentApp(sessionId);
5792
- await this._waitForApp(sessionId, DASHBOARD_APP_NAME);
5793
- }
5794
- onConfirmOnDevice?.();
5795
- await this._openApp(sessionId, targetAppName);
5796
- await this._waitForApp(sessionId, targetAppName);
5797
- }
5798
- // ---------------------------------------------------------------------------
5799
- // Private helpers
5800
- // ---------------------------------------------------------------------------
5801
- async _getCurrentApp(sessionId) {
5802
- const result = await this._dmk.sendCommand({
5803
- sessionId,
5804
- command: new import_device_management_kit3.GetAppAndVersionCommand()
5805
- });
5806
- if ((0, import_device_management_kit3.isSuccessCommandResult)(result)) {
5807
- debugLog("[AppManager] currentApp:", result.data.name);
5808
- return result.data.name;
5809
- }
5810
- const errResult = result;
5811
- const dmkErr = errResult.error ?? {};
5812
- const original = dmkErr.originalError;
5813
- debugLog(
5814
- "[AppManager] _getCurrentApp failed sessionId=",
5815
- sessionId,
5816
- "tag=",
5817
- dmkErr._tag,
5818
- "errorCode=",
5819
- dmkErr.errorCode,
5820
- "message=",
5821
- dmkErr.message,
5822
- "originalErrorMessage=",
5823
- original?.message ?? String(original ?? "")
5824
- );
5825
- throw Object.assign(
5826
- new Error(
5827
- dmkErr.message ?? "Failed to get current app from device"
5828
- ),
5829
- {
5830
- _tag: dmkErr._tag,
5831
- errorCode: dmkErr.errorCode,
5832
- originalError: original
5833
- }
5834
- );
5835
- }
5836
- async _openApp(sessionId, appName) {
5837
- const result = await this._dmk.sendCommand({
5838
- sessionId,
5839
- command: new import_device_management_kit3.OpenAppCommand({ appName })
5840
- });
5841
- if (!(0, import_device_management_kit3.isSuccessCommandResult)(result)) {
5842
- const dmkErr = result.error;
5843
- const errorCode = "errorCode" in dmkErr && dmkErr.errorCode != null ? String(dmkErr.errorCode) : "";
5844
- const message = "message" in dmkErr && typeof dmkErr.message === "string" ? dmkErr.message : "";
5845
- debugLog(
5846
- "[AppManager] openApp failed:",
5847
- appName,
5848
- "errorCode:",
5849
- errorCode,
5850
- "tag:",
5851
- dmkErr._tag
5852
- );
5853
- let code;
5854
- if (errorCode === "6807" || /unknown application/i.test(message)) {
5855
- code = import_hwk_adapter_core13.HardwareErrorCode.AppNotInstalled;
5856
- } else if (errorCode === "5501" || dmkErr._tag === "ActionRefusedError") {
5857
- code = import_hwk_adapter_core13.HardwareErrorCode.UserRejected;
5858
- }
5859
- throw Object.assign(new Error(`Failed to open "${appName}"`), {
5860
- _tag: ERROR_TAG.OpenAppCommand,
5861
- code,
5862
- errorCode,
5863
- statusCode: errorCode,
5864
- appName,
5865
- originalError: dmkErr
5866
- });
5867
- }
5868
- }
5869
- async _closeCurrentApp(sessionId) {
5870
- debugLog("[AppManager] closeCurrentApp");
5871
- await this._dmk.sendCommand({
5872
- sessionId,
5873
- command: new import_device_management_kit3.CloseAppCommand()
5874
- });
5875
- }
5876
- /**
5877
- * Poll the device until the expected app is reported as running,
5878
- * or throw after `_maxRetries` attempts.
5879
- */
5880
- async _waitForApp(sessionId, expectedAppName) {
5881
- let lastSeen = "";
5882
- for (let i = 0; i < this._maxRetries; i++) {
5883
- await this._wait();
5884
- const current = await this._getCurrentApp(sessionId);
5885
- lastSeen = current;
5886
- if (current === expectedAppName) {
5887
- return;
5888
- }
5889
- }
5890
- debugLog(
5891
- "[AppManager] waitForApp exhausted: expected=",
5892
- expectedAppName,
5893
- "lastSeen=",
5894
- lastSeen
5895
- );
5896
- throw new Error(
5897
- `Ledger: failed to open "${expectedAppName}" after ${this._maxRetries} retries (last seen: ${lastSeen})`
5898
- );
5899
- }
5900
- _isDashboard(appName) {
5901
- return appName === DASHBOARD_APP_NAME;
5902
- }
5903
- _wait() {
5904
- return new Promise((resolve) => setTimeout(resolve, this._waitMs));
5905
- }
5906
- };
5907
4953
  // Annotate the CommonJS export names for ESM import in node:
5908
4954
  0 && (module.exports = {
5909
4955
  AppManager,
@@ -5915,7 +4961,6 @@ var AppManager = class {
5915
4961
  SignerEth,
5916
4962
  SignerManager,
5917
4963
  SignerSol,
5918
- SignerZcash,
5919
4964
  debugLog,
5920
4965
  deviceActionToPromise,
5921
4966
  isDeviceLockedError,