@onekeyfe/hwk-ledger-adapter 1.2.3-alpha.3 → 1.2.3-alpha.5
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 -1554
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +778 -1569
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -13
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,12 +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
|
-
};
|
|
489
|
+
return { code, message: (0, import_hwk_adapter_core.enrichErrorMessage)(code, originalMessage), appName };
|
|
492
490
|
}
|
|
493
491
|
|
|
494
492
|
// src/adapter/methods/allNetworkGetAddress.ts
|
|
@@ -549,81 +547,57 @@ var LEDGER_BTC_NETWORK_COIN_MAP = {
|
|
|
549
547
|
var LEDGER_UNSUPPORTED_ALLNETWORK_NETWORKS = /* @__PURE__ */ new Set(["doge", "dogecoin"]);
|
|
550
548
|
function createAllNetworkGetAddress({
|
|
551
549
|
callChain,
|
|
552
|
-
getChainFingerprint
|
|
553
|
-
retainOperation,
|
|
554
|
-
errorToFailure
|
|
550
|
+
getChainFingerprint
|
|
555
551
|
}) {
|
|
556
552
|
return async function allNetworkGetAddress(connectId, _deviceId, params) {
|
|
557
|
-
debugLog("[LedgerAdapter][REQ]", {
|
|
558
|
-
method: "allNetworkGetAddress",
|
|
559
|
-
connectId,
|
|
560
|
-
itemCount: params.bundle.length
|
|
561
|
-
});
|
|
562
|
-
const target = (0, import_hwk_adapter_core2.resolveHardwareOperationTarget)(connectId, params.operationId, "ledger");
|
|
563
|
-
if (!target.success) return target;
|
|
564
|
-
const effectiveTargetId = target.payload.targetId ?? "";
|
|
565
|
-
let releaseOperationRetention;
|
|
566
|
-
try {
|
|
567
|
-
releaseOperationRetention = target.payload.operationId ? retainOperation(target.payload.operationId) : void 0;
|
|
568
|
-
} catch (error) {
|
|
569
|
-
return errorToFailure(error);
|
|
570
|
-
}
|
|
553
|
+
debugLog("[LedgerAdapter][REQ]", { method: "allNetworkGetAddress", connectId, params });
|
|
571
554
|
const installContext = {};
|
|
572
555
|
const commonParams = {
|
|
573
|
-
autoInstallApp: params.autoInstallApp
|
|
574
|
-
operationId: target.payload.operationId,
|
|
575
|
-
knownConnections: params.knownConnections,
|
|
576
|
-
extra: params.extra,
|
|
577
|
-
allowDeviceSelection: params.allowDeviceSelection
|
|
556
|
+
autoInstallApp: params.autoInstallApp
|
|
578
557
|
};
|
|
579
558
|
const chainFingerprints = /* @__PURE__ */ new Map();
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
method,
|
|
594
|
-
item,
|
|
595
|
-
commonParams,
|
|
596
|
-
installContext
|
|
597
|
-
);
|
|
598
|
-
},
|
|
599
|
-
attachIdentity: async ({ item, chain, payload }) => attachLedgerIdentity(
|
|
600
|
-
getChainFingerprint,
|
|
601
|
-
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,
|
|
602
572
|
item,
|
|
603
|
-
|
|
604
|
-
payload,
|
|
605
|
-
chainFingerprints,
|
|
573
|
+
commonParams,
|
|
606
574
|
installContext
|
|
607
|
-
)
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
}
|
|
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;
|
|
627
601
|
};
|
|
628
602
|
}
|
|
629
603
|
function isTopLevelAllNetworkFailure(response) {
|
|
@@ -631,7 +605,7 @@ function isTopLevelAllNetworkFailure(response) {
|
|
|
631
605
|
return false;
|
|
632
606
|
}
|
|
633
607
|
const code = response.payload?.code;
|
|
634
|
-
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;
|
|
635
609
|
}
|
|
636
610
|
function getItemDeviceId(item) {
|
|
637
611
|
const { deviceId } = item;
|
|
@@ -661,13 +635,8 @@ function normalizeLedgerAllNetworkItem(method, item) {
|
|
|
661
635
|
const coin = LEDGER_BTC_NETWORK_COIN_MAP[item.network];
|
|
662
636
|
return coin ? { ...item, coin } : item;
|
|
663
637
|
}
|
|
664
|
-
async function attachLedgerIdentity(getChainFingerprint, connectId, item, chain, payload, chainFingerprints
|
|
665
|
-
const fingerprint = getItemDeviceId(item) || chainFingerprints.get(chain) || await bootstrapChainFingerprint(
|
|
666
|
-
getChainFingerprint,
|
|
667
|
-
context.connection?.connectId ?? connectId,
|
|
668
|
-
chain,
|
|
669
|
-
context
|
|
670
|
-
);
|
|
638
|
+
async function attachLedgerIdentity(getChainFingerprint, connectId, item, chain, payload, chainFingerprints) {
|
|
639
|
+
const fingerprint = getItemDeviceId(item) || chainFingerprints.get(chain) || await bootstrapChainFingerprint(getChainFingerprint, connectId, chain);
|
|
671
640
|
if (!fingerprint) {
|
|
672
641
|
return buildFingerprintBootstrapFailure(item, chain);
|
|
673
642
|
}
|
|
@@ -688,8 +657,8 @@ async function attachLedgerIdentity(getChainFingerprint, connectId, item, chain,
|
|
|
688
657
|
}
|
|
689
658
|
};
|
|
690
659
|
}
|
|
691
|
-
async function bootstrapChainFingerprint(getChainFingerprint, connectId, chain
|
|
692
|
-
const response = await getChainFingerprint(connectId, chain
|
|
660
|
+
async function bootstrapChainFingerprint(getChainFingerprint, connectId, chain) {
|
|
661
|
+
const response = await getChainFingerprint(connectId, chain);
|
|
693
662
|
return response.success ? response.payload : "";
|
|
694
663
|
}
|
|
695
664
|
function buildFingerprintBootstrapFailure(item, chain) {
|
|
@@ -794,27 +763,8 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
794
763
|
constructor(connector, options) {
|
|
795
764
|
this.vendor = "ledger";
|
|
796
765
|
this.emitter = new import_hwk_adapter_core3.TypedEventEmitter();
|
|
797
|
-
this._operations = new import_hwk_adapter_core3.OperationRegistry({
|
|
798
|
-
vendor: "ledger",
|
|
799
|
-
onEnded: (operation, reason) => {
|
|
800
|
-
const binding = this._pendingOperationBindings.get(operation.operationId);
|
|
801
|
-
if (binding?.selectedConnection?.requestId === this._bindingSelectionRequestId) {
|
|
802
|
-
this._finishBleBinding("cancelled");
|
|
803
|
-
}
|
|
804
|
-
this._pendingOperationBindings.delete(operation.operationId);
|
|
805
|
-
this.emitter.emit(import_hwk_adapter_core3.SDK.OPERATION_ENDED, {
|
|
806
|
-
type: import_hwk_adapter_core3.SDK.OPERATION_ENDED,
|
|
807
|
-
payload: { operationId: operation.operationId, reason }
|
|
808
|
-
});
|
|
809
|
-
if (reason === "timeout") {
|
|
810
|
-
void this._releaseOperationConnection(operation);
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
});
|
|
814
766
|
this._discoveredDevices = /* @__PURE__ */ new Map();
|
|
815
767
|
this._sessions = /* @__PURE__ */ new Map();
|
|
816
|
-
this._pendingOperationBindings = /* @__PURE__ */ new Map();
|
|
817
|
-
this._verifiedBleReconnectTargets = /* @__PURE__ */ new Map();
|
|
818
768
|
this._uiRegistry = new import_hwk_adapter_core3.UiRequestRegistry();
|
|
819
769
|
// BTC App rejects account index >= 100 unless display=true. Cached per
|
|
820
770
|
// adapter instance: first 100+ path asks the user once via UI request,
|
|
@@ -828,30 +778,10 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
828
778
|
this._deviceAuthenticityQueueTail = Promise.resolve();
|
|
829
779
|
// Shared across concurrent callers — only `cancel()` aborts.
|
|
830
780
|
this._doConnectAbortController = null;
|
|
831
|
-
this._unsettledConnectorOperations = /* @__PURE__ */ new Map();
|
|
832
|
-
this._connectorIdleWaiters = /* @__PURE__ */ new Set();
|
|
833
|
-
this._resetPromise = null;
|
|
834
|
-
this._stateGeneration = 0;
|
|
835
|
-
this._connectorTeardownTail = Promise.resolve();
|
|
836
|
-
this._pendingConnectorTeardowns = 0;
|
|
837
|
-
this._activeOperationJobs = /* @__PURE__ */ new Set();
|
|
838
|
-
this._pendingOperationDisconnects = /* @__PURE__ */ new Set();
|
|
839
781
|
this._installProgressLastEmittedValue = -Infinity;
|
|
840
782
|
this.allNetworkGetAddress = createAllNetworkGetAddress({
|
|
841
783
|
callChain: this.callChain.bind(this),
|
|
842
|
-
getChainFingerprint:
|
|
843
|
-
try {
|
|
844
|
-
const fingerprint = await this._computeChainFingerprint(
|
|
845
|
-
chain,
|
|
846
|
-
(method, params) => this.connectorCall(connectId, method, params, void 0, void 0, void 0, context)
|
|
847
|
-
);
|
|
848
|
-
return (0, import_hwk_adapter_core3.success)(fingerprint);
|
|
849
|
-
} catch (error) {
|
|
850
|
-
return this.errorToFailure(error);
|
|
851
|
-
}
|
|
852
|
-
},
|
|
853
|
-
retainOperation: (operationId) => this._operations.retain(operationId),
|
|
854
|
-
errorToFailure: (error) => this.errorToFailure(error)
|
|
784
|
+
getChainFingerprint: (connectId, chain) => this.getChainFingerprint(connectId, "", chain)
|
|
855
785
|
});
|
|
856
786
|
// ---------------------------------------------------------------------------
|
|
857
787
|
// Private helpers
|
|
@@ -861,7 +791,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
861
791
|
*
|
|
862
792
|
* - If a session already exists for the given connectId, reuse it.
|
|
863
793
|
* - If ANY session exists (Ledger IDs are ephemeral), reuse it.
|
|
864
|
-
* - Otherwise: search →
|
|
794
|
+
* - Otherwise: search → exactly 1 USB device auto-connects; multiple or none throws.
|
|
865
795
|
*/
|
|
866
796
|
// Mutex for ensureConnected — prevents concurrent calls from establishing duplicate connections
|
|
867
797
|
this._connectingPromise = null;
|
|
@@ -878,12 +808,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
878
808
|
});
|
|
879
809
|
};
|
|
880
810
|
this.deviceDisconnectHandler = (data) => {
|
|
881
|
-
const activeOperation = this._operations.findActiveByConnectionKey(data.connectId);
|
|
882
|
-
if (activeOperation && this._activeOperationJobs.has(activeOperation.operationId)) {
|
|
883
|
-
this._pendingOperationDisconnects.add(activeOperation.operationId);
|
|
884
|
-
} else {
|
|
885
|
-
this._operations.endByConnectionKey(data.connectId, "disconnect");
|
|
886
|
-
}
|
|
887
811
|
this._discoveredDevices.delete(data.connectId);
|
|
888
812
|
this._sessions.delete(data.connectId);
|
|
889
813
|
this.emitter.emit(import_hwk_adapter_core3.DEVICE.DISCONNECT, {
|
|
@@ -940,28 +864,11 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
940
864
|
this._jobQueue = new import_hwk_adapter_core3.DeviceJobQueue();
|
|
941
865
|
this.registerEventListeners();
|
|
942
866
|
}
|
|
943
|
-
_finishBleBinding(status) {
|
|
944
|
-
const selectionRequestId = this._bindingSelectionRequestId;
|
|
945
|
-
this._bindingSelectionRequestId = void 0;
|
|
946
|
-
if (selectionRequestId)
|
|
947
|
-
this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.DEVICE_BINDING_STATUS, {
|
|
948
|
-
type: import_hwk_adapter_core3.UI_REQUEST.DEVICE_BINDING_STATUS,
|
|
949
|
-
payload: { selectionRequestId, status }
|
|
950
|
-
});
|
|
951
|
-
}
|
|
952
|
-
_isBleConnection() {
|
|
953
|
-
return isLedgerBleConnectionType(this._activeConnectionType ?? this.connector.connectionType);
|
|
954
|
-
}
|
|
955
867
|
// Transport
|
|
956
868
|
get activeTransport() {
|
|
957
|
-
return this.
|
|
869
|
+
return isLedgerBleConnectionType(this.connector.connectionType) ? "ble" : "hid";
|
|
958
870
|
}
|
|
959
871
|
getAvailableTransports() {
|
|
960
|
-
if (this.connector.availableTransports) {
|
|
961
|
-
return this.connector.availableTransports.map(
|
|
962
|
-
(transport) => transport === "ble" ? "ble" : "hid"
|
|
963
|
-
);
|
|
964
|
-
}
|
|
965
872
|
return this.activeTransport ? [this.activeTransport] : [];
|
|
966
873
|
}
|
|
967
874
|
// Connector is bound at construction; switching requires a new adapter.
|
|
@@ -978,39 +885,21 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
978
885
|
* The next operation will re-discover and re-connect automatically.
|
|
979
886
|
*/
|
|
980
887
|
resetState() {
|
|
981
|
-
void this._resetStateAndDisconnectSessions();
|
|
982
|
-
}
|
|
983
|
-
_resetStateAndDisconnectSessions() {
|
|
984
|
-
if (this._resetPromise) return this._resetPromise;
|
|
985
|
-
const sessionIds = new Set(this._sessions.values());
|
|
986
|
-
this._stateGeneration += 1;
|
|
987
|
-
this._finishBleBinding("cancelled");
|
|
988
|
-
this._operations.endAll("runtime-reset");
|
|
989
|
-
this._doConnectAbortController?.abort();
|
|
990
888
|
this._discoveredDevices.clear();
|
|
991
889
|
this._sessions.clear();
|
|
992
|
-
this._verifiedBleReconnectTargets.clear();
|
|
993
890
|
this._connectingPromise = null;
|
|
994
|
-
this._doConnectAbortController = null;
|
|
995
891
|
this._uiRegistry.reset();
|
|
996
892
|
this._jobQueue.clear();
|
|
997
893
|
this._btcHighIndexConfirmedThisSession = false;
|
|
998
|
-
const resetPromise = this._runConnectorTeardown(async () => {
|
|
999
|
-
for (const sessionId of sessionIds) {
|
|
1000
|
-
await this.connector.disconnect(sessionId).catch(() => void 0);
|
|
1001
|
-
}
|
|
1002
|
-
});
|
|
1003
|
-
this._resetPromise = resetPromise;
|
|
1004
|
-
return resetPromise.finally(() => {
|
|
1005
|
-
if (this._resetPromise === resetPromise) {
|
|
1006
|
-
this._resetPromise = null;
|
|
1007
|
-
}
|
|
1008
|
-
});
|
|
1009
894
|
}
|
|
1010
895
|
async dispose() {
|
|
1011
|
-
|
|
896
|
+
this._uiRegistry.reset();
|
|
897
|
+
this._jobQueue.clear();
|
|
1012
898
|
this.unregisterEventListeners();
|
|
1013
899
|
this.connector.reset();
|
|
900
|
+
this._discoveredDevices.clear();
|
|
901
|
+
this._sessions.clear();
|
|
902
|
+
this._btcHighIndexConfirmedThisSession = false;
|
|
1014
903
|
this.emitter.removeAllListeners();
|
|
1015
904
|
}
|
|
1016
905
|
uiResponse(response) {
|
|
@@ -1020,32 +909,17 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1020
909
|
// Device management
|
|
1021
910
|
// ---------------------------------------------------------------------------
|
|
1022
911
|
async searchDevices(options) {
|
|
1023
|
-
return this._searchDevices(options);
|
|
1024
|
-
}
|
|
1025
|
-
async _searchDevices(options, signal) {
|
|
1026
912
|
debugLog("[LedgerAdapter][REQ]", { method: "searchDevices", params: options });
|
|
1027
913
|
try {
|
|
1028
914
|
if (options?.resetSession) {
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
if (signal) _LedgerAdapter._throwIfAborted(signal);
|
|
1035
|
-
const stateGeneration = this._stateGeneration;
|
|
1036
|
-
const devices = await this.connector.searchDevices(
|
|
1037
|
-
options?.transportType ? {
|
|
1038
|
-
transportType: options.transportType,
|
|
1039
|
-
waitForAll: options.waitForAllTransports
|
|
1040
|
-
} : void 0
|
|
1041
|
-
);
|
|
1042
|
-
if (signal) _LedgerAdapter._throwIfAborted(signal);
|
|
1043
|
-
if (stateGeneration !== this._stateGeneration) {
|
|
1044
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
1045
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.UserAborted,
|
|
1046
|
-
message: "Ledger discovery was reset"
|
|
1047
|
-
});
|
|
915
|
+
this._doConnectAbortController?.abort();
|
|
916
|
+
this._sessions.clear();
|
|
917
|
+
this._connectingPromise = null;
|
|
918
|
+
this._doConnectAbortController = null;
|
|
919
|
+
this._btcHighIndexConfirmedThisSession = false;
|
|
1048
920
|
}
|
|
921
|
+
await this._ensureDevicePermission();
|
|
922
|
+
const devices = await this.connector.searchDevices();
|
|
1049
923
|
this._discoveredDevices.clear();
|
|
1050
924
|
for (const d of devices) {
|
|
1051
925
|
if (d.connectId) {
|
|
@@ -1053,7 +927,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1053
927
|
}
|
|
1054
928
|
}
|
|
1055
929
|
if (this._discoveredDevices.size === 0) {
|
|
1056
|
-
await this._ensureDevicePermission(
|
|
930
|
+
await this._ensureDevicePermission();
|
|
1057
931
|
}
|
|
1058
932
|
const result = Array.from(this._discoveredDevices.values());
|
|
1059
933
|
debugLog("[LedgerAdapter][RES]", {
|
|
@@ -1072,285 +946,41 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1072
946
|
throw err;
|
|
1073
947
|
}
|
|
1074
948
|
}
|
|
1075
|
-
async searchDeviceTargets(options) {
|
|
1076
|
-
const devices = await this.searchDevices(options);
|
|
1077
|
-
return devices.map((device) => ({
|
|
1078
|
-
searchTargetId: device.connectId,
|
|
1079
|
-
searchTargetReusePolicy: (0, import_hwk_adapter_core3.resolveSearchTargetReusePolicy)(device),
|
|
1080
|
-
vendor: "ledger",
|
|
1081
|
-
connectionType: device.connectionType,
|
|
1082
|
-
kind: "physical",
|
|
1083
|
-
label: device.label,
|
|
1084
|
-
model: device.model,
|
|
1085
|
-
modelName: device.modelName,
|
|
1086
|
-
serialNumber: device.serialNumber
|
|
1087
|
-
}));
|
|
1088
|
-
}
|
|
1089
|
-
async listConnectionTargets(options) {
|
|
1090
|
-
const targets = await this.searchDeviceTargets(options);
|
|
1091
|
-
return targets.map(({ searchTargetId, ...target }) => ({
|
|
1092
|
-
...target,
|
|
1093
|
-
targetId: searchTargetId
|
|
1094
|
-
}));
|
|
1095
|
-
}
|
|
1096
949
|
// USB single-session invariant: evict all sessions, best-effort (see connectDevice).
|
|
1097
|
-
async _evictAllSessions(
|
|
1098
|
-
this._operations.endAll("explicit", preserveOperationId);
|
|
950
|
+
async _evictAllSessions() {
|
|
1099
951
|
if (this._sessions.size === 0) return;
|
|
1100
952
|
const stale = [...this._sessions.values()];
|
|
1101
953
|
this._sessions.clear();
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
} catch {
|
|
1107
|
-
}
|
|
954
|
+
for (const sid of stale) {
|
|
955
|
+
try {
|
|
956
|
+
await this.connector.disconnect(sid);
|
|
957
|
+
} catch {
|
|
1108
958
|
}
|
|
1109
|
-
}
|
|
959
|
+
}
|
|
1110
960
|
}
|
|
1111
961
|
static _createDeviceBusyError(method) {
|
|
1112
962
|
return Object.assign(new Error(`Ledger device is busy while calling ${method}`), {
|
|
1113
963
|
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceBusy
|
|
1114
964
|
});
|
|
1115
965
|
}
|
|
1116
|
-
async connectDevice(
|
|
1117
|
-
try {
|
|
1118
|
-
return await this._jobQueue.enqueue(
|
|
1119
|
-
searchTargetId || "__ledger_connect__",
|
|
1120
|
-
async () => {
|
|
1121
|
-
const connected = await this._connectTarget(searchTargetId);
|
|
1122
|
-
if (!connected.success) return connected;
|
|
1123
|
-
return this._createOperation(searchTargetId, connected.payload);
|
|
1124
|
-
},
|
|
1125
|
-
{
|
|
1126
|
-
label: "connectDevice",
|
|
1127
|
-
rejectIfBusy: true,
|
|
1128
|
-
busyError: _LedgerAdapter._createDeviceBusyError("connectDevice")
|
|
1129
|
-
}
|
|
1130
|
-
);
|
|
1131
|
-
} catch (error) {
|
|
1132
|
-
return this.errorToFailure(error);
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
async bindBleDevice(params) {
|
|
1136
|
-
if (params.identity.vendor !== "ledger" || !params.identity.value) {
|
|
1137
|
-
return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "Ledger wallet identity is required");
|
|
1138
|
-
}
|
|
1139
|
-
const { chain, value: expectedFingerprint } = params.identity;
|
|
1140
|
-
try {
|
|
1141
|
-
return await this._jobQueue.enqueue(
|
|
1142
|
-
expectedFingerprint,
|
|
1143
|
-
async (signal) => {
|
|
1144
|
-
if (!this.getAvailableTransports().includes("ble")) {
|
|
1145
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
1146
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.TransportNotAvailable,
|
|
1147
|
-
message: "Ledger Bluetooth transport is not available"
|
|
1148
|
-
});
|
|
1149
|
-
}
|
|
1150
|
-
this._activeConnectionType = "ble";
|
|
1151
|
-
await this._ensureDevicePermission(void 0, void 0, signal);
|
|
1152
|
-
const attempt = {
|
|
1153
|
-
extra: params.extra,
|
|
1154
|
-
bindingReason: "manual-rebind"
|
|
1155
|
-
};
|
|
1156
|
-
try {
|
|
1157
|
-
for (; ; ) {
|
|
1158
|
-
const connectId = await this._connectFirstOrSelect(
|
|
1159
|
-
[],
|
|
1160
|
-
void 0,
|
|
1161
|
-
true,
|
|
1162
|
-
void 0,
|
|
1163
|
-
attempt,
|
|
1164
|
-
signal
|
|
1165
|
-
);
|
|
1166
|
-
const sessionId = this._sessions.get(connectId);
|
|
1167
|
-
if (!sessionId) {
|
|
1168
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
1169
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
|
|
1170
|
-
message: "Selected Ledger connection ended"
|
|
1171
|
-
});
|
|
1172
|
-
}
|
|
1173
|
-
let saved = false;
|
|
1174
|
-
try {
|
|
1175
|
-
const installContext = {
|
|
1176
|
-
connection: { connectId, sessionId }
|
|
1177
|
-
};
|
|
1178
|
-
const fingerprint = await this._computeChainFingerprint(
|
|
1179
|
-
chain,
|
|
1180
|
-
(method, callParams) => this._runConnectorCall(
|
|
1181
|
-
connectId,
|
|
1182
|
-
method,
|
|
1183
|
-
callParams,
|
|
1184
|
-
signal,
|
|
1185
|
-
void 0,
|
|
1186
|
-
void 0,
|
|
1187
|
-
{ autoInstallApp: true },
|
|
1188
|
-
installContext
|
|
1189
|
-
)
|
|
1190
|
-
);
|
|
1191
|
-
if (fingerprint !== expectedFingerprint) {
|
|
1192
|
-
attempt.rejectedConnectIds ?? (attempt.rejectedConnectIds = /* @__PURE__ */ new Set());
|
|
1193
|
-
attempt.rejectedConnectIds.add(connectId);
|
|
1194
|
-
attempt.rejectedConnectId = connectId;
|
|
1195
|
-
} else {
|
|
1196
|
-
const persisted = await this._publishVerifiedBleBinding(
|
|
1197
|
-
connectId,
|
|
1198
|
-
chain,
|
|
1199
|
-
fingerprint,
|
|
1200
|
-
attempt,
|
|
1201
|
-
void 0,
|
|
1202
|
-
signal
|
|
1203
|
-
);
|
|
1204
|
-
if (!persisted) {
|
|
1205
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
1206
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.UnknownError,
|
|
1207
|
-
message: "Bluetooth binding could not be saved",
|
|
1208
|
-
origin: "host"
|
|
1209
|
-
});
|
|
1210
|
-
}
|
|
1211
|
-
saved = true;
|
|
1212
|
-
return (0, import_hwk_adapter_core3.success)(connectId);
|
|
1213
|
-
}
|
|
1214
|
-
} finally {
|
|
1215
|
-
if (!saved && this._sessions.get(connectId) === sessionId) {
|
|
1216
|
-
this._sessions.delete(connectId);
|
|
1217
|
-
const teardown = this._runConnectorTeardown(
|
|
1218
|
-
() => this.connector.disconnect(sessionId)
|
|
1219
|
-
).catch(() => void 0);
|
|
1220
|
-
if (!signal.aborted) await teardown;
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
} catch (error) {
|
|
1225
|
-
this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
|
|
1226
|
-
throw error;
|
|
1227
|
-
}
|
|
1228
|
-
},
|
|
1229
|
-
{
|
|
1230
|
-
label: "bindBleDevice",
|
|
1231
|
-
rejectIfBusy: true,
|
|
1232
|
-
busyError: _LedgerAdapter._createDeviceBusyError("bindBleDevice")
|
|
1233
|
-
}
|
|
1234
|
-
);
|
|
1235
|
-
} catch (error) {
|
|
1236
|
-
return this.errorToFailure(error);
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1239
|
-
async acquireOperation(connectId, context) {
|
|
1240
|
-
try {
|
|
1241
|
-
return await this._jobQueue.enqueue(
|
|
1242
|
-
connectId || "__ledger_acquire__",
|
|
1243
|
-
async (signal) => {
|
|
1244
|
-
const transport = this._isBleConnection() ? "ble" : "usb";
|
|
1245
|
-
const hint = context.knownConnections?.find(
|
|
1246
|
-
(connection) => connection.transport === transport
|
|
1247
|
-
);
|
|
1248
|
-
const target = hint && hint.transport !== "qr" ? hint.connectId : connectId;
|
|
1249
|
-
await this._ensureDevicePermission(target, void 0, signal);
|
|
1250
|
-
const attempt = {
|
|
1251
|
-
...context,
|
|
1252
|
-
extra: context.extra ? { ...context.extra } : void 0
|
|
1253
|
-
};
|
|
1254
|
-
try {
|
|
1255
|
-
const resolvedConnectId = await this.ensureConnected(
|
|
1256
|
-
target,
|
|
1257
|
-
signal,
|
|
1258
|
-
true,
|
|
1259
|
-
void 0,
|
|
1260
|
-
attempt
|
|
1261
|
-
);
|
|
1262
|
-
_LedgerAdapter._throwIfAborted(signal);
|
|
1263
|
-
const result = this._createOperation(connectId, resolvedConnectId);
|
|
1264
|
-
if (result.success && attempt.selectedConnection) {
|
|
1265
|
-
this._pendingOperationBindings.set(result.payload, attempt);
|
|
1266
|
-
}
|
|
1267
|
-
return result;
|
|
1268
|
-
} catch (error) {
|
|
1269
|
-
this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
|
|
1270
|
-
throw error;
|
|
1271
|
-
}
|
|
1272
|
-
},
|
|
1273
|
-
{
|
|
1274
|
-
label: "acquireOperation",
|
|
1275
|
-
rejectIfBusy: true,
|
|
1276
|
-
busyError: _LedgerAdapter._createDeviceBusyError("acquireOperation")
|
|
1277
|
-
}
|
|
1278
|
-
);
|
|
1279
|
-
} catch (error) {
|
|
1280
|
-
return this.errorToFailure(error);
|
|
1281
|
-
}
|
|
1282
|
-
}
|
|
1283
|
-
_createOperation(searchTargetId, resolvedConnectId) {
|
|
1284
|
-
this._operations.endByConnectionKey(resolvedConnectId, "explicit");
|
|
1285
|
-
const sessionId = this._sessions.get(resolvedConnectId);
|
|
1286
|
-
if (sessionId) this._operations.endByConnectionKey(sessionId, "explicit");
|
|
1287
|
-
const device = this._discoveredDevices.get(resolvedConnectId) ?? {
|
|
1288
|
-
vendor: "ledger",
|
|
1289
|
-
model: "unknown",
|
|
1290
|
-
firmwareVersion: "",
|
|
1291
|
-
deviceId: "",
|
|
1292
|
-
connectId: resolvedConnectId,
|
|
1293
|
-
connectionType: this.connector.connectionType
|
|
1294
|
-
};
|
|
1295
|
-
const operation = this._operations.create({
|
|
1296
|
-
searchTargetId,
|
|
1297
|
-
connectId: resolvedConnectId,
|
|
1298
|
-
device,
|
|
1299
|
-
connectionKeys: [this._sessions.get(resolvedConnectId) ?? ""]
|
|
1300
|
-
});
|
|
1301
|
-
return (0, import_hwk_adapter_core3.success)(operation.operationId);
|
|
1302
|
-
}
|
|
1303
|
-
async _connectTarget(connectId, preserveOperationId, signal) {
|
|
966
|
+
async connectDevice(connectId) {
|
|
1304
967
|
debugLog("[LedgerAdapter][REQ]", { method: "connectDevice", connectId, params: { connectId } });
|
|
1305
968
|
try {
|
|
1306
|
-
this.
|
|
1307
|
-
const discoveredType = this._discoveredDevices.get(connectId)?.connectionType;
|
|
1308
|
-
if (discoveredType === "usb" || discoveredType === "ble") {
|
|
1309
|
-
this._activeConnectionType = discoveredType;
|
|
1310
|
-
}
|
|
1311
|
-
if (this._isBleConnection() && !connectId) {
|
|
969
|
+
if (isLedgerBleConnectionType(this.connector.connectionType) && !connectId) {
|
|
1312
970
|
throw Object.assign(new Error("Ledger BLE connectId is required."), {
|
|
1313
971
|
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
|
|
1314
972
|
});
|
|
1315
973
|
}
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
if (this.connector.availableTransports && this.connector.availableTransports.length > 1) {
|
|
1319
|
-
await this._evictAllSessions(preserveOperationId);
|
|
1320
|
-
} else if (this._isBleConnection()) {
|
|
1321
|
-
const previousSessionId = this._sessions.get(connectId);
|
|
1322
|
-
this._operations.endByConnectionKey(connectId, "explicit", preserveOperationId);
|
|
1323
|
-
if (previousSessionId) {
|
|
1324
|
-
this._operations.endByConnectionKey(previousSessionId, "explicit", preserveOperationId);
|
|
1325
|
-
this._sessions.delete(connectId);
|
|
1326
|
-
await this.connector.disconnect(previousSessionId).catch(() => void 0);
|
|
1327
|
-
}
|
|
1328
|
-
} else {
|
|
1329
|
-
await this._evictAllSessions(preserveOperationId);
|
|
1330
|
-
}
|
|
1331
|
-
if (signal) _LedgerAdapter._throwIfAborted(signal);
|
|
1332
|
-
const stateGeneration = this._stateGeneration;
|
|
1333
|
-
const releaseOperation = this._retainConnectorOperation(`connect:${connectId}`);
|
|
1334
|
-
let session;
|
|
1335
|
-
try {
|
|
1336
|
-
session = this.connector.availableTransports?.length ? await this.connector.connect(connectId, {
|
|
1337
|
-
transportType: this._activeConnectionType ?? "usb"
|
|
1338
|
-
}) : await this.connector.connect(connectId);
|
|
1339
|
-
if (signal?.aborted || stateGeneration !== this._stateGeneration) {
|
|
1340
|
-
await this.connector.disconnect(session.sessionId).catch(() => void 0);
|
|
1341
|
-
throw Object.assign(new Error("Ledger connection aborted"), {
|
|
1342
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.UserAborted
|
|
1343
|
-
});
|
|
1344
|
-
}
|
|
1345
|
-
} finally {
|
|
1346
|
-
releaseOperation();
|
|
974
|
+
if (!isLedgerBleConnectionType(this.connector.connectionType)) {
|
|
975
|
+
await this._evictAllSessions();
|
|
1347
976
|
}
|
|
1348
|
-
|
|
1349
|
-
this.
|
|
977
|
+
await this._ensureDevicePermission(connectId);
|
|
978
|
+
const session = await this.connector.connect(connectId);
|
|
979
|
+
this._sessions.set(connectId, session.sessionId);
|
|
1350
980
|
if (session.deviceInfo) {
|
|
1351
|
-
this._discoveredDevices.set(
|
|
981
|
+
this._discoveredDevices.set(connectId, session.deviceInfo);
|
|
1352
982
|
}
|
|
1353
|
-
const result = (0, import_hwk_adapter_core3.success)(
|
|
983
|
+
const result = (0, import_hwk_adapter_core3.success)(connectId);
|
|
1354
984
|
debugLog("[LedgerAdapter][RES]", { method: "connectDevice", success: true, payload: result });
|
|
1355
985
|
return result;
|
|
1356
986
|
} catch (err) {
|
|
@@ -1363,60 +993,30 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1363
993
|
return failureResult;
|
|
1364
994
|
}
|
|
1365
995
|
}
|
|
1366
|
-
async
|
|
1367
|
-
const operation = this._operations.find(operationId);
|
|
1368
|
-
if (!operation) {
|
|
1369
|
-
this._operations.resolve(operationId);
|
|
1370
|
-
return;
|
|
1371
|
-
}
|
|
1372
|
-
const endedOperation = this._operations.end(operationId, "explicit");
|
|
1373
|
-
if (!endedOperation) return;
|
|
1374
|
-
const { connectId } = operation;
|
|
996
|
+
async disconnectDevice(connectId) {
|
|
1375
997
|
debugLog("[LedgerAdapter][REQ]", {
|
|
1376
|
-
method: "
|
|
998
|
+
method: "disconnectDevice",
|
|
1377
999
|
connectId,
|
|
1378
1000
|
params: { connectId }
|
|
1379
1001
|
});
|
|
1380
1002
|
try {
|
|
1381
|
-
|
|
1382
|
-
|
|
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 });
|
|
1383
1009
|
} catch (err) {
|
|
1384
1010
|
const e = err;
|
|
1385
1011
|
debugLog("[LedgerAdapter][RES]", {
|
|
1386
|
-
method: "
|
|
1012
|
+
method: "disconnectDevice",
|
|
1387
1013
|
success: false,
|
|
1388
1014
|
error: { message: e?.message, _tag: e?._tag, code: e?.code ?? e?.errorCode }
|
|
1389
1015
|
});
|
|
1390
1016
|
throw err;
|
|
1391
1017
|
}
|
|
1392
1018
|
}
|
|
1393
|
-
async
|
|
1394
|
-
const sessionIds = /* @__PURE__ */ new Set();
|
|
1395
|
-
for (const [connectId, sessionId] of this._sessions) {
|
|
1396
|
-
if (connectId === operation.connectId || operation.connectionKeys.includes(connectId) || operation.connectionKeys.includes(sessionId)) {
|
|
1397
|
-
this._sessions.delete(connectId);
|
|
1398
|
-
sessionIds.add(sessionId);
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
for (const sessionId of sessionIds) {
|
|
1402
|
-
await this._runConnectorTeardown(
|
|
1403
|
-
() => this.connector.disconnect(sessionId).catch(() => void 0)
|
|
1404
|
-
);
|
|
1405
|
-
}
|
|
1406
|
-
}
|
|
1407
|
-
async _releaseLostOperationConnection(operationId) {
|
|
1408
|
-
const endedOperation = this._operations.end(operationId, "disconnect");
|
|
1409
|
-
if (!endedOperation) return;
|
|
1410
|
-
this._discoveredDevices.delete(endedOperation.connectId);
|
|
1411
|
-
await this._releaseOperationConnection(endedOperation);
|
|
1412
|
-
}
|
|
1413
|
-
async getDeviceInfo(connectIdOrOperationId, deviceId) {
|
|
1414
|
-
let connectId;
|
|
1415
|
-
try {
|
|
1416
|
-
connectId = (0, import_hwk_adapter_core3.isHardwareOperationId)(connectIdOrOperationId) ? this._operations.resolve(connectIdOrOperationId).connectId : connectIdOrOperationId;
|
|
1417
|
-
} catch (error) {
|
|
1418
|
-
return this.errorToFailure(error);
|
|
1419
|
-
}
|
|
1019
|
+
async getDeviceInfo(connectId, deviceId) {
|
|
1420
1020
|
debugLog("[LedgerAdapter][REQ]", {
|
|
1421
1021
|
method: "getDeviceInfo",
|
|
1422
1022
|
connectId,
|
|
@@ -1454,6 +1054,9 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1454
1054
|
throw err;
|
|
1455
1055
|
}
|
|
1456
1056
|
}
|
|
1057
|
+
getSupportedChains() {
|
|
1058
|
+
return ["evm", "btc", "sol", "tron"];
|
|
1059
|
+
}
|
|
1457
1060
|
// ---------------------------------------------------------------------------
|
|
1458
1061
|
// Chain call helper
|
|
1459
1062
|
// ---------------------------------------------------------------------------
|
|
@@ -1488,21 +1091,13 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1488
1091
|
if (params && typeof params === "object") {
|
|
1489
1092
|
const {
|
|
1490
1093
|
autoInstallApp,
|
|
1491
|
-
operationId,
|
|
1492
1094
|
passphraseState: _passphraseState,
|
|
1493
1095
|
useEmptyPassphrase: _useEmptyPassphrase,
|
|
1494
|
-
knownConnections,
|
|
1495
|
-
extra,
|
|
1496
|
-
allowDeviceSelection,
|
|
1497
1096
|
...rest
|
|
1498
1097
|
} = params;
|
|
1499
1098
|
return {
|
|
1500
1099
|
commonParams: {
|
|
1501
|
-
autoInstallApp: typeof autoInstallApp === "boolean" ? autoInstallApp : void 0
|
|
1502
|
-
operationId: typeof operationId === "string" ? operationId : void 0,
|
|
1503
|
-
knownConnections,
|
|
1504
|
-
extra,
|
|
1505
|
-
allowDeviceSelection: typeof allowDeviceSelection === "boolean" ? allowDeviceSelection : void 0
|
|
1100
|
+
autoInstallApp: typeof autoInstallApp === "boolean" ? autoInstallApp : void 0
|
|
1506
1101
|
},
|
|
1507
1102
|
rest
|
|
1508
1103
|
};
|
|
@@ -1678,27 +1273,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1678
1273
|
);
|
|
1679
1274
|
}
|
|
1680
1275
|
// ---------------------------------------------------------------------------
|
|
1681
|
-
// Zcash chain methods (viewing key + shielded address reads; Zcash app >= 3.8.0)
|
|
1682
|
-
// ---------------------------------------------------------------------------
|
|
1683
|
-
zcashGetFullViewingKey(connectId, deviceId, params) {
|
|
1684
|
-
return this.callChainWithMergedParams(
|
|
1685
|
-
connectId,
|
|
1686
|
-
deviceId,
|
|
1687
|
-
"zcash",
|
|
1688
|
-
"zcashGetFullViewingKey",
|
|
1689
|
-
params
|
|
1690
|
-
);
|
|
1691
|
-
}
|
|
1692
|
-
zcashGetShieldedAddress(connectId, deviceId, params) {
|
|
1693
|
-
return this.callChainWithMergedParams(
|
|
1694
|
-
connectId,
|
|
1695
|
-
deviceId,
|
|
1696
|
-
"zcash",
|
|
1697
|
-
"zcashGetShieldedAddress",
|
|
1698
|
-
params
|
|
1699
|
-
);
|
|
1700
|
-
}
|
|
1701
|
-
// ---------------------------------------------------------------------------
|
|
1702
1276
|
// App management — OS-level Ledger app install / list. Bypasses fingerprint
|
|
1703
1277
|
// and chain-handler dispatch; installApp progress is forwarded to the adapter
|
|
1704
1278
|
// emitter via 'ui-event' AppInstallProgress events.
|
|
@@ -1787,7 +1361,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1787
1361
|
);
|
|
1788
1362
|
}
|
|
1789
1363
|
await this.connector.configure({ ledgerGenuineCheckWebSocketUrl: relayUrl });
|
|
1790
|
-
|
|
1364
|
+
this.resetState();
|
|
1791
1365
|
}
|
|
1792
1366
|
const result = await this.connectorCall(connectId, "getDeviceGenuineCheck", {});
|
|
1793
1367
|
if (!result.isGenuine) {
|
|
@@ -1813,10 +1387,10 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1813
1387
|
if (relayUrl) {
|
|
1814
1388
|
try {
|
|
1815
1389
|
await this.connector.configure?.({ ledgerGenuineCheckWebSocketUrl: void 0 });
|
|
1816
|
-
|
|
1390
|
+
this.resetState();
|
|
1817
1391
|
} catch {
|
|
1818
1392
|
this.connector.reset();
|
|
1819
|
-
|
|
1393
|
+
this.resetState();
|
|
1820
1394
|
}
|
|
1821
1395
|
}
|
|
1822
1396
|
}
|
|
@@ -1828,20 +1402,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1828
1402
|
this.emitter.off(event, listener);
|
|
1829
1403
|
}
|
|
1830
1404
|
cancel(connectId) {
|
|
1831
|
-
const namedOperationIsLive = (id) => {
|
|
1832
|
-
try {
|
|
1833
|
-
this._operations.resolve(id);
|
|
1834
|
-
return true;
|
|
1835
|
-
} catch {
|
|
1836
|
-
return false;
|
|
1837
|
-
}
|
|
1838
|
-
};
|
|
1839
|
-
if ((0, import_hwk_adapter_core3.isHardwareOperationId)(connectId) && !namedOperationIsLive(connectId)) {
|
|
1840
|
-
debugLog("[LedgerAdapter] cancel target already ended; nothing to cancel", {
|
|
1841
|
-
connectId
|
|
1842
|
-
});
|
|
1843
|
-
return;
|
|
1844
|
-
}
|
|
1845
1405
|
const userAbortReason = Object.assign(new Error("User aborted operation"), {
|
|
1846
1406
|
code: import_hwk_adapter_core3.HardwareErrorCode.UserAborted,
|
|
1847
1407
|
_tag: ERROR_TAG.UserAborted
|
|
@@ -1852,37 +1412,14 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1852
1412
|
this._lastCancelReason = void 0;
|
|
1853
1413
|
}
|
|
1854
1414
|
}, 2e3);
|
|
1855
|
-
const activeJobId = this._jobQueue.getActiveJob()?.deviceId;
|
|
1856
|
-
let operationId;
|
|
1857
|
-
if ((0, import_hwk_adapter_core3.isHardwareOperationId)(connectId)) {
|
|
1858
|
-
operationId = connectId;
|
|
1859
|
-
} else if (!connectId && (0, import_hwk_adapter_core3.isHardwareOperationId)(activeJobId)) {
|
|
1860
|
-
operationId = activeJobId;
|
|
1861
|
-
}
|
|
1862
|
-
let resolvedConnectId = connectId;
|
|
1863
|
-
if (operationId) {
|
|
1864
|
-
try {
|
|
1865
|
-
resolvedConnectId = this._operations.resolve(operationId).connectId;
|
|
1866
|
-
} catch {
|
|
1867
|
-
resolvedConnectId = void 0;
|
|
1868
|
-
}
|
|
1869
|
-
}
|
|
1870
1415
|
this._uiRegistry.cancel();
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
const queueKey = operationId ?? (activeJobId === connectId ? connectId : interactionForPhysicalId?.operationId) ?? connectId;
|
|
1874
|
-
const pendingOperationId = operationId ?? interactionForPhysicalId?.operationId;
|
|
1875
|
-
if (!connectId) this._pendingOperationBindings.clear();
|
|
1876
|
-
else if (pendingOperationId) {
|
|
1877
|
-
this._pendingOperationBindings.delete(pendingOperationId);
|
|
1878
|
-
}
|
|
1879
|
-
if (queueKey) {
|
|
1880
|
-
this._jobQueue.cancelActiveAndPending(queueKey, userAbortReason);
|
|
1416
|
+
if (connectId) {
|
|
1417
|
+
this._jobQueue.cancelActiveAndPending(connectId, userAbortReason);
|
|
1881
1418
|
} else {
|
|
1882
1419
|
this._jobQueue.cancelActiveAndPending(void 0, userAbortReason);
|
|
1883
1420
|
}
|
|
1884
|
-
if (
|
|
1885
|
-
const sessionId = this._sessions.get(
|
|
1421
|
+
if (connectId) {
|
|
1422
|
+
const sessionId = this._sessions.get(connectId) ?? connectId;
|
|
1886
1423
|
void this.connector.cancel(sessionId);
|
|
1887
1424
|
} else {
|
|
1888
1425
|
for (const sid of this._sessions.values()) void this.connector.cancel(sid);
|
|
@@ -1894,98 +1431,41 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1894
1431
|
// ---------------------------------------------------------------------------
|
|
1895
1432
|
// Chain fingerprint
|
|
1896
1433
|
// ---------------------------------------------------------------------------
|
|
1897
|
-
/** A non-empty deviceId is an expected chain fingerprint, not a transport identifier. */
|
|
1898
1434
|
async getChainFingerprint(connectId, deviceId, chain) {
|
|
1899
1435
|
try {
|
|
1900
1436
|
const fingerprint = await this._computeChainFingerprint(
|
|
1901
1437
|
chain,
|
|
1902
1438
|
(method, params) => this.connectorCall(connectId, method, params, void 0, deviceId)
|
|
1903
1439
|
);
|
|
1904
|
-
if (deviceId) {
|
|
1905
|
-
if (fingerprint !== deviceId) {
|
|
1906
|
-
return (0, import_hwk_adapter_core3.failure)(
|
|
1907
|
-
import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch,
|
|
1908
|
-
formatDeviceMismatchError(deviceId, fingerprint)
|
|
1909
|
-
);
|
|
1910
|
-
}
|
|
1911
|
-
if ((0, import_hwk_adapter_core3.isHardwareOperationId)(connectId)) {
|
|
1912
|
-
const operation = this._operations.resolve(connectId);
|
|
1913
|
-
await this._publishVerifiedBleBinding(
|
|
1914
|
-
operation.connectId,
|
|
1915
|
-
chain,
|
|
1916
|
-
fingerprint,
|
|
1917
|
-
void 0,
|
|
1918
|
-
connectId
|
|
1919
|
-
);
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
1922
1440
|
return (0, import_hwk_adapter_core3.success)(fingerprint);
|
|
1923
1441
|
} catch (err) {
|
|
1924
1442
|
debugError("[LedgerAdapter] getChainFingerprint error:", chain, err);
|
|
1925
1443
|
return this.errorToFailure(err);
|
|
1926
1444
|
}
|
|
1927
1445
|
}
|
|
1928
|
-
/**
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
}
|
|
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 };
|
|
1934
1452
|
try {
|
|
1935
|
-
const
|
|
1936
|
-
|
|
1937
|
-
this.
|
|
1938
|
-
{
|
|
1939
|
-
selectionRequestId: binding.selectedConnection.requestId,
|
|
1940
|
-
connection: { transport: "ble", connectId },
|
|
1941
|
-
identity: { vendor: "ledger", type: "chainFingerprint", chain, value: fingerprint },
|
|
1942
|
-
extra: binding.extra
|
|
1943
|
-
},
|
|
1944
|
-
signal
|
|
1453
|
+
const fingerprint = await this._computeChainFingerprint(
|
|
1454
|
+
chain,
|
|
1455
|
+
(method, params) => this._callConnector(sessionId, method, params)
|
|
1945
1456
|
);
|
|
1946
|
-
if (
|
|
1947
|
-
|
|
1948
|
-
debugLog("[LedgerAdapter] BLE binding not persisted by host", {
|
|
1949
|
-
connectId,
|
|
1950
|
-
reason: outcome.reason
|
|
1951
|
-
});
|
|
1952
|
-
}
|
|
1953
|
-
return outcome.saved;
|
|
1954
|
-
} catch (error) {
|
|
1955
|
-
if (operationId) {
|
|
1956
|
-
this._pendingOperationBindings.delete(operationId);
|
|
1957
|
-
this._operations.end(operationId, "explicit");
|
|
1958
|
-
}
|
|
1959
|
-
const sessionId = this._sessions.get(connectId);
|
|
1960
|
-
this._sessions.delete(connectId);
|
|
1961
|
-
if (sessionId) {
|
|
1962
|
-
const teardown = this._runConnectorTeardown(
|
|
1963
|
-
() => this.connector.disconnect(sessionId)
|
|
1964
|
-
).catch(() => void 0);
|
|
1965
|
-
if (!signal?.aborted) await teardown;
|
|
1457
|
+
if (fingerprint === deviceId) {
|
|
1458
|
+
return { success: true };
|
|
1966
1459
|
}
|
|
1967
|
-
|
|
1968
|
-
}
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
if (operationId) {
|
|
1973
|
-
this._pendingOperationBindings.delete(operationId);
|
|
1460
|
+
return { success: false, expected: deviceId, actual: fingerprint };
|
|
1461
|
+
} catch (err) {
|
|
1462
|
+
const mapped = mapLedgerError(err);
|
|
1463
|
+
if (mapped.code === import_hwk_adapter_core3.HardwareErrorCode.WrongApp || mapped.code === import_hwk_adapter_core3.HardwareErrorCode.DeviceLocked) {
|
|
1464
|
+
return { success: true };
|
|
1974
1465
|
}
|
|
1466
|
+
throw err;
|
|
1975
1467
|
}
|
|
1976
1468
|
}
|
|
1977
|
-
/** Verify on the acquired session without re-entering the job queue. */
|
|
1978
|
-
async _verifyDeviceFingerprintWithSession(sessionId, deviceId, chain) {
|
|
1979
|
-
if (!deviceId) return { success: true };
|
|
1980
|
-
const fingerprint = await this._computeChainFingerprint(
|
|
1981
|
-
chain,
|
|
1982
|
-
(method, params) => this._callConnector(sessionId, method, params)
|
|
1983
|
-
);
|
|
1984
|
-
if (fingerprint === deviceId) {
|
|
1985
|
-
return { success: true };
|
|
1986
|
-
}
|
|
1987
|
-
return { success: false, expected: deviceId, actual: fingerprint };
|
|
1988
|
-
}
|
|
1989
1469
|
/**
|
|
1990
1470
|
* Compute the chain fingerprint via a caller-supplied call strategy.
|
|
1991
1471
|
*
|
|
@@ -2013,8 +1493,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2013
1493
|
address = (await callMethod("solGetAddress", { path, showOnDevice: false })).address;
|
|
2014
1494
|
} else if (chain === "tron") {
|
|
2015
1495
|
address = (await callMethod("tronGetAddress", { path, showOnDevice: false })).address;
|
|
2016
|
-
} else if (chain === "zcash") {
|
|
2017
|
-
address = (await callMethod("zcashGetShieldedAddress", { path, showOnDevice: false })).address;
|
|
2018
1496
|
} else {
|
|
2019
1497
|
throw new Error(`Unsupported chain for fingerprint: ${chain}`);
|
|
2020
1498
|
}
|
|
@@ -2144,17 +1622,16 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2144
1622
|
// Layer 1 entry. Caller signal only races the outer awaiter; the shared
|
|
2145
1623
|
// `_doConnect` runs under its own internal controller so caller A's cancel
|
|
2146
1624
|
// doesn't kill caller B's await.
|
|
2147
|
-
async ensureConnected(connectId, signal, allowUsbEphemeralFallback = false
|
|
1625
|
+
async ensureConnected(connectId, signal, allowUsbEphemeralFallback = false) {
|
|
2148
1626
|
if (signal.aborted) _LedgerAdapter._throwIfAborted(signal);
|
|
2149
|
-
this.
|
|
2150
|
-
if (this._isBleConnection() && !connectId && !allowUsbEphemeralFallback) {
|
|
1627
|
+
if (isLedgerBleConnectionType(this.connector.connectionType) && !connectId) {
|
|
2151
1628
|
throw Object.assign(new Error("Ledger BLE connectId is required."), {
|
|
2152
1629
|
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
|
|
2153
1630
|
});
|
|
2154
1631
|
}
|
|
2155
1632
|
if (connectId && this._sessions.has(connectId)) return connectId;
|
|
2156
1633
|
if (!connectId && this._sessions.size > 0) {
|
|
2157
|
-
if (!this.
|
|
1634
|
+
if (!isLedgerBleConnectionType(this.connector.connectionType) && this._sessions.size > 1) {
|
|
2158
1635
|
throw Object.assign(
|
|
2159
1636
|
new Error(
|
|
2160
1637
|
"Ledger USB session invariant violated: more than one session is active. Please reconnect the device."
|
|
@@ -2164,24 +1641,15 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2164
1641
|
}
|
|
2165
1642
|
return this._sessions.keys().next().value;
|
|
2166
1643
|
}
|
|
2167
|
-
if (!this._connectingPromise
|
|
2168
|
-
|
|
2169
|
-
this._doConnectAbortController
|
|
2170
|
-
const innerSignal = controller.signal;
|
|
1644
|
+
if (!this._connectingPromise) {
|
|
1645
|
+
this._doConnectAbortController = new AbortController();
|
|
1646
|
+
const innerSignal = this._doConnectAbortController.signal;
|
|
2171
1647
|
this._connectingPromise = (async () => {
|
|
2172
1648
|
try {
|
|
2173
|
-
return await this._doConnect(
|
|
2174
|
-
innerSignal,
|
|
2175
|
-
connectId,
|
|
2176
|
-
allowUsbEphemeralFallback,
|
|
2177
|
-
preserveOperationId,
|
|
2178
|
-
context
|
|
2179
|
-
);
|
|
1649
|
+
return await this._doConnect(innerSignal, connectId, allowUsbEphemeralFallback);
|
|
2180
1650
|
} finally {
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
this._doConnectAbortController = null;
|
|
2184
|
-
}
|
|
1651
|
+
this._connectingPromise = null;
|
|
1652
|
+
this._doConnectAbortController = null;
|
|
2185
1653
|
}
|
|
2186
1654
|
})();
|
|
2187
1655
|
}
|
|
@@ -2190,51 +1658,22 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2190
1658
|
// Layer 1 main loop — the ONLY place in SDK that emits unlock dialog.
|
|
2191
1659
|
// Bounded by MAX_DOCONNECT_CONFIRMS — after N Confirms with no progress,
|
|
2192
1660
|
// throw DeviceNotFound so the user is kicked out of the loop.
|
|
2193
|
-
async _doConnect(internalSignal, targetConnectId, allowUsbEphemeralFallback = false
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
)
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
preserveOperationId,
|
|
2209
|
-
context,
|
|
2210
|
-
internalSignal
|
|
2211
|
-
);
|
|
2212
|
-
}
|
|
2213
|
-
this._activeConnectionType = "ble";
|
|
2214
|
-
const knownBle = context?.knownConnections?.find(
|
|
2215
|
-
(connection) => connection.transport === "ble"
|
|
2216
|
-
);
|
|
2217
|
-
if (knownBle?.transport === "ble") {
|
|
2218
|
-
return this._connectDeviceOrThrow(knownBle.connectId, preserveOperationId, internalSignal);
|
|
2219
|
-
}
|
|
2220
|
-
if (targetConnectId && context?.knownConnections === void 0) {
|
|
2221
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2222
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound,
|
|
2223
|
-
message: "Ledger connection metadata is required before starting Bluetooth binding"
|
|
2224
|
-
});
|
|
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
|
+
}
|
|
2225
1676
|
}
|
|
2226
|
-
const bleDevices = await this._searchDevices({ transportType: "ble" }, internalSignal);
|
|
2227
|
-
return this._connectFirstOrSelect(
|
|
2228
|
-
bleDevices,
|
|
2229
|
-
void 0,
|
|
2230
|
-
allowUsbEphemeralFallback,
|
|
2231
|
-
preserveOperationId,
|
|
2232
|
-
context,
|
|
2233
|
-
internalSignal
|
|
2234
|
-
);
|
|
2235
|
-
}
|
|
2236
|
-
if (this._isBleConnection() && targetConnectId) {
|
|
2237
|
-
return this._connectDeviceOrThrow(targetConnectId, preserveOperationId, internalSignal);
|
|
2238
1677
|
}
|
|
2239
1678
|
let confirms = 0;
|
|
2240
1679
|
while (!internalSignal.aborted) {
|
|
@@ -2242,28 +1681,22 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2242
1681
|
type: import_hwk_adapter_core3.EConnectorInteraction.Searching,
|
|
2243
1682
|
payload: { sessionId: "" }
|
|
2244
1683
|
});
|
|
2245
|
-
let devices = await this.
|
|
2246
|
-
_LedgerAdapter._throwIfAborted(internalSignal);
|
|
1684
|
+
let devices = await this.searchDevices();
|
|
2247
1685
|
if (devices.length === 0) {
|
|
2248
1686
|
for (let i = 0; i < 3 && !internalSignal.aborted; i += 1) {
|
|
2249
1687
|
await new Promise((resolve) => {
|
|
2250
1688
|
setTimeout(resolve, import_hwk_adapter_core3.DEVICE_CONNECT_RETRY_DELAY_MS);
|
|
2251
1689
|
});
|
|
2252
|
-
|
|
2253
|
-
devices = await this._searchDevices(void 0, internalSignal);
|
|
2254
|
-
_LedgerAdapter._throwIfAborted(internalSignal);
|
|
1690
|
+
devices = await this.searchDevices();
|
|
2255
1691
|
if (devices.length > 0) break;
|
|
2256
1692
|
}
|
|
2257
1693
|
}
|
|
2258
|
-
if (devices.length > 0
|
|
1694
|
+
if (devices.length > 0) {
|
|
2259
1695
|
try {
|
|
2260
1696
|
return await this._connectFirstOrSelect(
|
|
2261
1697
|
devices,
|
|
2262
1698
|
targetConnectId,
|
|
2263
|
-
allowUsbEphemeralFallback
|
|
2264
|
-
preserveOperationId,
|
|
2265
|
-
context,
|
|
2266
|
-
internalSignal
|
|
1699
|
+
allowUsbEphemeralFallback
|
|
2267
1700
|
);
|
|
2268
1701
|
} catch (err) {
|
|
2269
1702
|
if (!isDeviceLockedError(err) && !isDeviceNotAdvertisingError(err) && !isDeviceDisconnectedError(err)) {
|
|
@@ -2292,133 +1725,45 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2292
1725
|
_LedgerAdapter._throwIfAborted(internalSignal);
|
|
2293
1726
|
throw new Error("_doConnect aborted");
|
|
2294
1727
|
}
|
|
2295
|
-
async _connectFirstOrSelect(devices, targetConnectId, allowUsbEphemeralFallback
|
|
2296
|
-
_LedgerAdapter._throwIfAborted(signal);
|
|
1728
|
+
async _connectFirstOrSelect(devices, targetConnectId, allowUsbEphemeralFallback = false) {
|
|
2297
1729
|
if (targetConnectId) {
|
|
2298
1730
|
const target = devices.find(
|
|
2299
1731
|
(d) => d.connectId === targetConnectId || d.deviceId === targetConnectId
|
|
2300
1732
|
);
|
|
2301
1733
|
if (target) {
|
|
2302
|
-
return this._connectDeviceOrThrow(target.connectId
|
|
1734
|
+
return this._connectDeviceOrThrow(target.connectId);
|
|
2303
1735
|
}
|
|
2304
|
-
if (!this.
|
|
1736
|
+
if (!isLedgerBleConnectionType(this.connector.connectionType) && devices.length === 1 && allowUsbEphemeralFallback) {
|
|
2305
1737
|
debugLog(
|
|
2306
1738
|
`[LedgerAdapter] target ${targetConnectId} not in fresh enumeration; accepting sole USB device ${devices[0].connectId} for fingerprint-verified recovery`
|
|
2307
1739
|
);
|
|
2308
|
-
return this._connectDeviceOrThrow(devices[0].connectId
|
|
1740
|
+
return this._connectDeviceOrThrow(devices[0].connectId);
|
|
2309
1741
|
}
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
err._tag = ERROR_TAG.DeviceNotAdvertising;
|
|
2316
|
-
}
|
|
2317
|
-
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;
|
|
2318
1747
|
}
|
|
1748
|
+
throw err;
|
|
2319
1749
|
}
|
|
2320
|
-
|
|
2321
|
-
if (requiresBleSelection && !allowUsbEphemeralFallback) {
|
|
1750
|
+
if (isLedgerBleConnectionType(this.connector.connectionType)) {
|
|
2322
1751
|
throw Object.assign(new Error("Ledger BLE connectId is required."), {
|
|
2323
1752
|
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
|
|
2324
1753
|
});
|
|
2325
1754
|
}
|
|
2326
|
-
if (
|
|
2327
|
-
|
|
2328
|
-
if (context) context.bindingSessionId = bindingSessionId;
|
|
2329
|
-
const allowUsbFallback = context?.bindingReason !== "manual-rebind" && Boolean(this.connector.availableTransports?.includes("usb"));
|
|
2330
|
-
const knownUsb = context?.knownConnections?.find(
|
|
2331
|
-
(connection) => connection.transport === "usb"
|
|
2332
|
-
);
|
|
2333
|
-
const usbConnectId = knownUsb?.transport === "usb" ? knownUsb.connectId : targetConnectId;
|
|
2334
|
-
const { device, requestId } = await (0, import_hwk_adapter_core3.requestBleDeviceSelection)({
|
|
2335
|
-
emitter: this.emitter,
|
|
2336
|
-
registry: this._uiRegistry,
|
|
2337
|
-
signal,
|
|
2338
|
-
allowUsbFallback,
|
|
2339
|
-
scan: async () => {
|
|
2340
|
-
if (allowUsbFallback) {
|
|
2341
|
-
const usbDevices = await this._searchDevices({ transportType: "usb" }, signal);
|
|
2342
|
-
const candidate = usbDevices.find(
|
|
2343
|
-
(device2) => device2.connectionType === "usb" && device2.connectId === usbConnectId
|
|
2344
|
-
) ?? (usbDevices.length === 1 && usbDevices[0].connectionType === "usb" ? usbDevices[0] : void 0);
|
|
2345
|
-
if (candidate) return [candidate];
|
|
2346
|
-
}
|
|
2347
|
-
return (await this._searchDevices({ transportType: "ble", waitForAllTransports: true }, signal)).filter((device2) => !context?.rejectedConnectIds?.has(device2.connectId));
|
|
2348
|
-
},
|
|
2349
|
-
request: {
|
|
2350
|
-
devices: devices.filter((device2) => !context?.rejectedConnectIds?.has(device2.connectId)),
|
|
2351
|
-
bindingSessionId,
|
|
2352
|
-
rejectedConnectId: context?.rejectedConnectId,
|
|
2353
|
-
context: {
|
|
2354
|
-
kind: "bind-connection",
|
|
2355
|
-
transport: "ble",
|
|
2356
|
-
reason: context?.bindingReason ?? (targetConnectId ? "known-connection-unavailable" : "missing-binding")
|
|
2357
|
-
},
|
|
2358
|
-
extra: context?.extra
|
|
2359
|
-
}
|
|
2360
|
-
});
|
|
2361
|
-
if (device.connectionType === "usb") {
|
|
2362
|
-
this._activeConnectionType = "usb";
|
|
2363
|
-
if (context) context.selectedConnection = void 0;
|
|
2364
|
-
if (preserveOperationId) this._pendingOperationBindings.delete(preserveOperationId);
|
|
2365
|
-
this._bindingSelectionRequestId = void 0;
|
|
2366
|
-
this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.DEVICE_BINDING_STATUS, {
|
|
2367
|
-
type: import_hwk_adapter_core3.UI_REQUEST.DEVICE_BINDING_STATUS,
|
|
2368
|
-
payload: { selectionRequestId: requestId, status: "cancelled" }
|
|
2369
|
-
});
|
|
2370
|
-
return this._connectDeviceOrThrow(device.connectId, preserveOperationId, signal);
|
|
2371
|
-
}
|
|
2372
|
-
if (context) context.selectedConnection = { connectId: device.connectId, requestId };
|
|
2373
|
-
this._bindingSelectionRequestId = requestId;
|
|
2374
|
-
return this._connectDeviceOrThrow(device.connectId, preserveOperationId, signal);
|
|
2375
|
-
}
|
|
2376
|
-
if (devices.length > 0 && (devices.length > 1 || requiresBleSelection)) {
|
|
2377
|
-
if (context?.allowDeviceSelection === false || !this.emitter.listenerCount(import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE)) {
|
|
2378
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2379
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound,
|
|
2380
|
-
message: "Select a Ledger device before continuing"
|
|
2381
|
-
});
|
|
2382
|
-
}
|
|
2383
|
-
const requestId = this._uiRegistry.createRequestId();
|
|
2384
|
-
const waitPromise = this._uiRegistry.wait(
|
|
2385
|
-
import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE,
|
|
2386
|
-
{ requestId }
|
|
2387
|
-
);
|
|
2388
|
-
this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE, {
|
|
2389
|
-
type: import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE,
|
|
2390
|
-
payload: {
|
|
2391
|
-
devices,
|
|
2392
|
-
requestId,
|
|
2393
|
-
context: requiresBleSelection ? {
|
|
2394
|
-
kind: "bind-connection",
|
|
2395
|
-
transport: "ble",
|
|
2396
|
-
reason: targetConnectId ? "known-connection-unavailable" : "missing-binding"
|
|
2397
|
-
} : { kind: "select-device", transport: "usb", reason: "multiple-candidates" },
|
|
2398
|
-
extra: context?.extra
|
|
2399
|
-
}
|
|
2400
|
-
});
|
|
2401
|
-
const { sdkConnectId } = await (signal ? this._abortable(signal, waitPromise) : waitPromise);
|
|
2402
|
-
if (signal) _LedgerAdapter._throwIfAborted(signal);
|
|
2403
|
-
const selected = devices.find((device) => device.connectId === sdkConnectId);
|
|
2404
|
-
if (!selected) {
|
|
2405
|
-
throw Object.assign(new Error("Selected Ledger is no longer available"), {
|
|
2406
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
|
|
2407
|
-
});
|
|
2408
|
-
}
|
|
2409
|
-
if (context && requiresBleSelection)
|
|
2410
|
-
context.selectedConnection = { connectId: selected.connectId, requestId };
|
|
2411
|
-
return this._connectDeviceOrThrow(selected.connectId, preserveOperationId, signal);
|
|
1755
|
+
if (devices.length > 1) {
|
|
1756
|
+
throw createMultipleUsbLedgerDevicesError();
|
|
2412
1757
|
}
|
|
2413
1758
|
if (devices.length !== 1) {
|
|
2414
1759
|
throw Object.assign(new Error("Ledger device not found."), {
|
|
2415
1760
|
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
|
|
2416
1761
|
});
|
|
2417
1762
|
}
|
|
2418
|
-
return this._connectDeviceOrThrow(devices[0].connectId
|
|
1763
|
+
return this._connectDeviceOrThrow(devices[0].connectId);
|
|
2419
1764
|
}
|
|
2420
|
-
async _connectDeviceOrThrow(chosenConnectId
|
|
2421
|
-
const result = await this.
|
|
1765
|
+
async _connectDeviceOrThrow(chosenConnectId) {
|
|
1766
|
+
const result = await this.connectDevice(chosenConnectId);
|
|
2422
1767
|
if (!result.success) {
|
|
2423
1768
|
const payload = result.payload;
|
|
2424
1769
|
const rethrow = Object.assign(new Error(payload.error), {
|
|
@@ -2429,7 +1774,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2429
1774
|
}
|
|
2430
1775
|
throw rethrow;
|
|
2431
1776
|
}
|
|
2432
|
-
return
|
|
1777
|
+
return chosenConnectId;
|
|
2433
1778
|
}
|
|
2434
1779
|
/**
|
|
2435
1780
|
* Call the connector with automatic session resolution and disconnect retry.
|
|
@@ -2459,122 +1804,26 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2459
1804
|
* lives in one place.
|
|
2460
1805
|
*/
|
|
2461
1806
|
async _callConnector(sessionId, method, params, signal) {
|
|
2462
|
-
this.
|
|
2463
|
-
if (signal?.aborted) throw this._abortReason(signal);
|
|
2464
|
-
const releaseOperation = this._retainConnectorOperation(`call:${sessionId}`);
|
|
2465
|
-
let promise;
|
|
2466
|
-
try {
|
|
2467
|
-
promise = this.connector.call(sessionId, method, params).finally(releaseOperation);
|
|
2468
|
-
} catch (error) {
|
|
2469
|
-
releaseOperation();
|
|
2470
|
-
throw error;
|
|
2471
|
-
}
|
|
1807
|
+
const promise = this.connector.call(sessionId, method, params);
|
|
2472
1808
|
const result = signal ? await this._abortable(signal, promise) : await promise;
|
|
2473
1809
|
return this._unwrapConnectorResult(result);
|
|
2474
1810
|
}
|
|
2475
|
-
_assertConnectorReady(method) {
|
|
2476
|
-
if (this._resetPromise || this._pendingConnectorTeardowns > 0 || this._unsettledConnectorOperations.size > 0) {
|
|
2477
|
-
throw _LedgerAdapter._createDeviceBusyError(method);
|
|
2478
|
-
}
|
|
2479
|
-
}
|
|
2480
|
-
_runConnectorTeardown(task) {
|
|
2481
|
-
const previous = this._connectorTeardownTail;
|
|
2482
|
-
let releaseTail = () => void 0;
|
|
2483
|
-
this._connectorTeardownTail = new Promise((resolve) => {
|
|
2484
|
-
releaseTail = resolve;
|
|
2485
|
-
});
|
|
2486
|
-
this._pendingConnectorTeardowns += 1;
|
|
2487
|
-
return (async () => {
|
|
2488
|
-
try {
|
|
2489
|
-
await previous;
|
|
2490
|
-
await this._waitForConnectorOperationsToDrain();
|
|
2491
|
-
await task();
|
|
2492
|
-
} finally {
|
|
2493
|
-
this._pendingConnectorTeardowns -= 1;
|
|
2494
|
-
releaseTail();
|
|
2495
|
-
}
|
|
2496
|
-
})();
|
|
2497
|
-
}
|
|
2498
|
-
_waitForConnectorOperationsToDrain() {
|
|
2499
|
-
if (this._unsettledConnectorOperations.size === 0) {
|
|
2500
|
-
return Promise.resolve();
|
|
2501
|
-
}
|
|
2502
|
-
return new Promise((resolve) => {
|
|
2503
|
-
this._connectorIdleWaiters.add(resolve);
|
|
2504
|
-
});
|
|
2505
|
-
}
|
|
2506
|
-
_retainConnectorOperation(key) {
|
|
2507
|
-
this._unsettledConnectorOperations.set(
|
|
2508
|
-
key,
|
|
2509
|
-
(this._unsettledConnectorOperations.get(key) ?? 0) + 1
|
|
2510
|
-
);
|
|
2511
|
-
let released = false;
|
|
2512
|
-
return () => {
|
|
2513
|
-
if (released) return;
|
|
2514
|
-
released = true;
|
|
2515
|
-
const remaining = (this._unsettledConnectorOperations.get(key) ?? 1) - 1;
|
|
2516
|
-
if (remaining > 0) {
|
|
2517
|
-
this._unsettledConnectorOperations.set(key, remaining);
|
|
2518
|
-
} else {
|
|
2519
|
-
this._unsettledConnectorOperations.delete(key);
|
|
2520
|
-
}
|
|
2521
|
-
if (this._unsettledConnectorOperations.size === 0) {
|
|
2522
|
-
for (const resolve of this._connectorIdleWaiters) resolve();
|
|
2523
|
-
this._connectorIdleWaiters.clear();
|
|
2524
|
-
}
|
|
2525
|
-
};
|
|
2526
|
-
}
|
|
2527
1811
|
async connectorCall(connectId, method, params, fingerprint, permissionDeviceId, commonParams, installContext) {
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2531
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.InvalidParams,
|
|
2532
|
-
message: "Conflicting Ledger operation ids",
|
|
2533
|
-
params: {
|
|
2534
|
-
positionalOperationId,
|
|
2535
|
-
commonOperationId: commonParams.operationId
|
|
2536
|
-
}
|
|
2537
|
-
});
|
|
2538
|
-
}
|
|
2539
|
-
const operationId = commonParams?.operationId ?? positionalOperationId;
|
|
2540
|
-
const operation = operationId ? this._operations.resolve(operationId) : void 0;
|
|
2541
|
-
const releaseOperationRetention = operationId ? this._operations.retain(operationId) : void 0;
|
|
2542
|
-
const effectiveConnectId = operation?.connectId ?? connectId;
|
|
2543
|
-
debugLog("[LedgerAdapter][REQ]", {
|
|
2544
|
-
method,
|
|
2545
|
-
connectId: effectiveConnectId || "(empty)",
|
|
2546
|
-
params
|
|
2547
|
-
});
|
|
2548
|
-
const queueKey = (operationId ?? effectiveConnectId) || "__ledger_default__";
|
|
1812
|
+
debugLog("[LedgerAdapter][REQ]", { method, connectId: connectId || "(empty)", params });
|
|
1813
|
+
const queueKey = connectId || "__ledger_default__";
|
|
2549
1814
|
try {
|
|
2550
1815
|
const result = await this._jobQueue.enqueue(
|
|
2551
1816
|
queueKey,
|
|
2552
|
-
async (signal) =>
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
commonParams,
|
|
2563
|
-
installContext ?? {},
|
|
2564
|
-
operationId
|
|
2565
|
-
);
|
|
2566
|
-
} catch (error) {
|
|
2567
|
-
this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
|
|
2568
|
-
throw error;
|
|
2569
|
-
} finally {
|
|
2570
|
-
if (operationId) {
|
|
2571
|
-
this._activeOperationJobs.delete(operationId);
|
|
2572
|
-
if (this._pendingOperationDisconnects.delete(operationId)) {
|
|
2573
|
-
await this._releaseLostOperationConnection(operationId);
|
|
2574
|
-
}
|
|
2575
|
-
}
|
|
2576
|
-
}
|
|
2577
|
-
},
|
|
1817
|
+
async (signal) => this._runConnectorCall(
|
|
1818
|
+
connectId,
|
|
1819
|
+
method,
|
|
1820
|
+
params,
|
|
1821
|
+
signal,
|
|
1822
|
+
fingerprint,
|
|
1823
|
+
permissionDeviceId,
|
|
1824
|
+
commonParams,
|
|
1825
|
+
installContext
|
|
1826
|
+
),
|
|
2578
1827
|
{
|
|
2579
1828
|
label: method,
|
|
2580
1829
|
rejectIfBusy: true,
|
|
@@ -2595,22 +1844,15 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2595
1844
|
}
|
|
2596
1845
|
});
|
|
2597
1846
|
throw err;
|
|
2598
|
-
} finally {
|
|
2599
|
-
releaseOperationRetention?.();
|
|
2600
1847
|
}
|
|
2601
1848
|
}
|
|
2602
1849
|
/**
|
|
2603
1850
|
* Race a promise against an abort signal. On abort, rejects with
|
|
2604
1851
|
* signal.reason → instance _lastCancelReason → generic Error('Aborted').
|
|
2605
1852
|
*/
|
|
2606
|
-
/** Hermes/RN polyfills don't always populate signal.reason; fall back. */
|
|
2607
|
-
_abortReason(signal) {
|
|
2608
|
-
return signal.reason ?? this._lastCancelReason ?? new Error("Aborted");
|
|
2609
|
-
}
|
|
2610
1853
|
_abortable(signal, promise) {
|
|
2611
|
-
const getAbortReason = () => this.
|
|
1854
|
+
const getAbortReason = () => signal.reason ?? this._lastCancelReason ?? new Error("Aborted");
|
|
2612
1855
|
if (signal.aborted) {
|
|
2613
|
-
void promise.catch(() => void 0);
|
|
2614
1856
|
return Promise.reject(getAbortReason());
|
|
2615
1857
|
}
|
|
2616
1858
|
return new Promise((resolve, reject) => {
|
|
@@ -2637,15 +1879,13 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2637
1879
|
}
|
|
2638
1880
|
}
|
|
2639
1881
|
/** Actual work done under the job queue — connection, fingerprint, call, and recovery. */
|
|
2640
|
-
async _runConnectorCall(connectId, method, params, signal, fingerprint, permissionDeviceId, commonParams, installContext
|
|
1882
|
+
async _runConnectorCall(connectId, method, params, signal, fingerprint, permissionDeviceId, commonParams, installContext) {
|
|
2641
1883
|
_LedgerAdapter._throwIfAborted(signal);
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
);
|
|
2648
|
-
}
|
|
1884
|
+
await this._ensureDevicePermission(
|
|
1885
|
+
connectId,
|
|
1886
|
+
permissionDeviceId ?? fingerprint?.deviceId,
|
|
1887
|
+
signal
|
|
1888
|
+
);
|
|
2649
1889
|
_LedgerAdapter._throwIfAborted(signal);
|
|
2650
1890
|
let effectiveParams = params;
|
|
2651
1891
|
if (method === "btcGetPublicKey") {
|
|
@@ -2659,132 +1899,36 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2659
1899
|
effectiveParams = gatedParams;
|
|
2660
1900
|
}
|
|
2661
1901
|
const allowUsbEphemeralFallback = !!fingerprint?.deviceId && !fingerprint.skipFingerprint;
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
const knownTransport = this._isBleConnection() ? "ble" : "usb";
|
|
2665
|
-
const hintedConnectId = commonParams?.knownConnections?.find(
|
|
2666
|
-
(connection) => connection.transport === knownTransport
|
|
2667
|
-
);
|
|
2668
|
-
const inputConnectId = hintedConnectId && hintedConnectId.transport !== "qr" ? hintedConnectId.connectId : connectId;
|
|
2669
|
-
const preferredConnectId = fingerprint && !fingerprint.skipFingerprint && verifiedBleTarget?.chain === fingerprint.chain && verifiedBleTarget.fingerprint === fingerprint.deviceId ? verifiedBleTarget.connectId : inputConnectId;
|
|
2670
|
-
const connectionAttempt = { ...commonParams };
|
|
2671
|
-
const bundleConnection = installContext?.connection;
|
|
2672
|
-
if (bundleConnection && this._sessions.get(bundleConnection.connectId) !== bundleConnection.sessionId) {
|
|
2673
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2674
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
|
|
2675
|
-
message: "Ledger all-network connection ended"
|
|
2676
|
-
});
|
|
2677
|
-
}
|
|
2678
|
-
let resolvedConnectId = operationId ? this._operations.resolve(operationId).connectId : bundleConnection?.connectId ?? await this.ensureConnected(
|
|
2679
|
-
preferredConnectId,
|
|
1902
|
+
const resolvedConnectId = await this.ensureConnected(
|
|
1903
|
+
connectId,
|
|
2680
1904
|
signal,
|
|
2681
|
-
allowUsbEphemeralFallback
|
|
2682
|
-
void 0,
|
|
2683
|
-
connectionAttempt
|
|
1905
|
+
allowUsbEphemeralFallback
|
|
2684
1906
|
);
|
|
2685
|
-
|
|
2686
|
-
if (sessionId && installContext && !installContext.connection) {
|
|
2687
|
-
installContext.connection = { connectId: resolvedConnectId, sessionId };
|
|
2688
|
-
}
|
|
1907
|
+
const sessionId = this._sessions.get(resolvedConnectId);
|
|
2689
1908
|
if (!sessionId) {
|
|
2690
|
-
if (operationId) {
|
|
2691
|
-
this._operations.end(operationId, "disconnect");
|
|
2692
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2693
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.OperationEnded,
|
|
2694
|
-
message: "Ledger operation connection is no longer active",
|
|
2695
|
-
params: { operationId, reason: "disconnect" }
|
|
2696
|
-
});
|
|
2697
|
-
}
|
|
2698
1909
|
throw Object.assign(new Error("Auto-connect succeeded but no session found"), {
|
|
2699
1910
|
_tag: ERROR_TAG.DeviceSessionNotFound
|
|
2700
1911
|
});
|
|
2701
1912
|
}
|
|
2702
1913
|
try {
|
|
2703
1914
|
if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId) {
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
)
|
|
2712
|
-
);
|
|
2713
|
-
if (fp.success) break;
|
|
2714
|
-
const binding = operationId ? this._pendingOperationBindings.get(operationId) : connectionAttempt;
|
|
2715
|
-
if (!this._isBleConnection() || binding?.selectedConnection?.connectId !== resolvedConnectId) {
|
|
2716
|
-
throw Object.assign(new Error(formatDeviceMismatchError(fp.expected, fp.actual)), {
|
|
2717
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch
|
|
2718
|
-
});
|
|
2719
|
-
}
|
|
2720
|
-
binding.rejectedConnectIds ?? (binding.rejectedConnectIds = /* @__PURE__ */ new Set());
|
|
2721
|
-
binding.rejectedConnectIds.add(resolvedConnectId);
|
|
2722
|
-
binding.rejectedConnectId = resolvedConnectId;
|
|
2723
|
-
this._sessions.delete(resolvedConnectId);
|
|
2724
|
-
await this.connector.disconnect(sessionId);
|
|
2725
|
-
if (operationId) this._pendingOperationDisconnects.delete(operationId);
|
|
2726
|
-
_LedgerAdapter._throwIfAborted(signal);
|
|
2727
|
-
resolvedConnectId = await this._connectFirstOrSelect(
|
|
2728
|
-
[],
|
|
2729
|
-
void 0,
|
|
2730
|
-
true,
|
|
2731
|
-
operationId,
|
|
2732
|
-
binding,
|
|
2733
|
-
signal
|
|
2734
|
-
);
|
|
2735
|
-
const selectedSession = this._sessions.get(resolvedConnectId);
|
|
2736
|
-
const selectedDevice = this._discoveredDevices.get(resolvedConnectId);
|
|
2737
|
-
if (!selectedSession || !selectedDevice)
|
|
2738
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2739
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
|
|
2740
|
-
message: "Selected Ledger connection ended"
|
|
2741
|
-
});
|
|
2742
|
-
sessionId = selectedSession;
|
|
2743
|
-
if (operationId)
|
|
2744
|
-
this._operations.rebind(operationId, {
|
|
2745
|
-
connectId: resolvedConnectId,
|
|
2746
|
-
device: selectedDevice,
|
|
2747
|
-
connectionKeys: [sessionId]
|
|
2748
|
-
});
|
|
2749
|
-
if (installContext)
|
|
2750
|
-
installContext.connection = { connectId: resolvedConnectId, sessionId };
|
|
2751
|
-
}
|
|
2752
|
-
await this._publishVerifiedBleBinding(
|
|
2753
|
-
resolvedConnectId,
|
|
2754
|
-
fingerprint.chain,
|
|
2755
|
-
fingerprint.deviceId,
|
|
2756
|
-
connectionAttempt,
|
|
2757
|
-
operationId,
|
|
2758
|
-
signal
|
|
1915
|
+
const fp = await this._abortable(
|
|
1916
|
+
signal,
|
|
1917
|
+
this._verifyDeviceFingerprintWithSession(
|
|
1918
|
+
sessionId,
|
|
1919
|
+
fingerprint.deviceId,
|
|
1920
|
+
fingerprint.chain
|
|
1921
|
+
)
|
|
2759
1922
|
);
|
|
2760
|
-
if (!
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
chain: fingerprint.chain,
|
|
2764
|
-
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
|
|
2765
1926
|
});
|
|
2766
1927
|
}
|
|
2767
1928
|
}
|
|
2768
|
-
businessCallStarted = true;
|
|
2769
1929
|
return await this._callConnector(sessionId, method, effectiveParams, signal);
|
|
2770
1930
|
} catch (err) {
|
|
2771
1931
|
if (signal.aborted) throw err;
|
|
2772
|
-
if (isDeviceDisconnectedError(err) || isDeviceNotAdvertisingError(err) || isTimeoutError(err) || isConnectionLevelError(err)) {
|
|
2773
|
-
this._discoveredDevices.delete(resolvedConnectId);
|
|
2774
|
-
if (operationId) await this._releaseLostOperationConnection(operationId);
|
|
2775
|
-
else {
|
|
2776
|
-
this._sessions.delete(resolvedConnectId);
|
|
2777
|
-
await this.connector.disconnect(sessionId).catch(() => void 0);
|
|
2778
|
-
}
|
|
2779
|
-
const ambiguous = businessCallStarted && !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method);
|
|
2780
|
-
const interactionParams = operationId ? { operationId, reason: "disconnect" } : void 0;
|
|
2781
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2782
|
-
code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : mapLedgerError(err).code,
|
|
2783
|
-
message: "Ledger operation connection was lost; start a new operation",
|
|
2784
|
-
params: ambiguous ? (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(method, { operationId }) : interactionParams,
|
|
2785
|
-
recovery: ambiguous ? { scope: "unknown" } : void 0
|
|
2786
|
-
});
|
|
2787
|
-
}
|
|
2788
1932
|
const errObj = err;
|
|
2789
1933
|
debugLog("[LedgerAdapter] connectorCall error:", method, {
|
|
2790
1934
|
message: errObj?.message,
|
|
@@ -2796,65 +1940,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2796
1940
|
isNotAdvertising: isDeviceNotAdvertisingError(err),
|
|
2797
1941
|
isStuckApp: isStuckAppStateError(err)
|
|
2798
1942
|
});
|
|
2799
|
-
if ((isDeviceLockedError(err) || errObj?.code === import_hwk_adapter_core3.HardwareErrorCode.DeviceLocked) && lockedRetryBudget > 0) {
|
|
2800
|
-
await this._waitForDeviceConnect(signal);
|
|
2801
|
-
if (this._sessions.get(resolvedConnectId) !== sessionId) {
|
|
2802
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2803
|
-
code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
|
|
2804
|
-
message: "Ledger connection ended while waiting for unlock"
|
|
2805
|
-
});
|
|
2806
|
-
}
|
|
2807
|
-
return this._runConnectorCall(
|
|
2808
|
-
resolvedConnectId,
|
|
2809
|
-
method,
|
|
2810
|
-
effectiveParams,
|
|
2811
|
-
signal,
|
|
2812
|
-
fingerprint,
|
|
2813
|
-
permissionDeviceId,
|
|
2814
|
-
commonParams,
|
|
2815
|
-
installContext,
|
|
2816
|
-
operationId,
|
|
2817
|
-
lockedRetryBudget - 1
|
|
2818
|
-
);
|
|
2819
|
-
}
|
|
2820
|
-
if (businessCallStarted && isStuckAppStateError(err)) {
|
|
2821
|
-
await this._sleepAbortable(_LedgerAdapter.STUCK_APP_RETRY_DELAY_MS, signal);
|
|
2822
|
-
if (this._sessions.get(resolvedConnectId) !== sessionId) {
|
|
2823
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2824
|
-
code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
|
|
2825
|
-
message: "Ledger connection ended during the app transition"
|
|
2826
|
-
});
|
|
2827
|
-
}
|
|
2828
|
-
try {
|
|
2829
|
-
return await this._callConnector(sessionId, method, effectiveParams, signal);
|
|
2830
|
-
} catch (retryErr) {
|
|
2831
|
-
if (isStuckAppStateError(retryErr)) throw err;
|
|
2832
|
-
if (isDeviceDisconnectedError(retryErr) || isDeviceNotAdvertisingError(retryErr) || isTimeoutError(retryErr) || isConnectionLevelError(retryErr)) {
|
|
2833
|
-
if (operationId) await this._releaseLostOperationConnection(operationId);
|
|
2834
|
-
else {
|
|
2835
|
-
this._sessions.delete(resolvedConnectId);
|
|
2836
|
-
this._discoveredDevices.delete(resolvedConnectId);
|
|
2837
|
-
await this.connector.disconnect(sessionId).catch(() => void 0);
|
|
2838
|
-
}
|
|
2839
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2840
|
-
code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : mapLedgerError(retryErr).code,
|
|
2841
|
-
message: `Ledger ${method} may have completed before the connection was lost`,
|
|
2842
|
-
params: !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method) ? (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(method, {
|
|
2843
|
-
operationId,
|
|
2844
|
-
reason: "disconnect"
|
|
2845
|
-
}) : { operationId, reason: "disconnect" },
|
|
2846
|
-
recovery: !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method) ? { scope: "unknown" } : void 0
|
|
2847
|
-
});
|
|
2848
|
-
}
|
|
2849
|
-
throw retryErr;
|
|
2850
|
-
}
|
|
2851
|
-
}
|
|
2852
|
-
if (!operationId && err?.code === import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch) {
|
|
2853
|
-
this._sessions.delete(resolvedConnectId);
|
|
2854
|
-
this._discoveredDevices.delete(resolvedConnectId);
|
|
2855
|
-
await this.connector.disconnect(sessionId).catch(() => void 0);
|
|
2856
|
-
throw err;
|
|
2857
|
-
}
|
|
2858
1943
|
const autoInstallApp = commonParams?.autoInstallApp ?? this._defaultAutoInstallApp;
|
|
2859
1944
|
const isAppMissing = isAppNotInstalledError(err) || err?.code === import_hwk_adapter_core3.HardwareErrorCode.AppNotInstalled;
|
|
2860
1945
|
if (autoInstallApp && isAppMissing) {
|
|
@@ -2910,14 +1995,157 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2910
1995
|
fingerprint,
|
|
2911
1996
|
permissionDeviceId,
|
|
2912
1997
|
commonParams,
|
|
2913
|
-
installContext
|
|
2914
|
-
|
|
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
|
|
2915
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
|
|
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
|
+
}
|
|
2916
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
|
+
});
|
|
2917
2111
|
}
|
|
2918
2112
|
throw err;
|
|
2919
2113
|
}
|
|
2920
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
|
+
}
|
|
2921
2149
|
_sleepAbortable(ms, signal) {
|
|
2922
2150
|
return new Promise((resolve, reject) => {
|
|
2923
2151
|
if (signal.aborted) {
|
|
@@ -2935,6 +2163,88 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2935
2163
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
2936
2164
|
});
|
|
2937
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
|
+
}
|
|
2938
2248
|
/**
|
|
2939
2249
|
* Ensure OS-level device permission (Bluetooth / USB) before proceeding.
|
|
2940
2250
|
*
|
|
@@ -3004,15 +2314,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
3004
2314
|
if (err && typeof err === "object" && "code" in err && typeof err.code === "number") {
|
|
3005
2315
|
const e = err;
|
|
3006
2316
|
const params = e.code === import_hwk_adapter_core3.HardwareErrorCode.DevicePermissionDenied && e.reason ? { permissionDeniedReason: e.reason } : e.params;
|
|
3007
|
-
return ledgerFailure(
|
|
3008
|
-
e.code,
|
|
3009
|
-
e.message ?? "Unknown error",
|
|
3010
|
-
e.appName,
|
|
3011
|
-
tag,
|
|
3012
|
-
params,
|
|
3013
|
-
void 0,
|
|
3014
|
-
(0, import_hwk_adapter_core3.isHwkRecoveryHint)(e.recovery) ? e.recovery : void 0
|
|
3015
|
-
);
|
|
2317
|
+
return ledgerFailure(e.code, e.message ?? "Unknown error", e.appName, tag, params);
|
|
3016
2318
|
}
|
|
3017
2319
|
const mapped = mapLedgerError(err);
|
|
3018
2320
|
return ledgerFailure(mapped.code, mapped.message, mapped.appName, tag);
|
|
@@ -3039,7 +2341,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
3039
2341
|
deviceId: device.deviceId,
|
|
3040
2342
|
connectId: device.connectId,
|
|
3041
2343
|
label: device.name,
|
|
3042
|
-
connectionType:
|
|
2344
|
+
connectionType: this.connector.connectionType,
|
|
3043
2345
|
rssi: device.rssi,
|
|
3044
2346
|
isConnectable: device.isConnectable,
|
|
3045
2347
|
serialNumber: device.serialNumber,
|
|
@@ -3064,7 +2366,7 @@ _LedgerAdapter.APP_INSTALL_PROGRESS_MIN_DELTA = 0.05;
|
|
|
3064
2366
|
var LedgerAdapter = _LedgerAdapter;
|
|
3065
2367
|
|
|
3066
2368
|
// src/connector/LedgerConnectorBase.ts
|
|
3067
|
-
var
|
|
2369
|
+
var import_hwk_adapter_core13 = require("@onekeyfe/hwk-adapter-core");
|
|
3068
2370
|
|
|
3069
2371
|
// src/device/LedgerDeviceManager.ts
|
|
3070
2372
|
var LedgerDeviceManager = class {
|
|
@@ -3600,7 +2902,7 @@ var SignerManager = class _SignerManager {
|
|
|
3600
2902
|
return (args) => new import_device_signer_kit_ethereum.SignerEthBuilder(args);
|
|
3601
2903
|
}
|
|
3602
2904
|
static _createContextModule() {
|
|
3603
|
-
const contextModule = new import_context_module.ContextModuleBuilder({}).
|
|
2905
|
+
const contextModule = new import_context_module.ContextModuleBuilder({}).removeDefaultLoaders().build();
|
|
3604
2906
|
return _SignerManager.wrapBlindSigningReportNonBlocking(contextModule);
|
|
3605
2907
|
}
|
|
3606
2908
|
static wrapBlindSigningReportNonBlocking(contextModule) {
|
|
@@ -4071,7 +3373,6 @@ function _applySignaturesToPsbt(psbtHex, signatures) {
|
|
|
4071
3373
|
|
|
4072
3374
|
// src/connector/chains/sol.ts
|
|
4073
3375
|
var import_hwk_adapter_core9 = require("@onekeyfe/hwk-adapter-core");
|
|
4074
|
-
var import_bs58 = __toESM(require("bs58"));
|
|
4075
3376
|
|
|
4076
3377
|
// src/signer/SignerSol.ts
|
|
4077
3378
|
var SignerSol = class {
|
|
@@ -4155,21 +3456,8 @@ async function solSignMessage(ctx, sessionId, params) {
|
|
|
4155
3456
|
const path = normalizePath(params.path);
|
|
4156
3457
|
const messageBytes = (0, import_hwk_adapter_core9.hexToBytes)(params.message);
|
|
4157
3458
|
try {
|
|
4158
|
-
if (params.messageVersion === 1) {
|
|
4159
|
-
const preparedMessage = (0, import_hwk_adapter_core9.prepareSolanaOffchainMessageV1)({
|
|
4160
|
-
message: messageBytes,
|
|
4161
|
-
requiredSigners: params.requiredSigners
|
|
4162
|
-
});
|
|
4163
|
-
const { SignMessageVersion } = await ctx.importLedgerKit(
|
|
4164
|
-
"@ledgerhq/device-signer-kit-solana"
|
|
4165
|
-
);
|
|
4166
|
-
const result2 = await solSigner.signMessage(path, preparedMessage.serializedMessage, {
|
|
4167
|
-
version: SignMessageVersion.Raw
|
|
4168
|
-
});
|
|
4169
|
-
return { signature: decodeBase58Signature(result2.signature) };
|
|
4170
|
-
}
|
|
4171
3459
|
const result = await solSigner.signMessage(path, messageBytes);
|
|
4172
|
-
return { signature:
|
|
3460
|
+
return { signature: result.signature };
|
|
4173
3461
|
} catch (err) {
|
|
4174
3462
|
ctx.invalidateSession(sessionId);
|
|
4175
3463
|
throw ctx.wrapError(err);
|
|
@@ -4177,27 +3465,11 @@ async function solSignMessage(ctx, sessionId, params) {
|
|
|
4177
3465
|
ctx.clearCanceller(sessionId);
|
|
4178
3466
|
}
|
|
4179
3467
|
}
|
|
4180
|
-
function decodeBase58Signature(signature) {
|
|
4181
|
-
const bytes = import_bs58.default.decode(signature);
|
|
4182
|
-
if (bytes.length !== 64) {
|
|
4183
|
-
throw new Error(`Ledger Solana signature must be 64 bytes, received ${bytes.length}`);
|
|
4184
|
-
}
|
|
4185
|
-
return (0, import_hwk_adapter_core9.bytesToHex)(bytes);
|
|
4186
|
-
}
|
|
4187
|
-
function decodeBase58EnvelopeSignature(envelope) {
|
|
4188
|
-
const bytes = import_bs58.default.decode(envelope);
|
|
4189
|
-
if (bytes.length < 65 || bytes[0] !== 1) {
|
|
4190
|
-
throw new Error("Ledger Solana signature envelope is invalid");
|
|
4191
|
-
}
|
|
4192
|
-
return (0, import_hwk_adapter_core9.bytesToHex)(bytes.subarray(1, 65));
|
|
4193
|
-
}
|
|
4194
3468
|
async function _createSolSigner(ctx, sessionId) {
|
|
4195
3469
|
const dmk = await ctx.getOrCreateDmk();
|
|
4196
|
-
const { ContextModuleBuilder: ContextModuleBuilder2
|
|
4197
|
-
"@ledgerhq/context-module"
|
|
4198
|
-
);
|
|
3470
|
+
const { ContextModuleBuilder: ContextModuleBuilder2 } = await ctx.importLedgerKit("@ledgerhq/context-module");
|
|
4199
3471
|
const { SignerSolanaBuilder } = await ctx.importLedgerKit("@ledgerhq/device-signer-kit-solana");
|
|
4200
|
-
const contextModule = new ContextModuleBuilder2({}).
|
|
3472
|
+
const contextModule = new ContextModuleBuilder2({}).removeDefaultLoaders().build();
|
|
4201
3473
|
const sdkSigner = new SignerSolanaBuilder({ dmk, sessionId }).withContextModule(contextModule).build();
|
|
4202
3474
|
const signer = new SignerSol(sdkSigner);
|
|
4203
3475
|
signer.onInteraction = (interaction) => {
|
|
@@ -4213,196 +3485,360 @@ async function _createSolSigner(ctx, sessionId) {
|
|
|
4213
3485
|
return signer;
|
|
4214
3486
|
}
|
|
4215
3487
|
|
|
4216
|
-
// src/connector/chains/
|
|
4217
|
-
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"));
|
|
4218
3491
|
|
|
4219
|
-
// src/
|
|
4220
|
-
var
|
|
4221
|
-
// eslint-disable-next-line no-useless-constructor, no-empty-function
|
|
4222
|
-
constructor(_sdk) {
|
|
4223
|
-
this._sdk = _sdk;
|
|
4224
|
-
}
|
|
4225
|
-
/** GET_VK: UFVK string (default) or raw 96-byte Orchard FVK. */
|
|
4226
|
-
async getFullViewingKey(derivationPath, options) {
|
|
4227
|
-
const action = this._sdk.getFullViewingKey(derivationPath, options);
|
|
4228
|
-
return deviceActionToPromise(
|
|
4229
|
-
action,
|
|
4230
|
-
this.onInteraction,
|
|
4231
|
-
void 0,
|
|
4232
|
-
this.onRegisterCanceller
|
|
4233
|
-
);
|
|
4234
|
-
}
|
|
4235
|
-
/** GET_SHIELDED_ADDRESS: single-Orchard-receiver UA for a 5-level transparent path. */
|
|
4236
|
-
async getShieldedAddress(derivationPath, options) {
|
|
4237
|
-
const action = this._sdk.getShieldedAddress(derivationPath, options);
|
|
4238
|
-
return deviceActionToPromise(
|
|
4239
|
-
action,
|
|
4240
|
-
this.onInteraction,
|
|
4241
|
-
void 0,
|
|
4242
|
-
this.onRegisterCanceller
|
|
4243
|
-
);
|
|
4244
|
-
}
|
|
4245
|
-
};
|
|
3492
|
+
// src/connector/chains/legacyChainCall.ts
|
|
3493
|
+
var import_hwk_adapter_core11 = require("@onekeyfe/hwk-adapter-core");
|
|
4246
3494
|
|
|
4247
|
-
// src/
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
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;
|
|
4263
3514
|
}
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
3515
|
+
/**
|
|
3516
|
+
* Return the Ledger app name for a given chain ticker,
|
|
3517
|
+
* or undefined if the chain is not supported.
|
|
3518
|
+
*/
|
|
3519
|
+
static getAppName(chain) {
|
|
3520
|
+
return APP_NAME_MAP[chain];
|
|
3521
|
+
}
|
|
3522
|
+
/**
|
|
3523
|
+
* Ensure the target app is open on the device identified by `sessionId`.
|
|
3524
|
+
*
|
|
3525
|
+
* Flow:
|
|
3526
|
+
* 1. Check the currently running app.
|
|
3527
|
+
* 2. If it is already the target, return immediately.
|
|
3528
|
+
* 3. If a different app is running (not dashboard), close it first.
|
|
3529
|
+
* 4. Open the target app.
|
|
3530
|
+
* 5. Poll until the device confirms the target app is running.
|
|
3531
|
+
*/
|
|
3532
|
+
/**
|
|
3533
|
+
* @param onConfirmOnDevice Called BEFORE OpenAppCommand is issued — the
|
|
3534
|
+
* device is about to display "Open <app>" on screen and wait for the
|
|
3535
|
+
* user's button press. UI consumers should show their "open app" prompt
|
|
3536
|
+
* in response. NOT called when the target app is already open (no user
|
|
3537
|
+
* interaction needed in that case).
|
|
3538
|
+
*
|
|
3539
|
+
* Important: OpenAppCommand is blocking. It does not resolve until the user
|
|
3540
|
+
* has physically confirmed on the device, so anything that runs AFTER
|
|
3541
|
+
* `await this._openApp(...)` lands AFTER the prompt is already gone.
|
|
3542
|
+
* Hence the callback must fire BEFORE that await.
|
|
3543
|
+
*/
|
|
3544
|
+
async ensureAppOpen(sessionId, targetAppName, onConfirmOnDevice) {
|
|
3545
|
+
const currentApp = await this._getCurrentApp(sessionId);
|
|
3546
|
+
if (currentApp === targetAppName) {
|
|
3547
|
+
return;
|
|
3548
|
+
}
|
|
3549
|
+
if (!this._isDashboard(currentApp)) {
|
|
3550
|
+
await this._closeCurrentApp(sessionId);
|
|
3551
|
+
await this._waitForApp(sessionId, DASHBOARD_APP_NAME);
|
|
3552
|
+
}
|
|
3553
|
+
onConfirmOnDevice?.();
|
|
3554
|
+
await this._openApp(sessionId, targetAppName);
|
|
3555
|
+
await this._waitForApp(sessionId, targetAppName);
|
|
3556
|
+
}
|
|
3557
|
+
// ---------------------------------------------------------------------------
|
|
3558
|
+
// Private helpers
|
|
3559
|
+
// ---------------------------------------------------------------------------
|
|
3560
|
+
async _getCurrentApp(sessionId) {
|
|
3561
|
+
const result = await this._dmk.sendCommand({
|
|
3562
|
+
sessionId,
|
|
3563
|
+
command: new import_device_management_kit2.GetAppAndVersionCommand()
|
|
4271
3564
|
});
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
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
|
+
);
|
|
4278
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);
|
|
4279
3670
|
}
|
|
4280
|
-
async function
|
|
4281
|
-
const
|
|
4282
|
-
|
|
4283
|
-
const
|
|
4284
|
-
|
|
4285
|
-
signer.onInteraction = (interaction) => {
|
|
4286
|
-
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;
|
|
4287
3676
|
ctx.emit("ui-event", {
|
|
4288
|
-
type:
|
|
3677
|
+
type: import_hwk_adapter_core11.EConnectorInteraction.ConfirmOpenApp,
|
|
4289
3678
|
payload: { sessionId }
|
|
4290
3679
|
});
|
|
4291
3680
|
};
|
|
4292
|
-
|
|
4293
|
-
|
|
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);
|
|
4294
3752
|
}
|
|
4295
3753
|
|
|
4296
|
-
// src/
|
|
4297
|
-
var
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
this._sdk = _sdk;
|
|
4304
|
-
}
|
|
4305
|
-
/** Base58 Tron address plus the uncompressed public key at `derivationPath`. */
|
|
4306
|
-
async getAddress(derivationPath, options) {
|
|
4307
|
-
const action = this._sdk.getAddress(derivationPath, options);
|
|
4308
|
-
const result = await deviceActionToPromise(
|
|
4309
|
-
action,
|
|
4310
|
-
this.onInteraction,
|
|
4311
|
-
void 0,
|
|
4312
|
-
this.onRegisterCanceller
|
|
4313
|
-
);
|
|
4314
|
-
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;
|
|
4315
3761
|
}
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
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;
|
|
4325
3774
|
}
|
|
4326
|
-
|
|
4327
|
-
async signPersonalMessage(derivationPath, message, options) {
|
|
4328
|
-
const action = this._sdk.signPersonalMessage(derivationPath, message, options);
|
|
4329
|
-
return deviceActionToPromise(
|
|
4330
|
-
action,
|
|
4331
|
-
this.onInteraction,
|
|
4332
|
-
void 0,
|
|
4333
|
-
this.onRegisterCanceller
|
|
4334
|
-
);
|
|
3775
|
+
async close() {
|
|
4335
3776
|
}
|
|
4336
3777
|
};
|
|
4337
3778
|
|
|
4338
3779
|
// src/connector/chains/tron.ts
|
|
4339
3780
|
async function tronGetAddress(ctx, sessionId, params) {
|
|
4340
|
-
const tronSigner = await _createTronSigner(ctx, sessionId);
|
|
4341
3781
|
const path = normalizePath(params.path);
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
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
|
+
);
|
|
4353
3798
|
}
|
|
4354
3799
|
async function tronSignTransaction(ctx, sessionId, params) {
|
|
4355
3800
|
if (!params.rawTxHex) {
|
|
4356
3801
|
throw Object.assign(
|
|
4357
3802
|
new Error("TRON signing requires a protobuf-encoded raw transaction hex (rawTxHex)."),
|
|
4358
|
-
{ code:
|
|
3803
|
+
{ code: import_hwk_adapter_core12.HardwareErrorCode.InvalidParams }
|
|
4359
3804
|
);
|
|
4360
3805
|
}
|
|
4361
|
-
const tronSigner = await _createTronSigner(ctx, sessionId);
|
|
4362
3806
|
const path = normalizePath(params.path);
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
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
|
+
);
|
|
4372
3821
|
}
|
|
4373
3822
|
async function tronSignMessage(ctx, sessionId, params) {
|
|
4374
|
-
const tronSigner = await _createTronSigner(ctx, sessionId);
|
|
4375
3823
|
const path = normalizePath(params.path);
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
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
|
+
);
|
|
4385
3834
|
}
|
|
4386
|
-
async function
|
|
3835
|
+
async function _createTrx(ctx, sessionId) {
|
|
4387
3836
|
const dmk = await ctx.getOrCreateDmk();
|
|
4388
|
-
|
|
4389
|
-
const sdkSigner = new SignerTrxBuilder({ dmk, sessionId }).build();
|
|
4390
|
-
const signer = new SignerTron(sdkSigner);
|
|
4391
|
-
signer.onInteraction = (interaction) => {
|
|
4392
|
-
debugLog("[LedgerConnector] tron.onInteraction:", interaction);
|
|
4393
|
-
ctx.emit("ui-event", {
|
|
4394
|
-
type: collapseSignerInteraction(interaction),
|
|
4395
|
-
payload: { sessionId }
|
|
4396
|
-
});
|
|
4397
|
-
};
|
|
4398
|
-
signer.onRegisterCanceller = (cancel) => {
|
|
4399
|
-
ctx.registerCanceller(sessionId, cancel);
|
|
4400
|
-
};
|
|
4401
|
-
return signer;
|
|
3837
|
+
return new import_hw_app_trx.default(new DmkTransport(dmk, sessionId));
|
|
4402
3838
|
}
|
|
4403
3839
|
|
|
4404
3840
|
// src/device-apps/customActions.ts
|
|
4405
|
-
var
|
|
3841
|
+
var import_device_management_kit3 = require("@ledgerhq/device-management-kit");
|
|
4406
3842
|
var import_rxjs = require("rxjs");
|
|
4407
3843
|
var GetOsVersionDeviceAction = class {
|
|
4408
3844
|
// eslint-disable-next-line no-useless-constructor, no-empty-function
|
|
@@ -4416,7 +3852,7 @@ var GetOsVersionDeviceAction = class {
|
|
|
4416
3852
|
(async () => {
|
|
4417
3853
|
try {
|
|
4418
3854
|
subject.next({
|
|
4419
|
-
status:
|
|
3855
|
+
status: import_device_management_kit3.DeviceActionStatus.Pending,
|
|
4420
3856
|
intermediateValue: { requiredUserInteraction: "none" }
|
|
4421
3857
|
});
|
|
4422
3858
|
const result = await internalApi.sendCommand(new this._deps.GetOsVersionCommand());
|
|
@@ -4425,11 +3861,11 @@ var GetOsVersionDeviceAction = class {
|
|
|
4425
3861
|
const errObj = result?.error;
|
|
4426
3862
|
throw new Error(errObj?.message ?? "GetOsVersionCommand failed");
|
|
4427
3863
|
}
|
|
4428
|
-
subject.next({ status:
|
|
3864
|
+
subject.next({ status: import_device_management_kit3.DeviceActionStatus.Completed, output: result.data });
|
|
4429
3865
|
subject.complete();
|
|
4430
3866
|
} catch (err) {
|
|
4431
3867
|
if (cancelled) return;
|
|
4432
|
-
subject.next({ status:
|
|
3868
|
+
subject.next({ status: import_device_management_kit3.DeviceActionStatus.Error, error: err });
|
|
4433
3869
|
subject.complete();
|
|
4434
3870
|
}
|
|
4435
3871
|
})();
|
|
@@ -4437,7 +3873,7 @@ var GetOsVersionDeviceAction = class {
|
|
|
4437
3873
|
observable: subject.asObservable(),
|
|
4438
3874
|
cancel: () => {
|
|
4439
3875
|
cancelled = true;
|
|
4440
|
-
subject.next({ status:
|
|
3876
|
+
subject.next({ status: import_device_management_kit3.DeviceActionStatus.Stopped });
|
|
4441
3877
|
subject.complete();
|
|
4442
3878
|
}
|
|
4443
3879
|
};
|
|
@@ -4455,7 +3891,7 @@ var ListAvailableAppsDeviceAction = class {
|
|
|
4455
3891
|
(async () => {
|
|
4456
3892
|
try {
|
|
4457
3893
|
subject.next({
|
|
4458
|
-
status:
|
|
3894
|
+
status: import_device_management_kit3.DeviceActionStatus.Pending,
|
|
4459
3895
|
intermediateValue: { requiredUserInteraction: "none" }
|
|
4460
3896
|
});
|
|
4461
3897
|
const osVersionResult = await internalApi.sendCommand(new this._GetOsVersionCommand());
|
|
@@ -4472,11 +3908,11 @@ var ListAvailableAppsDeviceAction = class {
|
|
|
4472
3908
|
throw new Error(httpErr?.message ?? "Manager API getAppList failed");
|
|
4473
3909
|
}
|
|
4474
3910
|
const apps = either.extract();
|
|
4475
|
-
subject.next({ status:
|
|
3911
|
+
subject.next({ status: import_device_management_kit3.DeviceActionStatus.Completed, output: apps });
|
|
4476
3912
|
subject.complete();
|
|
4477
3913
|
} catch (err) {
|
|
4478
3914
|
if (cancelled) return;
|
|
4479
|
-
subject.next({ status:
|
|
3915
|
+
subject.next({ status: import_device_management_kit3.DeviceActionStatus.Error, error: err });
|
|
4480
3916
|
subject.complete();
|
|
4481
3917
|
}
|
|
4482
3918
|
})();
|
|
@@ -4484,7 +3920,7 @@ var ListAvailableAppsDeviceAction = class {
|
|
|
4484
3920
|
observable: subject.asObservable(),
|
|
4485
3921
|
cancel: () => {
|
|
4486
3922
|
cancelled = true;
|
|
4487
|
-
subject.next({ status:
|
|
3923
|
+
subject.next({ status: import_device_management_kit3.DeviceActionStatus.Stopped });
|
|
4488
3924
|
subject.complete();
|
|
4489
3925
|
}
|
|
4490
3926
|
};
|
|
@@ -4577,7 +4013,7 @@ var DeviceApps = class {
|
|
|
4577
4013
|
seTargetId: v.seTargetId,
|
|
4578
4014
|
mcuTargetId: v.mcuTargetId,
|
|
4579
4015
|
seVersion: v.seVersion,
|
|
4580
|
-
seFlagsHex:
|
|
4016
|
+
seFlagsHex: bytesToHex2(v.seFlags),
|
|
4581
4017
|
mcuSephVersion: v.mcuSephVersion,
|
|
4582
4018
|
mcuBootloaderVersion: v.mcuBootloaderVersion,
|
|
4583
4019
|
hwVersion: v.hwVersion
|
|
@@ -4651,7 +4087,7 @@ var DeviceApps = class {
|
|
|
4651
4087
|
}
|
|
4652
4088
|
}
|
|
4653
4089
|
};
|
|
4654
|
-
function
|
|
4090
|
+
function bytesToHex2(bytes) {
|
|
4655
4091
|
if (!bytes) return "";
|
|
4656
4092
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
4657
4093
|
}
|
|
@@ -4694,11 +4130,10 @@ var METHOD_PREFIX_TO_APP_NAME = {
|
|
|
4694
4130
|
evm: "Ethereum",
|
|
4695
4131
|
btc: "Bitcoin",
|
|
4696
4132
|
sol: "Solana",
|
|
4697
|
-
tron: "Tron"
|
|
4698
|
-
zcash: "Zcash"
|
|
4133
|
+
tron: "Tron"
|
|
4699
4134
|
};
|
|
4700
4135
|
var HARDWARE_ERROR_CODE_VALUES = new Set(
|
|
4701
|
-
Object.values(
|
|
4136
|
+
Object.values(import_hwk_adapter_core13.HardwareErrorCode).filter((value) => typeof value === "number")
|
|
4702
4137
|
);
|
|
4703
4138
|
var BLE_CONNECT_SCAN_TIMEOUT_MS = 1500;
|
|
4704
4139
|
var LEDGER_RELAY_ALLOWED_ROOT_DOMAINS = ["onekeytest.com", "onekey.com"];
|
|
@@ -4735,10 +4170,6 @@ async function defaultLedgerKitImporter(pkg) {
|
|
|
4735
4170
|
return import("@ledgerhq/device-signer-kit-bitcoin");
|
|
4736
4171
|
case "@ledgerhq/device-signer-kit-solana":
|
|
4737
4172
|
return import("@ledgerhq/device-signer-kit-solana");
|
|
4738
|
-
case "@ledgerhq/device-signer-kit-tron":
|
|
4739
|
-
return import("@ledgerhq/device-signer-kit-tron");
|
|
4740
|
-
case "@ledgerhq/device-signer-kit-zcash":
|
|
4741
|
-
return import("@ledgerhq/device-signer-kit-zcash");
|
|
4742
4173
|
case "@ledgerhq/context-module":
|
|
4743
4174
|
return import("@ledgerhq/context-module");
|
|
4744
4175
|
default:
|
|
@@ -4849,7 +4280,7 @@ var LedgerConnectorBase = class {
|
|
|
4849
4280
|
async searchDevices() {
|
|
4850
4281
|
const dm = await this._getDeviceManager();
|
|
4851
4282
|
const descriptors = await this._discoverDescriptors(dm);
|
|
4852
|
-
const resolvedDescriptors = descriptors.filter((d) => !(0,
|
|
4283
|
+
const resolvedDescriptors = descriptors.filter((d) => !(0, import_hwk_adapter_core13.isKnownNonTargetHardwareVendor)(d, "ledger")).map((d) => ({
|
|
4853
4284
|
descriptor: d,
|
|
4854
4285
|
connectId: this._resolveConnectId(d)
|
|
4855
4286
|
}));
|
|
@@ -4897,7 +4328,7 @@ var LedgerConnectorBase = class {
|
|
|
4897
4328
|
`Ledger BLE connect did not return within ${HANG_CEILING_MS / 6e4}min \u2014 DMK hang fallback.`
|
|
4898
4329
|
);
|
|
4899
4330
|
err._tag = ERROR_TAG.BlePairingTimeout;
|
|
4900
|
-
err.code =
|
|
4331
|
+
err.code = import_hwk_adapter_core13.HardwareErrorCode.BlePairingTimeout;
|
|
4901
4332
|
reject(err);
|
|
4902
4333
|
}, HANG_CEILING_MS);
|
|
4903
4334
|
});
|
|
@@ -4930,7 +4361,7 @@ var LedgerConnectorBase = class {
|
|
|
4930
4361
|
"Ledger device is not currently advertising. Wake up and unlock the device, keep it nearby, then try again."
|
|
4931
4362
|
);
|
|
4932
4363
|
err._tag = ERROR_TAG.DeviceNotAdvertising;
|
|
4933
|
-
err.code =
|
|
4364
|
+
err.code = import_hwk_adapter_core13.HardwareErrorCode.DeviceNotFound;
|
|
4934
4365
|
throw err;
|
|
4935
4366
|
};
|
|
4936
4367
|
const doConnect = async (path) => {
|
|
@@ -4994,7 +4425,7 @@ var LedgerConnectorBase = class {
|
|
|
4994
4425
|
"Ledger Bluetooth pairing failed. Make sure the device is unlocked and nearby, then try again."
|
|
4995
4426
|
);
|
|
4996
4427
|
wrapped._tag = ERROR_TAG.BleGattBondingFailed;
|
|
4997
|
-
wrapped.code =
|
|
4428
|
+
wrapped.code = import_hwk_adapter_core13.HardwareErrorCode.BlePairingTimeout;
|
|
4998
4429
|
wrapped.originalError = err;
|
|
4999
4430
|
throw wrapped;
|
|
5000
4431
|
}
|
|
@@ -5072,7 +4503,7 @@ var LedgerConnectorBase = class {
|
|
|
5072
4503
|
this._unwatchSessionState(sessionId);
|
|
5073
4504
|
this._signerManager?.invalidate(sessionId);
|
|
5074
4505
|
this._cancellers.get(sessionId)?.({
|
|
5075
|
-
code:
|
|
4506
|
+
code: import_hwk_adapter_core13.HardwareErrorCode.DeviceDisconnected,
|
|
5076
4507
|
tag: "DeviceDisconnected",
|
|
5077
4508
|
message: "Device disconnected"
|
|
5078
4509
|
});
|
|
@@ -5096,9 +4527,9 @@ var LedgerConnectorBase = class {
|
|
|
5096
4527
|
if (isAppStuckByApdu(err)) {
|
|
5097
4528
|
return {
|
|
5098
4529
|
success: false,
|
|
5099
|
-
error: (0,
|
|
4530
|
+
error: (0, import_hwk_adapter_core13.serializeConnectorError)(
|
|
5100
4531
|
Object.assign(new Error("Ledger app is unresponsive"), {
|
|
5101
|
-
code:
|
|
4532
|
+
code: import_hwk_adapter_core13.HardwareErrorCode.DeviceAppStuck,
|
|
5102
4533
|
_tag: ERROR_TAG.DeviceAppStuck,
|
|
5103
4534
|
originalError: err
|
|
5104
4535
|
})
|
|
@@ -5108,16 +4539,16 @@ var LedgerConnectorBase = class {
|
|
|
5108
4539
|
if (isTransportStuck(err)) {
|
|
5109
4540
|
return {
|
|
5110
4541
|
success: false,
|
|
5111
|
-
error: (0,
|
|
4542
|
+
error: (0, import_hwk_adapter_core13.serializeConnectorError)(
|
|
5112
4543
|
Object.assign(new Error("Device communication interrupted, please retry"), {
|
|
5113
|
-
code:
|
|
4544
|
+
code: import_hwk_adapter_core13.HardwareErrorCode.TransportError,
|
|
5114
4545
|
_tag: ERROR_TAG.DeviceTransportStuck,
|
|
5115
4546
|
originalError: err
|
|
5116
4547
|
})
|
|
5117
4548
|
)
|
|
5118
4549
|
};
|
|
5119
4550
|
}
|
|
5120
|
-
return { success: false, error: (0,
|
|
4551
|
+
return { success: false, error: (0, import_hwk_adapter_core13.serializeConnectorError)(err) };
|
|
5121
4552
|
}
|
|
5122
4553
|
}
|
|
5123
4554
|
async _dispatch(sessionId, method, params) {
|
|
@@ -5156,11 +4587,6 @@ var LedgerConnectorBase = class {
|
|
|
5156
4587
|
return solSignTransaction(ctx, sessionId, params);
|
|
5157
4588
|
case "solSignMessage":
|
|
5158
4589
|
return solSignMessage(ctx, sessionId, params);
|
|
5159
|
-
// ZCASH
|
|
5160
|
-
case "zcashGetFullViewingKey":
|
|
5161
|
-
return zcashGetFullViewingKey(ctx, sessionId, params);
|
|
5162
|
-
case "zcashGetShieldedAddress":
|
|
5163
|
-
return zcashGetShieldedAddress(ctx, sessionId, params);
|
|
5164
4590
|
// TRON
|
|
5165
4591
|
case "tronGetAddress":
|
|
5166
4592
|
return tronGetAddress(ctx, sessionId, params);
|
|
@@ -5185,7 +4611,7 @@ var LedgerConnectorBase = class {
|
|
|
5185
4611
|
try {
|
|
5186
4612
|
return await apps.install(p.appName, ({ progress }) => {
|
|
5187
4613
|
ctx.emit("ui-event", {
|
|
5188
|
-
type:
|
|
4614
|
+
type: import_hwk_adapter_core13.EConnectorInteraction.AppInstallProgress,
|
|
5189
4615
|
payload: {
|
|
5190
4616
|
sessionId,
|
|
5191
4617
|
appName: p.appName,
|
|
@@ -5490,7 +4916,7 @@ var LedgerConnectorBase = class {
|
|
|
5490
4916
|
* at every catch site. Falls through unchanged for unknown methods.
|
|
5491
4917
|
*/
|
|
5492
4918
|
_ctxForMethod(method) {
|
|
5493
|
-
const prefix = /^(evm|btc|sol|tron
|
|
4919
|
+
const prefix = /^(evm|btc|sol|tron)/.exec(method)?.[1];
|
|
5494
4920
|
const defaultAppName = prefix ? METHOD_PREFIX_TO_APP_NAME[prefix] : void 0;
|
|
5495
4921
|
if (!defaultAppName) return this._ctx;
|
|
5496
4922
|
return {
|
|
@@ -5524,204 +4950,6 @@ var LedgerConnectorBase = class {
|
|
|
5524
4950
|
return error;
|
|
5525
4951
|
}
|
|
5526
4952
|
};
|
|
5527
|
-
|
|
5528
|
-
// src/transport/DmkTransport.ts
|
|
5529
|
-
var import_hw_transport = __toESM(require("@ledgerhq/hw-transport"));
|
|
5530
|
-
var DmkTransport = class extends import_hw_transport.default {
|
|
5531
|
-
constructor(dmk, sessionId) {
|
|
5532
|
-
super();
|
|
5533
|
-
this._dmk = dmk;
|
|
5534
|
-
this._sessionId = sessionId;
|
|
5535
|
-
}
|
|
5536
|
-
async exchange(apdu) {
|
|
5537
|
-
const response = await this._dmk.sendApdu({
|
|
5538
|
-
sessionId: this._sessionId,
|
|
5539
|
-
apdu: new Uint8Array(apdu)
|
|
5540
|
-
});
|
|
5541
|
-
const { data, statusCode } = response;
|
|
5542
|
-
const result = Buffer.alloc(data.length + 2);
|
|
5543
|
-
if (data.length > 0) {
|
|
5544
|
-
result.set(data, 0);
|
|
5545
|
-
}
|
|
5546
|
-
result.set(statusCode, data.length);
|
|
5547
|
-
return result;
|
|
5548
|
-
}
|
|
5549
|
-
async close() {
|
|
5550
|
-
}
|
|
5551
|
-
};
|
|
5552
|
-
|
|
5553
|
-
// src/app/AppManager.ts
|
|
5554
|
-
var import_device_management_kit3 = require("@ledgerhq/device-management-kit");
|
|
5555
|
-
var import_hwk_adapter_core13 = require("@onekeyfe/hwk-adapter-core");
|
|
5556
|
-
var APP_NAME_MAP = {
|
|
5557
|
-
ETH: "Ethereum",
|
|
5558
|
-
BTC: "Bitcoin",
|
|
5559
|
-
SOL: "Solana",
|
|
5560
|
-
TRX: "Tron",
|
|
5561
|
-
ZEC: "Zcash",
|
|
5562
|
-
XRP: "XRP",
|
|
5563
|
-
ADA: "Cardano",
|
|
5564
|
-
DOT: "Polkadot",
|
|
5565
|
-
ATOM: "Cosmos"
|
|
5566
|
-
};
|
|
5567
|
-
var DASHBOARD_APP_NAME = "BOLOS";
|
|
5568
|
-
var AppManager = class {
|
|
5569
|
-
constructor(dmk, options) {
|
|
5570
|
-
this._dmk = dmk;
|
|
5571
|
-
this._waitMs = options?.waitMs ?? 1e3;
|
|
5572
|
-
this._maxRetries = options?.maxRetries ?? 10;
|
|
5573
|
-
}
|
|
5574
|
-
/**
|
|
5575
|
-
* Return the Ledger app name for a given chain ticker,
|
|
5576
|
-
* or undefined if the chain is not supported.
|
|
5577
|
-
*/
|
|
5578
|
-
static getAppName(chain) {
|
|
5579
|
-
return APP_NAME_MAP[chain];
|
|
5580
|
-
}
|
|
5581
|
-
/**
|
|
5582
|
-
* Ensure the target app is open on the device identified by `sessionId`.
|
|
5583
|
-
*
|
|
5584
|
-
* Flow:
|
|
5585
|
-
* 1. Check the currently running app.
|
|
5586
|
-
* 2. If it is already the target, return immediately.
|
|
5587
|
-
* 3. If a different app is running (not dashboard), close it first.
|
|
5588
|
-
* 4. Open the target app.
|
|
5589
|
-
* 5. Poll until the device confirms the target app is running.
|
|
5590
|
-
*/
|
|
5591
|
-
/**
|
|
5592
|
-
* @param onConfirmOnDevice Called BEFORE OpenAppCommand is issued — the
|
|
5593
|
-
* device is about to display "Open <app>" on screen and wait for the
|
|
5594
|
-
* user's button press. UI consumers should show their "open app" prompt
|
|
5595
|
-
* in response. NOT called when the target app is already open (no user
|
|
5596
|
-
* interaction needed in that case).
|
|
5597
|
-
*
|
|
5598
|
-
* Important: OpenAppCommand is blocking. It does not resolve until the user
|
|
5599
|
-
* has physically confirmed on the device, so anything that runs AFTER
|
|
5600
|
-
* `await this._openApp(...)` lands AFTER the prompt is already gone.
|
|
5601
|
-
* Hence the callback must fire BEFORE that await.
|
|
5602
|
-
*/
|
|
5603
|
-
async ensureAppOpen(sessionId, targetAppName, onConfirmOnDevice) {
|
|
5604
|
-
const currentApp = await this._getCurrentApp(sessionId);
|
|
5605
|
-
if (currentApp === targetAppName) {
|
|
5606
|
-
return;
|
|
5607
|
-
}
|
|
5608
|
-
if (!this._isDashboard(currentApp)) {
|
|
5609
|
-
await this._closeCurrentApp(sessionId);
|
|
5610
|
-
await this._waitForApp(sessionId, DASHBOARD_APP_NAME);
|
|
5611
|
-
}
|
|
5612
|
-
onConfirmOnDevice?.();
|
|
5613
|
-
await this._openApp(sessionId, targetAppName);
|
|
5614
|
-
await this._waitForApp(sessionId, targetAppName);
|
|
5615
|
-
}
|
|
5616
|
-
// ---------------------------------------------------------------------------
|
|
5617
|
-
// Private helpers
|
|
5618
|
-
// ---------------------------------------------------------------------------
|
|
5619
|
-
async _getCurrentApp(sessionId) {
|
|
5620
|
-
const result = await this._dmk.sendCommand({
|
|
5621
|
-
sessionId,
|
|
5622
|
-
command: new import_device_management_kit3.GetAppAndVersionCommand()
|
|
5623
|
-
});
|
|
5624
|
-
if ((0, import_device_management_kit3.isSuccessCommandResult)(result)) {
|
|
5625
|
-
debugLog("[AppManager] currentApp:", result.data.name);
|
|
5626
|
-
return result.data.name;
|
|
5627
|
-
}
|
|
5628
|
-
const errResult = result;
|
|
5629
|
-
const dmkErr = errResult.error ?? {};
|
|
5630
|
-
const original = dmkErr.originalError;
|
|
5631
|
-
debugLog(
|
|
5632
|
-
"[AppManager] _getCurrentApp failed sessionId=",
|
|
5633
|
-
sessionId,
|
|
5634
|
-
"tag=",
|
|
5635
|
-
dmkErr._tag,
|
|
5636
|
-
"errorCode=",
|
|
5637
|
-
dmkErr.errorCode,
|
|
5638
|
-
"message=",
|
|
5639
|
-
dmkErr.message,
|
|
5640
|
-
"originalErrorMessage=",
|
|
5641
|
-
original?.message ?? String(original ?? "")
|
|
5642
|
-
);
|
|
5643
|
-
throw Object.assign(
|
|
5644
|
-
new Error(
|
|
5645
|
-
dmkErr.message ?? "Failed to get current app from device"
|
|
5646
|
-
),
|
|
5647
|
-
{
|
|
5648
|
-
_tag: dmkErr._tag,
|
|
5649
|
-
errorCode: dmkErr.errorCode,
|
|
5650
|
-
originalError: original
|
|
5651
|
-
}
|
|
5652
|
-
);
|
|
5653
|
-
}
|
|
5654
|
-
async _openApp(sessionId, appName) {
|
|
5655
|
-
const result = await this._dmk.sendCommand({
|
|
5656
|
-
sessionId,
|
|
5657
|
-
command: new import_device_management_kit3.OpenAppCommand({ appName })
|
|
5658
|
-
});
|
|
5659
|
-
if (!(0, import_device_management_kit3.isSuccessCommandResult)(result)) {
|
|
5660
|
-
const dmkErr = result.error;
|
|
5661
|
-
const errorCode = "errorCode" in dmkErr && dmkErr.errorCode != null ? String(dmkErr.errorCode) : "";
|
|
5662
|
-
const message = "message" in dmkErr && typeof dmkErr.message === "string" ? dmkErr.message : "";
|
|
5663
|
-
debugLog(
|
|
5664
|
-
"[AppManager] openApp failed:",
|
|
5665
|
-
appName,
|
|
5666
|
-
"errorCode:",
|
|
5667
|
-
errorCode,
|
|
5668
|
-
"tag:",
|
|
5669
|
-
dmkErr._tag
|
|
5670
|
-
);
|
|
5671
|
-
let code;
|
|
5672
|
-
if (errorCode === "6807" || /unknown application/i.test(message)) {
|
|
5673
|
-
code = import_hwk_adapter_core13.HardwareErrorCode.AppNotInstalled;
|
|
5674
|
-
} else if (errorCode === "5501" || dmkErr._tag === "ActionRefusedError") {
|
|
5675
|
-
code = import_hwk_adapter_core13.HardwareErrorCode.UserRejected;
|
|
5676
|
-
}
|
|
5677
|
-
throw Object.assign(new Error(`Failed to open "${appName}"`), {
|
|
5678
|
-
_tag: ERROR_TAG.OpenAppCommand,
|
|
5679
|
-
code,
|
|
5680
|
-
errorCode,
|
|
5681
|
-
statusCode: errorCode,
|
|
5682
|
-
appName,
|
|
5683
|
-
originalError: dmkErr
|
|
5684
|
-
});
|
|
5685
|
-
}
|
|
5686
|
-
}
|
|
5687
|
-
async _closeCurrentApp(sessionId) {
|
|
5688
|
-
debugLog("[AppManager] closeCurrentApp");
|
|
5689
|
-
await this._dmk.sendCommand({
|
|
5690
|
-
sessionId,
|
|
5691
|
-
command: new import_device_management_kit3.CloseAppCommand()
|
|
5692
|
-
});
|
|
5693
|
-
}
|
|
5694
|
-
/**
|
|
5695
|
-
* Poll the device until the expected app is reported as running,
|
|
5696
|
-
* or throw after `_maxRetries` attempts.
|
|
5697
|
-
*/
|
|
5698
|
-
async _waitForApp(sessionId, expectedAppName) {
|
|
5699
|
-
let lastSeen = "";
|
|
5700
|
-
for (let i = 0; i < this._maxRetries; i++) {
|
|
5701
|
-
await this._wait();
|
|
5702
|
-
const current = await this._getCurrentApp(sessionId);
|
|
5703
|
-
lastSeen = current;
|
|
5704
|
-
if (current === expectedAppName) {
|
|
5705
|
-
return;
|
|
5706
|
-
}
|
|
5707
|
-
}
|
|
5708
|
-
debugLog(
|
|
5709
|
-
"[AppManager] waitForApp exhausted: expected=",
|
|
5710
|
-
expectedAppName,
|
|
5711
|
-
"lastSeen=",
|
|
5712
|
-
lastSeen
|
|
5713
|
-
);
|
|
5714
|
-
throw new Error(
|
|
5715
|
-
`Ledger: failed to open "${expectedAppName}" after ${this._maxRetries} retries (last seen: ${lastSeen})`
|
|
5716
|
-
);
|
|
5717
|
-
}
|
|
5718
|
-
_isDashboard(appName) {
|
|
5719
|
-
return appName === DASHBOARD_APP_NAME;
|
|
5720
|
-
}
|
|
5721
|
-
_wait() {
|
|
5722
|
-
return new Promise((resolve) => setTimeout(resolve, this._waitMs));
|
|
5723
|
-
}
|
|
5724
|
-
};
|
|
5725
4953
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5726
4954
|
0 && (module.exports = {
|
|
5727
4955
|
AppManager,
|
|
@@ -5733,7 +4961,6 @@ var AppManager = class {
|
|
|
5733
4961
|
SignerEth,
|
|
5734
4962
|
SignerManager,
|
|
5735
4963
|
SignerSol,
|
|
5736
|
-
SignerZcash,
|
|
5737
4964
|
debugLog,
|
|
5738
4965
|
deviceActionToPromise,
|
|
5739
4966
|
isDeviceLockedError,
|