@onekeyfe/hwk-ledger-adapter 1.2.5-alpha.4 → 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +39 -81
- package/dist/index.d.ts +39 -81
- package/dist/index.js +834 -1617
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +828 -1631
- 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,103 +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
|
|
550
|
+
getChainFingerprint
|
|
619
551
|
}) {
|
|
620
552
|
return async function allNetworkGetAddress(connectId, _deviceId, params) {
|
|
621
|
-
debugLog("[LedgerAdapter][REQ]", {
|
|
622
|
-
method: "allNetworkGetAddress",
|
|
623
|
-
connectId,
|
|
624
|
-
itemCount: params.bundle.length
|
|
625
|
-
});
|
|
626
|
-
const target = (0, import_hwk_adapter_core2.resolveHardwareOperationTarget)(connectId, params.operationId, "ledger");
|
|
627
|
-
if (!target.success) return target;
|
|
628
|
-
const effectiveTargetId = target.payload.targetId ?? "";
|
|
629
|
-
let releaseOperationRetention;
|
|
630
|
-
try {
|
|
631
|
-
releaseOperationRetention = target.payload.operationId ? retainOperation(target.payload.operationId) : void 0;
|
|
632
|
-
} catch (error) {
|
|
633
|
-
return errorToFailure(error);
|
|
634
|
-
}
|
|
635
|
-
const cancelScope = createCancelScope(
|
|
636
|
-
ledgerQueueKey({ operationId: target.payload.operationId, connectId: effectiveTargetId })
|
|
637
|
-
);
|
|
553
|
+
debugLog("[LedgerAdapter][REQ]", { method: "allNetworkGetAddress", connectId, params });
|
|
638
554
|
const installContext = {};
|
|
639
555
|
const commonParams = {
|
|
640
|
-
autoInstallApp: params.autoInstallApp
|
|
641
|
-
operationId: target.payload.operationId,
|
|
642
|
-
knownConnections: params.knownConnections,
|
|
643
|
-
extra: params.extra,
|
|
644
|
-
allowDeviceSelection: params.allowDeviceSelection,
|
|
645
|
-
supportedTransports: params.supportedTransports
|
|
556
|
+
autoInstallApp: params.autoInstallApp
|
|
646
557
|
};
|
|
647
558
|
const chainFingerprints = /* @__PURE__ */ new Map();
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
itemDeviceId,
|
|
662
|
-
method,
|
|
663
|
-
item,
|
|
664
|
-
commonParams,
|
|
665
|
-
installContext
|
|
666
|
-
);
|
|
667
|
-
},
|
|
668
|
-
attachIdentity: async ({ item, chain, payload }) => attachLedgerIdentity(
|
|
669
|
-
getChainFingerprint,
|
|
670
|
-
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,
|
|
671
572
|
item,
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
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;
|
|
698
601
|
};
|
|
699
602
|
}
|
|
700
|
-
function buildCancelledFailure(signal) {
|
|
701
|
-
const reason = signal.reason;
|
|
702
|
-
const code = typeof reason?.code === "number" ? reason.code : import_hwk_adapter_core2.HardwareErrorCode.UserAborted;
|
|
703
|
-
const message = typeof reason?.message === "string" ? reason.message : "";
|
|
704
|
-
return (0, import_hwk_adapter_core2.failure)(code, message || "All-network get-address cancelled");
|
|
705
|
-
}
|
|
706
603
|
function isTopLevelAllNetworkFailure(response) {
|
|
707
604
|
if (response.success) {
|
|
708
605
|
return false;
|
|
709
606
|
}
|
|
710
607
|
const code = response.payload?.code;
|
|
711
|
-
return code === import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch ||
|
|
608
|
+
return code === import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch || code === import_hwk_adapter_core2.HardwareErrorCode.UserAborted || code === import_hwk_adapter_core2.HardwareErrorCode.UserRejected;
|
|
712
609
|
}
|
|
713
610
|
function getItemDeviceId(item) {
|
|
714
611
|
const { deviceId } = item;
|
|
@@ -738,18 +635,8 @@ function normalizeLedgerAllNetworkItem(method, item) {
|
|
|
738
635
|
const coin = LEDGER_BTC_NETWORK_COIN_MAP[item.network];
|
|
739
636
|
return coin ? { ...item, coin } : item;
|
|
740
637
|
}
|
|
741
|
-
async function attachLedgerIdentity(getChainFingerprint, connectId, item, chain, payload, chainFingerprints
|
|
742
|
-
const
|
|
743
|
-
if (!knownFingerprint && cancelSignal.aborted) {
|
|
744
|
-
const cancelled = buildCancelledFailure(cancelSignal);
|
|
745
|
-
return { ...item, success: false, payload: cancelled.payload };
|
|
746
|
-
}
|
|
747
|
-
const fingerprint = knownFingerprint || await bootstrapChainFingerprint(
|
|
748
|
-
getChainFingerprint,
|
|
749
|
-
context.connection?.connectId ?? connectId,
|
|
750
|
-
chain,
|
|
751
|
-
context
|
|
752
|
-
);
|
|
638
|
+
async function attachLedgerIdentity(getChainFingerprint, connectId, item, chain, payload, chainFingerprints) {
|
|
639
|
+
const fingerprint = getItemDeviceId(item) || chainFingerprints.get(chain) || await bootstrapChainFingerprint(getChainFingerprint, connectId, chain);
|
|
753
640
|
if (!fingerprint) {
|
|
754
641
|
return buildFingerprintBootstrapFailure(item, chain);
|
|
755
642
|
}
|
|
@@ -770,8 +657,8 @@ async function attachLedgerIdentity(getChainFingerprint, connectId, item, chain,
|
|
|
770
657
|
}
|
|
771
658
|
};
|
|
772
659
|
}
|
|
773
|
-
async function bootstrapChainFingerprint(getChainFingerprint, connectId, chain
|
|
774
|
-
const response = await getChainFingerprint(connectId, chain
|
|
660
|
+
async function bootstrapChainFingerprint(getChainFingerprint, connectId, chain) {
|
|
661
|
+
const response = await getChainFingerprint(connectId, chain);
|
|
775
662
|
return response.success ? response.payload : "";
|
|
776
663
|
}
|
|
777
664
|
function buildFingerprintBootstrapFailure(item, chain) {
|
|
@@ -864,16 +751,6 @@ function isLedgerBleDescriptor(connectionType, descriptor) {
|
|
|
864
751
|
function formatDeviceMismatchError(expected, actual) {
|
|
865
752
|
return `Wrong device: expected ${expected}, got ${actual}`;
|
|
866
753
|
}
|
|
867
|
-
var LOG_REDACTED_RESULT_KEYS = ["ufvk", "orchardFvk"];
|
|
868
|
-
function redactResultForLog(result) {
|
|
869
|
-
if (!result || typeof result !== "object") return result;
|
|
870
|
-
const keys = LOG_REDACTED_RESULT_KEYS.filter((key) => key in result);
|
|
871
|
-
if (!keys.length) return result;
|
|
872
|
-
return { ...result, ...Object.fromEntries(keys.map((key) => [key, "[redacted]"])) };
|
|
873
|
-
}
|
|
874
|
-
function isLostConnectionError(err) {
|
|
875
|
-
return isDeviceDisconnectedError(err) || isDeviceNotAdvertisingError(err) || isTimeoutError(err) || isConnectionLevelError(err);
|
|
876
|
-
}
|
|
877
754
|
var BTC_HIGH_INDEX_THRESHOLD = 100;
|
|
878
755
|
function btcAccountIndexFromPath(path) {
|
|
879
756
|
const segments = path.replace(/^m\//, "").split("/");
|
|
@@ -885,28 +762,9 @@ function btcAccountIndexFromPath(path) {
|
|
|
885
762
|
var _LedgerAdapter = class _LedgerAdapter {
|
|
886
763
|
constructor(connector, options) {
|
|
887
764
|
this.vendor = "ledger";
|
|
888
|
-
// Cancel frees the DMK action and its intent-queue slot, but cannot retract a
|
|
889
|
-
// confirmation screen the device is already showing.
|
|
890
|
-
this.cancelCapability = "stops-waiting";
|
|
891
765
|
this.emitter = new import_hwk_adapter_core3.TypedEventEmitter();
|
|
892
|
-
this._operations = new import_hwk_adapter_core3.OperationRegistry({
|
|
893
|
-
vendor: "ledger",
|
|
894
|
-
onEnded: (operation, reason) => {
|
|
895
|
-
this.emitter.emit(import_hwk_adapter_core3.SDK.OPERATION_ENDED, {
|
|
896
|
-
type: import_hwk_adapter_core3.SDK.OPERATION_ENDED,
|
|
897
|
-
payload: { operationId: operation.operationId, reason }
|
|
898
|
-
});
|
|
899
|
-
if (reason === "timeout") {
|
|
900
|
-
void this._releaseOperationConnection(operation);
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
});
|
|
904
766
|
this._discoveredDevices = /* @__PURE__ */ new Map();
|
|
905
767
|
this._sessions = /* @__PURE__ */ new Map();
|
|
906
|
-
// Transport each session was opened on, by sessionId. The adapter-wide
|
|
907
|
-
// `_activeConnectionType` moves with every discovery and can go stale.
|
|
908
|
-
this._sessionTransports = /* @__PURE__ */ new Map();
|
|
909
|
-
this._selectedBleReconnectTargets = /* @__PURE__ */ new Map();
|
|
910
768
|
this._uiRegistry = new import_hwk_adapter_core3.UiRequestRegistry();
|
|
911
769
|
// BTC App rejects account index >= 100 unless display=true. Cached per
|
|
912
770
|
// adapter instance: first 100+ path asks the user once via UI request,
|
|
@@ -920,31 +778,10 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
920
778
|
this._deviceAuthenticityQueueTail = Promise.resolve();
|
|
921
779
|
// Shared across concurrent callers — only `cancel()` aborts.
|
|
922
780
|
this._doConnectAbortController = null;
|
|
923
|
-
this._unsettledConnectorOperations = /* @__PURE__ */ new Map();
|
|
924
|
-
this._connectorIdleWaiters = /* @__PURE__ */ new Set();
|
|
925
|
-
this._resetPromise = null;
|
|
926
|
-
this._stateGeneration = 0;
|
|
927
|
-
this._connectorTeardownTail = Promise.resolve();
|
|
928
|
-
this._pendingConnectorTeardowns = 0;
|
|
929
|
-
this._activeOperationJobs = /* @__PURE__ */ new Set();
|
|
930
|
-
this._pendingOperationDisconnects = /* @__PURE__ */ new Set();
|
|
931
781
|
this._installProgressLastEmittedValue = -Infinity;
|
|
932
782
|
this.allNetworkGetAddress = createAllNetworkGetAddress({
|
|
933
783
|
callChain: this.callChain.bind(this),
|
|
934
|
-
getChainFingerprint:
|
|
935
|
-
try {
|
|
936
|
-
const fingerprint = await this._computeChainFingerprint(
|
|
937
|
-
chain,
|
|
938
|
-
(method, params) => this.connectorCall(connectId, method, params, void 0, void 0, void 0, context)
|
|
939
|
-
);
|
|
940
|
-
return (0, import_hwk_adapter_core3.success)(fingerprint);
|
|
941
|
-
} catch (error) {
|
|
942
|
-
return this.errorToFailure(error);
|
|
943
|
-
}
|
|
944
|
-
},
|
|
945
|
-
retainOperation: (operationId) => this._operations.retain(operationId),
|
|
946
|
-
errorToFailure: (error) => this.errorToFailure(error),
|
|
947
|
-
createCancelScope: (queueKey) => this._jobQueue.createCancelScope(queueKey)
|
|
784
|
+
getChainFingerprint: (connectId, chain) => this.getChainFingerprint(connectId, "", chain)
|
|
948
785
|
});
|
|
949
786
|
// ---------------------------------------------------------------------------
|
|
950
787
|
// Private helpers
|
|
@@ -954,7 +791,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
954
791
|
*
|
|
955
792
|
* - If a session already exists for the given connectId, reuse it.
|
|
956
793
|
* - If ANY session exists (Ledger IDs are ephemeral), reuse it.
|
|
957
|
-
* - Otherwise: search →
|
|
794
|
+
* - Otherwise: search → exactly 1 USB device auto-connects; multiple or none throws.
|
|
958
795
|
*/
|
|
959
796
|
// Mutex for ensureConnected — prevents concurrent calls from establishing duplicate connections
|
|
960
797
|
this._connectingPromise = null;
|
|
@@ -971,12 +808,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
971
808
|
});
|
|
972
809
|
};
|
|
973
810
|
this.deviceDisconnectHandler = (data) => {
|
|
974
|
-
const activeOperation = this._operations.findActiveByConnectionKey(data.connectId);
|
|
975
|
-
if (activeOperation && this._activeOperationJobs.has(activeOperation.operationId)) {
|
|
976
|
-
this._pendingOperationDisconnects.add(activeOperation.operationId);
|
|
977
|
-
} else {
|
|
978
|
-
this._operations.endByConnectionKey(data.connectId, "disconnect");
|
|
979
|
-
}
|
|
980
811
|
this._discoveredDevices.delete(data.connectId);
|
|
981
812
|
this._sessions.delete(data.connectId);
|
|
982
813
|
this.emitter.emit(import_hwk_adapter_core3.DEVICE.DISCONNECT, {
|
|
@@ -985,8 +816,10 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
985
816
|
});
|
|
986
817
|
};
|
|
987
818
|
// Forward connector `ui-event` to the public hw.emitter so consumers only
|
|
988
|
-
// need to subscribe in one place.
|
|
989
|
-
// 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.
|
|
990
823
|
this.uiEventForwarder = (event) => {
|
|
991
824
|
if (event.type === import_hwk_adapter_core3.EConnectorInteraction.AppInstallProgress) {
|
|
992
825
|
let connectId;
|
|
@@ -1031,28 +864,11 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1031
864
|
this._jobQueue = new import_hwk_adapter_core3.DeviceJobQueue();
|
|
1032
865
|
this.registerEventListeners();
|
|
1033
866
|
}
|
|
1034
|
-
_finishBleBinding(status) {
|
|
1035
|
-
const selectionRequestId = this._bindingSelectionRequestId;
|
|
1036
|
-
this._bindingSelectionRequestId = void 0;
|
|
1037
|
-
if (selectionRequestId)
|
|
1038
|
-
this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.DEVICE_BINDING_STATUS, {
|
|
1039
|
-
type: import_hwk_adapter_core3.UI_REQUEST.DEVICE_BINDING_STATUS,
|
|
1040
|
-
payload: { selectionRequestId, status }
|
|
1041
|
-
});
|
|
1042
|
-
}
|
|
1043
|
-
_isBleConnection() {
|
|
1044
|
-
return isLedgerBleConnectionType(this._activeConnectionType ?? this.connector.connectionType);
|
|
1045
|
-
}
|
|
1046
867
|
// Transport
|
|
1047
868
|
get activeTransport() {
|
|
1048
|
-
return this.
|
|
869
|
+
return isLedgerBleConnectionType(this.connector.connectionType) ? "ble" : "hid";
|
|
1049
870
|
}
|
|
1050
871
|
getAvailableTransports() {
|
|
1051
|
-
if (this.connector.availableTransports) {
|
|
1052
|
-
return this.connector.availableTransports.map(
|
|
1053
|
-
(transport) => transport === "ble" ? "ble" : "hid"
|
|
1054
|
-
);
|
|
1055
|
-
}
|
|
1056
872
|
return this.activeTransport ? [this.activeTransport] : [];
|
|
1057
873
|
}
|
|
1058
874
|
// Connector is bound at construction; switching requires a new adapter.
|
|
@@ -1069,40 +885,21 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1069
885
|
* The next operation will re-discover and re-connect automatically.
|
|
1070
886
|
*/
|
|
1071
887
|
resetState() {
|
|
1072
|
-
void this._resetStateAndDisconnectSessions();
|
|
1073
|
-
}
|
|
1074
|
-
_resetStateAndDisconnectSessions() {
|
|
1075
|
-
if (this._resetPromise) return this._resetPromise;
|
|
1076
|
-
const sessionIds = new Set(this._sessions.values());
|
|
1077
|
-
this._stateGeneration += 1;
|
|
1078
|
-
this._finishBleBinding("cancelled");
|
|
1079
|
-
this._operations.endAll("runtime-reset");
|
|
1080
|
-
this._doConnectAbortController?.abort();
|
|
1081
888
|
this._discoveredDevices.clear();
|
|
1082
889
|
this._sessions.clear();
|
|
1083
|
-
this._sessionTransports.clear();
|
|
1084
|
-
this._selectedBleReconnectTargets.clear();
|
|
1085
890
|
this._connectingPromise = null;
|
|
1086
|
-
this._doConnectAbortController = null;
|
|
1087
891
|
this._uiRegistry.reset();
|
|
1088
892
|
this._jobQueue.clear();
|
|
1089
893
|
this._btcHighIndexConfirmedThisSession = false;
|
|
1090
|
-
const resetPromise = this._runConnectorTeardown(async () => {
|
|
1091
|
-
for (const sessionId of sessionIds) {
|
|
1092
|
-
await this.connector.disconnect(sessionId).catch(() => void 0);
|
|
1093
|
-
}
|
|
1094
|
-
});
|
|
1095
|
-
this._resetPromise = resetPromise;
|
|
1096
|
-
return resetPromise.finally(() => {
|
|
1097
|
-
if (this._resetPromise === resetPromise) {
|
|
1098
|
-
this._resetPromise = null;
|
|
1099
|
-
}
|
|
1100
|
-
});
|
|
1101
894
|
}
|
|
1102
895
|
async dispose() {
|
|
1103
|
-
|
|
896
|
+
this._uiRegistry.reset();
|
|
897
|
+
this._jobQueue.clear();
|
|
1104
898
|
this.unregisterEventListeners();
|
|
1105
899
|
this.connector.reset();
|
|
900
|
+
this._discoveredDevices.clear();
|
|
901
|
+
this._sessions.clear();
|
|
902
|
+
this._btcHighIndexConfirmedThisSession = false;
|
|
1106
903
|
this.emitter.removeAllListeners();
|
|
1107
904
|
}
|
|
1108
905
|
uiResponse(response) {
|
|
@@ -1112,32 +909,17 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1112
909
|
// Device management
|
|
1113
910
|
// ---------------------------------------------------------------------------
|
|
1114
911
|
async searchDevices(options) {
|
|
1115
|
-
return this._searchDevices(options);
|
|
1116
|
-
}
|
|
1117
|
-
async _searchDevices(options, signal) {
|
|
1118
912
|
debugLog("[LedgerAdapter][REQ]", { method: "searchDevices", params: options });
|
|
1119
913
|
try {
|
|
1120
914
|
if (options?.resetSession) {
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
if (signal) _LedgerAdapter._throwIfAborted(signal);
|
|
1127
|
-
const stateGeneration = this._stateGeneration;
|
|
1128
|
-
const devices = await this.connector.searchDevices(
|
|
1129
|
-
options?.transportType ? {
|
|
1130
|
-
transportType: options.transportType,
|
|
1131
|
-
waitForAll: options.waitForAllTransports
|
|
1132
|
-
} : void 0
|
|
1133
|
-
);
|
|
1134
|
-
if (signal) _LedgerAdapter._throwIfAborted(signal);
|
|
1135
|
-
if (stateGeneration !== this._stateGeneration) {
|
|
1136
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
1137
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.UserAborted,
|
|
1138
|
-
message: "Ledger discovery was reset"
|
|
1139
|
-
});
|
|
915
|
+
this._doConnectAbortController?.abort();
|
|
916
|
+
this._sessions.clear();
|
|
917
|
+
this._connectingPromise = null;
|
|
918
|
+
this._doConnectAbortController = null;
|
|
919
|
+
this._btcHighIndexConfirmedThisSession = false;
|
|
1140
920
|
}
|
|
921
|
+
await this._ensureDevicePermission();
|
|
922
|
+
const devices = await this.connector.searchDevices();
|
|
1141
923
|
this._discoveredDevices.clear();
|
|
1142
924
|
for (const d of devices) {
|
|
1143
925
|
if (d.connectId) {
|
|
@@ -1145,7 +927,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1145
927
|
}
|
|
1146
928
|
}
|
|
1147
929
|
if (this._discoveredDevices.size === 0) {
|
|
1148
|
-
await this._ensureDevicePermission(
|
|
930
|
+
await this._ensureDevicePermission();
|
|
1149
931
|
}
|
|
1150
932
|
const result = Array.from(this._discoveredDevices.values());
|
|
1151
933
|
debugLog("[LedgerAdapter][RES]", {
|
|
@@ -1164,233 +946,41 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1164
946
|
throw err;
|
|
1165
947
|
}
|
|
1166
948
|
}
|
|
1167
|
-
async searchDeviceTargets(options) {
|
|
1168
|
-
const devices = await this.searchDevices(options);
|
|
1169
|
-
return devices.map((device) => ({
|
|
1170
|
-
searchTargetId: device.connectId,
|
|
1171
|
-
searchTargetReusePolicy: (0, import_hwk_adapter_core3.resolveSearchTargetReusePolicy)(device),
|
|
1172
|
-
vendor: "ledger",
|
|
1173
|
-
connectionType: device.connectionType,
|
|
1174
|
-
kind: "physical",
|
|
1175
|
-
label: device.label,
|
|
1176
|
-
model: device.model,
|
|
1177
|
-
modelName: device.modelName,
|
|
1178
|
-
serialNumber: device.serialNumber
|
|
1179
|
-
}));
|
|
1180
|
-
}
|
|
1181
|
-
async listConnectionTargets(options) {
|
|
1182
|
-
const targets = await this.searchDeviceTargets(options);
|
|
1183
|
-
return targets.map(({ searchTargetId, ...target }) => ({
|
|
1184
|
-
...target,
|
|
1185
|
-
targetId: searchTargetId
|
|
1186
|
-
}));
|
|
1187
|
-
}
|
|
1188
949
|
// USB single-session invariant: evict all sessions, best-effort (see connectDevice).
|
|
1189
|
-
async _evictAllSessions(
|
|
1190
|
-
this._operations.endAll("explicit", preserveOperationId);
|
|
950
|
+
async _evictAllSessions() {
|
|
1191
951
|
if (this._sessions.size === 0) return;
|
|
1192
952
|
const stale = [...this._sessions.values()];
|
|
1193
953
|
this._sessions.clear();
|
|
1194
|
-
for (const sid of stale)
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
await this.connector.disconnect(sid);
|
|
1199
|
-
} catch {
|
|
1200
|
-
}
|
|
954
|
+
for (const sid of stale) {
|
|
955
|
+
try {
|
|
956
|
+
await this.connector.disconnect(sid);
|
|
957
|
+
} catch {
|
|
1201
958
|
}
|
|
1202
|
-
}
|
|
959
|
+
}
|
|
1203
960
|
}
|
|
1204
961
|
static _createDeviceBusyError(method) {
|
|
1205
962
|
return Object.assign(new Error(`Ledger device is busy while calling ${method}`), {
|
|
1206
963
|
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceBusy
|
|
1207
964
|
});
|
|
1208
965
|
}
|
|
1209
|
-
async connectDevice(
|
|
1210
|
-
try {
|
|
1211
|
-
return await this._jobQueue.enqueue(
|
|
1212
|
-
searchTargetId || "__ledger_connect__",
|
|
1213
|
-
async (signal) => {
|
|
1214
|
-
const connected = await this._connectTarget(searchTargetId, void 0, signal);
|
|
1215
|
-
if (!connected.success) return connected;
|
|
1216
|
-
return this._createOperation(searchTargetId, connected.payload);
|
|
1217
|
-
},
|
|
1218
|
-
{
|
|
1219
|
-
label: "connectDevice",
|
|
1220
|
-
rejectIfBusy: true,
|
|
1221
|
-
busyError: _LedgerAdapter._createDeviceBusyError("connectDevice")
|
|
1222
|
-
}
|
|
1223
|
-
);
|
|
1224
|
-
} catch (error) {
|
|
1225
|
-
return this.errorToFailure(error);
|
|
1226
|
-
}
|
|
1227
|
-
}
|
|
1228
|
-
/** Ledger binds whichever BLE device the user picks; its wallet is not checked. */
|
|
1229
|
-
async bindBleDevice(params) {
|
|
1230
|
-
try {
|
|
1231
|
-
return await this._jobQueue.enqueue(
|
|
1232
|
-
"__ledger_bind_ble__",
|
|
1233
|
-
async (signal) => {
|
|
1234
|
-
if (!this.getAvailableTransports().includes("ble")) {
|
|
1235
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
1236
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.TransportNotAvailable,
|
|
1237
|
-
message: "Ledger Bluetooth transport is not available"
|
|
1238
|
-
});
|
|
1239
|
-
}
|
|
1240
|
-
this._activeConnectionType = "ble";
|
|
1241
|
-
await this._ensureDevicePermission(void 0, void 0, signal);
|
|
1242
|
-
const attempt = {
|
|
1243
|
-
extra: params.extra,
|
|
1244
|
-
bindingReason: "manual-rebind"
|
|
1245
|
-
};
|
|
1246
|
-
try {
|
|
1247
|
-
const connectId = await this._connectFirstOrSelect(
|
|
1248
|
-
[],
|
|
1249
|
-
void 0,
|
|
1250
|
-
true,
|
|
1251
|
-
void 0,
|
|
1252
|
-
attempt,
|
|
1253
|
-
signal
|
|
1254
|
-
);
|
|
1255
|
-
if (!attempt.bindingSaved) {
|
|
1256
|
-
await this._dropSession(connectId, signal);
|
|
1257
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
1258
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.UnknownError,
|
|
1259
|
-
message: "Bluetooth binding could not be saved",
|
|
1260
|
-
origin: "host"
|
|
1261
|
-
});
|
|
1262
|
-
}
|
|
1263
|
-
return (0, import_hwk_adapter_core3.success)(connectId);
|
|
1264
|
-
} catch (error) {
|
|
1265
|
-
this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
|
|
1266
|
-
throw error;
|
|
1267
|
-
}
|
|
1268
|
-
},
|
|
1269
|
-
{
|
|
1270
|
-
label: "bindBleDevice",
|
|
1271
|
-
rejectIfBusy: true,
|
|
1272
|
-
busyError: _LedgerAdapter._createDeviceBusyError("bindBleDevice")
|
|
1273
|
-
}
|
|
1274
|
-
);
|
|
1275
|
-
} catch (error) {
|
|
1276
|
-
return this.errorToFailure(error);
|
|
1277
|
-
}
|
|
1278
|
-
}
|
|
1279
|
-
async acquireOperation(connectId, context) {
|
|
1280
|
-
try {
|
|
1281
|
-
return await this._jobQueue.enqueue(
|
|
1282
|
-
connectId || "__ledger_acquire__",
|
|
1283
|
-
async (signal) => {
|
|
1284
|
-
const transport = this._isBleConnection() ? "ble" : "usb";
|
|
1285
|
-
const hint = context.knownConnections?.find(
|
|
1286
|
-
(connection) => connection.transport === transport
|
|
1287
|
-
);
|
|
1288
|
-
const target = hint && hint.transport !== "qr" ? hint.connectId : connectId;
|
|
1289
|
-
await this._ensureDevicePermission(target, void 0, signal);
|
|
1290
|
-
const attempt = {
|
|
1291
|
-
...context,
|
|
1292
|
-
extra: context.extra ? { ...context.extra } : void 0
|
|
1293
|
-
};
|
|
1294
|
-
try {
|
|
1295
|
-
const resolvedConnectId = await this.ensureConnected(
|
|
1296
|
-
target,
|
|
1297
|
-
signal,
|
|
1298
|
-
true,
|
|
1299
|
-
void 0,
|
|
1300
|
-
attempt
|
|
1301
|
-
);
|
|
1302
|
-
_LedgerAdapter._throwIfAborted(signal);
|
|
1303
|
-
return this._createOperation(connectId, resolvedConnectId);
|
|
1304
|
-
} catch (error) {
|
|
1305
|
-
this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
|
|
1306
|
-
throw error;
|
|
1307
|
-
}
|
|
1308
|
-
},
|
|
1309
|
-
{
|
|
1310
|
-
label: "acquireOperation",
|
|
1311
|
-
rejectIfBusy: true,
|
|
1312
|
-
busyError: _LedgerAdapter._createDeviceBusyError("acquireOperation")
|
|
1313
|
-
}
|
|
1314
|
-
);
|
|
1315
|
-
} catch (error) {
|
|
1316
|
-
return this.errorToFailure(error);
|
|
1317
|
-
}
|
|
1318
|
-
}
|
|
1319
|
-
_createOperation(searchTargetId, resolvedConnectId) {
|
|
1320
|
-
this._operations.endByConnectionKey(resolvedConnectId, "explicit");
|
|
1321
|
-
const sessionId = this._sessions.get(resolvedConnectId);
|
|
1322
|
-
if (sessionId) this._operations.endByConnectionKey(sessionId, "explicit");
|
|
1323
|
-
const connectionType = sessionId && this._sessionTransports.get(sessionId) || (this._isBleConnection() ? "ble" : "usb");
|
|
1324
|
-
const device = this._discoveredDevices.get(resolvedConnectId) ?? {
|
|
1325
|
-
vendor: "ledger",
|
|
1326
|
-
model: "unknown",
|
|
1327
|
-
firmwareVersion: "",
|
|
1328
|
-
deviceId: "",
|
|
1329
|
-
connectId: resolvedConnectId,
|
|
1330
|
-
connectionType
|
|
1331
|
-
};
|
|
1332
|
-
const operation = this._operations.create({
|
|
1333
|
-
searchTargetId,
|
|
1334
|
-
connectId: resolvedConnectId,
|
|
1335
|
-
device,
|
|
1336
|
-
connectionType,
|
|
1337
|
-
connectionKeys: [this._sessions.get(resolvedConnectId) ?? ""]
|
|
1338
|
-
});
|
|
1339
|
-
return (0, import_hwk_adapter_core3.success)(operation.operationId);
|
|
1340
|
-
}
|
|
1341
|
-
async _connectTarget(connectId, preserveOperationId, signal) {
|
|
966
|
+
async connectDevice(connectId) {
|
|
1342
967
|
debugLog("[LedgerAdapter][REQ]", { method: "connectDevice", connectId, params: { connectId } });
|
|
1343
968
|
try {
|
|
1344
|
-
this.
|
|
1345
|
-
const discoveredType = this._discoveredDevices.get(connectId)?.connectionType;
|
|
1346
|
-
if (discoveredType === "usb" || discoveredType === "ble") {
|
|
1347
|
-
this._activeConnectionType = discoveredType;
|
|
1348
|
-
}
|
|
1349
|
-
if (this._isBleConnection() && !connectId) {
|
|
969
|
+
if (isLedgerBleConnectionType(this.connector.connectionType) && !connectId) {
|
|
1350
970
|
throw Object.assign(new Error("Ledger BLE connectId is required."), {
|
|
1351
971
|
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
|
|
1352
972
|
});
|
|
1353
973
|
}
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
const isMultiTransport = (this.connector.availableTransports?.length ?? 0) > 1;
|
|
1357
|
-
if (!isMultiTransport && this._isBleConnection()) {
|
|
1358
|
-
const previousSessionId = this._sessions.get(connectId);
|
|
1359
|
-
this._operations.endByConnectionKey(connectId, "explicit", preserveOperationId);
|
|
1360
|
-
if (previousSessionId) {
|
|
1361
|
-
this._operations.endByConnectionKey(previousSessionId, "explicit", preserveOperationId);
|
|
1362
|
-
this._sessions.delete(connectId);
|
|
1363
|
-
await this.connector.disconnect(previousSessionId).catch(() => void 0);
|
|
1364
|
-
}
|
|
1365
|
-
} else {
|
|
1366
|
-
await this._evictAllSessions(preserveOperationId);
|
|
1367
|
-
}
|
|
1368
|
-
if (signal) _LedgerAdapter._throwIfAborted(signal);
|
|
1369
|
-
const stateGeneration = this._stateGeneration;
|
|
1370
|
-
const releaseOperation = this._retainConnectorOperation(`connect:${connectId}`);
|
|
1371
|
-
let session;
|
|
1372
|
-
this._connectingConnectId = connectId;
|
|
1373
|
-
try {
|
|
1374
|
-
session = this.connector.availableTransports?.length ? await this.connector.connect(connectId, {
|
|
1375
|
-
transportType: this._activeConnectionType ?? "usb"
|
|
1376
|
-
}) : await this.connector.connect(connectId);
|
|
1377
|
-
if (signal?.aborted || stateGeneration !== this._stateGeneration) {
|
|
1378
|
-
await this.connector.disconnect(session.sessionId).catch(() => void 0);
|
|
1379
|
-
throw Object.assign(new Error("Ledger connection aborted"), {
|
|
1380
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.UserAborted
|
|
1381
|
-
});
|
|
1382
|
-
}
|
|
1383
|
-
} finally {
|
|
1384
|
-
if (this._connectingConnectId === connectId) this._connectingConnectId = void 0;
|
|
1385
|
-
releaseOperation();
|
|
974
|
+
if (!isLedgerBleConnectionType(this.connector.connectionType)) {
|
|
975
|
+
await this._evictAllSessions();
|
|
1386
976
|
}
|
|
1387
|
-
|
|
1388
|
-
this.
|
|
1389
|
-
this.
|
|
977
|
+
await this._ensureDevicePermission(connectId);
|
|
978
|
+
const session = await this.connector.connect(connectId);
|
|
979
|
+
this._sessions.set(connectId, session.sessionId);
|
|
1390
980
|
if (session.deviceInfo) {
|
|
1391
|
-
this._discoveredDevices.set(
|
|
981
|
+
this._discoveredDevices.set(connectId, session.deviceInfo);
|
|
1392
982
|
}
|
|
1393
|
-
const result = (0, import_hwk_adapter_core3.success)(
|
|
983
|
+
const result = (0, import_hwk_adapter_core3.success)(connectId);
|
|
1394
984
|
debugLog("[LedgerAdapter][RES]", { method: "connectDevice", success: true, payload: result });
|
|
1395
985
|
return result;
|
|
1396
986
|
} catch (err) {
|
|
@@ -1403,60 +993,30 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1403
993
|
return failureResult;
|
|
1404
994
|
}
|
|
1405
995
|
}
|
|
1406
|
-
async
|
|
1407
|
-
const operation = this._operations.find(operationId);
|
|
1408
|
-
if (!operation) {
|
|
1409
|
-
this._operations.resolve(operationId);
|
|
1410
|
-
return;
|
|
1411
|
-
}
|
|
1412
|
-
const endedOperation = this._operations.end(operationId, "explicit");
|
|
1413
|
-
if (!endedOperation) return;
|
|
1414
|
-
const { connectId } = operation;
|
|
996
|
+
async disconnectDevice(connectId) {
|
|
1415
997
|
debugLog("[LedgerAdapter][REQ]", {
|
|
1416
|
-
method: "
|
|
998
|
+
method: "disconnectDevice",
|
|
1417
999
|
connectId,
|
|
1418
1000
|
params: { connectId }
|
|
1419
1001
|
});
|
|
1420
1002
|
try {
|
|
1421
|
-
|
|
1422
|
-
|
|
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 });
|
|
1423
1009
|
} catch (err) {
|
|
1424
1010
|
const e = err;
|
|
1425
1011
|
debugLog("[LedgerAdapter][RES]", {
|
|
1426
|
-
method: "
|
|
1012
|
+
method: "disconnectDevice",
|
|
1427
1013
|
success: false,
|
|
1428
1014
|
error: { message: e?.message, _tag: e?._tag, code: e?.code ?? e?.errorCode }
|
|
1429
1015
|
});
|
|
1430
1016
|
throw err;
|
|
1431
1017
|
}
|
|
1432
1018
|
}
|
|
1433
|
-
async
|
|
1434
|
-
const sessionIds = /* @__PURE__ */ new Set();
|
|
1435
|
-
for (const [connectId, sessionId] of this._sessions) {
|
|
1436
|
-
if (connectId === operation.connectId || operation.connectionKeys.includes(connectId) || operation.connectionKeys.includes(sessionId)) {
|
|
1437
|
-
this._sessions.delete(connectId);
|
|
1438
|
-
sessionIds.add(sessionId);
|
|
1439
|
-
}
|
|
1440
|
-
}
|
|
1441
|
-
for (const sessionId of sessionIds) {
|
|
1442
|
-
await this._runConnectorTeardown(
|
|
1443
|
-
() => this.connector.disconnect(sessionId).catch(() => void 0)
|
|
1444
|
-
);
|
|
1445
|
-
}
|
|
1446
|
-
}
|
|
1447
|
-
async _releaseLostOperationConnection(operationId) {
|
|
1448
|
-
const endedOperation = this._operations.end(operationId, "disconnect");
|
|
1449
|
-
if (!endedOperation) return;
|
|
1450
|
-
this._discoveredDevices.delete(endedOperation.connectId);
|
|
1451
|
-
await this._releaseOperationConnection(endedOperation);
|
|
1452
|
-
}
|
|
1453
|
-
async getDeviceInfo(connectIdOrOperationId, deviceId) {
|
|
1454
|
-
let connectId;
|
|
1455
|
-
try {
|
|
1456
|
-
connectId = (0, import_hwk_adapter_core3.isHardwareOperationId)(connectIdOrOperationId) ? this._operations.resolve(connectIdOrOperationId).connectId : connectIdOrOperationId;
|
|
1457
|
-
} catch (error) {
|
|
1458
|
-
return this.errorToFailure(error);
|
|
1459
|
-
}
|
|
1019
|
+
async getDeviceInfo(connectId, deviceId) {
|
|
1460
1020
|
debugLog("[LedgerAdapter][REQ]", {
|
|
1461
1021
|
method: "getDeviceInfo",
|
|
1462
1022
|
connectId,
|
|
@@ -1491,9 +1051,12 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1491
1051
|
success: false,
|
|
1492
1052
|
error: { message: e?.message, _tag: e?._tag, code: e?.code ?? e?.errorCode }
|
|
1493
1053
|
});
|
|
1494
|
-
|
|
1054
|
+
throw err;
|
|
1495
1055
|
}
|
|
1496
1056
|
}
|
|
1057
|
+
getSupportedChains() {
|
|
1058
|
+
return ["evm", "btc", "sol", "tron"];
|
|
1059
|
+
}
|
|
1497
1060
|
// ---------------------------------------------------------------------------
|
|
1498
1061
|
// Chain call helper
|
|
1499
1062
|
// ---------------------------------------------------------------------------
|
|
@@ -1528,23 +1091,13 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1528
1091
|
if (params && typeof params === "object") {
|
|
1529
1092
|
const {
|
|
1530
1093
|
autoInstallApp,
|
|
1531
|
-
operationId,
|
|
1532
1094
|
passphraseState: _passphraseState,
|
|
1533
1095
|
useEmptyPassphrase: _useEmptyPassphrase,
|
|
1534
|
-
knownConnections,
|
|
1535
|
-
extra,
|
|
1536
|
-
allowDeviceSelection,
|
|
1537
|
-
supportedTransports,
|
|
1538
1096
|
...rest
|
|
1539
1097
|
} = params;
|
|
1540
1098
|
return {
|
|
1541
1099
|
commonParams: {
|
|
1542
|
-
autoInstallApp: typeof autoInstallApp === "boolean" ? autoInstallApp : void 0
|
|
1543
|
-
operationId: typeof operationId === "string" ? operationId : void 0,
|
|
1544
|
-
knownConnections,
|
|
1545
|
-
extra,
|
|
1546
|
-
allowDeviceSelection: typeof allowDeviceSelection === "boolean" ? allowDeviceSelection : void 0,
|
|
1547
|
-
supportedTransports
|
|
1100
|
+
autoInstallApp: typeof autoInstallApp === "boolean" ? autoInstallApp : void 0
|
|
1548
1101
|
},
|
|
1549
1102
|
rest
|
|
1550
1103
|
};
|
|
@@ -1720,28 +1273,9 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1720
1273
|
);
|
|
1721
1274
|
}
|
|
1722
1275
|
// ---------------------------------------------------------------------------
|
|
1723
|
-
//
|
|
1724
|
-
//
|
|
1725
|
-
|
|
1726
|
-
return this.callChainWithMergedParams(
|
|
1727
|
-
connectId,
|
|
1728
|
-
deviceId,
|
|
1729
|
-
"zcash",
|
|
1730
|
-
"zcashGetFullViewingKey",
|
|
1731
|
-
params
|
|
1732
|
-
);
|
|
1733
|
-
}
|
|
1734
|
-
zcashGetShieldedAddress(connectId, deviceId, params) {
|
|
1735
|
-
return this.callChainWithMergedParams(
|
|
1736
|
-
connectId,
|
|
1737
|
-
deviceId,
|
|
1738
|
-
"zcash",
|
|
1739
|
-
"zcashGetShieldedAddress",
|
|
1740
|
-
params
|
|
1741
|
-
);
|
|
1742
|
-
}
|
|
1743
|
-
// ---------------------------------------------------------------------------
|
|
1744
|
-
// 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.
|
|
1745
1279
|
// ---------------------------------------------------------------------------
|
|
1746
1280
|
async installApp(connectId, appName) {
|
|
1747
1281
|
try {
|
|
@@ -1827,7 +1361,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1827
1361
|
);
|
|
1828
1362
|
}
|
|
1829
1363
|
await this.connector.configure({ ledgerGenuineCheckWebSocketUrl: relayUrl });
|
|
1830
|
-
|
|
1364
|
+
this.resetState();
|
|
1831
1365
|
}
|
|
1832
1366
|
const result = await this.connectorCall(connectId, "getDeviceGenuineCheck", {});
|
|
1833
1367
|
if (!result.isGenuine) {
|
|
@@ -1853,10 +1387,10 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1853
1387
|
if (relayUrl) {
|
|
1854
1388
|
try {
|
|
1855
1389
|
await this.connector.configure?.({ ledgerGenuineCheckWebSocketUrl: void 0 });
|
|
1856
|
-
|
|
1390
|
+
this.resetState();
|
|
1857
1391
|
} catch {
|
|
1858
1392
|
this.connector.reset();
|
|
1859
|
-
|
|
1393
|
+
this.resetState();
|
|
1860
1394
|
}
|
|
1861
1395
|
}
|
|
1862
1396
|
}
|
|
@@ -1868,20 +1402,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1868
1402
|
this.emitter.off(event, listener);
|
|
1869
1403
|
}
|
|
1870
1404
|
cancel(connectId) {
|
|
1871
|
-
const namedOperationIsLive = (id) => {
|
|
1872
|
-
try {
|
|
1873
|
-
this._operations.resolve(id);
|
|
1874
|
-
return true;
|
|
1875
|
-
} catch {
|
|
1876
|
-
return false;
|
|
1877
|
-
}
|
|
1878
|
-
};
|
|
1879
|
-
if ((0, import_hwk_adapter_core3.isHardwareOperationId)(connectId) && !namedOperationIsLive(connectId)) {
|
|
1880
|
-
debugLog("[LedgerAdapter] cancel target already ended; nothing to cancel", {
|
|
1881
|
-
connectId
|
|
1882
|
-
});
|
|
1883
|
-
return;
|
|
1884
|
-
}
|
|
1885
1405
|
const userAbortReason = Object.assign(new Error("User aborted operation"), {
|
|
1886
1406
|
code: import_hwk_adapter_core3.HardwareErrorCode.UserAborted,
|
|
1887
1407
|
_tag: ERROR_TAG.UserAborted
|
|
@@ -1892,46 +1412,14 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1892
1412
|
this._lastCancelReason = void 0;
|
|
1893
1413
|
}
|
|
1894
1414
|
}, 2e3);
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
operationId = connectId;
|
|
1899
|
-
} else if (!connectId && (0, import_hwk_adapter_core3.isHardwareOperationId)(activeJobId)) {
|
|
1900
|
-
operationId = activeJobId;
|
|
1901
|
-
}
|
|
1902
|
-
let resolvedConnectId = connectId;
|
|
1903
|
-
if (operationId) {
|
|
1904
|
-
try {
|
|
1905
|
-
resolvedConnectId = this._operations.resolve(operationId).connectId;
|
|
1906
|
-
} catch {
|
|
1907
|
-
resolvedConnectId = void 0;
|
|
1908
|
-
}
|
|
1909
|
-
}
|
|
1910
|
-
const interactionForPhysicalId = !operationId && connectId ? this._operations.findActiveByConnectionKey(connectId) : void 0;
|
|
1911
|
-
const pendingOperationId = operationId ?? interactionForPhysicalId?.operationId;
|
|
1912
|
-
if (!connectId) {
|
|
1913
|
-
this._uiRegistry.cancel();
|
|
1914
|
-
} else if (pendingOperationId) {
|
|
1915
|
-
this._uiRegistry.cancel(void 0, void 0, pendingOperationId);
|
|
1916
|
-
}
|
|
1917
|
-
this._finishBleBinding("cancelled");
|
|
1918
|
-
const queueKeys = /* @__PURE__ */ new Set();
|
|
1919
|
-
if (connectId) queueKeys.add(ledgerQueueKey({ connectId }));
|
|
1920
|
-
if (pendingOperationId) queueKeys.add(ledgerQueueKey({ operationId: pendingOperationId }));
|
|
1921
|
-
if (queueKeys.size) {
|
|
1922
|
-
let cancelledAnyJob = false;
|
|
1923
|
-
for (const key of queueKeys) {
|
|
1924
|
-
cancelledAnyJob = this._jobQueue.cancelActiveAndPending(key, userAbortReason) || cancelledAnyJob;
|
|
1925
|
-
}
|
|
1926
|
-
debugLog("[LedgerAdapter] cancel routed to queue keys", {
|
|
1927
|
-
queueKeys: [...queueKeys],
|
|
1928
|
-
cancelledAnyJob
|
|
1929
|
-
});
|
|
1415
|
+
this._uiRegistry.cancel();
|
|
1416
|
+
if (connectId) {
|
|
1417
|
+
this._jobQueue.cancelActiveAndPending(connectId, userAbortReason);
|
|
1930
1418
|
} else {
|
|
1931
1419
|
this._jobQueue.cancelActiveAndPending(void 0, userAbortReason);
|
|
1932
1420
|
}
|
|
1933
|
-
if (
|
|
1934
|
-
const sessionId = this._sessions.get(
|
|
1421
|
+
if (connectId) {
|
|
1422
|
+
const sessionId = this._sessions.get(connectId) ?? connectId;
|
|
1935
1423
|
void this.connector.cancel(sessionId);
|
|
1936
1424
|
} else {
|
|
1937
1425
|
for (const sid of this._sessions.values()) void this.connector.cancel(sid);
|
|
@@ -1939,85 +1427,45 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1939
1427
|
if (this._connectingPromise) {
|
|
1940
1428
|
this._doConnectAbortController?.abort(userAbortReason);
|
|
1941
1429
|
}
|
|
1942
|
-
const connectingConnectId = this._connectingConnectId;
|
|
1943
|
-
if (connectingConnectId) void this.connector.cancel(connectingConnectId);
|
|
1944
1430
|
}
|
|
1945
1431
|
// ---------------------------------------------------------------------------
|
|
1946
1432
|
// Chain fingerprint
|
|
1947
1433
|
// ---------------------------------------------------------------------------
|
|
1948
|
-
/** A non-empty deviceId is an expected chain fingerprint, not a transport identifier. */
|
|
1949
1434
|
async getChainFingerprint(connectId, deviceId, chain) {
|
|
1950
1435
|
try {
|
|
1951
1436
|
const fingerprint = await this._computeChainFingerprint(
|
|
1952
1437
|
chain,
|
|
1953
1438
|
(method, params) => this.connectorCall(connectId, method, params, void 0, deviceId)
|
|
1954
1439
|
);
|
|
1955
|
-
if (deviceId) {
|
|
1956
|
-
if (fingerprint !== deviceId) {
|
|
1957
|
-
return (0, import_hwk_adapter_core3.failure)(
|
|
1958
|
-
import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch,
|
|
1959
|
-
formatDeviceMismatchError(deviceId, fingerprint)
|
|
1960
|
-
);
|
|
1961
|
-
}
|
|
1962
|
-
}
|
|
1963
1440
|
return (0, import_hwk_adapter_core3.success)(fingerprint);
|
|
1964
1441
|
} catch (err) {
|
|
1965
1442
|
debugError("[LedgerAdapter] getChainFingerprint error:", chain, err);
|
|
1966
1443
|
return this.errorToFailure(err);
|
|
1967
1444
|
}
|
|
1968
1445
|
}
|
|
1969
|
-
/**
|
|
1970
|
-
|
|
1446
|
+
/**
|
|
1447
|
+
* Verify fingerprint using an existing sessionId directly.
|
|
1448
|
+
* Safe to call inside connectorCall without causing queue deadlock.
|
|
1449
|
+
*/
|
|
1450
|
+
async _verifyDeviceFingerprintWithSession(sessionId, deviceId, chain) {
|
|
1451
|
+
if (!deviceId) return { success: true };
|
|
1971
1452
|
try {
|
|
1972
|
-
const
|
|
1973
|
-
|
|
1974
|
-
this.
|
|
1975
|
-
{
|
|
1976
|
-
selectionRequestId,
|
|
1977
|
-
connection: { transport: "ble", connectId },
|
|
1978
|
-
extra: context?.extra,
|
|
1979
|
-
operationId
|
|
1980
|
-
},
|
|
1981
|
-
signal
|
|
1453
|
+
const fingerprint = await this._computeChainFingerprint(
|
|
1454
|
+
chain,
|
|
1455
|
+
(method, params) => this._callConnector(sessionId, method, params)
|
|
1982
1456
|
);
|
|
1983
|
-
if (
|
|
1984
|
-
|
|
1985
|
-
debugLog("[LedgerAdapter] BLE binding not persisted by host", {
|
|
1986
|
-
connectId,
|
|
1987
|
-
reason: outcome.reason
|
|
1988
|
-
});
|
|
1457
|
+
if (fingerprint === deviceId) {
|
|
1458
|
+
return { success: true };
|
|
1989
1459
|
}
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
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 };
|
|
1996
1465
|
}
|
|
1466
|
+
throw err;
|
|
1997
1467
|
}
|
|
1998
1468
|
}
|
|
1999
|
-
async _dropSession(connectId, signal) {
|
|
2000
|
-
const sessionId = this._sessions.get(connectId);
|
|
2001
|
-
this._sessions.delete(connectId);
|
|
2002
|
-
if (!sessionId) return;
|
|
2003
|
-
this._sessionTransports.delete(sessionId);
|
|
2004
|
-
const teardown = this._runConnectorTeardown(() => this.connector.disconnect(sessionId)).catch(
|
|
2005
|
-
() => void 0
|
|
2006
|
-
);
|
|
2007
|
-
if (!signal.aborted) await teardown;
|
|
2008
|
-
}
|
|
2009
|
-
/** Verify on the acquired session without re-entering the job queue. */
|
|
2010
|
-
async _verifyDeviceFingerprintWithSession(sessionId, deviceId, chain) {
|
|
2011
|
-
if (!deviceId) return { success: true };
|
|
2012
|
-
const fingerprint = await this._computeChainFingerprint(
|
|
2013
|
-
chain,
|
|
2014
|
-
(method, params) => this._callConnector(sessionId, method, params)
|
|
2015
|
-
);
|
|
2016
|
-
if (fingerprint === deviceId) {
|
|
2017
|
-
return { success: true };
|
|
2018
|
-
}
|
|
2019
|
-
return { success: false, expected: deviceId, actual: fingerprint };
|
|
2020
|
-
}
|
|
2021
1469
|
/**
|
|
2022
1470
|
* Compute the chain fingerprint via a caller-supplied call strategy.
|
|
2023
1471
|
*
|
|
@@ -2045,23 +1493,11 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2045
1493
|
address = (await callMethod("solGetAddress", { path, showOnDevice: false })).address;
|
|
2046
1494
|
} else if (chain === "tron") {
|
|
2047
1495
|
address = (await callMethod("tronGetAddress", { path, showOnDevice: false })).address;
|
|
2048
|
-
} else if (chain === "zcash") {
|
|
2049
|
-
address = (await callMethod("zcashGetShieldedAddress", { path, showOnDevice: false })).address;
|
|
2050
1496
|
} else {
|
|
2051
1497
|
throw new Error(`Unsupported chain for fingerprint: ${chain}`);
|
|
2052
1498
|
}
|
|
2053
1499
|
return (0, import_hwk_adapter_core3.deriveDeviceFingerprint)(address);
|
|
2054
1500
|
}
|
|
2055
|
-
/**
|
|
2056
|
-
* Operation owning the running job, so a mid-call UI request can name it.
|
|
2057
|
-
* Undefined at cold start when no operation owns the job.
|
|
2058
|
-
*/
|
|
2059
|
-
_activeOperationId() {
|
|
2060
|
-
const activeJobId = this._jobQueue.getActiveJob()?.deviceId;
|
|
2061
|
-
if (!activeJobId) return void 0;
|
|
2062
|
-
if ((0, import_hwk_adapter_core3.isHardwareOperationId)(activeJobId)) return activeJobId;
|
|
2063
|
-
return this._operations.findActiveByConnectionKey(activeJobId)?.operationId;
|
|
2064
|
-
}
|
|
2065
1501
|
// Ledger WebUSB won't expose a locked device, so we can't auto-detect unlock.
|
|
2066
1502
|
// The user must press Confirm after unlocking, which triggers a search retry.
|
|
2067
1503
|
// If `signal` is provided, an abort cancels the pending UI request so the
|
|
@@ -2071,18 +1507,15 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2071
1507
|
if (signal?.aborted) {
|
|
2072
1508
|
_LedgerAdapter._throwIfAborted(signal);
|
|
2073
1509
|
}
|
|
2074
|
-
const operationId = this._activeOperationId();
|
|
2075
1510
|
const waitPromise = this._uiRegistry.wait(
|
|
2076
|
-
import_hwk_adapter_core3.UI_REQUEST.REQUEST_DEVICE_CONNECT
|
|
2077
|
-
{ operationId }
|
|
1511
|
+
import_hwk_adapter_core3.UI_REQUEST.REQUEST_DEVICE_CONNECT
|
|
2078
1512
|
);
|
|
2079
1513
|
this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.REQUEST_DEVICE_CONNECT, {
|
|
2080
1514
|
type: import_hwk_adapter_core3.UI_REQUEST.REQUEST_DEVICE_CONNECT,
|
|
2081
1515
|
payload: {
|
|
2082
1516
|
vendor: "ledger",
|
|
2083
1517
|
reason: "device-not-found",
|
|
2084
|
-
message: "Please connect and unlock your Ledger device"
|
|
2085
|
-
operationId
|
|
1518
|
+
message: "Please connect and unlock your Ledger device"
|
|
2086
1519
|
}
|
|
2087
1520
|
});
|
|
2088
1521
|
let payload;
|
|
@@ -2143,18 +1576,15 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2143
1576
|
return { ...params, showOnDevice: true };
|
|
2144
1577
|
}
|
|
2145
1578
|
async _waitForBtcHighIndexConfirm(path, accountIndex) {
|
|
2146
|
-
const operationId = this._activeOperationId();
|
|
2147
1579
|
const waitPromise = this._uiRegistry.wait(
|
|
2148
|
-
import_hwk_adapter_core3.UI_REQUEST.REQUEST_BTC_HIGH_INDEX_CONFIRM
|
|
2149
|
-
{ operationId }
|
|
1580
|
+
import_hwk_adapter_core3.UI_REQUEST.REQUEST_BTC_HIGH_INDEX_CONFIRM
|
|
2150
1581
|
);
|
|
2151
1582
|
this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.REQUEST_BTC_HIGH_INDEX_CONFIRM, {
|
|
2152
1583
|
type: import_hwk_adapter_core3.UI_REQUEST.REQUEST_BTC_HIGH_INDEX_CONFIRM,
|
|
2153
1584
|
payload: {
|
|
2154
1585
|
vendor: "ledger",
|
|
2155
1586
|
path,
|
|
2156
|
-
accountIndex
|
|
2157
|
-
operationId
|
|
1587
|
+
accountIndex
|
|
2158
1588
|
}
|
|
2159
1589
|
});
|
|
2160
1590
|
try {
|
|
@@ -2171,14 +1601,12 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2171
1601
|
// Ask the user whether to install a missing app (autoInstallApp flow).
|
|
2172
1602
|
// Same register-then-emit ordering as the BTC high-index gate.
|
|
2173
1603
|
async _waitForInstallAppConfirm(appName) {
|
|
2174
|
-
const operationId = this._activeOperationId();
|
|
2175
1604
|
const waitPromise = this._uiRegistry.wait(
|
|
2176
|
-
import_hwk_adapter_core3.UI_REQUEST.REQUEST_INSTALL_APP
|
|
2177
|
-
{ operationId }
|
|
1605
|
+
import_hwk_adapter_core3.UI_REQUEST.REQUEST_INSTALL_APP
|
|
2178
1606
|
);
|
|
2179
1607
|
this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.REQUEST_INSTALL_APP, {
|
|
2180
1608
|
type: import_hwk_adapter_core3.UI_REQUEST.REQUEST_INSTALL_APP,
|
|
2181
|
-
payload: { vendor: "ledger", appName
|
|
1609
|
+
payload: { vendor: "ledger", appName }
|
|
2182
1610
|
});
|
|
2183
1611
|
try {
|
|
2184
1612
|
const payload = await waitPromise;
|
|
@@ -2194,17 +1622,16 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2194
1622
|
// Layer 1 entry. Caller signal only races the outer awaiter; the shared
|
|
2195
1623
|
// `_doConnect` runs under its own internal controller so caller A's cancel
|
|
2196
1624
|
// doesn't kill caller B's await.
|
|
2197
|
-
async ensureConnected(connectId, signal, allowUsbEphemeralFallback = false
|
|
1625
|
+
async ensureConnected(connectId, signal, allowUsbEphemeralFallback = false) {
|
|
2198
1626
|
if (signal.aborted) _LedgerAdapter._throwIfAborted(signal);
|
|
2199
|
-
this.
|
|
2200
|
-
if (this._isBleConnection() && !connectId && !allowUsbEphemeralFallback) {
|
|
1627
|
+
if (isLedgerBleConnectionType(this.connector.connectionType) && !connectId) {
|
|
2201
1628
|
throw Object.assign(new Error("Ledger BLE connectId is required."), {
|
|
2202
1629
|
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
|
|
2203
1630
|
});
|
|
2204
1631
|
}
|
|
2205
1632
|
if (connectId && this._sessions.has(connectId)) return connectId;
|
|
2206
1633
|
if (!connectId && this._sessions.size > 0) {
|
|
2207
|
-
if (!this.
|
|
1634
|
+
if (!isLedgerBleConnectionType(this.connector.connectionType) && this._sessions.size > 1) {
|
|
2208
1635
|
throw Object.assign(
|
|
2209
1636
|
new Error(
|
|
2210
1637
|
"Ledger USB session invariant violated: more than one session is active. Please reconnect the device."
|
|
@@ -2214,24 +1641,15 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2214
1641
|
}
|
|
2215
1642
|
return this._sessions.keys().next().value;
|
|
2216
1643
|
}
|
|
2217
|
-
if (!this._connectingPromise
|
|
2218
|
-
|
|
2219
|
-
this._doConnectAbortController
|
|
2220
|
-
const innerSignal = controller.signal;
|
|
1644
|
+
if (!this._connectingPromise) {
|
|
1645
|
+
this._doConnectAbortController = new AbortController();
|
|
1646
|
+
const innerSignal = this._doConnectAbortController.signal;
|
|
2221
1647
|
this._connectingPromise = (async () => {
|
|
2222
1648
|
try {
|
|
2223
|
-
return await this._doConnect(
|
|
2224
|
-
innerSignal,
|
|
2225
|
-
connectId,
|
|
2226
|
-
allowUsbEphemeralFallback,
|
|
2227
|
-
preserveOperationId,
|
|
2228
|
-
context
|
|
2229
|
-
);
|
|
1649
|
+
return await this._doConnect(innerSignal, connectId, allowUsbEphemeralFallback);
|
|
2230
1650
|
} finally {
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
this._doConnectAbortController = null;
|
|
2234
|
-
}
|
|
1651
|
+
this._connectingPromise = null;
|
|
1652
|
+
this._doConnectAbortController = null;
|
|
2235
1653
|
}
|
|
2236
1654
|
})();
|
|
2237
1655
|
}
|
|
@@ -2240,57 +1658,22 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2240
1658
|
// Layer 1 main loop — the ONLY place in SDK that emits unlock dialog.
|
|
2241
1659
|
// Bounded by MAX_DOCONNECT_CONFIRMS — after N Confirms with no progress,
|
|
2242
1660
|
// throw DeviceNotFound so the user is kicked out of the loop.
|
|
2243
|
-
async _doConnect(internalSignal, targetConnectId, allowUsbEphemeralFallback = false
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
)
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
preserveOperationId,
|
|
2259
|
-
context,
|
|
2260
|
-
internalSignal
|
|
2261
|
-
);
|
|
2262
|
-
}
|
|
2263
|
-
if (context?.supportedTransports && !context.supportedTransports.includes("ble")) {
|
|
2264
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2265
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound,
|
|
2266
|
-
message: "This Ledger model has no Bluetooth transport; connect it over USB"
|
|
2267
|
-
});
|
|
2268
|
-
}
|
|
2269
|
-
this._activeConnectionType = "ble";
|
|
2270
|
-
const knownBle = context?.knownConnections?.find(
|
|
2271
|
-
(connection) => connection.transport === "ble"
|
|
2272
|
-
);
|
|
2273
|
-
if (knownBle?.transport === "ble") {
|
|
2274
|
-
return this._connectDeviceOrThrow(knownBle.connectId, preserveOperationId, internalSignal);
|
|
2275
|
-
}
|
|
2276
|
-
if (targetConnectId && context?.knownConnections === void 0) {
|
|
2277
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2278
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound,
|
|
2279
|
-
message: "Ledger connection metadata is required before starting Bluetooth binding"
|
|
2280
|
-
});
|
|
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
|
+
}
|
|
2281
1676
|
}
|
|
2282
|
-
const bleDevices = await this._searchDevices({ transportType: "ble" }, internalSignal);
|
|
2283
|
-
return this._connectFirstOrSelect(
|
|
2284
|
-
bleDevices,
|
|
2285
|
-
void 0,
|
|
2286
|
-
allowUsbEphemeralFallback,
|
|
2287
|
-
preserveOperationId,
|
|
2288
|
-
context,
|
|
2289
|
-
internalSignal
|
|
2290
|
-
);
|
|
2291
|
-
}
|
|
2292
|
-
if (this._isBleConnection() && targetConnectId) {
|
|
2293
|
-
return this._connectDeviceOrThrow(targetConnectId, preserveOperationId, internalSignal);
|
|
2294
1677
|
}
|
|
2295
1678
|
let confirms = 0;
|
|
2296
1679
|
while (!internalSignal.aborted) {
|
|
@@ -2298,28 +1681,22 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2298
1681
|
type: import_hwk_adapter_core3.EConnectorInteraction.Searching,
|
|
2299
1682
|
payload: { sessionId: "" }
|
|
2300
1683
|
});
|
|
2301
|
-
let devices = await this.
|
|
2302
|
-
_LedgerAdapter._throwIfAborted(internalSignal);
|
|
1684
|
+
let devices = await this.searchDevices();
|
|
2303
1685
|
if (devices.length === 0) {
|
|
2304
1686
|
for (let i = 0; i < 3 && !internalSignal.aborted; i += 1) {
|
|
2305
1687
|
await new Promise((resolve) => {
|
|
2306
1688
|
setTimeout(resolve, import_hwk_adapter_core3.DEVICE_CONNECT_RETRY_DELAY_MS);
|
|
2307
1689
|
});
|
|
2308
|
-
|
|
2309
|
-
devices = await this._searchDevices(void 0, internalSignal);
|
|
2310
|
-
_LedgerAdapter._throwIfAborted(internalSignal);
|
|
1690
|
+
devices = await this.searchDevices();
|
|
2311
1691
|
if (devices.length > 0) break;
|
|
2312
1692
|
}
|
|
2313
1693
|
}
|
|
2314
|
-
if (devices.length > 0
|
|
1694
|
+
if (devices.length > 0) {
|
|
2315
1695
|
try {
|
|
2316
1696
|
return await this._connectFirstOrSelect(
|
|
2317
1697
|
devices,
|
|
2318
1698
|
targetConnectId,
|
|
2319
|
-
allowUsbEphemeralFallback
|
|
2320
|
-
preserveOperationId,
|
|
2321
|
-
context,
|
|
2322
|
-
internalSignal
|
|
1699
|
+
allowUsbEphemeralFallback
|
|
2323
1700
|
);
|
|
2324
1701
|
} catch (err) {
|
|
2325
1702
|
if (!isDeviceLockedError(err) && !isDeviceNotAdvertisingError(err) && !isDeviceDisconnectedError(err)) {
|
|
@@ -2348,143 +1725,45 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2348
1725
|
_LedgerAdapter._throwIfAborted(internalSignal);
|
|
2349
1726
|
throw new Error("_doConnect aborted");
|
|
2350
1727
|
}
|
|
2351
|
-
async _connectFirstOrSelect(devices, targetConnectId, allowUsbEphemeralFallback
|
|
2352
|
-
_LedgerAdapter._throwIfAborted(signal);
|
|
1728
|
+
async _connectFirstOrSelect(devices, targetConnectId, allowUsbEphemeralFallback = false) {
|
|
2353
1729
|
if (targetConnectId) {
|
|
2354
1730
|
const target = devices.find(
|
|
2355
1731
|
(d) => d.connectId === targetConnectId || d.deviceId === targetConnectId
|
|
2356
1732
|
);
|
|
2357
1733
|
if (target) {
|
|
2358
|
-
return this._connectDeviceOrThrow(target.connectId
|
|
1734
|
+
return this._connectDeviceOrThrow(target.connectId);
|
|
2359
1735
|
}
|
|
2360
|
-
if (!this.
|
|
1736
|
+
if (!isLedgerBleConnectionType(this.connector.connectionType) && devices.length === 1 && allowUsbEphemeralFallback) {
|
|
2361
1737
|
debugLog(
|
|
2362
1738
|
`[LedgerAdapter] target ${targetConnectId} not in fresh enumeration; accepting sole USB device ${devices[0].connectId} for fingerprint-verified recovery`
|
|
2363
1739
|
);
|
|
2364
|
-
return this._connectDeviceOrThrow(devices[0].connectId
|
|
1740
|
+
return this._connectDeviceOrThrow(devices[0].connectId);
|
|
2365
1741
|
}
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
err._tag = ERROR_TAG.DeviceNotAdvertising;
|
|
2372
|
-
}
|
|
2373
|
-
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;
|
|
2374
1747
|
}
|
|
1748
|
+
throw err;
|
|
2375
1749
|
}
|
|
2376
|
-
|
|
2377
|
-
if (requiresBleSelection && !allowUsbEphemeralFallback) {
|
|
1750
|
+
if (isLedgerBleConnectionType(this.connector.connectionType)) {
|
|
2378
1751
|
throw Object.assign(new Error("Ledger BLE connectId is required."), {
|
|
2379
1752
|
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
|
|
2380
1753
|
});
|
|
2381
1754
|
}
|
|
2382
|
-
if (
|
|
2383
|
-
|
|
2384
|
-
if (context) context.bindingSessionId = bindingSessionId;
|
|
2385
|
-
const allowUsbFallback = context?.bindingReason !== "manual-rebind" && Boolean(this.connector.availableTransports?.includes("usb"));
|
|
2386
|
-
const knownUsb = context?.knownConnections?.find(
|
|
2387
|
-
(connection) => connection.transport === "usb"
|
|
2388
|
-
);
|
|
2389
|
-
const usbConnectId = knownUsb?.transport === "usb" ? knownUsb.connectId : targetConnectId;
|
|
2390
|
-
const { device, requestId } = await (0, import_hwk_adapter_core3.requestBleDeviceSelection)({
|
|
2391
|
-
emitter: this.emitter,
|
|
2392
|
-
registry: this._uiRegistry,
|
|
2393
|
-
signal,
|
|
2394
|
-
allowUsbFallback,
|
|
2395
|
-
scan: async () => {
|
|
2396
|
-
if (allowUsbFallback) {
|
|
2397
|
-
const usbDevices = await this._searchDevices({ transportType: "usb" }, signal);
|
|
2398
|
-
const candidate = usbDevices.find(
|
|
2399
|
-
(device2) => device2.connectionType === "usb" && device2.connectId === usbConnectId
|
|
2400
|
-
) ?? (usbDevices.length === 1 && usbDevices[0].connectionType === "usb" ? usbDevices[0] : void 0);
|
|
2401
|
-
if (candidate) return [candidate];
|
|
2402
|
-
}
|
|
2403
|
-
return this._searchDevices({ transportType: "ble", waitForAllTransports: true }, signal);
|
|
2404
|
-
},
|
|
2405
|
-
request: {
|
|
2406
|
-
devices,
|
|
2407
|
-
bindingSessionId,
|
|
2408
|
-
context: {
|
|
2409
|
-
kind: "bind-connection",
|
|
2410
|
-
transport: "ble",
|
|
2411
|
-
reason: context?.bindingReason ?? (targetConnectId ? "known-connection-unavailable" : "missing-binding")
|
|
2412
|
-
},
|
|
2413
|
-
extra: context?.extra,
|
|
2414
|
-
operationId: preserveOperationId
|
|
2415
|
-
}
|
|
2416
|
-
});
|
|
2417
|
-
if (device.connectionType === "usb") {
|
|
2418
|
-
this._activeConnectionType = "usb";
|
|
2419
|
-
if (context) context.selectedConnection = void 0;
|
|
2420
|
-
this._bindingSelectionRequestId = requestId;
|
|
2421
|
-
this._finishBleBinding("cancelled");
|
|
2422
|
-
return this._connectDeviceOrThrow(device.connectId, preserveOperationId, signal);
|
|
2423
|
-
}
|
|
2424
|
-
this._bindingSelectionRequestId = requestId;
|
|
2425
|
-
const connected = await this._connectDeviceOrThrow(
|
|
2426
|
-
device.connectId,
|
|
2427
|
-
preserveOperationId,
|
|
2428
|
-
signal
|
|
2429
|
-
);
|
|
2430
|
-
if (context) context.selectedConnection = { connectId: connected, requestId };
|
|
2431
|
-
await this._saveSelectedBleBinding(
|
|
2432
|
-
connected,
|
|
2433
|
-
requestId,
|
|
2434
|
-
context,
|
|
2435
|
-
preserveOperationId,
|
|
2436
|
-
signal
|
|
2437
|
-
);
|
|
2438
|
-
return connected;
|
|
2439
|
-
}
|
|
2440
|
-
if (devices.length > 0 && (devices.length > 1 || requiresBleSelection)) {
|
|
2441
|
-
if (context?.allowDeviceSelection === false || !this.emitter.listenerCount(import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE)) {
|
|
2442
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2443
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound,
|
|
2444
|
-
message: "Select a Ledger device before continuing"
|
|
2445
|
-
});
|
|
2446
|
-
}
|
|
2447
|
-
const requestId = this._uiRegistry.createRequestId();
|
|
2448
|
-
const operationId = this._activeOperationId();
|
|
2449
|
-
const waitPromise = this._uiRegistry.wait(
|
|
2450
|
-
import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE,
|
|
2451
|
-
{ requestId, operationId }
|
|
2452
|
-
);
|
|
2453
|
-
this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE, {
|
|
2454
|
-
type: import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE,
|
|
2455
|
-
payload: {
|
|
2456
|
-
devices,
|
|
2457
|
-
requestId,
|
|
2458
|
-
operationId,
|
|
2459
|
-
context: requiresBleSelection ? {
|
|
2460
|
-
kind: "bind-connection",
|
|
2461
|
-
transport: "ble",
|
|
2462
|
-
reason: targetConnectId ? "known-connection-unavailable" : "missing-binding"
|
|
2463
|
-
} : { kind: "select-device", transport: "usb", reason: "multiple-candidates" },
|
|
2464
|
-
extra: context?.extra
|
|
2465
|
-
}
|
|
2466
|
-
});
|
|
2467
|
-
const { sdkConnectId } = await this._abortable(signal, waitPromise);
|
|
2468
|
-
_LedgerAdapter._throwIfAborted(signal);
|
|
2469
|
-
const selected = devices.find((device) => device.connectId === sdkConnectId);
|
|
2470
|
-
if (!selected) {
|
|
2471
|
-
throw Object.assign(new Error("Selected Ledger is no longer available"), {
|
|
2472
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
|
|
2473
|
-
});
|
|
2474
|
-
}
|
|
2475
|
-
if (context && requiresBleSelection)
|
|
2476
|
-
context.selectedConnection = { connectId: selected.connectId, requestId };
|
|
2477
|
-
return this._connectDeviceOrThrow(selected.connectId, preserveOperationId, signal);
|
|
1755
|
+
if (devices.length > 1) {
|
|
1756
|
+
throw createMultipleUsbLedgerDevicesError();
|
|
2478
1757
|
}
|
|
2479
1758
|
if (devices.length !== 1) {
|
|
2480
1759
|
throw Object.assign(new Error("Ledger device not found."), {
|
|
2481
1760
|
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
|
|
2482
1761
|
});
|
|
2483
1762
|
}
|
|
2484
|
-
return this._connectDeviceOrThrow(devices[0].connectId
|
|
1763
|
+
return this._connectDeviceOrThrow(devices[0].connectId);
|
|
2485
1764
|
}
|
|
2486
|
-
async _connectDeviceOrThrow(chosenConnectId
|
|
2487
|
-
const result = await this.
|
|
1765
|
+
async _connectDeviceOrThrow(chosenConnectId) {
|
|
1766
|
+
const result = await this.connectDevice(chosenConnectId);
|
|
2488
1767
|
if (!result.success) {
|
|
2489
1768
|
const payload = result.payload;
|
|
2490
1769
|
const rethrow = Object.assign(new Error(payload.error), {
|
|
@@ -2495,7 +1774,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2495
1774
|
}
|
|
2496
1775
|
throw rethrow;
|
|
2497
1776
|
}
|
|
2498
|
-
return
|
|
1777
|
+
return chosenConnectId;
|
|
2499
1778
|
}
|
|
2500
1779
|
/**
|
|
2501
1780
|
* Call the connector with automatic session resolution and disconnect retry.
|
|
@@ -2525,133 +1804,33 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2525
1804
|
* lives in one place.
|
|
2526
1805
|
*/
|
|
2527
1806
|
async _callConnector(sessionId, method, params, signal) {
|
|
2528
|
-
this.
|
|
2529
|
-
if (signal?.aborted) throw this._abortReason(signal);
|
|
2530
|
-
const releaseOperation = this._retainConnectorOperation(`call:${sessionId}`);
|
|
2531
|
-
let promise;
|
|
2532
|
-
try {
|
|
2533
|
-
promise = this.connector.call(sessionId, method, params).finally(releaseOperation);
|
|
2534
|
-
} catch (error) {
|
|
2535
|
-
releaseOperation();
|
|
2536
|
-
throw error;
|
|
2537
|
-
}
|
|
1807
|
+
const promise = this.connector.call(sessionId, method, params);
|
|
2538
1808
|
const result = signal ? await this._abortable(signal, promise) : await promise;
|
|
2539
1809
|
return this._unwrapConnectorResult(result);
|
|
2540
1810
|
}
|
|
2541
|
-
_assertConnectorReady(method) {
|
|
2542
|
-
if (this._resetPromise || this._pendingConnectorTeardowns > 0 || this._unsettledConnectorOperations.size > 0) {
|
|
2543
|
-
throw _LedgerAdapter._createDeviceBusyError(method);
|
|
2544
|
-
}
|
|
2545
|
-
}
|
|
2546
|
-
_runConnectorTeardown(task) {
|
|
2547
|
-
const previous = this._connectorTeardownTail;
|
|
2548
|
-
let releaseTail = () => void 0;
|
|
2549
|
-
this._connectorTeardownTail = new Promise((resolve) => {
|
|
2550
|
-
releaseTail = resolve;
|
|
2551
|
-
});
|
|
2552
|
-
this._pendingConnectorTeardowns += 1;
|
|
2553
|
-
return (async () => {
|
|
2554
|
-
try {
|
|
2555
|
-
await previous;
|
|
2556
|
-
await this._waitForConnectorOperationsToDrain();
|
|
2557
|
-
await task();
|
|
2558
|
-
} finally {
|
|
2559
|
-
this._pendingConnectorTeardowns -= 1;
|
|
2560
|
-
releaseTail();
|
|
2561
|
-
}
|
|
2562
|
-
})();
|
|
2563
|
-
}
|
|
2564
|
-
_waitForConnectorOperationsToDrain() {
|
|
2565
|
-
if (this._unsettledConnectorOperations.size === 0) {
|
|
2566
|
-
return Promise.resolve();
|
|
2567
|
-
}
|
|
2568
|
-
return new Promise((resolve) => {
|
|
2569
|
-
this._connectorIdleWaiters.add(resolve);
|
|
2570
|
-
});
|
|
2571
|
-
}
|
|
2572
|
-
_retainConnectorOperation(key) {
|
|
2573
|
-
this._unsettledConnectorOperations.set(
|
|
2574
|
-
key,
|
|
2575
|
-
(this._unsettledConnectorOperations.get(key) ?? 0) + 1
|
|
2576
|
-
);
|
|
2577
|
-
let released = false;
|
|
2578
|
-
return () => {
|
|
2579
|
-
if (released) return;
|
|
2580
|
-
released = true;
|
|
2581
|
-
const remaining = (this._unsettledConnectorOperations.get(key) ?? 1) - 1;
|
|
2582
|
-
if (remaining > 0) {
|
|
2583
|
-
this._unsettledConnectorOperations.set(key, remaining);
|
|
2584
|
-
} else {
|
|
2585
|
-
this._unsettledConnectorOperations.delete(key);
|
|
2586
|
-
}
|
|
2587
|
-
if (this._unsettledConnectorOperations.size === 0) {
|
|
2588
|
-
for (const resolve of this._connectorIdleWaiters) resolve();
|
|
2589
|
-
this._connectorIdleWaiters.clear();
|
|
2590
|
-
}
|
|
2591
|
-
};
|
|
2592
|
-
}
|
|
2593
1811
|
async connectorCall(connectId, method, params, fingerprint, permissionDeviceId, commonParams, installContext) {
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2597
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.InvalidParams,
|
|
2598
|
-
message: "Conflicting Ledger operation ids",
|
|
2599
|
-
params: {
|
|
2600
|
-
positionalOperationId,
|
|
2601
|
-
commonOperationId: commonParams.operationId
|
|
2602
|
-
}
|
|
2603
|
-
});
|
|
2604
|
-
}
|
|
2605
|
-
const operationId = commonParams?.operationId ?? positionalOperationId;
|
|
2606
|
-
const operation = operationId ? this._operations.resolve(operationId) : void 0;
|
|
2607
|
-
const releaseOperationRetention = operationId ? this._operations.retain(operationId) : void 0;
|
|
2608
|
-
const effectiveConnectId = operation?.connectId ?? connectId;
|
|
2609
|
-
debugLog("[LedgerAdapter][REQ]", {
|
|
2610
|
-
method,
|
|
2611
|
-
connectId: effectiveConnectId || "(empty)",
|
|
2612
|
-
params
|
|
2613
|
-
});
|
|
2614
|
-
const queueKey = ledgerQueueKey({ operationId, connectId: effectiveConnectId });
|
|
1812
|
+
debugLog("[LedgerAdapter][REQ]", { method, connectId: connectId || "(empty)", params });
|
|
1813
|
+
const queueKey = connectId || "__ledger_default__";
|
|
2615
1814
|
try {
|
|
2616
1815
|
const result = await this._jobQueue.enqueue(
|
|
2617
1816
|
queueKey,
|
|
2618
|
-
async (signal) =>
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
commonParams,
|
|
2629
|
-
installContext ?? {},
|
|
2630
|
-
operationId
|
|
2631
|
-
);
|
|
2632
|
-
} catch (error) {
|
|
2633
|
-
this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
|
|
2634
|
-
throw error;
|
|
2635
|
-
} finally {
|
|
2636
|
-
if (operationId) {
|
|
2637
|
-
this._activeOperationJobs.delete(operationId);
|
|
2638
|
-
if (this._pendingOperationDisconnects.delete(operationId)) {
|
|
2639
|
-
await this._releaseLostOperationConnection(operationId);
|
|
2640
|
-
}
|
|
2641
|
-
}
|
|
2642
|
-
}
|
|
2643
|
-
},
|
|
1817
|
+
async (signal) => this._runConnectorCall(
|
|
1818
|
+
connectId,
|
|
1819
|
+
method,
|
|
1820
|
+
params,
|
|
1821
|
+
signal,
|
|
1822
|
+
fingerprint,
|
|
1823
|
+
permissionDeviceId,
|
|
1824
|
+
commonParams,
|
|
1825
|
+
installContext
|
|
1826
|
+
),
|
|
2644
1827
|
{
|
|
2645
1828
|
label: method,
|
|
2646
1829
|
rejectIfBusy: true,
|
|
2647
1830
|
busyError: _LedgerAdapter._createDeviceBusyError(method)
|
|
2648
1831
|
}
|
|
2649
1832
|
);
|
|
2650
|
-
debugLog("[LedgerAdapter][RES]", {
|
|
2651
|
-
method,
|
|
2652
|
-
success: true,
|
|
2653
|
-
payload: redactResultForLog(result)
|
|
2654
|
-
});
|
|
1833
|
+
debugLog("[LedgerAdapter][RES]", { method, success: true, payload: result });
|
|
2655
1834
|
return result;
|
|
2656
1835
|
} catch (err) {
|
|
2657
1836
|
const e = err;
|
|
@@ -2665,22 +1844,15 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2665
1844
|
}
|
|
2666
1845
|
});
|
|
2667
1846
|
throw err;
|
|
2668
|
-
} finally {
|
|
2669
|
-
releaseOperationRetention?.();
|
|
2670
1847
|
}
|
|
2671
1848
|
}
|
|
2672
|
-
/** Hermes/RN polyfills don't always populate signal.reason; fall back. */
|
|
2673
|
-
_abortReason(signal) {
|
|
2674
|
-
return signal.reason ?? this._lastCancelReason ?? new Error("Aborted");
|
|
2675
|
-
}
|
|
2676
1849
|
/**
|
|
2677
1850
|
* Race a promise against an abort signal. On abort, rejects with
|
|
2678
1851
|
* signal.reason → instance _lastCancelReason → generic Error('Aborted').
|
|
2679
1852
|
*/
|
|
2680
1853
|
_abortable(signal, promise) {
|
|
2681
|
-
const getAbortReason = () => this.
|
|
1854
|
+
const getAbortReason = () => signal.reason ?? this._lastCancelReason ?? new Error("Aborted");
|
|
2682
1855
|
if (signal.aborted) {
|
|
2683
|
-
void promise.catch(() => void 0);
|
|
2684
1856
|
return Promise.reject(getAbortReason());
|
|
2685
1857
|
}
|
|
2686
1858
|
return new Promise((resolve, reject) => {
|
|
@@ -2707,15 +1879,13 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2707
1879
|
}
|
|
2708
1880
|
}
|
|
2709
1881
|
/** Actual work done under the job queue — connection, fingerprint, call, and recovery. */
|
|
2710
|
-
async _runConnectorCall(connectId, method, params, signal, fingerprint, permissionDeviceId, commonParams, installContext
|
|
1882
|
+
async _runConnectorCall(connectId, method, params, signal, fingerprint, permissionDeviceId, commonParams, installContext) {
|
|
2711
1883
|
_LedgerAdapter._throwIfAborted(signal);
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
);
|
|
2718
|
-
}
|
|
1884
|
+
await this._ensureDevicePermission(
|
|
1885
|
+
connectId,
|
|
1886
|
+
permissionDeviceId ?? fingerprint?.deviceId,
|
|
1887
|
+
signal
|
|
1888
|
+
);
|
|
2719
1889
|
_LedgerAdapter._throwIfAborted(signal);
|
|
2720
1890
|
let effectiveParams = params;
|
|
2721
1891
|
if (method === "btcGetPublicKey") {
|
|
@@ -2729,49 +1899,19 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2729
1899
|
effectiveParams = gatedParams;
|
|
2730
1900
|
}
|
|
2731
1901
|
const allowUsbEphemeralFallback = !!fingerprint?.deviceId && !fingerprint.skipFingerprint;
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
const knownTransport = this._isBleConnection() ? "ble" : "usb";
|
|
2735
|
-
const hintedConnectId = commonParams?.knownConnections?.find(
|
|
2736
|
-
(connection) => connection.transport === knownTransport
|
|
2737
|
-
);
|
|
2738
|
-
const inputConnectId = hintedConnectId && hintedConnectId.transport !== "qr" ? hintedConnectId.connectId : connectId;
|
|
2739
|
-
const preferredConnectId = fingerprint && !fingerprint.skipFingerprint && selectedBleTarget?.chain === fingerprint.chain && selectedBleTarget.fingerprint === fingerprint.deviceId ? selectedBleTarget.connectId : inputConnectId;
|
|
2740
|
-
const connectionAttempt = { ...commonParams };
|
|
2741
|
-
const bundleConnection = installContext?.connection;
|
|
2742
|
-
if (bundleConnection && this._sessions.get(bundleConnection.connectId) !== bundleConnection.sessionId) {
|
|
2743
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2744
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
|
|
2745
|
-
message: "Ledger all-network connection ended"
|
|
2746
|
-
});
|
|
2747
|
-
}
|
|
2748
|
-
const resolvedConnectId = operationId ? this._operations.resolve(operationId).connectId : bundleConnection?.connectId ?? await this.ensureConnected(
|
|
2749
|
-
preferredConnectId,
|
|
1902
|
+
const resolvedConnectId = await this.ensureConnected(
|
|
1903
|
+
connectId,
|
|
2750
1904
|
signal,
|
|
2751
|
-
allowUsbEphemeralFallback
|
|
2752
|
-
void 0,
|
|
2753
|
-
connectionAttempt
|
|
1905
|
+
allowUsbEphemeralFallback
|
|
2754
1906
|
);
|
|
2755
1907
|
const sessionId = this._sessions.get(resolvedConnectId);
|
|
2756
|
-
if (sessionId && installContext && !installContext.connection) {
|
|
2757
|
-
installContext.connection = { connectId: resolvedConnectId, sessionId };
|
|
2758
|
-
}
|
|
2759
1908
|
if (!sessionId) {
|
|
2760
|
-
if (operationId) {
|
|
2761
|
-
this._operations.end(operationId, "disconnect");
|
|
2762
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2763
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.OperationEnded,
|
|
2764
|
-
message: "Ledger operation connection is no longer active",
|
|
2765
|
-
params: { operationId, reason: "disconnect" }
|
|
2766
|
-
});
|
|
2767
|
-
}
|
|
2768
1909
|
throw Object.assign(new Error("Auto-connect succeeded but no session found"), {
|
|
2769
1910
|
_tag: ERROR_TAG.DeviceSessionNotFound
|
|
2770
1911
|
});
|
|
2771
1912
|
}
|
|
2772
1913
|
try {
|
|
2773
|
-
|
|
2774
|
-
if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId && !isBleSession) {
|
|
1914
|
+
if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId) {
|
|
2775
1915
|
const fp = await this._abortable(
|
|
2776
1916
|
signal,
|
|
2777
1917
|
this._verifyDeviceFingerprintWithSession(
|
|
@@ -2786,33 +1926,9 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2786
1926
|
});
|
|
2787
1927
|
}
|
|
2788
1928
|
}
|
|
2789
|
-
if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId && !operationId && isBleSession && connectionAttempt.selectedConnection?.connectId === resolvedConnectId) {
|
|
2790
|
-
this._selectedBleReconnectTargets.set(connectId, {
|
|
2791
|
-
connectId: resolvedConnectId,
|
|
2792
|
-
chain: fingerprint.chain,
|
|
2793
|
-
fingerprint: fingerprint.deviceId
|
|
2794
|
-
});
|
|
2795
|
-
}
|
|
2796
|
-
businessCallStarted = true;
|
|
2797
1929
|
return await this._callConnector(sessionId, method, effectiveParams, signal);
|
|
2798
1930
|
} catch (err) {
|
|
2799
1931
|
if (signal.aborted) throw err;
|
|
2800
|
-
if (isLostConnectionError(err)) {
|
|
2801
|
-
this._discoveredDevices.delete(resolvedConnectId);
|
|
2802
|
-
if (operationId) await this._releaseLostOperationConnection(operationId);
|
|
2803
|
-
else {
|
|
2804
|
-
this._sessions.delete(resolvedConnectId);
|
|
2805
|
-
await this.connector.disconnect(sessionId).catch(() => void 0);
|
|
2806
|
-
}
|
|
2807
|
-
const ambiguous = businessCallStarted && !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method);
|
|
2808
|
-
const interactionParams = operationId ? { operationId, reason: "disconnect" } : void 0;
|
|
2809
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2810
|
-
code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : mapLedgerError(err).code,
|
|
2811
|
-
message: "Ledger operation connection was lost; start a new operation",
|
|
2812
|
-
params: ambiguous ? (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(method, { operationId }) : interactionParams,
|
|
2813
|
-
recovery: ambiguous ? { scope: "unknown" } : void 0
|
|
2814
|
-
});
|
|
2815
|
-
}
|
|
2816
1932
|
const errObj = err;
|
|
2817
1933
|
debugLog("[LedgerAdapter] connectorCall error:", method, {
|
|
2818
1934
|
message: errObj?.message,
|
|
@@ -2824,60 +1940,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2824
1940
|
isNotAdvertising: isDeviceNotAdvertisingError(err),
|
|
2825
1941
|
isStuckApp: isStuckAppStateError(err)
|
|
2826
1942
|
});
|
|
2827
|
-
const assertSessionCurrent = (message) => {
|
|
2828
|
-
if (this._sessions.get(resolvedConnectId) === sessionId) return;
|
|
2829
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2830
|
-
code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
|
|
2831
|
-
message
|
|
2832
|
-
});
|
|
2833
|
-
};
|
|
2834
|
-
if ((isDeviceLockedError(err) || errObj?.code === import_hwk_adapter_core3.HardwareErrorCode.DeviceLocked) && lockedRetryBudget > 0) {
|
|
2835
|
-
await this._waitForDeviceConnect(signal);
|
|
2836
|
-
assertSessionCurrent("Ledger connection ended while waiting for unlock");
|
|
2837
|
-
return this._runConnectorCall(
|
|
2838
|
-
resolvedConnectId,
|
|
2839
|
-
method,
|
|
2840
|
-
effectiveParams,
|
|
2841
|
-
signal,
|
|
2842
|
-
fingerprint,
|
|
2843
|
-
permissionDeviceId,
|
|
2844
|
-
commonParams,
|
|
2845
|
-
installContext,
|
|
2846
|
-
operationId,
|
|
2847
|
-
lockedRetryBudget - 1
|
|
2848
|
-
);
|
|
2849
|
-
}
|
|
2850
|
-
if (businessCallStarted && isStuckAppStateError(err)) {
|
|
2851
|
-
await this._sleepAbortable(_LedgerAdapter.STUCK_APP_RETRY_DELAY_MS, signal);
|
|
2852
|
-
assertSessionCurrent("Ledger connection ended during the app transition");
|
|
2853
|
-
try {
|
|
2854
|
-
return await this._callConnector(sessionId, method, effectiveParams, signal);
|
|
2855
|
-
} catch (retryErr) {
|
|
2856
|
-
if (isStuckAppStateError(retryErr)) throw err;
|
|
2857
|
-
if (isLostConnectionError(retryErr)) {
|
|
2858
|
-
if (operationId) await this._releaseLostOperationConnection(operationId);
|
|
2859
|
-
else {
|
|
2860
|
-
this._sessions.delete(resolvedConnectId);
|
|
2861
|
-
this._discoveredDevices.delete(resolvedConnectId);
|
|
2862
|
-
await this.connector.disconnect(sessionId).catch(() => void 0);
|
|
2863
|
-
}
|
|
2864
|
-
const ambiguous = !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method);
|
|
2865
|
-
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2866
|
-
code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : mapLedgerError(retryErr).code,
|
|
2867
|
-
message: `Ledger ${method} may have completed before the connection was lost`,
|
|
2868
|
-
params: ambiguous ? (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(method, { operationId, reason: "disconnect" }) : { operationId, reason: "disconnect" },
|
|
2869
|
-
recovery: ambiguous ? { scope: "unknown" } : void 0
|
|
2870
|
-
});
|
|
2871
|
-
}
|
|
2872
|
-
throw retryErr;
|
|
2873
|
-
}
|
|
2874
|
-
}
|
|
2875
|
-
if (!operationId && errObj?.code === import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch) {
|
|
2876
|
-
this._sessions.delete(resolvedConnectId);
|
|
2877
|
-
this._discoveredDevices.delete(resolvedConnectId);
|
|
2878
|
-
await this.connector.disconnect(sessionId).catch(() => void 0);
|
|
2879
|
-
throw err;
|
|
2880
|
-
}
|
|
2881
1943
|
const autoInstallApp = commonParams?.autoInstallApp ?? this._defaultAutoInstallApp;
|
|
2882
1944
|
const isAppMissing = isAppNotInstalledError(err) || err?.code === import_hwk_adapter_core3.HardwareErrorCode.AppNotInstalled;
|
|
2883
1945
|
if (autoInstallApp && isAppMissing) {
|
|
@@ -2933,14 +1995,157 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2933
1995
|
fingerprint,
|
|
2934
1996
|
permissionDeviceId,
|
|
2935
1997
|
commonParams,
|
|
2936
|
-
installContext
|
|
2937
|
-
operationId
|
|
1998
|
+
installContext
|
|
2938
1999
|
);
|
|
2939
2000
|
}
|
|
2940
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
|
+
}
|
|
2941
2112
|
throw err;
|
|
2942
2113
|
}
|
|
2943
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
|
+
}
|
|
2944
2149
|
_sleepAbortable(ms, signal) {
|
|
2945
2150
|
return new Promise((resolve, reject) => {
|
|
2946
2151
|
if (signal.aborted) {
|
|
@@ -2959,22 +2164,111 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2959
2164
|
});
|
|
2960
2165
|
}
|
|
2961
2166
|
/**
|
|
2962
|
-
*
|
|
2963
|
-
*
|
|
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
|
|
2964
2259
|
*/
|
|
2965
2260
|
async _ensureDevicePermission(connectId, deviceId, signal) {
|
|
2966
2261
|
if (signal?.aborted) {
|
|
2967
2262
|
_LedgerAdapter._throwIfAborted(signal);
|
|
2968
2263
|
}
|
|
2969
2264
|
const transportType = this.activeTransport ?? "hid";
|
|
2970
|
-
const operationId = this._activeOperationId();
|
|
2971
2265
|
const waitPromise = this._uiRegistry.wait(
|
|
2972
2266
|
import_hwk_adapter_core3.UI_REQUEST.REQUEST_DEVICE_PERMISSION,
|
|
2973
|
-
{ timeoutMs: 6e4
|
|
2267
|
+
{ timeoutMs: 6e4 }
|
|
2974
2268
|
);
|
|
2975
2269
|
this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.REQUEST_DEVICE_PERMISSION, {
|
|
2976
2270
|
type: import_hwk_adapter_core3.UI_REQUEST.REQUEST_DEVICE_PERMISSION,
|
|
2977
|
-
payload: { transportType, connectId, deviceId
|
|
2271
|
+
payload: { transportType, connectId, deviceId }
|
|
2978
2272
|
});
|
|
2979
2273
|
let response;
|
|
2980
2274
|
const onAbort = () => {
|
|
@@ -3020,15 +2314,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
3020
2314
|
if (err && typeof err === "object" && "code" in err && typeof err.code === "number") {
|
|
3021
2315
|
const e = err;
|
|
3022
2316
|
const params = e.code === import_hwk_adapter_core3.HardwareErrorCode.DevicePermissionDenied && e.reason ? { permissionDeniedReason: e.reason } : e.params;
|
|
3023
|
-
return ledgerFailure(
|
|
3024
|
-
e.code,
|
|
3025
|
-
e.message ?? "Unknown error",
|
|
3026
|
-
e.appName,
|
|
3027
|
-
tag,
|
|
3028
|
-
params,
|
|
3029
|
-
void 0,
|
|
3030
|
-
(0, import_hwk_adapter_core3.isHwkRecoveryHint)(e.recovery) ? e.recovery : void 0
|
|
3031
|
-
);
|
|
2317
|
+
return ledgerFailure(e.code, e.message ?? "Unknown error", e.appName, tag, params);
|
|
3032
2318
|
}
|
|
3033
2319
|
const mapped = mapLedgerError(err);
|
|
3034
2320
|
return ledgerFailure(mapped.code, mapped.message, mapped.appName, tag);
|
|
@@ -3055,7 +2341,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
3055
2341
|
deviceId: device.deviceId,
|
|
3056
2342
|
connectId: device.connectId,
|
|
3057
2343
|
label: device.name,
|
|
3058
|
-
connectionType:
|
|
2344
|
+
connectionType: this.connector.connectionType,
|
|
3059
2345
|
rssi: device.rssi,
|
|
3060
2346
|
isConnectable: device.isConnectable,
|
|
3061
2347
|
serialNumber: device.serialNumber,
|
|
@@ -3080,7 +2366,7 @@ _LedgerAdapter.APP_INSTALL_PROGRESS_MIN_DELTA = 0.05;
|
|
|
3080
2366
|
var LedgerAdapter = _LedgerAdapter;
|
|
3081
2367
|
|
|
3082
2368
|
// src/connector/LedgerConnectorBase.ts
|
|
3083
|
-
var
|
|
2369
|
+
var import_hwk_adapter_core13 = require("@onekeyfe/hwk-adapter-core");
|
|
3084
2370
|
|
|
3085
2371
|
// src/device/LedgerDeviceManager.ts
|
|
3086
2372
|
var LedgerDeviceManager = class {
|
|
@@ -3616,7 +2902,7 @@ var SignerManager = class _SignerManager {
|
|
|
3616
2902
|
return (args) => new import_device_signer_kit_ethereum.SignerEthBuilder(args);
|
|
3617
2903
|
}
|
|
3618
2904
|
static _createContextModule() {
|
|
3619
|
-
const contextModule = new import_context_module.ContextModuleBuilder({}).
|
|
2905
|
+
const contextModule = new import_context_module.ContextModuleBuilder({}).removeDefaultLoaders().build();
|
|
3620
2906
|
return _SignerManager.wrapBlindSigningReportNonBlocking(contextModule);
|
|
3621
2907
|
}
|
|
3622
2908
|
static wrapBlindSigningReportNonBlocking(contextModule) {
|
|
@@ -3654,27 +2940,6 @@ function collapseSignerInteraction(interaction) {
|
|
|
3654
2940
|
return import_hwk_adapter_core5.EConnectorInteraction.ConfirmOnDevice;
|
|
3655
2941
|
}
|
|
3656
2942
|
}
|
|
3657
|
-
function wireSignerToSession(ctx, sessionId, chain, signer) {
|
|
3658
|
-
signer.onInteraction = (interaction) => {
|
|
3659
|
-
debugLog(`[LedgerConnector] ${chain}.onInteraction:`, interaction);
|
|
3660
|
-
ctx.emit("ui-event", {
|
|
3661
|
-
type: collapseSignerInteraction(interaction),
|
|
3662
|
-
payload: { sessionId }
|
|
3663
|
-
});
|
|
3664
|
-
};
|
|
3665
|
-
signer.onRegisterCanceller = (cancel) => ctx.registerCanceller(sessionId, cancel);
|
|
3666
|
-
return signer;
|
|
3667
|
-
}
|
|
3668
|
-
async function runSignerCall(ctx, sessionId, call) {
|
|
3669
|
-
try {
|
|
3670
|
-
return await call();
|
|
3671
|
-
} catch (err) {
|
|
3672
|
-
ctx.invalidateSession(sessionId);
|
|
3673
|
-
throw ctx.wrapError(err);
|
|
3674
|
-
} finally {
|
|
3675
|
-
ctx.clearCanceller(sessionId);
|
|
3676
|
-
}
|
|
3677
|
-
}
|
|
3678
2943
|
|
|
3679
2944
|
// src/connector/chains/evm.ts
|
|
3680
2945
|
async function evmGetAddress(ctx, sessionId, params) {
|
|
@@ -4108,7 +3373,6 @@ function _applySignaturesToPsbt(psbtHex, signatures) {
|
|
|
4108
3373
|
|
|
4109
3374
|
// src/connector/chains/sol.ts
|
|
4110
3375
|
var import_hwk_adapter_core9 = require("@onekeyfe/hwk-adapter-core");
|
|
4111
|
-
var import_bs58 = __toESM(require("bs58"));
|
|
4112
3376
|
|
|
4113
3377
|
// src/signer/SignerSol.ts
|
|
4114
3378
|
var SignerSol = class {
|
|
@@ -4192,21 +3456,8 @@ async function solSignMessage(ctx, sessionId, params) {
|
|
|
4192
3456
|
const path = normalizePath(params.path);
|
|
4193
3457
|
const messageBytes = (0, import_hwk_adapter_core9.hexToBytes)(params.message);
|
|
4194
3458
|
try {
|
|
4195
|
-
if (params.messageVersion === 1) {
|
|
4196
|
-
const preparedMessage = (0, import_hwk_adapter_core9.prepareSolanaOffchainMessageV1)({
|
|
4197
|
-
message: messageBytes,
|
|
4198
|
-
requiredSigners: params.requiredSigners
|
|
4199
|
-
});
|
|
4200
|
-
const { SignMessageVersion } = await ctx.importLedgerKit(
|
|
4201
|
-
"@ledgerhq/device-signer-kit-solana"
|
|
4202
|
-
);
|
|
4203
|
-
const result2 = await solSigner.signMessage(path, preparedMessage.serializedMessage, {
|
|
4204
|
-
version: SignMessageVersion.Raw
|
|
4205
|
-
});
|
|
4206
|
-
return { signature: decodeBase58Signature(result2.signature) };
|
|
4207
|
-
}
|
|
4208
3459
|
const result = await solSigner.signMessage(path, messageBytes);
|
|
4209
|
-
return { signature:
|
|
3460
|
+
return { signature: result.signature };
|
|
4210
3461
|
} catch (err) {
|
|
4211
3462
|
ctx.invalidateSession(sessionId);
|
|
4212
3463
|
throw ctx.wrapError(err);
|
|
@@ -4214,27 +3465,11 @@ async function solSignMessage(ctx, sessionId, params) {
|
|
|
4214
3465
|
ctx.clearCanceller(sessionId);
|
|
4215
3466
|
}
|
|
4216
3467
|
}
|
|
4217
|
-
function decodeBase58Signature(signature) {
|
|
4218
|
-
const bytes = import_bs58.default.decode(signature);
|
|
4219
|
-
if (bytes.length !== 64) {
|
|
4220
|
-
throw new Error(`Ledger Solana signature must be 64 bytes, received ${bytes.length}`);
|
|
4221
|
-
}
|
|
4222
|
-
return (0, import_hwk_adapter_core9.bytesToHex)(bytes);
|
|
4223
|
-
}
|
|
4224
|
-
function decodeBase58EnvelopeSignature(envelope) {
|
|
4225
|
-
const bytes = import_bs58.default.decode(envelope);
|
|
4226
|
-
if (bytes.length < 65 || bytes[0] !== 1) {
|
|
4227
|
-
throw new Error("Ledger Solana signature envelope is invalid");
|
|
4228
|
-
}
|
|
4229
|
-
return (0, import_hwk_adapter_core9.bytesToHex)(bytes.subarray(1, 65));
|
|
4230
|
-
}
|
|
4231
3468
|
async function _createSolSigner(ctx, sessionId) {
|
|
4232
3469
|
const dmk = await ctx.getOrCreateDmk();
|
|
4233
|
-
const { ContextModuleBuilder: ContextModuleBuilder2
|
|
4234
|
-
"@ledgerhq/context-module"
|
|
4235
|
-
);
|
|
3470
|
+
const { ContextModuleBuilder: ContextModuleBuilder2 } = await ctx.importLedgerKit("@ledgerhq/context-module");
|
|
4236
3471
|
const { SignerSolanaBuilder } = await ctx.importLedgerKit("@ledgerhq/device-signer-kit-solana");
|
|
4237
|
-
const contextModule = new ContextModuleBuilder2({}).
|
|
3472
|
+
const contextModule = new ContextModuleBuilder2({}).removeDefaultLoaders().build();
|
|
4238
3473
|
const sdkSigner = new SignerSolanaBuilder({ dmk, sessionId }).withContextModule(contextModule).build();
|
|
4239
3474
|
const signer = new SignerSol(sdkSigner);
|
|
4240
3475
|
signer.onInteraction = (interaction) => {
|
|
@@ -4250,151 +3485,360 @@ async function _createSolSigner(ctx, sessionId) {
|
|
|
4250
3485
|
return signer;
|
|
4251
3486
|
}
|
|
4252
3487
|
|
|
4253
|
-
// src/connector/chains/
|
|
4254
|
-
var
|
|
3488
|
+
// src/connector/chains/tron.ts
|
|
3489
|
+
var import_hwk_adapter_core12 = require("@onekeyfe/hwk-adapter-core");
|
|
3490
|
+
var import_hw_app_trx = __toESM(require("@ledgerhq/hw-app-trx"));
|
|
4255
3491
|
|
|
4256
|
-
// src/
|
|
4257
|
-
var
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
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;
|
|
4261
3514
|
}
|
|
4262
|
-
/**
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
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
|
+
}
|
|
4270
3593
|
);
|
|
4271
3594
|
}
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
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})`
|
|
4280
3657
|
);
|
|
4281
3658
|
}
|
|
3659
|
+
_isDashboard(appName) {
|
|
3660
|
+
return appName === DASHBOARD_APP_NAME;
|
|
3661
|
+
}
|
|
3662
|
+
_wait() {
|
|
3663
|
+
return new Promise((resolve) => setTimeout(resolve, this._waitMs));
|
|
3664
|
+
}
|
|
4282
3665
|
};
|
|
4283
3666
|
|
|
4284
|
-
// src/connector/chains/
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
const path = normalizePath(params.path);
|
|
4288
|
-
const mode = params.mode ?? "ufvk";
|
|
4289
|
-
return runSignerCall(ctx, sessionId, async () => {
|
|
4290
|
-
const result = await signer.getFullViewingKey(path, { mode });
|
|
4291
|
-
if (result.mode === "ufvk") {
|
|
4292
|
-
return { path: params.path, mode, ufvk: result.fullViewingKey };
|
|
4293
|
-
}
|
|
4294
|
-
return { path: params.path, mode, orchardFvk: (0, import_hwk_adapter_core10.bytesToHex)(result.fullViewingKey) };
|
|
4295
|
-
});
|
|
3667
|
+
// src/connector/chains/legacyChainCall.ts
|
|
3668
|
+
function isLegacyWrongAppError(err, _appName) {
|
|
3669
|
+
return isWrongAppError(err);
|
|
4296
3670
|
}
|
|
4297
|
-
async function
|
|
4298
|
-
const
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
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 }
|
|
4303
3679
|
});
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
}
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
this._sdk = _sdk;
|
|
4322
|
-
}
|
|
4323
|
-
/** Base58 Tron address plus the uncompressed public key at `derivationPath`. */
|
|
4324
|
-
async getAddress(derivationPath, options) {
|
|
4325
|
-
const action = this._sdk.getAddress(derivationPath, options);
|
|
4326
|
-
const result = await deviceActionToPromise(
|
|
4327
|
-
action,
|
|
4328
|
-
this.onInteraction,
|
|
4329
|
-
void 0,
|
|
4330
|
-
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
|
|
4331
3697
|
);
|
|
4332
|
-
|
|
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;
|
|
4333
3761
|
}
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
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;
|
|
4343
3774
|
}
|
|
4344
|
-
|
|
4345
|
-
async signPersonalMessage(derivationPath, message, options) {
|
|
4346
|
-
const action = this._sdk.signPersonalMessage(derivationPath, message, options);
|
|
4347
|
-
return deviceActionToPromise(
|
|
4348
|
-
action,
|
|
4349
|
-
this.onInteraction,
|
|
4350
|
-
void 0,
|
|
4351
|
-
this.onRegisterCanceller
|
|
4352
|
-
);
|
|
3775
|
+
async close() {
|
|
4353
3776
|
}
|
|
4354
3777
|
};
|
|
4355
3778
|
|
|
4356
3779
|
// src/connector/chains/tron.ts
|
|
4357
3780
|
async function tronGetAddress(ctx, sessionId, params) {
|
|
4358
|
-
const tronSigner = await _createTronSigner(ctx, sessionId);
|
|
4359
3781
|
const path = normalizePath(params.path);
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
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
|
+
);
|
|
4366
3798
|
}
|
|
4367
3799
|
async function tronSignTransaction(ctx, sessionId, params) {
|
|
4368
3800
|
if (!params.rawTxHex) {
|
|
4369
3801
|
throw Object.assign(
|
|
4370
3802
|
new Error("TRON signing requires a protobuf-encoded raw transaction hex (rawTxHex)."),
|
|
4371
|
-
{ code:
|
|
3803
|
+
{ code: import_hwk_adapter_core12.HardwareErrorCode.InvalidParams }
|
|
4372
3804
|
);
|
|
4373
3805
|
}
|
|
4374
|
-
const tronSigner = await _createTronSigner(ctx, sessionId);
|
|
4375
3806
|
const path = normalizePath(params.path);
|
|
4376
|
-
return
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
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
|
+
);
|
|
4380
3821
|
}
|
|
4381
3822
|
async function tronSignMessage(ctx, sessionId, params) {
|
|
4382
|
-
const tronSigner = await _createTronSigner(ctx, sessionId);
|
|
4383
3823
|
const path = normalizePath(params.path);
|
|
4384
|
-
return
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
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
|
+
);
|
|
4388
3834
|
}
|
|
4389
|
-
async function
|
|
3835
|
+
async function _createTrx(ctx, sessionId) {
|
|
4390
3836
|
const dmk = await ctx.getOrCreateDmk();
|
|
4391
|
-
|
|
4392
|
-
const sdkSigner = new SignerTrxBuilder({ dmk, sessionId }).build();
|
|
4393
|
-
return wireSignerToSession(ctx, sessionId, "tron", new SignerTron(sdkSigner));
|
|
3837
|
+
return new import_hw_app_trx.default(new DmkTransport(dmk, sessionId));
|
|
4394
3838
|
}
|
|
4395
3839
|
|
|
4396
3840
|
// src/device-apps/customActions.ts
|
|
4397
|
-
var
|
|
3841
|
+
var import_device_management_kit3 = require("@ledgerhq/device-management-kit");
|
|
4398
3842
|
var import_rxjs = require("rxjs");
|
|
4399
3843
|
var GetOsVersionDeviceAction = class {
|
|
4400
3844
|
// eslint-disable-next-line no-useless-constructor, no-empty-function
|
|
@@ -4408,7 +3852,7 @@ var GetOsVersionDeviceAction = class {
|
|
|
4408
3852
|
(async () => {
|
|
4409
3853
|
try {
|
|
4410
3854
|
subject.next({
|
|
4411
|
-
status:
|
|
3855
|
+
status: import_device_management_kit3.DeviceActionStatus.Pending,
|
|
4412
3856
|
intermediateValue: { requiredUserInteraction: "none" }
|
|
4413
3857
|
});
|
|
4414
3858
|
const result = await internalApi.sendCommand(new this._deps.GetOsVersionCommand());
|
|
@@ -4417,11 +3861,11 @@ var GetOsVersionDeviceAction = class {
|
|
|
4417
3861
|
const errObj = result?.error;
|
|
4418
3862
|
throw new Error(errObj?.message ?? "GetOsVersionCommand failed");
|
|
4419
3863
|
}
|
|
4420
|
-
subject.next({ status:
|
|
3864
|
+
subject.next({ status: import_device_management_kit3.DeviceActionStatus.Completed, output: result.data });
|
|
4421
3865
|
subject.complete();
|
|
4422
3866
|
} catch (err) {
|
|
4423
3867
|
if (cancelled) return;
|
|
4424
|
-
subject.next({ status:
|
|
3868
|
+
subject.next({ status: import_device_management_kit3.DeviceActionStatus.Error, error: err });
|
|
4425
3869
|
subject.complete();
|
|
4426
3870
|
}
|
|
4427
3871
|
})();
|
|
@@ -4429,7 +3873,7 @@ var GetOsVersionDeviceAction = class {
|
|
|
4429
3873
|
observable: subject.asObservable(),
|
|
4430
3874
|
cancel: () => {
|
|
4431
3875
|
cancelled = true;
|
|
4432
|
-
subject.next({ status:
|
|
3876
|
+
subject.next({ status: import_device_management_kit3.DeviceActionStatus.Stopped });
|
|
4433
3877
|
subject.complete();
|
|
4434
3878
|
}
|
|
4435
3879
|
};
|
|
@@ -4447,7 +3891,7 @@ var ListAvailableAppsDeviceAction = class {
|
|
|
4447
3891
|
(async () => {
|
|
4448
3892
|
try {
|
|
4449
3893
|
subject.next({
|
|
4450
|
-
status:
|
|
3894
|
+
status: import_device_management_kit3.DeviceActionStatus.Pending,
|
|
4451
3895
|
intermediateValue: { requiredUserInteraction: "none" }
|
|
4452
3896
|
});
|
|
4453
3897
|
const osVersionResult = await internalApi.sendCommand(new this._GetOsVersionCommand());
|
|
@@ -4464,11 +3908,11 @@ var ListAvailableAppsDeviceAction = class {
|
|
|
4464
3908
|
throw new Error(httpErr?.message ?? "Manager API getAppList failed");
|
|
4465
3909
|
}
|
|
4466
3910
|
const apps = either.extract();
|
|
4467
|
-
subject.next({ status:
|
|
3911
|
+
subject.next({ status: import_device_management_kit3.DeviceActionStatus.Completed, output: apps });
|
|
4468
3912
|
subject.complete();
|
|
4469
3913
|
} catch (err) {
|
|
4470
3914
|
if (cancelled) return;
|
|
4471
|
-
subject.next({ status:
|
|
3915
|
+
subject.next({ status: import_device_management_kit3.DeviceActionStatus.Error, error: err });
|
|
4472
3916
|
subject.complete();
|
|
4473
3917
|
}
|
|
4474
3918
|
})();
|
|
@@ -4476,7 +3920,7 @@ var ListAvailableAppsDeviceAction = class {
|
|
|
4476
3920
|
observable: subject.asObservable(),
|
|
4477
3921
|
cancel: () => {
|
|
4478
3922
|
cancelled = true;
|
|
4479
|
-
subject.next({ status:
|
|
3923
|
+
subject.next({ status: import_device_management_kit3.DeviceActionStatus.Stopped });
|
|
4480
3924
|
subject.complete();
|
|
4481
3925
|
}
|
|
4482
3926
|
};
|
|
@@ -4569,7 +4013,7 @@ var DeviceApps = class {
|
|
|
4569
4013
|
seTargetId: v.seTargetId,
|
|
4570
4014
|
mcuTargetId: v.mcuTargetId,
|
|
4571
4015
|
seVersion: v.seVersion,
|
|
4572
|
-
seFlagsHex:
|
|
4016
|
+
seFlagsHex: bytesToHex2(v.seFlags),
|
|
4573
4017
|
mcuSephVersion: v.mcuSephVersion,
|
|
4574
4018
|
mcuBootloaderVersion: v.mcuBootloaderVersion,
|
|
4575
4019
|
hwVersion: v.hwVersion
|
|
@@ -4643,7 +4087,7 @@ var DeviceApps = class {
|
|
|
4643
4087
|
}
|
|
4644
4088
|
}
|
|
4645
4089
|
};
|
|
4646
|
-
function
|
|
4090
|
+
function bytesToHex2(bytes) {
|
|
4647
4091
|
if (!bytes) return "";
|
|
4648
4092
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
4649
4093
|
}
|
|
@@ -4686,11 +4130,10 @@ var METHOD_PREFIX_TO_APP_NAME = {
|
|
|
4686
4130
|
evm: "Ethereum",
|
|
4687
4131
|
btc: "Bitcoin",
|
|
4688
4132
|
sol: "Solana",
|
|
4689
|
-
tron: "Tron"
|
|
4690
|
-
zcash: "Zcash"
|
|
4133
|
+
tron: "Tron"
|
|
4691
4134
|
};
|
|
4692
4135
|
var HARDWARE_ERROR_CODE_VALUES = new Set(
|
|
4693
|
-
Object.values(
|
|
4136
|
+
Object.values(import_hwk_adapter_core13.HardwareErrorCode).filter((value) => typeof value === "number")
|
|
4694
4137
|
);
|
|
4695
4138
|
var BLE_CONNECT_SCAN_TIMEOUT_MS = 1500;
|
|
4696
4139
|
var LEDGER_RELAY_ALLOWED_ROOT_DOMAINS = ["onekeytest.com", "onekey.com"];
|
|
@@ -4727,10 +4170,6 @@ async function defaultLedgerKitImporter(pkg) {
|
|
|
4727
4170
|
return import("@ledgerhq/device-signer-kit-bitcoin");
|
|
4728
4171
|
case "@ledgerhq/device-signer-kit-solana":
|
|
4729
4172
|
return import("@ledgerhq/device-signer-kit-solana");
|
|
4730
|
-
case "@ledgerhq/device-signer-kit-tron":
|
|
4731
|
-
return import("@ledgerhq/device-signer-kit-tron");
|
|
4732
|
-
case "@ledgerhq/device-signer-kit-zcash":
|
|
4733
|
-
return import("@ledgerhq/device-signer-kit-zcash");
|
|
4734
4173
|
case "@ledgerhq/context-module":
|
|
4735
4174
|
return import("@ledgerhq/context-module");
|
|
4736
4175
|
default:
|
|
@@ -4790,7 +4229,6 @@ var LedgerConnectorBase = class {
|
|
|
4790
4229
|
this._ctx = {
|
|
4791
4230
|
emit: (event, data) => this._emit(event, data),
|
|
4792
4231
|
invalidateSession: (sid) => this._invalidateSession(sid),
|
|
4793
|
-
teardownSecureChannelSession: (sid) => this._teardownSecureChannelSession(sid),
|
|
4794
4232
|
wrapError: (err, opts) => this._wrapError(err, opts),
|
|
4795
4233
|
getOrCreateDmk: () => this._getOrCreateDmk(),
|
|
4796
4234
|
getDeviceManager: () => this._getDeviceManager(),
|
|
@@ -4842,7 +4280,7 @@ var LedgerConnectorBase = class {
|
|
|
4842
4280
|
async searchDevices() {
|
|
4843
4281
|
const dm = await this._getDeviceManager();
|
|
4844
4282
|
const descriptors = await this._discoverDescriptors(dm);
|
|
4845
|
-
const resolvedDescriptors = descriptors.filter((d) => !(0,
|
|
4283
|
+
const resolvedDescriptors = descriptors.filter((d) => !(0, import_hwk_adapter_core13.isKnownNonTargetHardwareVendor)(d, "ledger")).map((d) => ({
|
|
4846
4284
|
descriptor: d,
|
|
4847
4285
|
connectId: this._resolveConnectId(d)
|
|
4848
4286
|
}));
|
|
@@ -4890,7 +4328,7 @@ var LedgerConnectorBase = class {
|
|
|
4890
4328
|
`Ledger BLE connect did not return within ${HANG_CEILING_MS / 6e4}min \u2014 DMK hang fallback.`
|
|
4891
4329
|
);
|
|
4892
4330
|
err._tag = ERROR_TAG.BlePairingTimeout;
|
|
4893
|
-
err.code =
|
|
4331
|
+
err.code = import_hwk_adapter_core13.HardwareErrorCode.BlePairingTimeout;
|
|
4894
4332
|
reject(err);
|
|
4895
4333
|
}, HANG_CEILING_MS);
|
|
4896
4334
|
});
|
|
@@ -4923,7 +4361,7 @@ var LedgerConnectorBase = class {
|
|
|
4923
4361
|
"Ledger device is not currently advertising. Wake up and unlock the device, keep it nearby, then try again."
|
|
4924
4362
|
);
|
|
4925
4363
|
err._tag = ERROR_TAG.DeviceNotAdvertising;
|
|
4926
|
-
err.code =
|
|
4364
|
+
err.code = import_hwk_adapter_core13.HardwareErrorCode.DeviceNotFound;
|
|
4927
4365
|
throw err;
|
|
4928
4366
|
};
|
|
4929
4367
|
const doConnect = async (path) => {
|
|
@@ -4980,14 +4418,14 @@ var LedgerConnectorBase = class {
|
|
|
4980
4418
|
this._resetSignersAndSessions();
|
|
4981
4419
|
if (isLedgerBleConnectionType(this.connectionType)) {
|
|
4982
4420
|
const tag = err?._tag;
|
|
4983
|
-
if (isKnownConnectionTag(tag)
|
|
4421
|
+
if (isKnownConnectionTag(tag)) {
|
|
4984
4422
|
throw err;
|
|
4985
4423
|
}
|
|
4986
4424
|
const wrapped = new Error(
|
|
4987
4425
|
"Ledger Bluetooth pairing failed. Make sure the device is unlocked and nearby, then try again."
|
|
4988
4426
|
);
|
|
4989
4427
|
wrapped._tag = ERROR_TAG.BleGattBondingFailed;
|
|
4990
|
-
wrapped.code =
|
|
4428
|
+
wrapped.code = import_hwk_adapter_core13.HardwareErrorCode.BlePairingTimeout;
|
|
4991
4429
|
wrapped.originalError = err;
|
|
4992
4430
|
throw wrapped;
|
|
4993
4431
|
}
|
|
@@ -5065,7 +4503,7 @@ var LedgerConnectorBase = class {
|
|
|
5065
4503
|
this._unwatchSessionState(sessionId);
|
|
5066
4504
|
this._signerManager?.invalidate(sessionId);
|
|
5067
4505
|
this._cancellers.get(sessionId)?.({
|
|
5068
|
-
code:
|
|
4506
|
+
code: import_hwk_adapter_core13.HardwareErrorCode.DeviceDisconnected,
|
|
5069
4507
|
tag: "DeviceDisconnected",
|
|
5070
4508
|
message: "Device disconnected"
|
|
5071
4509
|
});
|
|
@@ -5089,9 +4527,9 @@ var LedgerConnectorBase = class {
|
|
|
5089
4527
|
if (isAppStuckByApdu(err)) {
|
|
5090
4528
|
return {
|
|
5091
4529
|
success: false,
|
|
5092
|
-
error: (0,
|
|
4530
|
+
error: (0, import_hwk_adapter_core13.serializeConnectorError)(
|
|
5093
4531
|
Object.assign(new Error("Ledger app is unresponsive"), {
|
|
5094
|
-
code:
|
|
4532
|
+
code: import_hwk_adapter_core13.HardwareErrorCode.DeviceAppStuck,
|
|
5095
4533
|
_tag: ERROR_TAG.DeviceAppStuck,
|
|
5096
4534
|
originalError: err
|
|
5097
4535
|
})
|
|
@@ -5101,16 +4539,16 @@ var LedgerConnectorBase = class {
|
|
|
5101
4539
|
if (isTransportStuck(err)) {
|
|
5102
4540
|
return {
|
|
5103
4541
|
success: false,
|
|
5104
|
-
error: (0,
|
|
4542
|
+
error: (0, import_hwk_adapter_core13.serializeConnectorError)(
|
|
5105
4543
|
Object.assign(new Error("Device communication interrupted, please retry"), {
|
|
5106
|
-
code:
|
|
4544
|
+
code: import_hwk_adapter_core13.HardwareErrorCode.TransportError,
|
|
5107
4545
|
_tag: ERROR_TAG.DeviceTransportStuck,
|
|
5108
4546
|
originalError: err
|
|
5109
4547
|
})
|
|
5110
4548
|
)
|
|
5111
4549
|
};
|
|
5112
4550
|
}
|
|
5113
|
-
return { success: false, error: (0,
|
|
4551
|
+
return { success: false, error: (0, import_hwk_adapter_core13.serializeConnectorError)(err) };
|
|
5114
4552
|
}
|
|
5115
4553
|
}
|
|
5116
4554
|
async _dispatch(sessionId, method, params) {
|
|
@@ -5149,11 +4587,6 @@ var LedgerConnectorBase = class {
|
|
|
5149
4587
|
return solSignTransaction(ctx, sessionId, params);
|
|
5150
4588
|
case "solSignMessage":
|
|
5151
4589
|
return solSignMessage(ctx, sessionId, params);
|
|
5152
|
-
// ZCASH
|
|
5153
|
-
case "zcashGetFullViewingKey":
|
|
5154
|
-
return zcashGetFullViewingKey(ctx, sessionId, params);
|
|
5155
|
-
case "zcashGetShieldedAddress":
|
|
5156
|
-
return zcashGetShieldedAddress(ctx, sessionId, params);
|
|
5157
4590
|
// TRON
|
|
5158
4591
|
case "tronGetAddress":
|
|
5159
4592
|
return tronGetAddress(ctx, sessionId, params);
|
|
@@ -5178,7 +4611,7 @@ var LedgerConnectorBase = class {
|
|
|
5178
4611
|
try {
|
|
5179
4612
|
return await apps.install(p.appName, ({ progress }) => {
|
|
5180
4613
|
ctx.emit("ui-event", {
|
|
5181
|
-
type:
|
|
4614
|
+
type: import_hwk_adapter_core13.EConnectorInteraction.AppInstallProgress,
|
|
5182
4615
|
payload: {
|
|
5183
4616
|
sessionId,
|
|
5184
4617
|
appName: p.appName,
|
|
@@ -5187,7 +4620,7 @@ var LedgerConnectorBase = class {
|
|
|
5187
4620
|
});
|
|
5188
4621
|
});
|
|
5189
4622
|
} catch (err) {
|
|
5190
|
-
ctx.
|
|
4623
|
+
ctx.invalidateSession(sessionId);
|
|
5191
4624
|
throw ctx.wrapError(err);
|
|
5192
4625
|
} finally {
|
|
5193
4626
|
ctx.clearCanceller(sessionId);
|
|
@@ -5277,7 +4710,7 @@ var LedgerConnectorBase = class {
|
|
|
5277
4710
|
);
|
|
5278
4711
|
return { isGenuine: output.isGenuine, deviceId };
|
|
5279
4712
|
} catch (err) {
|
|
5280
|
-
ctx.
|
|
4713
|
+
ctx.invalidateSession(sessionId);
|
|
5281
4714
|
throw ctx.wrapError(err);
|
|
5282
4715
|
} finally {
|
|
5283
4716
|
ctx.clearCanceller(sessionId);
|
|
@@ -5396,26 +4829,9 @@ var LedgerConnectorBase = class {
|
|
|
5396
4829
|
}
|
|
5397
4830
|
return this._deviceAppsManager;
|
|
5398
4831
|
}
|
|
5399
|
-
// DeviceAppsManager is a per-call factory with no cached session state, so
|
|
5400
|
-
// there is nothing to invalidate for it here.
|
|
5401
4832
|
_invalidateSession(sessionId) {
|
|
5402
4833
|
this._signerManager?.invalidate(sessionId);
|
|
5403
4834
|
}
|
|
5404
|
-
/**
|
|
5405
|
-
* Fire the canceller so DMK closes the secure-channel WebSocket. The DMK device
|
|
5406
|
-
* session is kept: unlock/retry recovery reuses it.
|
|
5407
|
-
*/
|
|
5408
|
-
_teardownSecureChannelSession(sessionId) {
|
|
5409
|
-
const cancel = this._cancellers.get(sessionId);
|
|
5410
|
-
this._cancellers.delete(sessionId);
|
|
5411
|
-
if (cancel) {
|
|
5412
|
-
try {
|
|
5413
|
-
cancel();
|
|
5414
|
-
} catch {
|
|
5415
|
-
}
|
|
5416
|
-
}
|
|
5417
|
-
this._invalidateSession(sessionId);
|
|
5418
|
-
}
|
|
5419
4835
|
/**
|
|
5420
4836
|
* Replace an old session with a new one after app switch.
|
|
5421
4837
|
* Emits device-connect so the adapter updates its _sessions Map.
|
|
@@ -5500,7 +4916,7 @@ var LedgerConnectorBase = class {
|
|
|
5500
4916
|
* at every catch site. Falls through unchanged for unknown methods.
|
|
5501
4917
|
*/
|
|
5502
4918
|
_ctxForMethod(method) {
|
|
5503
|
-
const prefix = /^(evm|btc|sol|tron
|
|
4919
|
+
const prefix = /^(evm|btc|sol|tron)/.exec(method)?.[1];
|
|
5504
4920
|
const defaultAppName = prefix ? METHOD_PREFIX_TO_APP_NAME[prefix] : void 0;
|
|
5505
4921
|
if (!defaultAppName) return this._ctx;
|
|
5506
4922
|
return {
|
|
@@ -5534,204 +4950,6 @@ var LedgerConnectorBase = class {
|
|
|
5534
4950
|
return error;
|
|
5535
4951
|
}
|
|
5536
4952
|
};
|
|
5537
|
-
|
|
5538
|
-
// src/transport/DmkTransport.ts
|
|
5539
|
-
var import_hw_transport = __toESM(require("@ledgerhq/hw-transport"));
|
|
5540
|
-
var DmkTransport = class extends import_hw_transport.default {
|
|
5541
|
-
constructor(dmk, sessionId) {
|
|
5542
|
-
super();
|
|
5543
|
-
this._dmk = dmk;
|
|
5544
|
-
this._sessionId = sessionId;
|
|
5545
|
-
}
|
|
5546
|
-
async exchange(apdu) {
|
|
5547
|
-
const response = await this._dmk.sendApdu({
|
|
5548
|
-
sessionId: this._sessionId,
|
|
5549
|
-
apdu: new Uint8Array(apdu)
|
|
5550
|
-
});
|
|
5551
|
-
const { data, statusCode } = response;
|
|
5552
|
-
const result = Buffer.alloc(data.length + 2);
|
|
5553
|
-
if (data.length > 0) {
|
|
5554
|
-
result.set(data, 0);
|
|
5555
|
-
}
|
|
5556
|
-
result.set(statusCode, data.length);
|
|
5557
|
-
return result;
|
|
5558
|
-
}
|
|
5559
|
-
async close() {
|
|
5560
|
-
}
|
|
5561
|
-
};
|
|
5562
|
-
|
|
5563
|
-
// src/app/AppManager.ts
|
|
5564
|
-
var import_device_management_kit3 = require("@ledgerhq/device-management-kit");
|
|
5565
|
-
var import_hwk_adapter_core13 = require("@onekeyfe/hwk-adapter-core");
|
|
5566
|
-
var APP_NAME_MAP = {
|
|
5567
|
-
ETH: "Ethereum",
|
|
5568
|
-
BTC: "Bitcoin",
|
|
5569
|
-
SOL: "Solana",
|
|
5570
|
-
TRX: "Tron",
|
|
5571
|
-
ZEC: "Zcash",
|
|
5572
|
-
XRP: "XRP",
|
|
5573
|
-
ADA: "Cardano",
|
|
5574
|
-
DOT: "Polkadot",
|
|
5575
|
-
ATOM: "Cosmos"
|
|
5576
|
-
};
|
|
5577
|
-
var DASHBOARD_APP_NAME = "BOLOS";
|
|
5578
|
-
var AppManager = class {
|
|
5579
|
-
constructor(dmk, options) {
|
|
5580
|
-
this._dmk = dmk;
|
|
5581
|
-
this._waitMs = options?.waitMs ?? 1e3;
|
|
5582
|
-
this._maxRetries = options?.maxRetries ?? 10;
|
|
5583
|
-
}
|
|
5584
|
-
/**
|
|
5585
|
-
* Return the Ledger app name for a given chain ticker,
|
|
5586
|
-
* or undefined if the chain is not supported.
|
|
5587
|
-
*/
|
|
5588
|
-
static getAppName(chain) {
|
|
5589
|
-
return APP_NAME_MAP[chain];
|
|
5590
|
-
}
|
|
5591
|
-
/**
|
|
5592
|
-
* Ensure the target app is open on the device identified by `sessionId`.
|
|
5593
|
-
*
|
|
5594
|
-
* Flow:
|
|
5595
|
-
* 1. Check the currently running app.
|
|
5596
|
-
* 2. If it is already the target, return immediately.
|
|
5597
|
-
* 3. If a different app is running (not dashboard), close it first.
|
|
5598
|
-
* 4. Open the target app.
|
|
5599
|
-
* 5. Poll until the device confirms the target app is running.
|
|
5600
|
-
*/
|
|
5601
|
-
/**
|
|
5602
|
-
* @param onConfirmOnDevice Called BEFORE OpenAppCommand is issued — the
|
|
5603
|
-
* device is about to display "Open <app>" on screen and wait for the
|
|
5604
|
-
* user's button press. UI consumers should show their "open app" prompt
|
|
5605
|
-
* in response. NOT called when the target app is already open (no user
|
|
5606
|
-
* interaction needed in that case).
|
|
5607
|
-
*
|
|
5608
|
-
* Important: OpenAppCommand is blocking. It does not resolve until the user
|
|
5609
|
-
* has physically confirmed on the device, so anything that runs AFTER
|
|
5610
|
-
* `await this._openApp(...)` lands AFTER the prompt is already gone.
|
|
5611
|
-
* Hence the callback must fire BEFORE that await.
|
|
5612
|
-
*/
|
|
5613
|
-
async ensureAppOpen(sessionId, targetAppName, onConfirmOnDevice) {
|
|
5614
|
-
const currentApp = await this._getCurrentApp(sessionId);
|
|
5615
|
-
if (currentApp === targetAppName) {
|
|
5616
|
-
return;
|
|
5617
|
-
}
|
|
5618
|
-
if (!this._isDashboard(currentApp)) {
|
|
5619
|
-
await this._closeCurrentApp(sessionId);
|
|
5620
|
-
await this._waitForApp(sessionId, DASHBOARD_APP_NAME);
|
|
5621
|
-
}
|
|
5622
|
-
onConfirmOnDevice?.();
|
|
5623
|
-
await this._openApp(sessionId, targetAppName);
|
|
5624
|
-
await this._waitForApp(sessionId, targetAppName);
|
|
5625
|
-
}
|
|
5626
|
-
// ---------------------------------------------------------------------------
|
|
5627
|
-
// Private helpers
|
|
5628
|
-
// ---------------------------------------------------------------------------
|
|
5629
|
-
async _getCurrentApp(sessionId) {
|
|
5630
|
-
const result = await this._dmk.sendCommand({
|
|
5631
|
-
sessionId,
|
|
5632
|
-
command: new import_device_management_kit3.GetAppAndVersionCommand()
|
|
5633
|
-
});
|
|
5634
|
-
if ((0, import_device_management_kit3.isSuccessCommandResult)(result)) {
|
|
5635
|
-
debugLog("[AppManager] currentApp:", result.data.name);
|
|
5636
|
-
return result.data.name;
|
|
5637
|
-
}
|
|
5638
|
-
const errResult = result;
|
|
5639
|
-
const dmkErr = errResult.error ?? {};
|
|
5640
|
-
const original = dmkErr.originalError;
|
|
5641
|
-
debugLog(
|
|
5642
|
-
"[AppManager] _getCurrentApp failed sessionId=",
|
|
5643
|
-
sessionId,
|
|
5644
|
-
"tag=",
|
|
5645
|
-
dmkErr._tag,
|
|
5646
|
-
"errorCode=",
|
|
5647
|
-
dmkErr.errorCode,
|
|
5648
|
-
"message=",
|
|
5649
|
-
dmkErr.message,
|
|
5650
|
-
"originalErrorMessage=",
|
|
5651
|
-
original?.message ?? String(original ?? "")
|
|
5652
|
-
);
|
|
5653
|
-
throw Object.assign(
|
|
5654
|
-
new Error(
|
|
5655
|
-
dmkErr.message ?? "Failed to get current app from device"
|
|
5656
|
-
),
|
|
5657
|
-
{
|
|
5658
|
-
_tag: dmkErr._tag,
|
|
5659
|
-
errorCode: dmkErr.errorCode,
|
|
5660
|
-
originalError: original
|
|
5661
|
-
}
|
|
5662
|
-
);
|
|
5663
|
-
}
|
|
5664
|
-
async _openApp(sessionId, appName) {
|
|
5665
|
-
const result = await this._dmk.sendCommand({
|
|
5666
|
-
sessionId,
|
|
5667
|
-
command: new import_device_management_kit3.OpenAppCommand({ appName })
|
|
5668
|
-
});
|
|
5669
|
-
if (!(0, import_device_management_kit3.isSuccessCommandResult)(result)) {
|
|
5670
|
-
const dmkErr = result.error;
|
|
5671
|
-
const errorCode = "errorCode" in dmkErr && dmkErr.errorCode != null ? String(dmkErr.errorCode) : "";
|
|
5672
|
-
const message = "message" in dmkErr && typeof dmkErr.message === "string" ? dmkErr.message : "";
|
|
5673
|
-
debugLog(
|
|
5674
|
-
"[AppManager] openApp failed:",
|
|
5675
|
-
appName,
|
|
5676
|
-
"errorCode:",
|
|
5677
|
-
errorCode,
|
|
5678
|
-
"tag:",
|
|
5679
|
-
dmkErr._tag
|
|
5680
|
-
);
|
|
5681
|
-
let code;
|
|
5682
|
-
if (errorCode === "6807" || /unknown application/i.test(message)) {
|
|
5683
|
-
code = import_hwk_adapter_core13.HardwareErrorCode.AppNotInstalled;
|
|
5684
|
-
} else if (errorCode === "5501" || dmkErr._tag === "ActionRefusedError") {
|
|
5685
|
-
code = import_hwk_adapter_core13.HardwareErrorCode.UserRejected;
|
|
5686
|
-
}
|
|
5687
|
-
throw Object.assign(new Error(`Failed to open "${appName}"`), {
|
|
5688
|
-
_tag: ERROR_TAG.OpenAppCommand,
|
|
5689
|
-
code,
|
|
5690
|
-
errorCode,
|
|
5691
|
-
statusCode: errorCode,
|
|
5692
|
-
appName,
|
|
5693
|
-
originalError: dmkErr
|
|
5694
|
-
});
|
|
5695
|
-
}
|
|
5696
|
-
}
|
|
5697
|
-
async _closeCurrentApp(sessionId) {
|
|
5698
|
-
debugLog("[AppManager] closeCurrentApp");
|
|
5699
|
-
await this._dmk.sendCommand({
|
|
5700
|
-
sessionId,
|
|
5701
|
-
command: new import_device_management_kit3.CloseAppCommand()
|
|
5702
|
-
});
|
|
5703
|
-
}
|
|
5704
|
-
/**
|
|
5705
|
-
* Poll the device until the expected app is reported as running,
|
|
5706
|
-
* or throw after `_maxRetries` attempts.
|
|
5707
|
-
*/
|
|
5708
|
-
async _waitForApp(sessionId, expectedAppName) {
|
|
5709
|
-
let lastSeen = "";
|
|
5710
|
-
for (let i = 0; i < this._maxRetries; i++) {
|
|
5711
|
-
await this._wait();
|
|
5712
|
-
const current = await this._getCurrentApp(sessionId);
|
|
5713
|
-
lastSeen = current;
|
|
5714
|
-
if (current === expectedAppName) {
|
|
5715
|
-
return;
|
|
5716
|
-
}
|
|
5717
|
-
}
|
|
5718
|
-
debugLog(
|
|
5719
|
-
"[AppManager] waitForApp exhausted: expected=",
|
|
5720
|
-
expectedAppName,
|
|
5721
|
-
"lastSeen=",
|
|
5722
|
-
lastSeen
|
|
5723
|
-
);
|
|
5724
|
-
throw new Error(
|
|
5725
|
-
`Ledger: failed to open "${expectedAppName}" after ${this._maxRetries} retries (last seen: ${lastSeen})`
|
|
5726
|
-
);
|
|
5727
|
-
}
|
|
5728
|
-
_isDashboard(appName) {
|
|
5729
|
-
return appName === DASHBOARD_APP_NAME;
|
|
5730
|
-
}
|
|
5731
|
-
_wait() {
|
|
5732
|
-
return new Promise((resolve) => setTimeout(resolve, this._waitMs));
|
|
5733
|
-
}
|
|
5734
|
-
};
|
|
5735
4953
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5736
4954
|
0 && (module.exports = {
|
|
5737
4955
|
AppManager,
|
|
@@ -5743,7 +4961,6 @@ var AppManager = class {
|
|
|
5743
4961
|
SignerEth,
|
|
5744
4962
|
SignerManager,
|
|
5745
4963
|
SignerSol,
|
|
5746
|
-
SignerZcash,
|
|
5747
4964
|
debugLog,
|
|
5748
4965
|
deviceActionToPromise,
|
|
5749
4966
|
isDeviceLockedError,
|