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