@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.d.mts +29 -65
- package/dist/index.d.ts +29 -65
- package/dist/index.js +781 -1591
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +778 -1606
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -14
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
|
-
|
|
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
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
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
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
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.
|
|
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
|
|
687
|
-
const
|
|
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
|
|
719
|
-
const response = await getChainFingerprint(connectId, chain
|
|
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:
|
|
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 →
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
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(
|
|
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.
|
|
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
|
-
|
|
1345
|
-
|
|
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
|
-
|
|
1377
|
-
this.
|
|
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(
|
|
981
|
+
this._discoveredDevices.set(connectId, session.deviceInfo);
|
|
1380
982
|
}
|
|
1381
|
-
const result = (0, import_hwk_adapter_core3.success)(
|
|
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
|
|
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: "
|
|
998
|
+
method: "disconnectDevice",
|
|
1405
999
|
connectId,
|
|
1406
1000
|
params: { connectId }
|
|
1407
1001
|
});
|
|
1408
1002
|
try {
|
|
1409
|
-
|
|
1410
|
-
|
|
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: "
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
1390
|
+
this.resetState();
|
|
1845
1391
|
} catch {
|
|
1846
1392
|
this.connector.reset();
|
|
1847
|
-
|
|
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
|
-
|
|
1900
|
-
|
|
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 (
|
|
1922
|
-
const sessionId = this._sessions.get(
|
|
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
|
-
/**
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
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
|
|
1973
|
-
|
|
1974
|
-
this.
|
|
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 (
|
|
1984
|
-
|
|
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
|
-
|
|
2010
|
-
|
|
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
|
|
1625
|
+
async ensureConnected(connectId, signal, allowUsbEphemeralFallback = false) {
|
|
2185
1626
|
if (signal.aborted) _LedgerAdapter._throwIfAborted(signal);
|
|
2186
|
-
this.
|
|
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.
|
|
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
|
|
2205
|
-
|
|
2206
|
-
this._doConnectAbortController
|
|
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
|
-
|
|
2219
|
-
|
|
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
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
)
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
1734
|
+
return this._connectDeviceOrThrow(target.connectId);
|
|
2340
1735
|
}
|
|
2341
|
-
if (!this.
|
|
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
|
|
1740
|
+
return this._connectDeviceOrThrow(devices[0].connectId);
|
|
2346
1741
|
}
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
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
|
-
|
|
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 (
|
|
2364
|
-
|
|
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
|
|
1763
|
+
return this._connectDeviceOrThrow(devices[0].connectId);
|
|
2456
1764
|
}
|
|
2457
|
-
async _connectDeviceOrThrow(chosenConnectId
|
|
2458
|
-
const result = await this.
|
|
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
|
|
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.
|
|
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
|
-
|
|
2566
|
-
|
|
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
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
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.
|
|
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
|
|
1882
|
+
async _runConnectorCall(connectId, method, params, signal, fingerprint, permissionDeviceId, commonParams, installContext) {
|
|
2678
1883
|
_LedgerAdapter._throwIfAborted(signal);
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
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
|
-
|
|
2700
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
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 (!
|
|
2798
|
-
|
|
2799
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
|
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({}).
|
|
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:
|
|
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
|
|
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({}).
|
|
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/
|
|
4254
|
-
var
|
|
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/
|
|
4257
|
-
var
|
|
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/
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
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
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
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
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
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
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
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
|
|
4318
|
-
const
|
|
4319
|
-
|
|
4320
|
-
const
|
|
4321
|
-
|
|
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:
|
|
3677
|
+
type: import_hwk_adapter_core11.EConnectorInteraction.ConfirmOpenApp,
|
|
4326
3678
|
payload: { sessionId }
|
|
4327
3679
|
});
|
|
4328
3680
|
};
|
|
4329
|
-
|
|
4330
|
-
|
|
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/
|
|
4334
|
-
var
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
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
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
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:
|
|
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
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
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
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
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
|
|
3835
|
+
async function _createTrx(ctx, sessionId) {
|
|
4424
3836
|
const dmk = await ctx.getOrCreateDmk();
|
|
4425
|
-
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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(
|
|
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,
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
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,
|
|
4530
|
+
error: (0, import_hwk_adapter_core13.serializeConnectorError)(
|
|
5137
4531
|
Object.assign(new Error("Ledger app is unresponsive"), {
|
|
5138
|
-
code:
|
|
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,
|
|
4542
|
+
error: (0, import_hwk_adapter_core13.serializeConnectorError)(
|
|
5149
4543
|
Object.assign(new Error("Device communication interrupted, please retry"), {
|
|
5150
|
-
code:
|
|
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,
|
|
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:
|
|
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
|
|
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,
|