@onekeyfe/hwk-ledger-adapter 1.1.26-alpha.12 → 1.1.26-alpha.13
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 +20 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +247 -46
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +242 -41
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { IHardwareWallet, IConnector, TransportType, UiResponseEvent, DeviceInfo, Response, ChainCapability, EvmGetAddressParams, EvmAddress, EvmSignTxParams, EvmSignedTx, EvmSignMsgParams, EvmSignature, EvmSignTypedDataParams, BtcGetAddressParams, BtcAddress, BtcGetPublicKeyParams, BtcPublicKey, BtcSignTxParams, BtcSignedTx, BtcSignPsbtParams, BtcSignedPsbt, BtcSignMsgParams, BtcSignature, SolGetAddressParams, SolAddress, SolSignTxParams, SolSignedTx, SolSignMsgParams, SolSignature, TronGetAddressParams, TronAddress, TronSignTxParams, TronSignedTx, TronSignMsgParams, TronSignature, HardwareEventMap, DeviceEventListener, ChainForFingerprint, DeviceDescriptor, DeviceChangeEvent, ConnectionType, ConnectorDevice, ConnectorSession, ConnectorEventType, ConnectorEventMap, Failure, HardwareErrorCode } from '@onekeyfe/hwk-adapter-core';
|
|
2
2
|
import { DeviceActionState as DeviceActionState$1, DiscoveredDevice, ExecuteDeviceActionReturnType, DeviceManagementKit } from '@ledgerhq/device-management-kit';
|
|
3
3
|
import { Address, Signature, SignerEth as SignerEth$1, TypedData } from '@ledgerhq/device-signer-kit-ethereum';
|
|
4
|
+
import { ContextModule } from '@ledgerhq/context-module';
|
|
4
5
|
import { SignerBtc as SignerBtc$1 } from '@ledgerhq/device-signer-kit-bitcoin';
|
|
5
6
|
import { SignerSolana } from '@ledgerhq/device-signer-kit-solana';
|
|
6
7
|
import Transport from '@ledgerhq/hw-transport';
|
|
@@ -39,6 +40,7 @@ declare class LedgerAdapter implements IHardwareWallet {
|
|
|
39
40
|
uiResponse(response: UiResponseEvent): void;
|
|
40
41
|
searchDevices(): Promise<DeviceInfo[]>;
|
|
41
42
|
private static readonly MAX_BUSINESS_RETRY_BUDGET;
|
|
43
|
+
private static readonly STUCK_APP_RETRY_DELAY_MS;
|
|
42
44
|
private static readonly MAX_DOCONNECT_CONFIRMS;
|
|
43
45
|
private _lastCancelReason;
|
|
44
46
|
private static _createDeviceBusyError;
|
|
@@ -132,6 +134,16 @@ declare class LedgerAdapter implements IHardwareWallet {
|
|
|
132
134
|
private static _throwIfAborted;
|
|
133
135
|
/** Actual work done under the job queue — connection, fingerprint, call, and recovery. */
|
|
134
136
|
private _runConnectorCall;
|
|
137
|
+
/**
|
|
138
|
+
* Stuck-app recovery: pause for the device's UI transition, then retry once.
|
|
139
|
+
*
|
|
140
|
+
* Caller has already cleared the session + reset connector. We wait so Stax
|
|
141
|
+
* finishes its post-CloseApp animation, then go through ensureConnected +
|
|
142
|
+
* fingerprint check + call exactly once. Caller decides what to do on a
|
|
143
|
+
* second stuck-app hit.
|
|
144
|
+
*/
|
|
145
|
+
private _retryAfterStuckApp;
|
|
146
|
+
private _sleepAbortable;
|
|
135
147
|
/**
|
|
136
148
|
* Clear stale session, reconnect, and retry the call.
|
|
137
149
|
*
|
|
@@ -446,8 +458,14 @@ type SignerEthBuilderFn = (args: {
|
|
|
446
458
|
dmk: DeviceManagementKit;
|
|
447
459
|
sessionId: string;
|
|
448
460
|
}) => {
|
|
461
|
+
withContextModule?(contextModule: ContextModule): {
|
|
462
|
+
build(): SignerEth$1;
|
|
463
|
+
};
|
|
449
464
|
build(): SignerEth$1;
|
|
450
465
|
} | Promise<{
|
|
466
|
+
withContextModule?(contextModule: ContextModule): {
|
|
467
|
+
build(): SignerEth$1;
|
|
468
|
+
};
|
|
451
469
|
build(): SignerEth$1;
|
|
452
470
|
}>;
|
|
453
471
|
/**
|
|
@@ -463,6 +481,8 @@ declare class SignerManager {
|
|
|
463
481
|
invalidate(_sessionId: string): void;
|
|
464
482
|
clearAll(): void;
|
|
465
483
|
private static _defaultBuilder;
|
|
484
|
+
private static _createContextModule;
|
|
485
|
+
static wrapBlindSigningReportNonBlocking<T extends ContextModule>(contextModule: T): T;
|
|
466
486
|
}
|
|
467
487
|
|
|
468
488
|
type BtcWallet = Parameters<SignerBtc$1['getWalletAddress']>[0];
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { IHardwareWallet, IConnector, TransportType, UiResponseEvent, DeviceInfo, Response, ChainCapability, EvmGetAddressParams, EvmAddress, EvmSignTxParams, EvmSignedTx, EvmSignMsgParams, EvmSignature, EvmSignTypedDataParams, BtcGetAddressParams, BtcAddress, BtcGetPublicKeyParams, BtcPublicKey, BtcSignTxParams, BtcSignedTx, BtcSignPsbtParams, BtcSignedPsbt, BtcSignMsgParams, BtcSignature, SolGetAddressParams, SolAddress, SolSignTxParams, SolSignedTx, SolSignMsgParams, SolSignature, TronGetAddressParams, TronAddress, TronSignTxParams, TronSignedTx, TronSignMsgParams, TronSignature, HardwareEventMap, DeviceEventListener, ChainForFingerprint, DeviceDescriptor, DeviceChangeEvent, ConnectionType, ConnectorDevice, ConnectorSession, ConnectorEventType, ConnectorEventMap, Failure, HardwareErrorCode } from '@onekeyfe/hwk-adapter-core';
|
|
2
2
|
import { DeviceActionState as DeviceActionState$1, DiscoveredDevice, ExecuteDeviceActionReturnType, DeviceManagementKit } from '@ledgerhq/device-management-kit';
|
|
3
3
|
import { Address, Signature, SignerEth as SignerEth$1, TypedData } from '@ledgerhq/device-signer-kit-ethereum';
|
|
4
|
+
import { ContextModule } from '@ledgerhq/context-module';
|
|
4
5
|
import { SignerBtc as SignerBtc$1 } from '@ledgerhq/device-signer-kit-bitcoin';
|
|
5
6
|
import { SignerSolana } from '@ledgerhq/device-signer-kit-solana';
|
|
6
7
|
import Transport from '@ledgerhq/hw-transport';
|
|
@@ -39,6 +40,7 @@ declare class LedgerAdapter implements IHardwareWallet {
|
|
|
39
40
|
uiResponse(response: UiResponseEvent): void;
|
|
40
41
|
searchDevices(): Promise<DeviceInfo[]>;
|
|
41
42
|
private static readonly MAX_BUSINESS_RETRY_BUDGET;
|
|
43
|
+
private static readonly STUCK_APP_RETRY_DELAY_MS;
|
|
42
44
|
private static readonly MAX_DOCONNECT_CONFIRMS;
|
|
43
45
|
private _lastCancelReason;
|
|
44
46
|
private static _createDeviceBusyError;
|
|
@@ -132,6 +134,16 @@ declare class LedgerAdapter implements IHardwareWallet {
|
|
|
132
134
|
private static _throwIfAborted;
|
|
133
135
|
/** Actual work done under the job queue — connection, fingerprint, call, and recovery. */
|
|
134
136
|
private _runConnectorCall;
|
|
137
|
+
/**
|
|
138
|
+
* Stuck-app recovery: pause for the device's UI transition, then retry once.
|
|
139
|
+
*
|
|
140
|
+
* Caller has already cleared the session + reset connector. We wait so Stax
|
|
141
|
+
* finishes its post-CloseApp animation, then go through ensureConnected +
|
|
142
|
+
* fingerprint check + call exactly once. Caller decides what to do on a
|
|
143
|
+
* second stuck-app hit.
|
|
144
|
+
*/
|
|
145
|
+
private _retryAfterStuckApp;
|
|
146
|
+
private _sleepAbortable;
|
|
135
147
|
/**
|
|
136
148
|
* Clear stale session, reconnect, and retry the call.
|
|
137
149
|
*
|
|
@@ -446,8 +458,14 @@ type SignerEthBuilderFn = (args: {
|
|
|
446
458
|
dmk: DeviceManagementKit;
|
|
447
459
|
sessionId: string;
|
|
448
460
|
}) => {
|
|
461
|
+
withContextModule?(contextModule: ContextModule): {
|
|
462
|
+
build(): SignerEth$1;
|
|
463
|
+
};
|
|
449
464
|
build(): SignerEth$1;
|
|
450
465
|
} | Promise<{
|
|
466
|
+
withContextModule?(contextModule: ContextModule): {
|
|
467
|
+
build(): SignerEth$1;
|
|
468
|
+
};
|
|
451
469
|
build(): SignerEth$1;
|
|
452
470
|
}>;
|
|
453
471
|
/**
|
|
@@ -463,6 +481,8 @@ declare class SignerManager {
|
|
|
463
481
|
invalidate(_sessionId: string): void;
|
|
464
482
|
clearAll(): void;
|
|
465
483
|
private static _defaultBuilder;
|
|
484
|
+
private static _createContextModule;
|
|
485
|
+
static wrapBlindSigningReportNonBlocking<T extends ContextModule>(contextModule: T): T;
|
|
466
486
|
}
|
|
467
487
|
|
|
468
488
|
type BtcWallet = Parameters<SignerBtc$1['getWalletAddress']>[0];
|
package/dist/index.js
CHANGED
|
@@ -69,7 +69,7 @@ var LOCKED_ERROR_CODES = /* @__PURE__ */ new Set(["5515", "21781", "6982", "2701
|
|
|
69
69
|
var USER_REJECTED_CODES = /* @__PURE__ */ new Set(["6985", "27013"]);
|
|
70
70
|
var WRONG_APP_CODES = /* @__PURE__ */ new Set(["6e00", "28160", "6d00", "27904", "6a83", "27267"]);
|
|
71
71
|
var APP_NOT_INSTALLED_CODES = /* @__PURE__ */ new Set(["6807", "26631"]);
|
|
72
|
-
var
|
|
72
|
+
var STEP_BLIND_SIGN_TRANSACTION_FALLBACK = "signer.eth.steps.blindSignTransactionFallback";
|
|
73
73
|
function getEthAppErrorCode(err) {
|
|
74
74
|
if (!err || typeof err !== "object") return null;
|
|
75
75
|
const e = err;
|
|
@@ -134,13 +134,8 @@ function mapBtcAppError(hex) {
|
|
|
134
134
|
return null;
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
|
-
function
|
|
137
|
+
function mapEthAppErrorCode(ethCode) {
|
|
138
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;
|
|
144
139
|
case "6984":
|
|
145
140
|
return import_hwk_adapter_core.HardwareErrorCode.EvmClearSignPluginMissing;
|
|
146
141
|
case "6a84":
|
|
@@ -153,6 +148,14 @@ function mapEthAppError(ethCode, lastStep) {
|
|
|
153
148
|
return null;
|
|
154
149
|
}
|
|
155
150
|
}
|
|
151
|
+
function classifyEthAppError(err) {
|
|
152
|
+
const ethCode = getEthAppErrorCode(err);
|
|
153
|
+
if (!ethCode) return null;
|
|
154
|
+
if (ethCode === "6a80") {
|
|
155
|
+
return hasBlindSignFallbackStep(err) ? import_hwk_adapter_core.HardwareErrorCode.EvmBlindSigningRequired : null;
|
|
156
|
+
}
|
|
157
|
+
return mapEthAppErrorCode(ethCode);
|
|
158
|
+
}
|
|
156
159
|
var ERROR_TAG = {
|
|
157
160
|
// SDK-mint
|
|
158
161
|
DeviceNotAdvertising: "DeviceNotAdvertisingError",
|
|
@@ -239,6 +242,22 @@ var CONNECTION_LEVEL_TAGS = /* @__PURE__ */ new Set([
|
|
|
239
242
|
ERROR_TAG.ReconnectionFailed,
|
|
240
243
|
ERROR_TAG.WebHIDDisconnect
|
|
241
244
|
]);
|
|
245
|
+
var DEVICE_NOT_FOUND_TAGS = /* @__PURE__ */ new Set([
|
|
246
|
+
ERROR_TAG.NoAccessibleDevice,
|
|
247
|
+
ERROR_TAG.UnknownDevice,
|
|
248
|
+
ERROR_TAG.DeviceNotInitialized
|
|
249
|
+
]);
|
|
250
|
+
var DEVICE_BUSY_TAGS = /* @__PURE__ */ new Set([ERROR_TAG.OpeningConnection]);
|
|
251
|
+
var DEVICE_DISCONNECTED_TAGS = /* @__PURE__ */ new Set([
|
|
252
|
+
ERROR_TAG.DeviceNotRecognized,
|
|
253
|
+
ERROR_TAG.DeviceSessionNotFound,
|
|
254
|
+
ERROR_TAG.DeviceSessionRefresher,
|
|
255
|
+
ERROR_TAG.DeviceDisconnectedBeforeSendingApdu,
|
|
256
|
+
ERROR_TAG.DeviceDisconnectedWhileSending,
|
|
257
|
+
ERROR_TAG.Disconnect,
|
|
258
|
+
ERROR_TAG.ReconnectionFailed,
|
|
259
|
+
ERROR_TAG.WebHIDDisconnect
|
|
260
|
+
]);
|
|
242
261
|
function isConnectionLevelError(err) {
|
|
243
262
|
if (!err || typeof err !== "object") return false;
|
|
244
263
|
const tag = err._tag;
|
|
@@ -260,6 +279,35 @@ function hasStatusCode(err, codeSet) {
|
|
|
260
279
|
if (e.error != null && e._tag && hasStatusCode(e.error, codeSet)) return true;
|
|
261
280
|
return false;
|
|
262
281
|
}
|
|
282
|
+
function hasBlindSignFallbackStep(err) {
|
|
283
|
+
if (!err || typeof err !== "object") return false;
|
|
284
|
+
const e = err;
|
|
285
|
+
if (e._lastStep === STEP_BLIND_SIGN_TRANSACTION_FALLBACK) return true;
|
|
286
|
+
if (Array.isArray(e._deviceActionSteps) && e._deviceActionSteps.includes(STEP_BLIND_SIGN_TRANSACTION_FALLBACK)) {
|
|
287
|
+
return true;
|
|
288
|
+
}
|
|
289
|
+
if (e.originalError != null && hasBlindSignFallbackStep(e.originalError)) return true;
|
|
290
|
+
if (e.error != null && e._tag && hasBlindSignFallbackStep(e.error)) return true;
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
function isDeviceNotFoundError(err) {
|
|
294
|
+
if (!err || typeof err !== "object") return false;
|
|
295
|
+
const tag = err._tag;
|
|
296
|
+
if (tag && DEVICE_NOT_FOUND_TAGS.has(tag)) return true;
|
|
297
|
+
const e = err;
|
|
298
|
+
if (e.originalError != null && isDeviceNotFoundError(e.originalError)) return true;
|
|
299
|
+
if (e.error != null && e._tag && isDeviceNotFoundError(e.error)) return true;
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
function isDeviceBusyError(err) {
|
|
303
|
+
if (!err || typeof err !== "object") return false;
|
|
304
|
+
const tag = err._tag;
|
|
305
|
+
if (tag && DEVICE_BUSY_TAGS.has(tag)) return true;
|
|
306
|
+
const e = err;
|
|
307
|
+
if (e.originalError != null && isDeviceBusyError(e.originalError)) return true;
|
|
308
|
+
if (e.error != null && e._tag && isDeviceBusyError(e.error)) return true;
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
263
311
|
function isUserRejectedError(err) {
|
|
264
312
|
if (!err || typeof err !== "object") return false;
|
|
265
313
|
const e = err;
|
|
@@ -292,8 +340,8 @@ function isAppNotInstalledError(err) {
|
|
|
292
340
|
function isDeviceDisconnectedError(err) {
|
|
293
341
|
if (!err || typeof err !== "object") return false;
|
|
294
342
|
const e = err;
|
|
295
|
-
|
|
296
|
-
|
|
343
|
+
const tag = e._tag;
|
|
344
|
+
if (typeof tag === "string" && DEVICE_DISCONNECTED_TAGS.has(tag)) return true;
|
|
297
345
|
if (typeof e.message === "string") {
|
|
298
346
|
const msg = e.message.toLowerCase();
|
|
299
347
|
if (msg.includes("disconnected") || msg.includes("not found") || msg.includes("no device") || msg.includes("unplugged"))
|
|
@@ -339,8 +387,10 @@ function mapLedgerError(err, opts) {
|
|
|
339
387
|
let code;
|
|
340
388
|
if (isDeviceLockedError(err)) {
|
|
341
389
|
code = import_hwk_adapter_core.HardwareErrorCode.DeviceLocked;
|
|
342
|
-
} else if (isDeviceNotAdvertisingError(err)) {
|
|
390
|
+
} else if (isDeviceNotAdvertisingError(err) || isDeviceNotFoundError(err)) {
|
|
343
391
|
code = import_hwk_adapter_core.HardwareErrorCode.DeviceNotFound;
|
|
392
|
+
} else if (isDeviceBusyError(err)) {
|
|
393
|
+
code = import_hwk_adapter_core.HardwareErrorCode.DeviceBusy;
|
|
344
394
|
} else if (isBlePairingFailureError(err)) {
|
|
345
395
|
code = import_hwk_adapter_core.HardwareErrorCode.BlePairingTimeout;
|
|
346
396
|
} else if (isUserRejectedError(err)) {
|
|
@@ -354,9 +404,7 @@ function mapLedgerError(err, opts) {
|
|
|
354
404
|
} else if (isTimeoutError(err)) {
|
|
355
405
|
code = import_hwk_adapter_core.HardwareErrorCode.OperationTimeout;
|
|
356
406
|
} else {
|
|
357
|
-
const
|
|
358
|
-
const lastStep = err && typeof err === "object" ? err._lastStep : void 0;
|
|
359
|
-
const ethMapped = ethCode ? mapEthAppError(ethCode, lastStep) : null;
|
|
407
|
+
const ethMapped = classifyEthAppError(err);
|
|
360
408
|
const apduHex = ethMapped ? null : extractApduHex(err);
|
|
361
409
|
const chainMapped = apduHex ? mapSolanaAppError(apduHex) ?? mapTronAppError(apduHex) ?? mapBtcAppError(apduHex) : null;
|
|
362
410
|
code = ethMapped ?? chainMapped ?? import_hwk_adapter_core.HardwareErrorCode.UnknownError;
|
|
@@ -544,6 +592,17 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
544
592
|
await this._ensureDevicePermission();
|
|
545
593
|
debugLog(`[LedgerAdapter] searchDevices() entry, cacheBefore=${this._discoveredDevices.size}`);
|
|
546
594
|
const devices = await this.connector.searchDevices();
|
|
595
|
+
debugLog(
|
|
596
|
+
"[DMK] adapter.searchDevices raw:",
|
|
597
|
+
devices.map((device) => ({
|
|
598
|
+
id: device?.deviceId,
|
|
599
|
+
deviceId: device?.deviceId,
|
|
600
|
+
connectId: device?.connectId,
|
|
601
|
+
deviceName: device?.name,
|
|
602
|
+
"device.name": device?.name,
|
|
603
|
+
model: device?.model
|
|
604
|
+
}))
|
|
605
|
+
);
|
|
547
606
|
this._discoveredDevices.clear();
|
|
548
607
|
for (const d of devices) {
|
|
549
608
|
if (d.connectId) {
|
|
@@ -1185,7 +1244,39 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1185
1244
|
this.connector.reset?.();
|
|
1186
1245
|
} catch {
|
|
1187
1246
|
}
|
|
1188
|
-
|
|
1247
|
+
debugLog(
|
|
1248
|
+
"[LedgerAdapter] stuck-app retry: method=",
|
|
1249
|
+
method,
|
|
1250
|
+
"delayMs=",
|
|
1251
|
+
_LedgerAdapter.STUCK_APP_RETRY_DELAY_MS,
|
|
1252
|
+
"_tag=",
|
|
1253
|
+
err?._tag
|
|
1254
|
+
);
|
|
1255
|
+
try {
|
|
1256
|
+
const retryResult = await this._retryAfterStuckApp(
|
|
1257
|
+
resolvedConnectId,
|
|
1258
|
+
method,
|
|
1259
|
+
effectiveParams,
|
|
1260
|
+
signal,
|
|
1261
|
+
err,
|
|
1262
|
+
fingerprint
|
|
1263
|
+
);
|
|
1264
|
+
debugLog("[LedgerAdapter] stuck-app retry succeeded: method=", method);
|
|
1265
|
+
return retryResult;
|
|
1266
|
+
} catch (retryErr) {
|
|
1267
|
+
if (signal.aborted) throw retryErr;
|
|
1268
|
+
if (isStuckAppStateError(retryErr)) {
|
|
1269
|
+
debugLog("[LedgerAdapter] stuck-app retry exhausted (2nd 6901): method=", method);
|
|
1270
|
+
throw err;
|
|
1271
|
+
}
|
|
1272
|
+
debugLog(
|
|
1273
|
+
"[LedgerAdapter] stuck-app retry threw non-stuck error: method=",
|
|
1274
|
+
method,
|
|
1275
|
+
"retryErrTag=",
|
|
1276
|
+
retryErr?._tag
|
|
1277
|
+
);
|
|
1278
|
+
throw retryErr;
|
|
1279
|
+
}
|
|
1189
1280
|
}
|
|
1190
1281
|
if (isDeviceLockedError(err) || isDeviceNotAdvertisingError(err) || isDeviceDisconnectedError(err)) {
|
|
1191
1282
|
let lastErr = err;
|
|
@@ -1259,6 +1350,54 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1259
1350
|
throw err;
|
|
1260
1351
|
}
|
|
1261
1352
|
}
|
|
1353
|
+
/**
|
|
1354
|
+
* Stuck-app recovery: pause for the device's UI transition, then retry once.
|
|
1355
|
+
*
|
|
1356
|
+
* Caller has already cleared the session + reset connector. We wait so Stax
|
|
1357
|
+
* finishes its post-CloseApp animation, then go through ensureConnected +
|
|
1358
|
+
* fingerprint check + call exactly once. Caller decides what to do on a
|
|
1359
|
+
* second stuck-app hit.
|
|
1360
|
+
*/
|
|
1361
|
+
async _retryAfterStuckApp(resolvedConnectId, method, params, signal, originalErr, fingerprint) {
|
|
1362
|
+
await this._sleepAbortable(_LedgerAdapter.STUCK_APP_RETRY_DELAY_MS, signal);
|
|
1363
|
+
const retryTargetConnectId = isLedgerBleConnectionType(this.connector.connectionType) ? resolvedConnectId : void 0;
|
|
1364
|
+
const retryConnectId = await this.ensureConnected(retryTargetConnectId, signal);
|
|
1365
|
+
const retrySessionId = this._sessions.get(retryConnectId);
|
|
1366
|
+
if (!retrySessionId) throw originalErr;
|
|
1367
|
+
if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId) {
|
|
1368
|
+
const fp = await this._abortable(
|
|
1369
|
+
signal,
|
|
1370
|
+
this._verifyDeviceFingerprintWithSession(
|
|
1371
|
+
retrySessionId,
|
|
1372
|
+
fingerprint.deviceId,
|
|
1373
|
+
fingerprint.chain
|
|
1374
|
+
)
|
|
1375
|
+
);
|
|
1376
|
+
if (!fp.success) {
|
|
1377
|
+
throw Object.assign(new Error(formatDeviceMismatchError(fp.expected, fp.actual)), {
|
|
1378
|
+
code: import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch
|
|
1379
|
+
});
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
return this._abortable(signal, this.connector.call(retrySessionId, method, params));
|
|
1383
|
+
}
|
|
1384
|
+
_sleepAbortable(ms, signal) {
|
|
1385
|
+
return new Promise((resolve, reject) => {
|
|
1386
|
+
if (signal.aborted) {
|
|
1387
|
+
reject(signal.reason ?? new Error("Aborted"));
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
const timer = setTimeout(() => {
|
|
1391
|
+
signal.removeEventListener("abort", onAbort);
|
|
1392
|
+
resolve();
|
|
1393
|
+
}, ms);
|
|
1394
|
+
const onAbort = () => {
|
|
1395
|
+
clearTimeout(timer);
|
|
1396
|
+
reject(signal.reason ?? new Error("Aborted"));
|
|
1397
|
+
};
|
|
1398
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1399
|
+
});
|
|
1400
|
+
}
|
|
1262
1401
|
/**
|
|
1263
1402
|
* Clear stale session, reconnect, and retry the call.
|
|
1264
1403
|
*
|
|
@@ -1436,6 +1575,10 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1436
1575
|
// Layer 2 retry budget after connection-class error. Each round delegates
|
|
1437
1576
|
// to Layer 1 (which owns the unlock prompt). Layer 2 never emits UI itself.
|
|
1438
1577
|
_LedgerAdapter.MAX_BUSINESS_RETRY_BUDGET = 3;
|
|
1578
|
+
// Stuck-app (APDU 0x6901) retry pause. Ledger Stax often returns 6901 when
|
|
1579
|
+
// OpenAppCommand lands mid-transition right after CloseApp; a short wait
|
|
1580
|
+
// lets the device finish its UI animation before we retry once.
|
|
1581
|
+
_LedgerAdapter.STUCK_APP_RETRY_DELAY_MS = 500;
|
|
1439
1582
|
// Layer 1 confirm budget. After N failed Confirm cycles (user keeps clicking
|
|
1440
1583
|
// Confirm but device never shows up / never unlocks), throw DeviceNotFound
|
|
1441
1584
|
// instead of looping forever.
|
|
@@ -1443,7 +1586,7 @@ _LedgerAdapter.MAX_DOCONNECT_CONFIRMS = 3;
|
|
|
1443
1586
|
var LedgerAdapter = _LedgerAdapter;
|
|
1444
1587
|
|
|
1445
1588
|
// src/connector/LedgerConnectorBase.ts
|
|
1446
|
-
var
|
|
1589
|
+
var import_hwk_adapter_core12 = require("@onekeyfe/hwk-adapter-core");
|
|
1447
1590
|
|
|
1448
1591
|
// src/device/LedgerDeviceManager.ts
|
|
1449
1592
|
var LedgerDeviceManager = class {
|
|
@@ -1704,6 +1847,7 @@ function deviceActionToPromise(action, onInteraction, timeoutMs = IDLE_WATCHDOG_
|
|
|
1704
1847
|
return new Promise((resolve, reject) => {
|
|
1705
1848
|
let settled = false;
|
|
1706
1849
|
let lastStep;
|
|
1850
|
+
const observedSteps = [];
|
|
1707
1851
|
let sub;
|
|
1708
1852
|
let timer = null;
|
|
1709
1853
|
const cancelAction = () => {
|
|
@@ -1763,7 +1907,12 @@ function deviceActionToPromise(action, onInteraction, timeoutMs = IDLE_WATCHDOG_
|
|
|
1763
1907
|
}
|
|
1764
1908
|
armIdleWatchdog();
|
|
1765
1909
|
const step = state?.intermediateValue?.step;
|
|
1766
|
-
if (step)
|
|
1910
|
+
if (step) {
|
|
1911
|
+
lastStep = step;
|
|
1912
|
+
if (observedSteps[observedSteps.length - 1] !== step) {
|
|
1913
|
+
observedSteps.push(step);
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1767
1916
|
if (state.status === import_device_management_kit.DeviceActionStatus.Completed) {
|
|
1768
1917
|
settled = true;
|
|
1769
1918
|
if (timer) clearTimeout(timer);
|
|
@@ -1775,7 +1924,7 @@ function deviceActionToPromise(action, onInteraction, timeoutMs = IDLE_WATCHDOG_
|
|
|
1775
1924
|
if (timer) clearTimeout(timer);
|
|
1776
1925
|
onInteraction?.("interaction-complete");
|
|
1777
1926
|
sub?.unsubscribe();
|
|
1778
|
-
|
|
1927
|
+
rejectWithStepContext(state.error, lastStep, observedSteps, reject);
|
|
1779
1928
|
} else if (state.status === import_device_management_kit.DeviceActionStatus.Pending && onInteraction) {
|
|
1780
1929
|
const interaction = state.intermediateValue?.requiredUserInteraction;
|
|
1781
1930
|
if (interaction && interaction !== "none") {
|
|
@@ -1792,7 +1941,7 @@ function deviceActionToPromise(action, onInteraction, timeoutMs = IDLE_WATCHDOG_
|
|
|
1792
1941
|
settled = true;
|
|
1793
1942
|
if (timer) clearTimeout(timer);
|
|
1794
1943
|
sub?.unsubscribe();
|
|
1795
|
-
|
|
1944
|
+
rejectWithStepContext(err, lastStep, observedSteps, reject);
|
|
1796
1945
|
}
|
|
1797
1946
|
},
|
|
1798
1947
|
complete: () => {
|
|
@@ -1805,15 +1954,25 @@ function deviceActionToPromise(action, onInteraction, timeoutMs = IDLE_WATCHDOG_
|
|
|
1805
1954
|
});
|
|
1806
1955
|
});
|
|
1807
1956
|
}
|
|
1808
|
-
function
|
|
1809
|
-
if (err && typeof err === "object" && lastStep) {
|
|
1957
|
+
function rejectWithStepContext(err, lastStep, observedSteps, reject) {
|
|
1958
|
+
if (err && typeof err === "object" && (lastStep || observedSteps.length > 0)) {
|
|
1810
1959
|
try {
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1960
|
+
if (lastStep) {
|
|
1961
|
+
Object.defineProperty(err, "_lastStep", {
|
|
1962
|
+
value: lastStep,
|
|
1963
|
+
configurable: true,
|
|
1964
|
+
enumerable: false,
|
|
1965
|
+
writable: true
|
|
1966
|
+
});
|
|
1967
|
+
}
|
|
1968
|
+
if (observedSteps.length > 0) {
|
|
1969
|
+
Object.defineProperty(err, "_deviceActionSteps", {
|
|
1970
|
+
value: [...observedSteps],
|
|
1971
|
+
configurable: true,
|
|
1972
|
+
enumerable: false,
|
|
1973
|
+
writable: true
|
|
1974
|
+
});
|
|
1975
|
+
}
|
|
1817
1976
|
} catch {
|
|
1818
1977
|
}
|
|
1819
1978
|
}
|
|
@@ -1879,7 +2038,8 @@ var SignerManager = class _SignerManager {
|
|
|
1879
2038
|
async getOrCreate(sessionId) {
|
|
1880
2039
|
debugLog("[DMK] SignerManager.getOrCreate:", { sessionId });
|
|
1881
2040
|
const builder = await this._builderFn({ dmk: this._dmk, sessionId });
|
|
1882
|
-
|
|
2041
|
+
const builderWithContext = builder.withContextModule ? builder.withContextModule(_SignerManager._createContextModule()) : builder;
|
|
2042
|
+
return new SignerEth(builderWithContext.build());
|
|
1883
2043
|
}
|
|
1884
2044
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars, class-methods-use-this
|
|
1885
2045
|
invalidate(_sessionId) {
|
|
@@ -1888,10 +2048,24 @@ var SignerManager = class _SignerManager {
|
|
|
1888
2048
|
clearAll() {
|
|
1889
2049
|
}
|
|
1890
2050
|
static _defaultBuilder() {
|
|
1891
|
-
return (args) =>
|
|
1892
|
-
|
|
1893
|
-
|
|
2051
|
+
return (args) => new import_device_signer_kit_ethereum.SignerEthBuilder(args);
|
|
2052
|
+
}
|
|
2053
|
+
static _createContextModule() {
|
|
2054
|
+
const contextModule = new import_context_module.ContextModuleBuilder({}).removeDefaultLoaders().build();
|
|
2055
|
+
return _SignerManager.wrapBlindSigningReportNonBlocking(contextModule);
|
|
2056
|
+
}
|
|
2057
|
+
static wrapBlindSigningReportNonBlocking(contextModule) {
|
|
2058
|
+
const report = contextModule.report.bind(contextModule);
|
|
2059
|
+
contextModule.report = async (params) => {
|
|
2060
|
+
try {
|
|
2061
|
+
void report(params).catch((err) => {
|
|
2062
|
+
debugLog("[DMK] ContextModule.report failed:", err);
|
|
2063
|
+
});
|
|
2064
|
+
} catch (err) {
|
|
2065
|
+
debugLog("[DMK] ContextModule.report failed:", err);
|
|
2066
|
+
}
|
|
1894
2067
|
};
|
|
2068
|
+
return contextModule;
|
|
1895
2069
|
}
|
|
1896
2070
|
};
|
|
1897
2071
|
|
|
@@ -2461,14 +2635,15 @@ async function _createSolSigner(ctx, sessionId) {
|
|
|
2461
2635
|
}
|
|
2462
2636
|
|
|
2463
2637
|
// src/connector/chains/tron.ts
|
|
2464
|
-
var
|
|
2638
|
+
var import_hwk_adapter_core11 = require("@onekeyfe/hwk-adapter-core");
|
|
2465
2639
|
var import_hw_app_trx = __toESM(require("@ledgerhq/hw-app-trx"));
|
|
2466
2640
|
|
|
2467
2641
|
// src/connector/chains/legacyChainCall.ts
|
|
2468
|
-
var
|
|
2642
|
+
var import_hwk_adapter_core10 = require("@onekeyfe/hwk-adapter-core");
|
|
2469
2643
|
|
|
2470
2644
|
// src/app/AppManager.ts
|
|
2471
2645
|
var import_device_management_kit2 = require("@ledgerhq/device-management-kit");
|
|
2646
|
+
var import_hwk_adapter_core9 = require("@onekeyfe/hwk-adapter-core");
|
|
2472
2647
|
var APP_NAME_MAP = {
|
|
2473
2648
|
ETH: "Ethereum",
|
|
2474
2649
|
BTC: "Bitcoin",
|
|
@@ -2573,9 +2748,11 @@ var AppManager = class {
|
|
|
2573
2748
|
});
|
|
2574
2749
|
if (!(0, import_device_management_kit2.isSuccessCommandResult)(result)) {
|
|
2575
2750
|
const { statusCode } = result;
|
|
2751
|
+
const hasStatusCode2 = statusCode != null && statusCode !== "";
|
|
2576
2752
|
debugLog("[AppManager] openApp failed:", appName, "statusCode:", statusCode);
|
|
2577
2753
|
throw Object.assign(new Error(`Failed to open "${appName}"`), {
|
|
2578
2754
|
_tag: ERROR_TAG.OpenAppCommand,
|
|
2755
|
+
code: hasStatusCode2 ? void 0 : import_hwk_adapter_core9.HardwareErrorCode.AppNotInstalled,
|
|
2579
2756
|
errorCode: String(statusCode ?? ""),
|
|
2580
2757
|
statusCode,
|
|
2581
2758
|
appName
|
|
@@ -2631,14 +2808,14 @@ async function withLegacyChainCall(ctx, sessionId, options, action) {
|
|
|
2631
2808
|
const onAppOpenPrompt = () => {
|
|
2632
2809
|
openAppPromptShown = true;
|
|
2633
2810
|
ctx.emit("ui-event", {
|
|
2634
|
-
type:
|
|
2811
|
+
type: import_hwk_adapter_core10.EConnectorInteraction.ConfirmOpenApp,
|
|
2635
2812
|
payload: { sessionId }
|
|
2636
2813
|
});
|
|
2637
2814
|
};
|
|
2638
2815
|
const closeOpenAppUiIfShown = () => {
|
|
2639
2816
|
if (openAppPromptShown) {
|
|
2640
2817
|
ctx.emit("ui-event", {
|
|
2641
|
-
type:
|
|
2818
|
+
type: import_hwk_adapter_core10.EConnectorInteraction.InteractionComplete,
|
|
2642
2819
|
payload: { sessionId }
|
|
2643
2820
|
});
|
|
2644
2821
|
openAppPromptShown = false;
|
|
@@ -2659,7 +2836,7 @@ async function withLegacyChainCall(ctx, sessionId, options, action) {
|
|
|
2659
2836
|
let confirmEmitted = false;
|
|
2660
2837
|
if (needsConfirmation) {
|
|
2661
2838
|
ctx.emit("ui-event", {
|
|
2662
|
-
type:
|
|
2839
|
+
type: import_hwk_adapter_core10.EConnectorInteraction.ConfirmOnDevice,
|
|
2663
2840
|
payload: { sessionId }
|
|
2664
2841
|
});
|
|
2665
2842
|
confirmEmitted = true;
|
|
@@ -2669,7 +2846,7 @@ async function withLegacyChainCall(ctx, sessionId, options, action) {
|
|
|
2669
2846
|
} finally {
|
|
2670
2847
|
if (confirmEmitted || openAppPromptShown) {
|
|
2671
2848
|
ctx.emit("ui-event", {
|
|
2672
|
-
type:
|
|
2849
|
+
type: import_hwk_adapter_core10.EConnectorInteraction.InteractionComplete,
|
|
2673
2850
|
payload: { sessionId }
|
|
2674
2851
|
});
|
|
2675
2852
|
openAppPromptShown = false;
|
|
@@ -2757,7 +2934,7 @@ async function tronSignTransaction(ctx, sessionId, params) {
|
|
|
2757
2934
|
if (!params.rawTxHex) {
|
|
2758
2935
|
throw Object.assign(
|
|
2759
2936
|
new Error("TRON signing requires a protobuf-encoded raw transaction hex (rawTxHex)."),
|
|
2760
|
-
{ code:
|
|
2937
|
+
{ code: import_hwk_adapter_core11.HardwareErrorCode.InvalidParams }
|
|
2761
2938
|
);
|
|
2762
2939
|
}
|
|
2763
2940
|
const path = normalizePath(params.path);
|
|
@@ -2801,6 +2978,9 @@ var METHOD_PREFIX_TO_APP_NAME = {
|
|
|
2801
2978
|
sol: "Solana",
|
|
2802
2979
|
tron: "Tron"
|
|
2803
2980
|
};
|
|
2981
|
+
var HARDWARE_ERROR_CODE_VALUES = new Set(
|
|
2982
|
+
Object.values(import_hwk_adapter_core12.HardwareErrorCode).filter((value) => typeof value === "number")
|
|
2983
|
+
);
|
|
2804
2984
|
async function defaultLedgerKitImporter(pkg) {
|
|
2805
2985
|
switch (pkg) {
|
|
2806
2986
|
case "@ledgerhq/device-management-kit":
|
|
@@ -2922,6 +3102,21 @@ var LedgerConnectorBase = class {
|
|
|
2922
3102
|
descriptor: d,
|
|
2923
3103
|
connectId: this._resolveConnectId(d)
|
|
2924
3104
|
}));
|
|
3105
|
+
debugLog(
|
|
3106
|
+
"[DMK] connector.searchDevices() raw descriptors:",
|
|
3107
|
+
resolvedDescriptors.map(({ descriptor: d, connectId }) => ({
|
|
3108
|
+
id: d?.path,
|
|
3109
|
+
path: d?.path,
|
|
3110
|
+
connectId,
|
|
3111
|
+
deviceName: d?.name,
|
|
3112
|
+
"device.name": d?.bleName,
|
|
3113
|
+
localName: d?.localName,
|
|
3114
|
+
bleName: d?.bleName,
|
|
3115
|
+
model: d?.type,
|
|
3116
|
+
transport: d?.transport,
|
|
3117
|
+
rssi: d?.rssi
|
|
3118
|
+
}))
|
|
3119
|
+
);
|
|
2925
3120
|
const bleConnectIdCounts = /* @__PURE__ */ new Map();
|
|
2926
3121
|
for (const item of resolvedDescriptors) {
|
|
2927
3122
|
if (isLedgerBleDescriptor(this.connectionType, item.descriptor)) {
|
|
@@ -2929,7 +3124,7 @@ var LedgerConnectorBase = class {
|
|
|
2929
3124
|
debugLog(`[DMK] connector.searchDevices() invalid BLE connectId=${item.connectId}`);
|
|
2930
3125
|
throw Object.assign(
|
|
2931
3126
|
new Error("Ledger BLE connectId must be the 4-character BLE identifier"),
|
|
2932
|
-
{ code:
|
|
3127
|
+
{ code: import_hwk_adapter_core12.HardwareErrorCode.DeviceNotFound }
|
|
2933
3128
|
);
|
|
2934
3129
|
}
|
|
2935
3130
|
bleConnectIdCounts.set(item.connectId, (bleConnectIdCounts.get(item.connectId) ?? 0) + 1);
|
|
@@ -2946,7 +3141,7 @@ var LedgerConnectorBase = class {
|
|
|
2946
3141
|
);
|
|
2947
3142
|
throw Object.assign(
|
|
2948
3143
|
new Error(`Duplicate Ledger BLE connectId detected: ${duplicateBleConnectId}`),
|
|
2949
|
-
{ code:
|
|
3144
|
+
{ code: import_hwk_adapter_core12.HardwareErrorCode.DeviceNotFound }
|
|
2950
3145
|
);
|
|
2951
3146
|
}
|
|
2952
3147
|
const result = resolvedDescriptors.map(({ descriptor: d, connectId }) => {
|
|
@@ -2992,7 +3187,7 @@ var LedgerConnectorBase = class {
|
|
|
2992
3187
|
`Ledger BLE connect did not return within ${HANG_CEILING_MS / 6e4}min \u2014 DMK hang fallback.`
|
|
2993
3188
|
);
|
|
2994
3189
|
err._tag = ERROR_TAG.BlePairingTimeout;
|
|
2995
|
-
err.code =
|
|
3190
|
+
err.code = import_hwk_adapter_core12.HardwareErrorCode.BlePairingTimeout;
|
|
2996
3191
|
reject(err);
|
|
2997
3192
|
}, HANG_CEILING_MS);
|
|
2998
3193
|
});
|
|
@@ -3054,7 +3249,7 @@ var LedgerConnectorBase = class {
|
|
|
3054
3249
|
"Ledger Bluetooth pairing failed. Make sure the device is unlocked and nearby, then try again."
|
|
3055
3250
|
);
|
|
3056
3251
|
wrapped._tag = ERROR_TAG.BleGattBondingFailed;
|
|
3057
|
-
wrapped.code =
|
|
3252
|
+
wrapped.code = import_hwk_adapter_core12.HardwareErrorCode.BlePairingTimeout;
|
|
3058
3253
|
wrapped.originalError = err;
|
|
3059
3254
|
throw wrapped;
|
|
3060
3255
|
}
|
|
@@ -3137,7 +3332,7 @@ var LedgerConnectorBase = class {
|
|
|
3137
3332
|
this._unwatchSessionState(sessionId);
|
|
3138
3333
|
this._signerManager?.invalidate(sessionId);
|
|
3139
3334
|
this._cancellers.get(sessionId)?.({
|
|
3140
|
-
code:
|
|
3335
|
+
code: import_hwk_adapter_core12.HardwareErrorCode.DeviceDisconnected,
|
|
3141
3336
|
tag: "DeviceDisconnected",
|
|
3142
3337
|
message: "Device disconnected"
|
|
3143
3338
|
});
|
|
@@ -3154,14 +3349,14 @@ var LedgerConnectorBase = class {
|
|
|
3154
3349
|
} catch (err) {
|
|
3155
3350
|
if (isAppStuckByApdu(err)) {
|
|
3156
3351
|
throw Object.assign(new Error("Ledger app is unresponsive"), {
|
|
3157
|
-
code:
|
|
3352
|
+
code: import_hwk_adapter_core12.HardwareErrorCode.DeviceAppStuck,
|
|
3158
3353
|
_tag: ERROR_TAG.DeviceAppStuck,
|
|
3159
3354
|
originalError: err
|
|
3160
3355
|
});
|
|
3161
3356
|
}
|
|
3162
3357
|
if (isTransportStuck(err)) {
|
|
3163
3358
|
throw Object.assign(new Error("Device communication interrupted, please retry"), {
|
|
3164
|
-
code:
|
|
3359
|
+
code: import_hwk_adapter_core12.HardwareErrorCode.TransportError,
|
|
3165
3360
|
_tag: ERROR_TAG.DeviceTransportStuck,
|
|
3166
3361
|
originalError: err
|
|
3167
3362
|
});
|
|
@@ -3399,15 +3594,21 @@ var LedgerConnectorBase = class {
|
|
|
3399
3594
|
};
|
|
3400
3595
|
}
|
|
3401
3596
|
_wrapError(err, opts) {
|
|
3402
|
-
const mapped = mapLedgerError(err, opts);
|
|
3403
3597
|
const src = err && typeof err === "object" ? err : {};
|
|
3598
|
+
const hasSerializedCode = typeof src.code === "number" && HARDWARE_ERROR_CODE_VALUES.has(src.code);
|
|
3599
|
+
const mapped = hasSerializedCode ? {
|
|
3600
|
+
code: src.code,
|
|
3601
|
+
message: typeof src.message === "string" ? src.message : "Unknown Ledger error",
|
|
3602
|
+
appName: typeof src.appName === "string" ? src.appName : opts?.defaultAppName
|
|
3603
|
+
} : mapLedgerError(err, opts);
|
|
3404
3604
|
const error = new Error(mapped.message);
|
|
3405
3605
|
Object.assign(error, {
|
|
3406
3606
|
code: mapped.code,
|
|
3407
3607
|
appName: mapped.appName,
|
|
3408
3608
|
_tag: src._tag,
|
|
3409
3609
|
errorCode: src.errorCode,
|
|
3410
|
-
_lastStep: src._lastStep
|
|
3610
|
+
_lastStep: src._lastStep,
|
|
3611
|
+
_deviceActionSteps: src._deviceActionSteps
|
|
3411
3612
|
});
|
|
3412
3613
|
Object.defineProperty(error, "originalError", {
|
|
3413
3614
|
value: err,
|