@onekeyfe/hwk-ledger-adapter 1.2.3-alpha.4 → 1.2.3-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.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"]);
@@ -249,6 +251,7 @@ function isBlePairingFailureError(err) {
249
251
  return false;
250
252
  }
251
253
  var CONNECTION_LEVEL_TAGS = /* @__PURE__ */ new Set([
254
+ ERROR_TAG.DeviceLocked,
252
255
  ERROR_TAG.DeviceNotAdvertising,
253
256
  ERROR_TAG.BlePairingTimeout,
254
257
  ERROR_TAG.BleGattBondingFailed,
@@ -483,21 +486,7 @@ function mapLedgerError(err, opts) {
483
486
  }
484
487
  const errAppName = err && typeof err === "object" ? err.appName : void 0;
485
488
  const appName = errAppName ?? opts?.defaultAppName;
486
- return {
487
- code,
488
- message: (0, import_hwk_adapter_core.enrichErrorMessage)(code, originalMessage),
489
- origin: (0, import_hwk_adapter_core.defaultOriginForCode)(code),
490
- appName
491
- };
492
- }
493
-
494
- // src/utils/queueKey.ts
495
- var LEDGER_DEFAULT_QUEUE_KEY = "__ledger_default__";
496
- function ledgerQueueKey({
497
- operationId,
498
- connectId
499
- }) {
500
- return (operationId ?? connectId) || LEDGER_DEFAULT_QUEUE_KEY;
489
+ return { code, message: (0, import_hwk_adapter_core.enrichErrorMessage)(code, originalMessage), appName };
501
490
  }
502
491
 
503
492
  // src/adapter/methods/allNetworkGetAddress.ts
@@ -558,102 +547,65 @@ var LEDGER_BTC_NETWORK_COIN_MAP = {
558
547
  var LEDGER_UNSUPPORTED_ALLNETWORK_NETWORKS = /* @__PURE__ */ new Set(["doge", "dogecoin"]);
559
548
  function createAllNetworkGetAddress({
560
549
  callChain,
561
- getChainFingerprint,
562
- retainOperation,
563
- errorToFailure,
564
- createCancelScope
550
+ getChainFingerprint
565
551
  }) {
566
552
  return async function allNetworkGetAddress(connectId, _deviceId, params) {
567
- debugLog("[LedgerAdapter][REQ]", {
568
- method: "allNetworkGetAddress",
569
- connectId,
570
- itemCount: params.bundle.length
571
- });
572
- const target = (0, import_hwk_adapter_core2.resolveHardwareOperationTarget)(connectId, params.operationId, "ledger");
573
- if (!target.success) return target;
574
- const effectiveTargetId = target.payload.targetId ?? "";
575
- let releaseOperationRetention;
576
- try {
577
- releaseOperationRetention = target.payload.operationId ? retainOperation(target.payload.operationId) : void 0;
578
- } catch (error) {
579
- return errorToFailure(error);
580
- }
581
- const cancelScope = createCancelScope(
582
- ledgerQueueKey({ operationId: target.payload.operationId, connectId: effectiveTargetId })
583
- );
553
+ debugLog("[LedgerAdapter][REQ]", { method: "allNetworkGetAddress", connectId, params });
584
554
  const installContext = {};
585
555
  const commonParams = {
586
- autoInstallApp: params.autoInstallApp,
587
- operationId: target.payload.operationId,
588
- knownConnections: params.knownConnections,
589
- extra: params.extra,
590
- allowDeviceSelection: params.allowDeviceSelection
556
+ autoInstallApp: params.autoInstallApp
591
557
  };
592
558
  const chainFingerprints = /* @__PURE__ */ new Map();
593
- try {
594
- const result = await (0, import_hwk_adapter_core2.runAllNetworkGetAddress)({
595
- connectId: effectiveTargetId,
596
- deviceId: _deviceId,
597
- params,
598
- normalizeItem: normalizeLedgerAllNetworkItem,
599
- buildUnsupportedNetworkResponse: (item) => isUnsupportedLedgerAllNetworkNetwork(item) ? buildUnsupportedNetworkResponse(item) : void 0,
600
- callItem: async ({ method, chain, item }) => {
601
- if (cancelScope.signal.aborted) return buildCancelledFailure(cancelScope.signal);
602
- const itemDeviceId = getItemDeviceId(item) ?? chainFingerprints.get(chain) ?? "";
603
- return callAllNetworkMethod(
604
- callChain,
605
- effectiveTargetId,
606
- itemDeviceId,
607
- method,
608
- item,
609
- commonParams,
610
- installContext
611
- );
612
- },
613
- attachIdentity: async ({ item, chain, payload }) => attachLedgerIdentity(
614
- getChainFingerprint,
615
- 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,
616
572
  item,
617
- chain,
618
- payload,
619
- chainFingerprints,
620
- installContext,
621
- cancelScope.signal
622
- ),
623
- shouldAbortBundle: isTopLevelAllNetworkFailure,
624
- buildTopLevelFailure: (response) => {
625
- const code = response.payload?.code ?? import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch;
626
- return (0, import_hwk_adapter_core2.failure)(
627
- code,
628
- response.payload?.error ?? "All-network get-address aborted",
629
- response.payload?.params
630
- );
631
- }
632
- });
633
- debugLog("[LedgerAdapter][RES]", {
634
- method: "allNetworkGetAddress",
635
- success: result.success,
636
- payload: result
637
- });
638
- return result;
639
- } finally {
640
- cancelScope.release();
641
- releaseOperationRetention?.();
642
- }
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;
643
601
  };
644
602
  }
645
- function buildCancelledFailure(signal) {
646
- const reason = signal.reason;
647
- const code = typeof reason?.code === "number" ? reason.code : import_hwk_adapter_core2.HardwareErrorCode.UserAborted;
648
- const message = typeof reason?.message === "string" ? reason.message : "";
649
- return (0, import_hwk_adapter_core2.failure)(code, message || "All-network get-address cancelled");
650
- }
651
603
  function isTopLevelAllNetworkFailure(response) {
652
604
  if (response.success) {
653
605
  return false;
654
606
  }
655
607
  const code = response.payload?.code;
656
- return code === import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch || code === import_hwk_adapter_core2.HardwareErrorCode.DeviceDisconnected || code === import_hwk_adapter_core2.HardwareErrorCode.OperationTimeout || code === import_hwk_adapter_core2.HardwareErrorCode.TransportError || code === import_hwk_adapter_core2.HardwareErrorCode.OperationEnded || code === import_hwk_adapter_core2.HardwareErrorCode.OperationNotFound || code === import_hwk_adapter_core2.HardwareErrorCode.UserAborted || code === import_hwk_adapter_core2.HardwareErrorCode.UserRejected;
608
+ return code === import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch || code === import_hwk_adapter_core2.HardwareErrorCode.UserAborted || code === import_hwk_adapter_core2.HardwareErrorCode.UserRejected;
657
609
  }
658
610
  function getItemDeviceId(item) {
659
611
  const { deviceId } = item;
@@ -683,18 +635,8 @@ function normalizeLedgerAllNetworkItem(method, item) {
683
635
  const coin = LEDGER_BTC_NETWORK_COIN_MAP[item.network];
684
636
  return coin ? { ...item, coin } : item;
685
637
  }
686
- async function attachLedgerIdentity(getChainFingerprint, connectId, item, chain, payload, chainFingerprints, context, cancelSignal) {
687
- const knownFingerprint = getItemDeviceId(item) || chainFingerprints.get(chain) || "";
688
- if (!knownFingerprint && cancelSignal.aborted) {
689
- const cancelled = buildCancelledFailure(cancelSignal);
690
- return { ...item, success: false, payload: cancelled.payload };
691
- }
692
- const fingerprint = knownFingerprint || await bootstrapChainFingerprint(
693
- getChainFingerprint,
694
- context.connection?.connectId ?? connectId,
695
- chain,
696
- context
697
- );
638
+ async function attachLedgerIdentity(getChainFingerprint, connectId, item, chain, payload, chainFingerprints) {
639
+ const fingerprint = getItemDeviceId(item) || chainFingerprints.get(chain) || await bootstrapChainFingerprint(getChainFingerprint, connectId, chain);
698
640
  if (!fingerprint) {
699
641
  return buildFingerprintBootstrapFailure(item, chain);
700
642
  }
@@ -715,8 +657,8 @@ async function attachLedgerIdentity(getChainFingerprint, connectId, item, chain,
715
657
  }
716
658
  };
717
659
  }
718
- async function bootstrapChainFingerprint(getChainFingerprint, connectId, chain, context) {
719
- const response = await getChainFingerprint(connectId, chain, context);
660
+ async function bootstrapChainFingerprint(getChainFingerprint, connectId, chain) {
661
+ const response = await getChainFingerprint(connectId, chain);
720
662
  return response.success ? response.payload : "";
721
663
  }
722
664
  function buildFingerprintBootstrapFailure(item, chain) {
@@ -821,27 +763,8 @@ var _LedgerAdapter = class _LedgerAdapter {
821
763
  constructor(connector, options) {
822
764
  this.vendor = "ledger";
823
765
  this.emitter = new import_hwk_adapter_core3.TypedEventEmitter();
824
- this._operations = new import_hwk_adapter_core3.OperationRegistry({
825
- vendor: "ledger",
826
- onEnded: (operation, reason) => {
827
- const binding = this._pendingOperationBindings.get(operation.operationId);
828
- if (binding?.selectedConnection?.requestId === this._bindingSelectionRequestId) {
829
- this._finishBleBinding("cancelled");
830
- }
831
- this._pendingOperationBindings.delete(operation.operationId);
832
- this.emitter.emit(import_hwk_adapter_core3.SDK.OPERATION_ENDED, {
833
- type: import_hwk_adapter_core3.SDK.OPERATION_ENDED,
834
- payload: { operationId: operation.operationId, reason }
835
- });
836
- if (reason === "timeout") {
837
- void this._releaseOperationConnection(operation);
838
- }
839
- }
840
- });
841
766
  this._discoveredDevices = /* @__PURE__ */ new Map();
842
767
  this._sessions = /* @__PURE__ */ new Map();
843
- this._pendingOperationBindings = /* @__PURE__ */ new Map();
844
- this._verifiedBleReconnectTargets = /* @__PURE__ */ new Map();
845
768
  this._uiRegistry = new import_hwk_adapter_core3.UiRequestRegistry();
846
769
  // BTC App rejects account index >= 100 unless display=true. Cached per
847
770
  // adapter instance: first 100+ path asks the user once via UI request,
@@ -855,31 +778,10 @@ var _LedgerAdapter = class _LedgerAdapter {
855
778
  this._deviceAuthenticityQueueTail = Promise.resolve();
856
779
  // Shared across concurrent callers — only `cancel()` aborts.
857
780
  this._doConnectAbortController = null;
858
- this._unsettledConnectorOperations = /* @__PURE__ */ new Map();
859
- this._connectorIdleWaiters = /* @__PURE__ */ new Set();
860
- this._resetPromise = null;
861
- this._stateGeneration = 0;
862
- this._connectorTeardownTail = Promise.resolve();
863
- this._pendingConnectorTeardowns = 0;
864
- this._activeOperationJobs = /* @__PURE__ */ new Set();
865
- this._pendingOperationDisconnects = /* @__PURE__ */ new Set();
866
781
  this._installProgressLastEmittedValue = -Infinity;
867
782
  this.allNetworkGetAddress = createAllNetworkGetAddress({
868
783
  callChain: this.callChain.bind(this),
869
- getChainFingerprint: async (connectId, chain, context) => {
870
- try {
871
- const fingerprint = await this._computeChainFingerprint(
872
- chain,
873
- (method, params) => this.connectorCall(connectId, method, params, void 0, void 0, void 0, context)
874
- );
875
- return (0, import_hwk_adapter_core3.success)(fingerprint);
876
- } catch (error) {
877
- return this.errorToFailure(error);
878
- }
879
- },
880
- retainOperation: (operationId) => this._operations.retain(operationId),
881
- errorToFailure: (error) => this.errorToFailure(error),
882
- createCancelScope: (queueKey) => this._jobQueue.createCancelScope(queueKey)
784
+ getChainFingerprint: (connectId, chain) => this.getChainFingerprint(connectId, "", chain)
883
785
  });
884
786
  // ---------------------------------------------------------------------------
885
787
  // Private helpers
@@ -889,7 +791,7 @@ var _LedgerAdapter = class _LedgerAdapter {
889
791
  *
890
792
  * - If a session already exists for the given connectId, reuse it.
891
793
  * - If ANY session exists (Ledger IDs are ephemeral), reuse it.
892
- * - 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.
893
795
  */
894
796
  // Mutex for ensureConnected — prevents concurrent calls from establishing duplicate connections
895
797
  this._connectingPromise = null;
@@ -906,12 +808,6 @@ var _LedgerAdapter = class _LedgerAdapter {
906
808
  });
907
809
  };
908
810
  this.deviceDisconnectHandler = (data) => {
909
- const activeOperation = this._operations.findActiveByConnectionKey(data.connectId);
910
- if (activeOperation && this._activeOperationJobs.has(activeOperation.operationId)) {
911
- this._pendingOperationDisconnects.add(activeOperation.operationId);
912
- } else {
913
- this._operations.endByConnectionKey(data.connectId, "disconnect");
914
- }
915
811
  this._discoveredDevices.delete(data.connectId);
916
812
  this._sessions.delete(data.connectId);
917
813
  this.emitter.emit(import_hwk_adapter_core3.DEVICE.DISCONNECT, {
@@ -968,28 +864,11 @@ var _LedgerAdapter = class _LedgerAdapter {
968
864
  this._jobQueue = new import_hwk_adapter_core3.DeviceJobQueue();
969
865
  this.registerEventListeners();
970
866
  }
971
- _finishBleBinding(status) {
972
- const selectionRequestId = this._bindingSelectionRequestId;
973
- this._bindingSelectionRequestId = void 0;
974
- if (selectionRequestId)
975
- this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.DEVICE_BINDING_STATUS, {
976
- type: import_hwk_adapter_core3.UI_REQUEST.DEVICE_BINDING_STATUS,
977
- payload: { selectionRequestId, status }
978
- });
979
- }
980
- _isBleConnection() {
981
- return isLedgerBleConnectionType(this._activeConnectionType ?? this.connector.connectionType);
982
- }
983
867
  // Transport
984
868
  get activeTransport() {
985
- return this._isBleConnection() ? "ble" : "hid";
869
+ return isLedgerBleConnectionType(this.connector.connectionType) ? "ble" : "hid";
986
870
  }
987
871
  getAvailableTransports() {
988
- if (this.connector.availableTransports) {
989
- return this.connector.availableTransports.map(
990
- (transport) => transport === "ble" ? "ble" : "hid"
991
- );
992
- }
993
872
  return this.activeTransport ? [this.activeTransport] : [];
994
873
  }
995
874
  // Connector is bound at construction; switching requires a new adapter.
@@ -1006,39 +885,21 @@ var _LedgerAdapter = class _LedgerAdapter {
1006
885
  * The next operation will re-discover and re-connect automatically.
1007
886
  */
1008
887
  resetState() {
1009
- void this._resetStateAndDisconnectSessions();
1010
- }
1011
- _resetStateAndDisconnectSessions() {
1012
- if (this._resetPromise) return this._resetPromise;
1013
- const sessionIds = new Set(this._sessions.values());
1014
- this._stateGeneration += 1;
1015
- this._finishBleBinding("cancelled");
1016
- this._operations.endAll("runtime-reset");
1017
- this._doConnectAbortController?.abort();
1018
888
  this._discoveredDevices.clear();
1019
889
  this._sessions.clear();
1020
- this._verifiedBleReconnectTargets.clear();
1021
890
  this._connectingPromise = null;
1022
- this._doConnectAbortController = null;
1023
891
  this._uiRegistry.reset();
1024
892
  this._jobQueue.clear();
1025
893
  this._btcHighIndexConfirmedThisSession = false;
1026
- const resetPromise = this._runConnectorTeardown(async () => {
1027
- for (const sessionId of sessionIds) {
1028
- await this.connector.disconnect(sessionId).catch(() => void 0);
1029
- }
1030
- });
1031
- this._resetPromise = resetPromise;
1032
- return resetPromise.finally(() => {
1033
- if (this._resetPromise === resetPromise) {
1034
- this._resetPromise = null;
1035
- }
1036
- });
1037
894
  }
1038
895
  async dispose() {
1039
- await this._resetStateAndDisconnectSessions();
896
+ this._uiRegistry.reset();
897
+ this._jobQueue.clear();
1040
898
  this.unregisterEventListeners();
1041
899
  this.connector.reset();
900
+ this._discoveredDevices.clear();
901
+ this._sessions.clear();
902
+ this._btcHighIndexConfirmedThisSession = false;
1042
903
  this.emitter.removeAllListeners();
1043
904
  }
1044
905
  uiResponse(response) {
@@ -1048,32 +909,17 @@ var _LedgerAdapter = class _LedgerAdapter {
1048
909
  // Device management
1049
910
  // ---------------------------------------------------------------------------
1050
911
  async searchDevices(options) {
1051
- return this._searchDevices(options);
1052
- }
1053
- async _searchDevices(options, signal) {
1054
912
  debugLog("[LedgerAdapter][REQ]", { method: "searchDevices", params: options });
1055
913
  try {
1056
914
  if (options?.resetSession) {
1057
- await this._resetStateAndDisconnectSessions();
1058
- } else {
1059
- await this._connectorTeardownTail;
1060
- }
1061
- await this._ensureDevicePermission(void 0, void 0, signal);
1062
- if (signal) _LedgerAdapter._throwIfAborted(signal);
1063
- const stateGeneration = this._stateGeneration;
1064
- const devices = await this.connector.searchDevices(
1065
- options?.transportType ? {
1066
- transportType: options.transportType,
1067
- waitForAll: options.waitForAllTransports
1068
- } : void 0
1069
- );
1070
- if (signal) _LedgerAdapter._throwIfAborted(signal);
1071
- if (stateGeneration !== this._stateGeneration) {
1072
- throw (0, import_hwk_adapter_core3.createHwkError)({
1073
- code: import_hwk_adapter_core3.HardwareErrorCode.UserAborted,
1074
- message: "Ledger discovery was reset"
1075
- });
915
+ this._doConnectAbortController?.abort();
916
+ this._sessions.clear();
917
+ this._connectingPromise = null;
918
+ this._doConnectAbortController = null;
919
+ this._btcHighIndexConfirmedThisSession = false;
1076
920
  }
921
+ await this._ensureDevicePermission();
922
+ const devices = await this.connector.searchDevices();
1077
923
  this._discoveredDevices.clear();
1078
924
  for (const d of devices) {
1079
925
  if (d.connectId) {
@@ -1081,7 +927,7 @@ var _LedgerAdapter = class _LedgerAdapter {
1081
927
  }
1082
928
  }
1083
929
  if (this._discoveredDevices.size === 0) {
1084
- await this._ensureDevicePermission(void 0, void 0, signal);
930
+ await this._ensureDevicePermission();
1085
931
  }
1086
932
  const result = Array.from(this._discoveredDevices.values());
1087
933
  debugLog("[LedgerAdapter][RES]", {
@@ -1100,285 +946,41 @@ var _LedgerAdapter = class _LedgerAdapter {
1100
946
  throw err;
1101
947
  }
1102
948
  }
1103
- async searchDeviceTargets(options) {
1104
- const devices = await this.searchDevices(options);
1105
- return devices.map((device) => ({
1106
- searchTargetId: device.connectId,
1107
- searchTargetReusePolicy: (0, import_hwk_adapter_core3.resolveSearchTargetReusePolicy)(device),
1108
- vendor: "ledger",
1109
- connectionType: device.connectionType,
1110
- kind: "physical",
1111
- label: device.label,
1112
- model: device.model,
1113
- modelName: device.modelName,
1114
- serialNumber: device.serialNumber
1115
- }));
1116
- }
1117
- async listConnectionTargets(options) {
1118
- const targets = await this.searchDeviceTargets(options);
1119
- return targets.map(({ searchTargetId, ...target }) => ({
1120
- ...target,
1121
- targetId: searchTargetId
1122
- }));
1123
- }
1124
949
  // USB single-session invariant: evict all sessions, best-effort (see connectDevice).
1125
- async _evictAllSessions(preserveOperationId) {
1126
- this._operations.endAll("explicit", preserveOperationId);
950
+ async _evictAllSessions() {
1127
951
  if (this._sessions.size === 0) return;
1128
952
  const stale = [...this._sessions.values()];
1129
953
  this._sessions.clear();
1130
- await this._runConnectorTeardown(async () => {
1131
- for (const sid of stale) {
1132
- try {
1133
- await this.connector.disconnect(sid);
1134
- } catch {
1135
- }
954
+ for (const sid of stale) {
955
+ try {
956
+ await this.connector.disconnect(sid);
957
+ } catch {
1136
958
  }
1137
- });
959
+ }
1138
960
  }
1139
961
  static _createDeviceBusyError(method) {
1140
962
  return Object.assign(new Error(`Ledger device is busy while calling ${method}`), {
1141
963
  code: import_hwk_adapter_core3.HardwareErrorCode.DeviceBusy
1142
964
  });
1143
965
  }
1144
- async connectDevice(searchTargetId) {
1145
- try {
1146
- return await this._jobQueue.enqueue(
1147
- searchTargetId || "__ledger_connect__",
1148
- async () => {
1149
- const connected = await this._connectTarget(searchTargetId);
1150
- if (!connected.success) return connected;
1151
- return this._createOperation(searchTargetId, connected.payload);
1152
- },
1153
- {
1154
- label: "connectDevice",
1155
- rejectIfBusy: true,
1156
- busyError: _LedgerAdapter._createDeviceBusyError("connectDevice")
1157
- }
1158
- );
1159
- } catch (error) {
1160
- return this.errorToFailure(error);
1161
- }
1162
- }
1163
- async bindBleDevice(params) {
1164
- if (params.identity.vendor !== "ledger" || !params.identity.value) {
1165
- return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "Ledger wallet identity is required");
1166
- }
1167
- const { chain, value: expectedFingerprint } = params.identity;
1168
- try {
1169
- return await this._jobQueue.enqueue(
1170
- expectedFingerprint,
1171
- async (signal) => {
1172
- if (!this.getAvailableTransports().includes("ble")) {
1173
- throw (0, import_hwk_adapter_core3.createHwkError)({
1174
- code: import_hwk_adapter_core3.HardwareErrorCode.TransportNotAvailable,
1175
- message: "Ledger Bluetooth transport is not available"
1176
- });
1177
- }
1178
- this._activeConnectionType = "ble";
1179
- await this._ensureDevicePermission(void 0, void 0, signal);
1180
- const attempt = {
1181
- extra: params.extra,
1182
- bindingReason: "manual-rebind"
1183
- };
1184
- try {
1185
- for (; ; ) {
1186
- const connectId = await this._connectFirstOrSelect(
1187
- [],
1188
- void 0,
1189
- true,
1190
- void 0,
1191
- attempt,
1192
- signal
1193
- );
1194
- const sessionId = this._sessions.get(connectId);
1195
- if (!sessionId) {
1196
- throw (0, import_hwk_adapter_core3.createHwkError)({
1197
- code: import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
1198
- message: "Selected Ledger connection ended"
1199
- });
1200
- }
1201
- let saved = false;
1202
- try {
1203
- const installContext = {
1204
- connection: { connectId, sessionId }
1205
- };
1206
- const fingerprint = await this._computeChainFingerprint(
1207
- chain,
1208
- (method, callParams) => this._runConnectorCall(
1209
- connectId,
1210
- method,
1211
- callParams,
1212
- signal,
1213
- void 0,
1214
- void 0,
1215
- { autoInstallApp: true },
1216
- installContext
1217
- )
1218
- );
1219
- if (fingerprint !== expectedFingerprint) {
1220
- attempt.rejectedConnectIds ?? (attempt.rejectedConnectIds = /* @__PURE__ */ new Set());
1221
- attempt.rejectedConnectIds.add(connectId);
1222
- attempt.rejectedConnectId = connectId;
1223
- } else {
1224
- const persisted = await this._publishVerifiedBleBinding(
1225
- connectId,
1226
- chain,
1227
- fingerprint,
1228
- attempt,
1229
- void 0,
1230
- signal
1231
- );
1232
- if (!persisted) {
1233
- throw (0, import_hwk_adapter_core3.createHwkError)({
1234
- code: import_hwk_adapter_core3.HardwareErrorCode.UnknownError,
1235
- message: "Bluetooth binding could not be saved",
1236
- origin: "host"
1237
- });
1238
- }
1239
- saved = true;
1240
- return (0, import_hwk_adapter_core3.success)(connectId);
1241
- }
1242
- } finally {
1243
- if (!saved && this._sessions.get(connectId) === sessionId) {
1244
- this._sessions.delete(connectId);
1245
- const teardown = this._runConnectorTeardown(
1246
- () => this.connector.disconnect(sessionId)
1247
- ).catch(() => void 0);
1248
- if (!signal.aborted) await teardown;
1249
- }
1250
- }
1251
- }
1252
- } catch (error) {
1253
- this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
1254
- throw error;
1255
- }
1256
- },
1257
- {
1258
- label: "bindBleDevice",
1259
- rejectIfBusy: true,
1260
- busyError: _LedgerAdapter._createDeviceBusyError("bindBleDevice")
1261
- }
1262
- );
1263
- } catch (error) {
1264
- return this.errorToFailure(error);
1265
- }
1266
- }
1267
- async acquireOperation(connectId, context) {
1268
- try {
1269
- return await this._jobQueue.enqueue(
1270
- connectId || "__ledger_acquire__",
1271
- async (signal) => {
1272
- const transport = this._isBleConnection() ? "ble" : "usb";
1273
- const hint = context.knownConnections?.find(
1274
- (connection) => connection.transport === transport
1275
- );
1276
- const target = hint && hint.transport !== "qr" ? hint.connectId : connectId;
1277
- await this._ensureDevicePermission(target, void 0, signal);
1278
- const attempt = {
1279
- ...context,
1280
- extra: context.extra ? { ...context.extra } : void 0
1281
- };
1282
- try {
1283
- const resolvedConnectId = await this.ensureConnected(
1284
- target,
1285
- signal,
1286
- true,
1287
- void 0,
1288
- attempt
1289
- );
1290
- _LedgerAdapter._throwIfAborted(signal);
1291
- const result = this._createOperation(connectId, resolvedConnectId);
1292
- if (result.success && attempt.selectedConnection) {
1293
- this._pendingOperationBindings.set(result.payload, attempt);
1294
- }
1295
- return result;
1296
- } catch (error) {
1297
- this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
1298
- throw error;
1299
- }
1300
- },
1301
- {
1302
- label: "acquireOperation",
1303
- rejectIfBusy: true,
1304
- busyError: _LedgerAdapter._createDeviceBusyError("acquireOperation")
1305
- }
1306
- );
1307
- } catch (error) {
1308
- return this.errorToFailure(error);
1309
- }
1310
- }
1311
- _createOperation(searchTargetId, resolvedConnectId) {
1312
- this._operations.endByConnectionKey(resolvedConnectId, "explicit");
1313
- const sessionId = this._sessions.get(resolvedConnectId);
1314
- if (sessionId) this._operations.endByConnectionKey(sessionId, "explicit");
1315
- const device = this._discoveredDevices.get(resolvedConnectId) ?? {
1316
- vendor: "ledger",
1317
- model: "unknown",
1318
- firmwareVersion: "",
1319
- deviceId: "",
1320
- connectId: resolvedConnectId,
1321
- connectionType: this.connector.connectionType
1322
- };
1323
- const operation = this._operations.create({
1324
- searchTargetId,
1325
- connectId: resolvedConnectId,
1326
- device,
1327
- connectionKeys: [this._sessions.get(resolvedConnectId) ?? ""]
1328
- });
1329
- return (0, import_hwk_adapter_core3.success)(operation.operationId);
1330
- }
1331
- async _connectTarget(connectId, preserveOperationId, signal) {
966
+ async connectDevice(connectId) {
1332
967
  debugLog("[LedgerAdapter][REQ]", { method: "connectDevice", connectId, params: { connectId } });
1333
968
  try {
1334
- this._assertConnectorReady("connectDevice");
1335
- const discoveredType = this._discoveredDevices.get(connectId)?.connectionType;
1336
- if (discoveredType === "usb" || discoveredType === "ble") {
1337
- this._activeConnectionType = discoveredType;
1338
- }
1339
- if (this._isBleConnection() && !connectId) {
969
+ if (isLedgerBleConnectionType(this.connector.connectionType) && !connectId) {
1340
970
  throw Object.assign(new Error("Ledger BLE connectId is required."), {
1341
971
  code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
1342
972
  });
1343
973
  }
1344
- await this._ensureDevicePermission(connectId, void 0, signal);
1345
- if (signal) _LedgerAdapter._throwIfAborted(signal);
1346
- if (this.connector.availableTransports && this.connector.availableTransports.length > 1) {
1347
- await this._evictAllSessions(preserveOperationId);
1348
- } else if (this._isBleConnection()) {
1349
- const previousSessionId = this._sessions.get(connectId);
1350
- this._operations.endByConnectionKey(connectId, "explicit", preserveOperationId);
1351
- if (previousSessionId) {
1352
- this._operations.endByConnectionKey(previousSessionId, "explicit", preserveOperationId);
1353
- this._sessions.delete(connectId);
1354
- await this.connector.disconnect(previousSessionId).catch(() => void 0);
1355
- }
1356
- } else {
1357
- await this._evictAllSessions(preserveOperationId);
1358
- }
1359
- if (signal) _LedgerAdapter._throwIfAborted(signal);
1360
- const stateGeneration = this._stateGeneration;
1361
- const releaseOperation = this._retainConnectorOperation(`connect:${connectId}`);
1362
- let session;
1363
- try {
1364
- session = this.connector.availableTransports?.length ? await this.connector.connect(connectId, {
1365
- transportType: this._activeConnectionType ?? "usb"
1366
- }) : await this.connector.connect(connectId);
1367
- if (signal?.aborted || stateGeneration !== this._stateGeneration) {
1368
- await this.connector.disconnect(session.sessionId).catch(() => void 0);
1369
- throw Object.assign(new Error("Ledger connection aborted"), {
1370
- code: import_hwk_adapter_core3.HardwareErrorCode.UserAborted
1371
- });
1372
- }
1373
- } finally {
1374
- releaseOperation();
974
+ if (!isLedgerBleConnectionType(this.connector.connectionType)) {
975
+ await this._evictAllSessions();
1375
976
  }
1376
- const resolvedConnectId = session.deviceInfo?.connectId || connectId;
1377
- 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);
1378
980
  if (session.deviceInfo) {
1379
- this._discoveredDevices.set(resolvedConnectId, session.deviceInfo);
981
+ this._discoveredDevices.set(connectId, session.deviceInfo);
1380
982
  }
1381
- const result = (0, import_hwk_adapter_core3.success)(resolvedConnectId);
983
+ const result = (0, import_hwk_adapter_core3.success)(connectId);
1382
984
  debugLog("[LedgerAdapter][RES]", { method: "connectDevice", success: true, payload: result });
1383
985
  return result;
1384
986
  } catch (err) {
@@ -1391,60 +993,30 @@ var _LedgerAdapter = class _LedgerAdapter {
1391
993
  return failureResult;
1392
994
  }
1393
995
  }
1394
- async releaseOperation(operationId) {
1395
- const operation = this._operations.find(operationId);
1396
- if (!operation) {
1397
- this._operations.resolve(operationId);
1398
- return;
1399
- }
1400
- const endedOperation = this._operations.end(operationId, "explicit");
1401
- if (!endedOperation) return;
1402
- const { connectId } = operation;
996
+ async disconnectDevice(connectId) {
1403
997
  debugLog("[LedgerAdapter][REQ]", {
1404
- method: "releaseOperation",
998
+ method: "disconnectDevice",
1405
999
  connectId,
1406
1000
  params: { connectId }
1407
1001
  });
1408
1002
  try {
1409
- await this._releaseOperationConnection(endedOperation);
1410
- 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 });
1411
1009
  } catch (err) {
1412
1010
  const e = err;
1413
1011
  debugLog("[LedgerAdapter][RES]", {
1414
- method: "releaseOperation",
1012
+ method: "disconnectDevice",
1415
1013
  success: false,
1416
1014
  error: { message: e?.message, _tag: e?._tag, code: e?.code ?? e?.errorCode }
1417
1015
  });
1418
1016
  throw err;
1419
1017
  }
1420
1018
  }
1421
- async _releaseOperationConnection(operation) {
1422
- const sessionIds = /* @__PURE__ */ new Set();
1423
- for (const [connectId, sessionId] of this._sessions) {
1424
- if (connectId === operation.connectId || operation.connectionKeys.includes(connectId) || operation.connectionKeys.includes(sessionId)) {
1425
- this._sessions.delete(connectId);
1426
- sessionIds.add(sessionId);
1427
- }
1428
- }
1429
- for (const sessionId of sessionIds) {
1430
- await this._runConnectorTeardown(
1431
- () => this.connector.disconnect(sessionId).catch(() => void 0)
1432
- );
1433
- }
1434
- }
1435
- async _releaseLostOperationConnection(operationId) {
1436
- const endedOperation = this._operations.end(operationId, "disconnect");
1437
- if (!endedOperation) return;
1438
- this._discoveredDevices.delete(endedOperation.connectId);
1439
- await this._releaseOperationConnection(endedOperation);
1440
- }
1441
- async getDeviceInfo(connectIdOrOperationId, deviceId) {
1442
- let connectId;
1443
- try {
1444
- connectId = (0, import_hwk_adapter_core3.isHardwareOperationId)(connectIdOrOperationId) ? this._operations.resolve(connectIdOrOperationId).connectId : connectIdOrOperationId;
1445
- } catch (error) {
1446
- return this.errorToFailure(error);
1447
- }
1019
+ async getDeviceInfo(connectId, deviceId) {
1448
1020
  debugLog("[LedgerAdapter][REQ]", {
1449
1021
  method: "getDeviceInfo",
1450
1022
  connectId,
@@ -1482,6 +1054,9 @@ var _LedgerAdapter = class _LedgerAdapter {
1482
1054
  throw err;
1483
1055
  }
1484
1056
  }
1057
+ getSupportedChains() {
1058
+ return ["evm", "btc", "sol", "tron"];
1059
+ }
1485
1060
  // ---------------------------------------------------------------------------
1486
1061
  // Chain call helper
1487
1062
  // ---------------------------------------------------------------------------
@@ -1516,21 +1091,13 @@ var _LedgerAdapter = class _LedgerAdapter {
1516
1091
  if (params && typeof params === "object") {
1517
1092
  const {
1518
1093
  autoInstallApp,
1519
- operationId,
1520
1094
  passphraseState: _passphraseState,
1521
1095
  useEmptyPassphrase: _useEmptyPassphrase,
1522
- knownConnections,
1523
- extra,
1524
- allowDeviceSelection,
1525
1096
  ...rest
1526
1097
  } = params;
1527
1098
  return {
1528
1099
  commonParams: {
1529
- autoInstallApp: typeof autoInstallApp === "boolean" ? autoInstallApp : void 0,
1530
- operationId: typeof operationId === "string" ? operationId : void 0,
1531
- knownConnections,
1532
- extra,
1533
- allowDeviceSelection: typeof allowDeviceSelection === "boolean" ? allowDeviceSelection : void 0
1100
+ autoInstallApp: typeof autoInstallApp === "boolean" ? autoInstallApp : void 0
1534
1101
  },
1535
1102
  rest
1536
1103
  };
@@ -1706,27 +1273,6 @@ var _LedgerAdapter = class _LedgerAdapter {
1706
1273
  );
1707
1274
  }
1708
1275
  // ---------------------------------------------------------------------------
1709
- // Zcash chain methods (viewing key + shielded address reads; Zcash app >= 3.8.0)
1710
- // ---------------------------------------------------------------------------
1711
- zcashGetFullViewingKey(connectId, deviceId, params) {
1712
- return this.callChainWithMergedParams(
1713
- connectId,
1714
- deviceId,
1715
- "zcash",
1716
- "zcashGetFullViewingKey",
1717
- params
1718
- );
1719
- }
1720
- zcashGetShieldedAddress(connectId, deviceId, params) {
1721
- return this.callChainWithMergedParams(
1722
- connectId,
1723
- deviceId,
1724
- "zcash",
1725
- "zcashGetShieldedAddress",
1726
- params
1727
- );
1728
- }
1729
- // ---------------------------------------------------------------------------
1730
1276
  // App management — OS-level Ledger app install / list. Bypasses fingerprint
1731
1277
  // and chain-handler dispatch; installApp progress is forwarded to the adapter
1732
1278
  // emitter via 'ui-event' AppInstallProgress events.
@@ -1815,7 +1361,7 @@ var _LedgerAdapter = class _LedgerAdapter {
1815
1361
  );
1816
1362
  }
1817
1363
  await this.connector.configure({ ledgerGenuineCheckWebSocketUrl: relayUrl });
1818
- await this._resetStateAndDisconnectSessions();
1364
+ this.resetState();
1819
1365
  }
1820
1366
  const result = await this.connectorCall(connectId, "getDeviceGenuineCheck", {});
1821
1367
  if (!result.isGenuine) {
@@ -1841,10 +1387,10 @@ var _LedgerAdapter = class _LedgerAdapter {
1841
1387
  if (relayUrl) {
1842
1388
  try {
1843
1389
  await this.connector.configure?.({ ledgerGenuineCheckWebSocketUrl: void 0 });
1844
- await this._resetStateAndDisconnectSessions();
1390
+ this.resetState();
1845
1391
  } catch {
1846
1392
  this.connector.reset();
1847
- await this._resetStateAndDisconnectSessions();
1393
+ this.resetState();
1848
1394
  }
1849
1395
  }
1850
1396
  }
@@ -1856,20 +1402,6 @@ var _LedgerAdapter = class _LedgerAdapter {
1856
1402
  this.emitter.off(event, listener);
1857
1403
  }
1858
1404
  cancel(connectId) {
1859
- const namedOperationIsLive = (id) => {
1860
- try {
1861
- this._operations.resolve(id);
1862
- return true;
1863
- } catch {
1864
- return false;
1865
- }
1866
- };
1867
- if ((0, import_hwk_adapter_core3.isHardwareOperationId)(connectId) && !namedOperationIsLive(connectId)) {
1868
- debugLog("[LedgerAdapter] cancel target already ended; nothing to cancel", {
1869
- connectId
1870
- });
1871
- return;
1872
- }
1873
1405
  const userAbortReason = Object.assign(new Error("User aborted operation"), {
1874
1406
  code: import_hwk_adapter_core3.HardwareErrorCode.UserAborted,
1875
1407
  _tag: ERROR_TAG.UserAborted
@@ -1880,46 +1412,14 @@ var _LedgerAdapter = class _LedgerAdapter {
1880
1412
  this._lastCancelReason = void 0;
1881
1413
  }
1882
1414
  }, 2e3);
1883
- const activeJobId = this._jobQueue.getActiveJob()?.deviceId;
1884
- let operationId;
1885
- if ((0, import_hwk_adapter_core3.isHardwareOperationId)(connectId)) {
1886
- operationId = connectId;
1887
- } else if (!connectId && (0, import_hwk_adapter_core3.isHardwareOperationId)(activeJobId)) {
1888
- operationId = activeJobId;
1889
- }
1890
- let resolvedConnectId = connectId;
1891
- if (operationId) {
1892
- try {
1893
- resolvedConnectId = this._operations.resolve(operationId).connectId;
1894
- } catch {
1895
- resolvedConnectId = void 0;
1896
- }
1897
- }
1898
1415
  this._uiRegistry.cancel();
1899
- this._finishBleBinding("cancelled");
1900
- const interactionForPhysicalId = !operationId && connectId ? this._operations.findActiveByConnectionKey(connectId) : void 0;
1901
- const pendingOperationId = operationId ?? interactionForPhysicalId?.operationId;
1902
- if (!connectId) this._pendingOperationBindings.clear();
1903
- else if (pendingOperationId) {
1904
- this._pendingOperationBindings.delete(pendingOperationId);
1905
- }
1906
- const queueKeys = /* @__PURE__ */ new Set();
1907
- if (connectId) queueKeys.add(ledgerQueueKey({ connectId }));
1908
- if (pendingOperationId) queueKeys.add(ledgerQueueKey({ operationId: pendingOperationId }));
1909
- if (queueKeys.size) {
1910
- let cancelledAnyJob = false;
1911
- for (const key of queueKeys) {
1912
- cancelledAnyJob = this._jobQueue.cancelActiveAndPending(key, userAbortReason) || cancelledAnyJob;
1913
- }
1914
- debugLog("[LedgerAdapter] cancel routed to queue keys", {
1915
- queueKeys: [...queueKeys],
1916
- cancelledAnyJob
1917
- });
1416
+ if (connectId) {
1417
+ this._jobQueue.cancelActiveAndPending(connectId, userAbortReason);
1918
1418
  } else {
1919
1419
  this._jobQueue.cancelActiveAndPending(void 0, userAbortReason);
1920
1420
  }
1921
- if (resolvedConnectId) {
1922
- const sessionId = this._sessions.get(resolvedConnectId) ?? resolvedConnectId;
1421
+ if (connectId) {
1422
+ const sessionId = this._sessions.get(connectId) ?? connectId;
1923
1423
  void this.connector.cancel(sessionId);
1924
1424
  } else {
1925
1425
  for (const sid of this._sessions.values()) void this.connector.cancel(sid);
@@ -1931,98 +1431,41 @@ var _LedgerAdapter = class _LedgerAdapter {
1931
1431
  // ---------------------------------------------------------------------------
1932
1432
  // Chain fingerprint
1933
1433
  // ---------------------------------------------------------------------------
1934
- /** A non-empty deviceId is an expected chain fingerprint, not a transport identifier. */
1935
1434
  async getChainFingerprint(connectId, deviceId, chain) {
1936
1435
  try {
1937
1436
  const fingerprint = await this._computeChainFingerprint(
1938
1437
  chain,
1939
1438
  (method, params) => this.connectorCall(connectId, method, params, void 0, deviceId)
1940
1439
  );
1941
- if (deviceId) {
1942
- if (fingerprint !== deviceId) {
1943
- return (0, import_hwk_adapter_core3.failure)(
1944
- import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch,
1945
- formatDeviceMismatchError(deviceId, fingerprint)
1946
- );
1947
- }
1948
- if ((0, import_hwk_adapter_core3.isHardwareOperationId)(connectId)) {
1949
- const operation = this._operations.resolve(connectId);
1950
- await this._publishVerifiedBleBinding(
1951
- operation.connectId,
1952
- chain,
1953
- fingerprint,
1954
- void 0,
1955
- connectId
1956
- );
1957
- }
1958
- }
1959
1440
  return (0, import_hwk_adapter_core3.success)(fingerprint);
1960
1441
  } catch (err) {
1961
1442
  debugError("[LedgerAdapter] getChainFingerprint error:", chain, err);
1962
1443
  return this.errorToFailure(err);
1963
1444
  }
1964
1445
  }
1965
- /** Discovery may select a BLE target before a later call verifies its wallet. */
1966
- async _publishVerifiedBleBinding(connectId, chain, fingerprint, attempt, operationId, signal) {
1967
- const binding = operationId ? this._pendingOperationBindings.get(operationId) : attempt;
1968
- if (!this._isBleConnection() || binding?.selectedConnection?.connectId !== connectId) {
1969
- return false;
1970
- }
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 };
1971
1452
  try {
1972
- const outcome = await (0, import_hwk_adapter_core3.requestSaveDeviceBinding)(
1973
- this.emitter,
1974
- this._uiRegistry,
1975
- {
1976
- selectionRequestId: binding.selectedConnection.requestId,
1977
- connection: { transport: "ble", connectId },
1978
- identity: { vendor: "ledger", type: "chainFingerprint", chain, value: fingerprint },
1979
- extra: binding.extra
1980
- },
1981
- signal
1453
+ const fingerprint = await this._computeChainFingerprint(
1454
+ chain,
1455
+ (method, params) => this._callConnector(sessionId, method, params)
1982
1456
  );
1983
- if (operationId) this._operations.resolve(operationId);
1984
- if (!outcome.saved) {
1985
- debugLog("[LedgerAdapter] BLE binding not persisted by host", {
1986
- connectId,
1987
- reason: outcome.reason
1988
- });
1989
- }
1990
- return outcome.saved;
1991
- } catch (error) {
1992
- if (operationId) {
1993
- this._pendingOperationBindings.delete(operationId);
1994
- this._operations.end(operationId, "explicit");
1995
- }
1996
- const sessionId = this._sessions.get(connectId);
1997
- this._sessions.delete(connectId);
1998
- if (sessionId) {
1999
- const teardown = this._runConnectorTeardown(
2000
- () => this.connector.disconnect(sessionId)
2001
- ).catch(() => void 0);
2002
- if (!signal?.aborted) await teardown;
2003
- }
2004
- throw error;
2005
- } finally {
2006
- if (this._bindingSelectionRequestId === binding.selectedConnection.requestId) {
2007
- this._bindingSelectionRequestId = void 0;
1457
+ if (fingerprint === deviceId) {
1458
+ return { success: true };
2008
1459
  }
2009
- if (operationId) {
2010
- 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 };
2011
1465
  }
1466
+ throw err;
2012
1467
  }
2013
1468
  }
2014
- /** Verify on the acquired session without re-entering the job queue. */
2015
- async _verifyDeviceFingerprintWithSession(sessionId, deviceId, chain) {
2016
- if (!deviceId) return { success: true };
2017
- const fingerprint = await this._computeChainFingerprint(
2018
- chain,
2019
- (method, params) => this._callConnector(sessionId, method, params)
2020
- );
2021
- if (fingerprint === deviceId) {
2022
- return { success: true };
2023
- }
2024
- return { success: false, expected: deviceId, actual: fingerprint };
2025
- }
2026
1469
  /**
2027
1470
  * Compute the chain fingerprint via a caller-supplied call strategy.
2028
1471
  *
@@ -2050,8 +1493,6 @@ var _LedgerAdapter = class _LedgerAdapter {
2050
1493
  address = (await callMethod("solGetAddress", { path, showOnDevice: false })).address;
2051
1494
  } else if (chain === "tron") {
2052
1495
  address = (await callMethod("tronGetAddress", { path, showOnDevice: false })).address;
2053
- } else if (chain === "zcash") {
2054
- address = (await callMethod("zcashGetShieldedAddress", { path, showOnDevice: false })).address;
2055
1496
  } else {
2056
1497
  throw new Error(`Unsupported chain for fingerprint: ${chain}`);
2057
1498
  }
@@ -2181,17 +1622,16 @@ var _LedgerAdapter = class _LedgerAdapter {
2181
1622
  // Layer 1 entry. Caller signal only races the outer awaiter; the shared
2182
1623
  // `_doConnect` runs under its own internal controller so caller A's cancel
2183
1624
  // doesn't kill caller B's await.
2184
- async ensureConnected(connectId, signal, allowUsbEphemeralFallback = false, preserveOperationId, context) {
1625
+ async ensureConnected(connectId, signal, allowUsbEphemeralFallback = false) {
2185
1626
  if (signal.aborted) _LedgerAdapter._throwIfAborted(signal);
2186
- this._assertConnectorReady("connectDevice");
2187
- if (this._isBleConnection() && !connectId && !allowUsbEphemeralFallback) {
1627
+ if (isLedgerBleConnectionType(this.connector.connectionType) && !connectId) {
2188
1628
  throw Object.assign(new Error("Ledger BLE connectId is required."), {
2189
1629
  code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
2190
1630
  });
2191
1631
  }
2192
1632
  if (connectId && this._sessions.has(connectId)) return connectId;
2193
1633
  if (!connectId && this._sessions.size > 0) {
2194
- if (!this._isBleConnection() && this._sessions.size > 1) {
1634
+ if (!isLedgerBleConnectionType(this.connector.connectionType) && this._sessions.size > 1) {
2195
1635
  throw Object.assign(
2196
1636
  new Error(
2197
1637
  "Ledger USB session invariant violated: more than one session is active. Please reconnect the device."
@@ -2201,24 +1641,15 @@ var _LedgerAdapter = class _LedgerAdapter {
2201
1641
  }
2202
1642
  return this._sessions.keys().next().value;
2203
1643
  }
2204
- if (!this._connectingPromise || this._doConnectAbortController?.signal.aborted) {
2205
- const controller = new AbortController();
2206
- this._doConnectAbortController = controller;
2207
- const innerSignal = controller.signal;
1644
+ if (!this._connectingPromise) {
1645
+ this._doConnectAbortController = new AbortController();
1646
+ const innerSignal = this._doConnectAbortController.signal;
2208
1647
  this._connectingPromise = (async () => {
2209
1648
  try {
2210
- return await this._doConnect(
2211
- innerSignal,
2212
- connectId,
2213
- allowUsbEphemeralFallback,
2214
- preserveOperationId,
2215
- context
2216
- );
1649
+ return await this._doConnect(innerSignal, connectId, allowUsbEphemeralFallback);
2217
1650
  } finally {
2218
- if (this._doConnectAbortController === controller) {
2219
- this._connectingPromise = null;
2220
- this._doConnectAbortController = null;
2221
- }
1651
+ this._connectingPromise = null;
1652
+ this._doConnectAbortController = null;
2222
1653
  }
2223
1654
  })();
2224
1655
  }
@@ -2227,51 +1658,22 @@ var _LedgerAdapter = class _LedgerAdapter {
2227
1658
  // Layer 1 main loop — the ONLY place in SDK that emits unlock dialog.
2228
1659
  // Bounded by MAX_DOCONNECT_CONFIRMS — after N Confirms with no progress,
2229
1660
  // throw DeviceNotFound so the user is kicked out of the loop.
2230
- async _doConnect(internalSignal, targetConnectId, allowUsbEphemeralFallback = false, preserveOperationId, context) {
2231
- _LedgerAdapter._throwIfAborted(internalSignal);
2232
- if (this.connector.availableTransports?.includes("usb") && this.connector.availableTransports.includes("ble")) {
2233
- this._activeConnectionType = "usb";
2234
- const usbDevices = await this._searchDevices({ transportType: "usb" }, internalSignal);
2235
- _LedgerAdapter._throwIfAborted(internalSignal);
2236
- if (usbDevices.length > 0) {
2237
- const knownUsb = context?.knownConnections?.find(
2238
- (connection) => connection.transport === "usb"
2239
- );
2240
- const usbTarget = knownUsb?.transport === "usb" ? knownUsb.connectId : usbDevices.find((device) => device.connectId === targetConnectId)?.connectId;
2241
- return this._connectFirstOrSelect(
2242
- usbDevices,
2243
- usbTarget,
2244
- allowUsbEphemeralFallback,
2245
- preserveOperationId,
2246
- context,
2247
- internalSignal
2248
- );
2249
- }
2250
- this._activeConnectionType = "ble";
2251
- const knownBle = context?.knownConnections?.find(
2252
- (connection) => connection.transport === "ble"
2253
- );
2254
- if (knownBle?.transport === "ble") {
2255
- return this._connectDeviceOrThrow(knownBle.connectId, preserveOperationId, internalSignal);
2256
- }
2257
- if (targetConnectId && context?.knownConnections === void 0) {
2258
- throw (0, import_hwk_adapter_core3.createHwkError)({
2259
- code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound,
2260
- message: "Ledger connection metadata is required before starting Bluetooth binding"
2261
- });
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
+ }
2262
1676
  }
2263
- const bleDevices = await this._searchDevices({ transportType: "ble" }, internalSignal);
2264
- return this._connectFirstOrSelect(
2265
- bleDevices,
2266
- void 0,
2267
- allowUsbEphemeralFallback,
2268
- preserveOperationId,
2269
- context,
2270
- internalSignal
2271
- );
2272
- }
2273
- if (this._isBleConnection() && targetConnectId) {
2274
- return this._connectDeviceOrThrow(targetConnectId, preserveOperationId, internalSignal);
2275
1677
  }
2276
1678
  let confirms = 0;
2277
1679
  while (!internalSignal.aborted) {
@@ -2279,28 +1681,22 @@ var _LedgerAdapter = class _LedgerAdapter {
2279
1681
  type: import_hwk_adapter_core3.EConnectorInteraction.Searching,
2280
1682
  payload: { sessionId: "" }
2281
1683
  });
2282
- let devices = await this._searchDevices(void 0, internalSignal);
2283
- _LedgerAdapter._throwIfAborted(internalSignal);
1684
+ let devices = await this.searchDevices();
2284
1685
  if (devices.length === 0) {
2285
1686
  for (let i = 0; i < 3 && !internalSignal.aborted; i += 1) {
2286
1687
  await new Promise((resolve) => {
2287
1688
  setTimeout(resolve, import_hwk_adapter_core3.DEVICE_CONNECT_RETRY_DELAY_MS);
2288
1689
  });
2289
- _LedgerAdapter._throwIfAborted(internalSignal);
2290
- devices = await this._searchDevices(void 0, internalSignal);
2291
- _LedgerAdapter._throwIfAborted(internalSignal);
1690
+ devices = await this.searchDevices();
2292
1691
  if (devices.length > 0) break;
2293
1692
  }
2294
1693
  }
2295
- if (devices.length > 0 || this._isBleConnection() && allowUsbEphemeralFallback) {
1694
+ if (devices.length > 0) {
2296
1695
  try {
2297
1696
  return await this._connectFirstOrSelect(
2298
1697
  devices,
2299
1698
  targetConnectId,
2300
- allowUsbEphemeralFallback,
2301
- preserveOperationId,
2302
- context,
2303
- internalSignal
1699
+ allowUsbEphemeralFallback
2304
1700
  );
2305
1701
  } catch (err) {
2306
1702
  if (!isDeviceLockedError(err) && !isDeviceNotAdvertisingError(err) && !isDeviceDisconnectedError(err)) {
@@ -2329,133 +1725,45 @@ var _LedgerAdapter = class _LedgerAdapter {
2329
1725
  _LedgerAdapter._throwIfAborted(internalSignal);
2330
1726
  throw new Error("_doConnect aborted");
2331
1727
  }
2332
- async _connectFirstOrSelect(devices, targetConnectId, allowUsbEphemeralFallback, preserveOperationId, context, signal) {
2333
- _LedgerAdapter._throwIfAborted(signal);
1728
+ async _connectFirstOrSelect(devices, targetConnectId, allowUsbEphemeralFallback = false) {
2334
1729
  if (targetConnectId) {
2335
1730
  const target = devices.find(
2336
1731
  (d) => d.connectId === targetConnectId || d.deviceId === targetConnectId
2337
1732
  );
2338
1733
  if (target) {
2339
- return this._connectDeviceOrThrow(target.connectId, preserveOperationId, signal);
1734
+ return this._connectDeviceOrThrow(target.connectId);
2340
1735
  }
2341
- if (!this._isBleConnection() && devices.length === 1 && allowUsbEphemeralFallback) {
1736
+ if (!isLedgerBleConnectionType(this.connector.connectionType) && devices.length === 1 && allowUsbEphemeralFallback) {
2342
1737
  debugLog(
2343
1738
  `[LedgerAdapter] target ${targetConnectId} not in fresh enumeration; accepting sole USB device ${devices[0].connectId} for fingerprint-verified recovery`
2344
1739
  );
2345
- return this._connectDeviceOrThrow(devices[0].connectId, preserveOperationId, signal);
1740
+ return this._connectDeviceOrThrow(devices[0].connectId);
2346
1741
  }
2347
- if (!this._isBleConnection() || !allowUsbEphemeralFallback) {
2348
- const err = Object.assign(new Error(`Target Ledger unavailable: ${targetConnectId}`), {
2349
- code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
2350
- });
2351
- if (this._isBleConnection()) {
2352
- err._tag = ERROR_TAG.DeviceNotAdvertising;
2353
- }
2354
- 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;
2355
1747
  }
1748
+ throw err;
2356
1749
  }
2357
- const requiresBleSelection = this._isBleConnection();
2358
- if (requiresBleSelection && !allowUsbEphemeralFallback) {
1750
+ if (isLedgerBleConnectionType(this.connector.connectionType)) {
2359
1751
  throw Object.assign(new Error("Ledger BLE connectId is required."), {
2360
1752
  code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
2361
1753
  });
2362
1754
  }
2363
- if (requiresBleSelection && context?.allowDeviceSelection !== false) {
2364
- const bindingSessionId = context?.bindingSessionId ?? this._uiRegistry.createRequestId();
2365
- if (context) context.bindingSessionId = bindingSessionId;
2366
- const allowUsbFallback = context?.bindingReason !== "manual-rebind" && Boolean(this.connector.availableTransports?.includes("usb"));
2367
- const knownUsb = context?.knownConnections?.find(
2368
- (connection) => connection.transport === "usb"
2369
- );
2370
- const usbConnectId = knownUsb?.transport === "usb" ? knownUsb.connectId : targetConnectId;
2371
- const { device, requestId } = await (0, import_hwk_adapter_core3.requestBleDeviceSelection)({
2372
- emitter: this.emitter,
2373
- registry: this._uiRegistry,
2374
- signal,
2375
- allowUsbFallback,
2376
- scan: async () => {
2377
- if (allowUsbFallback) {
2378
- const usbDevices = await this._searchDevices({ transportType: "usb" }, signal);
2379
- const candidate = usbDevices.find(
2380
- (device2) => device2.connectionType === "usb" && device2.connectId === usbConnectId
2381
- ) ?? (usbDevices.length === 1 && usbDevices[0].connectionType === "usb" ? usbDevices[0] : void 0);
2382
- if (candidate) return [candidate];
2383
- }
2384
- return (await this._searchDevices({ transportType: "ble", waitForAllTransports: true }, signal)).filter((device2) => !context?.rejectedConnectIds?.has(device2.connectId));
2385
- },
2386
- request: {
2387
- devices: devices.filter((device2) => !context?.rejectedConnectIds?.has(device2.connectId)),
2388
- bindingSessionId,
2389
- rejectedConnectId: context?.rejectedConnectId,
2390
- context: {
2391
- kind: "bind-connection",
2392
- transport: "ble",
2393
- reason: context?.bindingReason ?? (targetConnectId ? "known-connection-unavailable" : "missing-binding")
2394
- },
2395
- extra: context?.extra
2396
- }
2397
- });
2398
- if (device.connectionType === "usb") {
2399
- this._activeConnectionType = "usb";
2400
- if (context) context.selectedConnection = void 0;
2401
- if (preserveOperationId) this._pendingOperationBindings.delete(preserveOperationId);
2402
- this._bindingSelectionRequestId = void 0;
2403
- this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.DEVICE_BINDING_STATUS, {
2404
- type: import_hwk_adapter_core3.UI_REQUEST.DEVICE_BINDING_STATUS,
2405
- payload: { selectionRequestId: requestId, status: "cancelled" }
2406
- });
2407
- return this._connectDeviceOrThrow(device.connectId, preserveOperationId, signal);
2408
- }
2409
- if (context) context.selectedConnection = { connectId: device.connectId, requestId };
2410
- this._bindingSelectionRequestId = requestId;
2411
- return this._connectDeviceOrThrow(device.connectId, preserveOperationId, signal);
2412
- }
2413
- if (devices.length > 0 && (devices.length > 1 || requiresBleSelection)) {
2414
- if (context?.allowDeviceSelection === false || !this.emitter.listenerCount(import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE)) {
2415
- throw (0, import_hwk_adapter_core3.createHwkError)({
2416
- code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound,
2417
- message: "Select a Ledger device before continuing"
2418
- });
2419
- }
2420
- const requestId = this._uiRegistry.createRequestId();
2421
- const waitPromise = this._uiRegistry.wait(
2422
- import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE,
2423
- { requestId }
2424
- );
2425
- this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE, {
2426
- type: import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE,
2427
- payload: {
2428
- devices,
2429
- requestId,
2430
- context: requiresBleSelection ? {
2431
- kind: "bind-connection",
2432
- transport: "ble",
2433
- reason: targetConnectId ? "known-connection-unavailable" : "missing-binding"
2434
- } : { kind: "select-device", transport: "usb", reason: "multiple-candidates" },
2435
- extra: context?.extra
2436
- }
2437
- });
2438
- const { sdkConnectId } = await (signal ? this._abortable(signal, waitPromise) : waitPromise);
2439
- if (signal) _LedgerAdapter._throwIfAborted(signal);
2440
- const selected = devices.find((device) => device.connectId === sdkConnectId);
2441
- if (!selected) {
2442
- throw Object.assign(new Error("Selected Ledger is no longer available"), {
2443
- code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
2444
- });
2445
- }
2446
- if (context && requiresBleSelection)
2447
- context.selectedConnection = { connectId: selected.connectId, requestId };
2448
- return this._connectDeviceOrThrow(selected.connectId, preserveOperationId, signal);
1755
+ if (devices.length > 1) {
1756
+ throw createMultipleUsbLedgerDevicesError();
2449
1757
  }
2450
1758
  if (devices.length !== 1) {
2451
1759
  throw Object.assign(new Error("Ledger device not found."), {
2452
1760
  code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
2453
1761
  });
2454
1762
  }
2455
- return this._connectDeviceOrThrow(devices[0].connectId, preserveOperationId, signal);
1763
+ return this._connectDeviceOrThrow(devices[0].connectId);
2456
1764
  }
2457
- async _connectDeviceOrThrow(chosenConnectId, preserveOperationId, signal) {
2458
- const result = await this._connectTarget(chosenConnectId, preserveOperationId, signal);
1765
+ async _connectDeviceOrThrow(chosenConnectId) {
1766
+ const result = await this.connectDevice(chosenConnectId);
2459
1767
  if (!result.success) {
2460
1768
  const payload = result.payload;
2461
1769
  const rethrow = Object.assign(new Error(payload.error), {
@@ -2466,7 +1774,7 @@ var _LedgerAdapter = class _LedgerAdapter {
2466
1774
  }
2467
1775
  throw rethrow;
2468
1776
  }
2469
- return result.payload;
1777
+ return chosenConnectId;
2470
1778
  }
2471
1779
  /**
2472
1780
  * Call the connector with automatic session resolution and disconnect retry.
@@ -2496,122 +1804,26 @@ var _LedgerAdapter = class _LedgerAdapter {
2496
1804
  * lives in one place.
2497
1805
  */
2498
1806
  async _callConnector(sessionId, method, params, signal) {
2499
- this._assertConnectorReady(method);
2500
- if (signal?.aborted) throw this._abortReason(signal);
2501
- const releaseOperation = this._retainConnectorOperation(`call:${sessionId}`);
2502
- let promise;
2503
- try {
2504
- promise = this.connector.call(sessionId, method, params).finally(releaseOperation);
2505
- } catch (error) {
2506
- releaseOperation();
2507
- throw error;
2508
- }
1807
+ const promise = this.connector.call(sessionId, method, params);
2509
1808
  const result = signal ? await this._abortable(signal, promise) : await promise;
2510
1809
  return this._unwrapConnectorResult(result);
2511
1810
  }
2512
- _assertConnectorReady(method) {
2513
- if (this._resetPromise || this._pendingConnectorTeardowns > 0 || this._unsettledConnectorOperations.size > 0) {
2514
- throw _LedgerAdapter._createDeviceBusyError(method);
2515
- }
2516
- }
2517
- _runConnectorTeardown(task) {
2518
- const previous = this._connectorTeardownTail;
2519
- let releaseTail = () => void 0;
2520
- this._connectorTeardownTail = new Promise((resolve) => {
2521
- releaseTail = resolve;
2522
- });
2523
- this._pendingConnectorTeardowns += 1;
2524
- return (async () => {
2525
- try {
2526
- await previous;
2527
- await this._waitForConnectorOperationsToDrain();
2528
- await task();
2529
- } finally {
2530
- this._pendingConnectorTeardowns -= 1;
2531
- releaseTail();
2532
- }
2533
- })();
2534
- }
2535
- _waitForConnectorOperationsToDrain() {
2536
- if (this._unsettledConnectorOperations.size === 0) {
2537
- return Promise.resolve();
2538
- }
2539
- return new Promise((resolve) => {
2540
- this._connectorIdleWaiters.add(resolve);
2541
- });
2542
- }
2543
- _retainConnectorOperation(key) {
2544
- this._unsettledConnectorOperations.set(
2545
- key,
2546
- (this._unsettledConnectorOperations.get(key) ?? 0) + 1
2547
- );
2548
- let released = false;
2549
- return () => {
2550
- if (released) return;
2551
- released = true;
2552
- const remaining = (this._unsettledConnectorOperations.get(key) ?? 1) - 1;
2553
- if (remaining > 0) {
2554
- this._unsettledConnectorOperations.set(key, remaining);
2555
- } else {
2556
- this._unsettledConnectorOperations.delete(key);
2557
- }
2558
- if (this._unsettledConnectorOperations.size === 0) {
2559
- for (const resolve of this._connectorIdleWaiters) resolve();
2560
- this._connectorIdleWaiters.clear();
2561
- }
2562
- };
2563
- }
2564
1811
  async connectorCall(connectId, method, params, fingerprint, permissionDeviceId, commonParams, installContext) {
2565
- const positionalOperationId = (0, import_hwk_adapter_core3.isHardwareOperationId)(connectId) ? connectId : void 0;
2566
- if (positionalOperationId && commonParams?.operationId && positionalOperationId !== commonParams.operationId) {
2567
- throw (0, import_hwk_adapter_core3.createHwkError)({
2568
- code: import_hwk_adapter_core3.HardwareErrorCode.InvalidParams,
2569
- message: "Conflicting Ledger operation ids",
2570
- params: {
2571
- positionalOperationId,
2572
- commonOperationId: commonParams.operationId
2573
- }
2574
- });
2575
- }
2576
- const operationId = commonParams?.operationId ?? positionalOperationId;
2577
- const operation = operationId ? this._operations.resolve(operationId) : void 0;
2578
- const releaseOperationRetention = operationId ? this._operations.retain(operationId) : void 0;
2579
- const effectiveConnectId = operation?.connectId ?? connectId;
2580
- debugLog("[LedgerAdapter][REQ]", {
2581
- method,
2582
- connectId: effectiveConnectId || "(empty)",
2583
- params
2584
- });
2585
- const queueKey = ledgerQueueKey({ operationId, connectId: effectiveConnectId });
1812
+ debugLog("[LedgerAdapter][REQ]", { method, connectId: connectId || "(empty)", params });
1813
+ const queueKey = connectId || "__ledger_default__";
2586
1814
  try {
2587
1815
  const result = await this._jobQueue.enqueue(
2588
1816
  queueKey,
2589
- async (signal) => {
2590
- if (operationId) this._activeOperationJobs.add(operationId);
2591
- try {
2592
- return await this._runConnectorCall(
2593
- effectiveConnectId,
2594
- method,
2595
- params,
2596
- signal,
2597
- fingerprint,
2598
- permissionDeviceId,
2599
- commonParams,
2600
- installContext ?? {},
2601
- operationId
2602
- );
2603
- } catch (error) {
2604
- this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
2605
- throw error;
2606
- } finally {
2607
- if (operationId) {
2608
- this._activeOperationJobs.delete(operationId);
2609
- if (this._pendingOperationDisconnects.delete(operationId)) {
2610
- await this._releaseLostOperationConnection(operationId);
2611
- }
2612
- }
2613
- }
2614
- },
1817
+ async (signal) => this._runConnectorCall(
1818
+ connectId,
1819
+ method,
1820
+ params,
1821
+ signal,
1822
+ fingerprint,
1823
+ permissionDeviceId,
1824
+ commonParams,
1825
+ installContext
1826
+ ),
2615
1827
  {
2616
1828
  label: method,
2617
1829
  rejectIfBusy: true,
@@ -2632,22 +1844,15 @@ var _LedgerAdapter = class _LedgerAdapter {
2632
1844
  }
2633
1845
  });
2634
1846
  throw err;
2635
- } finally {
2636
- releaseOperationRetention?.();
2637
1847
  }
2638
1848
  }
2639
1849
  /**
2640
1850
  * Race a promise against an abort signal. On abort, rejects with
2641
1851
  * signal.reason → instance _lastCancelReason → generic Error('Aborted').
2642
1852
  */
2643
- /** Hermes/RN polyfills don't always populate signal.reason; fall back. */
2644
- _abortReason(signal) {
2645
- return signal.reason ?? this._lastCancelReason ?? new Error("Aborted");
2646
- }
2647
1853
  _abortable(signal, promise) {
2648
- const getAbortReason = () => this._abortReason(signal);
1854
+ const getAbortReason = () => signal.reason ?? this._lastCancelReason ?? new Error("Aborted");
2649
1855
  if (signal.aborted) {
2650
- void promise.catch(() => void 0);
2651
1856
  return Promise.reject(getAbortReason());
2652
1857
  }
2653
1858
  return new Promise((resolve, reject) => {
@@ -2674,15 +1879,13 @@ var _LedgerAdapter = class _LedgerAdapter {
2674
1879
  }
2675
1880
  }
2676
1881
  /** Actual work done under the job queue — connection, fingerprint, call, and recovery. */
2677
- 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) {
2678
1883
  _LedgerAdapter._throwIfAborted(signal);
2679
- if (!operationId) {
2680
- await this._ensureDevicePermission(
2681
- connectId,
2682
- permissionDeviceId ?? fingerprint?.deviceId,
2683
- signal
2684
- );
2685
- }
1884
+ await this._ensureDevicePermission(
1885
+ connectId,
1886
+ permissionDeviceId ?? fingerprint?.deviceId,
1887
+ signal
1888
+ );
2686
1889
  _LedgerAdapter._throwIfAborted(signal);
2687
1890
  let effectiveParams = params;
2688
1891
  if (method === "btcGetPublicKey") {
@@ -2696,132 +1899,36 @@ var _LedgerAdapter = class _LedgerAdapter {
2696
1899
  effectiveParams = gatedParams;
2697
1900
  }
2698
1901
  const allowUsbEphemeralFallback = !!fingerprint?.deviceId && !fingerprint.skipFingerprint;
2699
- let businessCallStarted = false;
2700
- const verifiedBleTarget = connectId ? this._verifiedBleReconnectTargets.get(connectId) : void 0;
2701
- const knownTransport = this._isBleConnection() ? "ble" : "usb";
2702
- const hintedConnectId = commonParams?.knownConnections?.find(
2703
- (connection) => connection.transport === knownTransport
2704
- );
2705
- const inputConnectId = hintedConnectId && hintedConnectId.transport !== "qr" ? hintedConnectId.connectId : connectId;
2706
- const preferredConnectId = fingerprint && !fingerprint.skipFingerprint && verifiedBleTarget?.chain === fingerprint.chain && verifiedBleTarget.fingerprint === fingerprint.deviceId ? verifiedBleTarget.connectId : inputConnectId;
2707
- const connectionAttempt = { ...commonParams };
2708
- const bundleConnection = installContext?.connection;
2709
- if (bundleConnection && this._sessions.get(bundleConnection.connectId) !== bundleConnection.sessionId) {
2710
- throw (0, import_hwk_adapter_core3.createHwkError)({
2711
- code: import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
2712
- message: "Ledger all-network connection ended"
2713
- });
2714
- }
2715
- let resolvedConnectId = operationId ? this._operations.resolve(operationId).connectId : bundleConnection?.connectId ?? await this.ensureConnected(
2716
- preferredConnectId,
1902
+ const resolvedConnectId = await this.ensureConnected(
1903
+ connectId,
2717
1904
  signal,
2718
- allowUsbEphemeralFallback,
2719
- void 0,
2720
- connectionAttempt
1905
+ allowUsbEphemeralFallback
2721
1906
  );
2722
- let sessionId = this._sessions.get(resolvedConnectId);
2723
- if (sessionId && installContext && !installContext.connection) {
2724
- installContext.connection = { connectId: resolvedConnectId, sessionId };
2725
- }
1907
+ const sessionId = this._sessions.get(resolvedConnectId);
2726
1908
  if (!sessionId) {
2727
- if (operationId) {
2728
- this._operations.end(operationId, "disconnect");
2729
- throw (0, import_hwk_adapter_core3.createHwkError)({
2730
- code: import_hwk_adapter_core3.HardwareErrorCode.OperationEnded,
2731
- message: "Ledger operation connection is no longer active",
2732
- params: { operationId, reason: "disconnect" }
2733
- });
2734
- }
2735
1909
  throw Object.assign(new Error("Auto-connect succeeded but no session found"), {
2736
1910
  _tag: ERROR_TAG.DeviceSessionNotFound
2737
1911
  });
2738
1912
  }
2739
1913
  try {
2740
1914
  if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId) {
2741
- for (; ; ) {
2742
- const fp = await this._abortable(
2743
- signal,
2744
- this._verifyDeviceFingerprintWithSession(
2745
- sessionId,
2746
- fingerprint.deviceId,
2747
- fingerprint.chain
2748
- )
2749
- );
2750
- if (fp.success) break;
2751
- const binding = operationId ? this._pendingOperationBindings.get(operationId) : connectionAttempt;
2752
- if (!this._isBleConnection() || binding?.selectedConnection?.connectId !== resolvedConnectId) {
2753
- throw Object.assign(new Error(formatDeviceMismatchError(fp.expected, fp.actual)), {
2754
- code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch
2755
- });
2756
- }
2757
- binding.rejectedConnectIds ?? (binding.rejectedConnectIds = /* @__PURE__ */ new Set());
2758
- binding.rejectedConnectIds.add(resolvedConnectId);
2759
- binding.rejectedConnectId = resolvedConnectId;
2760
- this._sessions.delete(resolvedConnectId);
2761
- await this.connector.disconnect(sessionId);
2762
- if (operationId) this._pendingOperationDisconnects.delete(operationId);
2763
- _LedgerAdapter._throwIfAborted(signal);
2764
- resolvedConnectId = await this._connectFirstOrSelect(
2765
- [],
2766
- void 0,
2767
- true,
2768
- operationId,
2769
- binding,
2770
- signal
2771
- );
2772
- const selectedSession = this._sessions.get(resolvedConnectId);
2773
- const selectedDevice = this._discoveredDevices.get(resolvedConnectId);
2774
- if (!selectedSession || !selectedDevice)
2775
- throw (0, import_hwk_adapter_core3.createHwkError)({
2776
- code: import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
2777
- message: "Selected Ledger connection ended"
2778
- });
2779
- sessionId = selectedSession;
2780
- if (operationId)
2781
- this._operations.rebind(operationId, {
2782
- connectId: resolvedConnectId,
2783
- device: selectedDevice,
2784
- connectionKeys: [sessionId]
2785
- });
2786
- if (installContext)
2787
- installContext.connection = { connectId: resolvedConnectId, sessionId };
2788
- }
2789
- await this._publishVerifiedBleBinding(
2790
- resolvedConnectId,
2791
- fingerprint.chain,
2792
- fingerprint.deviceId,
2793
- connectionAttempt,
2794
- operationId,
2795
- signal
1915
+ const fp = await this._abortable(
1916
+ signal,
1917
+ this._verifyDeviceFingerprintWithSession(
1918
+ sessionId,
1919
+ fingerprint.deviceId,
1920
+ fingerprint.chain
1921
+ )
2796
1922
  );
2797
- if (!operationId && connectionAttempt.selectedConnection?.connectId === resolvedConnectId && this._isBleConnection()) {
2798
- this._verifiedBleReconnectTargets.set(connectId, {
2799
- connectId: resolvedConnectId,
2800
- chain: fingerprint.chain,
2801
- 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
2802
1926
  });
2803
1927
  }
2804
1928
  }
2805
- businessCallStarted = true;
2806
1929
  return await this._callConnector(sessionId, method, effectiveParams, signal);
2807
1930
  } catch (err) {
2808
1931
  if (signal.aborted) throw err;
2809
- if (isDeviceDisconnectedError(err) || isDeviceNotAdvertisingError(err) || isTimeoutError(err) || isConnectionLevelError(err)) {
2810
- this._discoveredDevices.delete(resolvedConnectId);
2811
- if (operationId) await this._releaseLostOperationConnection(operationId);
2812
- else {
2813
- this._sessions.delete(resolvedConnectId);
2814
- await this.connector.disconnect(sessionId).catch(() => void 0);
2815
- }
2816
- const ambiguous = businessCallStarted && !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method);
2817
- const interactionParams = operationId ? { operationId, reason: "disconnect" } : void 0;
2818
- throw (0, import_hwk_adapter_core3.createHwkError)({
2819
- code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : mapLedgerError(err).code,
2820
- message: "Ledger operation connection was lost; start a new operation",
2821
- params: ambiguous ? (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(method, { operationId }) : interactionParams,
2822
- recovery: ambiguous ? { scope: "unknown" } : void 0
2823
- });
2824
- }
2825
1932
  const errObj = err;
2826
1933
  debugLog("[LedgerAdapter] connectorCall error:", method, {
2827
1934
  message: errObj?.message,
@@ -2833,65 +1940,6 @@ var _LedgerAdapter = class _LedgerAdapter {
2833
1940
  isNotAdvertising: isDeviceNotAdvertisingError(err),
2834
1941
  isStuckApp: isStuckAppStateError(err)
2835
1942
  });
2836
- if ((isDeviceLockedError(err) || errObj?.code === import_hwk_adapter_core3.HardwareErrorCode.DeviceLocked) && lockedRetryBudget > 0) {
2837
- await this._waitForDeviceConnect(signal);
2838
- if (this._sessions.get(resolvedConnectId) !== sessionId) {
2839
- throw (0, import_hwk_adapter_core3.createHwkError)({
2840
- code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
2841
- message: "Ledger connection ended while waiting for unlock"
2842
- });
2843
- }
2844
- return this._runConnectorCall(
2845
- resolvedConnectId,
2846
- method,
2847
- effectiveParams,
2848
- signal,
2849
- fingerprint,
2850
- permissionDeviceId,
2851
- commonParams,
2852
- installContext,
2853
- operationId,
2854
- lockedRetryBudget - 1
2855
- );
2856
- }
2857
- if (businessCallStarted && isStuckAppStateError(err)) {
2858
- await this._sleepAbortable(_LedgerAdapter.STUCK_APP_RETRY_DELAY_MS, signal);
2859
- if (this._sessions.get(resolvedConnectId) !== sessionId) {
2860
- throw (0, import_hwk_adapter_core3.createHwkError)({
2861
- code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
2862
- message: "Ledger connection ended during the app transition"
2863
- });
2864
- }
2865
- try {
2866
- return await this._callConnector(sessionId, method, effectiveParams, signal);
2867
- } catch (retryErr) {
2868
- if (isStuckAppStateError(retryErr)) throw err;
2869
- if (isDeviceDisconnectedError(retryErr) || isDeviceNotAdvertisingError(retryErr) || isTimeoutError(retryErr) || isConnectionLevelError(retryErr)) {
2870
- if (operationId) await this._releaseLostOperationConnection(operationId);
2871
- else {
2872
- this._sessions.delete(resolvedConnectId);
2873
- this._discoveredDevices.delete(resolvedConnectId);
2874
- await this.connector.disconnect(sessionId).catch(() => void 0);
2875
- }
2876
- throw (0, import_hwk_adapter_core3.createHwkError)({
2877
- code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : mapLedgerError(retryErr).code,
2878
- message: `Ledger ${method} may have completed before the connection was lost`,
2879
- params: !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method) ? (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(method, {
2880
- operationId,
2881
- reason: "disconnect"
2882
- }) : { operationId, reason: "disconnect" },
2883
- recovery: !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method) ? { scope: "unknown" } : void 0
2884
- });
2885
- }
2886
- throw retryErr;
2887
- }
2888
- }
2889
- if (!operationId && err?.code === import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch) {
2890
- this._sessions.delete(resolvedConnectId);
2891
- this._discoveredDevices.delete(resolvedConnectId);
2892
- await this.connector.disconnect(sessionId).catch(() => void 0);
2893
- throw err;
2894
- }
2895
1943
  const autoInstallApp = commonParams?.autoInstallApp ?? this._defaultAutoInstallApp;
2896
1944
  const isAppMissing = isAppNotInstalledError(err) || err?.code === import_hwk_adapter_core3.HardwareErrorCode.AppNotInstalled;
2897
1945
  if (autoInstallApp && isAppMissing) {
@@ -2947,14 +1995,157 @@ var _LedgerAdapter = class _LedgerAdapter {
2947
1995
  fingerprint,
2948
1996
  permissionDeviceId,
2949
1997
  commonParams,
2950
- installContext,
2951
- 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
2952
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
+ }
2953
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
+ });
2954
2111
  }
2955
2112
  throw err;
2956
2113
  }
2957
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
+ }
2958
2149
  _sleepAbortable(ms, signal) {
2959
2150
  return new Promise((resolve, reject) => {
2960
2151
  if (signal.aborted) {
@@ -2972,6 +2163,88 @@ var _LedgerAdapter = class _LedgerAdapter {
2972
2163
  signal.addEventListener("abort", onAbort, { once: true });
2973
2164
  });
2974
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
+ }
2975
2248
  /**
2976
2249
  * Ensure OS-level device permission (Bluetooth / USB) before proceeding.
2977
2250
  *
@@ -3041,15 +2314,7 @@ var _LedgerAdapter = class _LedgerAdapter {
3041
2314
  if (err && typeof err === "object" && "code" in err && typeof err.code === "number") {
3042
2315
  const e = err;
3043
2316
  const params = e.code === import_hwk_adapter_core3.HardwareErrorCode.DevicePermissionDenied && e.reason ? { permissionDeniedReason: e.reason } : e.params;
3044
- return ledgerFailure(
3045
- e.code,
3046
- e.message ?? "Unknown error",
3047
- e.appName,
3048
- tag,
3049
- params,
3050
- void 0,
3051
- (0, import_hwk_adapter_core3.isHwkRecoveryHint)(e.recovery) ? e.recovery : void 0
3052
- );
2317
+ return ledgerFailure(e.code, e.message ?? "Unknown error", e.appName, tag, params);
3053
2318
  }
3054
2319
  const mapped = mapLedgerError(err);
3055
2320
  return ledgerFailure(mapped.code, mapped.message, mapped.appName, tag);
@@ -3076,7 +2341,7 @@ var _LedgerAdapter = class _LedgerAdapter {
3076
2341
  deviceId: device.deviceId,
3077
2342
  connectId: device.connectId,
3078
2343
  label: device.name,
3079
- connectionType: device.connectionType ?? this.connector.connectionType,
2344
+ connectionType: this.connector.connectionType,
3080
2345
  rssi: device.rssi,
3081
2346
  isConnectable: device.isConnectable,
3082
2347
  serialNumber: device.serialNumber,
@@ -3101,7 +2366,7 @@ _LedgerAdapter.APP_INSTALL_PROGRESS_MIN_DELTA = 0.05;
3101
2366
  var LedgerAdapter = _LedgerAdapter;
3102
2367
 
3103
2368
  // src/connector/LedgerConnectorBase.ts
3104
- var import_hwk_adapter_core12 = require("@onekeyfe/hwk-adapter-core");
2369
+ var import_hwk_adapter_core13 = require("@onekeyfe/hwk-adapter-core");
3105
2370
 
3106
2371
  // src/device/LedgerDeviceManager.ts
3107
2372
  var LedgerDeviceManager = class {
@@ -3637,7 +2902,7 @@ var SignerManager = class _SignerManager {
3637
2902
  return (args) => new import_device_signer_kit_ethereum.SignerEthBuilder(args);
3638
2903
  }
3639
2904
  static _createContextModule() {
3640
- 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();
3641
2906
  return _SignerManager.wrapBlindSigningReportNonBlocking(contextModule);
3642
2907
  }
3643
2908
  static wrapBlindSigningReportNonBlocking(contextModule) {
@@ -4108,7 +3373,6 @@ function _applySignaturesToPsbt(psbtHex, signatures) {
4108
3373
 
4109
3374
  // src/connector/chains/sol.ts
4110
3375
  var import_hwk_adapter_core9 = require("@onekeyfe/hwk-adapter-core");
4111
- var import_bs58 = __toESM(require("bs58"));
4112
3376
 
4113
3377
  // src/signer/SignerSol.ts
4114
3378
  var SignerSol = class {
@@ -4192,21 +3456,8 @@ async function solSignMessage(ctx, sessionId, params) {
4192
3456
  const path = normalizePath(params.path);
4193
3457
  const messageBytes = (0, import_hwk_adapter_core9.hexToBytes)(params.message);
4194
3458
  try {
4195
- if (params.messageVersion === 1) {
4196
- const preparedMessage = (0, import_hwk_adapter_core9.prepareSolanaOffchainMessageV1)({
4197
- message: messageBytes,
4198
- requiredSigners: params.requiredSigners
4199
- });
4200
- const { SignMessageVersion } = await ctx.importLedgerKit(
4201
- "@ledgerhq/device-signer-kit-solana"
4202
- );
4203
- const result2 = await solSigner.signMessage(path, preparedMessage.serializedMessage, {
4204
- version: SignMessageVersion.Raw
4205
- });
4206
- return { signature: decodeBase58Signature(result2.signature) };
4207
- }
4208
3459
  const result = await solSigner.signMessage(path, messageBytes);
4209
- return { signature: decodeBase58EnvelopeSignature(result.signature) };
3460
+ return { signature: result.signature };
4210
3461
  } catch (err) {
4211
3462
  ctx.invalidateSession(sessionId);
4212
3463
  throw ctx.wrapError(err);
@@ -4214,27 +3465,11 @@ async function solSignMessage(ctx, sessionId, params) {
4214
3465
  ctx.clearCanceller(sessionId);
4215
3466
  }
4216
3467
  }
4217
- function decodeBase58Signature(signature) {
4218
- const bytes = import_bs58.default.decode(signature);
4219
- if (bytes.length !== 64) {
4220
- throw new Error(`Ledger Solana signature must be 64 bytes, received ${bytes.length}`);
4221
- }
4222
- return (0, import_hwk_adapter_core9.bytesToHex)(bytes);
4223
- }
4224
- function decodeBase58EnvelopeSignature(envelope) {
4225
- const bytes = import_bs58.default.decode(envelope);
4226
- if (bytes.length < 65 || bytes[0] !== 1) {
4227
- throw new Error("Ledger Solana signature envelope is invalid");
4228
- }
4229
- return (0, import_hwk_adapter_core9.bytesToHex)(bytes.subarray(1, 65));
4230
- }
4231
3468
  async function _createSolSigner(ctx, sessionId) {
4232
3469
  const dmk = await ctx.getOrCreateDmk();
4233
- const { ContextModuleBuilder: ContextModuleBuilder2, ContextModuleChainID: ContextModuleChainID2 } = await ctx.importLedgerKit(
4234
- "@ledgerhq/context-module"
4235
- );
3470
+ const { ContextModuleBuilder: ContextModuleBuilder2 } = await ctx.importLedgerKit("@ledgerhq/context-module");
4236
3471
  const { SignerSolanaBuilder } = await ctx.importLedgerKit("@ledgerhq/device-signer-kit-solana");
4237
- const contextModule = new ContextModuleBuilder2({}).setChain(ContextModuleChainID2.Solana).removeDefaultLoaders().build();
3472
+ const contextModule = new ContextModuleBuilder2({}).removeDefaultLoaders().build();
4238
3473
  const sdkSigner = new SignerSolanaBuilder({ dmk, sessionId }).withContextModule(contextModule).build();
4239
3474
  const signer = new SignerSol(sdkSigner);
4240
3475
  signer.onInteraction = (interaction) => {
@@ -4250,196 +3485,360 @@ async function _createSolSigner(ctx, sessionId) {
4250
3485
  return signer;
4251
3486
  }
4252
3487
 
4253
- // src/connector/chains/zcash.ts
4254
- 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"));
4255
3491
 
4256
- // src/signer/SignerZcash.ts
4257
- var SignerZcash = class {
4258
- // eslint-disable-next-line no-useless-constructor, no-empty-function
4259
- constructor(_sdk) {
4260
- this._sdk = _sdk;
4261
- }
4262
- /** GET_VK: UFVK string (default) or raw 96-byte Orchard FVK. */
4263
- async getFullViewingKey(derivationPath, options) {
4264
- const action = this._sdk.getFullViewingKey(derivationPath, options);
4265
- return deviceActionToPromise(
4266
- action,
4267
- this.onInteraction,
4268
- void 0,
4269
- this.onRegisterCanceller
4270
- );
4271
- }
4272
- /** GET_SHIELDED_ADDRESS: single-Orchard-receiver UA for a 5-level transparent path. */
4273
- async getShieldedAddress(derivationPath, options) {
4274
- const action = this._sdk.getShieldedAddress(derivationPath, options);
4275
- return deviceActionToPromise(
4276
- action,
4277
- this.onInteraction,
4278
- void 0,
4279
- this.onRegisterCanceller
4280
- );
4281
- }
4282
- };
3492
+ // src/connector/chains/legacyChainCall.ts
3493
+ var import_hwk_adapter_core11 = require("@onekeyfe/hwk-adapter-core");
4283
3494
 
4284
- // src/connector/chains/zcash.ts
4285
- async function zcashGetFullViewingKey(ctx, sessionId, params) {
4286
- const signer = await _createZcashSigner(ctx, sessionId);
4287
- const path = normalizePath(params.path);
4288
- const mode = params.mode ?? "ufvk";
4289
- try {
4290
- const result = await signer.getFullViewingKey(path, { mode });
4291
- if (result.mode === "ufvk") {
4292
- return { path: params.path, mode, ufvk: result.fullViewingKey };
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;
3514
+ }
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;
4293
3548
  }
4294
- return { path: params.path, mode, orchardFvk: (0, import_hwk_adapter_core10.bytesToHex)(result.fullViewingKey) };
4295
- } catch (err) {
4296
- ctx.invalidateSession(sessionId);
4297
- throw ctx.wrapError(err);
4298
- } finally {
4299
- ctx.clearCanceller(sessionId);
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);
4300
3556
  }
4301
- }
4302
- async function zcashGetShieldedAddress(ctx, sessionId, params) {
4303
- const signer = await _createZcashSigner(ctx, sessionId);
4304
- const path = normalizePath(params.path);
4305
- try {
4306
- const result = await signer.getShieldedAddress(path, {
4307
- checkOnDevice: params.showOnDevice ?? false
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()
4308
3564
  });
4309
- return { address: result.address, path: params.path };
4310
- } catch (err) {
4311
- ctx.invalidateSession(sessionId);
4312
- throw ctx.wrapError(err);
4313
- } finally {
4314
- ctx.clearCanceller(sessionId);
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
+ }
3593
+ );
4315
3594
  }
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})`
3657
+ );
3658
+ }
3659
+ _isDashboard(appName) {
3660
+ return appName === DASHBOARD_APP_NAME;
3661
+ }
3662
+ _wait() {
3663
+ return new Promise((resolve) => setTimeout(resolve, this._waitMs));
3664
+ }
3665
+ };
3666
+
3667
+ // src/connector/chains/legacyChainCall.ts
3668
+ function isLegacyWrongAppError(err, _appName) {
3669
+ return isWrongAppError(err);
4316
3670
  }
4317
- async function _createZcashSigner(ctx, sessionId) {
4318
- const dmk = await ctx.getOrCreateDmk();
4319
- const { SignerZcashBuilder } = await ctx.importLedgerKit("@ledgerhq/device-signer-kit-zcash");
4320
- const sdkSigner = new SignerZcashBuilder({ dmk, sessionId }).build();
4321
- const signer = new SignerZcash(sdkSigner);
4322
- signer.onInteraction = (interaction) => {
4323
- debugLog("[LedgerConnector] zcash.onInteraction:", interaction);
3671
+ async function withLegacyChainCall(ctx, sessionId, options, action) {
3672
+ const { appName, needsConfirmation } = options;
3673
+ let openAppPromptShown = false;
3674
+ const onAppOpenPrompt = () => {
3675
+ openAppPromptShown = true;
4324
3676
  ctx.emit("ui-event", {
4325
- type: collapseSignerInteraction(interaction),
3677
+ type: import_hwk_adapter_core11.EConnectorInteraction.ConfirmOpenApp,
4326
3678
  payload: { sessionId }
4327
3679
  });
4328
3680
  };
4329
- signer.onRegisterCanceller = (cancel) => ctx.registerCanceller(sessionId, cancel);
4330
- return signer;
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;
3688
+ }
3689
+ };
3690
+ try {
3691
+ await _ensureAppOpen(ctx, sessionId, appName, onAppOpenPrompt);
3692
+ } catch (err) {
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
+ };
3722
+ try {
3723
+ return await runOnce();
3724
+ } catch (err) {
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;
3746
+ }
3747
+ }
3748
+ async function _ensureAppOpen(ctx, sessionId, appName, onPrompt) {
3749
+ const dmk = await ctx.getOrCreateDmk();
3750
+ const appManager = new AppManager(dmk);
3751
+ await appManager.ensureAppOpen(sessionId, appName, onPrompt);
4331
3752
  }
4332
3753
 
4333
- // src/connector/chains/tron.ts
4334
- var import_hwk_adapter_core11 = require("@onekeyfe/hwk-adapter-core");
4335
-
4336
- // src/signer/SignerTron.ts
4337
- var SignerTron = class {
4338
- // eslint-disable-next-line no-useless-constructor, no-empty-function
4339
- constructor(_sdk) {
4340
- this._sdk = _sdk;
4341
- }
4342
- /** Base58 Tron address plus the uncompressed public key at `derivationPath`. */
4343
- async getAddress(derivationPath, options) {
4344
- const action = this._sdk.getAddress(derivationPath, options);
4345
- const result = await deviceActionToPromise(
4346
- action,
4347
- this.onInteraction,
4348
- void 0,
4349
- this.onRegisterCanceller
4350
- );
4351
- 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;
4352
3761
  }
4353
- /** Sign a protobuf-encoded raw transaction. */
4354
- async signTransaction(derivationPath, transaction, options) {
4355
- const action = this._sdk.signTransaction(derivationPath, transaction, options);
4356
- return deviceActionToPromise(
4357
- action,
4358
- this.onInteraction,
4359
- void 0,
4360
- this.onRegisterCanceller
4361
- );
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;
4362
3774
  }
4363
- /** Sign a personal message (TIP-191). */
4364
- async signPersonalMessage(derivationPath, message, options) {
4365
- const action = this._sdk.signPersonalMessage(derivationPath, message, options);
4366
- return deviceActionToPromise(
4367
- action,
4368
- this.onInteraction,
4369
- void 0,
4370
- this.onRegisterCanceller
4371
- );
3775
+ async close() {
4372
3776
  }
4373
3777
  };
4374
3778
 
4375
3779
  // src/connector/chains/tron.ts
4376
3780
  async function tronGetAddress(ctx, sessionId, params) {
4377
- const tronSigner = await _createTronSigner(ctx, sessionId);
4378
3781
  const path = normalizePath(params.path);
4379
- try {
4380
- const result = await tronSigner.getAddress(path, {
4381
- checkOnDevice: params.showOnDevice ?? false
4382
- });
4383
- return { address: result.address, publicKey: result.publicKey, path: params.path };
4384
- } catch (err) {
4385
- ctx.invalidateSession(sessionId);
4386
- throw ctx.wrapError(err);
4387
- } finally {
4388
- ctx.clearCanceller(sessionId);
4389
- }
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
+ );
4390
3798
  }
4391
3799
  async function tronSignTransaction(ctx, sessionId, params) {
4392
3800
  if (!params.rawTxHex) {
4393
3801
  throw Object.assign(
4394
3802
  new Error("TRON signing requires a protobuf-encoded raw transaction hex (rawTxHex)."),
4395
- { code: import_hwk_adapter_core11.HardwareErrorCode.InvalidParams }
3803
+ { code: import_hwk_adapter_core12.HardwareErrorCode.InvalidParams }
4396
3804
  );
4397
3805
  }
4398
- const tronSigner = await _createTronSigner(ctx, sessionId);
4399
3806
  const path = normalizePath(params.path);
4400
- try {
4401
- const signature = await tronSigner.signTransaction(path, (0, import_hwk_adapter_core11.hexToBytes)(params.rawTxHex));
4402
- return { signature: (0, import_hwk_adapter_core11.bytesToHex)(signature) };
4403
- } catch (err) {
4404
- ctx.invalidateSession(sessionId);
4405
- throw ctx.wrapError(err);
4406
- } finally {
4407
- ctx.clearCanceller(sessionId);
4408
- }
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
+ );
4409
3821
  }
4410
3822
  async function tronSignMessage(ctx, sessionId, params) {
4411
- const tronSigner = await _createTronSigner(ctx, sessionId);
4412
3823
  const path = normalizePath(params.path);
4413
- try {
4414
- const signature = await tronSigner.signPersonalMessage(path, (0, import_hwk_adapter_core11.hexToBytes)(params.messageHex));
4415
- return { signature: (0, import_hwk_adapter_core11.bytesToHex)(signature) };
4416
- } catch (err) {
4417
- ctx.invalidateSession(sessionId);
4418
- throw ctx.wrapError(err);
4419
- } finally {
4420
- ctx.clearCanceller(sessionId);
4421
- }
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
+ );
4422
3834
  }
4423
- async function _createTronSigner(ctx, sessionId) {
3835
+ async function _createTrx(ctx, sessionId) {
4424
3836
  const dmk = await ctx.getOrCreateDmk();
4425
- const { SignerTrxBuilder } = await ctx.importLedgerKit("@ledgerhq/device-signer-kit-tron");
4426
- const sdkSigner = new SignerTrxBuilder({ dmk, sessionId }).build();
4427
- const signer = new SignerTron(sdkSigner);
4428
- signer.onInteraction = (interaction) => {
4429
- debugLog("[LedgerConnector] tron.onInteraction:", interaction);
4430
- ctx.emit("ui-event", {
4431
- type: collapseSignerInteraction(interaction),
4432
- payload: { sessionId }
4433
- });
4434
- };
4435
- signer.onRegisterCanceller = (cancel) => {
4436
- ctx.registerCanceller(sessionId, cancel);
4437
- };
4438
- return signer;
3837
+ return new import_hw_app_trx.default(new DmkTransport(dmk, sessionId));
4439
3838
  }
4440
3839
 
4441
3840
  // src/device-apps/customActions.ts
4442
- var import_device_management_kit2 = require("@ledgerhq/device-management-kit");
3841
+ var import_device_management_kit3 = require("@ledgerhq/device-management-kit");
4443
3842
  var import_rxjs = require("rxjs");
4444
3843
  var GetOsVersionDeviceAction = class {
4445
3844
  // eslint-disable-next-line no-useless-constructor, no-empty-function
@@ -4453,7 +3852,7 @@ var GetOsVersionDeviceAction = class {
4453
3852
  (async () => {
4454
3853
  try {
4455
3854
  subject.next({
4456
- status: import_device_management_kit2.DeviceActionStatus.Pending,
3855
+ status: import_device_management_kit3.DeviceActionStatus.Pending,
4457
3856
  intermediateValue: { requiredUserInteraction: "none" }
4458
3857
  });
4459
3858
  const result = await internalApi.sendCommand(new this._deps.GetOsVersionCommand());
@@ -4462,11 +3861,11 @@ var GetOsVersionDeviceAction = class {
4462
3861
  const errObj = result?.error;
4463
3862
  throw new Error(errObj?.message ?? "GetOsVersionCommand failed");
4464
3863
  }
4465
- 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 });
4466
3865
  subject.complete();
4467
3866
  } catch (err) {
4468
3867
  if (cancelled) return;
4469
- subject.next({ status: import_device_management_kit2.DeviceActionStatus.Error, error: err });
3868
+ subject.next({ status: import_device_management_kit3.DeviceActionStatus.Error, error: err });
4470
3869
  subject.complete();
4471
3870
  }
4472
3871
  })();
@@ -4474,7 +3873,7 @@ var GetOsVersionDeviceAction = class {
4474
3873
  observable: subject.asObservable(),
4475
3874
  cancel: () => {
4476
3875
  cancelled = true;
4477
- subject.next({ status: import_device_management_kit2.DeviceActionStatus.Stopped });
3876
+ subject.next({ status: import_device_management_kit3.DeviceActionStatus.Stopped });
4478
3877
  subject.complete();
4479
3878
  }
4480
3879
  };
@@ -4492,7 +3891,7 @@ var ListAvailableAppsDeviceAction = class {
4492
3891
  (async () => {
4493
3892
  try {
4494
3893
  subject.next({
4495
- status: import_device_management_kit2.DeviceActionStatus.Pending,
3894
+ status: import_device_management_kit3.DeviceActionStatus.Pending,
4496
3895
  intermediateValue: { requiredUserInteraction: "none" }
4497
3896
  });
4498
3897
  const osVersionResult = await internalApi.sendCommand(new this._GetOsVersionCommand());
@@ -4509,11 +3908,11 @@ var ListAvailableAppsDeviceAction = class {
4509
3908
  throw new Error(httpErr?.message ?? "Manager API getAppList failed");
4510
3909
  }
4511
3910
  const apps = either.extract();
4512
- subject.next({ status: import_device_management_kit2.DeviceActionStatus.Completed, output: apps });
3911
+ subject.next({ status: import_device_management_kit3.DeviceActionStatus.Completed, output: apps });
4513
3912
  subject.complete();
4514
3913
  } catch (err) {
4515
3914
  if (cancelled) return;
4516
- subject.next({ status: import_device_management_kit2.DeviceActionStatus.Error, error: err });
3915
+ subject.next({ status: import_device_management_kit3.DeviceActionStatus.Error, error: err });
4517
3916
  subject.complete();
4518
3917
  }
4519
3918
  })();
@@ -4521,7 +3920,7 @@ var ListAvailableAppsDeviceAction = class {
4521
3920
  observable: subject.asObservable(),
4522
3921
  cancel: () => {
4523
3922
  cancelled = true;
4524
- subject.next({ status: import_device_management_kit2.DeviceActionStatus.Stopped });
3923
+ subject.next({ status: import_device_management_kit3.DeviceActionStatus.Stopped });
4525
3924
  subject.complete();
4526
3925
  }
4527
3926
  };
@@ -4614,7 +4013,7 @@ var DeviceApps = class {
4614
4013
  seTargetId: v.seTargetId,
4615
4014
  mcuTargetId: v.mcuTargetId,
4616
4015
  seVersion: v.seVersion,
4617
- seFlagsHex: bytesToHex4(v.seFlags),
4016
+ seFlagsHex: bytesToHex2(v.seFlags),
4618
4017
  mcuSephVersion: v.mcuSephVersion,
4619
4018
  mcuBootloaderVersion: v.mcuBootloaderVersion,
4620
4019
  hwVersion: v.hwVersion
@@ -4688,7 +4087,7 @@ var DeviceApps = class {
4688
4087
  }
4689
4088
  }
4690
4089
  };
4691
- function bytesToHex4(bytes) {
4090
+ function bytesToHex2(bytes) {
4692
4091
  if (!bytes) return "";
4693
4092
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
4694
4093
  }
@@ -4731,11 +4130,10 @@ var METHOD_PREFIX_TO_APP_NAME = {
4731
4130
  evm: "Ethereum",
4732
4131
  btc: "Bitcoin",
4733
4132
  sol: "Solana",
4734
- tron: "Tron",
4735
- zcash: "Zcash"
4133
+ tron: "Tron"
4736
4134
  };
4737
4135
  var HARDWARE_ERROR_CODE_VALUES = new Set(
4738
- 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")
4739
4137
  );
4740
4138
  var BLE_CONNECT_SCAN_TIMEOUT_MS = 1500;
4741
4139
  var LEDGER_RELAY_ALLOWED_ROOT_DOMAINS = ["onekeytest.com", "onekey.com"];
@@ -4772,10 +4170,6 @@ async function defaultLedgerKitImporter(pkg) {
4772
4170
  return import("@ledgerhq/device-signer-kit-bitcoin");
4773
4171
  case "@ledgerhq/device-signer-kit-solana":
4774
4172
  return import("@ledgerhq/device-signer-kit-solana");
4775
- case "@ledgerhq/device-signer-kit-tron":
4776
- return import("@ledgerhq/device-signer-kit-tron");
4777
- case "@ledgerhq/device-signer-kit-zcash":
4778
- return import("@ledgerhq/device-signer-kit-zcash");
4779
4173
  case "@ledgerhq/context-module":
4780
4174
  return import("@ledgerhq/context-module");
4781
4175
  default:
@@ -4886,7 +4280,7 @@ var LedgerConnectorBase = class {
4886
4280
  async searchDevices() {
4887
4281
  const dm = await this._getDeviceManager();
4888
4282
  const descriptors = await this._discoverDescriptors(dm);
4889
- 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) => ({
4890
4284
  descriptor: d,
4891
4285
  connectId: this._resolveConnectId(d)
4892
4286
  }));
@@ -4934,7 +4328,7 @@ var LedgerConnectorBase = class {
4934
4328
  `Ledger BLE connect did not return within ${HANG_CEILING_MS / 6e4}min \u2014 DMK hang fallback.`
4935
4329
  );
4936
4330
  err._tag = ERROR_TAG.BlePairingTimeout;
4937
- err.code = import_hwk_adapter_core12.HardwareErrorCode.BlePairingTimeout;
4331
+ err.code = import_hwk_adapter_core13.HardwareErrorCode.BlePairingTimeout;
4938
4332
  reject(err);
4939
4333
  }, HANG_CEILING_MS);
4940
4334
  });
@@ -4967,7 +4361,7 @@ var LedgerConnectorBase = class {
4967
4361
  "Ledger device is not currently advertising. Wake up and unlock the device, keep it nearby, then try again."
4968
4362
  );
4969
4363
  err._tag = ERROR_TAG.DeviceNotAdvertising;
4970
- err.code = import_hwk_adapter_core12.HardwareErrorCode.DeviceNotFound;
4364
+ err.code = import_hwk_adapter_core13.HardwareErrorCode.DeviceNotFound;
4971
4365
  throw err;
4972
4366
  };
4973
4367
  const doConnect = async (path) => {
@@ -5031,7 +4425,7 @@ var LedgerConnectorBase = class {
5031
4425
  "Ledger Bluetooth pairing failed. Make sure the device is unlocked and nearby, then try again."
5032
4426
  );
5033
4427
  wrapped._tag = ERROR_TAG.BleGattBondingFailed;
5034
- wrapped.code = import_hwk_adapter_core12.HardwareErrorCode.BlePairingTimeout;
4428
+ wrapped.code = import_hwk_adapter_core13.HardwareErrorCode.BlePairingTimeout;
5035
4429
  wrapped.originalError = err;
5036
4430
  throw wrapped;
5037
4431
  }
@@ -5109,7 +4503,7 @@ var LedgerConnectorBase = class {
5109
4503
  this._unwatchSessionState(sessionId);
5110
4504
  this._signerManager?.invalidate(sessionId);
5111
4505
  this._cancellers.get(sessionId)?.({
5112
- code: import_hwk_adapter_core12.HardwareErrorCode.DeviceDisconnected,
4506
+ code: import_hwk_adapter_core13.HardwareErrorCode.DeviceDisconnected,
5113
4507
  tag: "DeviceDisconnected",
5114
4508
  message: "Device disconnected"
5115
4509
  });
@@ -5133,9 +4527,9 @@ var LedgerConnectorBase = class {
5133
4527
  if (isAppStuckByApdu(err)) {
5134
4528
  return {
5135
4529
  success: false,
5136
- error: (0, import_hwk_adapter_core12.serializeConnectorError)(
4530
+ error: (0, import_hwk_adapter_core13.serializeConnectorError)(
5137
4531
  Object.assign(new Error("Ledger app is unresponsive"), {
5138
- code: import_hwk_adapter_core12.HardwareErrorCode.DeviceAppStuck,
4532
+ code: import_hwk_adapter_core13.HardwareErrorCode.DeviceAppStuck,
5139
4533
  _tag: ERROR_TAG.DeviceAppStuck,
5140
4534
  originalError: err
5141
4535
  })
@@ -5145,16 +4539,16 @@ var LedgerConnectorBase = class {
5145
4539
  if (isTransportStuck(err)) {
5146
4540
  return {
5147
4541
  success: false,
5148
- error: (0, import_hwk_adapter_core12.serializeConnectorError)(
4542
+ error: (0, import_hwk_adapter_core13.serializeConnectorError)(
5149
4543
  Object.assign(new Error("Device communication interrupted, please retry"), {
5150
- code: import_hwk_adapter_core12.HardwareErrorCode.TransportError,
4544
+ code: import_hwk_adapter_core13.HardwareErrorCode.TransportError,
5151
4545
  _tag: ERROR_TAG.DeviceTransportStuck,
5152
4546
  originalError: err
5153
4547
  })
5154
4548
  )
5155
4549
  };
5156
4550
  }
5157
- return { success: false, error: (0, import_hwk_adapter_core12.serializeConnectorError)(err) };
4551
+ return { success: false, error: (0, import_hwk_adapter_core13.serializeConnectorError)(err) };
5158
4552
  }
5159
4553
  }
5160
4554
  async _dispatch(sessionId, method, params) {
@@ -5193,11 +4587,6 @@ var LedgerConnectorBase = class {
5193
4587
  return solSignTransaction(ctx, sessionId, params);
5194
4588
  case "solSignMessage":
5195
4589
  return solSignMessage(ctx, sessionId, params);
5196
- // ZCASH
5197
- case "zcashGetFullViewingKey":
5198
- return zcashGetFullViewingKey(ctx, sessionId, params);
5199
- case "zcashGetShieldedAddress":
5200
- return zcashGetShieldedAddress(ctx, sessionId, params);
5201
4590
  // TRON
5202
4591
  case "tronGetAddress":
5203
4592
  return tronGetAddress(ctx, sessionId, params);
@@ -5222,7 +4611,7 @@ var LedgerConnectorBase = class {
5222
4611
  try {
5223
4612
  return await apps.install(p.appName, ({ progress }) => {
5224
4613
  ctx.emit("ui-event", {
5225
- type: import_hwk_adapter_core12.EConnectorInteraction.AppInstallProgress,
4614
+ type: import_hwk_adapter_core13.EConnectorInteraction.AppInstallProgress,
5226
4615
  payload: {
5227
4616
  sessionId,
5228
4617
  appName: p.appName,
@@ -5527,7 +4916,7 @@ var LedgerConnectorBase = class {
5527
4916
  * at every catch site. Falls through unchanged for unknown methods.
5528
4917
  */
5529
4918
  _ctxForMethod(method) {
5530
- const prefix = /^(evm|btc|sol|tron|zcash)/.exec(method)?.[1];
4919
+ const prefix = /^(evm|btc|sol|tron)/.exec(method)?.[1];
5531
4920
  const defaultAppName = prefix ? METHOD_PREFIX_TO_APP_NAME[prefix] : void 0;
5532
4921
  if (!defaultAppName) return this._ctx;
5533
4922
  return {
@@ -5561,204 +4950,6 @@ var LedgerConnectorBase = class {
5561
4950
  return error;
5562
4951
  }
5563
4952
  };
5564
-
5565
- // src/transport/DmkTransport.ts
5566
- var import_hw_transport = __toESM(require("@ledgerhq/hw-transport"));
5567
- var DmkTransport = class extends import_hw_transport.default {
5568
- constructor(dmk, sessionId) {
5569
- super();
5570
- this._dmk = dmk;
5571
- this._sessionId = sessionId;
5572
- }
5573
- async exchange(apdu) {
5574
- const response = await this._dmk.sendApdu({
5575
- sessionId: this._sessionId,
5576
- apdu: new Uint8Array(apdu)
5577
- });
5578
- const { data, statusCode } = response;
5579
- const result = Buffer.alloc(data.length + 2);
5580
- if (data.length > 0) {
5581
- result.set(data, 0);
5582
- }
5583
- result.set(statusCode, data.length);
5584
- return result;
5585
- }
5586
- async close() {
5587
- }
5588
- };
5589
-
5590
- // src/app/AppManager.ts
5591
- var import_device_management_kit3 = require("@ledgerhq/device-management-kit");
5592
- var import_hwk_adapter_core13 = require("@onekeyfe/hwk-adapter-core");
5593
- var APP_NAME_MAP = {
5594
- ETH: "Ethereum",
5595
- BTC: "Bitcoin",
5596
- SOL: "Solana",
5597
- TRX: "Tron",
5598
- ZEC: "Zcash",
5599
- XRP: "XRP",
5600
- ADA: "Cardano",
5601
- DOT: "Polkadot",
5602
- ATOM: "Cosmos"
5603
- };
5604
- var DASHBOARD_APP_NAME = "BOLOS";
5605
- var AppManager = class {
5606
- constructor(dmk, options) {
5607
- this._dmk = dmk;
5608
- this._waitMs = options?.waitMs ?? 1e3;
5609
- this._maxRetries = options?.maxRetries ?? 10;
5610
- }
5611
- /**
5612
- * Return the Ledger app name for a given chain ticker,
5613
- * or undefined if the chain is not supported.
5614
- */
5615
- static getAppName(chain) {
5616
- return APP_NAME_MAP[chain];
5617
- }
5618
- /**
5619
- * Ensure the target app is open on the device identified by `sessionId`.
5620
- *
5621
- * Flow:
5622
- * 1. Check the currently running app.
5623
- * 2. If it is already the target, return immediately.
5624
- * 3. If a different app is running (not dashboard), close it first.
5625
- * 4. Open the target app.
5626
- * 5. Poll until the device confirms the target app is running.
5627
- */
5628
- /**
5629
- * @param onConfirmOnDevice Called BEFORE OpenAppCommand is issued — the
5630
- * device is about to display "Open <app>" on screen and wait for the
5631
- * user's button press. UI consumers should show their "open app" prompt
5632
- * in response. NOT called when the target app is already open (no user
5633
- * interaction needed in that case).
5634
- *
5635
- * Important: OpenAppCommand is blocking. It does not resolve until the user
5636
- * has physically confirmed on the device, so anything that runs AFTER
5637
- * `await this._openApp(...)` lands AFTER the prompt is already gone.
5638
- * Hence the callback must fire BEFORE that await.
5639
- */
5640
- async ensureAppOpen(sessionId, targetAppName, onConfirmOnDevice) {
5641
- const currentApp = await this._getCurrentApp(sessionId);
5642
- if (currentApp === targetAppName) {
5643
- return;
5644
- }
5645
- if (!this._isDashboard(currentApp)) {
5646
- await this._closeCurrentApp(sessionId);
5647
- await this._waitForApp(sessionId, DASHBOARD_APP_NAME);
5648
- }
5649
- onConfirmOnDevice?.();
5650
- await this._openApp(sessionId, targetAppName);
5651
- await this._waitForApp(sessionId, targetAppName);
5652
- }
5653
- // ---------------------------------------------------------------------------
5654
- // Private helpers
5655
- // ---------------------------------------------------------------------------
5656
- async _getCurrentApp(sessionId) {
5657
- const result = await this._dmk.sendCommand({
5658
- sessionId,
5659
- command: new import_device_management_kit3.GetAppAndVersionCommand()
5660
- });
5661
- if ((0, import_device_management_kit3.isSuccessCommandResult)(result)) {
5662
- debugLog("[AppManager] currentApp:", result.data.name);
5663
- return result.data.name;
5664
- }
5665
- const errResult = result;
5666
- const dmkErr = errResult.error ?? {};
5667
- const original = dmkErr.originalError;
5668
- debugLog(
5669
- "[AppManager] _getCurrentApp failed sessionId=",
5670
- sessionId,
5671
- "tag=",
5672
- dmkErr._tag,
5673
- "errorCode=",
5674
- dmkErr.errorCode,
5675
- "message=",
5676
- dmkErr.message,
5677
- "originalErrorMessage=",
5678
- original?.message ?? String(original ?? "")
5679
- );
5680
- throw Object.assign(
5681
- new Error(
5682
- dmkErr.message ?? "Failed to get current app from device"
5683
- ),
5684
- {
5685
- _tag: dmkErr._tag,
5686
- errorCode: dmkErr.errorCode,
5687
- originalError: original
5688
- }
5689
- );
5690
- }
5691
- async _openApp(sessionId, appName) {
5692
- const result = await this._dmk.sendCommand({
5693
- sessionId,
5694
- command: new import_device_management_kit3.OpenAppCommand({ appName })
5695
- });
5696
- if (!(0, import_device_management_kit3.isSuccessCommandResult)(result)) {
5697
- const dmkErr = result.error;
5698
- const errorCode = "errorCode" in dmkErr && dmkErr.errorCode != null ? String(dmkErr.errorCode) : "";
5699
- const message = "message" in dmkErr && typeof dmkErr.message === "string" ? dmkErr.message : "";
5700
- debugLog(
5701
- "[AppManager] openApp failed:",
5702
- appName,
5703
- "errorCode:",
5704
- errorCode,
5705
- "tag:",
5706
- dmkErr._tag
5707
- );
5708
- let code;
5709
- if (errorCode === "6807" || /unknown application/i.test(message)) {
5710
- code = import_hwk_adapter_core13.HardwareErrorCode.AppNotInstalled;
5711
- } else if (errorCode === "5501" || dmkErr._tag === "ActionRefusedError") {
5712
- code = import_hwk_adapter_core13.HardwareErrorCode.UserRejected;
5713
- }
5714
- throw Object.assign(new Error(`Failed to open "${appName}"`), {
5715
- _tag: ERROR_TAG.OpenAppCommand,
5716
- code,
5717
- errorCode,
5718
- statusCode: errorCode,
5719
- appName,
5720
- originalError: dmkErr
5721
- });
5722
- }
5723
- }
5724
- async _closeCurrentApp(sessionId) {
5725
- debugLog("[AppManager] closeCurrentApp");
5726
- await this._dmk.sendCommand({
5727
- sessionId,
5728
- command: new import_device_management_kit3.CloseAppCommand()
5729
- });
5730
- }
5731
- /**
5732
- * Poll the device until the expected app is reported as running,
5733
- * or throw after `_maxRetries` attempts.
5734
- */
5735
- async _waitForApp(sessionId, expectedAppName) {
5736
- let lastSeen = "";
5737
- for (let i = 0; i < this._maxRetries; i++) {
5738
- await this._wait();
5739
- const current = await this._getCurrentApp(sessionId);
5740
- lastSeen = current;
5741
- if (current === expectedAppName) {
5742
- return;
5743
- }
5744
- }
5745
- debugLog(
5746
- "[AppManager] waitForApp exhausted: expected=",
5747
- expectedAppName,
5748
- "lastSeen=",
5749
- lastSeen
5750
- );
5751
- throw new Error(
5752
- `Ledger: failed to open "${expectedAppName}" after ${this._maxRetries} retries (last seen: ${lastSeen})`
5753
- );
5754
- }
5755
- _isDashboard(appName) {
5756
- return appName === DASHBOARD_APP_NAME;
5757
- }
5758
- _wait() {
5759
- return new Promise((resolve) => setTimeout(resolve, this._waitMs));
5760
- }
5761
- };
5762
4953
  // Annotate the CommonJS export names for ESM import in node:
5763
4954
  0 && (module.exports = {
5764
4955
  AppManager,
@@ -5770,7 +4961,6 @@ var AppManager = class {
5770
4961
  SignerEth,
5771
4962
  SignerManager,
5772
4963
  SignerSol,
5773
- SignerZcash,
5774
4964
  debugLog,
5775
4965
  deviceActionToPromise,
5776
4966
  isDeviceLockedError,