@onekeyfe/hwk-keystone-adapter 1.2.2-alpha.100 → 1.2.3-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -30,17 +30,19 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ KEYSTONE_WALLET_CONNECT_ID_PREFIX: () => KEYSTONE_WALLET_CONNECT_ID_PREFIX,
34
+ KEYSTONE_WALLET_ID_PATH: () => KEYSTONE_WALLET_ID_PATH,
33
35
  KeystoneAdapter: () => KeystoneAdapter,
34
36
  KeystoneUrEngine: () => KeystoneUrEngine,
35
- QR_CONNECT_ID_PREFIX: () => QR_CONNECT_ID_PREFIX,
36
37
  accountKey: () => accountKey,
37
38
  btcScriptTypeFromPath: () => btcScriptTypeFromPath,
38
39
  createDeviceRecord: () => createDeviceRecord,
40
+ deriveKeystoneWalletId: () => deriveKeystoneWalletId,
39
41
  normalizePath: () => normalizePath,
40
42
  placeholderDeviceInfo: () => placeholderDeviceInfo,
41
- qrConnectId: () => qrConnectId,
42
43
  splitAccountPath: () => splitAccountPath,
43
- toDeviceInfo: () => toDeviceInfo
44
+ toDeviceInfo: () => toDeviceInfo,
45
+ walletConnectId: () => walletConnectId
44
46
  });
45
47
  module.exports = __toCommonJS(index_exports);
46
48
 
@@ -51,6 +53,7 @@ var import_bs58check = __toESM(require("bs58check"));
51
53
  var bitcoin = __toESM(require("bitcoinjs-lib"));
52
54
  var import_hdkey = __toESM(require("hdkey"));
53
55
  var import_uuid = require("uuid");
56
+ var import_hwk_adapter_core = require("@onekeyfe/hwk-adapter-core");
54
57
 
55
58
  // src/urEngine/TronSignRequest.ts
56
59
  var import_bc_ur_registry = require("@keystonehq/bc-ur-registry");
@@ -69,13 +72,13 @@ var TronSignRequest = class _TronSignRequest extends import_bc_ur_registry.Regis
69
72
  if (this.requestId) {
70
73
  map[1 /* requestId */] = new import_bc_ur_registry.DataItem(this.requestId, import_bc_ur_registry.RegistryTypes.UUID.getTag());
71
74
  }
72
- if (this.address) map[4 /* address */] = this.address;
73
- if (this.origin) map[5 /* origin */] = this.origin;
75
+ if (this.address) map[5 /* address */] = this.address;
76
+ if (this.origin) map[6 /* origin */] = this.origin;
74
77
  map[2 /* signData */] = this.signData;
75
- map[6 /* signType */] = this.signType;
78
+ map[3 /* dataType */] = this.signType;
76
79
  const keyPath = this.derivationPath.toDataItem();
77
80
  keyPath.setTag(this.derivationPath.getRegistryType().getTag());
78
- map[3 /* derivationPath */] = keyPath;
81
+ map[4 /* derivationPath */] = keyPath;
79
82
  return new import_bc_ur_registry.DataItem(map);
80
83
  };
81
84
  this.requestId = args.requestId;
@@ -88,12 +91,12 @@ var TronSignRequest = class _TronSignRequest extends import_bc_ur_registry.Regis
88
91
  static fromDataItem(dataItem) {
89
92
  const map = dataItem.getData();
90
93
  const signData = map[2 /* signData */];
91
- const derivationPath = import_bc_ur_registry.CryptoKeypath.fromDataItem(map[3 /* derivationPath */]);
92
- const address = map[4 /* address */];
94
+ const derivationPath = import_bc_ur_registry.CryptoKeypath.fromDataItem(map[4 /* derivationPath */]);
95
+ const address = map[5 /* address */];
93
96
  const requestIdItem = map[1 /* requestId */];
94
97
  const requestId = requestIdItem?.getData();
95
- const origin = map[5 /* origin */];
96
- const signType = map[6 /* signType */];
98
+ const origin = map[6 /* origin */];
99
+ const signType = map[3 /* dataType */];
97
100
  return new _TronSignRequest({ requestId, signData, derivationPath, address, origin, signType });
98
101
  }
99
102
  static fromCBOR(cborPayload) {
@@ -169,6 +172,13 @@ function fromSdkUr(ur) {
169
172
  function splitSignature65(hex) {
170
173
  return { r: hex.slice(0, 64), s: hex.slice(64, 128), v: hex.slice(128) };
171
174
  }
175
+ function requireBip32MasterFingerprint(value) {
176
+ const fingerprint = (0, import_hwk_adapter_core.parseBip32MasterFingerprint)(value);
177
+ if (!fingerprint) {
178
+ throw new Error("Keystone master fingerprint must be exactly 4 bytes (8 hex characters)");
179
+ }
180
+ return fingerprint;
181
+ }
172
182
  var KeystoneUrEngine = class {
173
183
  constructor(origin = "OneKey") {
174
184
  this.sdk = new import_keystone_sdk.KeystoneSDK({ origin });
@@ -178,7 +188,7 @@ var KeystoneUrEngine = class {
178
188
  parseMultiAccounts(ur) {
179
189
  const parsed = this.sdk.parseMultiAccounts(toSdkUr(ur));
180
190
  return {
181
- masterFingerprint: parsed.masterFingerprint.toLowerCase(),
191
+ masterFingerprint: requireBip32MasterFingerprint(parsed.masterFingerprint),
182
192
  device: parsed.device,
183
193
  deviceId: parsed.deviceId,
184
194
  deviceVersion: parsed.deviceVersion,
@@ -188,7 +198,7 @@ var KeystoneUrEngine = class {
188
198
  path: key.path,
189
199
  publicKey: key.publicKey,
190
200
  extendedPublicKey: key.extendedPublicKey,
191
- xfp: key.xfp,
201
+ xfp: key.xfp ? requireBip32MasterFingerprint(key.xfp) : void 0,
192
202
  name: key.name
193
203
  })
194
204
  )
@@ -201,7 +211,7 @@ var KeystoneUrEngine = class {
201
211
  path: key.path,
202
212
  publicKey: key.publicKey,
203
213
  extendedPublicKey: key.extendedPublicKey,
204
- xfp: key.xfp,
214
+ xfp: key.xfp ? requireBip32MasterFingerprint(key.xfp) : void 0,
205
215
  name: key.name
206
216
  };
207
217
  }
@@ -250,7 +260,10 @@ var KeystoneUrEngine = class {
250
260
  if (!account.xfp) {
251
261
  throw new Error("Keystone crypto-hdkey response is missing its source fingerprint");
252
262
  }
253
- return { masterFingerprint: account.xfp.toLowerCase(), accounts: [account] };
263
+ return {
264
+ masterFingerprint: requireBip32MasterFingerprint(account.xfp),
265
+ accounts: [account]
266
+ };
254
267
  }
255
268
  return this.parseMultiAccounts(ur);
256
269
  }
@@ -302,12 +315,18 @@ var KeystoneUrEngine = class {
302
315
  deriveBtcAddressFromXpub(xpub, relativeDerivePath, scriptType) {
303
316
  const node = import_hdkey.default.fromExtendedKey(xpub).derive(`m/${relativeDerivePath.replace(/^m\//i, "")}`);
304
317
  if (!node.publicKey) throw new Error("HDKey derivation did not produce a public key");
305
- const pubkey = Buffer.from(node.publicKey);
318
+ return this.deriveBtcAddressFromPublicKey(
319
+ Buffer.from(node.publicKey).toString("hex"),
320
+ scriptType
321
+ );
322
+ }
323
+ deriveBtcAddressFromPublicKey(publicKeyHex, scriptType) {
324
+ const pubkey = Buffer.from(stripHexPrefix(publicKeyHex), "hex");
306
325
  const network = bitcoin.networks.bitcoin;
307
326
  switch (scriptType) {
308
327
  case "p2pkh": {
309
328
  const { address } = bitcoin.payments.p2pkh({ pubkey, network });
310
- if (!address) throw new Error("Failed to derive a P2PKH address from this xpub");
329
+ if (!address) throw new Error("Failed to derive a P2PKH address from this public key");
311
330
  return address;
312
331
  }
313
332
  case "p2sh-p2wpkh": {
@@ -315,12 +334,13 @@ var KeystoneUrEngine = class {
315
334
  redeem: bitcoin.payments.p2wpkh({ pubkey, network }),
316
335
  network
317
336
  });
318
- if (!address) throw new Error("Failed to derive a P2SH-P2WPKH address from this xpub");
337
+ if (!address)
338
+ throw new Error("Failed to derive a P2SH-P2WPKH address from this public key");
319
339
  return address;
320
340
  }
321
341
  case "p2wpkh": {
322
342
  const { address } = bitcoin.payments.p2wpkh({ pubkey, network });
323
- if (!address) throw new Error("Failed to derive a P2WPKH address from this xpub");
343
+ if (!address) throw new Error("Failed to derive a P2WPKH address from this public key");
324
344
  return address;
325
345
  }
326
346
  case "p2tr":
@@ -379,21 +399,14 @@ var KeystoneUrEngine = class {
379
399
  }
380
400
  // --- TRON ---
381
401
  /**
382
- * `@keystonehq/keystone-sdk`'s own bundled `sdk.tron` module is
383
- * deliberately NOT used here — see `TronSignRequest.ts`'s doc comment for
384
- * why: it's a different (gzip/protobuf) protocol with response semantics
385
- * this package has no way to verify, whereas `TronSignRequest`/
386
- * `TronSignature` are a direct port of OneKey's own already-proven
387
- * production QR-wallet TRON implementation (a plain CBOR-native
388
- * sign-request/signature pair, same shape as eth/sol). The device decodes
389
- * `rawTxHex` itself — no client-side contract-type pre-parsing or
390
- * `tokenInfo` needed, unlike the public SDK's module.
402
+ * Keystone's native tron-sign-request/tron-signature pair (bare signature).
403
+ * `sdk.tron` from keystone-sdk is the older protobuf envelope; not used.
391
404
  */
392
405
  buildTronSignRequest(input) {
393
406
  const request = new TronSignRequest({
394
407
  requestId: Buffer.from((0, import_uuid.parse)(input.requestId)),
395
408
  signData: Buffer.from(stripHexPrefix(input.rawTxHex), "hex"),
396
- signType: 0 /* Transaction */,
409
+ signType: input.signType ?? 1 /* Transaction */,
397
410
  derivationPath: TronSignRequest.parsePath(input.path, input.xfp),
398
411
  origin: input.origin
399
412
  });
@@ -430,12 +443,35 @@ var KeystoneUrEngine = class {
430
443
  ]);
431
444
  return import_bs58check.default.encode(addressBytes);
432
445
  }
446
+ /**
447
+ * Split an account-level xpub back into the BIP-32 fields a host needs to
448
+ * treat it as a real extended key (`BtcPublicKey`). Everything here is
449
+ * carried inside the xpub's own serialization — depth, the PARENT key
450
+ * fingerprint (not the seed's master fingerprint), the chain code and the
451
+ * compressed public key — so this is a pure decode with no device round
452
+ * trip; the xpub itself was already device-verified when it was synced.
453
+ */
454
+ parseXpubMeta(xpub) {
455
+ const raw = Buffer.from(import_bs58check.default.decode(xpub));
456
+ if (raw.length !== 78) {
457
+ throw new Error(`Keystone xpub did not decode to a 78-byte BIP-32 key (got ${raw.length})`);
458
+ }
459
+ return {
460
+ publicKey: raw.subarray(45, 78).toString("hex"),
461
+ chainCode: raw.subarray(13, 45).toString("hex"),
462
+ depth: raw.readUInt8(4),
463
+ parentFingerprint: raw.readUInt32BE(5)
464
+ };
465
+ }
433
466
  };
434
467
 
435
468
  // src/adapter/KeystoneAdapter.ts
436
469
  var import_bs58 = __toESM(require("bs58"));
437
470
  var import_uuid2 = require("uuid");
438
- var import_hwk_adapter_core = require("@onekeyfe/hwk-adapter-core");
471
+ var import_hwk_adapter_core3 = require("@onekeyfe/hwk-adapter-core");
472
+
473
+ // src/adapter/deviceTable.ts
474
+ var import_hwk_adapter_core2 = require("@onekeyfe/hwk-adapter-core");
439
475
 
440
476
  // src/adapter/pathUtils.ts
441
477
  function normalizePath(path) {
@@ -471,20 +507,41 @@ function btcScriptTypeFromPath(path) {
471
507
  return void 0;
472
508
  }
473
509
  }
510
+ function isKeystoneSignableBtcAccountPath(accountPath) {
511
+ const segments = normalizePath(accountPath).slice(2).split("/");
512
+ if (segments.length !== 3) return false;
513
+ const [purpose, coin, account] = segments;
514
+ return ["44'", "49'", "84'", "86'"].includes(purpose) && coin === "0'" && account === "0'";
515
+ }
516
+ var KEYSTONE_BTC_ACCOUNT_FORBIDDEN_MESSAGE = "Keystone BTC is limited to mainnet account 0 (m/44'|49'|84'|86'/0'/0')";
474
517
 
475
518
  // src/adapter/deviceTable.ts
476
- var QR_CONNECT_ID_PREFIX = "keystone-qr:";
477
- function qrConnectId(masterFingerprint) {
478
- return `${QR_CONNECT_ID_PREFIX}${masterFingerprint}`;
519
+ var KEYSTONE_WALLET_CONNECT_ID_PREFIX = "keystone-wallet:";
520
+ var KEYSTONE_WALLET_ID_PATH = "m/44'/60'/0'";
521
+ function walletConnectId(walletId) {
522
+ return `${KEYSTONE_WALLET_CONNECT_ID_PREFIX}${walletId}`;
479
523
  }
480
524
  function accountKey(hwkChain, path) {
481
525
  return `${hwkChain}:${normalizePath(path)}`;
482
526
  }
483
- function createDeviceRecord(masterFingerprint) {
527
+ function deriveKeystoneWalletId(accounts) {
528
+ const identityAccount = accounts.find(
529
+ (account) => normalizePath(account.path) === KEYSTONE_WALLET_ID_PATH
530
+ );
531
+ if (!identityAccount?.extendedPublicKey) {
532
+ throw new Error(
533
+ `Keystone identity response is missing the extended public key at ${KEYSTONE_WALLET_ID_PATH}`
534
+ );
535
+ }
536
+ return (0, import_hwk_adapter_core2.deriveWalletId)(
537
+ `keystone:secp256k1:${KEYSTONE_WALLET_ID_PATH}:${identityAccount.extendedPublicKey.trim()}`
538
+ );
539
+ }
540
+ function createDeviceRecord(walletId, masterFingerprint) {
484
541
  return {
542
+ walletId,
485
543
  masterFingerprint,
486
- connectId: qrConnectId(masterFingerprint),
487
- accounts: /* @__PURE__ */ new Map(),
544
+ connectId: walletConnectId(walletId),
488
545
  importedAt: Date.now()
489
546
  };
490
547
  }
@@ -499,11 +556,15 @@ function toDeviceInfo(record) {
499
556
  model: record.model ?? "unknown",
500
557
  modelName: record.model,
501
558
  firmwareVersion: record.deviceVersion ?? "0.0.0",
502
- deviceId: record.masterFingerprint,
559
+ deviceId: record.walletId,
503
560
  connectId: record.connectId,
504
561
  connectionType: record.usbSessionId ? "usb" : "qr",
505
562
  capabilities: CAPABILITIES,
506
- raw: { availableChannels }
563
+ raw: {
564
+ availableChannels,
565
+ masterFingerprint: record.masterFingerprint,
566
+ hardwareDeviceId: record.hardwareDeviceId
567
+ }
507
568
  };
508
569
  }
509
570
  function placeholderDeviceInfo() {
@@ -520,6 +581,26 @@ function placeholderDeviceInfo() {
520
581
 
521
582
  // src/adapter/KeystoneAdapter.ts
522
583
  var COLD_START_JOB_LABEL = "keystone-cold-start";
584
+ var KEYSTONE_USB_REATTACH_PROBE_ATTEMPTS = 4;
585
+ var KEYSTONE_USB_REATTACH_PROBE_INTERVAL_MS = 500;
586
+ function resolveHardwareOperationTarget(positionalTargetId, interactionId) {
587
+ const result = (0, import_hwk_adapter_core3.resolveHardwareOperationTarget)(
588
+ positionalTargetId,
589
+ interactionId,
590
+ "keystone"
591
+ );
592
+ return result;
593
+ }
594
+ function waitForKeystoneUsbReattachProbe() {
595
+ return new Promise((resolve) => {
596
+ setTimeout(resolve, KEYSTONE_USB_REATTACH_PROBE_INTERVAL_MS);
597
+ });
598
+ }
599
+ function isKeystoneUsbReconnectableError(error) {
600
+ if (!error || typeof error !== "object") return false;
601
+ const { code } = error;
602
+ return code === import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound || code === import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected;
603
+ }
523
604
  var BIP44_COIN_TYPE_TO_CHAIN = {
524
605
  60: "evm",
525
606
  0: "btc",
@@ -530,64 +611,111 @@ function inferHwkChainFromPath(path) {
530
611
  const match = normalizePath(path).match(/^m\/\d+'\/(\d+)'/);
531
612
  return match ? BIP44_COIN_TYPE_TO_CHAIN[Number(match[1])] : void 0;
532
613
  }
533
- var DEFAULT_IMPORT_SCHEMAS = [
534
- { hwkChain: "evm", path: import_hwk_adapter_core.CHAIN_FINGERPRINT_PATHS.evm.replace(/\/0\/0$/, "") },
535
- // The 3 BTC purposes this package can actually derive addresses for
536
- // (btcScriptTypeFromPath: 44'→P2PKH, 49'→P2SH-P2WPKH, 84'→P2WPKH) —
537
- // explicitly requested, not left to chance on whether the device
538
- // volunteers the others unprompted. Still one combined round trip: these
539
- // are 3 more entries in the same qr-hardware-call, not 3 more scans.
540
- // 86' (P2TR/taproot) deliberately excluded — `deriveBtcAddressFromXpub`
541
- // can't use it yet (needs an elliptic-curve library not wired in), and
542
- // unlike app-monorepo's own sync-all bundle (which also requests 86', but
543
- // to compute a "full xfp" — a need this adapter doesn't have, since its
544
- // mfp already comes for free from the response envelope), there's no
545
- // other use for that xpub here — so it stays out until P2TR is real.
546
- { hwkChain: "btc", path: import_hwk_adapter_core.CHAIN_FINGERPRINT_PATHS.btc },
547
- { hwkChain: "btc", path: "m/49'/0'/0'" },
548
- { hwkChain: "btc", path: "m/84'/0'/0'" },
549
- { hwkChain: "sol", path: import_hwk_adapter_core.CHAIN_FINGERPRINT_PATHS.sol },
550
- { hwkChain: "tron", path: import_hwk_adapter_core.CHAIN_FINGERPRINT_PATHS.tron.replace(/\/0\/0$/, "") }
551
- ];
552
614
  var KeystoneAdapter = class _KeystoneAdapter {
553
615
  constructor(options) {
554
616
  this.vendor = "keystone";
555
- this.emitter = new import_hwk_adapter_core.TypedEventEmitter();
556
- this._uiRegistry = new import_hwk_adapter_core.UiRequestRegistry();
617
+ this.emitter = new import_hwk_adapter_core3.TypedEventEmitter();
618
+ this._interactionRoutes = /* @__PURE__ */ new Map();
619
+ this._interactions = new import_hwk_adapter_core3.InteractionRegistry({
620
+ vendor: "keystone",
621
+ onEnded: (interaction, reason) => {
622
+ const route = this._interactionRoutes.get(interaction.connectId);
623
+ if (route?.interactionId === interaction.interactionId) {
624
+ this._interactionRoutes.delete(interaction.connectId);
625
+ }
626
+ this.emitter.emit(import_hwk_adapter_core3.SDK.INTERACTION_ENDED, {
627
+ type: import_hwk_adapter_core3.SDK.INTERACTION_ENDED,
628
+ payload: { interactionId: interaction.interactionId, reason }
629
+ });
630
+ if (reason === "timeout") {
631
+ this._releaseInteractionConnection(interaction).catch(() => void 0);
632
+ }
633
+ }
634
+ });
635
+ this._uiRegistry = new import_hwk_adapter_core3.UiRequestRegistry();
557
636
  this._devices = /* @__PURE__ */ new Map();
637
+ this._searchDeviceTargets = /* @__PURE__ */ new Map();
638
+ /** Serializes USB open/identity handshakes that run outside the job queue. */
639
+ this._usbConnectTail = Promise.resolve();
640
+ this._unsettledUsbOperations = /* @__PURE__ */ new Map();
641
+ this._usbIdleWaiters = /* @__PURE__ */ new Set();
642
+ this._usbTeardownTail = Promise.resolve();
643
+ this._pendingUsbTeardowns = 0;
644
+ this._handleUsbDisconnect = ({ connectId }) => {
645
+ const record = Array.from(this._devices.values()).find((item) => item.usbSessionId === connectId);
646
+ if (!record) return;
647
+ this._interactions.endByConnectionKey(connectId, "disconnect");
648
+ this._interactions.endByConnectionKey(record.connectId, "disconnect");
649
+ record.usbSessionId = void 0;
650
+ const info = toDeviceInfo(record);
651
+ if (record.qrSynced) {
652
+ this.emitter.emit(import_hwk_adapter_core3.DEVICE.CHANGED, { type: import_hwk_adapter_core3.DEVICE.CHANGED, payload: info });
653
+ } else {
654
+ this._devices.delete(record.walletId);
655
+ this.emitter.emit(import_hwk_adapter_core3.DEVICE.DISCONNECT, { type: import_hwk_adapter_core3.DEVICE.DISCONNECT, payload: info });
656
+ }
657
+ };
658
+ this._handleUsbUiEvent = (event) => {
659
+ this.emitter.emit("ui-event", event);
660
+ };
558
661
  // ---------------------------------------------------------------------------
559
662
  // All-network bundle — dispatches to the same per-chain methods below, so
560
663
  // there's exactly one implementation of each chain's address logic.
561
664
  // ---------------------------------------------------------------------------
562
665
  this.allNetworkGetAddress = async (connectId, deviceId, params) => {
666
+ const operationTarget = resolveHardwareOperationTarget(connectId, params.interactionId);
667
+ if (!operationTarget.success) return operationTarget;
668
+ const effectiveConnectId = operationTarget.payload.targetId ?? "";
669
+ const { interactionId } = operationTarget.payload;
563
670
  try {
564
- return await (0, import_hwk_adapter_core.runAllNetworkGetAddress)({
565
- connectId,
671
+ const prefetched = await this._prefetchAllNetworkAccounts(
672
+ effectiveConnectId,
566
673
  deviceId,
674
+ params
675
+ );
676
+ const { book } = prefetched;
677
+ const itemDeviceId = deviceId || prefetched.walletId || "";
678
+ return await (0, import_hwk_adapter_core3.runAllNetworkGetAddress)({
679
+ connectId: effectiveConnectId,
680
+ deviceId: itemDeviceId,
567
681
  params,
568
- callItem: async ({ chain, item }) => {
569
- const commonArgs = { path: item.path, showOnDevice: item.showOnDevice };
570
- switch (chain) {
571
- case "evm":
572
- return this.evmGetAddress(connectId, deviceId, commonArgs);
573
- case "btc":
574
- return this.btcGetAddress(connectId, deviceId, commonArgs);
575
- case "sol":
576
- return this.solGetAddress(connectId, deviceId, commonArgs);
577
- case "tron":
578
- return this.tronGetAddress(connectId, deviceId, commonArgs);
682
+ callItem: async ({ method, item }) => {
683
+ const commonArgs = {
684
+ path: item.path,
685
+ showOnDevice: item.showOnDevice,
686
+ interactionId
687
+ };
688
+ switch (method) {
689
+ case "evmGetAddress":
690
+ return this.evmGetAddress(effectiveConnectId, itemDeviceId, commonArgs, book);
691
+ case "btcGetAddress":
692
+ return this.btcGetAddress(effectiveConnectId, itemDeviceId, commonArgs, book);
693
+ case "btcGetPublicKey":
694
+ return this.btcGetPublicKey(effectiveConnectId, itemDeviceId, commonArgs, book);
695
+ case "solGetAddress":
696
+ return this.solGetAddress(effectiveConnectId, itemDeviceId, commonArgs, book);
697
+ case "tronGetAddress":
698
+ return this.tronGetAddress(effectiveConnectId, itemDeviceId, commonArgs, book);
579
699
  default:
580
- return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.MethodNotSupported, `Unsupported chain: ${chain}`);
700
+ return (0, import_hwk_adapter_core3.failure)(
701
+ import_hwk_adapter_core3.HardwareErrorCode.MethodNotSupported,
702
+ `Unsupported method: ${String(method)}`
703
+ );
581
704
  }
582
705
  },
583
706
  attachIdentity: (context) => {
584
- const mfp = deviceId ? deviceId.toLowerCase() : void 0;
707
+ const { record } = this._resolveTarget(effectiveConnectId, itemDeviceId);
585
708
  return Promise.resolve({
586
709
  ...context.item,
587
710
  success: true,
588
711
  payload: {
589
712
  ...context.payload,
590
- deviceIdentity: mfp ? { vendor: "keystone", type: "masterFingerprint", value: mfp } : void 0
713
+ rootFingerprint: record ? Number.parseInt(record.masterFingerprint, 16) : void 0,
714
+ deviceIdentity: record ? {
715
+ vendor: "keystone",
716
+ type: "walletId",
717
+ value: record.walletId
718
+ } : void 0
591
719
  }
592
720
  });
593
721
  }
@@ -599,8 +727,10 @@ var KeystoneAdapter = class _KeystoneAdapter {
599
727
  this._origin = options?.origin ?? "OneKey";
600
728
  this._qrTimeoutMs = options?.qrTimeoutMs;
601
729
  this.urEngine = new KeystoneUrEngine(this._origin);
602
- this._jobQueue = new import_hwk_adapter_core.DeviceJobQueue();
730
+ this._jobQueue = new import_hwk_adapter_core3.DeviceJobQueue();
603
731
  this._usbConnector = options?.usbConnector;
732
+ this._usbConnector?.on("device-disconnect", this._handleUsbDisconnect);
733
+ this._usbConnector?.on("ui-event", this._handleUsbUiEvent);
604
734
  }
605
735
  // ---------------------------------------------------------------------------
606
736
  // Lifecycle / transport
@@ -621,56 +751,187 @@ var KeystoneAdapter = class _KeystoneAdapter {
621
751
  init(_config) {
622
752
  return Promise.resolve();
623
753
  }
624
- dispose() {
754
+ async dispose() {
755
+ this._interactions.endAll("runtime-reset");
625
756
  this._uiRegistry.cancel();
626
757
  this._jobQueue.clear();
627
- this.emitter.removeAllListeners();
628
- this._devices.clear();
758
+ this._searchDeviceTargets.clear();
759
+ await this._resetUsbSessions();
760
+ this._usbConnector?.off("device-disconnect", this._handleUsbDisconnect);
761
+ this._usbConnector?.off("ui-event", this._handleUsbUiEvent);
629
762
  this._usbConnector?.reset();
630
- return Promise.resolve();
763
+ this._devices.clear();
764
+ this.emitter.removeAllListeners();
631
765
  }
632
766
  // ---------------------------------------------------------------------------
633
767
  // Device table
634
768
  // ---------------------------------------------------------------------------
635
769
  /**
636
- * QR-synced wallets are always included (this instance's own state — no
637
- * enumeration exists for QR). When a USB connector is configured, its raw
638
- * scan results are appended as-is: a USB descriptor has no mfp until
639
- * `connectDevice()` actually opens+claims it (see
770
+ * Unscoped discovery includes QR-synced wallets already known to this
771
+ * adapter. Explicit QR discovery returns a virtual connection target because
772
+ * there is no physical descriptor to enumerate. When a USB connector is
773
+ * configured, its raw scan results are appended as-is: a USB descriptor has
774
+ * no mfp until `connectDevice()` actually opens+claims it (see
640
775
  * `KeystoneUsbConnectorBase.searchDevices`), so these entries carry an
641
776
  * empty `deviceId` and exist purely so a host can list "plugged in, click
642
777
  * to connect" candidates.
643
778
  */
644
- async searchDevices(_options) {
779
+ async searchDevices(options) {
780
+ const searchGeneration = /* @__PURE__ */ Symbol("keystone-device-search");
781
+ this._activeSearchGeneration = searchGeneration;
782
+ this._searchDeviceTargets.clear();
783
+ if (options?.resetSession) {
784
+ await this._resetUsbSessions();
785
+ } else {
786
+ await this._usbTeardownTail;
787
+ }
645
788
  const known = Array.from(this._devices.values()).map(toDeviceInfo);
646
- if (!this._usbConnector) return known;
789
+ if (options?.transportType === "qr") {
790
+ const searchTargetId = (0, import_hwk_adapter_core3.createHardwareSearchTargetId)({
791
+ vendor: "keystone",
792
+ connectionType: "qr"
793
+ });
794
+ this._searchDeviceTargets.set(searchTargetId, "qr");
795
+ return [
796
+ {
797
+ ...placeholderDeviceInfo(),
798
+ model: "",
799
+ connectId: searchTargetId,
800
+ capabilities: { persistentDeviceIdentity: false }
801
+ }
802
+ ];
803
+ }
804
+ if (options?.transportType === "ble") return [];
805
+ if (!this._usbConnector) return options?.transportType === "usb" ? [] : known;
647
806
  let usbDevices;
648
807
  try {
649
808
  usbDevices = await this._usbConnector.searchDevices();
650
- } catch {
809
+ } catch (error) {
810
+ if (options?.transportType === "usb") throw error;
651
811
  return known;
652
812
  }
813
+ if (this._activeSearchGeneration !== searchGeneration) return [];
653
814
  const placeholders = usbDevices.map((d) => ({
654
815
  vendor: "keystone",
655
- model: d.model ?? "unknown",
816
+ // Empty, not 'unknown': enumeration genuinely cannot tell the model
817
+ // apart (every Keystone shares one vid/pid), and a literal placeholder
818
+ // string would beat the host's own default-name fallback and surface as
819
+ // a device called "unknown".
820
+ model: d.model ?? "",
656
821
  modelName: d.modelName,
822
+ // Placeholders — neither is knowable until the device is opened.
657
823
  firmwareVersion: "0.0.0",
658
824
  deviceId: d.deviceId,
659
825
  connectId: d.connectId,
660
826
  connectionType: "usb",
661
- capabilities: d.capabilities ?? { persistentDeviceIdentity: true }
827
+ // The USB product name, which IS readable at enumeration time.
828
+ label: d.name,
829
+ serialNumber: d.serialNumber,
830
+ capabilities: d.capabilities ?? { persistentDeviceIdentity: false },
831
+ raw: d.raw
662
832
  }));
663
- return [...known, ...placeholders];
833
+ for (const placeholder of placeholders) {
834
+ this._searchDeviceTargets.set(placeholder.connectId, "usb");
835
+ }
836
+ return options?.transportType === "usb" ? placeholders : [...known, ...placeholders];
837
+ }
838
+ async _resetUsbSessions() {
839
+ await this._runUsbTeardown(async () => {
840
+ await this._usbConnectTail;
841
+ this._interactions.endAll("runtime-reset");
842
+ if (!this._usbConnector) return;
843
+ const sessionIds = new Set(
844
+ Array.from(this._devices.values()).map((record) => record.usbSessionId).filter((sessionId) => Boolean(sessionId))
845
+ );
846
+ for (const sessionId of sessionIds) {
847
+ try {
848
+ await this._usbConnector.disconnect(sessionId);
849
+ } catch {
850
+ }
851
+ this._handleUsbDisconnect({ connectId: sessionId });
852
+ }
853
+ });
664
854
  }
665
- async connectDevice(connectId) {
666
- const existing = this._findByConnectId(connectId);
667
- if (existing) return (0, import_hwk_adapter_core.success)(existing.connectId);
668
- if (!this._usbConnector) {
669
- return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.DeviceNotFound, `Unknown Keystone connectId: ${connectId}`);
855
+ async searchDeviceTargets(options) {
856
+ const devices = await this.searchDevices(options);
857
+ return devices.map((device) => ({
858
+ searchTargetId: device.connectId,
859
+ // Keystone's wallet id is stable only after the USB/QR handshake. The
860
+ // selectable handle remains owned by the current discovery snapshot.
861
+ searchTargetReusePolicy: "current-discovery",
862
+ vendor: device.vendor,
863
+ connectionType: device.connectionType,
864
+ kind: device.connectionType === "qr" ? "interactive" : "physical",
865
+ label: device.label,
866
+ model: device.model,
867
+ modelName: device.modelName,
868
+ serialNumber: device.serialNumber
869
+ }));
870
+ }
871
+ async listConnectionTargets(options) {
872
+ const targets = await this.searchDeviceTargets(options);
873
+ return targets.map(({ searchTargetId, ...target }) => ({
874
+ ...target,
875
+ targetId: searchTargetId
876
+ }));
877
+ }
878
+ async connectDevice(searchTargetId) {
879
+ try {
880
+ let connected;
881
+ let selectedConnectionType;
882
+ const discoveredConnectionType = this._searchDeviceTargets.get(searchTargetId);
883
+ if (discoveredConnectionType === "qr") {
884
+ selectedConnectionType = "qr";
885
+ connected = await this.importFromQr();
886
+ } else if (discoveredConnectionType === "usb") {
887
+ selectedConnectionType = "usb";
888
+ if (!this._usbConnector) {
889
+ return (0, import_hwk_adapter_core3.failure)(
890
+ import_hwk_adapter_core3.HardwareErrorCode.TransportNotAvailable,
891
+ "No USB connector configured for this Keystone adapter"
892
+ );
893
+ }
894
+ connected = await this._connectUsb({}, searchTargetId);
895
+ } else if ((0, import_hwk_adapter_core3.hasHardwareRuntimeIdPrefix)(searchTargetId)) {
896
+ return (0, import_hwk_adapter_core3.failure)(
897
+ import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound,
898
+ "Keystone search target has expired; search for devices again",
899
+ void 0,
900
+ void 0,
901
+ { scope: "search-target" }
902
+ );
903
+ } else {
904
+ const target = this._resolveTarget(searchTargetId);
905
+ if (target.record) {
906
+ selectedConnectionType = target.record.usbSessionId ? "usb" : "qr";
907
+ connected = (0, import_hwk_adapter_core3.success)(toDeviceInfo(target.record));
908
+ } else if (!this._usbConnector) {
909
+ return (0, import_hwk_adapter_core3.failure)(
910
+ import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound,
911
+ `Unknown Keystone device search target: ${searchTargetId}`
912
+ );
913
+ } else {
914
+ selectedConnectionType = "usb";
915
+ connected = await this._connectUsb(target);
916
+ }
917
+ }
918
+ if (!connected.success) return connected;
919
+ const record = this._devices.get(connected.payload.deviceId);
920
+ this._interactions.endByConnectionKey(connected.payload.connectId, "explicit");
921
+ const interaction = this._interactions.create({
922
+ searchTargetId,
923
+ connectId: connected.payload.connectId,
924
+ device: connected.payload,
925
+ connectionKeys: selectedConnectionType === "usb" && record?.usbSessionId ? [record.usbSessionId] : []
926
+ });
927
+ this._interactionRoutes.set(connected.payload.connectId, {
928
+ interactionId: interaction.interactionId,
929
+ connectionType: selectedConnectionType
930
+ });
931
+ return (0, import_hwk_adapter_core3.success)(interaction.interactionId);
932
+ } catch (err) {
933
+ return this._errorToFailure(err);
670
934
  }
671
- const result = await this._connectUsb();
672
- if (!result.success) return result;
673
- return (0, import_hwk_adapter_core.success)(result.payload.connectId);
674
935
  }
675
936
  /**
676
937
  * QR has no persistent connection to tear down — the account cache
@@ -679,57 +940,87 @@ var KeystoneAdapter = class _KeystoneAdapter {
679
940
  * QR-only (if it was ever QR-synced) or removes it entirely (pure-USB
680
941
  * wallet that was never seen over QR) — see §4.2 of the design doc.
681
942
  */
682
- async disconnectDevice(connectId) {
683
- const record = this._findByConnectId(connectId);
684
- if (!record?.usbSessionId) return;
685
- if (this._usbConnector) {
686
- try {
687
- await this._usbConnector.disconnect(record.usbSessionId);
688
- } catch {
689
- }
943
+ async releaseInteraction(interactionId) {
944
+ const interaction = this._interactions.find(interactionId);
945
+ if (!interaction) {
946
+ this._interactions.resolve(interactionId);
947
+ return;
690
948
  }
691
- record.usbSessionId = void 0;
692
- if (record.qrSynced) {
693
- const info = toDeviceInfo(record);
694
- this.emitter.emit(import_hwk_adapter_core.DEVICE.CHANGED, { type: import_hwk_adapter_core.DEVICE.CHANGED, payload: info });
695
- } else {
696
- this._devices.delete(record.masterFingerprint);
697
- const info = toDeviceInfo(record);
698
- this.emitter.emit(import_hwk_adapter_core.DEVICE.DISCONNECT, { type: import_hwk_adapter_core.DEVICE.DISCONNECT, payload: info });
949
+ const endedInteraction = this._interactions.end(interactionId, "explicit");
950
+ if (!endedInteraction) return;
951
+ await this._releaseInteractionConnection(endedInteraction);
952
+ }
953
+ async _releaseInteractionConnection(interaction) {
954
+ const { connectId } = interaction;
955
+ let record;
956
+ try {
957
+ record = this._resolveTarget(connectId).record;
958
+ } catch {
959
+ return;
960
+ }
961
+ if (!record?.usbSessionId || !interaction.connectionKeys.includes(record.usbSessionId)) {
962
+ return;
699
963
  }
964
+ const { usbSessionId } = record;
965
+ await this._runUsbTeardown(async () => {
966
+ if (this._usbConnector) {
967
+ try {
968
+ await this._usbConnector.disconnect(usbSessionId);
969
+ } catch {
970
+ }
971
+ }
972
+ this._handleUsbDisconnect({ connectId: usbSessionId });
973
+ });
700
974
  }
701
- getDeviceInfo(connectId, deviceId) {
702
- const record = this._findByConnectId(connectId) ?? this._devices.get(deviceId.toLowerCase());
703
- if (!record) {
704
- return Promise.resolve(
705
- (0, import_hwk_adapter_core.failure)(
706
- import_hwk_adapter_core.HardwareErrorCode.DeviceNotFound,
707
- `Unknown Keystone device: ${connectId || deviceId}`
708
- )
709
- );
975
+ getDeviceInfo(connectIdOrInteractionId, deviceId) {
976
+ try {
977
+ const connectId = (0, import_hwk_adapter_core3.isHardwareInteractionId)(connectIdOrInteractionId) ? this._interactions.resolve(connectIdOrInteractionId).connectId : connectIdOrInteractionId;
978
+ const { record } = this._resolveTarget(connectId, deviceId);
979
+ if (!record) {
980
+ return Promise.resolve(
981
+ (0, import_hwk_adapter_core3.failure)(
982
+ import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound,
983
+ `Unknown Keystone device: ${connectId || deviceId}`
984
+ )
985
+ );
986
+ }
987
+ return Promise.resolve((0, import_hwk_adapter_core3.success)(toDeviceInfo(record)));
988
+ } catch (err) {
989
+ return Promise.resolve(this._errorToFailure(err));
710
990
  }
711
- return Promise.resolve((0, import_hwk_adapter_core.success)(toDeviceInfo(record)));
712
991
  }
713
992
  getSupportedChains() {
714
993
  return ["evm", "btc", "sol", "tron"];
715
994
  }
716
995
  cancel(connectId) {
717
- const reason = (0, import_hwk_adapter_core.createHwkError)({
718
- code: import_hwk_adapter_core.HardwareErrorCode.UserAborted,
996
+ const reason = (0, import_hwk_adapter_core3.createHwkError)({
997
+ code: import_hwk_adapter_core3.HardwareErrorCode.UserAborted,
719
998
  message: "User aborted operation"
720
999
  });
721
1000
  this._uiRegistry.cancel();
722
- this._jobQueue.cancelActiveAndPending(connectId, reason);
1001
+ const activeJobId = this._jobQueue.getActiveJob()?.deviceId;
1002
+ const targetId = connectId ?? activeJobId;
1003
+ this._jobQueue.cancelActiveAndPending(
1004
+ targetId && (0, import_hwk_adapter_core3.isHardwareInteractionId)(targetId) ? activeJobId ?? targetId : targetId,
1005
+ reason
1006
+ );
723
1007
  }
724
1008
  getChainFingerprint(connectId, deviceId, chain) {
725
- const mfp = deviceId ? deviceId.toLowerCase() : this._mfpFromConnectId(connectId);
726
- if (!mfp) {
727
- return Promise.resolve((0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.DeviceNotFound, "Unknown Keystone device"));
1009
+ try {
1010
+ const target = this._resolveTarget(connectId, deviceId);
1011
+ const walletId = target.record?.walletId ?? target.expectedWalletId;
1012
+ if (!walletId) {
1013
+ return Promise.resolve(
1014
+ (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound, "Unknown Keystone wallet identity")
1015
+ );
1016
+ }
1017
+ return Promise.resolve((0, import_hwk_adapter_core3.success)((0, import_hwk_adapter_core3.deriveDeviceFingerprint)(`keystone:${chain}:${walletId}`)));
1018
+ } catch (err) {
1019
+ return Promise.resolve(this._errorToFailure(err));
728
1020
  }
729
- return Promise.resolve((0, import_hwk_adapter_core.success)((0, import_hwk_adapter_core.deriveDeviceFingerprint)(`keystone:${chain}:${mfp}`)));
730
1021
  }
731
1022
  uiResponse(response) {
732
- if (response.type === import_hwk_adapter_core.UI_RESPONSE.CANCEL) {
1023
+ if (response.type === import_hwk_adapter_core3.UI_RESPONSE.CANCEL) {
733
1024
  this.cancel();
734
1025
  return;
735
1026
  }
@@ -750,17 +1041,11 @@ var KeystoneAdapter = class _KeystoneAdapter {
750
1041
  return await this._jobQueue.enqueue(COLD_START_JOB_LABEL, async (signal) => {
751
1042
  const displayDevice = placeholderDeviceInfo();
752
1043
  let responseUr;
753
- let requestedChains;
754
1044
  if (options.mode === "scan") {
755
1045
  responseUr = await this._requestQrScanAndAwaitResponse(displayDevice);
756
1046
  } else {
757
- const schemas = options.paths?.length ? options.paths : DEFAULT_IMPORT_SCHEMAS;
758
- requestedChains = schemas.map((s) => s.hwkChain);
759
1047
  const requestUr = this.urEngine.buildKeyDerivationRequest({
760
- schemas: schemas.map((s) => ({
761
- path: s.path,
762
- curve: s.hwkChain === "sol" ? "ed25519" : "secp256k1"
763
- })),
1048
+ schemas: [{ path: KEYSTONE_WALLET_ID_PATH, curve: "secp256k1" }],
764
1049
  origin: this._origin
765
1050
  });
766
1051
  responseUr = await this._requestQrDisplayAndAwaitResponse(displayDevice, {
@@ -771,14 +1056,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
771
1056
  _KeystoneAdapter._throwIfAborted(signal);
772
1057
  const parsed = this.urEngine.parseAccountResponse(responseUr);
773
1058
  const record = this._upsertDeviceRecord(parsed);
774
- for (const account of parsed.accounts) {
775
- const hwkChain = requestedChains?.length === 1 ? requestedChains[0] : inferHwkChainFromPath(account.path);
776
- if (hwkChain) {
777
- const entry = { ...account, hwkChain };
778
- record.accounts.set(accountKey(hwkChain, account.path), entry);
779
- }
780
- }
781
- return (0, import_hwk_adapter_core.success)(toDeviceInfo(record));
1059
+ return (0, import_hwk_adapter_core3.success)(toDeviceInfo(record));
782
1060
  });
783
1061
  } catch (err) {
784
1062
  return this._errorToFailure(err);
@@ -787,17 +1065,19 @@ var KeystoneAdapter = class _KeystoneAdapter {
787
1065
  // ---------------------------------------------------------------------------
788
1066
  // EVM
789
1067
  // ---------------------------------------------------------------------------
790
- async evmGetAddress(connectIdArg, deviceIdArg, paramsArg) {
791
- const connectId = connectIdArg ?? void 0;
1068
+ async evmGetAddress(connectIdArg, deviceIdArg, paramsArg, book) {
1069
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1070
+ if (!operationTarget.success) return operationTarget;
1071
+ const connectId = operationTarget.payload.targetId;
792
1072
  const deviceId = deviceIdArg ?? void 0;
793
1073
  const params = paramsArg;
794
- if (!params) return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "evmGetAddress requires params");
1074
+ if (!params) return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "evmGetAddress requires params");
795
1075
  if (!params.path)
796
- return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "evmGetAddress requires params.path");
1076
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "evmGetAddress requires params.path");
797
1077
  const { accountPath, relativeDerivePath } = splitAccountPath(params.path);
798
1078
  if (!relativeDerivePath) {
799
- return (0, import_hwk_adapter_core.failure)(
800
- import_hwk_adapter_core.HardwareErrorCode.InvalidParams,
1079
+ return (0, import_hwk_adapter_core3.failure)(
1080
+ import_hwk_adapter_core3.HardwareErrorCode.InvalidParams,
801
1081
  "evmGetAddress requires a full leaf path, e.g. m/44'/60'/0'/0/0"
802
1082
  );
803
1083
  }
@@ -805,17 +1085,18 @@ var KeystoneAdapter = class _KeystoneAdapter {
805
1085
  return await this._jobQueue.enqueue(
806
1086
  deviceId ?? connectId ?? COLD_START_JOB_LABEL,
807
1087
  async (signal) => {
808
- const { account } = await this._ensureAccountSynced(
1088
+ const { account } = await this._fetchAccount(
809
1089
  connectId,
810
1090
  deviceId,
811
1091
  "evm",
812
1092
  accountPath,
813
- signal
1093
+ signal,
1094
+ { book }
814
1095
  );
815
1096
  _KeystoneAdapter._throwIfAborted(signal);
816
1097
  if (!account.extendedPublicKey) {
817
- throw (0, import_hwk_adapter_core.createHwkError)({
818
- code: import_hwk_adapter_core.HardwareErrorCode.MethodNotSupported,
1098
+ throw (0, import_hwk_adapter_core3.createHwkError)({
1099
+ code: import_hwk_adapter_core3.HardwareErrorCode.MethodNotSupported,
819
1100
  message: "Keystone did not return an extended public key for this account path"
820
1101
  });
821
1102
  }
@@ -823,7 +1104,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
823
1104
  account.extendedPublicKey,
824
1105
  relativeDerivePath
825
1106
  );
826
- return (0, import_hwk_adapter_core.success)({ address, path: normalizePath(params.path) });
1107
+ return (0, import_hwk_adapter_core3.success)({ address, path: normalizePath(params.path) });
827
1108
  }
828
1109
  );
829
1110
  } catch (err) {
@@ -831,27 +1112,29 @@ var KeystoneAdapter = class _KeystoneAdapter {
831
1112
  }
832
1113
  }
833
1114
  async evmSignTransaction(connectIdArg, deviceIdArg, paramsArg) {
834
- const connectId = connectIdArg ?? void 0;
1115
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1116
+ if (!operationTarget.success) return operationTarget;
1117
+ const connectId = operationTarget.payload.targetId;
835
1118
  const deviceId = deviceIdArg ?? void 0;
836
1119
  const params = paramsArg;
837
1120
  if (!params)
838
- return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "evmSignTransaction requires params");
1121
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "evmSignTransaction requires params");
839
1122
  if (!params.path) {
840
- return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "evmSignTransaction requires params.path");
1123
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "evmSignTransaction requires params.path");
841
1124
  }
842
1125
  if (!("serializedTx" in params) || typeof params.serializedTx !== "string" || !params.serializedTx) {
843
- return (0, import_hwk_adapter_core.failure)(
844
- import_hwk_adapter_core.HardwareErrorCode.MethodNotSupported,
1126
+ return (0, import_hwk_adapter_core3.failure)(
1127
+ import_hwk_adapter_core3.HardwareErrorCode.MethodNotSupported,
845
1128
  "Keystone only signs a fully RLP-serialized transaction (params.serializedTx) \u2014 structured-field signing is not supported"
846
1129
  );
847
1130
  }
848
- const rawTxHex = (0, import_hwk_adapter_core.stripHex)(params.serializedTx);
1131
+ const rawTxHex = (0, import_hwk_adapter_core3.stripHex)(params.serializedTx);
849
1132
  const path = normalizePath(params.path);
850
1133
  try {
851
1134
  return await this._jobQueue.enqueue(
852
1135
  deviceId ?? connectId ?? COLD_START_JOB_LABEL,
853
1136
  async (signal) => {
854
- const { record } = await this._ensureMfpKnown(connectId, deviceId, "evm", signal);
1137
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "evm", signal);
855
1138
  _KeystoneAdapter._throwIfAborted(signal);
856
1139
  const requestId = (0, import_uuid2.v4)();
857
1140
  const dataType = parseInt(rawTxHex.slice(0, 2), 16) < 192 ? "typedTransaction" : "transaction";
@@ -863,14 +1146,21 @@ var KeystoneAdapter = class _KeystoneAdapter {
863
1146
  xfp: record.masterFingerprint,
864
1147
  chainId: params.chainId
865
1148
  });
866
- const responseUr = await this._resolveUr(record, requestUr, true);
1149
+ const responseUr = await this._resolveUr(
1150
+ record,
1151
+ requestUr,
1152
+ true,
1153
+ connectId,
1154
+ signal,
1155
+ "evmSignTransaction"
1156
+ );
867
1157
  _KeystoneAdapter._throwIfAborted(signal);
868
1158
  const sig = this.urEngine.parseEthSignature(responseUr);
869
1159
  _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
870
- return (0, import_hwk_adapter_core.success)({
871
- v: (0, import_hwk_adapter_core.ensure0x)(sig.v),
872
- r: (0, import_hwk_adapter_core.ensure0x)(sig.r),
873
- s: (0, import_hwk_adapter_core.ensure0x)(sig.s)
1160
+ return (0, import_hwk_adapter_core3.success)({
1161
+ v: (0, import_hwk_adapter_core3.ensure0x)(sig.v),
1162
+ r: (0, import_hwk_adapter_core3.ensure0x)(sig.r),
1163
+ s: (0, import_hwk_adapter_core3.ensure0x)(sig.s)
874
1164
  });
875
1165
  }
876
1166
  );
@@ -879,23 +1169,25 @@ var KeystoneAdapter = class _KeystoneAdapter {
879
1169
  }
880
1170
  }
881
1171
  async evmSignMessage(connectIdArg, deviceIdArg, paramsArg) {
882
- const connectId = connectIdArg ?? void 0;
1172
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1173
+ if (!operationTarget.success) return operationTarget;
1174
+ const connectId = operationTarget.payload.targetId;
883
1175
  const deviceId = deviceIdArg ?? void 0;
884
1176
  const params = paramsArg;
885
- if (!params) return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "evmSignMessage requires params");
1177
+ if (!params) return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "evmSignMessage requires params");
886
1178
  if (!params.path || params.message === void 0) {
887
- return (0, import_hwk_adapter_core.failure)(
888
- import_hwk_adapter_core.HardwareErrorCode.InvalidParams,
1179
+ return (0, import_hwk_adapter_core3.failure)(
1180
+ import_hwk_adapter_core3.HardwareErrorCode.InvalidParams,
889
1181
  "evmSignMessage requires params.path and params.message"
890
1182
  );
891
1183
  }
892
- const messageHex = params.hex ? (0, import_hwk_adapter_core.stripHex)(params.message) : Buffer.from(params.message, "utf8").toString("hex");
1184
+ const messageHex = params.hex ? (0, import_hwk_adapter_core3.stripHex)(params.message) : Buffer.from(params.message, "utf8").toString("hex");
893
1185
  const path = normalizePath(params.path);
894
1186
  try {
895
1187
  return await this._jobQueue.enqueue(
896
1188
  deviceId ?? connectId ?? COLD_START_JOB_LABEL,
897
1189
  async (signal) => {
898
- const { record } = await this._ensureMfpKnown(connectId, deviceId, "evm", signal);
1190
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "evm", signal);
899
1191
  _KeystoneAdapter._throwIfAborted(signal);
900
1192
  const requestId = (0, import_uuid2.v4)();
901
1193
  const requestUr = this.urEngine.buildEthSignRequest({
@@ -906,11 +1198,18 @@ var KeystoneAdapter = class _KeystoneAdapter {
906
1198
  xfp: record.masterFingerprint,
907
1199
  chainId: params.chainId
908
1200
  });
909
- const responseUr = await this._resolveUr(record, requestUr, true);
1201
+ const responseUr = await this._resolveUr(
1202
+ record,
1203
+ requestUr,
1204
+ true,
1205
+ connectId,
1206
+ signal,
1207
+ "evmSignMessage"
1208
+ );
910
1209
  _KeystoneAdapter._throwIfAborted(signal);
911
1210
  const sig = this.urEngine.parseEthSignature(responseUr);
912
1211
  _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
913
- return (0, import_hwk_adapter_core.success)({ signature: (0, import_hwk_adapter_core.ensure0x)(sig.r + sig.s + sig.v) });
1212
+ return (0, import_hwk_adapter_core3.success)({ signature: (0, import_hwk_adapter_core3.ensure0x)(sig.r + sig.s + sig.v) });
914
1213
  }
915
1214
  );
916
1215
  } catch (err) {
@@ -918,17 +1217,19 @@ var KeystoneAdapter = class _KeystoneAdapter {
918
1217
  }
919
1218
  }
920
1219
  async evmSignTypedData(connectIdArg, deviceIdArg, paramsArg) {
921
- const connectId = connectIdArg ?? void 0;
1220
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1221
+ if (!operationTarget.success) return operationTarget;
1222
+ const connectId = operationTarget.payload.targetId;
922
1223
  const deviceId = deviceIdArg ?? void 0;
923
1224
  const params = paramsArg;
924
1225
  if (!params)
925
- return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "evmSignTypedData requires params");
1226
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "evmSignTypedData requires params");
926
1227
  if (!params.path) {
927
- return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "evmSignTypedData requires params.path");
1228
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "evmSignTypedData requires params.path");
928
1229
  }
929
1230
  if (params.mode === "hash") {
930
- return (0, import_hwk_adapter_core.failure)(
931
- import_hwk_adapter_core.HardwareErrorCode.MethodNotSupported,
1231
+ return (0, import_hwk_adapter_core3.failure)(
1232
+ import_hwk_adapter_core3.HardwareErrorCode.MethodNotSupported,
932
1233
  "Keystone always displays the full EIP-712 payload for on-device review \u2014 pre-hashed signing is not supported"
933
1234
  );
934
1235
  }
@@ -938,7 +1239,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
938
1239
  return await this._jobQueue.enqueue(
939
1240
  deviceId ?? connectId ?? COLD_START_JOB_LABEL,
940
1241
  async (signal) => {
941
- const { record } = await this._ensureMfpKnown(connectId, deviceId, "evm", signal);
1242
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "evm", signal);
942
1243
  _KeystoneAdapter._throwIfAborted(signal);
943
1244
  const requestId = (0, import_uuid2.v4)();
944
1245
  const requestUr = this.urEngine.buildEthSignRequest({
@@ -949,11 +1250,18 @@ var KeystoneAdapter = class _KeystoneAdapter {
949
1250
  xfp: record.masterFingerprint,
950
1251
  chainId: params.chainId
951
1252
  });
952
- const responseUr = await this._resolveUr(record, requestUr, true);
1253
+ const responseUr = await this._resolveUr(
1254
+ record,
1255
+ requestUr,
1256
+ true,
1257
+ connectId,
1258
+ signal,
1259
+ "evmSignTypedData"
1260
+ );
953
1261
  _KeystoneAdapter._throwIfAborted(signal);
954
1262
  const sig = this.urEngine.parseEthSignature(responseUr);
955
1263
  _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
956
- return (0, import_hwk_adapter_core.success)({ signature: (0, import_hwk_adapter_core.ensure0x)(sig.r + sig.s + sig.v) });
1264
+ return (0, import_hwk_adapter_core3.success)({ signature: (0, import_hwk_adapter_core3.ensure0x)(sig.r + sig.s + sig.v) });
957
1265
  }
958
1266
  );
959
1267
  } catch (err) {
@@ -966,17 +1274,19 @@ var KeystoneAdapter = class _KeystoneAdapter {
966
1274
  // phase doesn't wire in yet; structured-field tx signing needs host-side
967
1275
  // PSBT construction. Both are real, bounded follow-ups, not silent gaps.
968
1276
  // ---------------------------------------------------------------------------
969
- async btcGetAddress(connectIdArg, deviceIdArg, paramsArg) {
970
- const connectId = connectIdArg ?? void 0;
1277
+ async btcGetAddress(connectIdArg, deviceIdArg, paramsArg, book) {
1278
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1279
+ if (!operationTarget.success) return operationTarget;
1280
+ const connectId = operationTarget.payload.targetId;
971
1281
  const deviceId = deviceIdArg ?? void 0;
972
1282
  const params = paramsArg;
973
- if (!params) return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "btcGetAddress requires params");
1283
+ if (!params) return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "btcGetAddress requires params");
974
1284
  if (!params.path)
975
- return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "btcGetAddress requires params.path");
1285
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "btcGetAddress requires params.path");
976
1286
  const scriptType = btcScriptTypeFromPath(params.path);
977
1287
  if (!scriptType) {
978
- return (0, import_hwk_adapter_core.failure)(
979
- import_hwk_adapter_core.HardwareErrorCode.InvalidParams,
1288
+ return (0, import_hwk_adapter_core3.failure)(
1289
+ import_hwk_adapter_core3.HardwareErrorCode.InvalidParams,
980
1290
  "btcGetAddress requires a path whose purpose is 44'/49'/84'/86' (P2PKH/P2SH-P2WPKH/P2WPKH/P2TR)"
981
1291
  );
982
1292
  }
@@ -986,28 +1296,33 @@ var KeystoneAdapter = class _KeystoneAdapter {
986
1296
  "P2TR (purpose 86') needs an elliptic-curve library for BIP-341 tweaking, not yet wired in \u2014 44'/49'/84' work"
987
1297
  );
988
1298
  }
989
- const { accountPath, relativeDerivePath } = splitAccountPath(params.path);
1299
+ const normalizedPath = normalizePath(params.path);
1300
+ const { accountPath, relativeDerivePath } = splitAccountPath(normalizedPath);
990
1301
  if (!relativeDerivePath) {
991
- return (0, import_hwk_adapter_core.failure)(
992
- import_hwk_adapter_core.HardwareErrorCode.InvalidParams,
1302
+ return (0, import_hwk_adapter_core3.failure)(
1303
+ import_hwk_adapter_core3.HardwareErrorCode.InvalidParams,
993
1304
  "btcGetAddress requires a full leaf path, e.g. m/84'/0'/0'/0/0"
994
1305
  );
995
1306
  }
1307
+ if (!isKeystoneSignableBtcAccountPath(accountPath)) {
1308
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.DevicePathForbidden, KEYSTONE_BTC_ACCOUNT_FORBIDDEN_MESSAGE);
1309
+ }
996
1310
  try {
997
1311
  return await this._jobQueue.enqueue(
998
1312
  deviceId ?? connectId ?? COLD_START_JOB_LABEL,
999
1313
  async (signal) => {
1000
- const { account } = await this._ensureAccountSynced(
1314
+ const { account } = await this._fetchAccount(
1001
1315
  connectId,
1002
1316
  deviceId,
1003
1317
  "btc",
1004
1318
  accountPath,
1005
- signal
1319
+ signal,
1320
+ { book }
1006
1321
  );
1007
1322
  _KeystoneAdapter._throwIfAborted(signal);
1008
1323
  if (!account.extendedPublicKey) {
1009
- throw (0, import_hwk_adapter_core.createHwkError)({
1010
- code: import_hwk_adapter_core.HardwareErrorCode.MethodNotSupported,
1324
+ throw (0, import_hwk_adapter_core3.createHwkError)({
1325
+ code: import_hwk_adapter_core3.HardwareErrorCode.MethodNotSupported,
1011
1326
  message: "Keystone did not return an extended public key for this account path"
1012
1327
  });
1013
1328
  }
@@ -1016,18 +1331,74 @@ var KeystoneAdapter = class _KeystoneAdapter {
1016
1331
  relativeDerivePath,
1017
1332
  scriptType
1018
1333
  );
1019
- return (0, import_hwk_adapter_core.success)({ address, path: normalizePath(params.path) });
1334
+ return (0, import_hwk_adapter_core3.success)({ address, path: normalizedPath });
1020
1335
  }
1021
1336
  );
1022
1337
  } catch (err) {
1023
1338
  return this._errorToFailure(err);
1024
1339
  }
1025
1340
  }
1026
- async btcGetPublicKey(_connectId, _deviceId, _params) {
1027
- return this._unsupported(
1028
- "btcGetPublicKey",
1029
- "not yet wired \u2014 the underlying synced xpub/chainCode data already exists in the device table"
1030
- );
1341
+ /**
1342
+ * Returns the account-level extended public key. `params.path` must be an
1343
+ * ACCOUNT path (`m/84'/0'/0'`), not a leaf — that is the level Keystone
1344
+ * actually syncs, and it is what a host needs to derive a whole account's
1345
+ * addresses offline. Unlike `btcGetAddress` this has no script-type
1346
+ * restriction: an xpub is script-type agnostic, so `86'` (taproot) works
1347
+ * here even though deriving a taproot ADDRESS still needs an EC library
1348
+ * this package doesn't wire in.
1349
+ */
1350
+ async btcGetPublicKey(connectIdArg, deviceIdArg, paramsArg, book) {
1351
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1352
+ if (!operationTarget.success) return operationTarget;
1353
+ const connectId = operationTarget.payload.targetId;
1354
+ const deviceId = deviceIdArg ?? void 0;
1355
+ const params = paramsArg;
1356
+ if (!params) return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "btcGetPublicKey requires params");
1357
+ if (!params.path)
1358
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "btcGetPublicKey requires params.path");
1359
+ const { accountPath, relativeDerivePath } = splitAccountPath(params.path);
1360
+ if (relativeDerivePath) {
1361
+ return (0, import_hwk_adapter_core3.failure)(
1362
+ import_hwk_adapter_core3.HardwareErrorCode.InvalidParams,
1363
+ "btcGetPublicKey requires an account path, e.g. m/84'/0'/0' (not a leaf path)"
1364
+ );
1365
+ }
1366
+ if (!isKeystoneSignableBtcAccountPath(accountPath)) {
1367
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.DevicePathForbidden, KEYSTONE_BTC_ACCOUNT_FORBIDDEN_MESSAGE);
1368
+ }
1369
+ try {
1370
+ return await this._jobQueue.enqueue(
1371
+ deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1372
+ async (signal) => {
1373
+ const { account } = await this._fetchAccount(
1374
+ connectId,
1375
+ deviceId,
1376
+ "btc",
1377
+ accountPath,
1378
+ signal,
1379
+ { book }
1380
+ );
1381
+ _KeystoneAdapter._throwIfAborted(signal);
1382
+ if (!account.extendedPublicKey) {
1383
+ throw (0, import_hwk_adapter_core3.createHwkError)({
1384
+ code: import_hwk_adapter_core3.HardwareErrorCode.MethodNotSupported,
1385
+ message: "Keystone did not return an extended public key for this account path"
1386
+ });
1387
+ }
1388
+ const meta = this.urEngine.parseXpubMeta(account.extendedPublicKey);
1389
+ return (0, import_hwk_adapter_core3.success)({
1390
+ xpub: account.extendedPublicKey,
1391
+ publicKey: meta.publicKey,
1392
+ chainCode: meta.chainCode,
1393
+ depth: meta.depth,
1394
+ fingerprint: meta.parentFingerprint,
1395
+ path: normalizePath(accountPath)
1396
+ });
1397
+ }
1398
+ );
1399
+ } catch (err) {
1400
+ return this._errorToFailure(err);
1401
+ }
1031
1402
  }
1032
1403
  async btcSignTransaction(_connectId, _deviceId, _params) {
1033
1404
  return this._unsupported(
@@ -1036,23 +1407,35 @@ var KeystoneAdapter = class _KeystoneAdapter {
1036
1407
  );
1037
1408
  }
1038
1409
  async btcSignPsbt(connectIdArg, deviceIdArg, paramsArg) {
1039
- const connectId = connectIdArg ?? void 0;
1410
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1411
+ if (!operationTarget.success) return operationTarget;
1412
+ const connectId = operationTarget.payload.targetId;
1040
1413
  const deviceId = deviceIdArg ?? void 0;
1041
1414
  const params = paramsArg;
1042
- if (!params) return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "btcSignPsbt requires params");
1415
+ if (!params) return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "btcSignPsbt requires params");
1043
1416
  if (!params.psbt)
1044
- return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "btcSignPsbt requires params.psbt");
1417
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "btcSignPsbt requires params.psbt");
1418
+ if (params.path && !isKeystoneSignableBtcAccountPath(splitAccountPath(params.path).accountPath)) {
1419
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.DevicePathForbidden, KEYSTONE_BTC_ACCOUNT_FORBIDDEN_MESSAGE);
1420
+ }
1045
1421
  try {
1046
1422
  return await this._jobQueue.enqueue(
1047
1423
  deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1048
1424
  async (signal) => {
1049
- const { record } = await this._ensureMfpKnown(connectId, deviceId, "btc", signal);
1425
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "btc", signal);
1050
1426
  _KeystoneAdapter._throwIfAborted(signal);
1051
- const requestUr = this.urEngine.buildBtcPsbtRequest((0, import_hwk_adapter_core.stripHex)(params.psbt));
1052
- const responseUr = await this._resolveUr(record, requestUr, true);
1427
+ const requestUr = this.urEngine.buildBtcPsbtRequest((0, import_hwk_adapter_core3.stripHex)(params.psbt));
1428
+ const responseUr = await this._resolveUr(
1429
+ record,
1430
+ requestUr,
1431
+ true,
1432
+ connectId,
1433
+ signal,
1434
+ "btcSignPsbt"
1435
+ );
1053
1436
  _KeystoneAdapter._throwIfAborted(signal);
1054
1437
  const signedPsbt = this.urEngine.parseBtcPsbt(responseUr);
1055
- return (0, import_hwk_adapter_core.success)({ signedPsbt });
1438
+ return (0, import_hwk_adapter_core3.success)({ signedPsbt });
1056
1439
  }
1057
1440
  );
1058
1441
  } catch (err) {
@@ -1060,23 +1443,28 @@ var KeystoneAdapter = class _KeystoneAdapter {
1060
1443
  }
1061
1444
  }
1062
1445
  async btcSignMessage(connectIdArg, deviceIdArg, paramsArg) {
1063
- const connectId = connectIdArg ?? void 0;
1446
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1447
+ if (!operationTarget.success) return operationTarget;
1448
+ const connectId = operationTarget.payload.targetId;
1064
1449
  const deviceId = deviceIdArg ?? void 0;
1065
1450
  const params = paramsArg;
1066
- if (!params) return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "btcSignMessage requires params");
1451
+ if (!params) return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "btcSignMessage requires params");
1067
1452
  if (!params.path || params.message === void 0) {
1068
- return (0, import_hwk_adapter_core.failure)(
1069
- import_hwk_adapter_core.HardwareErrorCode.InvalidParams,
1453
+ return (0, import_hwk_adapter_core3.failure)(
1454
+ import_hwk_adapter_core3.HardwareErrorCode.InvalidParams,
1070
1455
  "btcSignMessage requires params.path and params.message"
1071
1456
  );
1072
1457
  }
1073
- const messageHex = params.hex ? (0, import_hwk_adapter_core.stripHex)(params.message) : Buffer.from(params.message, "utf8").toString("hex");
1458
+ const messageHex = params.hex ? (0, import_hwk_adapter_core3.stripHex)(params.message) : Buffer.from(params.message, "utf8").toString("hex");
1074
1459
  const path = normalizePath(params.path);
1460
+ if (!isKeystoneSignableBtcAccountPath(splitAccountPath(path).accountPath)) {
1461
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.DevicePathForbidden, KEYSTONE_BTC_ACCOUNT_FORBIDDEN_MESSAGE);
1462
+ }
1075
1463
  try {
1076
1464
  return await this._jobQueue.enqueue(
1077
1465
  deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1078
1466
  async (signal) => {
1079
- const { record } = await this._ensureMfpKnown(connectId, deviceId, "btc", signal);
1467
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "btc", signal);
1080
1468
  _KeystoneAdapter._throwIfAborted(signal);
1081
1469
  const requestId = (0, import_uuid2.v4)();
1082
1470
  const requestUr = this.urEngine.buildBtcMessageSignRequest({
@@ -1084,26 +1472,35 @@ var KeystoneAdapter = class _KeystoneAdapter {
1084
1472
  messageHex,
1085
1473
  accounts: [{ path, xfp: record.masterFingerprint }]
1086
1474
  });
1087
- const responseUr = await this._resolveUr(record, requestUr, true);
1475
+ const responseUr = await this._resolveUr(
1476
+ record,
1477
+ requestUr,
1478
+ true,
1479
+ connectId,
1480
+ signal,
1481
+ "btcSignMessage"
1482
+ );
1088
1483
  _KeystoneAdapter._throwIfAborted(signal);
1089
1484
  const sig = this.urEngine.parseBtcSignature(responseUr);
1090
1485
  _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1091
- return (0, import_hwk_adapter_core.success)({ signature: sig.signature });
1486
+ return (0, import_hwk_adapter_core3.success)({ signature: sig.signature });
1092
1487
  }
1093
1488
  );
1094
1489
  } catch (err) {
1095
1490
  return this._errorToFailure(err);
1096
1491
  }
1097
1492
  }
1098
- async btcGetMasterFingerprint(connectIdArg, deviceIdArg) {
1099
- const connectId = connectIdArg ?? void 0;
1493
+ async btcGetMasterFingerprint(connectIdArg, deviceIdArg, paramsArg) {
1494
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1495
+ if (!operationTarget.success) return operationTarget;
1496
+ const connectId = operationTarget.payload.targetId;
1100
1497
  const deviceId = deviceIdArg ?? void 0;
1101
1498
  try {
1102
1499
  return await this._jobQueue.enqueue(
1103
1500
  deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1104
1501
  async (signal) => {
1105
- const { record } = await this._ensureMfpKnown(connectId, deviceId, "btc", signal);
1106
- return (0, import_hwk_adapter_core.success)({ masterFingerprint: record.masterFingerprint });
1502
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "btc", signal);
1503
+ return (0, import_hwk_adapter_core3.success)({ masterFingerprint: record.masterFingerprint });
1107
1504
  }
1108
1505
  );
1109
1506
  } catch (err) {
@@ -1113,28 +1510,26 @@ var KeystoneAdapter = class _KeystoneAdapter {
1113
1510
  // ---------------------------------------------------------------------------
1114
1511
  // SOL
1115
1512
  // ---------------------------------------------------------------------------
1116
- async solGetAddress(connectIdArg, deviceIdArg, paramsArg) {
1117
- const connectId = connectIdArg ?? void 0;
1513
+ async solGetAddress(connectIdArg, deviceIdArg, paramsArg, book) {
1514
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1515
+ if (!operationTarget.success) return operationTarget;
1516
+ const connectId = operationTarget.payload.targetId;
1118
1517
  const deviceId = deviceIdArg ?? void 0;
1119
1518
  const params = paramsArg;
1120
- if (!params) return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "solGetAddress requires params");
1519
+ if (!params) return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "solGetAddress requires params");
1121
1520
  if (!params.path)
1122
- return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "solGetAddress requires params.path");
1521
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "solGetAddress requires params.path");
1123
1522
  const path = normalizePath(params.path);
1124
1523
  try {
1125
1524
  return await this._jobQueue.enqueue(
1126
1525
  deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1127
1526
  async (signal) => {
1128
- const { account } = await this._ensureAccountSynced(
1129
- connectId,
1130
- deviceId,
1131
- "sol",
1132
- path,
1133
- signal
1134
- );
1527
+ const { account } = await this._fetchAccount(connectId, deviceId, "sol", path, signal, {
1528
+ book
1529
+ });
1135
1530
  _KeystoneAdapter._throwIfAborted(signal);
1136
1531
  const address = import_bs58.default.encode(Buffer.from(account.publicKey, "hex"));
1137
- return (0, import_hwk_adapter_core.success)({ address, path });
1532
+ return (0, import_hwk_adapter_core3.success)({ address, path });
1138
1533
  }
1139
1534
  );
1140
1535
  } catch (err) {
@@ -1142,14 +1537,16 @@ var KeystoneAdapter = class _KeystoneAdapter {
1142
1537
  }
1143
1538
  }
1144
1539
  async solSignTransaction(connectIdArg, deviceIdArg, paramsArg) {
1145
- const connectId = connectIdArg ?? void 0;
1540
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1541
+ if (!operationTarget.success) return operationTarget;
1542
+ const connectId = operationTarget.payload.targetId;
1146
1543
  const deviceId = deviceIdArg ?? void 0;
1147
1544
  const params = paramsArg;
1148
1545
  if (!params)
1149
- return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "solSignTransaction requires params");
1546
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "solSignTransaction requires params");
1150
1547
  if (!params.path || !params.serializedTx) {
1151
- return (0, import_hwk_adapter_core.failure)(
1152
- import_hwk_adapter_core.HardwareErrorCode.InvalidParams,
1548
+ return (0, import_hwk_adapter_core3.failure)(
1549
+ import_hwk_adapter_core3.HardwareErrorCode.InvalidParams,
1153
1550
  "solSignTransaction requires params.path and params.serializedTx"
1154
1551
  );
1155
1552
  }
@@ -1158,21 +1555,28 @@ var KeystoneAdapter = class _KeystoneAdapter {
1158
1555
  return await this._jobQueue.enqueue(
1159
1556
  deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1160
1557
  async (signal) => {
1161
- const { record } = await this._ensureMfpKnown(connectId, deviceId, "sol", signal);
1558
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "sol", signal);
1162
1559
  _KeystoneAdapter._throwIfAborted(signal);
1163
1560
  const requestId = (0, import_uuid2.v4)();
1164
1561
  const requestUr = this.urEngine.buildSolSignRequest({
1165
1562
  requestId,
1166
- unsignedPayloadHex: (0, import_hwk_adapter_core.stripHex)(params.serializedTx),
1563
+ unsignedPayloadHex: (0, import_hwk_adapter_core3.stripHex)(params.serializedTx),
1167
1564
  dataType: "transaction",
1168
1565
  path,
1169
1566
  xfp: record.masterFingerprint
1170
1567
  });
1171
- const responseUr = await this._resolveUr(record, requestUr, true);
1568
+ const responseUr = await this._resolveUr(
1569
+ record,
1570
+ requestUr,
1571
+ true,
1572
+ connectId,
1573
+ signal,
1574
+ "solSignTransaction"
1575
+ );
1172
1576
  _KeystoneAdapter._throwIfAborted(signal);
1173
1577
  const sig = this.urEngine.parseSolSignature(responseUr);
1174
1578
  _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1175
- return (0, import_hwk_adapter_core.success)({ signature: sig.signature });
1579
+ return (0, import_hwk_adapter_core3.success)({ signature: sig.signature });
1176
1580
  }
1177
1581
  );
1178
1582
  } catch (err) {
@@ -1180,13 +1584,15 @@ var KeystoneAdapter = class _KeystoneAdapter {
1180
1584
  }
1181
1585
  }
1182
1586
  async solSignMessage(connectIdArg, deviceIdArg, paramsArg) {
1183
- const connectId = connectIdArg ?? void 0;
1587
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1588
+ if (!operationTarget.success) return operationTarget;
1589
+ const connectId = operationTarget.payload.targetId;
1184
1590
  const deviceId = deviceIdArg ?? void 0;
1185
1591
  const params = paramsArg;
1186
- if (!params) return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "solSignMessage requires params");
1592
+ if (!params) return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "solSignMessage requires params");
1187
1593
  if (!params.path || !params.message) {
1188
- return (0, import_hwk_adapter_core.failure)(
1189
- import_hwk_adapter_core.HardwareErrorCode.InvalidParams,
1594
+ return (0, import_hwk_adapter_core3.failure)(
1595
+ import_hwk_adapter_core3.HardwareErrorCode.InvalidParams,
1190
1596
  "solSignMessage requires params.path and params.message"
1191
1597
  );
1192
1598
  }
@@ -1195,21 +1601,28 @@ var KeystoneAdapter = class _KeystoneAdapter {
1195
1601
  return await this._jobQueue.enqueue(
1196
1602
  deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1197
1603
  async (signal) => {
1198
- const { record } = await this._ensureMfpKnown(connectId, deviceId, "sol", signal);
1604
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "sol", signal);
1199
1605
  _KeystoneAdapter._throwIfAborted(signal);
1200
1606
  const requestId = (0, import_uuid2.v4)();
1201
1607
  const requestUr = this.urEngine.buildSolSignRequest({
1202
1608
  requestId,
1203
- unsignedPayloadHex: (0, import_hwk_adapter_core.stripHex)(params.message),
1609
+ unsignedPayloadHex: (0, import_hwk_adapter_core3.stripHex)(params.message),
1204
1610
  dataType: "message",
1205
1611
  path,
1206
1612
  xfp: record.masterFingerprint
1207
1613
  });
1208
- const responseUr = await this._resolveUr(record, requestUr, true);
1614
+ const responseUr = await this._resolveUr(
1615
+ record,
1616
+ requestUr,
1617
+ true,
1618
+ connectId,
1619
+ signal,
1620
+ "solSignMessage"
1621
+ );
1209
1622
  _KeystoneAdapter._throwIfAborted(signal);
1210
1623
  const sig = this.urEngine.parseSolSignature(responseUr);
1211
1624
  _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1212
- return (0, import_hwk_adapter_core.success)({ signature: sig.signature });
1625
+ return (0, import_hwk_adapter_core3.success)({ signature: sig.signature });
1213
1626
  }
1214
1627
  );
1215
1628
  } catch (err) {
@@ -1223,17 +1636,19 @@ var KeystoneAdapter = class _KeystoneAdapter {
1223
1636
  // bundled `sdk.tron` module (different, protobuf-based protocol with
1224
1637
  // unverified response semantics).
1225
1638
  // ---------------------------------------------------------------------------
1226
- async tronGetAddress(connectIdArg, deviceIdArg, paramsArg) {
1227
- const connectId = connectIdArg ?? void 0;
1639
+ async tronGetAddress(connectIdArg, deviceIdArg, paramsArg, book) {
1640
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1641
+ if (!operationTarget.success) return operationTarget;
1642
+ const connectId = operationTarget.payload.targetId;
1228
1643
  const deviceId = deviceIdArg ?? void 0;
1229
1644
  const params = paramsArg;
1230
- if (!params) return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "tronGetAddress requires params");
1645
+ if (!params) return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "tronGetAddress requires params");
1231
1646
  if (!params.path)
1232
- return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "tronGetAddress requires params.path");
1647
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "tronGetAddress requires params.path");
1233
1648
  const { accountPath, relativeDerivePath } = splitAccountPath(params.path);
1234
1649
  if (!relativeDerivePath) {
1235
- return (0, import_hwk_adapter_core.failure)(
1236
- import_hwk_adapter_core.HardwareErrorCode.InvalidParams,
1650
+ return (0, import_hwk_adapter_core3.failure)(
1651
+ import_hwk_adapter_core3.HardwareErrorCode.InvalidParams,
1237
1652
  "tronGetAddress requires a full leaf path, e.g. m/44'/195'/0'/0/0"
1238
1653
  );
1239
1654
  }
@@ -1241,17 +1656,18 @@ var KeystoneAdapter = class _KeystoneAdapter {
1241
1656
  return await this._jobQueue.enqueue(
1242
1657
  deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1243
1658
  async (signal) => {
1244
- const { account } = await this._ensureAccountSynced(
1659
+ const { account } = await this._fetchAccount(
1245
1660
  connectId,
1246
1661
  deviceId,
1247
1662
  "tron",
1248
1663
  accountPath,
1249
- signal
1664
+ signal,
1665
+ { book }
1250
1666
  );
1251
1667
  _KeystoneAdapter._throwIfAborted(signal);
1252
1668
  if (!account.extendedPublicKey) {
1253
- throw (0, import_hwk_adapter_core.createHwkError)({
1254
- code: import_hwk_adapter_core.HardwareErrorCode.MethodNotSupported,
1669
+ throw (0, import_hwk_adapter_core3.createHwkError)({
1670
+ code: import_hwk_adapter_core3.HardwareErrorCode.MethodNotSupported,
1255
1671
  message: "Keystone did not return an extended public key for this account path"
1256
1672
  });
1257
1673
  }
@@ -1259,7 +1675,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
1259
1675
  account.extendedPublicKey,
1260
1676
  relativeDerivePath
1261
1677
  );
1262
- return (0, import_hwk_adapter_core.success)({ address, path: normalizePath(params.path) });
1678
+ return (0, import_hwk_adapter_core3.success)({ address, path: normalizePath(params.path) });
1263
1679
  }
1264
1680
  );
1265
1681
  } catch (err) {
@@ -1267,27 +1683,29 @@ var KeystoneAdapter = class _KeystoneAdapter {
1267
1683
  }
1268
1684
  }
1269
1685
  async tronSignTransaction(connectIdArg, deviceIdArg, paramsArg) {
1270
- const connectId = connectIdArg ?? void 0;
1686
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1687
+ if (!operationTarget.success) return operationTarget;
1688
+ const connectId = operationTarget.payload.targetId;
1271
1689
  const deviceId = deviceIdArg ?? void 0;
1272
1690
  const params = paramsArg;
1273
1691
  if (!params)
1274
- return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "tronSignTransaction requires params");
1692
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "tronSignTransaction requires params");
1275
1693
  if (!params.path) {
1276
- return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.InvalidParams, "tronSignTransaction requires params.path");
1694
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "tronSignTransaction requires params.path");
1277
1695
  }
1278
1696
  if (!params.rawTxHex) {
1279
- return (0, import_hwk_adapter_core.failure)(
1280
- import_hwk_adapter_core.HardwareErrorCode.InvalidParams,
1697
+ return (0, import_hwk_adapter_core3.failure)(
1698
+ import_hwk_adapter_core3.HardwareErrorCode.InvalidParams,
1281
1699
  "Keystone only signs a fully protobuf-serialized TRON transaction (params.rawTxHex) \u2014 the Trezor-style structured contract fields have no equivalent here"
1282
1700
  );
1283
1701
  }
1284
- const rawTxHex = (0, import_hwk_adapter_core.stripHex)(params.rawTxHex);
1702
+ const rawTxHex = (0, import_hwk_adapter_core3.stripHex)(params.rawTxHex);
1285
1703
  const path = normalizePath(params.path);
1286
1704
  try {
1287
1705
  return await this._jobQueue.enqueue(
1288
1706
  deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1289
1707
  async (signal) => {
1290
- const { record } = await this._ensureMfpKnown(connectId, deviceId, "tron", signal);
1708
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "tron", signal);
1291
1709
  _KeystoneAdapter._throwIfAborted(signal);
1292
1710
  const requestId = (0, import_uuid2.v4)();
1293
1711
  const requestUr = this.urEngine.buildTronSignRequest({
@@ -1296,38 +1714,262 @@ var KeystoneAdapter = class _KeystoneAdapter {
1296
1714
  path,
1297
1715
  xfp: record.masterFingerprint
1298
1716
  });
1299
- const responseUr = await this._resolveUr(record, requestUr, true);
1717
+ const responseUr = await this._resolveUr(
1718
+ record,
1719
+ requestUr,
1720
+ true,
1721
+ connectId,
1722
+ signal,
1723
+ "tronSignTransaction"
1724
+ );
1300
1725
  _KeystoneAdapter._throwIfAborted(signal);
1301
1726
  const sig = this.urEngine.parseTronSignature(responseUr);
1302
1727
  _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1303
- return (0, import_hwk_adapter_core.success)({ signature: sig.signature });
1728
+ return (0, import_hwk_adapter_core3.success)({ signature: sig.signature });
1304
1729
  }
1305
1730
  );
1306
1731
  } catch (err) {
1307
1732
  return this._errorToFailure(err);
1308
1733
  }
1309
1734
  }
1310
- async tronSignMessage(_connectId, _deviceId, _params) {
1311
- return this._unsupported(
1312
- "tronSignMessage",
1313
- "Keystone TRON message signing needs signType V1-vs-V2 verified against real hardware first \u2014 not wired in"
1314
- );
1735
+ async tronSignMessage(connectIdArg, deviceIdArg, paramsArg) {
1736
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1737
+ if (!operationTarget.success) return operationTarget;
1738
+ const connectId = operationTarget.payload.targetId;
1739
+ const deviceId = deviceIdArg ?? void 0;
1740
+ const params = paramsArg;
1741
+ if (!params) return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "tronSignMessage requires params");
1742
+ if (!params.path) {
1743
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "tronSignMessage requires params.path");
1744
+ }
1745
+ if (!params.messageHex) {
1746
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "tronSignMessage requires params.messageHex");
1747
+ }
1748
+ if (params.messageType !== "V2") {
1749
+ return (0, import_hwk_adapter_core3.failure)(
1750
+ import_hwk_adapter_core3.HardwareErrorCode.MethodNotSupported,
1751
+ 'Keystone signs TRON messages as TIP-191 signMessageV2 only (messageType: "V2")'
1752
+ );
1753
+ }
1754
+ const messageHex = (0, import_hwk_adapter_core3.stripHex)(params.messageHex);
1755
+ const path = normalizePath(params.path);
1756
+ try {
1757
+ return await this._jobQueue.enqueue(
1758
+ deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1759
+ async (signal) => {
1760
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "tron", signal);
1761
+ _KeystoneAdapter._throwIfAborted(signal);
1762
+ const requestId = (0, import_uuid2.v4)();
1763
+ const requestUr = this.urEngine.buildTronSignRequest({
1764
+ requestId,
1765
+ rawTxHex: messageHex,
1766
+ path,
1767
+ xfp: record.masterFingerprint,
1768
+ signType: 2 /* PersonalMessage */
1769
+ });
1770
+ const responseUr = await this._resolveUr(
1771
+ record,
1772
+ requestUr,
1773
+ true,
1774
+ connectId,
1775
+ signal,
1776
+ "tronSignMessage"
1777
+ );
1778
+ _KeystoneAdapter._throwIfAborted(signal);
1779
+ const sig = this.urEngine.parseTronSignature(responseUr);
1780
+ _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1781
+ return (0, import_hwk_adapter_core3.success)({ signature: sig.signature });
1782
+ }
1783
+ );
1784
+ } catch (err) {
1785
+ return this._errorToFailure(err);
1786
+ }
1315
1787
  }
1316
1788
  // ---------------------------------------------------------------------------
1317
1789
  // Internals
1318
1790
  // ---------------------------------------------------------------------------
1319
- _mfpFromConnectId(connectId) {
1320
- return connectId?.startsWith(QR_CONNECT_ID_PREFIX) ? connectId.slice(QR_CONNECT_ID_PREFIX.length) : void 0;
1791
+ _walletIdFromIdentifier(identifier) {
1792
+ const value = identifier.startsWith(KEYSTONE_WALLET_CONNECT_ID_PREFIX) ? identifier.slice(KEYSTONE_WALLET_CONNECT_ID_PREFIX.length) : identifier;
1793
+ return /^[0-9a-f]{64}$/i.test(value) ? value.toLowerCase() : void 0;
1794
+ }
1795
+ _allNetworkSyncSchema(item) {
1796
+ if (!(0, import_hwk_adapter_core3.isAllNetworkMethodName)(String(item.methodName)) || !item.path) return void 0;
1797
+ const method = item.methodName;
1798
+ const hwkChain = (0, import_hwk_adapter_core3.getAllNetworkMethodChain)(method);
1799
+ const path = normalizePath(item.path);
1800
+ if (hwkChain === "btc" && !isKeystoneSignableBtcAccountPath(splitAccountPath(path).accountPath)) {
1801
+ return void 0;
1802
+ }
1803
+ switch (method) {
1804
+ case "evmGetAddress":
1805
+ case "btcGetAddress":
1806
+ case "tronGetAddress":
1807
+ return { hwkChain, path: splitAccountPath(path).accountPath };
1808
+ case "btcGetPublicKey":
1809
+ case "solGetAddress":
1810
+ return { hwkChain, path };
1811
+ default:
1812
+ return void 0;
1813
+ }
1321
1814
  }
1322
1815
  /**
1323
- * Handles both connectId shapes a caller might hand back: the QR-style
1324
- * `keystone-qr:<mfp>` prefix, and a bare mfp — which is exactly what a
1325
- * USB session's `sessionId`/`connectId` is (see `KeystoneUsbConnectorBase`
1326
- * and `_connectUsb`).
1816
+ * QR is an interactive batch transport: one account-creation action must
1817
+ * produce one request QR and one response scan, regardless of how many
1818
+ * chains or derivation paths the host bundled. USB keeps its proven
1819
+ * one-path-at-a-time export flow because the device limits that channel.
1327
1820
  */
1328
- _findByConnectId(connectId) {
1329
- const mfp = this._mfpFromConnectId(connectId) ?? connectId?.toLowerCase();
1330
- return mfp ? this._devices.get(mfp) : void 0;
1821
+ async _prefetchAllNetworkAccounts(connectId, deviceId, params) {
1822
+ return this._jobQueue.enqueue(deviceId || connectId || COLD_START_JOB_LABEL, async (signal) => {
1823
+ const target = this._resolveTarget(connectId, deviceId);
1824
+ const { record: targetRecord } = target;
1825
+ let record = targetRecord;
1826
+ const requestedByKey = /* @__PURE__ */ new Map();
1827
+ for (const item of params.bundle) {
1828
+ const schema = this._allNetworkSyncSchema(item);
1829
+ if (schema) requestedByKey.set(accountKey(schema.hwkChain, schema.path), schema);
1830
+ }
1831
+ const book = /* @__PURE__ */ new Map();
1832
+ if (!requestedByKey.size) {
1833
+ return { book };
1834
+ }
1835
+ if (this._forcedTransport !== "qr" && !record?.usbSessionId && this._usbConnector && target.expectedWalletId) {
1836
+ record = await this._tryUsbAttach(
1837
+ target.expectedWalletId,
1838
+ record?.masterFingerprint ?? target.expectedMasterFingerprint
1839
+ ) ?? record;
1840
+ _KeystoneAdapter._throwIfAborted(signal);
1841
+ }
1842
+ if (this._forcedTransport !== "qr" && record?.usbSessionId) {
1843
+ const missingSchemas2 = Array.from(requestedByKey.values());
1844
+ for (const [index, schema] of missingSchemas2.entries()) {
1845
+ if (!book.has(accountKey(schema.hwkChain, schema.path))) {
1846
+ const synced = await this._fetchAccount(
1847
+ connectId,
1848
+ deviceId,
1849
+ schema.hwkChain,
1850
+ schema.path,
1851
+ signal,
1852
+ { qrFallbackSchemaPaths: missingSchemas2.slice(index), book }
1853
+ );
1854
+ record = synced.record;
1855
+ if (!record.usbSessionId) break;
1856
+ }
1857
+ }
1858
+ for (const schema of missingSchemas2) {
1859
+ if (!book.has(accountKey(schema.hwkChain, schema.path))) {
1860
+ throw (0, import_hwk_adapter_core3.createHwkError)({
1861
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch,
1862
+ message: `Keystone did not return the requested derivation path (${schema.path})`
1863
+ });
1864
+ }
1865
+ }
1866
+ return { book, walletId: record.walletId };
1867
+ }
1868
+ if (this._forcedTransport === "usb") {
1869
+ throw (0, import_hwk_adapter_core3.createHwkError)({
1870
+ code: import_hwk_adapter_core3.HardwareErrorCode.TransportNotAvailable,
1871
+ message: "USB channel is not connected for this Keystone wallet"
1872
+ });
1873
+ }
1874
+ const missingSchemas = Array.from(requestedByKey.values());
1875
+ const schemas = [
1876
+ { hwkChain: "evm", path: KEYSTONE_WALLET_ID_PATH },
1877
+ ...missingSchemas.filter((schema) => normalizePath(schema.path) !== KEYSTONE_WALLET_ID_PATH)
1878
+ ];
1879
+ const requestUr = this.urEngine.buildKeyDerivationRequest({
1880
+ schemas: schemas.map((schema) => ({
1881
+ path: schema.path,
1882
+ curve: schema.hwkChain === "sol" ? "ed25519" : "secp256k1"
1883
+ })),
1884
+ origin: this._origin
1885
+ });
1886
+ const responseUr = await this._requestQrDisplayAndAwaitResponse(
1887
+ record ? toDeviceInfo(record) : placeholderDeviceInfo(),
1888
+ { ...requestUr, animated: false }
1889
+ );
1890
+ _KeystoneAdapter._throwIfAborted(signal);
1891
+ const parsed = this.urEngine.parseAccountResponse(responseUr);
1892
+ this._assertParsedIdentity(parsed, target);
1893
+ record = this._upsertDeviceRecord(parsed);
1894
+ const requestedChainByPath = new Map(
1895
+ schemas.map((schema) => [normalizePath(schema.path), schema.hwkChain])
1896
+ );
1897
+ for (const account of parsed.accounts) {
1898
+ const normalizedPath = normalizePath(account.path);
1899
+ const hwkChain = requestedChainByPath.get(normalizedPath) ?? inferHwkChainFromPath(normalizedPath);
1900
+ if (hwkChain) {
1901
+ book.set(accountKey(hwkChain, normalizedPath), {
1902
+ ...account,
1903
+ hwkChain
1904
+ });
1905
+ }
1906
+ }
1907
+ for (const schema of missingSchemas) {
1908
+ if (!book.has(accountKey(schema.hwkChain, schema.path))) {
1909
+ throw (0, import_hwk_adapter_core3.createHwkError)({
1910
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch,
1911
+ message: `Keystone did not return the requested derivation path (${schema.path})`
1912
+ });
1913
+ }
1914
+ }
1915
+ return { book, walletId: record.walletId };
1916
+ });
1917
+ }
1918
+ /**
1919
+ * Resolve only the stable 64-hex wallet identity. The 8-hex BIP32 master
1920
+ * fingerprint is protocol metadata and is never accepted as a lookup key.
1921
+ */
1922
+ _resolveTarget(connectId, deviceId) {
1923
+ let resolvedConnectId = connectId;
1924
+ if ((0, import_hwk_adapter_core3.isHardwareInteractionId)(connectId)) {
1925
+ resolvedConnectId = this._interactions.resolve(connectId).connectId;
1926
+ }
1927
+ const identifiers = [deviceId, resolvedConnectId].filter(
1928
+ (identifier) => Boolean(identifier)
1929
+ );
1930
+ if (!identifiers.length) return {};
1931
+ const walletIds = identifiers.map((identifier) => this._walletIdFromIdentifier(identifier)).filter((walletId) => Boolean(walletId));
1932
+ if (!walletIds.length) {
1933
+ throw (0, import_hwk_adapter_core3.createHwkError)({
1934
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound,
1935
+ message: "Keystone device lookup requires a 64-hex wallet identity"
1936
+ });
1937
+ }
1938
+ const expectedWalletId = walletIds[0];
1939
+ if (walletIds.some((walletId) => walletId !== expectedWalletId)) {
1940
+ throw (0, import_hwk_adapter_core3.createHwkError)({
1941
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch,
1942
+ message: "Keystone connectId and deviceId identify different wallets"
1943
+ });
1944
+ }
1945
+ if (identifiers.some((identifier) => !this._walletIdFromIdentifier(identifier))) {
1946
+ throw (0, import_hwk_adapter_core3.createHwkError)({
1947
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch,
1948
+ message: "Keystone connectId and deviceId are inconsistent"
1949
+ });
1950
+ }
1951
+ const record = this._devices.get(expectedWalletId);
1952
+ return record ? {
1953
+ record,
1954
+ expectedWalletId,
1955
+ expectedMasterFingerprint: record.masterFingerprint
1956
+ } : { expectedWalletId };
1957
+ }
1958
+ _assertParsedIdentity(parsed, expected) {
1959
+ const walletId = deriveKeystoneWalletId(parsed.accounts);
1960
+ if (expected.expectedMasterFingerprint && parsed.masterFingerprint !== expected.expectedMasterFingerprint) {
1961
+ throw (0, import_hwk_adapter_core3.createHwkError)({
1962
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch,
1963
+ message: `Connected Keystone wallet (mfp ${parsed.masterFingerprint}) does not match the requested wallet fingerprint (${expected.expectedMasterFingerprint})`
1964
+ });
1965
+ }
1966
+ if (expected.expectedWalletId && walletId !== expected.expectedWalletId) {
1967
+ throw (0, import_hwk_adapter_core3.createHwkError)({
1968
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch,
1969
+ message: "Connected Keystone wallet does not match the requested wallet identity"
1970
+ });
1971
+ }
1972
+ return walletId;
1331
1973
  }
1332
1974
  /**
1333
1975
  * Folds a parsed account-response UR into the device table. `viaUsb`
@@ -1336,169 +1978,498 @@ var KeystoneAdapter = class _KeystoneAdapter {
1336
1978
  * already has a live session, so this must NOT unconditionally mark
1337
1979
  * `qrSynced`, or a USB-only wallet would wrongly survive a later USB
1338
1980
  * disconnect as a "QR-synced, demote to QR-only" entry instead of being
1339
- * dropped outright (see `disconnectDevice`).
1981
+ * dropped outright (see `releaseInteraction`).
1340
1982
  */
1341
1983
  _upsertDeviceRecord(parsed, options) {
1342
- const mfp = parsed.masterFingerprint;
1343
- let record = this._devices.get(mfp);
1984
+ const walletId = deriveKeystoneWalletId(parsed.accounts);
1985
+ let record = this._devices.get(walletId);
1344
1986
  const isNew = !record;
1345
1987
  if (!record) {
1346
- record = createDeviceRecord(mfp);
1347
- this._devices.set(mfp, record);
1988
+ record = createDeviceRecord(walletId, parsed.masterFingerprint);
1989
+ this._devices.set(walletId, record);
1990
+ } else if (record.masterFingerprint !== parsed.masterFingerprint) {
1991
+ throw (0, import_hwk_adapter_core3.createHwkError)({
1992
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch,
1993
+ message: "Keystone wallet identity returned an inconsistent master fingerprint"
1994
+ });
1348
1995
  }
1349
1996
  record.model = parsed.device ?? record.model;
1350
1997
  record.deviceVersion = parsed.deviceVersion ?? record.deviceVersion;
1998
+ record.hardwareDeviceId = parsed.deviceId ?? record.hardwareDeviceId;
1999
+ record.usbSessionId = options?.usbSessionId ?? record.usbSessionId;
1351
2000
  if (!options?.viaUsb) record.qrSynced = true;
1352
2001
  const info = toDeviceInfo(record);
1353
- const eventType = isNew ? import_hwk_adapter_core.DEVICE.CONNECT : import_hwk_adapter_core.DEVICE.CHANGED;
2002
+ const eventType = isNew ? import_hwk_adapter_core3.DEVICE.CONNECT : import_hwk_adapter_core3.DEVICE.CHANGED;
1354
2003
  this.emitter.emit(eventType, { type: eventType, payload: info });
1355
2004
  return record;
1356
2005
  }
1357
2006
  /**
1358
2007
  * Opens+claims whatever Keystone the USB connector currently has
1359
- * permission for, learns its mfp via `getAppConfig`, and merges it into
1360
- * the device table by that mfp — a QR-synced entry becomes
2008
+ * permission for, learns its protocol mfp via `getAppConfig`, then requests
2009
+ * one fixed account-level xpub and derives the stable wallet id. A
2010
+ * QR-synced entry becomes
1361
2011
  * `{qr, usb}`-capable in place (one `device-changed`, not a second
1362
2012
  * `device-connect`); a wallet never seen before becomes a new USB-only
1363
2013
  * entry. See §4.2 of the design doc.
1364
2014
  */
1365
- async _connectUsb() {
2015
+ async _connectUsb(expected, searchTargetId) {
2016
+ if (this._pendingUsbTeardowns > 0) {
2017
+ return (0, import_hwk_adapter_core3.failure)(
2018
+ import_hwk_adapter_core3.HardwareErrorCode.DeviceBusyInternal,
2019
+ "Keystone USB session is being released"
2020
+ );
2021
+ }
2022
+ const previous = this._usbConnectTail;
2023
+ let release;
2024
+ this._usbConnectTail = new Promise((resolve) => {
2025
+ release = resolve;
2026
+ });
2027
+ await previous;
2028
+ try {
2029
+ return await this._connectUsbExclusive(expected, searchTargetId);
2030
+ } finally {
2031
+ release?.();
2032
+ }
2033
+ }
2034
+ async _connectUsbExclusive(expected, searchTargetId) {
1366
2035
  if (!this._usbConnector) {
1367
- return (0, import_hwk_adapter_core.failure)(
1368
- import_hwk_adapter_core.HardwareErrorCode.TransportNotAvailable,
2036
+ return (0, import_hwk_adapter_core3.failure)(
2037
+ import_hwk_adapter_core3.HardwareErrorCode.TransportNotAvailable,
1369
2038
  "No USB connector configured for this Keystone adapter"
1370
2039
  );
1371
2040
  }
2041
+ let sessionId;
1372
2042
  try {
1373
- const session = await this._usbConnector.connect();
1374
- const mfp = session.deviceInfo.deviceId.toLowerCase();
1375
- let record = this._devices.get(mfp);
1376
- const isNew = !record;
1377
- if (!record) {
1378
- record = createDeviceRecord(mfp);
1379
- this._devices.set(mfp, record);
2043
+ let connectTarget = { type: "default" };
2044
+ if (searchTargetId) {
2045
+ connectTarget = { type: "search-target", searchTargetId };
2046
+ } else if (expected.expectedMasterFingerprint) {
2047
+ connectTarget = {
2048
+ type: "expected-device-identity",
2049
+ deviceIdentity: expected.expectedMasterFingerprint
2050
+ };
2051
+ }
2052
+ const connector = this._usbConnector;
2053
+ const session = await (connector.connectTarget ? connector.connectTarget(connectTarget) : connector.connect(searchTargetId ?? expected.expectedMasterFingerprint));
2054
+ sessionId = session.sessionId;
2055
+ const raw = session.deviceInfo.raw;
2056
+ const mfpValue = (0, import_hwk_adapter_core3.parseBip32MasterFingerprint)(raw?.masterFingerprint);
2057
+ if (!mfpValue) {
2058
+ throw (0, import_hwk_adapter_core3.createHwkError)({
2059
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch,
2060
+ message: "Keystone USB did not report a master fingerprint"
2061
+ });
1380
2062
  }
2063
+ const masterFingerprint = mfpValue.toLowerCase();
2064
+ if (expected.expectedMasterFingerprint && masterFingerprint !== expected.expectedMasterFingerprint) {
2065
+ throw (0, import_hwk_adapter_core3.createHwkError)({
2066
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch,
2067
+ message: `Connected Keystone wallet (mfp ${masterFingerprint}) does not match the requested wallet fingerprint (${expected.expectedMasterFingerprint})`
2068
+ });
2069
+ }
2070
+ const identityRequest = this.urEngine.buildKeyDerivationRequest({
2071
+ schemas: [{ path: KEYSTONE_WALLET_ID_PATH, curve: "secp256k1" }],
2072
+ origin: this._origin
2073
+ });
2074
+ const identityResult = await this._callUsbConnector(
2075
+ session.sessionId,
2076
+ "resolveUr",
2077
+ identityRequest
2078
+ );
2079
+ if (!identityResult.success) {
2080
+ throw (0, import_hwk_adapter_core3.rehydrateConnectorError)(identityResult.error);
2081
+ }
2082
+ const parsed = this.urEngine.parseAccountResponse(identityResult.payload);
2083
+ this._assertParsedIdentity(parsed, {
2084
+ ...expected,
2085
+ expectedMasterFingerprint: expected.expectedMasterFingerprint ?? masterFingerprint
2086
+ });
2087
+ const walletId = deriveKeystoneWalletId(parsed.accounts);
2088
+ const previousUsbSessionId = this._devices.get(walletId)?.usbSessionId;
2089
+ const record = this._upsertDeviceRecord(parsed, {
2090
+ viaUsb: true,
2091
+ usbSessionId: session.sessionId
2092
+ });
2093
+ if (previousUsbSessionId && previousUsbSessionId !== session.sessionId) {
2094
+ try {
2095
+ await this._usbConnector.disconnect(previousUsbSessionId);
2096
+ } catch {
2097
+ }
2098
+ }
2099
+ record.hadUsbSession = true;
1381
2100
  record.model = session.deviceInfo.modelName ?? session.deviceInfo.model ?? record.model;
1382
2101
  record.deviceVersion = session.deviceInfo.firmwareVersion ?? record.deviceVersion;
1383
- record.usbSessionId = session.sessionId;
1384
2102
  const info = toDeviceInfo(record);
1385
- const eventType = isNew ? import_hwk_adapter_core.DEVICE.CONNECT : import_hwk_adapter_core.DEVICE.CHANGED;
1386
- this.emitter.emit(eventType, { type: eventType, payload: info });
1387
- return (0, import_hwk_adapter_core.success)(info);
2103
+ return (0, import_hwk_adapter_core3.success)(info);
1388
2104
  } catch (err) {
2105
+ if (sessionId) {
2106
+ try {
2107
+ await this._usbConnector.disconnect(sessionId);
2108
+ } catch {
2109
+ }
2110
+ }
1389
2111
  return this._errorToFailure(err);
1390
2112
  }
1391
2113
  }
2114
+ /**
2115
+ * Probe already-authorized USB devices without opening a permission picker,
2116
+ * then attach and verify the requested wallet when one is present. This is
2117
+ * used both after an adapter restart and after a QR-only period, so plugging
2118
+ * USB back in affects the next business call without changing an in-flight
2119
+ * QR interaction.
2120
+ */
2121
+ async _tryUsbAttach(expectedWalletId, expectedMasterFingerprint, options) {
2122
+ if (!expectedWalletId || this._forcedTransport === "qr" || !this._usbConnector) {
2123
+ return void 0;
2124
+ }
2125
+ const maxAttempts = options?.waitForReenumeration ? KEYSTONE_USB_REATTACH_PROBE_ATTEMPTS : 1;
2126
+ let availableDevices = [];
2127
+ let lastSearchError;
2128
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
2129
+ try {
2130
+ availableDevices = await this._usbConnector.searchDevices({ purpose: "availability" });
2131
+ lastSearchError = void 0;
2132
+ } catch (error) {
2133
+ lastSearchError = error;
2134
+ }
2135
+ if (availableDevices.length) {
2136
+ break;
2137
+ }
2138
+ if (attempt < maxAttempts) {
2139
+ await waitForKeystoneUsbReattachProbe();
2140
+ }
2141
+ }
2142
+ if (!availableDevices.length) {
2143
+ if (this._forcedTransport === "usb" && lastSearchError) {
2144
+ throw lastSearchError instanceof Error ? lastSearchError : new Error(String(lastSearchError));
2145
+ }
2146
+ return void 0;
2147
+ }
2148
+ let attached;
2149
+ let record;
2150
+ const candidates = expectedMasterFingerprint ? [void 0] : availableDevices;
2151
+ for (const device of candidates) {
2152
+ attached = await this._connectUsb(
2153
+ { expectedWalletId, expectedMasterFingerprint },
2154
+ device?.connectId
2155
+ );
2156
+ if (attached.success) {
2157
+ record = this._devices.get(expectedWalletId);
2158
+ if (record) break;
2159
+ }
2160
+ }
2161
+ return record;
2162
+ }
1392
2163
  /**
1393
2164
  * The one place that decides QR vs. USB for a UR round trip and carries it
1394
2165
  * out. `record` is the (possibly not-yet-existing, for a true cold start)
1395
- * device row for the target wallet — USB is only used when `record`
1396
- * already has a live `usbSessionId` (a session comes from an explicit
1397
- * `connectDevice()`, never conjured mid-call — see the class doc). A
2166
+ * device row for the target wallet. USB is the preferred channel: a known
2167
+ * wallet record with no live session gets ONE best-effort re-attach here,
2168
+ * and anything that goes wrong just leaves the call on QR. A
1398
2169
  * `switchTransport('qr')` pin forces QR even for a USB-attached wallet;
1399
2170
  * `switchTransport('usb')` on a wallet with no live USB session fails
1400
2171
  * closed rather than silently falling back to QR.
1401
2172
  */
1402
- async _resolveUr(record, requestUr, animated) {
1403
- const wantUsb = this._forcedTransport === "usb" || this._forcedTransport !== "qr" && Boolean(record?.usbSessionId);
2173
+ async _resolveUr(record, requestUr, animated, interactionId, signal, operationName) {
2174
+ const releaseInteractionRetention = (0, import_hwk_adapter_core3.isHardwareInteractionId)(interactionId) ? this._interactions.retain(interactionId) : void 0;
2175
+ try {
2176
+ return await this._resolveUrWithRoute(
2177
+ record,
2178
+ requestUr,
2179
+ animated,
2180
+ interactionId,
2181
+ signal,
2182
+ operationName
2183
+ );
2184
+ } finally {
2185
+ releaseInteractionRetention?.();
2186
+ }
2187
+ }
2188
+ async _resolveUrWithRoute(record, requestUr, animated, interactionId, signal, operationName) {
2189
+ let interactionRoute;
2190
+ if ((0, import_hwk_adapter_core3.isHardwareInteractionId)(interactionId)) {
2191
+ const interaction = this._interactions.resolve(interactionId);
2192
+ const route = this._interactionRoutes.get(interaction.connectId);
2193
+ if (!route || route.interactionId !== interactionId) {
2194
+ this._interactions.end(interactionId, "disconnect");
2195
+ throw (0, import_hwk_adapter_core3.createHwkError)({
2196
+ code: import_hwk_adapter_core3.HardwareErrorCode.InteractionEnded,
2197
+ message: "Keystone hardware interaction is no longer connected",
2198
+ params: { interactionId, reason: "disconnect" }
2199
+ });
2200
+ }
2201
+ interactionRoute = route;
2202
+ }
2203
+ if (!interactionRoute && !this._forcedTransport && record && !record.usbSessionId && this._usbConnector) {
2204
+ await this._tryUsbAttach(record.walletId, record.masterFingerprint, {
2205
+ waitForReenumeration: record.hadUsbSession
2206
+ });
2207
+ }
2208
+ const wantUsb = interactionRoute ? interactionRoute.connectionType === "usb" : this._forcedTransport === "usb" || this._forcedTransport !== "qr" && Boolean(record?.usbSessionId);
1404
2209
  if (wantUsb) {
1405
2210
  if (!record?.usbSessionId || !this._usbConnector) {
1406
- throw (0, import_hwk_adapter_core.createHwkError)({
1407
- code: import_hwk_adapter_core.HardwareErrorCode.TransportNotAvailable,
2211
+ if (interactionRoute) {
2212
+ this._interactions.end(interactionRoute.interactionId, "disconnect");
2213
+ throw (0, import_hwk_adapter_core3.createHwkError)({
2214
+ code: import_hwk_adapter_core3.HardwareErrorCode.InteractionEnded,
2215
+ message: "Keystone interaction USB connection was lost",
2216
+ params: {
2217
+ interactionId: interactionRoute.interactionId,
2218
+ reason: "disconnect"
2219
+ }
2220
+ });
2221
+ }
2222
+ throw (0, import_hwk_adapter_core3.createHwkError)({
2223
+ code: import_hwk_adapter_core3.HardwareErrorCode.TransportNotAvailable,
1408
2224
  message: "USB channel is not connected for this Keystone wallet"
1409
2225
  });
1410
2226
  }
1411
- const result = await this._usbConnector.call(record.usbSessionId, "resolveUr", requestUr);
1412
- if (!result.success) throw (0, import_hwk_adapter_core.rehydrateConnectorError)(result.error);
1413
- return result.payload;
2227
+ const result = await this._callUsbConnector(
2228
+ record.usbSessionId,
2229
+ "resolveUr",
2230
+ requestUr,
2231
+ signal
2232
+ );
2233
+ if (result.success) return result.payload;
2234
+ const usbError = (0, import_hwk_adapter_core3.rehydrateConnectorError)(result.error);
2235
+ const usbErrorOrigin = usbError.origin;
2236
+ const usbErrorCode = usbError.code;
2237
+ if (!interactionRoute && !this._forcedTransport && usbErrorCode === import_hwk_adapter_core3.HardwareErrorCode.PayloadTooLarge && usbErrorOrigin !== "device") {
2238
+ const displayDevice2 = toDeviceInfo(record);
2239
+ return this._requestQrDisplayAndAwaitResponse(displayDevice2, {
2240
+ ...requestUr,
2241
+ animated
2242
+ });
2243
+ }
2244
+ const deviceAnswered = usbErrorOrigin !== void 0 ? usbErrorOrigin === "device" : usbErrorCode === import_hwk_adapter_core3.HardwareErrorCode.UserRejected || usbErrorCode === import_hwk_adapter_core3.HardwareErrorCode.UserAborted || usbErrorCode === import_hwk_adapter_core3.HardwareErrorCode.DeviceLocked || usbErrorCode === import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch;
2245
+ if (!deviceAnswered) {
2246
+ const lostSessionId = record.usbSessionId;
2247
+ if (lostSessionId) {
2248
+ this._usbConnector?.disconnect(lostSessionId).catch(() => void 0);
2249
+ }
2250
+ record.usbSessionId = void 0;
2251
+ if (interactionRoute) {
2252
+ this._interactions.end(interactionRoute.interactionId, "disconnect");
2253
+ throw (0, import_hwk_adapter_core3.createHwkError)({
2254
+ code: import_hwk_adapter_core3.HardwareErrorCode.InteractionEnded,
2255
+ message: operationName ? `Keystone ${operationName} may have completed before the USB connection was lost` : "Keystone interaction USB connection was lost",
2256
+ recovery: operationName ? { scope: "unknown" } : void 0,
2257
+ params: operationName ? (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(operationName, {
2258
+ interactionId: interactionRoute.interactionId,
2259
+ reason: "disconnect"
2260
+ }) : {
2261
+ interactionId: interactionRoute.interactionId,
2262
+ reason: "disconnect"
2263
+ }
2264
+ });
2265
+ }
2266
+ if (operationName) {
2267
+ throw (0, import_hwk_adapter_core3.createHwkError)({
2268
+ code: usbErrorCode ?? import_hwk_adapter_core3.HardwareErrorCode.TransportError,
2269
+ message: `Keystone ${operationName} may have completed before the USB connection was lost`,
2270
+ origin: "transport",
2271
+ recovery: { scope: "unknown" },
2272
+ params: (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(operationName)
2273
+ });
2274
+ }
2275
+ }
2276
+ throw usbError;
1414
2277
  }
1415
2278
  const displayDevice = record ? toDeviceInfo(record) : placeholderDeviceInfo();
1416
- return this._requestQrDisplayAndAwaitResponse(displayDevice, { ...requestUr, animated });
2279
+ try {
2280
+ return await this._requestQrDisplayAndAwaitResponse(displayDevice, {
2281
+ ...requestUr,
2282
+ animated
2283
+ });
2284
+ } catch (error) {
2285
+ const { code, _tag: tag } = error;
2286
+ if (operationName && (code === import_hwk_adapter_core3.HardwareErrorCode.OperationTimeout || tag === import_hwk_adapter_core3.UI_REQUEST_TIMEOUT_TAG)) {
2287
+ throw (0, import_hwk_adapter_core3.createHwkError)({
2288
+ code: import_hwk_adapter_core3.HardwareErrorCode.OperationTimeout,
2289
+ message: `Keystone ${operationName} may have completed before the QR response timed out`,
2290
+ recovery: { scope: "unknown" },
2291
+ params: (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(operationName)
2292
+ });
2293
+ }
2294
+ throw error;
2295
+ }
1417
2296
  }
1418
2297
  /**
1419
- * Resolve (syncing over QR if needed) the account cached for `hwkChain` at
1420
- * `syncPath`. Drives the "implicit account sync, then the real request" two
1421
- * hop flow the first time a wallet/path pair is seen; a cache hit skips
1422
- * straight to the caller's own round trip.
2298
+ * Fetch one account's key material from the device for this operation only.
2299
+ * `book` lets earlier fetches of the same operation be reused; nothing is
2300
+ * retained on the record. On a USB drop the remaining paths fall back to one
2301
+ * QR request.
1423
2302
  */
1424
- async _ensureAccountSynced(connectId, deviceId, hwkChain, syncPath, signal) {
1425
- const wantMfp = deviceId ? deviceId.toLowerCase() : this._mfpFromConnectId(connectId ?? "");
2303
+ async _fetchAccount(connectId, deviceId, hwkChain, syncPath, signal, options) {
2304
+ const target = this._resolveTarget(connectId, deviceId);
1426
2305
  const key = accountKey(hwkChain, syncPath);
1427
- const existingRecord = wantMfp ? this._devices.get(wantMfp) : void 0;
1428
- const cached = existingRecord?.accounts.get(key);
1429
- if (existingRecord && cached) {
1430
- return { record: existingRecord, account: cached };
2306
+ let existingRecord = target.record;
2307
+ if (!existingRecord) {
2308
+ const attached = await this._tryUsbAttach(target.expectedWalletId);
2309
+ _KeystoneAdapter._throwIfAborted(signal);
2310
+ existingRecord = attached;
2311
+ }
2312
+ const book = options?.book;
2313
+ const booked = book?.get(key);
2314
+ if (existingRecord && booked) {
2315
+ return { record: existingRecord, account: booked };
2316
+ }
2317
+ if (existingRecord && !existingRecord.usbSessionId && this._forcedTransport === "usb") {
2318
+ await this._tryUsbAttach(existingRecord.walletId, existingRecord.masterFingerprint, {
2319
+ waitForReenumeration: existingRecord.hadUsbSession
2320
+ });
2321
+ _KeystoneAdapter._throwIfAborted(signal);
2322
+ existingRecord = this._devices.get(existingRecord.walletId) ?? existingRecord;
1431
2323
  }
2324
+ const useSinglePathUsbExport = this._forcedTransport !== "qr" && Boolean(existingRecord?.usbSessionId);
2325
+ const requestedSchemaPaths = [
2326
+ { hwkChain, path: syncPath }
2327
+ ];
2328
+ const schemaPaths = useSinglePathUsbExport || requestedSchemaPaths.some((schema) => normalizePath(schema.path) === KEYSTONE_WALLET_ID_PATH) ? requestedSchemaPaths : [{ hwkChain: "evm", path: KEYSTONE_WALLET_ID_PATH }, ...requestedSchemaPaths];
1432
2329
  const requestUr = this.urEngine.buildKeyDerivationRequest({
1433
- schemas: [{ path: syncPath, curve: hwkChain === "sol" ? "ed25519" : "secp256k1" }],
2330
+ schemas: schemaPaths.map((s) => ({
2331
+ path: s.path,
2332
+ curve: s.hwkChain === "sol" ? "ed25519" : "secp256k1"
2333
+ })),
1434
2334
  origin: this._origin
1435
2335
  });
1436
- const responseUr = await this._resolveUr(existingRecord, requestUr, false);
2336
+ let resolvedViaUsb = useSinglePathUsbExport;
2337
+ let responseUr;
2338
+ try {
2339
+ responseUr = await this._resolveUr(existingRecord, requestUr, false, connectId, signal);
2340
+ } catch (error) {
2341
+ if ((0, import_hwk_adapter_core3.isHardwareInteractionId)(connectId) || !useSinglePathUsbExport || !isKeystoneUsbReconnectableError(error)) {
2342
+ throw error;
2343
+ }
2344
+ await waitForKeystoneUsbReattachProbe();
2345
+ _KeystoneAdapter._throwIfAborted(signal);
2346
+ const recoveredRecord = await this._tryUsbAttach(
2347
+ existingRecord?.walletId,
2348
+ existingRecord?.masterFingerprint,
2349
+ { waitForReenumeration: true }
2350
+ );
2351
+ _KeystoneAdapter._throwIfAborted(signal);
2352
+ if (recoveredRecord?.usbSessionId) {
2353
+ try {
2354
+ responseUr = await this._resolveUr(recoveredRecord, requestUr, false, connectId, signal);
2355
+ existingRecord = recoveredRecord;
2356
+ } catch (retryError) {
2357
+ if (!isKeystoneUsbReconnectableError(retryError)) throw retryError;
2358
+ }
2359
+ }
2360
+ if (!responseUr) {
2361
+ if (this._forcedTransport === "usb") throw error;
2362
+ const fallbackSchemaPaths = options?.qrFallbackSchemaPaths ?? [
2363
+ { hwkChain, path: syncPath }
2364
+ ];
2365
+ const qrFallbackSchemas = [
2366
+ { hwkChain: "evm", path: KEYSTONE_WALLET_ID_PATH },
2367
+ ...fallbackSchemaPaths.filter(
2368
+ (schema) => normalizePath(schema.path) !== KEYSTONE_WALLET_ID_PATH
2369
+ )
2370
+ ].map((schema) => ({
2371
+ path: schema.path,
2372
+ curve: schema.hwkChain === "sol" ? "ed25519" : "secp256k1"
2373
+ }));
2374
+ const qrRequestUr = this.urEngine.buildKeyDerivationRequest({
2375
+ schemas: qrFallbackSchemas,
2376
+ origin: this._origin
2377
+ });
2378
+ const displayDevice = existingRecord ? toDeviceInfo(existingRecord) : placeholderDeviceInfo();
2379
+ responseUr = await this._requestQrDisplayAndAwaitResponse(displayDevice, {
2380
+ ...qrRequestUr,
2381
+ animated: false
2382
+ });
2383
+ resolvedViaUsb = false;
2384
+ }
2385
+ }
1437
2386
  _KeystoneAdapter._throwIfAborted(signal);
1438
2387
  const parsed = this.urEngine.parseAccountResponse(responseUr);
1439
- if (wantMfp && parsed.masterFingerprint !== wantMfp) {
1440
- throw (0, import_hwk_adapter_core.createHwkError)({
1441
- code: import_hwk_adapter_core.HardwareErrorCode.DeviceMismatch,
1442
- message: `Scanned Keystone wallet (mfp ${parsed.masterFingerprint}) does not match the requested device (${wantMfp})`
2388
+ let record;
2389
+ if (resolvedViaUsb && existingRecord) {
2390
+ if (parsed.masterFingerprint !== existingRecord.masterFingerprint) {
2391
+ throw (0, import_hwk_adapter_core3.createHwkError)({
2392
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch,
2393
+ message: "Keystone USB account export returned a different master fingerprint"
2394
+ });
2395
+ }
2396
+ record = existingRecord;
2397
+ } else {
2398
+ this._assertParsedIdentity(parsed, target);
2399
+ record = this._upsertDeviceRecord(parsed, {
2400
+ viaUsb: Boolean(existingRecord?.usbSessionId)
1443
2401
  });
1444
2402
  }
1445
- const record = this._upsertDeviceRecord(parsed, {
1446
- viaUsb: Boolean(existingRecord?.usbSessionId)
1447
- });
1448
2403
  const account = parsed.accounts.find((a) => normalizePath(a.path) === syncPath);
1449
2404
  if (!account) {
1450
- throw (0, import_hwk_adapter_core.createHwkError)({
1451
- code: import_hwk_adapter_core.HardwareErrorCode.DeviceMismatch,
2405
+ throw (0, import_hwk_adapter_core3.createHwkError)({
2406
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch,
1452
2407
  message: `Keystone did not return the requested derivation path (${syncPath})`
1453
2408
  });
1454
2409
  }
1455
2410
  const entry = { ...account, hwkChain };
1456
- record.accounts.set(key, entry);
2411
+ if (book) {
2412
+ for (const returned of parsed.accounts) {
2413
+ const returnedChain = inferHwkChainFromPath(returned.path);
2414
+ if (returnedChain) {
2415
+ book.set(accountKey(returnedChain, returned.path), {
2416
+ ...returned,
2417
+ hwkChain: returnedChain
2418
+ });
2419
+ }
2420
+ }
2421
+ book.set(key, entry);
2422
+ }
1457
2423
  return { record, account: entry };
1458
2424
  }
1459
2425
  /**
1460
- * Like `_ensureAccountSynced`, but for operations (PSBT signing, master
2426
+ * Like `_fetchAccount`, but for operations (PSBT signing, master
1461
2427
  * fingerprint) that only need to know WHICH wallet is attached, not a
1462
2428
  * specific cached path. Syncs the account-level path for `chain` as a
1463
- * throwaway probe when the mfp isn't already known.
2429
+ * throwaway probe when the wallet record isn't already known.
1464
2430
  *
1465
2431
  * `CHAIN_FINGERPRINT_PATHS[chain]` is a 5-segment LEAF path for `evm`
1466
2432
  * (`m/44'/60'/0'/0/0`) — sending that verbatim as a KeyDerivation request
1467
2433
  * asks Keystone for a non-standard path. Keystone's own docs
1468
2434
  * (dev.keyst.one's multichain KeyDerivation example) show the ETH
1469
2435
  * account-level path as `m/44'/60'/0'` (3 segments), same as what
1470
- * `DEFAULT_IMPORT_SCHEMAS`/`_ensureAccountSynced` already request — so
2436
+ * `_fetchAccount` already requests — so
1471
2437
  * truncate through `splitAccountPath` here too instead of using the raw
1472
2438
  * fingerprint leaf path. `btc`/`sol` are already 3-segment account paths
1473
2439
  * and pass through unchanged.
1474
2440
  */
1475
- async _ensureMfpKnown(connectId, deviceId, chain, signal) {
1476
- const wantMfp = deviceId ? deviceId.toLowerCase() : this._mfpFromConnectId(connectId ?? "");
1477
- const existing = wantMfp ? this._devices.get(wantMfp) : void 0;
1478
- if (existing) return { record: existing };
1479
- const { accountPath } = splitAccountPath(import_hwk_adapter_core.CHAIN_FINGERPRINT_PATHS[chain]);
2441
+ async _ensureWalletKnown(connectId, deviceId, chain, signal) {
2442
+ const target = this._resolveTarget(connectId, deviceId);
2443
+ if (target.record) return { record: target.record };
2444
+ const attached = await this._tryUsbAttach(target.expectedWalletId);
2445
+ _KeystoneAdapter._throwIfAborted(signal);
2446
+ if (attached) return { record: attached };
2447
+ const { accountPath } = splitAccountPath(import_hwk_adapter_core3.CHAIN_FINGERPRINT_PATHS[chain]);
2448
+ const schemas = accountPath === KEYSTONE_WALLET_ID_PATH ? [{ path: KEYSTONE_WALLET_ID_PATH, curve: "secp256k1" }] : [
2449
+ { path: KEYSTONE_WALLET_ID_PATH, curve: "secp256k1" },
2450
+ {
2451
+ path: accountPath,
2452
+ curve: chain === "sol" ? "ed25519" : "secp256k1"
2453
+ }
2454
+ ];
1480
2455
  const requestUr = this.urEngine.buildKeyDerivationRequest({
1481
- schemas: [{ path: accountPath, curve: chain === "sol" ? "ed25519" : "secp256k1" }],
2456
+ schemas,
1482
2457
  origin: this._origin
1483
2458
  });
1484
- const responseUr = await this._resolveUr(void 0, requestUr, false);
2459
+ const responseUr = await this._resolveUr(void 0, requestUr, false, connectId, signal);
1485
2460
  _KeystoneAdapter._throwIfAborted(signal);
1486
2461
  const parsed = this.urEngine.parseAccountResponse(responseUr);
1487
- if (wantMfp && parsed.masterFingerprint !== wantMfp) {
1488
- throw (0, import_hwk_adapter_core.createHwkError)({
1489
- code: import_hwk_adapter_core.HardwareErrorCode.DeviceMismatch,
1490
- message: `Scanned Keystone wallet (mfp ${parsed.masterFingerprint}) does not match the requested device (${wantMfp})`
1491
- });
1492
- }
1493
- return { record: this._upsertDeviceRecord(parsed) };
2462
+ this._assertParsedIdentity(parsed, target);
2463
+ const record = this._upsertDeviceRecord(parsed);
2464
+ return { record };
1494
2465
  }
1495
2466
  async _requestQrDisplayAndAwaitResponse(device, data) {
1496
2467
  const waitPromise = this._uiRegistry.wait(
1497
- import_hwk_adapter_core.UI_REQUEST.REQUEST_QR_DISPLAY,
2468
+ import_hwk_adapter_core3.UI_REQUEST.REQUEST_QR_DISPLAY,
1498
2469
  { timeoutMs: this._qrTimeoutMs }
1499
2470
  );
1500
- this.emitter.emit(import_hwk_adapter_core.UI_REQUEST.REQUEST_QR_DISPLAY, {
1501
- type: import_hwk_adapter_core.UI_REQUEST.REQUEST_QR_DISPLAY,
2471
+ this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.REQUEST_QR_DISPLAY, {
2472
+ type: import_hwk_adapter_core3.UI_REQUEST.REQUEST_QR_DISPLAY,
1502
2473
  payload: { device, data }
1503
2474
  });
1504
2475
  const response = await waitPromise;
@@ -1506,16 +2477,103 @@ var KeystoneAdapter = class _KeystoneAdapter {
1506
2477
  }
1507
2478
  async _requestQrScanAndAwaitResponse(device) {
1508
2479
  const waitPromise = this._uiRegistry.wait(
1509
- import_hwk_adapter_core.UI_REQUEST.REQUEST_QR_SCAN,
2480
+ import_hwk_adapter_core3.UI_REQUEST.REQUEST_QR_SCAN,
1510
2481
  { timeoutMs: this._qrTimeoutMs }
1511
2482
  );
1512
- this.emitter.emit(import_hwk_adapter_core.UI_REQUEST.REQUEST_QR_SCAN, {
1513
- type: import_hwk_adapter_core.UI_REQUEST.REQUEST_QR_SCAN,
2483
+ this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.REQUEST_QR_SCAN, {
2484
+ type: import_hwk_adapter_core3.UI_REQUEST.REQUEST_QR_SCAN,
1514
2485
  payload: { device }
1515
2486
  });
1516
2487
  const response = await waitPromise;
1517
2488
  return { urType: response.urType, urData: response.urData };
1518
2489
  }
2490
+ async _callUsbConnector(sessionId, method, params, signal) {
2491
+ if (!this._usbConnector) {
2492
+ throw (0, import_hwk_adapter_core3.createHwkError)({
2493
+ code: import_hwk_adapter_core3.HardwareErrorCode.TransportNotAvailable,
2494
+ message: "No USB connector configured for this Keystone adapter"
2495
+ });
2496
+ }
2497
+ if (this._pendingUsbTeardowns > 0 || this._unsettledUsbOperations.size > 0) {
2498
+ throw (0, import_hwk_adapter_core3.createHwkError)({
2499
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceBusyInternal,
2500
+ message: `Keystone USB is busy while calling ${method}`
2501
+ });
2502
+ }
2503
+ const releaseOperation = this._retainUsbOperation(`call:${sessionId}`);
2504
+ let rawCall;
2505
+ try {
2506
+ const connector = this._usbConnector;
2507
+ rawCall = connector.call(sessionId, method, params).finally(releaseOperation);
2508
+ } catch (error) {
2509
+ releaseOperation();
2510
+ throw error;
2511
+ }
2512
+ return signal ? _KeystoneAdapter._abortable(signal, rawCall) : rawCall;
2513
+ }
2514
+ _runUsbTeardown(task) {
2515
+ const previous = this._usbTeardownTail;
2516
+ let releaseTail = () => void 0;
2517
+ this._usbTeardownTail = new Promise((resolve) => {
2518
+ releaseTail = resolve;
2519
+ });
2520
+ this._pendingUsbTeardowns += 1;
2521
+ return (async () => {
2522
+ try {
2523
+ await previous;
2524
+ await this._waitForUsbOperationsToDrain();
2525
+ await task();
2526
+ } finally {
2527
+ this._pendingUsbTeardowns -= 1;
2528
+ releaseTail();
2529
+ }
2530
+ })();
2531
+ }
2532
+ _waitForUsbOperationsToDrain() {
2533
+ if (this._unsettledUsbOperations.size === 0) return Promise.resolve();
2534
+ return new Promise((resolve) => {
2535
+ this._usbIdleWaiters.add(resolve);
2536
+ });
2537
+ }
2538
+ _retainUsbOperation(key) {
2539
+ this._unsettledUsbOperations.set(key, (this._unsettledUsbOperations.get(key) ?? 0) + 1);
2540
+ let released = false;
2541
+ return () => {
2542
+ if (released) return;
2543
+ released = true;
2544
+ const remaining = (this._unsettledUsbOperations.get(key) ?? 1) - 1;
2545
+ if (remaining > 0) {
2546
+ this._unsettledUsbOperations.set(key, remaining);
2547
+ } else {
2548
+ this._unsettledUsbOperations.delete(key);
2549
+ }
2550
+ if (this._unsettledUsbOperations.size === 0) {
2551
+ for (const resolve of this._usbIdleWaiters) resolve();
2552
+ this._usbIdleWaiters.clear();
2553
+ }
2554
+ };
2555
+ }
2556
+ static _abortable(signal, promise) {
2557
+ if (signal.aborted) {
2558
+ return Promise.reject(signal.reason instanceof Error ? signal.reason : new Error("Aborted"));
2559
+ }
2560
+ return new Promise((resolve, reject) => {
2561
+ const onAbort = () => {
2562
+ reject(signal.reason instanceof Error ? signal.reason : new Error("Aborted"));
2563
+ };
2564
+ signal.addEventListener("abort", onAbort, { once: true });
2565
+ promise.then(
2566
+ (value) => {
2567
+ signal.removeEventListener("abort", onAbort);
2568
+ resolve(value);
2569
+ },
2570
+ (error) => {
2571
+ signal.removeEventListener("abort", onAbort);
2572
+ reject(error);
2573
+ }
2574
+ );
2575
+ });
2576
+ }
1519
2577
  static _throwIfAborted(signal) {
1520
2578
  if (signal.aborted) {
1521
2579
  throw signal.reason instanceof Error ? signal.reason : new Error("Operation aborted");
@@ -1523,16 +2581,16 @@ var KeystoneAdapter = class _KeystoneAdapter {
1523
2581
  }
1524
2582
  static _assertRequestIdMatches(expected, actual) {
1525
2583
  if (actual && actual.toLowerCase() !== expected.toLowerCase()) {
1526
- throw (0, import_hwk_adapter_core.createHwkError)({
1527
- code: import_hwk_adapter_core.HardwareErrorCode.DeviceMismatch,
2584
+ throw (0, import_hwk_adapter_core3.createHwkError)({
2585
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch,
1528
2586
  message: "Keystone response requestId does not match the pending request \u2014 discarding a stale or unrelated scan"
1529
2587
  });
1530
2588
  }
1531
2589
  }
1532
2590
  _unsupported(method, reason) {
1533
2591
  return Promise.resolve(
1534
- (0, import_hwk_adapter_core.failure)(
1535
- import_hwk_adapter_core.HardwareErrorCode.MethodNotSupported,
2592
+ (0, import_hwk_adapter_core3.failure)(
2593
+ import_hwk_adapter_core3.HardwareErrorCode.MethodNotSupported,
1536
2594
  `KeystoneAdapter.${method} is not implemented yet: ${reason}`
1537
2595
  )
1538
2596
  );
@@ -1541,38 +2599,47 @@ var KeystoneAdapter = class _KeystoneAdapter {
1541
2599
  if (err && typeof err === "object") {
1542
2600
  const e = err;
1543
2601
  if (typeof e.code === "number") {
1544
- return (0, import_hwk_adapter_core.failure)(e.code, e.message ?? "Unknown error", e.params);
2602
+ const { origin } = e;
2603
+ return (0, import_hwk_adapter_core3.failure)(
2604
+ e.code,
2605
+ e.message ?? "Unknown error",
2606
+ e.params,
2607
+ origin === "device" || origin === "transport" || origin === "host" ? origin : void 0,
2608
+ (0, import_hwk_adapter_core3.isHwkRecoveryHint)(e.recovery) ? e.recovery : void 0
2609
+ );
1545
2610
  }
1546
- if (e._tag === import_hwk_adapter_core.UI_REQUEST_CANCELLED_TAG || e._tag === import_hwk_adapter_core.UI_REQUEST_PREEMPTED_TAG) {
1547
- return (0, import_hwk_adapter_core.failure)(
1548
- import_hwk_adapter_core.HardwareErrorCode.UserAborted,
2611
+ if (e._tag === import_hwk_adapter_core3.UI_REQUEST_CANCELLED_TAG || e._tag === import_hwk_adapter_core3.UI_REQUEST_PREEMPTED_TAG) {
2612
+ return (0, import_hwk_adapter_core3.failure)(
2613
+ import_hwk_adapter_core3.HardwareErrorCode.UserAborted,
1549
2614
  e.message ?? "Keystone QR interaction was cancelled"
1550
2615
  );
1551
2616
  }
1552
- if (e._tag === import_hwk_adapter_core.UI_REQUEST_TIMEOUT_TAG) {
1553
- return (0, import_hwk_adapter_core.failure)(
1554
- import_hwk_adapter_core.HardwareErrorCode.OperationTimeout,
2617
+ if (e._tag === import_hwk_adapter_core3.UI_REQUEST_TIMEOUT_TAG) {
2618
+ return (0, import_hwk_adapter_core3.failure)(
2619
+ import_hwk_adapter_core3.HardwareErrorCode.OperationTimeout,
1555
2620
  e.message ?? "Keystone QR interaction timed out"
1556
2621
  );
1557
2622
  }
1558
2623
  }
1559
2624
  const message = err instanceof Error ? err.message : String(err);
1560
2625
  const params = err instanceof Error && err.stack ? { stack: err.stack } : void 0;
1561
- return (0, import_hwk_adapter_core.failure)(import_hwk_adapter_core.HardwareErrorCode.UnknownError, message, params);
2626
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.UnknownError, message, params);
1562
2627
  }
1563
2628
  };
1564
2629
  // Annotate the CommonJS export names for ESM import in node:
1565
2630
  0 && (module.exports = {
2631
+ KEYSTONE_WALLET_CONNECT_ID_PREFIX,
2632
+ KEYSTONE_WALLET_ID_PATH,
1566
2633
  KeystoneAdapter,
1567
2634
  KeystoneUrEngine,
1568
- QR_CONNECT_ID_PREFIX,
1569
2635
  accountKey,
1570
2636
  btcScriptTypeFromPath,
1571
2637
  createDeviceRecord,
2638
+ deriveKeystoneWalletId,
1572
2639
  normalizePath,
1573
2640
  placeholderDeviceInfo,
1574
- qrConnectId,
1575
2641
  splitAccountPath,
1576
- toDeviceInfo
2642
+ toDeviceInfo,
2643
+ walletConnectId
1577
2644
  });
1578
2645
  //# sourceMappingURL=index.js.map