@onekeyfe/hwk-ledger-adapter 1.2.2-alpha.8 → 1.2.3-alpha.1
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 +62 -28
- package/dist/index.d.ts +62 -28
- package/dist/index.js +1113 -465
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1112 -446
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -9
package/dist/index.js
CHANGED
|
@@ -39,6 +39,7 @@ __export(index_exports, {
|
|
|
39
39
|
SignerEth: () => SignerEth,
|
|
40
40
|
SignerManager: () => SignerManager,
|
|
41
41
|
SignerSol: () => SignerSol,
|
|
42
|
+
SignerZcash: () => SignerZcash,
|
|
42
43
|
debugLog: () => debugLog,
|
|
43
44
|
deviceActionToPromise: () => deviceActionToPromise,
|
|
44
45
|
isDeviceLockedError: () => isDeviceLockedError,
|
|
@@ -57,17 +58,14 @@ var import_hwk_adapter_core3 = require("@onekeyfe/hwk-adapter-core");
|
|
|
57
58
|
|
|
58
59
|
// src/errors.ts
|
|
59
60
|
var import_hwk_adapter_core = require("@onekeyfe/hwk-adapter-core");
|
|
60
|
-
|
|
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) {
|
|
61
|
+
function ledgerFailure(code, error, appName, tag, params, origin, recovery) {
|
|
67
62
|
const payload = { error, code };
|
|
68
63
|
if (appName !== void 0) payload.appName = appName;
|
|
69
64
|
if (tag !== void 0) payload._tag = tag;
|
|
70
65
|
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);
|
|
71
69
|
return { success: false, payload };
|
|
72
70
|
}
|
|
73
71
|
var LOCKED_ERROR_CODES = /* @__PURE__ */ new Set(["5515", "21781", "6982", "27010", "5303", "21251"]);
|
|
@@ -251,7 +249,6 @@ function isBlePairingFailureError(err) {
|
|
|
251
249
|
return false;
|
|
252
250
|
}
|
|
253
251
|
var CONNECTION_LEVEL_TAGS = /* @__PURE__ */ new Set([
|
|
254
|
-
ERROR_TAG.DeviceLocked,
|
|
255
252
|
ERROR_TAG.DeviceNotAdvertising,
|
|
256
253
|
ERROR_TAG.BlePairingTimeout,
|
|
257
254
|
ERROR_TAG.BleGattBondingFailed,
|
|
@@ -486,7 +483,12 @@ function mapLedgerError(err, opts) {
|
|
|
486
483
|
}
|
|
487
484
|
const errAppName = err && typeof err === "object" ? err.appName : void 0;
|
|
488
485
|
const appName = errAppName ?? opts?.defaultAppName;
|
|
489
|
-
return {
|
|
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
|
+
};
|
|
490
492
|
}
|
|
491
493
|
|
|
492
494
|
// src/adapter/methods/allNetworkGetAddress.ts
|
|
@@ -547,57 +549,81 @@ var LEDGER_BTC_NETWORK_COIN_MAP = {
|
|
|
547
549
|
var LEDGER_UNSUPPORTED_ALLNETWORK_NETWORKS = /* @__PURE__ */ new Set(["doge", "dogecoin"]);
|
|
548
550
|
function createAllNetworkGetAddress({
|
|
549
551
|
callChain,
|
|
550
|
-
getChainFingerprint
|
|
552
|
+
getChainFingerprint,
|
|
553
|
+
retainInteraction,
|
|
554
|
+
errorToFailure
|
|
551
555
|
}) {
|
|
552
556
|
return async function allNetworkGetAddress(connectId, _deviceId, params) {
|
|
553
|
-
debugLog("[LedgerAdapter][REQ]", {
|
|
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.interactionId, "ledger");
|
|
563
|
+
if (!target.success) return target;
|
|
564
|
+
const effectiveTargetId = target.payload.targetId ?? "";
|
|
565
|
+
let releaseInteractionRetention;
|
|
566
|
+
try {
|
|
567
|
+
releaseInteractionRetention = target.payload.interactionId ? retainInteraction(target.payload.interactionId) : void 0;
|
|
568
|
+
} catch (error) {
|
|
569
|
+
return errorToFailure(error);
|
|
570
|
+
}
|
|
554
571
|
const installContext = {};
|
|
555
572
|
const commonParams = {
|
|
556
|
-
autoInstallApp: params.autoInstallApp
|
|
573
|
+
autoInstallApp: params.autoInstallApp,
|
|
574
|
+
interactionId: target.payload.interactionId,
|
|
575
|
+
knownConnections: params.knownConnections,
|
|
576
|
+
extra: params.extra,
|
|
577
|
+
allowDeviceSelection: params.allowDeviceSelection
|
|
557
578
|
};
|
|
558
579
|
const chainFingerprints = /* @__PURE__ */ new Map();
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
580
|
+
try {
|
|
581
|
+
const result = await (0, import_hwk_adapter_core2.runAllNetworkGetAddress)({
|
|
582
|
+
connectId: effectiveTargetId,
|
|
583
|
+
deviceId: _deviceId,
|
|
584
|
+
params,
|
|
585
|
+
normalizeItem: normalizeLedgerAllNetworkItem,
|
|
586
|
+
buildUnsupportedNetworkResponse: (item) => isUnsupportedLedgerAllNetworkNetwork(item) ? buildUnsupportedNetworkResponse(item) : void 0,
|
|
587
|
+
callItem: async ({ method, chain, item }) => {
|
|
588
|
+
const itemDeviceId = getItemDeviceId(item) ?? chainFingerprints.get(chain) ?? "";
|
|
589
|
+
return callAllNetworkMethod(
|
|
590
|
+
callChain,
|
|
591
|
+
effectiveTargetId,
|
|
592
|
+
itemDeviceId,
|
|
593
|
+
method,
|
|
594
|
+
item,
|
|
595
|
+
commonParams,
|
|
596
|
+
installContext
|
|
597
|
+
);
|
|
598
|
+
},
|
|
599
|
+
attachIdentity: async ({ item, chain, payload }) => attachLedgerIdentity(
|
|
600
|
+
getChainFingerprint,
|
|
601
|
+
effectiveTargetId,
|
|
572
602
|
item,
|
|
573
|
-
|
|
603
|
+
chain,
|
|
604
|
+
payload,
|
|
605
|
+
chainFingerprints,
|
|
574
606
|
installContext
|
|
575
|
-
)
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
}
|
|
595
|
-
debugLog("[LedgerAdapter][RES]", {
|
|
596
|
-
method: "allNetworkGetAddress",
|
|
597
|
-
success: result.success,
|
|
598
|
-
payload: result
|
|
599
|
-
});
|
|
600
|
-
return result;
|
|
607
|
+
),
|
|
608
|
+
shouldAbortBundle: isTopLevelAllNetworkFailure,
|
|
609
|
+
buildTopLevelFailure: (response) => {
|
|
610
|
+
const code = response.payload?.code ?? import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch;
|
|
611
|
+
return (0, import_hwk_adapter_core2.failure)(
|
|
612
|
+
code,
|
|
613
|
+
response.payload?.error ?? "All-network get-address aborted",
|
|
614
|
+
response.payload?.params
|
|
615
|
+
);
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
debugLog("[LedgerAdapter][RES]", {
|
|
619
|
+
method: "allNetworkGetAddress",
|
|
620
|
+
success: result.success,
|
|
621
|
+
payload: result
|
|
622
|
+
});
|
|
623
|
+
return result;
|
|
624
|
+
} finally {
|
|
625
|
+
releaseInteractionRetention?.();
|
|
626
|
+
}
|
|
601
627
|
};
|
|
602
628
|
}
|
|
603
629
|
function isTopLevelAllNetworkFailure(response) {
|
|
@@ -605,7 +631,7 @@ function isTopLevelAllNetworkFailure(response) {
|
|
|
605
631
|
return false;
|
|
606
632
|
}
|
|
607
633
|
const code = response.payload?.code;
|
|
608
|
-
return code === import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch || code === import_hwk_adapter_core2.HardwareErrorCode.UserAborted || code === import_hwk_adapter_core2.HardwareErrorCode.UserRejected;
|
|
634
|
+
return code === import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch || code === import_hwk_adapter_core2.HardwareErrorCode.DeviceDisconnected || code === import_hwk_adapter_core2.HardwareErrorCode.OperationTimeout || code === import_hwk_adapter_core2.HardwareErrorCode.TransportError || code === import_hwk_adapter_core2.HardwareErrorCode.InteractionEnded || code === import_hwk_adapter_core2.HardwareErrorCode.InteractionNotFound || code === import_hwk_adapter_core2.HardwareErrorCode.UserAborted || code === import_hwk_adapter_core2.HardwareErrorCode.UserRejected;
|
|
609
635
|
}
|
|
610
636
|
function getItemDeviceId(item) {
|
|
611
637
|
const { deviceId } = item;
|
|
@@ -635,8 +661,13 @@ function normalizeLedgerAllNetworkItem(method, item) {
|
|
|
635
661
|
const coin = LEDGER_BTC_NETWORK_COIN_MAP[item.network];
|
|
636
662
|
return coin ? { ...item, coin } : item;
|
|
637
663
|
}
|
|
638
|
-
async function attachLedgerIdentity(getChainFingerprint, connectId, item, chain, payload, chainFingerprints) {
|
|
639
|
-
const fingerprint = getItemDeviceId(item) || chainFingerprints.get(chain) || await bootstrapChainFingerprint(
|
|
664
|
+
async function attachLedgerIdentity(getChainFingerprint, connectId, item, chain, payload, chainFingerprints, context) {
|
|
665
|
+
const fingerprint = getItemDeviceId(item) || chainFingerprints.get(chain) || await bootstrapChainFingerprint(
|
|
666
|
+
getChainFingerprint,
|
|
667
|
+
context.connection?.connectId ?? connectId,
|
|
668
|
+
chain,
|
|
669
|
+
context
|
|
670
|
+
);
|
|
640
671
|
if (!fingerprint) {
|
|
641
672
|
return buildFingerprintBootstrapFailure(item, chain);
|
|
642
673
|
}
|
|
@@ -657,8 +688,8 @@ async function attachLedgerIdentity(getChainFingerprint, connectId, item, chain,
|
|
|
657
688
|
}
|
|
658
689
|
};
|
|
659
690
|
}
|
|
660
|
-
async function bootstrapChainFingerprint(getChainFingerprint, connectId, chain) {
|
|
661
|
-
const response = await getChainFingerprint(connectId, chain);
|
|
691
|
+
async function bootstrapChainFingerprint(getChainFingerprint, connectId, chain, context) {
|
|
692
|
+
const response = await getChainFingerprint(connectId, chain, context);
|
|
662
693
|
return response.success ? response.payload : "";
|
|
663
694
|
}
|
|
664
695
|
function buildFingerprintBootstrapFailure(item, chain) {
|
|
@@ -763,8 +794,27 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
763
794
|
constructor(connector, options) {
|
|
764
795
|
this.vendor = "ledger";
|
|
765
796
|
this.emitter = new import_hwk_adapter_core3.TypedEventEmitter();
|
|
797
|
+
this._interactions = new import_hwk_adapter_core3.InteractionRegistry({
|
|
798
|
+
vendor: "ledger",
|
|
799
|
+
onEnded: (interaction, reason) => {
|
|
800
|
+
const binding = this._pendingInteractionBindings.get(interaction.interactionId);
|
|
801
|
+
if (binding?.selectedConnection?.requestId === this._bindingSelectionRequestId) {
|
|
802
|
+
this._finishBleBinding("cancelled");
|
|
803
|
+
}
|
|
804
|
+
this._pendingInteractionBindings.delete(interaction.interactionId);
|
|
805
|
+
this.emitter.emit(import_hwk_adapter_core3.SDK.INTERACTION_ENDED, {
|
|
806
|
+
type: import_hwk_adapter_core3.SDK.INTERACTION_ENDED,
|
|
807
|
+
payload: { interactionId: interaction.interactionId, reason }
|
|
808
|
+
});
|
|
809
|
+
if (reason === "timeout") {
|
|
810
|
+
void this._releaseInteractionConnection(interaction);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
});
|
|
766
814
|
this._discoveredDevices = /* @__PURE__ */ new Map();
|
|
767
815
|
this._sessions = /* @__PURE__ */ new Map();
|
|
816
|
+
this._pendingInteractionBindings = /* @__PURE__ */ new Map();
|
|
817
|
+
this._verifiedBleReconnectTargets = /* @__PURE__ */ new Map();
|
|
768
818
|
this._uiRegistry = new import_hwk_adapter_core3.UiRequestRegistry();
|
|
769
819
|
// BTC App rejects account index >= 100 unless display=true. Cached per
|
|
770
820
|
// adapter instance: first 100+ path asks the user once via UI request,
|
|
@@ -778,10 +828,30 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
778
828
|
this._deviceAuthenticityQueueTail = Promise.resolve();
|
|
779
829
|
// Shared across concurrent callers — only `cancel()` aborts.
|
|
780
830
|
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._activeInteractionJobs = /* @__PURE__ */ new Set();
|
|
838
|
+
this._pendingInteractionDisconnects = /* @__PURE__ */ new Set();
|
|
781
839
|
this._installProgressLastEmittedValue = -Infinity;
|
|
782
840
|
this.allNetworkGetAddress = createAllNetworkGetAddress({
|
|
783
841
|
callChain: this.callChain.bind(this),
|
|
784
|
-
getChainFingerprint: (connectId, chain) =>
|
|
842
|
+
getChainFingerprint: async (connectId, chain, context) => {
|
|
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
|
+
retainInteraction: (interactionId) => this._interactions.retain(interactionId),
|
|
854
|
+
errorToFailure: (error) => this.errorToFailure(error)
|
|
785
855
|
});
|
|
786
856
|
// ---------------------------------------------------------------------------
|
|
787
857
|
// Private helpers
|
|
@@ -791,7 +861,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
791
861
|
*
|
|
792
862
|
* - If a session already exists for the given connectId, reuse it.
|
|
793
863
|
* - If ANY session exists (Ledger IDs are ephemeral), reuse it.
|
|
794
|
-
* - Otherwise: search →
|
|
864
|
+
* - Otherwise: search → one USB device auto-connects; multiple asks the host to choose.
|
|
795
865
|
*/
|
|
796
866
|
// Mutex for ensureConnected — prevents concurrent calls from establishing duplicate connections
|
|
797
867
|
this._connectingPromise = null;
|
|
@@ -808,6 +878,12 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
808
878
|
});
|
|
809
879
|
};
|
|
810
880
|
this.deviceDisconnectHandler = (data) => {
|
|
881
|
+
const activeInteraction = this._interactions.findActiveByConnectionKey(data.connectId);
|
|
882
|
+
if (activeInteraction && this._activeInteractionJobs.has(activeInteraction.interactionId)) {
|
|
883
|
+
this._pendingInteractionDisconnects.add(activeInteraction.interactionId);
|
|
884
|
+
} else {
|
|
885
|
+
this._interactions.endByConnectionKey(data.connectId, "disconnect");
|
|
886
|
+
}
|
|
811
887
|
this._discoveredDevices.delete(data.connectId);
|
|
812
888
|
this._sessions.delete(data.connectId);
|
|
813
889
|
this.emitter.emit(import_hwk_adapter_core3.DEVICE.DISCONNECT, {
|
|
@@ -864,11 +940,28 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
864
940
|
this._jobQueue = new import_hwk_adapter_core3.DeviceJobQueue();
|
|
865
941
|
this.registerEventListeners();
|
|
866
942
|
}
|
|
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
|
+
}
|
|
867
955
|
// Transport
|
|
868
956
|
get activeTransport() {
|
|
869
|
-
return
|
|
957
|
+
return this._isBleConnection() ? "ble" : "hid";
|
|
870
958
|
}
|
|
871
959
|
getAvailableTransports() {
|
|
960
|
+
if (this.connector.availableTransports) {
|
|
961
|
+
return this.connector.availableTransports.map(
|
|
962
|
+
(transport) => transport === "ble" ? "ble" : "hid"
|
|
963
|
+
);
|
|
964
|
+
}
|
|
872
965
|
return this.activeTransport ? [this.activeTransport] : [];
|
|
873
966
|
}
|
|
874
967
|
// Connector is bound at construction; switching requires a new adapter.
|
|
@@ -885,21 +978,39 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
885
978
|
* The next operation will re-discover and re-connect automatically.
|
|
886
979
|
*/
|
|
887
980
|
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._interactions.endAll("runtime-reset");
|
|
989
|
+
this._doConnectAbortController?.abort();
|
|
888
990
|
this._discoveredDevices.clear();
|
|
889
991
|
this._sessions.clear();
|
|
992
|
+
this._verifiedBleReconnectTargets.clear();
|
|
890
993
|
this._connectingPromise = null;
|
|
994
|
+
this._doConnectAbortController = null;
|
|
891
995
|
this._uiRegistry.reset();
|
|
892
996
|
this._jobQueue.clear();
|
|
893
997
|
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
|
+
});
|
|
894
1009
|
}
|
|
895
1010
|
async dispose() {
|
|
896
|
-
this.
|
|
897
|
-
this._jobQueue.clear();
|
|
1011
|
+
await this._resetStateAndDisconnectSessions();
|
|
898
1012
|
this.unregisterEventListeners();
|
|
899
1013
|
this.connector.reset();
|
|
900
|
-
this._discoveredDevices.clear();
|
|
901
|
-
this._sessions.clear();
|
|
902
|
-
this._btcHighIndexConfirmedThisSession = false;
|
|
903
1014
|
this.emitter.removeAllListeners();
|
|
904
1015
|
}
|
|
905
1016
|
uiResponse(response) {
|
|
@@ -909,17 +1020,32 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
909
1020
|
// Device management
|
|
910
1021
|
// ---------------------------------------------------------------------------
|
|
911
1022
|
async searchDevices(options) {
|
|
1023
|
+
return this._searchDevices(options);
|
|
1024
|
+
}
|
|
1025
|
+
async _searchDevices(options, signal) {
|
|
912
1026
|
debugLog("[LedgerAdapter][REQ]", { method: "searchDevices", params: options });
|
|
913
1027
|
try {
|
|
914
1028
|
if (options?.resetSession) {
|
|
915
|
-
this.
|
|
916
|
-
|
|
917
|
-
this.
|
|
918
|
-
|
|
919
|
-
|
|
1029
|
+
await this._resetStateAndDisconnectSessions();
|
|
1030
|
+
} else {
|
|
1031
|
+
await this._connectorTeardownTail;
|
|
1032
|
+
}
|
|
1033
|
+
await this._ensureDevicePermission(void 0, void 0, signal);
|
|
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
|
+
});
|
|
920
1048
|
}
|
|
921
|
-
await this._ensureDevicePermission();
|
|
922
|
-
const devices = await this.connector.searchDevices();
|
|
923
1049
|
this._discoveredDevices.clear();
|
|
924
1050
|
for (const d of devices) {
|
|
925
1051
|
if (d.connectId) {
|
|
@@ -927,7 +1053,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
927
1053
|
}
|
|
928
1054
|
}
|
|
929
1055
|
if (this._discoveredDevices.size === 0) {
|
|
930
|
-
await this._ensureDevicePermission();
|
|
1056
|
+
await this._ensureDevicePermission(void 0, void 0, signal);
|
|
931
1057
|
}
|
|
932
1058
|
const result = Array.from(this._discoveredDevices.values());
|
|
933
1059
|
debugLog("[LedgerAdapter][RES]", {
|
|
@@ -946,41 +1072,172 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
946
1072
|
throw err;
|
|
947
1073
|
}
|
|
948
1074
|
}
|
|
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
|
+
}
|
|
949
1096
|
// USB single-session invariant: evict all sessions, best-effort (see connectDevice).
|
|
950
|
-
async _evictAllSessions() {
|
|
1097
|
+
async _evictAllSessions(preserveInteractionId) {
|
|
1098
|
+
this._interactions.endAll("explicit", preserveInteractionId);
|
|
951
1099
|
if (this._sessions.size === 0) return;
|
|
952
1100
|
const stale = [...this._sessions.values()];
|
|
953
1101
|
this._sessions.clear();
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1102
|
+
await this._runConnectorTeardown(async () => {
|
|
1103
|
+
for (const sid of stale) {
|
|
1104
|
+
try {
|
|
1105
|
+
await this.connector.disconnect(sid);
|
|
1106
|
+
} catch {
|
|
1107
|
+
}
|
|
958
1108
|
}
|
|
959
|
-
}
|
|
1109
|
+
});
|
|
960
1110
|
}
|
|
961
1111
|
static _createDeviceBusyError(method) {
|
|
962
1112
|
return Object.assign(new Error(`Ledger device is busy while calling ${method}`), {
|
|
963
1113
|
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceBusy
|
|
964
1114
|
});
|
|
965
1115
|
}
|
|
966
|
-
async connectDevice(
|
|
1116
|
+
async connectDevice(searchTargetId) {
|
|
1117
|
+
const connected = await this._connectTarget(searchTargetId);
|
|
1118
|
+
if (!connected.success) return connected;
|
|
1119
|
+
return this._createInteraction(searchTargetId, connected.payload);
|
|
1120
|
+
}
|
|
1121
|
+
async acquireInteraction(connectId, context) {
|
|
1122
|
+
try {
|
|
1123
|
+
return await this._jobQueue.enqueue(
|
|
1124
|
+
connectId || "__ledger_acquire__",
|
|
1125
|
+
async (signal) => {
|
|
1126
|
+
const transport = this._isBleConnection() ? "ble" : "usb";
|
|
1127
|
+
const hint = context.knownConnections?.find(
|
|
1128
|
+
(connection) => connection.transport === transport
|
|
1129
|
+
);
|
|
1130
|
+
const target = hint && hint.transport !== "qr" ? hint.connectId : connectId;
|
|
1131
|
+
await this._ensureDevicePermission(target, void 0, signal);
|
|
1132
|
+
const attempt = {
|
|
1133
|
+
...context,
|
|
1134
|
+
extra: context.extra ? { ...context.extra } : void 0,
|
|
1135
|
+
previousConnectId: target
|
|
1136
|
+
};
|
|
1137
|
+
try {
|
|
1138
|
+
const resolvedConnectId = await this.ensureConnected(
|
|
1139
|
+
target,
|
|
1140
|
+
signal,
|
|
1141
|
+
true,
|
|
1142
|
+
void 0,
|
|
1143
|
+
attempt
|
|
1144
|
+
);
|
|
1145
|
+
_LedgerAdapter._throwIfAborted(signal);
|
|
1146
|
+
const result = this._createInteraction(connectId, resolvedConnectId);
|
|
1147
|
+
if (result.success && attempt.selectedConnection) {
|
|
1148
|
+
this._pendingInteractionBindings.set(result.payload, attempt);
|
|
1149
|
+
}
|
|
1150
|
+
return result;
|
|
1151
|
+
} catch (error) {
|
|
1152
|
+
this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
|
|
1153
|
+
throw error;
|
|
1154
|
+
}
|
|
1155
|
+
},
|
|
1156
|
+
{
|
|
1157
|
+
label: "acquireInteraction",
|
|
1158
|
+
rejectIfBusy: true,
|
|
1159
|
+
busyError: _LedgerAdapter._createDeviceBusyError("acquireInteraction")
|
|
1160
|
+
}
|
|
1161
|
+
);
|
|
1162
|
+
} catch (error) {
|
|
1163
|
+
return this.errorToFailure(error);
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
_createInteraction(searchTargetId, resolvedConnectId) {
|
|
1167
|
+
this._interactions.endByConnectionKey(resolvedConnectId, "explicit");
|
|
1168
|
+
const sessionId = this._sessions.get(resolvedConnectId);
|
|
1169
|
+
if (sessionId) this._interactions.endByConnectionKey(sessionId, "explicit");
|
|
1170
|
+
const device = this._discoveredDevices.get(resolvedConnectId) ?? {
|
|
1171
|
+
vendor: "ledger",
|
|
1172
|
+
model: "unknown",
|
|
1173
|
+
firmwareVersion: "",
|
|
1174
|
+
deviceId: "",
|
|
1175
|
+
connectId: resolvedConnectId,
|
|
1176
|
+
connectionType: this.connector.connectionType
|
|
1177
|
+
};
|
|
1178
|
+
const interaction = this._interactions.create({
|
|
1179
|
+
searchTargetId,
|
|
1180
|
+
connectId: resolvedConnectId,
|
|
1181
|
+
device,
|
|
1182
|
+
connectionKeys: [this._sessions.get(resolvedConnectId) ?? ""]
|
|
1183
|
+
});
|
|
1184
|
+
return (0, import_hwk_adapter_core3.success)(interaction.interactionId);
|
|
1185
|
+
}
|
|
1186
|
+
async _connectTarget(connectId, preserveInteractionId, signal) {
|
|
967
1187
|
debugLog("[LedgerAdapter][REQ]", { method: "connectDevice", connectId, params: { connectId } });
|
|
968
1188
|
try {
|
|
969
|
-
|
|
1189
|
+
this._assertConnectorReady("connectDevice");
|
|
1190
|
+
const discoveredType = this._discoveredDevices.get(connectId)?.connectionType;
|
|
1191
|
+
if (discoveredType === "usb" || discoveredType === "ble") {
|
|
1192
|
+
this._activeConnectionType = discoveredType;
|
|
1193
|
+
}
|
|
1194
|
+
if (this._isBleConnection() && !connectId) {
|
|
970
1195
|
throw Object.assign(new Error("Ledger BLE connectId is required."), {
|
|
971
1196
|
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
|
|
972
1197
|
});
|
|
973
1198
|
}
|
|
974
|
-
|
|
975
|
-
|
|
1199
|
+
await this._ensureDevicePermission(connectId, void 0, signal);
|
|
1200
|
+
if (signal) _LedgerAdapter._throwIfAborted(signal);
|
|
1201
|
+
if (this.connector.availableTransports && this.connector.availableTransports.length > 1) {
|
|
1202
|
+
await this._evictAllSessions(preserveInteractionId);
|
|
1203
|
+
} else if (this._isBleConnection()) {
|
|
1204
|
+
const previousSessionId = this._sessions.get(connectId);
|
|
1205
|
+
this._interactions.endByConnectionKey(connectId, "explicit", preserveInteractionId);
|
|
1206
|
+
if (previousSessionId) {
|
|
1207
|
+
this._interactions.endByConnectionKey(
|
|
1208
|
+
previousSessionId,
|
|
1209
|
+
"explicit",
|
|
1210
|
+
preserveInteractionId
|
|
1211
|
+
);
|
|
1212
|
+
this._sessions.delete(connectId);
|
|
1213
|
+
await this.connector.disconnect(previousSessionId).catch(() => void 0);
|
|
1214
|
+
}
|
|
1215
|
+
} else {
|
|
1216
|
+
await this._evictAllSessions(preserveInteractionId);
|
|
976
1217
|
}
|
|
977
|
-
|
|
978
|
-
const
|
|
979
|
-
this.
|
|
1218
|
+
if (signal) _LedgerAdapter._throwIfAborted(signal);
|
|
1219
|
+
const stateGeneration = this._stateGeneration;
|
|
1220
|
+
const releaseOperation = this._retainConnectorOperation(`connect:${connectId}`);
|
|
1221
|
+
let session;
|
|
1222
|
+
try {
|
|
1223
|
+
session = this.connector.availableTransports?.length ? await this.connector.connect(connectId, {
|
|
1224
|
+
transportType: this._activeConnectionType ?? "usb"
|
|
1225
|
+
}) : await this.connector.connect(connectId);
|
|
1226
|
+
if (signal?.aborted || stateGeneration !== this._stateGeneration) {
|
|
1227
|
+
await this.connector.disconnect(session.sessionId).catch(() => void 0);
|
|
1228
|
+
throw Object.assign(new Error("Ledger connection aborted"), {
|
|
1229
|
+
code: import_hwk_adapter_core3.HardwareErrorCode.UserAborted
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
} finally {
|
|
1233
|
+
releaseOperation();
|
|
1234
|
+
}
|
|
1235
|
+
const resolvedConnectId = session.deviceInfo?.connectId || connectId;
|
|
1236
|
+
this._sessions.set(resolvedConnectId, session.sessionId);
|
|
980
1237
|
if (session.deviceInfo) {
|
|
981
|
-
this._discoveredDevices.set(
|
|
1238
|
+
this._discoveredDevices.set(resolvedConnectId, session.deviceInfo);
|
|
982
1239
|
}
|
|
983
|
-
const result = (0, import_hwk_adapter_core3.success)(
|
|
1240
|
+
const result = (0, import_hwk_adapter_core3.success)(resolvedConnectId);
|
|
984
1241
|
debugLog("[LedgerAdapter][RES]", { method: "connectDevice", success: true, payload: result });
|
|
985
1242
|
return result;
|
|
986
1243
|
} catch (err) {
|
|
@@ -993,30 +1250,60 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
993
1250
|
return failureResult;
|
|
994
1251
|
}
|
|
995
1252
|
}
|
|
996
|
-
async
|
|
1253
|
+
async releaseInteraction(interactionId) {
|
|
1254
|
+
const interaction = this._interactions.find(interactionId);
|
|
1255
|
+
if (!interaction) {
|
|
1256
|
+
this._interactions.resolve(interactionId);
|
|
1257
|
+
return;
|
|
1258
|
+
}
|
|
1259
|
+
const endedInteraction = this._interactions.end(interactionId, "explicit");
|
|
1260
|
+
if (!endedInteraction) return;
|
|
1261
|
+
const { connectId } = interaction;
|
|
997
1262
|
debugLog("[LedgerAdapter][REQ]", {
|
|
998
|
-
method: "
|
|
1263
|
+
method: "releaseInteraction",
|
|
999
1264
|
connectId,
|
|
1000
1265
|
params: { connectId }
|
|
1001
1266
|
});
|
|
1002
1267
|
try {
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
await this.connector.disconnect(sessionId);
|
|
1006
|
-
this._sessions.delete(connectId);
|
|
1007
|
-
}
|
|
1008
|
-
debugLog("[LedgerAdapter][RES]", { method: "disconnectDevice", success: true });
|
|
1268
|
+
await this._releaseInteractionConnection(endedInteraction);
|
|
1269
|
+
debugLog("[LedgerAdapter][RES]", { method: "releaseInteraction", success: true });
|
|
1009
1270
|
} catch (err) {
|
|
1010
1271
|
const e = err;
|
|
1011
1272
|
debugLog("[LedgerAdapter][RES]", {
|
|
1012
|
-
method: "
|
|
1273
|
+
method: "releaseInteraction",
|
|
1013
1274
|
success: false,
|
|
1014
1275
|
error: { message: e?.message, _tag: e?._tag, code: e?.code ?? e?.errorCode }
|
|
1015
1276
|
});
|
|
1016
1277
|
throw err;
|
|
1017
1278
|
}
|
|
1018
1279
|
}
|
|
1019
|
-
async
|
|
1280
|
+
async _releaseInteractionConnection(interaction) {
|
|
1281
|
+
const sessionIds = /* @__PURE__ */ new Set();
|
|
1282
|
+
for (const [connectId, sessionId] of this._sessions) {
|
|
1283
|
+
if (connectId === interaction.connectId || interaction.connectionKeys.includes(connectId) || interaction.connectionKeys.includes(sessionId)) {
|
|
1284
|
+
this._sessions.delete(connectId);
|
|
1285
|
+
sessionIds.add(sessionId);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
for (const sessionId of sessionIds) {
|
|
1289
|
+
await this._runConnectorTeardown(
|
|
1290
|
+
() => this.connector.disconnect(sessionId).catch(() => void 0)
|
|
1291
|
+
);
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
async _releaseLostInteractionConnection(interactionId) {
|
|
1295
|
+
const endedInteraction = this._interactions.end(interactionId, "disconnect");
|
|
1296
|
+
if (!endedInteraction) return;
|
|
1297
|
+
this._discoveredDevices.delete(endedInteraction.connectId);
|
|
1298
|
+
await this._releaseInteractionConnection(endedInteraction);
|
|
1299
|
+
}
|
|
1300
|
+
async getDeviceInfo(connectIdOrInteractionId, deviceId) {
|
|
1301
|
+
let connectId;
|
|
1302
|
+
try {
|
|
1303
|
+
connectId = (0, import_hwk_adapter_core3.isHardwareInteractionId)(connectIdOrInteractionId) ? this._interactions.resolve(connectIdOrInteractionId).connectId : connectIdOrInteractionId;
|
|
1304
|
+
} catch (error) {
|
|
1305
|
+
return this.errorToFailure(error);
|
|
1306
|
+
}
|
|
1020
1307
|
debugLog("[LedgerAdapter][REQ]", {
|
|
1021
1308
|
method: "getDeviceInfo",
|
|
1022
1309
|
connectId,
|
|
@@ -1055,7 +1342,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1055
1342
|
}
|
|
1056
1343
|
}
|
|
1057
1344
|
getSupportedChains() {
|
|
1058
|
-
return ["evm", "btc", "sol", "tron"];
|
|
1345
|
+
return ["evm", "btc", "sol", "tron", "zcash"];
|
|
1059
1346
|
}
|
|
1060
1347
|
// ---------------------------------------------------------------------------
|
|
1061
1348
|
// Chain call helper
|
|
@@ -1091,13 +1378,21 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1091
1378
|
if (params && typeof params === "object") {
|
|
1092
1379
|
const {
|
|
1093
1380
|
autoInstallApp,
|
|
1381
|
+
interactionId,
|
|
1094
1382
|
passphraseState: _passphraseState,
|
|
1095
1383
|
useEmptyPassphrase: _useEmptyPassphrase,
|
|
1384
|
+
knownConnections,
|
|
1385
|
+
extra,
|
|
1386
|
+
allowDeviceSelection,
|
|
1096
1387
|
...rest
|
|
1097
1388
|
} = params;
|
|
1098
1389
|
return {
|
|
1099
1390
|
commonParams: {
|
|
1100
|
-
autoInstallApp: typeof autoInstallApp === "boolean" ? autoInstallApp : void 0
|
|
1391
|
+
autoInstallApp: typeof autoInstallApp === "boolean" ? autoInstallApp : void 0,
|
|
1392
|
+
interactionId: typeof interactionId === "string" ? interactionId : void 0,
|
|
1393
|
+
knownConnections,
|
|
1394
|
+
extra,
|
|
1395
|
+
allowDeviceSelection: typeof allowDeviceSelection === "boolean" ? allowDeviceSelection : void 0
|
|
1101
1396
|
},
|
|
1102
1397
|
rest
|
|
1103
1398
|
};
|
|
@@ -1273,6 +1568,27 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1273
1568
|
);
|
|
1274
1569
|
}
|
|
1275
1570
|
// ---------------------------------------------------------------------------
|
|
1571
|
+
// Zcash chain methods (viewing key + shielded address reads; Zcash app >= 3.8.0)
|
|
1572
|
+
// ---------------------------------------------------------------------------
|
|
1573
|
+
zcashGetFullViewingKey(connectId, deviceId, params) {
|
|
1574
|
+
return this.callChainWithMergedParams(
|
|
1575
|
+
connectId,
|
|
1576
|
+
deviceId,
|
|
1577
|
+
"zcash",
|
|
1578
|
+
"zcashGetFullViewingKey",
|
|
1579
|
+
params
|
|
1580
|
+
);
|
|
1581
|
+
}
|
|
1582
|
+
zcashGetShieldedAddress(connectId, deviceId, params) {
|
|
1583
|
+
return this.callChainWithMergedParams(
|
|
1584
|
+
connectId,
|
|
1585
|
+
deviceId,
|
|
1586
|
+
"zcash",
|
|
1587
|
+
"zcashGetShieldedAddress",
|
|
1588
|
+
params
|
|
1589
|
+
);
|
|
1590
|
+
}
|
|
1591
|
+
// ---------------------------------------------------------------------------
|
|
1276
1592
|
// App management — OS-level Ledger app install / list. Bypasses fingerprint
|
|
1277
1593
|
// and chain-handler dispatch; installApp progress is forwarded to the adapter
|
|
1278
1594
|
// emitter via 'ui-event' AppInstallProgress events.
|
|
@@ -1361,7 +1677,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1361
1677
|
);
|
|
1362
1678
|
}
|
|
1363
1679
|
await this.connector.configure({ ledgerGenuineCheckWebSocketUrl: relayUrl });
|
|
1364
|
-
this.
|
|
1680
|
+
await this._resetStateAndDisconnectSessions();
|
|
1365
1681
|
}
|
|
1366
1682
|
const result = await this.connectorCall(connectId, "getDeviceGenuineCheck", {});
|
|
1367
1683
|
if (!result.isGenuine) {
|
|
@@ -1387,10 +1703,10 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1387
1703
|
if (relayUrl) {
|
|
1388
1704
|
try {
|
|
1389
1705
|
await this.connector.configure?.({ ledgerGenuineCheckWebSocketUrl: void 0 });
|
|
1390
|
-
this.
|
|
1706
|
+
await this._resetStateAndDisconnectSessions();
|
|
1391
1707
|
} catch {
|
|
1392
1708
|
this.connector.reset();
|
|
1393
|
-
this.
|
|
1709
|
+
await this._resetStateAndDisconnectSessions();
|
|
1394
1710
|
}
|
|
1395
1711
|
}
|
|
1396
1712
|
}
|
|
@@ -1413,13 +1729,36 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1413
1729
|
}
|
|
1414
1730
|
}, 2e3);
|
|
1415
1731
|
this._uiRegistry.cancel();
|
|
1416
|
-
|
|
1417
|
-
|
|
1732
|
+
this._finishBleBinding("cancelled");
|
|
1733
|
+
const activeJobId = this._jobQueue.getActiveJob()?.deviceId;
|
|
1734
|
+
let interactionId;
|
|
1735
|
+
if ((0, import_hwk_adapter_core3.isHardwareInteractionId)(connectId)) {
|
|
1736
|
+
interactionId = connectId;
|
|
1737
|
+
} else if (!connectId && (0, import_hwk_adapter_core3.isHardwareInteractionId)(activeJobId)) {
|
|
1738
|
+
interactionId = activeJobId;
|
|
1739
|
+
}
|
|
1740
|
+
let resolvedConnectId = connectId;
|
|
1741
|
+
if (interactionId) {
|
|
1742
|
+
try {
|
|
1743
|
+
resolvedConnectId = this._interactions.resolve(interactionId).connectId;
|
|
1744
|
+
} catch {
|
|
1745
|
+
resolvedConnectId = void 0;
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
const interactionForPhysicalId = !interactionId && connectId ? this._interactions.findActiveByConnectionKey(connectId) : void 0;
|
|
1749
|
+
const queueKey = interactionId ?? (activeJobId === connectId ? connectId : interactionForPhysicalId?.interactionId) ?? connectId;
|
|
1750
|
+
const pendingInteractionId = interactionId ?? interactionForPhysicalId?.interactionId;
|
|
1751
|
+
if (!connectId) this._pendingInteractionBindings.clear();
|
|
1752
|
+
else if (pendingInteractionId) {
|
|
1753
|
+
this._pendingInteractionBindings.delete(pendingInteractionId);
|
|
1754
|
+
}
|
|
1755
|
+
if (queueKey) {
|
|
1756
|
+
this._jobQueue.cancelActiveAndPending(queueKey, userAbortReason);
|
|
1418
1757
|
} else {
|
|
1419
1758
|
this._jobQueue.cancelActiveAndPending(void 0, userAbortReason);
|
|
1420
1759
|
}
|
|
1421
|
-
if (
|
|
1422
|
-
const sessionId = this._sessions.get(
|
|
1760
|
+
if (resolvedConnectId) {
|
|
1761
|
+
const sessionId = this._sessions.get(resolvedConnectId) ?? resolvedConnectId;
|
|
1423
1762
|
void this.connector.cancel(sessionId);
|
|
1424
1763
|
} else {
|
|
1425
1764
|
for (const sid of this._sessions.values()) void this.connector.cancel(sid);
|
|
@@ -1431,40 +1770,83 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1431
1770
|
// ---------------------------------------------------------------------------
|
|
1432
1771
|
// Chain fingerprint
|
|
1433
1772
|
// ---------------------------------------------------------------------------
|
|
1773
|
+
/** A non-empty deviceId is an expected chain fingerprint, not a transport identifier. */
|
|
1434
1774
|
async getChainFingerprint(connectId, deviceId, chain) {
|
|
1435
1775
|
try {
|
|
1436
1776
|
const fingerprint = await this._computeChainFingerprint(
|
|
1437
1777
|
chain,
|
|
1438
1778
|
(method, params) => this.connectorCall(connectId, method, params, void 0, deviceId)
|
|
1439
1779
|
);
|
|
1780
|
+
if (deviceId) {
|
|
1781
|
+
if (fingerprint !== deviceId) {
|
|
1782
|
+
return (0, import_hwk_adapter_core3.failure)(
|
|
1783
|
+
import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch,
|
|
1784
|
+
formatDeviceMismatchError(deviceId, fingerprint)
|
|
1785
|
+
);
|
|
1786
|
+
}
|
|
1787
|
+
if ((0, import_hwk_adapter_core3.isHardwareInteractionId)(connectId)) {
|
|
1788
|
+
const interaction = this._interactions.resolve(connectId);
|
|
1789
|
+
await this._publishVerifiedBleBinding(
|
|
1790
|
+
interaction.connectId,
|
|
1791
|
+
chain,
|
|
1792
|
+
fingerprint,
|
|
1793
|
+
void 0,
|
|
1794
|
+
connectId
|
|
1795
|
+
);
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1440
1798
|
return (0, import_hwk_adapter_core3.success)(fingerprint);
|
|
1441
1799
|
} catch (err) {
|
|
1442
1800
|
debugError("[LedgerAdapter] getChainFingerprint error:", chain, err);
|
|
1443
1801
|
return this.errorToFailure(err);
|
|
1444
1802
|
}
|
|
1445
1803
|
}
|
|
1446
|
-
/**
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1804
|
+
/** Discovery may select a BLE target before a later call verifies its wallet. */
|
|
1805
|
+
async _publishVerifiedBleBinding(connectId, chain, fingerprint, attempt, interactionId, previousConnectId = "", signal) {
|
|
1806
|
+
const binding = interactionId ? this._pendingInteractionBindings.get(interactionId) : attempt;
|
|
1807
|
+
if (!this._isBleConnection() || binding?.selectedConnection?.connectId !== connectId) return;
|
|
1808
|
+
const acknowledged = await (0, import_hwk_adapter_core3.requestSaveDeviceBinding)(
|
|
1809
|
+
this.emitter,
|
|
1810
|
+
this._uiRegistry,
|
|
1811
|
+
{
|
|
1812
|
+
selectionRequestId: binding.selectedConnection.requestId,
|
|
1813
|
+
connection: { transport: "ble", connectId },
|
|
1814
|
+
identity: { vendor: "ledger", type: "chainFingerprint", chain, value: fingerprint },
|
|
1815
|
+
extra: binding.extra
|
|
1816
|
+
},
|
|
1817
|
+
signal
|
|
1818
|
+
);
|
|
1819
|
+
if (this._bindingSelectionRequestId === binding.selectedConnection.requestId) {
|
|
1820
|
+
this._bindingSelectionRequestId = void 0;
|
|
1821
|
+
}
|
|
1822
|
+
if (interactionId) {
|
|
1823
|
+
this._interactions.resolve(interactionId);
|
|
1824
|
+
this._pendingInteractionBindings.delete(interactionId);
|
|
1825
|
+
}
|
|
1826
|
+
if (acknowledged) return;
|
|
1827
|
+
this.emitter.emit(import_hwk_adapter_core3.DEVICE.LEDGER_CONNECTION_VERIFIED, {
|
|
1828
|
+
type: import_hwk_adapter_core3.DEVICE.LEDGER_CONNECTION_VERIFIED,
|
|
1829
|
+
payload: {
|
|
1830
|
+
previousConnectId: binding.previousConnectId ?? previousConnectId,
|
|
1831
|
+
connectId,
|
|
1454
1832
|
chain,
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
return { success: true };
|
|
1833
|
+
fingerprint,
|
|
1834
|
+
extra: binding.extra,
|
|
1835
|
+
selectionRequestId: binding.selectedConnection.requestId
|
|
1459
1836
|
}
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1837
|
+
});
|
|
1838
|
+
}
|
|
1839
|
+
/** Verify on the acquired session without re-entering the job queue. */
|
|
1840
|
+
async _verifyDeviceFingerprintWithSession(sessionId, deviceId, chain) {
|
|
1841
|
+
if (!deviceId) return { success: true };
|
|
1842
|
+
const fingerprint = await this._computeChainFingerprint(
|
|
1843
|
+
chain,
|
|
1844
|
+
(method, params) => this._callConnector(sessionId, method, params)
|
|
1845
|
+
);
|
|
1846
|
+
if (fingerprint === deviceId) {
|
|
1847
|
+
return { success: true };
|
|
1467
1848
|
}
|
|
1849
|
+
return { success: false, expected: deviceId, actual: fingerprint };
|
|
1468
1850
|
}
|
|
1469
1851
|
/**
|
|
1470
1852
|
* Compute the chain fingerprint via a caller-supplied call strategy.
|
|
@@ -1493,6 +1875,8 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1493
1875
|
address = (await callMethod("solGetAddress", { path, showOnDevice: false })).address;
|
|
1494
1876
|
} else if (chain === "tron") {
|
|
1495
1877
|
address = (await callMethod("tronGetAddress", { path, showOnDevice: false })).address;
|
|
1878
|
+
} else if (chain === "zcash") {
|
|
1879
|
+
address = (await callMethod("zcashGetShieldedAddress", { path, showOnDevice: false })).address;
|
|
1496
1880
|
} else {
|
|
1497
1881
|
throw new Error(`Unsupported chain for fingerprint: ${chain}`);
|
|
1498
1882
|
}
|
|
@@ -1622,16 +2006,17 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1622
2006
|
// Layer 1 entry. Caller signal only races the outer awaiter; the shared
|
|
1623
2007
|
// `_doConnect` runs under its own internal controller so caller A's cancel
|
|
1624
2008
|
// doesn't kill caller B's await.
|
|
1625
|
-
async ensureConnected(connectId, signal, allowUsbEphemeralFallback = false) {
|
|
2009
|
+
async ensureConnected(connectId, signal, allowUsbEphemeralFallback = false, preserveInteractionId, context) {
|
|
1626
2010
|
if (signal.aborted) _LedgerAdapter._throwIfAborted(signal);
|
|
1627
|
-
|
|
2011
|
+
this._assertConnectorReady("connectDevice");
|
|
2012
|
+
if (this._isBleConnection() && !connectId && !allowUsbEphemeralFallback) {
|
|
1628
2013
|
throw Object.assign(new Error("Ledger BLE connectId is required."), {
|
|
1629
2014
|
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
|
|
1630
2015
|
});
|
|
1631
2016
|
}
|
|
1632
2017
|
if (connectId && this._sessions.has(connectId)) return connectId;
|
|
1633
2018
|
if (!connectId && this._sessions.size > 0) {
|
|
1634
|
-
if (!
|
|
2019
|
+
if (!this._isBleConnection() && this._sessions.size > 1) {
|
|
1635
2020
|
throw Object.assign(
|
|
1636
2021
|
new Error(
|
|
1637
2022
|
"Ledger USB session invariant violated: more than one session is active. Please reconnect the device."
|
|
@@ -1641,15 +2026,24 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1641
2026
|
}
|
|
1642
2027
|
return this._sessions.keys().next().value;
|
|
1643
2028
|
}
|
|
1644
|
-
if (!this._connectingPromise) {
|
|
1645
|
-
|
|
1646
|
-
|
|
2029
|
+
if (!this._connectingPromise || this._doConnectAbortController?.signal.aborted) {
|
|
2030
|
+
const controller = new AbortController();
|
|
2031
|
+
this._doConnectAbortController = controller;
|
|
2032
|
+
const innerSignal = controller.signal;
|
|
1647
2033
|
this._connectingPromise = (async () => {
|
|
1648
2034
|
try {
|
|
1649
|
-
return await this._doConnect(
|
|
2035
|
+
return await this._doConnect(
|
|
2036
|
+
innerSignal,
|
|
2037
|
+
connectId,
|
|
2038
|
+
allowUsbEphemeralFallback,
|
|
2039
|
+
preserveInteractionId,
|
|
2040
|
+
context
|
|
2041
|
+
);
|
|
1650
2042
|
} finally {
|
|
1651
|
-
this.
|
|
1652
|
-
|
|
2043
|
+
if (this._doConnectAbortController === controller) {
|
|
2044
|
+
this._connectingPromise = null;
|
|
2045
|
+
this._doConnectAbortController = null;
|
|
2046
|
+
}
|
|
1653
2047
|
}
|
|
1654
2048
|
})();
|
|
1655
2049
|
}
|
|
@@ -1658,22 +2052,49 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1658
2052
|
// Layer 1 main loop — the ONLY place in SDK that emits unlock dialog.
|
|
1659
2053
|
// Bounded by MAX_DOCONNECT_CONFIRMS — after N Confirms with no progress,
|
|
1660
2054
|
// throw DeviceNotFound so the user is kicked out of the loop.
|
|
1661
|
-
async _doConnect(internalSignal, targetConnectId, allowUsbEphemeralFallback = false) {
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
2055
|
+
async _doConnect(internalSignal, targetConnectId, allowUsbEphemeralFallback = false, preserveInteractionId, context) {
|
|
2056
|
+
_LedgerAdapter._throwIfAborted(internalSignal);
|
|
2057
|
+
if (this.connector.availableTransports?.includes("usb") && this.connector.availableTransports.includes("ble")) {
|
|
2058
|
+
this._activeConnectionType = "usb";
|
|
2059
|
+
const usbDevices = await this._searchDevices({ transportType: "usb" }, internalSignal);
|
|
2060
|
+
_LedgerAdapter._throwIfAborted(internalSignal);
|
|
2061
|
+
if (usbDevices.length > 0) {
|
|
2062
|
+
const knownUsb = context?.knownConnections?.find(
|
|
2063
|
+
(connection) => connection.transport === "usb"
|
|
2064
|
+
);
|
|
2065
|
+
const usbTarget = knownUsb?.transport === "usb" ? knownUsb.connectId : usbDevices.find((device) => device.connectId === targetConnectId)?.connectId;
|
|
2066
|
+
return this._connectFirstOrSelect(
|
|
2067
|
+
usbDevices,
|
|
2068
|
+
usbTarget,
|
|
2069
|
+
allowUsbEphemeralFallback,
|
|
2070
|
+
preserveInteractionId,
|
|
2071
|
+
context,
|
|
2072
|
+
internalSignal
|
|
2073
|
+
);
|
|
1676
2074
|
}
|
|
2075
|
+
this._activeConnectionType = "ble";
|
|
2076
|
+
const knownBle = context?.knownConnections?.find(
|
|
2077
|
+
(connection) => connection.transport === "ble"
|
|
2078
|
+
);
|
|
2079
|
+
if (knownBle?.transport === "ble") {
|
|
2080
|
+
return this._connectDeviceOrThrow(
|
|
2081
|
+
knownBle.connectId,
|
|
2082
|
+
preserveInteractionId,
|
|
2083
|
+
internalSignal
|
|
2084
|
+
);
|
|
2085
|
+
}
|
|
2086
|
+
const bleDevices = await this._searchDevices({ transportType: "ble" }, internalSignal);
|
|
2087
|
+
return this._connectFirstOrSelect(
|
|
2088
|
+
bleDevices,
|
|
2089
|
+
void 0,
|
|
2090
|
+
allowUsbEphemeralFallback,
|
|
2091
|
+
preserveInteractionId,
|
|
2092
|
+
context,
|
|
2093
|
+
internalSignal
|
|
2094
|
+
);
|
|
2095
|
+
}
|
|
2096
|
+
if (this._isBleConnection() && targetConnectId) {
|
|
2097
|
+
return this._connectDeviceOrThrow(targetConnectId, preserveInteractionId, internalSignal);
|
|
1677
2098
|
}
|
|
1678
2099
|
let confirms = 0;
|
|
1679
2100
|
while (!internalSignal.aborted) {
|
|
@@ -1681,22 +2102,28 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1681
2102
|
type: import_hwk_adapter_core3.EConnectorInteraction.Searching,
|
|
1682
2103
|
payload: { sessionId: "" }
|
|
1683
2104
|
});
|
|
1684
|
-
let devices = await this.
|
|
2105
|
+
let devices = await this._searchDevices(void 0, internalSignal);
|
|
2106
|
+
_LedgerAdapter._throwIfAborted(internalSignal);
|
|
1685
2107
|
if (devices.length === 0) {
|
|
1686
2108
|
for (let i = 0; i < 3 && !internalSignal.aborted; i += 1) {
|
|
1687
2109
|
await new Promise((resolve) => {
|
|
1688
2110
|
setTimeout(resolve, import_hwk_adapter_core3.DEVICE_CONNECT_RETRY_DELAY_MS);
|
|
1689
2111
|
});
|
|
1690
|
-
|
|
2112
|
+
_LedgerAdapter._throwIfAborted(internalSignal);
|
|
2113
|
+
devices = await this._searchDevices(void 0, internalSignal);
|
|
2114
|
+
_LedgerAdapter._throwIfAborted(internalSignal);
|
|
1691
2115
|
if (devices.length > 0) break;
|
|
1692
2116
|
}
|
|
1693
2117
|
}
|
|
1694
|
-
if (devices.length > 0) {
|
|
2118
|
+
if (devices.length > 0 || this._isBleConnection() && allowUsbEphemeralFallback) {
|
|
1695
2119
|
try {
|
|
1696
2120
|
return await this._connectFirstOrSelect(
|
|
1697
2121
|
devices,
|
|
1698
2122
|
targetConnectId,
|
|
1699
|
-
allowUsbEphemeralFallback
|
|
2123
|
+
allowUsbEphemeralFallback,
|
|
2124
|
+
preserveInteractionId,
|
|
2125
|
+
context,
|
|
2126
|
+
internalSignal
|
|
1700
2127
|
);
|
|
1701
2128
|
} catch (err) {
|
|
1702
2129
|
if (!isDeviceLockedError(err) && !isDeviceNotAdvertisingError(err) && !isDeviceDisconnectedError(err)) {
|
|
@@ -1725,45 +2152,107 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1725
2152
|
_LedgerAdapter._throwIfAborted(internalSignal);
|
|
1726
2153
|
throw new Error("_doConnect aborted");
|
|
1727
2154
|
}
|
|
1728
|
-
async _connectFirstOrSelect(devices, targetConnectId, allowUsbEphemeralFallback = false) {
|
|
2155
|
+
async _connectFirstOrSelect(devices, targetConnectId, allowUsbEphemeralFallback = false, preserveInteractionId, context, signal) {
|
|
2156
|
+
if (signal) _LedgerAdapter._throwIfAborted(signal);
|
|
1729
2157
|
if (targetConnectId) {
|
|
1730
2158
|
const target = devices.find(
|
|
1731
2159
|
(d) => d.connectId === targetConnectId || d.deviceId === targetConnectId
|
|
1732
2160
|
);
|
|
1733
2161
|
if (target) {
|
|
1734
|
-
return this._connectDeviceOrThrow(target.connectId);
|
|
2162
|
+
return this._connectDeviceOrThrow(target.connectId, preserveInteractionId, signal);
|
|
1735
2163
|
}
|
|
1736
|
-
if (!
|
|
2164
|
+
if (!this._isBleConnection() && devices.length === 1 && allowUsbEphemeralFallback) {
|
|
1737
2165
|
debugLog(
|
|
1738
2166
|
`[LedgerAdapter] target ${targetConnectId} not in fresh enumeration; accepting sole USB device ${devices[0].connectId} for fingerprint-verified recovery`
|
|
1739
2167
|
);
|
|
1740
|
-
return this._connectDeviceOrThrow(devices[0].connectId);
|
|
2168
|
+
return this._connectDeviceOrThrow(devices[0].connectId, preserveInteractionId, signal);
|
|
1741
2169
|
}
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
2170
|
+
if (!this._isBleConnection() || !allowUsbEphemeralFallback) {
|
|
2171
|
+
const err = Object.assign(new Error(`Target Ledger unavailable: ${targetConnectId}`), {
|
|
2172
|
+
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
|
|
2173
|
+
});
|
|
2174
|
+
if (this._isBleConnection()) {
|
|
2175
|
+
err._tag = ERROR_TAG.DeviceNotAdvertising;
|
|
2176
|
+
}
|
|
2177
|
+
throw err;
|
|
1747
2178
|
}
|
|
1748
|
-
throw err;
|
|
1749
2179
|
}
|
|
1750
|
-
|
|
2180
|
+
const requiresBleSelection = this._isBleConnection();
|
|
2181
|
+
if (requiresBleSelection && !allowUsbEphemeralFallback) {
|
|
1751
2182
|
throw Object.assign(new Error("Ledger BLE connectId is required."), {
|
|
1752
2183
|
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
|
|
1753
2184
|
});
|
|
1754
2185
|
}
|
|
1755
|
-
if (
|
|
1756
|
-
|
|
2186
|
+
if (requiresBleSelection && context?.allowDeviceSelection !== false) {
|
|
2187
|
+
const bindingSessionId = context?.bindingSessionId ?? this._uiRegistry.createRequestId();
|
|
2188
|
+
if (context) context.bindingSessionId = bindingSessionId;
|
|
2189
|
+
const { device, requestId } = await (0, import_hwk_adapter_core3.requestBleDeviceSelection)({
|
|
2190
|
+
emitter: this.emitter,
|
|
2191
|
+
registry: this._uiRegistry,
|
|
2192
|
+
signal: signal ?? new AbortController().signal,
|
|
2193
|
+
scan: async () => (await this._searchDevices({ transportType: "ble", waitForAllTransports: true }, signal)).filter((device2) => !context?.rejectedConnectIds?.has(device2.connectId)),
|
|
2194
|
+
request: {
|
|
2195
|
+
devices: devices.filter((device2) => !context?.rejectedConnectIds?.has(device2.connectId)),
|
|
2196
|
+
bindingSessionId,
|
|
2197
|
+
rejectedConnectId: context?.rejectedConnectId,
|
|
2198
|
+
context: {
|
|
2199
|
+
kind: "bind-connection",
|
|
2200
|
+
transport: "ble",
|
|
2201
|
+
reason: targetConnectId ? "known-connection-unavailable" : "missing-binding"
|
|
2202
|
+
},
|
|
2203
|
+
extra: context?.extra
|
|
2204
|
+
}
|
|
2205
|
+
});
|
|
2206
|
+
if (context) context.selectedConnection = { connectId: device.connectId, requestId };
|
|
2207
|
+
this._bindingSelectionRequestId = requestId;
|
|
2208
|
+
return this._connectDeviceOrThrow(device.connectId, preserveInteractionId, signal);
|
|
2209
|
+
}
|
|
2210
|
+
if (devices.length > 0 && (devices.length > 1 || requiresBleSelection)) {
|
|
2211
|
+
if (context?.allowDeviceSelection === false || !this.emitter.listenerCount(import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE)) {
|
|
2212
|
+
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2213
|
+
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound,
|
|
2214
|
+
message: "Select a Ledger device before continuing"
|
|
2215
|
+
});
|
|
2216
|
+
}
|
|
2217
|
+
const requestId = this._uiRegistry.createRequestId();
|
|
2218
|
+
const waitPromise = this._uiRegistry.wait(
|
|
2219
|
+
import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE,
|
|
2220
|
+
{ requestId }
|
|
2221
|
+
);
|
|
2222
|
+
this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE, {
|
|
2223
|
+
type: import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE,
|
|
2224
|
+
payload: {
|
|
2225
|
+
devices,
|
|
2226
|
+
requestId,
|
|
2227
|
+
context: requiresBleSelection ? {
|
|
2228
|
+
kind: "bind-connection",
|
|
2229
|
+
transport: "ble",
|
|
2230
|
+
reason: targetConnectId ? "known-connection-unavailable" : "missing-binding"
|
|
2231
|
+
} : { kind: "select-device", transport: "usb", reason: "multiple-candidates" },
|
|
2232
|
+
extra: context?.extra
|
|
2233
|
+
}
|
|
2234
|
+
});
|
|
2235
|
+
const { sdkConnectId } = await (signal ? this._abortable(signal, waitPromise) : waitPromise);
|
|
2236
|
+
if (signal) _LedgerAdapter._throwIfAborted(signal);
|
|
2237
|
+
const selected = devices.find((device) => device.connectId === sdkConnectId);
|
|
2238
|
+
if (!selected) {
|
|
2239
|
+
throw Object.assign(new Error("Selected Ledger is no longer available"), {
|
|
2240
|
+
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
|
|
2241
|
+
});
|
|
2242
|
+
}
|
|
2243
|
+
if (context && requiresBleSelection)
|
|
2244
|
+
context.selectedConnection = { connectId: selected.connectId, requestId };
|
|
2245
|
+
return this._connectDeviceOrThrow(selected.connectId, preserveInteractionId, signal);
|
|
1757
2246
|
}
|
|
1758
2247
|
if (devices.length !== 1) {
|
|
1759
2248
|
throw Object.assign(new Error("Ledger device not found."), {
|
|
1760
2249
|
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
|
|
1761
2250
|
});
|
|
1762
2251
|
}
|
|
1763
|
-
return this._connectDeviceOrThrow(devices[0].connectId);
|
|
2252
|
+
return this._connectDeviceOrThrow(devices[0].connectId, preserveInteractionId, signal);
|
|
1764
2253
|
}
|
|
1765
|
-
async _connectDeviceOrThrow(chosenConnectId) {
|
|
1766
|
-
const result = await this.
|
|
2254
|
+
async _connectDeviceOrThrow(chosenConnectId, preserveInteractionId, signal) {
|
|
2255
|
+
const result = await this._connectTarget(chosenConnectId, preserveInteractionId, signal);
|
|
1767
2256
|
if (!result.success) {
|
|
1768
2257
|
const payload = result.payload;
|
|
1769
2258
|
const rethrow = Object.assign(new Error(payload.error), {
|
|
@@ -1774,7 +2263,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1774
2263
|
}
|
|
1775
2264
|
throw rethrow;
|
|
1776
2265
|
}
|
|
1777
|
-
return
|
|
2266
|
+
return result.payload;
|
|
1778
2267
|
}
|
|
1779
2268
|
/**
|
|
1780
2269
|
* Call the connector with automatic session resolution and disconnect retry.
|
|
@@ -1804,26 +2293,121 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1804
2293
|
* lives in one place.
|
|
1805
2294
|
*/
|
|
1806
2295
|
async _callConnector(sessionId, method, params, signal) {
|
|
1807
|
-
|
|
2296
|
+
this._assertConnectorReady(method);
|
|
2297
|
+
const releaseOperation = this._retainConnectorOperation(`call:${sessionId}`);
|
|
2298
|
+
let promise;
|
|
2299
|
+
try {
|
|
2300
|
+
promise = this.connector.call(sessionId, method, params).finally(releaseOperation);
|
|
2301
|
+
} catch (error) {
|
|
2302
|
+
releaseOperation();
|
|
2303
|
+
throw error;
|
|
2304
|
+
}
|
|
1808
2305
|
const result = signal ? await this._abortable(signal, promise) : await promise;
|
|
1809
2306
|
return this._unwrapConnectorResult(result);
|
|
1810
2307
|
}
|
|
2308
|
+
_assertConnectorReady(method) {
|
|
2309
|
+
if (this._resetPromise || this._pendingConnectorTeardowns > 0 || this._unsettledConnectorOperations.size > 0) {
|
|
2310
|
+
throw _LedgerAdapter._createDeviceBusyError(method);
|
|
2311
|
+
}
|
|
2312
|
+
}
|
|
2313
|
+
_runConnectorTeardown(task) {
|
|
2314
|
+
const previous = this._connectorTeardownTail;
|
|
2315
|
+
let releaseTail = () => void 0;
|
|
2316
|
+
this._connectorTeardownTail = new Promise((resolve) => {
|
|
2317
|
+
releaseTail = resolve;
|
|
2318
|
+
});
|
|
2319
|
+
this._pendingConnectorTeardowns += 1;
|
|
2320
|
+
return (async () => {
|
|
2321
|
+
try {
|
|
2322
|
+
await previous;
|
|
2323
|
+
await this._waitForConnectorOperationsToDrain();
|
|
2324
|
+
await task();
|
|
2325
|
+
} finally {
|
|
2326
|
+
this._pendingConnectorTeardowns -= 1;
|
|
2327
|
+
releaseTail();
|
|
2328
|
+
}
|
|
2329
|
+
})();
|
|
2330
|
+
}
|
|
2331
|
+
_waitForConnectorOperationsToDrain() {
|
|
2332
|
+
if (this._unsettledConnectorOperations.size === 0) {
|
|
2333
|
+
return Promise.resolve();
|
|
2334
|
+
}
|
|
2335
|
+
return new Promise((resolve) => {
|
|
2336
|
+
this._connectorIdleWaiters.add(resolve);
|
|
2337
|
+
});
|
|
2338
|
+
}
|
|
2339
|
+
_retainConnectorOperation(key) {
|
|
2340
|
+
this._unsettledConnectorOperations.set(
|
|
2341
|
+
key,
|
|
2342
|
+
(this._unsettledConnectorOperations.get(key) ?? 0) + 1
|
|
2343
|
+
);
|
|
2344
|
+
let released = false;
|
|
2345
|
+
return () => {
|
|
2346
|
+
if (released) return;
|
|
2347
|
+
released = true;
|
|
2348
|
+
const remaining = (this._unsettledConnectorOperations.get(key) ?? 1) - 1;
|
|
2349
|
+
if (remaining > 0) {
|
|
2350
|
+
this._unsettledConnectorOperations.set(key, remaining);
|
|
2351
|
+
} else {
|
|
2352
|
+
this._unsettledConnectorOperations.delete(key);
|
|
2353
|
+
}
|
|
2354
|
+
if (this._unsettledConnectorOperations.size === 0) {
|
|
2355
|
+
for (const resolve of this._connectorIdleWaiters) resolve();
|
|
2356
|
+
this._connectorIdleWaiters.clear();
|
|
2357
|
+
}
|
|
2358
|
+
};
|
|
2359
|
+
}
|
|
1811
2360
|
async connectorCall(connectId, method, params, fingerprint, permissionDeviceId, commonParams, installContext) {
|
|
1812
|
-
|
|
1813
|
-
|
|
2361
|
+
const positionalInteractionId = (0, import_hwk_adapter_core3.isHardwareInteractionId)(connectId) ? connectId : void 0;
|
|
2362
|
+
if (positionalInteractionId && commonParams?.interactionId && positionalInteractionId !== commonParams.interactionId) {
|
|
2363
|
+
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2364
|
+
code: import_hwk_adapter_core3.HardwareErrorCode.InvalidParams,
|
|
2365
|
+
message: "Conflicting Ledger interaction ids",
|
|
2366
|
+
params: {
|
|
2367
|
+
positionalInteractionId,
|
|
2368
|
+
commonInteractionId: commonParams.interactionId
|
|
2369
|
+
}
|
|
2370
|
+
});
|
|
2371
|
+
}
|
|
2372
|
+
const interactionId = commonParams?.interactionId ?? positionalInteractionId;
|
|
2373
|
+
const interaction = interactionId ? this._interactions.resolve(interactionId) : void 0;
|
|
2374
|
+
const releaseInteractionRetention = interactionId ? this._interactions.retain(interactionId) : void 0;
|
|
2375
|
+
const effectiveConnectId = interaction?.connectId ?? connectId;
|
|
2376
|
+
debugLog("[LedgerAdapter][REQ]", {
|
|
2377
|
+
method,
|
|
2378
|
+
connectId: effectiveConnectId || "(empty)",
|
|
2379
|
+
params
|
|
2380
|
+
});
|
|
2381
|
+
const queueKey = (interactionId ?? effectiveConnectId) || "__ledger_default__";
|
|
1814
2382
|
try {
|
|
1815
2383
|
const result = await this._jobQueue.enqueue(
|
|
1816
2384
|
queueKey,
|
|
1817
|
-
async (signal) =>
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
2385
|
+
async (signal) => {
|
|
2386
|
+
if (interactionId) this._activeInteractionJobs.add(interactionId);
|
|
2387
|
+
try {
|
|
2388
|
+
return await this._runConnectorCall(
|
|
2389
|
+
effectiveConnectId,
|
|
2390
|
+
method,
|
|
2391
|
+
params,
|
|
2392
|
+
signal,
|
|
2393
|
+
fingerprint,
|
|
2394
|
+
permissionDeviceId,
|
|
2395
|
+
commonParams,
|
|
2396
|
+
installContext ?? {},
|
|
2397
|
+
interactionId
|
|
2398
|
+
);
|
|
2399
|
+
} catch (error) {
|
|
2400
|
+
this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
|
|
2401
|
+
throw error;
|
|
2402
|
+
} finally {
|
|
2403
|
+
if (interactionId) {
|
|
2404
|
+
this._activeInteractionJobs.delete(interactionId);
|
|
2405
|
+
if (this._pendingInteractionDisconnects.delete(interactionId)) {
|
|
2406
|
+
await this._releaseLostInteractionConnection(interactionId);
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
},
|
|
1827
2411
|
{
|
|
1828
2412
|
label: method,
|
|
1829
2413
|
rejectIfBusy: true,
|
|
@@ -1844,6 +2428,8 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1844
2428
|
}
|
|
1845
2429
|
});
|
|
1846
2430
|
throw err;
|
|
2431
|
+
} finally {
|
|
2432
|
+
releaseInteractionRetention?.();
|
|
1847
2433
|
}
|
|
1848
2434
|
}
|
|
1849
2435
|
/**
|
|
@@ -1853,6 +2439,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1853
2439
|
_abortable(signal, promise) {
|
|
1854
2440
|
const getAbortReason = () => signal.reason ?? this._lastCancelReason ?? new Error("Aborted");
|
|
1855
2441
|
if (signal.aborted) {
|
|
2442
|
+
void promise.catch(() => void 0);
|
|
1856
2443
|
return Promise.reject(getAbortReason());
|
|
1857
2444
|
}
|
|
1858
2445
|
return new Promise((resolve, reject) => {
|
|
@@ -1879,13 +2466,15 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1879
2466
|
}
|
|
1880
2467
|
}
|
|
1881
2468
|
/** Actual work done under the job queue — connection, fingerprint, call, and recovery. */
|
|
1882
|
-
async _runConnectorCall(connectId, method, params, signal, fingerprint, permissionDeviceId, commonParams, installContext) {
|
|
2469
|
+
async _runConnectorCall(connectId, method, params, signal, fingerprint, permissionDeviceId, commonParams, installContext, interactionId, lockedRetryBudget = _LedgerAdapter.MAX_BUSINESS_RETRY_BUDGET) {
|
|
1883
2470
|
_LedgerAdapter._throwIfAborted(signal);
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
2471
|
+
if (!interactionId) {
|
|
2472
|
+
await this._ensureDevicePermission(
|
|
2473
|
+
connectId,
|
|
2474
|
+
permissionDeviceId ?? fingerprint?.deviceId,
|
|
2475
|
+
signal
|
|
2476
|
+
);
|
|
2477
|
+
}
|
|
1889
2478
|
_LedgerAdapter._throwIfAborted(signal);
|
|
1890
2479
|
let effectiveParams = params;
|
|
1891
2480
|
if (method === "btcGetPublicKey") {
|
|
@@ -1899,36 +2488,133 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1899
2488
|
effectiveParams = gatedParams;
|
|
1900
2489
|
}
|
|
1901
2490
|
const allowUsbEphemeralFallback = !!fingerprint?.deviceId && !fingerprint.skipFingerprint;
|
|
1902
|
-
|
|
1903
|
-
|
|
2491
|
+
let businessCallStarted = false;
|
|
2492
|
+
const verifiedBleTarget = connectId ? this._verifiedBleReconnectTargets.get(connectId) : void 0;
|
|
2493
|
+
const knownTransport = this._isBleConnection() ? "ble" : "usb";
|
|
2494
|
+
const hintedConnectId = commonParams?.knownConnections?.find(
|
|
2495
|
+
(connection) => connection.transport === knownTransport
|
|
2496
|
+
);
|
|
2497
|
+
const inputConnectId = hintedConnectId && hintedConnectId.transport !== "qr" ? hintedConnectId.connectId : connectId;
|
|
2498
|
+
const preferredConnectId = fingerprint && !fingerprint.skipFingerprint && verifiedBleTarget?.chain === fingerprint.chain && verifiedBleTarget.fingerprint === fingerprint.deviceId ? verifiedBleTarget.connectId : inputConnectId;
|
|
2499
|
+
const connectionAttempt = { ...commonParams };
|
|
2500
|
+
const bundleConnection = installContext?.connection;
|
|
2501
|
+
if (bundleConnection && this._sessions.get(bundleConnection.connectId) !== bundleConnection.sessionId) {
|
|
2502
|
+
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2503
|
+
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
|
|
2504
|
+
message: "Ledger all-network connection ended"
|
|
2505
|
+
});
|
|
2506
|
+
}
|
|
2507
|
+
let resolvedConnectId = interactionId ? this._interactions.resolve(interactionId).connectId : bundleConnection?.connectId ?? await this.ensureConnected(
|
|
2508
|
+
preferredConnectId,
|
|
1904
2509
|
signal,
|
|
1905
|
-
allowUsbEphemeralFallback
|
|
2510
|
+
allowUsbEphemeralFallback,
|
|
2511
|
+
void 0,
|
|
2512
|
+
connectionAttempt
|
|
1906
2513
|
);
|
|
1907
|
-
|
|
2514
|
+
let sessionId = this._sessions.get(resolvedConnectId);
|
|
2515
|
+
if (sessionId && installContext && !installContext.connection) {
|
|
2516
|
+
installContext.connection = { connectId: resolvedConnectId, sessionId };
|
|
2517
|
+
}
|
|
1908
2518
|
if (!sessionId) {
|
|
2519
|
+
if (interactionId) {
|
|
2520
|
+
this._interactions.end(interactionId, "disconnect");
|
|
2521
|
+
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2522
|
+
code: import_hwk_adapter_core3.HardwareErrorCode.InteractionEnded,
|
|
2523
|
+
message: "Ledger interaction connection is no longer active",
|
|
2524
|
+
params: { interactionId, reason: "disconnect" }
|
|
2525
|
+
});
|
|
2526
|
+
}
|
|
1909
2527
|
throw Object.assign(new Error("Auto-connect succeeded but no session found"), {
|
|
1910
2528
|
_tag: ERROR_TAG.DeviceSessionNotFound
|
|
1911
2529
|
});
|
|
1912
2530
|
}
|
|
1913
2531
|
try {
|
|
1914
2532
|
if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId) {
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
2533
|
+
for (; ; ) {
|
|
2534
|
+
const fp = await this._abortable(
|
|
2535
|
+
signal,
|
|
2536
|
+
this._verifyDeviceFingerprintWithSession(
|
|
2537
|
+
sessionId,
|
|
2538
|
+
fingerprint.deviceId,
|
|
2539
|
+
fingerprint.chain
|
|
2540
|
+
)
|
|
2541
|
+
);
|
|
2542
|
+
if (fp.success) break;
|
|
2543
|
+
const binding = interactionId ? this._pendingInteractionBindings.get(interactionId) : connectionAttempt;
|
|
2544
|
+
if (!this._isBleConnection() || binding?.selectedConnection?.connectId !== resolvedConnectId) {
|
|
2545
|
+
throw Object.assign(new Error(formatDeviceMismatchError(fp.expected, fp.actual)), {
|
|
2546
|
+
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch
|
|
2547
|
+
});
|
|
2548
|
+
}
|
|
2549
|
+
binding.rejectedConnectIds ?? (binding.rejectedConnectIds = /* @__PURE__ */ new Set());
|
|
2550
|
+
binding.rejectedConnectIds.add(resolvedConnectId);
|
|
2551
|
+
binding.rejectedConnectId = resolvedConnectId;
|
|
2552
|
+
this._sessions.delete(resolvedConnectId);
|
|
2553
|
+
await this.connector.disconnect(sessionId);
|
|
2554
|
+
if (interactionId) this._pendingInteractionDisconnects.delete(interactionId);
|
|
2555
|
+
_LedgerAdapter._throwIfAborted(signal);
|
|
2556
|
+
resolvedConnectId = await this._connectFirstOrSelect(
|
|
2557
|
+
[],
|
|
2558
|
+
void 0,
|
|
2559
|
+
true,
|
|
2560
|
+
interactionId,
|
|
2561
|
+
binding,
|
|
2562
|
+
signal
|
|
2563
|
+
);
|
|
2564
|
+
const selectedSession = this._sessions.get(resolvedConnectId);
|
|
2565
|
+
const selectedDevice = this._discoveredDevices.get(resolvedConnectId);
|
|
2566
|
+
if (!selectedSession || !selectedDevice)
|
|
2567
|
+
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2568
|
+
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
|
|
2569
|
+
message: "Selected Ledger connection ended"
|
|
2570
|
+
});
|
|
2571
|
+
sessionId = selectedSession;
|
|
2572
|
+
if (interactionId)
|
|
2573
|
+
this._interactions.rebind(interactionId, {
|
|
2574
|
+
connectId: resolvedConnectId,
|
|
2575
|
+
device: selectedDevice,
|
|
2576
|
+
connectionKeys: [sessionId]
|
|
2577
|
+
});
|
|
2578
|
+
if (installContext)
|
|
2579
|
+
installContext.connection = { connectId: resolvedConnectId, sessionId };
|
|
2580
|
+
}
|
|
2581
|
+
if (!interactionId && connectionAttempt.selectedConnection?.connectId === resolvedConnectId && this._isBleConnection()) {
|
|
2582
|
+
this._verifiedBleReconnectTargets.set(connectId, {
|
|
2583
|
+
connectId: resolvedConnectId,
|
|
2584
|
+
chain: fingerprint.chain,
|
|
2585
|
+
fingerprint: fingerprint.deviceId
|
|
1926
2586
|
});
|
|
1927
2587
|
}
|
|
2588
|
+
await this._publishVerifiedBleBinding(
|
|
2589
|
+
resolvedConnectId,
|
|
2590
|
+
fingerprint.chain,
|
|
2591
|
+
fingerprint.deviceId,
|
|
2592
|
+
connectionAttempt,
|
|
2593
|
+
interactionId,
|
|
2594
|
+
connectId,
|
|
2595
|
+
signal
|
|
2596
|
+
);
|
|
1928
2597
|
}
|
|
2598
|
+
businessCallStarted = true;
|
|
1929
2599
|
return await this._callConnector(sessionId, method, effectiveParams, signal);
|
|
1930
2600
|
} catch (err) {
|
|
1931
2601
|
if (signal.aborted) throw err;
|
|
2602
|
+
if (isDeviceDisconnectedError(err) || isDeviceNotAdvertisingError(err) || isTimeoutError(err) || isConnectionLevelError(err)) {
|
|
2603
|
+
this._discoveredDevices.delete(resolvedConnectId);
|
|
2604
|
+
if (interactionId) await this._releaseLostInteractionConnection(interactionId);
|
|
2605
|
+
else {
|
|
2606
|
+
this._sessions.delete(resolvedConnectId);
|
|
2607
|
+
await this.connector.disconnect(sessionId).catch(() => void 0);
|
|
2608
|
+
}
|
|
2609
|
+
const ambiguous = businessCallStarted && !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method);
|
|
2610
|
+
const interactionParams = interactionId ? { interactionId, reason: "disconnect" } : void 0;
|
|
2611
|
+
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2612
|
+
code: interactionId ? import_hwk_adapter_core3.HardwareErrorCode.InteractionEnded : mapLedgerError(err).code,
|
|
2613
|
+
message: "Ledger operation connection was lost; start a new operation",
|
|
2614
|
+
params: ambiguous ? (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(method, { interactionId }) : interactionParams,
|
|
2615
|
+
recovery: ambiguous ? { scope: "unknown" } : void 0
|
|
2616
|
+
});
|
|
2617
|
+
}
|
|
1932
2618
|
const errObj = err;
|
|
1933
2619
|
debugLog("[LedgerAdapter] connectorCall error:", method, {
|
|
1934
2620
|
message: errObj?.message,
|
|
@@ -1940,6 +2626,65 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1940
2626
|
isNotAdvertising: isDeviceNotAdvertisingError(err),
|
|
1941
2627
|
isStuckApp: isStuckAppStateError(err)
|
|
1942
2628
|
});
|
|
2629
|
+
if ((isDeviceLockedError(err) || errObj?.code === import_hwk_adapter_core3.HardwareErrorCode.DeviceLocked) && lockedRetryBudget > 0) {
|
|
2630
|
+
await this._waitForDeviceConnect(signal);
|
|
2631
|
+
if (this._sessions.get(resolvedConnectId) !== sessionId) {
|
|
2632
|
+
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2633
|
+
code: interactionId ? import_hwk_adapter_core3.HardwareErrorCode.InteractionEnded : import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
|
|
2634
|
+
message: "Ledger connection ended while waiting for unlock"
|
|
2635
|
+
});
|
|
2636
|
+
}
|
|
2637
|
+
return this._runConnectorCall(
|
|
2638
|
+
resolvedConnectId,
|
|
2639
|
+
method,
|
|
2640
|
+
effectiveParams,
|
|
2641
|
+
signal,
|
|
2642
|
+
fingerprint,
|
|
2643
|
+
permissionDeviceId,
|
|
2644
|
+
commonParams,
|
|
2645
|
+
installContext,
|
|
2646
|
+
interactionId,
|
|
2647
|
+
lockedRetryBudget - 1
|
|
2648
|
+
);
|
|
2649
|
+
}
|
|
2650
|
+
if (businessCallStarted && isStuckAppStateError(err)) {
|
|
2651
|
+
await this._sleepAbortable(_LedgerAdapter.STUCK_APP_RETRY_DELAY_MS, signal);
|
|
2652
|
+
if (this._sessions.get(resolvedConnectId) !== sessionId) {
|
|
2653
|
+
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2654
|
+
code: interactionId ? import_hwk_adapter_core3.HardwareErrorCode.InteractionEnded : import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
|
|
2655
|
+
message: "Ledger connection ended during the app transition"
|
|
2656
|
+
});
|
|
2657
|
+
}
|
|
2658
|
+
try {
|
|
2659
|
+
return await this._callConnector(sessionId, method, effectiveParams, signal);
|
|
2660
|
+
} catch (retryErr) {
|
|
2661
|
+
if (isStuckAppStateError(retryErr)) throw err;
|
|
2662
|
+
if (isDeviceDisconnectedError(retryErr) || isDeviceNotAdvertisingError(retryErr) || isTimeoutError(retryErr) || isConnectionLevelError(retryErr)) {
|
|
2663
|
+
if (interactionId) await this._releaseLostInteractionConnection(interactionId);
|
|
2664
|
+
else {
|
|
2665
|
+
this._sessions.delete(resolvedConnectId);
|
|
2666
|
+
this._discoveredDevices.delete(resolvedConnectId);
|
|
2667
|
+
await this.connector.disconnect(sessionId).catch(() => void 0);
|
|
2668
|
+
}
|
|
2669
|
+
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2670
|
+
code: interactionId ? import_hwk_adapter_core3.HardwareErrorCode.InteractionEnded : mapLedgerError(retryErr).code,
|
|
2671
|
+
message: `Ledger ${method} may have completed before the connection was lost`,
|
|
2672
|
+
params: !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method) ? (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(method, {
|
|
2673
|
+
interactionId,
|
|
2674
|
+
reason: "disconnect"
|
|
2675
|
+
}) : { interactionId, reason: "disconnect" },
|
|
2676
|
+
recovery: !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method) ? { scope: "unknown" } : void 0
|
|
2677
|
+
});
|
|
2678
|
+
}
|
|
2679
|
+
throw retryErr;
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
if (!interactionId && err?.code === import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch) {
|
|
2683
|
+
this._sessions.delete(resolvedConnectId);
|
|
2684
|
+
this._discoveredDevices.delete(resolvedConnectId);
|
|
2685
|
+
await this.connector.disconnect(sessionId).catch(() => void 0);
|
|
2686
|
+
throw err;
|
|
2687
|
+
}
|
|
1943
2688
|
const autoInstallApp = commonParams?.autoInstallApp ?? this._defaultAutoInstallApp;
|
|
1944
2689
|
const isAppMissing = isAppNotInstalledError(err) || err?.code === import_hwk_adapter_core3.HardwareErrorCode.AppNotInstalled;
|
|
1945
2690
|
if (autoInstallApp && isAppMissing) {
|
|
@@ -1995,157 +2740,14 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1995
2740
|
fingerprint,
|
|
1996
2741
|
permissionDeviceId,
|
|
1997
2742
|
commonParams,
|
|
1998
|
-
installContext
|
|
1999
|
-
|
|
2000
|
-
}
|
|
2001
|
-
}
|
|
2002
|
-
if (isStuckAppStateError(err)) {
|
|
2003
|
-
try {
|
|
2004
|
-
this._sessions.delete(resolvedConnectId);
|
|
2005
|
-
this._discoveredDevices.delete(resolvedConnectId);
|
|
2006
|
-
this.connector.reset?.();
|
|
2007
|
-
} catch {
|
|
2008
|
-
}
|
|
2009
|
-
debugLog(
|
|
2010
|
-
"[LedgerAdapter] stuck-app retry: method=",
|
|
2011
|
-
method,
|
|
2012
|
-
"delayMs=",
|
|
2013
|
-
_LedgerAdapter.STUCK_APP_RETRY_DELAY_MS,
|
|
2014
|
-
"_tag=",
|
|
2015
|
-
err?._tag
|
|
2016
|
-
);
|
|
2017
|
-
try {
|
|
2018
|
-
const retryResult = await this._retryAfterStuckApp(
|
|
2019
|
-
resolvedConnectId,
|
|
2020
|
-
method,
|
|
2021
|
-
effectiveParams,
|
|
2022
|
-
signal,
|
|
2023
|
-
err,
|
|
2024
|
-
fingerprint
|
|
2025
|
-
);
|
|
2026
|
-
debugLog("[LedgerAdapter] stuck-app retry succeeded: method=", method);
|
|
2027
|
-
return retryResult;
|
|
2028
|
-
} catch (retryErr) {
|
|
2029
|
-
if (signal.aborted) throw retryErr;
|
|
2030
|
-
if (isStuckAppStateError(retryErr)) {
|
|
2031
|
-
debugLog("[LedgerAdapter] stuck-app retry exhausted (2nd 6901): method=", method);
|
|
2032
|
-
throw err;
|
|
2033
|
-
}
|
|
2034
|
-
debugLog(
|
|
2035
|
-
"[LedgerAdapter] stuck-app retry threw non-stuck error: method=",
|
|
2036
|
-
method,
|
|
2037
|
-
"retryErrTag=",
|
|
2038
|
-
retryErr?._tag
|
|
2743
|
+
installContext,
|
|
2744
|
+
interactionId
|
|
2039
2745
|
);
|
|
2040
|
-
throw retryErr;
|
|
2041
2746
|
}
|
|
2042
2747
|
}
|
|
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
|
-
}
|
|
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
|
-
});
|
|
2111
|
-
}
|
|
2112
2748
|
throw err;
|
|
2113
2749
|
}
|
|
2114
2750
|
}
|
|
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
|
-
}
|
|
2149
2751
|
_sleepAbortable(ms, signal) {
|
|
2150
2752
|
return new Promise((resolve, reject) => {
|
|
2151
2753
|
if (signal.aborted) {
|
|
@@ -2163,88 +2765,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2163
2765
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
2164
2766
|
});
|
|
2165
2767
|
}
|
|
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
|
-
}
|
|
2248
2768
|
/**
|
|
2249
2769
|
* Ensure OS-level device permission (Bluetooth / USB) before proceeding.
|
|
2250
2770
|
*
|
|
@@ -2314,7 +2834,15 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2314
2834
|
if (err && typeof err === "object" && "code" in err && typeof err.code === "number") {
|
|
2315
2835
|
const e = err;
|
|
2316
2836
|
const params = e.code === import_hwk_adapter_core3.HardwareErrorCode.DevicePermissionDenied && e.reason ? { permissionDeniedReason: e.reason } : e.params;
|
|
2317
|
-
return ledgerFailure(
|
|
2837
|
+
return ledgerFailure(
|
|
2838
|
+
e.code,
|
|
2839
|
+
e.message ?? "Unknown error",
|
|
2840
|
+
e.appName,
|
|
2841
|
+
tag,
|
|
2842
|
+
params,
|
|
2843
|
+
void 0,
|
|
2844
|
+
(0, import_hwk_adapter_core3.isHwkRecoveryHint)(e.recovery) ? e.recovery : void 0
|
|
2845
|
+
);
|
|
2318
2846
|
}
|
|
2319
2847
|
const mapped = mapLedgerError(err);
|
|
2320
2848
|
return ledgerFailure(mapped.code, mapped.message, mapped.appName, tag);
|
|
@@ -2341,7 +2869,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2341
2869
|
deviceId: device.deviceId,
|
|
2342
2870
|
connectId: device.connectId,
|
|
2343
2871
|
label: device.name,
|
|
2344
|
-
connectionType: this.connector.connectionType,
|
|
2872
|
+
connectionType: device.connectionType ?? this.connector.connectionType,
|
|
2345
2873
|
rssi: device.rssi,
|
|
2346
2874
|
isConnectable: device.isConnectable,
|
|
2347
2875
|
serialNumber: device.serialNumber,
|
|
@@ -2366,7 +2894,7 @@ _LedgerAdapter.APP_INSTALL_PROGRESS_MIN_DELTA = 0.05;
|
|
|
2366
2894
|
var LedgerAdapter = _LedgerAdapter;
|
|
2367
2895
|
|
|
2368
2896
|
// src/connector/LedgerConnectorBase.ts
|
|
2369
|
-
var
|
|
2897
|
+
var import_hwk_adapter_core14 = require("@onekeyfe/hwk-adapter-core");
|
|
2370
2898
|
|
|
2371
2899
|
// src/device/LedgerDeviceManager.ts
|
|
2372
2900
|
var LedgerDeviceManager = class {
|
|
@@ -2902,7 +3430,7 @@ var SignerManager = class _SignerManager {
|
|
|
2902
3430
|
return (args) => new import_device_signer_kit_ethereum.SignerEthBuilder(args);
|
|
2903
3431
|
}
|
|
2904
3432
|
static _createContextModule() {
|
|
2905
|
-
const contextModule = new import_context_module.ContextModuleBuilder({}).removeDefaultLoaders().build();
|
|
3433
|
+
const contextModule = new import_context_module.ContextModuleBuilder({}).setChain(import_context_module.ContextModuleChainID.Ethereum).removeDefaultLoaders().build();
|
|
2906
3434
|
return _SignerManager.wrapBlindSigningReportNonBlocking(contextModule);
|
|
2907
3435
|
}
|
|
2908
3436
|
static wrapBlindSigningReportNonBlocking(contextModule) {
|
|
@@ -3373,6 +3901,7 @@ function _applySignaturesToPsbt(psbtHex, signatures) {
|
|
|
3373
3901
|
|
|
3374
3902
|
// src/connector/chains/sol.ts
|
|
3375
3903
|
var import_hwk_adapter_core9 = require("@onekeyfe/hwk-adapter-core");
|
|
3904
|
+
var import_bs58 = __toESM(require("bs58"));
|
|
3376
3905
|
|
|
3377
3906
|
// src/signer/SignerSol.ts
|
|
3378
3907
|
var SignerSol = class {
|
|
@@ -3456,8 +3985,21 @@ async function solSignMessage(ctx, sessionId, params) {
|
|
|
3456
3985
|
const path = normalizePath(params.path);
|
|
3457
3986
|
const messageBytes = (0, import_hwk_adapter_core9.hexToBytes)(params.message);
|
|
3458
3987
|
try {
|
|
3988
|
+
if (params.messageVersion === 1) {
|
|
3989
|
+
const preparedMessage = (0, import_hwk_adapter_core9.prepareSolanaOffchainMessageV1)({
|
|
3990
|
+
message: messageBytes,
|
|
3991
|
+
requiredSigners: params.requiredSigners
|
|
3992
|
+
});
|
|
3993
|
+
const { SignMessageVersion } = await ctx.importLedgerKit(
|
|
3994
|
+
"@ledgerhq/device-signer-kit-solana"
|
|
3995
|
+
);
|
|
3996
|
+
const result2 = await solSigner.signMessage(path, preparedMessage.serializedMessage, {
|
|
3997
|
+
version: SignMessageVersion.Raw
|
|
3998
|
+
});
|
|
3999
|
+
return { signature: decodeBase58Signature(result2.signature) };
|
|
4000
|
+
}
|
|
3459
4001
|
const result = await solSigner.signMessage(path, messageBytes);
|
|
3460
|
-
return { signature: result.signature };
|
|
4002
|
+
return { signature: decodeBase58EnvelopeSignature(result.signature) };
|
|
3461
4003
|
} catch (err) {
|
|
3462
4004
|
ctx.invalidateSession(sessionId);
|
|
3463
4005
|
throw ctx.wrapError(err);
|
|
@@ -3465,11 +4007,27 @@ async function solSignMessage(ctx, sessionId, params) {
|
|
|
3465
4007
|
ctx.clearCanceller(sessionId);
|
|
3466
4008
|
}
|
|
3467
4009
|
}
|
|
4010
|
+
function decodeBase58Signature(signature) {
|
|
4011
|
+
const bytes = import_bs58.default.decode(signature);
|
|
4012
|
+
if (bytes.length !== 64) {
|
|
4013
|
+
throw new Error(`Ledger Solana signature must be 64 bytes, received ${bytes.length}`);
|
|
4014
|
+
}
|
|
4015
|
+
return (0, import_hwk_adapter_core9.bytesToHex)(bytes);
|
|
4016
|
+
}
|
|
4017
|
+
function decodeBase58EnvelopeSignature(envelope) {
|
|
4018
|
+
const bytes = import_bs58.default.decode(envelope);
|
|
4019
|
+
if (bytes.length < 65 || bytes[0] !== 1) {
|
|
4020
|
+
throw new Error("Ledger Solana signature envelope is invalid");
|
|
4021
|
+
}
|
|
4022
|
+
return (0, import_hwk_adapter_core9.bytesToHex)(bytes.subarray(1, 65));
|
|
4023
|
+
}
|
|
3468
4024
|
async function _createSolSigner(ctx, sessionId) {
|
|
3469
4025
|
const dmk = await ctx.getOrCreateDmk();
|
|
3470
|
-
const { ContextModuleBuilder: ContextModuleBuilder2 } = await ctx.importLedgerKit(
|
|
4026
|
+
const { ContextModuleBuilder: ContextModuleBuilder2, ContextModuleChainID: ContextModuleChainID2 } = await ctx.importLedgerKit(
|
|
4027
|
+
"@ledgerhq/context-module"
|
|
4028
|
+
);
|
|
3471
4029
|
const { SignerSolanaBuilder } = await ctx.importLedgerKit("@ledgerhq/device-signer-kit-solana");
|
|
3472
|
-
const contextModule = new ContextModuleBuilder2({}).removeDefaultLoaders().build();
|
|
4030
|
+
const contextModule = new ContextModuleBuilder2({}).setChain(ContextModuleChainID2.Solana).removeDefaultLoaders().build();
|
|
3473
4031
|
const sdkSigner = new SignerSolanaBuilder({ dmk, sessionId }).withContextModule(contextModule).build();
|
|
3474
4032
|
const signer = new SignerSol(sdkSigner);
|
|
3475
4033
|
signer.onInteraction = (interaction) => {
|
|
@@ -3485,21 +4043,102 @@ async function _createSolSigner(ctx, sessionId) {
|
|
|
3485
4043
|
return signer;
|
|
3486
4044
|
}
|
|
3487
4045
|
|
|
4046
|
+
// src/connector/chains/zcash.ts
|
|
4047
|
+
var import_hwk_adapter_core10 = require("@onekeyfe/hwk-adapter-core");
|
|
4048
|
+
|
|
4049
|
+
// src/signer/SignerZcash.ts
|
|
4050
|
+
var SignerZcash = class {
|
|
4051
|
+
// eslint-disable-next-line no-useless-constructor, no-empty-function
|
|
4052
|
+
constructor(_sdk) {
|
|
4053
|
+
this._sdk = _sdk;
|
|
4054
|
+
}
|
|
4055
|
+
/** GET_VK: UFVK string (default) or raw 96-byte Orchard FVK. */
|
|
4056
|
+
async getFullViewingKey(derivationPath, options) {
|
|
4057
|
+
const action = this._sdk.getFullViewingKey(derivationPath, options);
|
|
4058
|
+
return deviceActionToPromise(
|
|
4059
|
+
action,
|
|
4060
|
+
this.onInteraction,
|
|
4061
|
+
void 0,
|
|
4062
|
+
this.onRegisterCanceller
|
|
4063
|
+
);
|
|
4064
|
+
}
|
|
4065
|
+
/** GET_SHIELDED_ADDRESS: single-Orchard-receiver UA for a 5-level transparent path. */
|
|
4066
|
+
async getShieldedAddress(derivationPath, options) {
|
|
4067
|
+
const action = this._sdk.getShieldedAddress(derivationPath, options);
|
|
4068
|
+
return deviceActionToPromise(
|
|
4069
|
+
action,
|
|
4070
|
+
this.onInteraction,
|
|
4071
|
+
void 0,
|
|
4072
|
+
this.onRegisterCanceller
|
|
4073
|
+
);
|
|
4074
|
+
}
|
|
4075
|
+
};
|
|
4076
|
+
|
|
4077
|
+
// src/connector/chains/zcash.ts
|
|
4078
|
+
async function zcashGetFullViewingKey(ctx, sessionId, params) {
|
|
4079
|
+
const signer = await _createZcashSigner(ctx, sessionId);
|
|
4080
|
+
const path = normalizePath(params.path);
|
|
4081
|
+
const mode = params.mode ?? "ufvk";
|
|
4082
|
+
try {
|
|
4083
|
+
const result = await signer.getFullViewingKey(path, { mode });
|
|
4084
|
+
if (result.mode === "ufvk") {
|
|
4085
|
+
return { path: params.path, mode, ufvk: result.fullViewingKey };
|
|
4086
|
+
}
|
|
4087
|
+
return { path: params.path, mode, orchardFvk: (0, import_hwk_adapter_core10.bytesToHex)(result.fullViewingKey) };
|
|
4088
|
+
} catch (err) {
|
|
4089
|
+
ctx.invalidateSession(sessionId);
|
|
4090
|
+
throw ctx.wrapError(err);
|
|
4091
|
+
} finally {
|
|
4092
|
+
ctx.clearCanceller(sessionId);
|
|
4093
|
+
}
|
|
4094
|
+
}
|
|
4095
|
+
async function zcashGetShieldedAddress(ctx, sessionId, params) {
|
|
4096
|
+
const signer = await _createZcashSigner(ctx, sessionId);
|
|
4097
|
+
const path = normalizePath(params.path);
|
|
4098
|
+
try {
|
|
4099
|
+
const result = await signer.getShieldedAddress(path, {
|
|
4100
|
+
checkOnDevice: params.showOnDevice ?? false
|
|
4101
|
+
});
|
|
4102
|
+
return { address: result.address, path: params.path };
|
|
4103
|
+
} catch (err) {
|
|
4104
|
+
ctx.invalidateSession(sessionId);
|
|
4105
|
+
throw ctx.wrapError(err);
|
|
4106
|
+
} finally {
|
|
4107
|
+
ctx.clearCanceller(sessionId);
|
|
4108
|
+
}
|
|
4109
|
+
}
|
|
4110
|
+
async function _createZcashSigner(ctx, sessionId) {
|
|
4111
|
+
const dmk = await ctx.getOrCreateDmk();
|
|
4112
|
+
const { SignerZcashBuilder } = await ctx.importLedgerKit("@ledgerhq/device-signer-kit-zcash");
|
|
4113
|
+
const sdkSigner = new SignerZcashBuilder({ dmk, sessionId }).build();
|
|
4114
|
+
const signer = new SignerZcash(sdkSigner);
|
|
4115
|
+
signer.onInteraction = (interaction) => {
|
|
4116
|
+
debugLog("[LedgerConnector] zcash.onInteraction:", interaction);
|
|
4117
|
+
ctx.emit("ui-event", {
|
|
4118
|
+
type: collapseSignerInteraction(interaction),
|
|
4119
|
+
payload: { sessionId }
|
|
4120
|
+
});
|
|
4121
|
+
};
|
|
4122
|
+
signer.onRegisterCanceller = (cancel) => ctx.registerCanceller(sessionId, cancel);
|
|
4123
|
+
return signer;
|
|
4124
|
+
}
|
|
4125
|
+
|
|
3488
4126
|
// src/connector/chains/tron.ts
|
|
3489
|
-
var
|
|
4127
|
+
var import_hwk_adapter_core13 = require("@onekeyfe/hwk-adapter-core");
|
|
3490
4128
|
var import_hw_app_trx = __toESM(require("@ledgerhq/hw-app-trx"));
|
|
3491
4129
|
|
|
3492
4130
|
// src/connector/chains/legacyChainCall.ts
|
|
3493
|
-
var
|
|
4131
|
+
var import_hwk_adapter_core12 = require("@onekeyfe/hwk-adapter-core");
|
|
3494
4132
|
|
|
3495
4133
|
// src/app/AppManager.ts
|
|
3496
4134
|
var import_device_management_kit2 = require("@ledgerhq/device-management-kit");
|
|
3497
|
-
var
|
|
4135
|
+
var import_hwk_adapter_core11 = require("@onekeyfe/hwk-adapter-core");
|
|
3498
4136
|
var APP_NAME_MAP = {
|
|
3499
4137
|
ETH: "Ethereum",
|
|
3500
4138
|
BTC: "Bitcoin",
|
|
3501
4139
|
SOL: "Solana",
|
|
3502
4140
|
TRX: "Tron",
|
|
4141
|
+
ZEC: "Zcash",
|
|
3503
4142
|
XRP: "XRP",
|
|
3504
4143
|
ADA: "Cardano",
|
|
3505
4144
|
DOT: "Polkadot",
|
|
@@ -3611,9 +4250,9 @@ var AppManager = class {
|
|
|
3611
4250
|
);
|
|
3612
4251
|
let code;
|
|
3613
4252
|
if (errorCode === "6807" || /unknown application/i.test(message)) {
|
|
3614
|
-
code =
|
|
4253
|
+
code = import_hwk_adapter_core11.HardwareErrorCode.AppNotInstalled;
|
|
3615
4254
|
} else if (errorCode === "5501" || dmkErr._tag === "ActionRefusedError") {
|
|
3616
|
-
code =
|
|
4255
|
+
code = import_hwk_adapter_core11.HardwareErrorCode.UserRejected;
|
|
3617
4256
|
}
|
|
3618
4257
|
throw Object.assign(new Error(`Failed to open "${appName}"`), {
|
|
3619
4258
|
_tag: ERROR_TAG.OpenAppCommand,
|
|
@@ -3674,14 +4313,14 @@ async function withLegacyChainCall(ctx, sessionId, options, action) {
|
|
|
3674
4313
|
const onAppOpenPrompt = () => {
|
|
3675
4314
|
openAppPromptShown = true;
|
|
3676
4315
|
ctx.emit("ui-event", {
|
|
3677
|
-
type:
|
|
4316
|
+
type: import_hwk_adapter_core12.EConnectorInteraction.ConfirmOpenApp,
|
|
3678
4317
|
payload: { sessionId }
|
|
3679
4318
|
});
|
|
3680
4319
|
};
|
|
3681
4320
|
const closeOpenAppUiIfShown = () => {
|
|
3682
4321
|
if (openAppPromptShown) {
|
|
3683
4322
|
ctx.emit("ui-event", {
|
|
3684
|
-
type:
|
|
4323
|
+
type: import_hwk_adapter_core12.EConnectorInteraction.InteractionComplete,
|
|
3685
4324
|
payload: { sessionId }
|
|
3686
4325
|
});
|
|
3687
4326
|
openAppPromptShown = false;
|
|
@@ -3702,7 +4341,7 @@ async function withLegacyChainCall(ctx, sessionId, options, action) {
|
|
|
3702
4341
|
let confirmEmitted = false;
|
|
3703
4342
|
if (needsConfirmation) {
|
|
3704
4343
|
ctx.emit("ui-event", {
|
|
3705
|
-
type:
|
|
4344
|
+
type: import_hwk_adapter_core12.EConnectorInteraction.ConfirmOnDevice,
|
|
3706
4345
|
payload: { sessionId }
|
|
3707
4346
|
});
|
|
3708
4347
|
confirmEmitted = true;
|
|
@@ -3712,7 +4351,7 @@ async function withLegacyChainCall(ctx, sessionId, options, action) {
|
|
|
3712
4351
|
} finally {
|
|
3713
4352
|
if (confirmEmitted || openAppPromptShown) {
|
|
3714
4353
|
ctx.emit("ui-event", {
|
|
3715
|
-
type:
|
|
4354
|
+
type: import_hwk_adapter_core12.EConnectorInteraction.InteractionComplete,
|
|
3716
4355
|
payload: { sessionId }
|
|
3717
4356
|
});
|
|
3718
4357
|
openAppPromptShown = false;
|
|
@@ -3800,7 +4439,7 @@ async function tronSignTransaction(ctx, sessionId, params) {
|
|
|
3800
4439
|
if (!params.rawTxHex) {
|
|
3801
4440
|
throw Object.assign(
|
|
3802
4441
|
new Error("TRON signing requires a protobuf-encoded raw transaction hex (rawTxHex)."),
|
|
3803
|
-
{ code:
|
|
4442
|
+
{ code: import_hwk_adapter_core13.HardwareErrorCode.InvalidParams }
|
|
3804
4443
|
);
|
|
3805
4444
|
}
|
|
3806
4445
|
const path = normalizePath(params.path);
|
|
@@ -4013,7 +4652,7 @@ var DeviceApps = class {
|
|
|
4013
4652
|
seTargetId: v.seTargetId,
|
|
4014
4653
|
mcuTargetId: v.mcuTargetId,
|
|
4015
4654
|
seVersion: v.seVersion,
|
|
4016
|
-
seFlagsHex:
|
|
4655
|
+
seFlagsHex: bytesToHex3(v.seFlags),
|
|
4017
4656
|
mcuSephVersion: v.mcuSephVersion,
|
|
4018
4657
|
mcuBootloaderVersion: v.mcuBootloaderVersion,
|
|
4019
4658
|
hwVersion: v.hwVersion
|
|
@@ -4087,7 +4726,7 @@ var DeviceApps = class {
|
|
|
4087
4726
|
}
|
|
4088
4727
|
}
|
|
4089
4728
|
};
|
|
4090
|
-
function
|
|
4729
|
+
function bytesToHex3(bytes) {
|
|
4091
4730
|
if (!bytes) return "";
|
|
4092
4731
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
4093
4732
|
}
|
|
@@ -4130,10 +4769,11 @@ var METHOD_PREFIX_TO_APP_NAME = {
|
|
|
4130
4769
|
evm: "Ethereum",
|
|
4131
4770
|
btc: "Bitcoin",
|
|
4132
4771
|
sol: "Solana",
|
|
4133
|
-
tron: "Tron"
|
|
4772
|
+
tron: "Tron",
|
|
4773
|
+
zcash: "Zcash"
|
|
4134
4774
|
};
|
|
4135
4775
|
var HARDWARE_ERROR_CODE_VALUES = new Set(
|
|
4136
|
-
Object.values(
|
|
4776
|
+
Object.values(import_hwk_adapter_core14.HardwareErrorCode).filter((value) => typeof value === "number")
|
|
4137
4777
|
);
|
|
4138
4778
|
var BLE_CONNECT_SCAN_TIMEOUT_MS = 1500;
|
|
4139
4779
|
var LEDGER_RELAY_ALLOWED_ROOT_DOMAINS = ["onekeytest.com", "onekey.com"];
|
|
@@ -4170,6 +4810,8 @@ async function defaultLedgerKitImporter(pkg) {
|
|
|
4170
4810
|
return import("@ledgerhq/device-signer-kit-bitcoin");
|
|
4171
4811
|
case "@ledgerhq/device-signer-kit-solana":
|
|
4172
4812
|
return import("@ledgerhq/device-signer-kit-solana");
|
|
4813
|
+
case "@ledgerhq/device-signer-kit-zcash":
|
|
4814
|
+
return import("@ledgerhq/device-signer-kit-zcash");
|
|
4173
4815
|
case "@ledgerhq/context-module":
|
|
4174
4816
|
return import("@ledgerhq/context-module");
|
|
4175
4817
|
default:
|
|
@@ -4280,7 +4922,7 @@ var LedgerConnectorBase = class {
|
|
|
4280
4922
|
async searchDevices() {
|
|
4281
4923
|
const dm = await this._getDeviceManager();
|
|
4282
4924
|
const descriptors = await this._discoverDescriptors(dm);
|
|
4283
|
-
const resolvedDescriptors = descriptors.filter((d) => !(0,
|
|
4925
|
+
const resolvedDescriptors = descriptors.filter((d) => !(0, import_hwk_adapter_core14.isKnownNonTargetHardwareVendor)(d, "ledger")).map((d) => ({
|
|
4284
4926
|
descriptor: d,
|
|
4285
4927
|
connectId: this._resolveConnectId(d)
|
|
4286
4928
|
}));
|
|
@@ -4328,7 +4970,7 @@ var LedgerConnectorBase = class {
|
|
|
4328
4970
|
`Ledger BLE connect did not return within ${HANG_CEILING_MS / 6e4}min \u2014 DMK hang fallback.`
|
|
4329
4971
|
);
|
|
4330
4972
|
err._tag = ERROR_TAG.BlePairingTimeout;
|
|
4331
|
-
err.code =
|
|
4973
|
+
err.code = import_hwk_adapter_core14.HardwareErrorCode.BlePairingTimeout;
|
|
4332
4974
|
reject(err);
|
|
4333
4975
|
}, HANG_CEILING_MS);
|
|
4334
4976
|
});
|
|
@@ -4361,7 +5003,7 @@ var LedgerConnectorBase = class {
|
|
|
4361
5003
|
"Ledger device is not currently advertising. Wake up and unlock the device, keep it nearby, then try again."
|
|
4362
5004
|
);
|
|
4363
5005
|
err._tag = ERROR_TAG.DeviceNotAdvertising;
|
|
4364
|
-
err.code =
|
|
5006
|
+
err.code = import_hwk_adapter_core14.HardwareErrorCode.DeviceNotFound;
|
|
4365
5007
|
throw err;
|
|
4366
5008
|
};
|
|
4367
5009
|
const doConnect = async (path) => {
|
|
@@ -4425,7 +5067,7 @@ var LedgerConnectorBase = class {
|
|
|
4425
5067
|
"Ledger Bluetooth pairing failed. Make sure the device is unlocked and nearby, then try again."
|
|
4426
5068
|
);
|
|
4427
5069
|
wrapped._tag = ERROR_TAG.BleGattBondingFailed;
|
|
4428
|
-
wrapped.code =
|
|
5070
|
+
wrapped.code = import_hwk_adapter_core14.HardwareErrorCode.BlePairingTimeout;
|
|
4429
5071
|
wrapped.originalError = err;
|
|
4430
5072
|
throw wrapped;
|
|
4431
5073
|
}
|
|
@@ -4503,7 +5145,7 @@ var LedgerConnectorBase = class {
|
|
|
4503
5145
|
this._unwatchSessionState(sessionId);
|
|
4504
5146
|
this._signerManager?.invalidate(sessionId);
|
|
4505
5147
|
this._cancellers.get(sessionId)?.({
|
|
4506
|
-
code:
|
|
5148
|
+
code: import_hwk_adapter_core14.HardwareErrorCode.DeviceDisconnected,
|
|
4507
5149
|
tag: "DeviceDisconnected",
|
|
4508
5150
|
message: "Device disconnected"
|
|
4509
5151
|
});
|
|
@@ -4527,9 +5169,9 @@ var LedgerConnectorBase = class {
|
|
|
4527
5169
|
if (isAppStuckByApdu(err)) {
|
|
4528
5170
|
return {
|
|
4529
5171
|
success: false,
|
|
4530
|
-
error: (0,
|
|
5172
|
+
error: (0, import_hwk_adapter_core14.serializeConnectorError)(
|
|
4531
5173
|
Object.assign(new Error("Ledger app is unresponsive"), {
|
|
4532
|
-
code:
|
|
5174
|
+
code: import_hwk_adapter_core14.HardwareErrorCode.DeviceAppStuck,
|
|
4533
5175
|
_tag: ERROR_TAG.DeviceAppStuck,
|
|
4534
5176
|
originalError: err
|
|
4535
5177
|
})
|
|
@@ -4539,16 +5181,16 @@ var LedgerConnectorBase = class {
|
|
|
4539
5181
|
if (isTransportStuck(err)) {
|
|
4540
5182
|
return {
|
|
4541
5183
|
success: false,
|
|
4542
|
-
error: (0,
|
|
5184
|
+
error: (0, import_hwk_adapter_core14.serializeConnectorError)(
|
|
4543
5185
|
Object.assign(new Error("Device communication interrupted, please retry"), {
|
|
4544
|
-
code:
|
|
5186
|
+
code: import_hwk_adapter_core14.HardwareErrorCode.TransportError,
|
|
4545
5187
|
_tag: ERROR_TAG.DeviceTransportStuck,
|
|
4546
5188
|
originalError: err
|
|
4547
5189
|
})
|
|
4548
5190
|
)
|
|
4549
5191
|
};
|
|
4550
5192
|
}
|
|
4551
|
-
return { success: false, error: (0,
|
|
5193
|
+
return { success: false, error: (0, import_hwk_adapter_core14.serializeConnectorError)(err) };
|
|
4552
5194
|
}
|
|
4553
5195
|
}
|
|
4554
5196
|
async _dispatch(sessionId, method, params) {
|
|
@@ -4587,6 +5229,11 @@ var LedgerConnectorBase = class {
|
|
|
4587
5229
|
return solSignTransaction(ctx, sessionId, params);
|
|
4588
5230
|
case "solSignMessage":
|
|
4589
5231
|
return solSignMessage(ctx, sessionId, params);
|
|
5232
|
+
// ZCASH
|
|
5233
|
+
case "zcashGetFullViewingKey":
|
|
5234
|
+
return zcashGetFullViewingKey(ctx, sessionId, params);
|
|
5235
|
+
case "zcashGetShieldedAddress":
|
|
5236
|
+
return zcashGetShieldedAddress(ctx, sessionId, params);
|
|
4590
5237
|
// TRON
|
|
4591
5238
|
case "tronGetAddress":
|
|
4592
5239
|
return tronGetAddress(ctx, sessionId, params);
|
|
@@ -4611,7 +5258,7 @@ var LedgerConnectorBase = class {
|
|
|
4611
5258
|
try {
|
|
4612
5259
|
return await apps.install(p.appName, ({ progress }) => {
|
|
4613
5260
|
ctx.emit("ui-event", {
|
|
4614
|
-
type:
|
|
5261
|
+
type: import_hwk_adapter_core14.EConnectorInteraction.AppInstallProgress,
|
|
4615
5262
|
payload: {
|
|
4616
5263
|
sessionId,
|
|
4617
5264
|
appName: p.appName,
|
|
@@ -4916,7 +5563,7 @@ var LedgerConnectorBase = class {
|
|
|
4916
5563
|
* at every catch site. Falls through unchanged for unknown methods.
|
|
4917
5564
|
*/
|
|
4918
5565
|
_ctxForMethod(method) {
|
|
4919
|
-
const prefix = /^(evm|btc|sol|tron)/.exec(method)?.[1];
|
|
5566
|
+
const prefix = /^(evm|btc|sol|tron|zcash)/.exec(method)?.[1];
|
|
4920
5567
|
const defaultAppName = prefix ? METHOD_PREFIX_TO_APP_NAME[prefix] : void 0;
|
|
4921
5568
|
if (!defaultAppName) return this._ctx;
|
|
4922
5569
|
return {
|
|
@@ -4961,6 +5608,7 @@ var LedgerConnectorBase = class {
|
|
|
4961
5608
|
SignerEth,
|
|
4962
5609
|
SignerManager,
|
|
4963
5610
|
SignerSol,
|
|
5611
|
+
SignerZcash,
|
|
4964
5612
|
debugLog,
|
|
4965
5613
|
deviceActionToPromise,
|
|
4966
5614
|
isDeviceLockedError,
|