@onekeyfe/hwk-ledger-adapter 1.1.26 → 1.1.27-alpha.31
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 +21 -49
- package/dist/index.d.ts +21 -49
- package/dist/index.js +161 -330
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +154 -324
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -39,12 +39,13 @@ __export(index_exports, {
|
|
|
39
39
|
SignerEth: () => SignerEth,
|
|
40
40
|
SignerManager: () => SignerManager,
|
|
41
41
|
SignerSol: () => SignerSol,
|
|
42
|
-
debugLog: () => debugLog,
|
|
43
42
|
deviceActionToPromise: () => deviceActionToPromise,
|
|
43
|
+
extractBleHexId: () => extractBleHexId,
|
|
44
44
|
isDeviceLockedError: () => isDeviceLockedError,
|
|
45
45
|
isLedgerBleConnectionType: () => isLedgerBleConnectionType,
|
|
46
46
|
isLedgerBleDescriptor: () => isLedgerBleDescriptor,
|
|
47
47
|
isLedgerDmkBleTransport: () => isLedgerDmkBleTransport,
|
|
48
|
+
isValidLedgerBleConnectId: () => isValidLedgerBleConnectId,
|
|
48
49
|
ledgerFailure: () => ledgerFailure,
|
|
49
50
|
mapLedgerError: () => mapLedgerError,
|
|
50
51
|
offSdkEvent: () => offSdkEvent,
|
|
@@ -68,7 +69,7 @@ var LOCKED_ERROR_CODES = /* @__PURE__ */ new Set(["5515", "21781", "6982", "2701
|
|
|
68
69
|
var USER_REJECTED_CODES = /* @__PURE__ */ new Set(["6985", "27013"]);
|
|
69
70
|
var WRONG_APP_CODES = /* @__PURE__ */ new Set(["6e00", "28160", "6d00", "27904", "6a83", "27267"]);
|
|
70
71
|
var APP_NOT_INSTALLED_CODES = /* @__PURE__ */ new Set(["6807", "26631"]);
|
|
71
|
-
var
|
|
72
|
+
var STEP_BLIND_SIGN_FALLBACK = "signer.eth.steps.blindSignTransactionFallback";
|
|
72
73
|
function getEthAppErrorCode(err) {
|
|
73
74
|
if (!err || typeof err !== "object") return null;
|
|
74
75
|
const e = err;
|
|
@@ -133,8 +134,13 @@ function mapBtcAppError(hex) {
|
|
|
133
134
|
return null;
|
|
134
135
|
}
|
|
135
136
|
}
|
|
136
|
-
function
|
|
137
|
+
function mapEthAppError(ethCode, lastStep) {
|
|
137
138
|
switch (ethCode) {
|
|
139
|
+
case "6a80":
|
|
140
|
+
if (lastStep === STEP_BLIND_SIGN_FALLBACK) {
|
|
141
|
+
return import_hwk_adapter_core.HardwareErrorCode.EvmBlindSigningRequired;
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
138
144
|
case "6984":
|
|
139
145
|
return import_hwk_adapter_core.HardwareErrorCode.EvmClearSignPluginMissing;
|
|
140
146
|
case "6a84":
|
|
@@ -147,20 +153,10 @@ function mapEthAppErrorCode(ethCode) {
|
|
|
147
153
|
return null;
|
|
148
154
|
}
|
|
149
155
|
}
|
|
150
|
-
function classifyEthAppError(err) {
|
|
151
|
-
const ethCode = getEthAppErrorCode(err);
|
|
152
|
-
if (!ethCode) return null;
|
|
153
|
-
if (ethCode === "6a80") {
|
|
154
|
-
return hasBlindSignFallbackStep(err) ? import_hwk_adapter_core.HardwareErrorCode.EvmBlindSigningRequired : null;
|
|
155
|
-
}
|
|
156
|
-
return mapEthAppErrorCode(ethCode);
|
|
157
|
-
}
|
|
158
156
|
var ERROR_TAG = {
|
|
159
157
|
// SDK-mint
|
|
160
158
|
DeviceNotAdvertising: "DeviceNotAdvertisingError",
|
|
161
159
|
// BLE scan miss
|
|
162
|
-
DeviceNotInDiscoveryCache: "DeviceNotInDiscoveryCacheError",
|
|
163
|
-
// dm.connect() before enumerate
|
|
164
160
|
BlePairingTimeout: "BlePairingTimeoutError",
|
|
165
161
|
// SMP 30s timeout
|
|
166
162
|
BleGattBondingFailed: "BleGattBondingFailedError",
|
|
@@ -243,25 +239,6 @@ var CONNECTION_LEVEL_TAGS = /* @__PURE__ */ new Set([
|
|
|
243
239
|
ERROR_TAG.ReconnectionFailed,
|
|
244
240
|
ERROR_TAG.WebHIDDisconnect
|
|
245
241
|
]);
|
|
246
|
-
var DEVICE_NOT_FOUND_TAGS = /* @__PURE__ */ new Set([
|
|
247
|
-
ERROR_TAG.NoAccessibleDevice,
|
|
248
|
-
ERROR_TAG.UnknownDevice,
|
|
249
|
-
ERROR_TAG.DeviceNotInitialized,
|
|
250
|
-
// SDK-internal: dm.connect() called before _discovered was populated.
|
|
251
|
-
// Map to DeviceNotFound so non-BLE-direct paths get a sensible error code.
|
|
252
|
-
ERROR_TAG.DeviceNotInDiscoveryCache
|
|
253
|
-
]);
|
|
254
|
-
var DEVICE_BUSY_TAGS = /* @__PURE__ */ new Set([ERROR_TAG.OpeningConnection]);
|
|
255
|
-
var DEVICE_DISCONNECTED_TAGS = /* @__PURE__ */ new Set([
|
|
256
|
-
ERROR_TAG.DeviceNotRecognized,
|
|
257
|
-
ERROR_TAG.DeviceSessionNotFound,
|
|
258
|
-
ERROR_TAG.DeviceSessionRefresher,
|
|
259
|
-
ERROR_TAG.DeviceDisconnectedBeforeSendingApdu,
|
|
260
|
-
ERROR_TAG.DeviceDisconnectedWhileSending,
|
|
261
|
-
ERROR_TAG.Disconnect,
|
|
262
|
-
ERROR_TAG.ReconnectionFailed,
|
|
263
|
-
ERROR_TAG.WebHIDDisconnect
|
|
264
|
-
]);
|
|
265
242
|
function isConnectionLevelError(err) {
|
|
266
243
|
if (!err || typeof err !== "object") return false;
|
|
267
244
|
const tag = err._tag;
|
|
@@ -283,35 +260,6 @@ function hasStatusCode(err, codeSet) {
|
|
|
283
260
|
if (e.error != null && e._tag && hasStatusCode(e.error, codeSet)) return true;
|
|
284
261
|
return false;
|
|
285
262
|
}
|
|
286
|
-
function hasBlindSignFallbackStep(err) {
|
|
287
|
-
if (!err || typeof err !== "object") return false;
|
|
288
|
-
const e = err;
|
|
289
|
-
if (e._lastStep === STEP_BLIND_SIGN_TRANSACTION_FALLBACK) return true;
|
|
290
|
-
if (Array.isArray(e._deviceActionSteps) && e._deviceActionSteps.includes(STEP_BLIND_SIGN_TRANSACTION_FALLBACK)) {
|
|
291
|
-
return true;
|
|
292
|
-
}
|
|
293
|
-
if (e.originalError != null && hasBlindSignFallbackStep(e.originalError)) return true;
|
|
294
|
-
if (e.error != null && e._tag && hasBlindSignFallbackStep(e.error)) return true;
|
|
295
|
-
return false;
|
|
296
|
-
}
|
|
297
|
-
function isDeviceNotFoundError(err) {
|
|
298
|
-
if (!err || typeof err !== "object") return false;
|
|
299
|
-
const tag = err._tag;
|
|
300
|
-
if (tag && DEVICE_NOT_FOUND_TAGS.has(tag)) return true;
|
|
301
|
-
const e = err;
|
|
302
|
-
if (e.originalError != null && isDeviceNotFoundError(e.originalError)) return true;
|
|
303
|
-
if (e.error != null && e._tag && isDeviceNotFoundError(e.error)) return true;
|
|
304
|
-
return false;
|
|
305
|
-
}
|
|
306
|
-
function isDeviceBusyError(err) {
|
|
307
|
-
if (!err || typeof err !== "object") return false;
|
|
308
|
-
const tag = err._tag;
|
|
309
|
-
if (tag && DEVICE_BUSY_TAGS.has(tag)) return true;
|
|
310
|
-
const e = err;
|
|
311
|
-
if (e.originalError != null && isDeviceBusyError(e.originalError)) return true;
|
|
312
|
-
if (e.error != null && e._tag && isDeviceBusyError(e.error)) return true;
|
|
313
|
-
return false;
|
|
314
|
-
}
|
|
315
263
|
function isUserRejectedError(err) {
|
|
316
264
|
if (!err || typeof err !== "object") return false;
|
|
317
265
|
const e = err;
|
|
@@ -344,8 +292,8 @@ function isAppNotInstalledError(err) {
|
|
|
344
292
|
function isDeviceDisconnectedError(err) {
|
|
345
293
|
if (!err || typeof err !== "object") return false;
|
|
346
294
|
const e = err;
|
|
347
|
-
|
|
348
|
-
|
|
295
|
+
if (e._tag === ERROR_TAG.DeviceNotRecognized || e._tag === ERROR_TAG.DeviceSessionNotFound)
|
|
296
|
+
return true;
|
|
349
297
|
if (typeof e.message === "string") {
|
|
350
298
|
const msg = e.message.toLowerCase();
|
|
351
299
|
if (msg.includes("disconnected") || msg.includes("not found") || msg.includes("no device") || msg.includes("unplugged"))
|
|
@@ -391,10 +339,8 @@ function mapLedgerError(err, opts) {
|
|
|
391
339
|
let code;
|
|
392
340
|
if (isDeviceLockedError(err)) {
|
|
393
341
|
code = import_hwk_adapter_core.HardwareErrorCode.DeviceLocked;
|
|
394
|
-
} else if (isDeviceNotAdvertisingError(err)
|
|
342
|
+
} else if (isDeviceNotAdvertisingError(err)) {
|
|
395
343
|
code = import_hwk_adapter_core.HardwareErrorCode.DeviceNotFound;
|
|
396
|
-
} else if (isDeviceBusyError(err)) {
|
|
397
|
-
code = import_hwk_adapter_core.HardwareErrorCode.DeviceBusy;
|
|
398
344
|
} else if (isBlePairingFailureError(err)) {
|
|
399
345
|
code = import_hwk_adapter_core.HardwareErrorCode.BlePairingTimeout;
|
|
400
346
|
} else if (isUserRejectedError(err)) {
|
|
@@ -408,7 +354,9 @@ function mapLedgerError(err, opts) {
|
|
|
408
354
|
} else if (isTimeoutError(err)) {
|
|
409
355
|
code = import_hwk_adapter_core.HardwareErrorCode.OperationTimeout;
|
|
410
356
|
} else {
|
|
411
|
-
const
|
|
357
|
+
const ethCode = getEthAppErrorCode(err);
|
|
358
|
+
const lastStep = err && typeof err === "object" ? err._lastStep : void 0;
|
|
359
|
+
const ethMapped = ethCode ? mapEthAppError(ethCode, lastStep) : null;
|
|
412
360
|
const apduHex = ethMapped ? null : extractApduHex(err);
|
|
413
361
|
const chainMapped = apduHex ? mapSolanaAppError(apduHex) ?? mapTronAppError(apduHex) ?? mapBtcAppError(apduHex) : null;
|
|
414
362
|
code = ethMapped ?? chainMapped ?? import_hwk_adapter_core.HardwareErrorCode.UnknownError;
|
|
@@ -429,6 +377,9 @@ function isLedgerBleConnectionType(connectionType) {
|
|
|
429
377
|
function isLedgerBleDescriptor(connectionType, descriptor) {
|
|
430
378
|
return isLedgerBleConnectionType(connectionType) || isLedgerDmkBleTransport(descriptor.transport);
|
|
431
379
|
}
|
|
380
|
+
function isValidLedgerBleConnectId(connectId) {
|
|
381
|
+
return /^[0-9A-Fa-f]{4}$/.test(connectId ?? "");
|
|
382
|
+
}
|
|
432
383
|
|
|
433
384
|
// src/utils/sdkEventBus.ts
|
|
434
385
|
var listeners = /* @__PURE__ */ new Set();
|
|
@@ -589,15 +540,9 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
589
540
|
// ---------------------------------------------------------------------------
|
|
590
541
|
// Device management
|
|
591
542
|
// ---------------------------------------------------------------------------
|
|
592
|
-
async searchDevices(
|
|
593
|
-
if (options?.resetSession) {
|
|
594
|
-
this._doConnectAbortController?.abort();
|
|
595
|
-
this._sessions.clear();
|
|
596
|
-
this._connectingPromise = null;
|
|
597
|
-
this._doConnectAbortController = null;
|
|
598
|
-
this._btcHighIndexConfirmedThisSession = false;
|
|
599
|
-
}
|
|
543
|
+
async searchDevices() {
|
|
600
544
|
await this._ensureDevicePermission();
|
|
545
|
+
debugLog(`[LedgerAdapter] searchDevices() entry, cacheBefore=${this._discoveredDevices.size}`);
|
|
601
546
|
const devices = await this.connector.searchDevices();
|
|
602
547
|
this._discoveredDevices.clear();
|
|
603
548
|
for (const d of devices) {
|
|
@@ -628,6 +573,16 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
628
573
|
});
|
|
629
574
|
}
|
|
630
575
|
await this._ensureDevicePermission(connectId);
|
|
576
|
+
if (isLedgerBleConnectionType(this.connector.connectionType)) {
|
|
577
|
+
const fresh = (await this.searchDevices()).some((d) => d.connectId === connectId);
|
|
578
|
+
if (!fresh) {
|
|
579
|
+
const err = new Error(
|
|
580
|
+
"Ledger device is not currently advertising. Wake up and unlock the device, keep it nearby, then try again."
|
|
581
|
+
);
|
|
582
|
+
err._tag = ERROR_TAG.DeviceNotAdvertising;
|
|
583
|
+
throw err;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
631
586
|
const session = await this.connector.connect(connectId);
|
|
632
587
|
this._sessions.set(connectId, session.sessionId);
|
|
633
588
|
if (session.deviceInfo) {
|
|
@@ -777,11 +732,21 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
777
732
|
// Chain fingerprint
|
|
778
733
|
// ---------------------------------------------------------------------------
|
|
779
734
|
async getChainFingerprint(connectId, deviceId, chain) {
|
|
735
|
+
debugLog(
|
|
736
|
+
"[LedgerAdapter] getChainFingerprint called, chain:",
|
|
737
|
+
chain,
|
|
738
|
+
"connectId:",
|
|
739
|
+
connectId || "(empty)",
|
|
740
|
+
"sessions:",
|
|
741
|
+
this._sessions.size
|
|
742
|
+
);
|
|
743
|
+
debugLog("[LedgerAdapter] getChainFingerprint permission ok, computing fingerprint");
|
|
780
744
|
try {
|
|
781
745
|
const fingerprint = await this._computeChainFingerprint(
|
|
782
746
|
chain,
|
|
783
747
|
(method, params) => this.connectorCall(connectId, method, params, void 0, deviceId)
|
|
784
748
|
);
|
|
749
|
+
debugLog("[LedgerAdapter] getChainFingerprint result:", fingerprint?.substring(0, 20));
|
|
785
750
|
return (0, import_hwk_adapter_core2.success)(fingerprint);
|
|
786
751
|
} catch (err) {
|
|
787
752
|
debugError("[LedgerAdapter] getChainFingerprint error:", chain, err);
|
|
@@ -975,22 +940,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
975
940
|
// Bounded by MAX_DOCONNECT_CONFIRMS — after N Confirms with no progress,
|
|
976
941
|
// throw DeviceNotFound so the user is kicked out of the loop.
|
|
977
942
|
async _doConnect(internalSignal, targetConnectId) {
|
|
978
|
-
if (isLedgerBleConnectionType(this.connector.connectionType) && targetConnectId) {
|
|
979
|
-
try {
|
|
980
|
-
return await this._connectDeviceOrThrow(targetConnectId);
|
|
981
|
-
} catch (err) {
|
|
982
|
-
if (!isDeviceLockedError(err) && !isDeviceNotAdvertisingError(err) && !isDeviceDisconnectedError(err)) {
|
|
983
|
-
throw err;
|
|
984
|
-
}
|
|
985
|
-
this._discoveredDevices.delete(targetConnectId);
|
|
986
|
-
if (isDeviceDisconnectedError(err)) {
|
|
987
|
-
try {
|
|
988
|
-
this.connector.reset?.();
|
|
989
|
-
} catch {
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
943
|
let confirms = 0;
|
|
995
944
|
while (!internalSignal.aborted) {
|
|
996
945
|
this.emitter.emit("ui-event", {
|
|
@@ -1043,13 +992,9 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1043
992
|
(d) => d.connectId === targetConnectId || d.deviceId === targetConnectId
|
|
1044
993
|
);
|
|
1045
994
|
if (!target) {
|
|
1046
|
-
|
|
995
|
+
throw Object.assign(new Error(`Target Ledger unavailable: ${targetConnectId}`), {
|
|
1047
996
|
code: import_hwk_adapter_core2.HardwareErrorCode.DeviceNotFound
|
|
1048
997
|
});
|
|
1049
|
-
if (isLedgerBleConnectionType(this.connector.connectionType)) {
|
|
1050
|
-
err._tag = ERROR_TAG.DeviceNotAdvertising;
|
|
1051
|
-
}
|
|
1052
|
-
throw err;
|
|
1053
998
|
}
|
|
1054
999
|
return this._connectDeviceOrThrow(target.connectId);
|
|
1055
1000
|
}
|
|
@@ -1190,6 +1135,14 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1190
1135
|
}
|
|
1191
1136
|
const resolvedConnectId = await this.ensureConnected(connectId, signal);
|
|
1192
1137
|
const sessionId = this._sessions.get(resolvedConnectId);
|
|
1138
|
+
debugLog(
|
|
1139
|
+
"[LedgerAdapter] connectorCall resolved:",
|
|
1140
|
+
method,
|
|
1141
|
+
"resolvedConnectId:",
|
|
1142
|
+
resolvedConnectId,
|
|
1143
|
+
"sessionId:",
|
|
1144
|
+
sessionId
|
|
1145
|
+
);
|
|
1193
1146
|
if (!sessionId) {
|
|
1194
1147
|
throw Object.assign(new Error("Auto-connect succeeded but no session found"), {
|
|
1195
1148
|
_tag: ERROR_TAG.DeviceSessionNotFound
|
|
@@ -1232,39 +1185,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1232
1185
|
this.connector.reset?.();
|
|
1233
1186
|
} catch {
|
|
1234
1187
|
}
|
|
1235
|
-
|
|
1236
|
-
"[LedgerAdapter] stuck-app retry: method=",
|
|
1237
|
-
method,
|
|
1238
|
-
"delayMs=",
|
|
1239
|
-
_LedgerAdapter.STUCK_APP_RETRY_DELAY_MS,
|
|
1240
|
-
"_tag=",
|
|
1241
|
-
err?._tag
|
|
1242
|
-
);
|
|
1243
|
-
try {
|
|
1244
|
-
const retryResult = await this._retryAfterStuckApp(
|
|
1245
|
-
resolvedConnectId,
|
|
1246
|
-
method,
|
|
1247
|
-
effectiveParams,
|
|
1248
|
-
signal,
|
|
1249
|
-
err,
|
|
1250
|
-
fingerprint
|
|
1251
|
-
);
|
|
1252
|
-
debugLog("[LedgerAdapter] stuck-app retry succeeded: method=", method);
|
|
1253
|
-
return retryResult;
|
|
1254
|
-
} catch (retryErr) {
|
|
1255
|
-
if (signal.aborted) throw retryErr;
|
|
1256
|
-
if (isStuckAppStateError(retryErr)) {
|
|
1257
|
-
debugLog("[LedgerAdapter] stuck-app retry exhausted (2nd 6901): method=", method);
|
|
1258
|
-
throw err;
|
|
1259
|
-
}
|
|
1260
|
-
debugLog(
|
|
1261
|
-
"[LedgerAdapter] stuck-app retry threw non-stuck error: method=",
|
|
1262
|
-
method,
|
|
1263
|
-
"retryErrTag=",
|
|
1264
|
-
retryErr?._tag
|
|
1265
|
-
);
|
|
1266
|
-
throw retryErr;
|
|
1267
|
-
}
|
|
1188
|
+
throw err;
|
|
1268
1189
|
}
|
|
1269
1190
|
if (isDeviceLockedError(err) || isDeviceNotAdvertisingError(err) || isDeviceDisconnectedError(err)) {
|
|
1270
1191
|
let lastErr = err;
|
|
@@ -1338,54 +1259,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1338
1259
|
throw err;
|
|
1339
1260
|
}
|
|
1340
1261
|
}
|
|
1341
|
-
/**
|
|
1342
|
-
* Stuck-app recovery: pause for the device's UI transition, then retry once.
|
|
1343
|
-
*
|
|
1344
|
-
* Caller has already cleared the session + reset connector. We wait so Stax
|
|
1345
|
-
* finishes its post-CloseApp animation, then go through ensureConnected +
|
|
1346
|
-
* fingerprint check + call exactly once. Caller decides what to do on a
|
|
1347
|
-
* second stuck-app hit.
|
|
1348
|
-
*/
|
|
1349
|
-
async _retryAfterStuckApp(resolvedConnectId, method, params, signal, originalErr, fingerprint) {
|
|
1350
|
-
await this._sleepAbortable(_LedgerAdapter.STUCK_APP_RETRY_DELAY_MS, signal);
|
|
1351
|
-
const retryTargetConnectId = isLedgerBleConnectionType(this.connector.connectionType) ? resolvedConnectId : void 0;
|
|
1352
|
-
const retryConnectId = await this.ensureConnected(retryTargetConnectId, signal);
|
|
1353
|
-
const retrySessionId = this._sessions.get(retryConnectId);
|
|
1354
|
-
if (!retrySessionId) throw originalErr;
|
|
1355
|
-
if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId) {
|
|
1356
|
-
const fp = await this._abortable(
|
|
1357
|
-
signal,
|
|
1358
|
-
this._verifyDeviceFingerprintWithSession(
|
|
1359
|
-
retrySessionId,
|
|
1360
|
-
fingerprint.deviceId,
|
|
1361
|
-
fingerprint.chain
|
|
1362
|
-
)
|
|
1363
|
-
);
|
|
1364
|
-
if (!fp.success) {
|
|
1365
|
-
throw Object.assign(new Error(formatDeviceMismatchError(fp.expected, fp.actual)), {
|
|
1366
|
-
code: import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch
|
|
1367
|
-
});
|
|
1368
|
-
}
|
|
1369
|
-
}
|
|
1370
|
-
return this._abortable(signal, this.connector.call(retrySessionId, method, params));
|
|
1371
|
-
}
|
|
1372
|
-
_sleepAbortable(ms, signal) {
|
|
1373
|
-
return new Promise((resolve, reject) => {
|
|
1374
|
-
if (signal.aborted) {
|
|
1375
|
-
reject(signal.reason ?? new Error("Aborted"));
|
|
1376
|
-
return;
|
|
1377
|
-
}
|
|
1378
|
-
const timer = setTimeout(() => {
|
|
1379
|
-
signal.removeEventListener("abort", onAbort);
|
|
1380
|
-
resolve();
|
|
1381
|
-
}, ms);
|
|
1382
|
-
const onAbort = () => {
|
|
1383
|
-
clearTimeout(timer);
|
|
1384
|
-
reject(signal.reason ?? new Error("Aborted"));
|
|
1385
|
-
};
|
|
1386
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
1387
|
-
});
|
|
1388
|
-
}
|
|
1389
1262
|
/**
|
|
1390
1263
|
* Clear stale session, reconnect, and retry the call.
|
|
1391
1264
|
*
|
|
@@ -1547,18 +1420,15 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1547
1420
|
// Device info mapping
|
|
1548
1421
|
// ---------------------------------------------------------------------------
|
|
1549
1422
|
connectorDeviceToDeviceInfo(device) {
|
|
1423
|
+
const isBle = device.connectId && /^[0-9A-Fa-f]{4}$/.test(device.connectId);
|
|
1550
1424
|
return {
|
|
1551
1425
|
vendor: "ledger",
|
|
1552
1426
|
model: device.model ?? "unknown",
|
|
1553
|
-
modelName: device.modelName,
|
|
1554
1427
|
firmwareVersion: "",
|
|
1555
1428
|
deviceId: device.deviceId,
|
|
1556
1429
|
connectId: device.connectId,
|
|
1557
1430
|
label: device.name,
|
|
1558
|
-
connectionType:
|
|
1559
|
-
rssi: device.rssi,
|
|
1560
|
-
isConnectable: device.isConnectable,
|
|
1561
|
-
serialNumber: device.serialNumber,
|
|
1431
|
+
connectionType: isBle ? "ble" : "usb",
|
|
1562
1432
|
capabilities: device.capabilities
|
|
1563
1433
|
};
|
|
1564
1434
|
}
|
|
@@ -1566,10 +1436,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1566
1436
|
// Layer 2 retry budget after connection-class error. Each round delegates
|
|
1567
1437
|
// to Layer 1 (which owns the unlock prompt). Layer 2 never emits UI itself.
|
|
1568
1438
|
_LedgerAdapter.MAX_BUSINESS_RETRY_BUDGET = 3;
|
|
1569
|
-
// Stuck-app (APDU 0x6901) retry pause. Ledger Stax often returns 6901 when
|
|
1570
|
-
// OpenAppCommand lands mid-transition right after CloseApp; a short wait
|
|
1571
|
-
// lets the device finish its UI animation before we retry once.
|
|
1572
|
-
_LedgerAdapter.STUCK_APP_RETRY_DELAY_MS = 500;
|
|
1573
1439
|
// Layer 1 confirm budget. After N failed Confirm cycles (user keeps clicking
|
|
1574
1440
|
// Confirm but device never shows up / never unlocks), throw DeviceNotFound
|
|
1575
1441
|
// instead of looping forever.
|
|
@@ -1577,7 +1443,7 @@ _LedgerAdapter.MAX_DOCONNECT_CONFIRMS = 3;
|
|
|
1577
1443
|
var LedgerAdapter = _LedgerAdapter;
|
|
1578
1444
|
|
|
1579
1445
|
// src/connector/LedgerConnectorBase.ts
|
|
1580
|
-
var
|
|
1446
|
+
var import_hwk_adapter_core11 = require("@onekeyfe/hwk-adapter-core");
|
|
1581
1447
|
|
|
1582
1448
|
// src/device/LedgerDeviceManager.ts
|
|
1583
1449
|
var LedgerDeviceManager = class {
|
|
@@ -1616,7 +1482,7 @@ var LedgerDeviceManager = class {
|
|
|
1616
1482
|
resolved = true;
|
|
1617
1483
|
this._discovered.clear();
|
|
1618
1484
|
debugLog(
|
|
1619
|
-
`[DMK] enumerate count=${devices.length} ids=[${devices.map((d) => d.id).join(",")}]`
|
|
1485
|
+
`[DMK] enumerate raw count=${devices.length} ids=[${devices.map((d) => d.id).join(",")}]`
|
|
1620
1486
|
);
|
|
1621
1487
|
for (const d of devices) {
|
|
1622
1488
|
this._discovered.set(d.id, d);
|
|
@@ -1627,7 +1493,6 @@ var LedgerDeviceManager = class {
|
|
|
1627
1493
|
devices.map((d) => ({
|
|
1628
1494
|
path: d.id,
|
|
1629
1495
|
type: d.deviceModel.model,
|
|
1630
|
-
modelName: d.deviceModel.name,
|
|
1631
1496
|
name: d.name,
|
|
1632
1497
|
transport: d.transport,
|
|
1633
1498
|
rssi: d.rssi
|
|
@@ -1651,7 +1516,6 @@ var LedgerDeviceManager = class {
|
|
|
1651
1516
|
devices.map((d) => ({
|
|
1652
1517
|
path: d.id,
|
|
1653
1518
|
type: d.deviceModel.model,
|
|
1654
|
-
modelName: d.deviceModel.name,
|
|
1655
1519
|
name: d.name,
|
|
1656
1520
|
transport: d.transport,
|
|
1657
1521
|
rssi: d.rssi
|
|
@@ -1678,7 +1542,6 @@ var LedgerDeviceManager = class {
|
|
|
1678
1542
|
descriptor: {
|
|
1679
1543
|
path: d.id,
|
|
1680
1544
|
type: d.deviceModel.model,
|
|
1681
|
-
modelName: d.deviceModel.name,
|
|
1682
1545
|
name: d.name,
|
|
1683
1546
|
transport: d.transport,
|
|
1684
1547
|
rssi: d.rssi
|
|
@@ -1769,29 +1632,11 @@ var LedgerDeviceManager = class {
|
|
|
1769
1632
|
getDeviceName(deviceId) {
|
|
1770
1633
|
return this._discovered.get(deviceId)?.name;
|
|
1771
1634
|
}
|
|
1772
|
-
/** Lookup minimal model/signal info from a previously-discovered device. */
|
|
1773
|
-
getDiscoveredDeviceInfo(deviceId) {
|
|
1774
|
-
const d = this._discovered.get(deviceId);
|
|
1775
|
-
if (!d) return void 0;
|
|
1776
|
-
return {
|
|
1777
|
-
model: d.deviceModel?.model,
|
|
1778
|
-
modelName: d.deviceModel?.name,
|
|
1779
|
-
name: d.name,
|
|
1780
|
-
rssi: d.rssi
|
|
1781
|
-
};
|
|
1782
|
-
}
|
|
1783
|
-
hasDiscoveredDevice(deviceId) {
|
|
1784
|
-
return this._discovered.has(deviceId);
|
|
1785
|
-
}
|
|
1786
1635
|
/** Connect to a previously discovered device. Returns sessionId. */
|
|
1787
1636
|
async connect(deviceId) {
|
|
1788
1637
|
const device = this._discovered.get(deviceId);
|
|
1789
1638
|
if (!device) {
|
|
1790
|
-
|
|
1791
|
-
`Device "${deviceId}" not found in discovery cache. Call enumerate() or listen() first.`
|
|
1792
|
-
);
|
|
1793
|
-
err._tag = ERROR_TAG.DeviceNotInDiscoveryCache;
|
|
1794
|
-
throw err;
|
|
1639
|
+
throw new Error(`Device "${deviceId}" not found. Call enumerate() or listen() first.`);
|
|
1795
1640
|
}
|
|
1796
1641
|
const sessionId = await this._dmk.connect({ device });
|
|
1797
1642
|
this._sessions.set(deviceId, sessionId);
|
|
@@ -1859,7 +1704,6 @@ function deviceActionToPromise(action, onInteraction, timeoutMs = IDLE_WATCHDOG_
|
|
|
1859
1704
|
return new Promise((resolve, reject) => {
|
|
1860
1705
|
let settled = false;
|
|
1861
1706
|
let lastStep;
|
|
1862
|
-
const observedSteps = [];
|
|
1863
1707
|
let sub;
|
|
1864
1708
|
let timer = null;
|
|
1865
1709
|
const cancelAction = () => {
|
|
@@ -1919,12 +1763,7 @@ function deviceActionToPromise(action, onInteraction, timeoutMs = IDLE_WATCHDOG_
|
|
|
1919
1763
|
}
|
|
1920
1764
|
armIdleWatchdog();
|
|
1921
1765
|
const step = state?.intermediateValue?.step;
|
|
1922
|
-
if (step)
|
|
1923
|
-
lastStep = step;
|
|
1924
|
-
if (observedSteps[observedSteps.length - 1] !== step) {
|
|
1925
|
-
observedSteps.push(step);
|
|
1926
|
-
}
|
|
1927
|
-
}
|
|
1766
|
+
if (step) lastStep = step;
|
|
1928
1767
|
if (state.status === import_device_management_kit.DeviceActionStatus.Completed) {
|
|
1929
1768
|
settled = true;
|
|
1930
1769
|
if (timer) clearTimeout(timer);
|
|
@@ -1936,7 +1775,7 @@ function deviceActionToPromise(action, onInteraction, timeoutMs = IDLE_WATCHDOG_
|
|
|
1936
1775
|
if (timer) clearTimeout(timer);
|
|
1937
1776
|
onInteraction?.("interaction-complete");
|
|
1938
1777
|
sub?.unsubscribe();
|
|
1939
|
-
|
|
1778
|
+
rejectWithLastStep(state.error, lastStep, reject);
|
|
1940
1779
|
} else if (state.status === import_device_management_kit.DeviceActionStatus.Pending && onInteraction) {
|
|
1941
1780
|
const interaction = state.intermediateValue?.requiredUserInteraction;
|
|
1942
1781
|
if (interaction && interaction !== "none") {
|
|
@@ -1953,7 +1792,7 @@ function deviceActionToPromise(action, onInteraction, timeoutMs = IDLE_WATCHDOG_
|
|
|
1953
1792
|
settled = true;
|
|
1954
1793
|
if (timer) clearTimeout(timer);
|
|
1955
1794
|
sub?.unsubscribe();
|
|
1956
|
-
|
|
1795
|
+
rejectWithLastStep(err, lastStep, reject);
|
|
1957
1796
|
}
|
|
1958
1797
|
},
|
|
1959
1798
|
complete: () => {
|
|
@@ -1966,25 +1805,15 @@ function deviceActionToPromise(action, onInteraction, timeoutMs = IDLE_WATCHDOG_
|
|
|
1966
1805
|
});
|
|
1967
1806
|
});
|
|
1968
1807
|
}
|
|
1969
|
-
function
|
|
1970
|
-
if (err && typeof err === "object" &&
|
|
1808
|
+
function rejectWithLastStep(err, lastStep, reject) {
|
|
1809
|
+
if (err && typeof err === "object" && lastStep) {
|
|
1971
1810
|
try {
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
});
|
|
1979
|
-
}
|
|
1980
|
-
if (observedSteps.length > 0) {
|
|
1981
|
-
Object.defineProperty(err, "_deviceActionSteps", {
|
|
1982
|
-
value: [...observedSteps],
|
|
1983
|
-
configurable: true,
|
|
1984
|
-
enumerable: false,
|
|
1985
|
-
writable: true
|
|
1986
|
-
});
|
|
1987
|
-
}
|
|
1811
|
+
Object.defineProperty(err, "_lastStep", {
|
|
1812
|
+
value: lastStep,
|
|
1813
|
+
configurable: true,
|
|
1814
|
+
enumerable: false,
|
|
1815
|
+
writable: true
|
|
1816
|
+
});
|
|
1988
1817
|
} catch {
|
|
1989
1818
|
}
|
|
1990
1819
|
}
|
|
@@ -2050,8 +1879,7 @@ var SignerManager = class _SignerManager {
|
|
|
2050
1879
|
async getOrCreate(sessionId) {
|
|
2051
1880
|
debugLog("[DMK] SignerManager.getOrCreate:", { sessionId });
|
|
2052
1881
|
const builder = await this._builderFn({ dmk: this._dmk, sessionId });
|
|
2053
|
-
|
|
2054
|
-
return new SignerEth(builderWithContext.build());
|
|
1882
|
+
return new SignerEth(builder.build());
|
|
2055
1883
|
}
|
|
2056
1884
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars, class-methods-use-this
|
|
2057
1885
|
invalidate(_sessionId) {
|
|
@@ -2060,24 +1888,10 @@ var SignerManager = class _SignerManager {
|
|
|
2060
1888
|
clearAll() {
|
|
2061
1889
|
}
|
|
2062
1890
|
static _defaultBuilder() {
|
|
2063
|
-
return (args) =>
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
const contextModule = new import_context_module.ContextModuleBuilder({}).removeDefaultLoaders().build();
|
|
2067
|
-
return _SignerManager.wrapBlindSigningReportNonBlocking(contextModule);
|
|
2068
|
-
}
|
|
2069
|
-
static wrapBlindSigningReportNonBlocking(contextModule) {
|
|
2070
|
-
const report = contextModule.report.bind(contextModule);
|
|
2071
|
-
contextModule.report = async (params) => {
|
|
2072
|
-
try {
|
|
2073
|
-
void report(params).catch((err) => {
|
|
2074
|
-
debugLog("[DMK] ContextModule.report failed:", err);
|
|
2075
|
-
});
|
|
2076
|
-
} catch (err) {
|
|
2077
|
-
debugLog("[DMK] ContextModule.report failed:", err);
|
|
2078
|
-
}
|
|
1891
|
+
return (args) => {
|
|
1892
|
+
const contextModule = new import_context_module.ContextModuleBuilder({}).removeDefaultLoaders().build();
|
|
1893
|
+
return new import_device_signer_kit_ethereum.SignerEthBuilder(args).withContextModule(contextModule);
|
|
2079
1894
|
};
|
|
2080
|
-
return contextModule;
|
|
2081
1895
|
}
|
|
2082
1896
|
};
|
|
2083
1897
|
|
|
@@ -2647,15 +2461,14 @@ async function _createSolSigner(ctx, sessionId) {
|
|
|
2647
2461
|
}
|
|
2648
2462
|
|
|
2649
2463
|
// src/connector/chains/tron.ts
|
|
2650
|
-
var
|
|
2464
|
+
var import_hwk_adapter_core10 = require("@onekeyfe/hwk-adapter-core");
|
|
2651
2465
|
var import_hw_app_trx = __toESM(require("@ledgerhq/hw-app-trx"));
|
|
2652
2466
|
|
|
2653
2467
|
// src/connector/chains/legacyChainCall.ts
|
|
2654
|
-
var
|
|
2468
|
+
var import_hwk_adapter_core9 = require("@onekeyfe/hwk-adapter-core");
|
|
2655
2469
|
|
|
2656
2470
|
// src/app/AppManager.ts
|
|
2657
2471
|
var import_device_management_kit2 = require("@ledgerhq/device-management-kit");
|
|
2658
|
-
var import_hwk_adapter_core9 = require("@onekeyfe/hwk-adapter-core");
|
|
2659
2472
|
var APP_NAME_MAP = {
|
|
2660
2473
|
ETH: "Ethereum",
|
|
2661
2474
|
BTC: "Bitcoin",
|
|
@@ -2760,11 +2573,9 @@ var AppManager = class {
|
|
|
2760
2573
|
});
|
|
2761
2574
|
if (!(0, import_device_management_kit2.isSuccessCommandResult)(result)) {
|
|
2762
2575
|
const { statusCode } = result;
|
|
2763
|
-
const hasStatusCode2 = statusCode != null && statusCode !== "";
|
|
2764
2576
|
debugLog("[AppManager] openApp failed:", appName, "statusCode:", statusCode);
|
|
2765
2577
|
throw Object.assign(new Error(`Failed to open "${appName}"`), {
|
|
2766
2578
|
_tag: ERROR_TAG.OpenAppCommand,
|
|
2767
|
-
code: hasStatusCode2 ? void 0 : import_hwk_adapter_core9.HardwareErrorCode.AppNotInstalled,
|
|
2768
2579
|
errorCode: String(statusCode ?? ""),
|
|
2769
2580
|
statusCode,
|
|
2770
2581
|
appName
|
|
@@ -2820,14 +2631,14 @@ async function withLegacyChainCall(ctx, sessionId, options, action) {
|
|
|
2820
2631
|
const onAppOpenPrompt = () => {
|
|
2821
2632
|
openAppPromptShown = true;
|
|
2822
2633
|
ctx.emit("ui-event", {
|
|
2823
|
-
type:
|
|
2634
|
+
type: import_hwk_adapter_core9.EConnectorInteraction.ConfirmOpenApp,
|
|
2824
2635
|
payload: { sessionId }
|
|
2825
2636
|
});
|
|
2826
2637
|
};
|
|
2827
2638
|
const closeOpenAppUiIfShown = () => {
|
|
2828
2639
|
if (openAppPromptShown) {
|
|
2829
2640
|
ctx.emit("ui-event", {
|
|
2830
|
-
type:
|
|
2641
|
+
type: import_hwk_adapter_core9.EConnectorInteraction.InteractionComplete,
|
|
2831
2642
|
payload: { sessionId }
|
|
2832
2643
|
});
|
|
2833
2644
|
openAppPromptShown = false;
|
|
@@ -2848,7 +2659,7 @@ async function withLegacyChainCall(ctx, sessionId, options, action) {
|
|
|
2848
2659
|
let confirmEmitted = false;
|
|
2849
2660
|
if (needsConfirmation) {
|
|
2850
2661
|
ctx.emit("ui-event", {
|
|
2851
|
-
type:
|
|
2662
|
+
type: import_hwk_adapter_core9.EConnectorInteraction.ConfirmOnDevice,
|
|
2852
2663
|
payload: { sessionId }
|
|
2853
2664
|
});
|
|
2854
2665
|
confirmEmitted = true;
|
|
@@ -2858,7 +2669,7 @@ async function withLegacyChainCall(ctx, sessionId, options, action) {
|
|
|
2858
2669
|
} finally {
|
|
2859
2670
|
if (confirmEmitted || openAppPromptShown) {
|
|
2860
2671
|
ctx.emit("ui-event", {
|
|
2861
|
-
type:
|
|
2672
|
+
type: import_hwk_adapter_core9.EConnectorInteraction.InteractionComplete,
|
|
2862
2673
|
payload: { sessionId }
|
|
2863
2674
|
});
|
|
2864
2675
|
openAppPromptShown = false;
|
|
@@ -2946,7 +2757,7 @@ async function tronSignTransaction(ctx, sessionId, params) {
|
|
|
2946
2757
|
if (!params.rawTxHex) {
|
|
2947
2758
|
throw Object.assign(
|
|
2948
2759
|
new Error("TRON signing requires a protobuf-encoded raw transaction hex (rawTxHex)."),
|
|
2949
|
-
{ code:
|
|
2760
|
+
{ code: import_hwk_adapter_core10.HardwareErrorCode.InvalidParams }
|
|
2950
2761
|
);
|
|
2951
2762
|
}
|
|
2952
2763
|
const path = normalizePath(params.path);
|
|
@@ -2990,10 +2801,6 @@ var METHOD_PREFIX_TO_APP_NAME = {
|
|
|
2990
2801
|
sol: "Solana",
|
|
2991
2802
|
tron: "Tron"
|
|
2992
2803
|
};
|
|
2993
|
-
var HARDWARE_ERROR_CODE_VALUES = new Set(
|
|
2994
|
-
Object.values(import_hwk_adapter_core12.HardwareErrorCode).filter((value) => typeof value === "number")
|
|
2995
|
-
);
|
|
2996
|
-
var BLE_CONNECT_SCAN_TIMEOUT_MS = 1500;
|
|
2997
2804
|
async function defaultLedgerKitImporter(pkg) {
|
|
2998
2805
|
switch (pkg) {
|
|
2999
2806
|
case "@ledgerhq/device-management-kit":
|
|
@@ -3017,6 +2824,16 @@ var LedgerConnectorBase = class {
|
|
|
3017
2824
|
this._dmk = null;
|
|
3018
2825
|
this._eventHandlers = /* @__PURE__ */ new Map();
|
|
3019
2826
|
// ---------------------------------------------------------------------------
|
|
2827
|
+
// ConnectId <-> DMK path mapping
|
|
2828
|
+
//
|
|
2829
|
+
// DMK uses internal paths (BLE MAC, USB UUID) that may change across sessions.
|
|
2830
|
+
// _resolveConnectId() maps these to stable external IDs (BLE: "A58F", USB: same).
|
|
2831
|
+
// This bidirectional map is the SINGLE SOURCE OF TRUTH for all connectId usage.
|
|
2832
|
+
// ---------------------------------------------------------------------------
|
|
2833
|
+
this._connectIdToPath = /* @__PURE__ */ new Map();
|
|
2834
|
+
// "A58F" -> "D5:75:7D:4B:51:E8"
|
|
2835
|
+
this._pathToConnectId = /* @__PURE__ */ new Map();
|
|
2836
|
+
// ---------------------------------------------------------------------------
|
|
3020
2837
|
// Per-session DeviceAction cancellers
|
|
3021
2838
|
//
|
|
3022
2839
|
// Each chain handler registers its active DeviceAction's canceller via
|
|
@@ -3041,7 +2858,6 @@ var LedgerConnectorBase = class {
|
|
|
3041
2858
|
this.connectionType = options?.connectionType ?? "usb";
|
|
3042
2859
|
this._providedDmk = options?.dmk;
|
|
3043
2860
|
this._importLedgerKit = options?.importLedgerKit ?? defaultLedgerKitImporter;
|
|
3044
|
-
this._requirePreFlightScan = options?.requirePreFlightScan ?? false;
|
|
3045
2861
|
if (this._providedDmk) {
|
|
3046
2862
|
this._initManagers(this._providedDmk);
|
|
3047
2863
|
}
|
|
@@ -3059,13 +2875,22 @@ var LedgerConnectorBase = class {
|
|
|
3059
2875
|
importLedgerKit: this._importLedgerKit
|
|
3060
2876
|
};
|
|
3061
2877
|
}
|
|
2878
|
+
// "D5:75:7D:4B:51:E8" -> "A58F"
|
|
2879
|
+
/** Get DMK path from external connectId. Falls back to connectId itself. */
|
|
2880
|
+
_getPathForConnectId(connectId) {
|
|
2881
|
+
return this._connectIdToPath.get(connectId) ?? connectId;
|
|
2882
|
+
}
|
|
2883
|
+
/** Get external connectId from DMK path. Falls back to path itself. */
|
|
2884
|
+
_getConnectIdForPath(path) {
|
|
2885
|
+
return this._pathToConnectId.get(path) ?? path;
|
|
2886
|
+
}
|
|
3062
2887
|
// ---------------------------------------------------------------------------
|
|
3063
2888
|
// Protected — hooks for subclasses
|
|
3064
2889
|
// ---------------------------------------------------------------------------
|
|
3065
2890
|
/**
|
|
3066
2891
|
* Resolve the connectId for a discovered device descriptor.
|
|
3067
2892
|
* Default: use the DMK path (ephemeral UUID).
|
|
3068
|
-
* Override in subclasses
|
|
2893
|
+
* Override in subclasses to extract stable identifiers (e.g. BLE hex ID).
|
|
3069
2894
|
*/
|
|
3070
2895
|
_resolveConnectId(descriptor) {
|
|
3071
2896
|
return descriptor.path;
|
|
@@ -3090,22 +2915,50 @@ var LedgerConnectorBase = class {
|
|
|
3090
2915
|
// IConnector -- Device discovery
|
|
3091
2916
|
// ---------------------------------------------------------------------------
|
|
3092
2917
|
async searchDevices() {
|
|
2918
|
+
debugLog("[DMK] connector.searchDevices() entry");
|
|
3093
2919
|
const dm = await this._getDeviceManager();
|
|
3094
2920
|
const descriptors = await this._discoverDescriptors(dm);
|
|
3095
2921
|
const resolvedDescriptors = descriptors.map((d) => ({
|
|
3096
2922
|
descriptor: d,
|
|
3097
2923
|
connectId: this._resolveConnectId(d)
|
|
3098
2924
|
}));
|
|
3099
|
-
const
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
2925
|
+
const bleConnectIdCounts = /* @__PURE__ */ new Map();
|
|
2926
|
+
for (const item of resolvedDescriptors) {
|
|
2927
|
+
if (isLedgerBleDescriptor(this.connectionType, item.descriptor)) {
|
|
2928
|
+
if (!isValidLedgerBleConnectId(item.connectId)) {
|
|
2929
|
+
debugLog(`[DMK] connector.searchDevices() invalid BLE connectId=${item.connectId}`);
|
|
2930
|
+
throw Object.assign(
|
|
2931
|
+
new Error("Ledger BLE connectId must be the 4-character BLE identifier"),
|
|
2932
|
+
{ code: import_hwk_adapter_core11.HardwareErrorCode.DeviceNotFound }
|
|
2933
|
+
);
|
|
2934
|
+
}
|
|
2935
|
+
bleConnectIdCounts.set(item.connectId, (bleConnectIdCounts.get(item.connectId) ?? 0) + 1);
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2938
|
+
const duplicateBleConnectId = Array.from(bleConnectIdCounts.entries()).find(
|
|
2939
|
+
([, count]) => count > 1
|
|
2940
|
+
)?.[0];
|
|
2941
|
+
if (duplicateBleConnectId) {
|
|
2942
|
+
debugLog(
|
|
2943
|
+
`[DMK] connector.searchDevices() duplicate BLE connectId=${duplicateBleConnectId} counts=${JSON.stringify(
|
|
2944
|
+
Array.from(bleConnectIdCounts.entries())
|
|
2945
|
+
)}`
|
|
2946
|
+
);
|
|
2947
|
+
throw Object.assign(
|
|
2948
|
+
new Error(`Duplicate Ledger BLE connectId detected: ${duplicateBleConnectId}`),
|
|
2949
|
+
{ code: import_hwk_adapter_core11.HardwareErrorCode.DeviceNotFound }
|
|
2950
|
+
);
|
|
2951
|
+
}
|
|
2952
|
+
const result = resolvedDescriptors.map(({ descriptor: d, connectId }) => {
|
|
2953
|
+
this._connectIdToPath.set(connectId, d.path);
|
|
2954
|
+
this._pathToConnectId.set(d.path, connectId);
|
|
2955
|
+
return {
|
|
2956
|
+
connectId,
|
|
2957
|
+
deviceId: d.path,
|
|
2958
|
+
name: d.name || d.type || "Ledger",
|
|
2959
|
+
model: d.type
|
|
2960
|
+
};
|
|
2961
|
+
});
|
|
3109
2962
|
debugLog(
|
|
3110
2963
|
`[DMK] connector.searchDevices() return count=${result.length} ids=[${result.map((r) => r.connectId).join(",")}] paths=[${result.map((r) => r.deviceId).join(",")}]`
|
|
3111
2964
|
);
|
|
@@ -3115,8 +2968,7 @@ var LedgerConnectorBase = class {
|
|
|
3115
2968
|
// IConnector -- Connection
|
|
3116
2969
|
// ---------------------------------------------------------------------------
|
|
3117
2970
|
async connect(deviceId) {
|
|
3118
|
-
|
|
3119
|
-
let targetPath = deviceId;
|
|
2971
|
+
let targetPath = deviceId ? this._getPathForConnectId(deviceId) : void 0;
|
|
3120
2972
|
if (!targetPath) {
|
|
3121
2973
|
const discovered = await this.searchDevices();
|
|
3122
2974
|
if (discovered.length === 0) {
|
|
@@ -3126,7 +2978,7 @@ var LedgerConnectorBase = class {
|
|
|
3126
2978
|
}
|
|
3127
2979
|
targetPath = discovered[0].deviceId;
|
|
3128
2980
|
}
|
|
3129
|
-
const externalConnectId = targetPath;
|
|
2981
|
+
const externalConnectId = this._getConnectIdForPath(targetPath);
|
|
3130
2982
|
const HANG_CEILING_MS = 5 * 6e4;
|
|
3131
2983
|
const dmConnectWithObserve = async (dm, path) => {
|
|
3132
2984
|
if (!isLedgerBleConnectionType(this.connectionType)) return dm.connect(path);
|
|
@@ -3140,7 +2992,7 @@ var LedgerConnectorBase = class {
|
|
|
3140
2992
|
`Ledger BLE connect did not return within ${HANG_CEILING_MS / 6e4}min \u2014 DMK hang fallback.`
|
|
3141
2993
|
);
|
|
3142
2994
|
err._tag = ERROR_TAG.BlePairingTimeout;
|
|
3143
|
-
err.code =
|
|
2995
|
+
err.code = import_hwk_adapter_core11.HardwareErrorCode.BlePairingTimeout;
|
|
3144
2996
|
reject(err);
|
|
3145
2997
|
}, HANG_CEILING_MS);
|
|
3146
2998
|
});
|
|
@@ -3167,45 +3019,19 @@ var LedgerConnectorBase = class {
|
|
|
3167
3019
|
if (timeoutId) clearTimeout(timeoutId);
|
|
3168
3020
|
}
|
|
3169
3021
|
};
|
|
3170
|
-
const isBleDirectConnect = isLedgerBleConnectionType(this.connectionType) && callerSuppliedConnectId;
|
|
3171
|
-
const throwNotAdvertising = () => {
|
|
3172
|
-
const err = new Error(
|
|
3173
|
-
"Ledger device is not currently advertising. Wake up and unlock the device, keep it nearby, then try again."
|
|
3174
|
-
);
|
|
3175
|
-
err._tag = ERROR_TAG.DeviceNotAdvertising;
|
|
3176
|
-
err.code = import_hwk_adapter_core12.HardwareErrorCode.DeviceNotFound;
|
|
3177
|
-
throw err;
|
|
3178
|
-
};
|
|
3179
3022
|
const doConnect = async (path) => {
|
|
3180
3023
|
const dm = await this._getDeviceManager();
|
|
3181
|
-
|
|
3182
|
-
const live = await dm.getLiveDevices(BLE_CONNECT_SCAN_TIMEOUT_MS);
|
|
3183
|
-
if (this._requirePreFlightScan && !live.some((d) => d.id === path)) {
|
|
3184
|
-
throwNotAdvertising();
|
|
3185
|
-
}
|
|
3186
|
-
}
|
|
3187
|
-
let sessionId;
|
|
3188
|
-
try {
|
|
3189
|
-
sessionId = await dmConnectWithObserve(dm, path);
|
|
3190
|
-
} catch (err) {
|
|
3191
|
-
if (isBleDirectConnect && err?._tag === ERROR_TAG.DeviceNotInDiscoveryCache) {
|
|
3192
|
-
throwNotAdvertising();
|
|
3193
|
-
}
|
|
3194
|
-
throw err;
|
|
3195
|
-
}
|
|
3024
|
+
const sessionId = await dmConnectWithObserve(dm, path);
|
|
3196
3025
|
this._watchSessionState(sessionId, externalConnectId);
|
|
3197
|
-
const info = dm.getDiscoveredDeviceInfo(path);
|
|
3198
3026
|
const session = {
|
|
3199
3027
|
sessionId,
|
|
3200
3028
|
deviceInfo: {
|
|
3201
3029
|
vendor: "ledger",
|
|
3202
|
-
model:
|
|
3203
|
-
modelName: info?.modelName,
|
|
3030
|
+
model: "unknown",
|
|
3204
3031
|
firmwareVersion: "unknown",
|
|
3205
3032
|
deviceId: path,
|
|
3206
3033
|
connectId: externalConnectId,
|
|
3207
3034
|
connectionType: this.connectionType,
|
|
3208
|
-
rssi: info?.rssi,
|
|
3209
3035
|
capabilities: { persistentDeviceIdentity: false }
|
|
3210
3036
|
}
|
|
3211
3037
|
};
|
|
@@ -3228,7 +3054,7 @@ var LedgerConnectorBase = class {
|
|
|
3228
3054
|
"Ledger Bluetooth pairing failed. Make sure the device is unlocked and nearby, then try again."
|
|
3229
3055
|
);
|
|
3230
3056
|
wrapped._tag = ERROR_TAG.BleGattBondingFailed;
|
|
3231
|
-
wrapped.code =
|
|
3057
|
+
wrapped.code = import_hwk_adapter_core11.HardwareErrorCode.BlePairingTimeout;
|
|
3232
3058
|
wrapped.originalError = err;
|
|
3233
3059
|
throw wrapped;
|
|
3234
3060
|
}
|
|
@@ -3311,7 +3137,7 @@ var LedgerConnectorBase = class {
|
|
|
3311
3137
|
this._unwatchSessionState(sessionId);
|
|
3312
3138
|
this._signerManager?.invalidate(sessionId);
|
|
3313
3139
|
this._cancellers.get(sessionId)?.({
|
|
3314
|
-
code:
|
|
3140
|
+
code: import_hwk_adapter_core11.HardwareErrorCode.DeviceDisconnected,
|
|
3315
3141
|
tag: "DeviceDisconnected",
|
|
3316
3142
|
message: "Device disconnected"
|
|
3317
3143
|
});
|
|
@@ -3328,14 +3154,14 @@ var LedgerConnectorBase = class {
|
|
|
3328
3154
|
} catch (err) {
|
|
3329
3155
|
if (isAppStuckByApdu(err)) {
|
|
3330
3156
|
throw Object.assign(new Error("Ledger app is unresponsive"), {
|
|
3331
|
-
code:
|
|
3157
|
+
code: import_hwk_adapter_core11.HardwareErrorCode.DeviceAppStuck,
|
|
3332
3158
|
_tag: ERROR_TAG.DeviceAppStuck,
|
|
3333
3159
|
originalError: err
|
|
3334
3160
|
});
|
|
3335
3161
|
}
|
|
3336
3162
|
if (isTransportStuck(err)) {
|
|
3337
3163
|
throw Object.assign(new Error("Device communication interrupted, please retry"), {
|
|
3338
|
-
code:
|
|
3164
|
+
code: import_hwk_adapter_core11.HardwareErrorCode.TransportError,
|
|
3339
3165
|
_tag: ERROR_TAG.DeviceTransportStuck,
|
|
3340
3166
|
originalError: err
|
|
3341
3167
|
});
|
|
@@ -3483,13 +3309,14 @@ var LedgerConnectorBase = class {
|
|
|
3483
3309
|
}
|
|
3484
3310
|
/**
|
|
3485
3311
|
* Replace an old session with a new one after app switch.
|
|
3486
|
-
*
|
|
3312
|
+
* Updates the connectId→path mapping so subsequent calls() use the new session,
|
|
3313
|
+
* and emits device-connect so the adapter updates its _sessions Map.
|
|
3487
3314
|
*/
|
|
3488
3315
|
_replaceSession(oldSessionId, _newSessionId) {
|
|
3489
3316
|
const dm = this._deviceManager;
|
|
3490
3317
|
if (!dm) return;
|
|
3491
3318
|
const oldDeviceId = dm.getDeviceId(oldSessionId);
|
|
3492
|
-
const connectId = oldDeviceId;
|
|
3319
|
+
const connectId = oldDeviceId ? this._pathToConnectId.get(oldDeviceId) : void 0;
|
|
3493
3320
|
this._signerManager?.invalidate(oldSessionId);
|
|
3494
3321
|
if (connectId) {
|
|
3495
3322
|
this._emit("device-connect", {
|
|
@@ -3502,7 +3329,7 @@ var LedgerConnectorBase = class {
|
|
|
3502
3329
|
}
|
|
3503
3330
|
}
|
|
3504
3331
|
/**
|
|
3505
|
-
* Light reset: clear signer/session state but keep DMK alive.
|
|
3332
|
+
* Light reset: clear signer/session state but keep DMK and ID mapping alive.
|
|
3506
3333
|
* Used by connect() retry — we want to re-discover with the same transport.
|
|
3507
3334
|
*
|
|
3508
3335
|
* Note: drops the device manager but tears down its RxJS subs first via
|
|
@@ -3537,6 +3364,8 @@ var LedgerConnectorBase = class {
|
|
|
3537
3364
|
this._deviceManager = null;
|
|
3538
3365
|
this._signerManager = null;
|
|
3539
3366
|
this._dmk = null;
|
|
3367
|
+
this._connectIdToPath.clear();
|
|
3368
|
+
this._pathToConnectId.clear();
|
|
3540
3369
|
}
|
|
3541
3370
|
// ---------------------------------------------------------------------------
|
|
3542
3371
|
// Private -- Events
|
|
@@ -3570,21 +3399,15 @@ var LedgerConnectorBase = class {
|
|
|
3570
3399
|
};
|
|
3571
3400
|
}
|
|
3572
3401
|
_wrapError(err, opts) {
|
|
3402
|
+
const mapped = mapLedgerError(err, opts);
|
|
3573
3403
|
const src = err && typeof err === "object" ? err : {};
|
|
3574
|
-
const hasSerializedCode = typeof src.code === "number" && HARDWARE_ERROR_CODE_VALUES.has(src.code);
|
|
3575
|
-
const mapped = hasSerializedCode ? {
|
|
3576
|
-
code: src.code,
|
|
3577
|
-
message: typeof src.message === "string" ? src.message : "Unknown Ledger error",
|
|
3578
|
-
appName: typeof src.appName === "string" ? src.appName : opts?.defaultAppName
|
|
3579
|
-
} : mapLedgerError(err, opts);
|
|
3580
3404
|
const error = new Error(mapped.message);
|
|
3581
3405
|
Object.assign(error, {
|
|
3582
3406
|
code: mapped.code,
|
|
3583
3407
|
appName: mapped.appName,
|
|
3584
3408
|
_tag: src._tag,
|
|
3585
3409
|
errorCode: src.errorCode,
|
|
3586
|
-
_lastStep: src._lastStep
|
|
3587
|
-
_deviceActionSteps: src._deviceActionSteps
|
|
3410
|
+
_lastStep: src._lastStep
|
|
3588
3411
|
});
|
|
3589
3412
|
Object.defineProperty(error, "originalError", {
|
|
3590
3413
|
value: err,
|
|
@@ -3595,6 +3418,13 @@ var LedgerConnectorBase = class {
|
|
|
3595
3418
|
return error;
|
|
3596
3419
|
}
|
|
3597
3420
|
};
|
|
3421
|
+
|
|
3422
|
+
// src/utils/bleIdentity.ts
|
|
3423
|
+
function extractBleHexId(name) {
|
|
3424
|
+
if (!name) return void 0;
|
|
3425
|
+
const match = name.match(/\b([0-9A-Fa-f]{4})$/);
|
|
3426
|
+
return match ? match[1].toUpperCase() : void 0;
|
|
3427
|
+
}
|
|
3598
3428
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3599
3429
|
0 && (module.exports = {
|
|
3600
3430
|
AppManager,
|
|
@@ -3606,12 +3436,13 @@ var LedgerConnectorBase = class {
|
|
|
3606
3436
|
SignerEth,
|
|
3607
3437
|
SignerManager,
|
|
3608
3438
|
SignerSol,
|
|
3609
|
-
debugLog,
|
|
3610
3439
|
deviceActionToPromise,
|
|
3440
|
+
extractBleHexId,
|
|
3611
3441
|
isDeviceLockedError,
|
|
3612
3442
|
isLedgerBleConnectionType,
|
|
3613
3443
|
isLedgerBleDescriptor,
|
|
3614
3444
|
isLedgerDmkBleTransport,
|
|
3445
|
+
isValidLedgerBleConnectId,
|
|
3615
3446
|
ledgerFailure,
|
|
3616
3447
|
mapLedgerError,
|
|
3617
3448
|
offSdkEvent,
|