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

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.mjs CHANGED
@@ -136,6 +136,11 @@ function fromSdkUr(ur) {
136
136
  return { urType: ur.type, urData: ur.cbor.toString("hex") };
137
137
  }
138
138
  function splitSignature65(hex) {
139
+ if (hex.length !== 130) {
140
+ throw new Error(
141
+ `Keystone returned a ${hex.length / 2}-byte signature; expected 65 bytes (r|s|v)`
142
+ );
143
+ }
139
144
  return { r: hex.slice(0, 64), s: hex.slice(64, 128), v: hex.slice(128) };
140
145
  }
141
146
  function requireBip32MasterFingerprint(value) {
@@ -439,7 +444,7 @@ import {
439
444
  DEVICE,
440
445
  DeviceJobQueue,
441
446
  HardwareErrorCode,
442
- InteractionRegistry,
447
+ OperationRegistry,
443
448
  SDK,
444
449
  TypedEventEmitter,
445
450
  UI_REQUEST,
@@ -456,7 +461,7 @@ import {
456
461
  getAllNetworkMethodChain,
457
462
  hasHardwareRuntimeIdPrefix,
458
463
  isAllNetworkMethodName,
459
- isHardwareInteractionId,
464
+ isHardwareOperationId,
460
465
  isHwkRecoveryHint,
461
466
  operationMayHaveCompletedParams,
462
467
  parseBip32MasterFingerprint as parseBip32MasterFingerprint2,
@@ -580,12 +585,8 @@ function placeholderDeviceInfo() {
580
585
  var COLD_START_JOB_LABEL = "keystone-cold-start";
581
586
  var KEYSTONE_USB_REATTACH_PROBE_ATTEMPTS = 4;
582
587
  var KEYSTONE_USB_REATTACH_PROBE_INTERVAL_MS = 500;
583
- function resolveHardwareOperationTarget(positionalTargetId, interactionId) {
584
- const result = resolveGenericHardwareOperationTarget(
585
- positionalTargetId,
586
- interactionId,
587
- "keystone"
588
- );
588
+ function resolveHardwareOperationTarget(positionalTargetId, operationId) {
589
+ const result = resolveGenericHardwareOperationTarget(positionalTargetId, operationId, "keystone");
589
590
  return result;
590
591
  }
591
592
  function waitForKeystoneUsbReattachProbe() {
@@ -593,10 +594,8 @@ function waitForKeystoneUsbReattachProbe() {
593
594
  setTimeout(resolve, KEYSTONE_USB_REATTACH_PROBE_INTERVAL_MS);
594
595
  });
595
596
  }
596
- function isKeystoneUsbReconnectableError(error) {
597
- if (!error || typeof error !== "object") return false;
598
- const { code } = error;
599
- return code === HardwareErrorCode.DeviceNotFound || code === HardwareErrorCode.DeviceDisconnected;
597
+ function getKeystoneJobId(connectId, deviceId) {
598
+ return isHardwareOperationId(connectId) ? connectId : deviceId || connectId || COLD_START_JOB_LABEL;
600
599
  }
601
600
  var BIP44_COIN_TYPE_TO_CHAIN = {
602
601
  60: "evm",
@@ -612,20 +611,20 @@ var KeystoneAdapter = class _KeystoneAdapter {
612
611
  constructor(options) {
613
612
  this.vendor = "keystone";
614
613
  this.emitter = new TypedEventEmitter();
615
- this._interactionRoutes = /* @__PURE__ */ new Map();
616
- this._interactions = new InteractionRegistry({
614
+ this._operationRoutes = /* @__PURE__ */ new Map();
615
+ this._operations = new OperationRegistry({
617
616
  vendor: "keystone",
618
- onEnded: (interaction, reason) => {
619
- const route = this._interactionRoutes.get(interaction.connectId);
620
- if (route?.interactionId === interaction.interactionId) {
621
- this._interactionRoutes.delete(interaction.connectId);
617
+ onEnded: (operation, reason) => {
618
+ const route = this._operationRoutes.get(operation.connectId);
619
+ if (route?.operationId === operation.operationId) {
620
+ this._operationRoutes.delete(operation.connectId);
622
621
  }
623
- this.emitter.emit(SDK.INTERACTION_ENDED, {
624
- type: SDK.INTERACTION_ENDED,
625
- payload: { interactionId: interaction.interactionId, reason }
622
+ this.emitter.emit(SDK.OPERATION_ENDED, {
623
+ type: SDK.OPERATION_ENDED,
624
+ payload: { operationId: operation.operationId, reason }
626
625
  });
627
626
  if (reason === "timeout") {
628
- this._releaseInteractionConnection(interaction).catch(() => void 0);
627
+ this._releaseOperationConnection(operation).catch(() => void 0);
629
628
  }
630
629
  }
631
630
  });
@@ -641,8 +640,8 @@ var KeystoneAdapter = class _KeystoneAdapter {
641
640
  this._handleUsbDisconnect = ({ connectId }) => {
642
641
  const record = Array.from(this._devices.values()).find((item) => item.usbSessionId === connectId);
643
642
  if (!record) return;
644
- this._interactions.endByConnectionKey(connectId, "disconnect");
645
- this._interactions.endByConnectionKey(record.connectId, "disconnect");
643
+ this._operations.endByConnectionKey(connectId, "disconnect");
644
+ this._operations.endByConnectionKey(record.connectId, "disconnect");
646
645
  record.usbSessionId = void 0;
647
646
  const info = toDeviceInfo(record);
648
647
  if (record.qrSynced) {
@@ -660,10 +659,10 @@ var KeystoneAdapter = class _KeystoneAdapter {
660
659
  // there's exactly one implementation of each chain's address logic.
661
660
  // ---------------------------------------------------------------------------
662
661
  this.allNetworkGetAddress = async (connectId, deviceId, params) => {
663
- const operationTarget = resolveHardwareOperationTarget(connectId, params.interactionId);
662
+ const operationTarget = resolveHardwareOperationTarget(connectId, params.operationId);
664
663
  if (!operationTarget.success) return operationTarget;
665
664
  const effectiveConnectId = operationTarget.payload.targetId ?? "";
666
- const { interactionId } = operationTarget.payload;
665
+ const { operationId } = operationTarget.payload;
667
666
  try {
668
667
  const prefetched = await this._prefetchAllNetworkAccounts(
669
668
  effectiveConnectId,
@@ -680,7 +679,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
680
679
  const commonArgs = {
681
680
  path: item.path,
682
681
  showOnDevice: item.showOnDevice,
683
- interactionId
682
+ operationId
684
683
  };
685
684
  switch (method) {
686
685
  case "evmGetAddress":
@@ -749,7 +748,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
749
748
  return Promise.resolve();
750
749
  }
751
750
  async dispose() {
752
- this._interactions.endAll("runtime-reset");
751
+ this._operations.endAll("runtime-reset");
753
752
  this._uiRegistry.cancel();
754
753
  this._jobQueue.clear();
755
754
  this._searchDeviceTargets.clear();
@@ -784,10 +783,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
784
783
  }
785
784
  const known = Array.from(this._devices.values()).map(toDeviceInfo);
786
785
  if (options?.transportType === "qr") {
787
- const searchTargetId = createHardwareSearchTargetId({
788
- vendor: "keystone",
789
- connectionType: "qr"
790
- });
786
+ const searchTargetId = createHardwareSearchTargetId("keystone");
791
787
  this._searchDeviceTargets.set(searchTargetId, "qr");
792
788
  return [
793
789
  {
@@ -835,7 +831,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
835
831
  async _resetUsbSessions() {
836
832
  await this._runUsbTeardown(async () => {
837
833
  await this._usbConnectTail;
838
- this._interactions.endAll("runtime-reset");
834
+ this._operations.endAll("runtime-reset");
839
835
  if (!this._usbConnector) return;
840
836
  const sessionIds = new Set(
841
837
  Array.from(this._devices.values()).map((record) => record.usbSessionId).filter((sessionId) => Boolean(sessionId))
@@ -914,18 +910,18 @@ var KeystoneAdapter = class _KeystoneAdapter {
914
910
  }
915
911
  if (!connected.success) return connected;
916
912
  const record = this._devices.get(connected.payload.deviceId);
917
- this._interactions.endByConnectionKey(connected.payload.connectId, "explicit");
918
- const interaction = this._interactions.create({
913
+ this._operations.endByConnectionKey(connected.payload.connectId, "explicit");
914
+ const operation = this._operations.create({
919
915
  searchTargetId,
920
916
  connectId: connected.payload.connectId,
921
917
  device: connected.payload,
922
918
  connectionKeys: selectedConnectionType === "usb" && record?.usbSessionId ? [record.usbSessionId] : []
923
919
  });
924
- this._interactionRoutes.set(connected.payload.connectId, {
925
- interactionId: interaction.interactionId,
920
+ this._operationRoutes.set(connected.payload.connectId, {
921
+ operationId: operation.operationId,
926
922
  connectionType: selectedConnectionType
927
923
  });
928
- return success(interaction.interactionId);
924
+ return success(operation.operationId);
929
925
  } catch (err) {
930
926
  return this._errorToFailure(err);
931
927
  }
@@ -937,25 +933,25 @@ var KeystoneAdapter = class _KeystoneAdapter {
937
933
  * QR-only (if it was ever QR-synced) or removes it entirely (pure-USB
938
934
  * wallet that was never seen over QR) — see §4.2 of the design doc.
939
935
  */
940
- async releaseInteraction(interactionId) {
941
- const interaction = this._interactions.find(interactionId);
942
- if (!interaction) {
943
- this._interactions.resolve(interactionId);
936
+ async releaseOperation(operationId) {
937
+ const operation = this._operations.find(operationId);
938
+ if (!operation) {
939
+ this._operations.resolve(operationId);
944
940
  return;
945
941
  }
946
- const endedInteraction = this._interactions.end(interactionId, "explicit");
947
- if (!endedInteraction) return;
948
- await this._releaseInteractionConnection(endedInteraction);
942
+ const endedOperation = this._operations.end(operationId, "explicit");
943
+ if (!endedOperation) return;
944
+ await this._releaseOperationConnection(endedOperation);
949
945
  }
950
- async _releaseInteractionConnection(interaction) {
951
- const { connectId } = interaction;
946
+ async _releaseOperationConnection(operation) {
947
+ const { connectId } = operation;
952
948
  let record;
953
949
  try {
954
950
  record = this._resolveTarget(connectId).record;
955
951
  } catch {
956
952
  return;
957
953
  }
958
- if (!record?.usbSessionId || !interaction.connectionKeys.includes(record.usbSessionId)) {
954
+ if (!record?.usbSessionId || !operation.connectionKeys.includes(record.usbSessionId)) {
959
955
  return;
960
956
  }
961
957
  const { usbSessionId } = record;
@@ -969,9 +965,9 @@ var KeystoneAdapter = class _KeystoneAdapter {
969
965
  this._handleUsbDisconnect({ connectId: usbSessionId });
970
966
  });
971
967
  }
972
- getDeviceInfo(connectIdOrInteractionId, deviceId) {
968
+ getDeviceInfo(connectIdOrOperationId, deviceId) {
973
969
  try {
974
- const connectId = isHardwareInteractionId(connectIdOrInteractionId) ? this._interactions.resolve(connectIdOrInteractionId).connectId : connectIdOrInteractionId;
970
+ const connectId = isHardwareOperationId(connectIdOrOperationId) ? this._operations.resolve(connectIdOrOperationId).connectId : connectIdOrOperationId;
975
971
  const { record } = this._resolveTarget(connectId, deviceId);
976
972
  if (!record) {
977
973
  return Promise.resolve(
@@ -986,21 +982,26 @@ var KeystoneAdapter = class _KeystoneAdapter {
986
982
  return Promise.resolve(this._errorToFailure(err));
987
983
  }
988
984
  }
989
- getSupportedChains() {
990
- return ["evm", "btc", "sol", "tron"];
991
- }
992
985
  cancel(connectId) {
993
986
  const reason = createHwkError({
994
987
  code: HardwareErrorCode.UserAborted,
995
988
  message: "User aborted operation"
996
989
  });
997
- this._uiRegistry.cancel();
998
990
  const activeJobId = this._jobQueue.getActiveJob()?.deviceId;
999
- const targetId = connectId ?? activeJobId;
1000
- this._jobQueue.cancelActiveAndPending(
1001
- targetId && isHardwareInteractionId(targetId) ? activeJobId ?? targetId : targetId,
1002
- reason
1003
- );
991
+ if (connectId) {
992
+ if (!activeJobId || activeJobId !== connectId && activeJobId !== this._walletIdFromIdentifier(connectId)) {
993
+ this._jobQueue.cancelActiveAndPending(connectId, reason);
994
+ const walletId = this._walletIdFromIdentifier(connectId);
995
+ if (walletId && walletId !== connectId) {
996
+ this._jobQueue.cancelActiveAndPending(walletId, reason);
997
+ }
998
+ return;
999
+ }
1000
+ this._jobQueue.cancelActiveAndPending(activeJobId, reason);
1001
+ } else {
1002
+ this._jobQueue.cancelActiveAndPending(void 0, reason);
1003
+ }
1004
+ this._uiRegistry.cancel();
1004
1005
  }
1005
1006
  getChainFingerprint(connectId, deviceId, chain) {
1006
1007
  try {
@@ -1063,7 +1064,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
1063
1064
  // EVM
1064
1065
  // ---------------------------------------------------------------------------
1065
1066
  async evmGetAddress(connectIdArg, deviceIdArg, paramsArg, book) {
1066
- const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1067
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.operationId);
1067
1068
  if (!operationTarget.success) return operationTarget;
1068
1069
  const connectId = operationTarget.payload.targetId;
1069
1070
  const deviceId = deviceIdArg ?? void 0;
@@ -1079,37 +1080,34 @@ var KeystoneAdapter = class _KeystoneAdapter {
1079
1080
  );
1080
1081
  }
1081
1082
  try {
1082
- return await this._jobQueue.enqueue(
1083
- deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1084
- async (signal) => {
1085
- const { account } = await this._fetchAccount(
1086
- connectId,
1087
- deviceId,
1088
- "evm",
1089
- accountPath,
1090
- signal,
1091
- { book }
1092
- );
1093
- _KeystoneAdapter._throwIfAborted(signal);
1094
- if (!account.extendedPublicKey) {
1095
- throw createHwkError({
1096
- code: HardwareErrorCode.MethodNotSupported,
1097
- message: "Keystone did not return an extended public key for this account path"
1098
- });
1099
- }
1100
- const address = this.urEngine.deriveEvmAddressFromXpub(
1101
- account.extendedPublicKey,
1102
- relativeDerivePath
1103
- );
1104
- return success({ address, path: normalizePath(params.path) });
1083
+ return await this._jobQueue.enqueue(getKeystoneJobId(connectId, deviceId), async (signal) => {
1084
+ const { account } = await this._fetchAccount(
1085
+ connectId,
1086
+ deviceId,
1087
+ "evm",
1088
+ accountPath,
1089
+ signal,
1090
+ { book }
1091
+ );
1092
+ _KeystoneAdapter._throwIfAborted(signal);
1093
+ if (!account.extendedPublicKey) {
1094
+ throw createHwkError({
1095
+ code: HardwareErrorCode.MethodNotSupported,
1096
+ message: "Keystone did not return an extended public key for this account path"
1097
+ });
1105
1098
  }
1106
- );
1099
+ const address = this.urEngine.deriveEvmAddressFromXpub(
1100
+ account.extendedPublicKey,
1101
+ relativeDerivePath
1102
+ );
1103
+ return success({ address, path: normalizePath(params.path) });
1104
+ });
1107
1105
  } catch (err) {
1108
1106
  return this._errorToFailure(err);
1109
1107
  }
1110
1108
  }
1111
1109
  async evmSignTransaction(connectIdArg, deviceIdArg, paramsArg) {
1112
- const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1110
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.operationId);
1113
1111
  if (!operationTarget.success) return operationTarget;
1114
1112
  const connectId = operationTarget.payload.targetId;
1115
1113
  const deviceId = deviceIdArg ?? void 0;
@@ -1128,45 +1126,42 @@ var KeystoneAdapter = class _KeystoneAdapter {
1128
1126
  const rawTxHex = stripHex(params.serializedTx);
1129
1127
  const path = normalizePath(params.path);
1130
1128
  try {
1131
- return await this._jobQueue.enqueue(
1132
- deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1133
- async (signal) => {
1134
- const { record } = await this._ensureWalletKnown(connectId, deviceId, "evm", signal);
1135
- _KeystoneAdapter._throwIfAborted(signal);
1136
- const requestId = uuidv4();
1137
- const dataType = parseInt(rawTxHex.slice(0, 2), 16) < 192 ? "typedTransaction" : "transaction";
1138
- const requestUr = this.urEngine.buildEthSignRequest({
1139
- requestId,
1140
- unsignedTxHex: rawTxHex,
1141
- dataType,
1142
- path,
1143
- xfp: record.masterFingerprint,
1144
- chainId: params.chainId
1145
- });
1146
- const responseUr = await this._resolveUr(
1147
- record,
1148
- requestUr,
1149
- true,
1150
- connectId,
1151
- signal,
1152
- "evmSignTransaction"
1153
- );
1154
- _KeystoneAdapter._throwIfAborted(signal);
1155
- const sig = this.urEngine.parseEthSignature(responseUr);
1156
- _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1157
- return success({
1158
- v: ensure0x(sig.v),
1159
- r: ensure0x(sig.r),
1160
- s: ensure0x(sig.s)
1161
- });
1162
- }
1163
- );
1129
+ return await this._jobQueue.enqueue(getKeystoneJobId(connectId, deviceId), async (signal) => {
1130
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "evm", signal);
1131
+ _KeystoneAdapter._throwIfAborted(signal);
1132
+ const requestId = uuidv4();
1133
+ const dataType = parseInt(rawTxHex.slice(0, 2), 16) < 192 ? "typedTransaction" : "transaction";
1134
+ const requestUr = this.urEngine.buildEthSignRequest({
1135
+ requestId,
1136
+ unsignedTxHex: rawTxHex,
1137
+ dataType,
1138
+ path,
1139
+ xfp: record.masterFingerprint,
1140
+ chainId: params.chainId
1141
+ });
1142
+ const responseUr = await this._resolveUr(
1143
+ record,
1144
+ requestUr,
1145
+ true,
1146
+ connectId,
1147
+ signal,
1148
+ "evmSignTransaction"
1149
+ );
1150
+ _KeystoneAdapter._throwIfAborted(signal);
1151
+ const sig = this.urEngine.parseEthSignature(responseUr);
1152
+ _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1153
+ return success({
1154
+ v: ensure0x(sig.v),
1155
+ r: ensure0x(sig.r),
1156
+ s: ensure0x(sig.s)
1157
+ });
1158
+ });
1164
1159
  } catch (err) {
1165
1160
  return this._errorToFailure(err);
1166
1161
  }
1167
1162
  }
1168
1163
  async evmSignMessage(connectIdArg, deviceIdArg, paramsArg) {
1169
- const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1164
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.operationId);
1170
1165
  if (!operationTarget.success) return operationTarget;
1171
1166
  const connectId = operationTarget.payload.targetId;
1172
1167
  const deviceId = deviceIdArg ?? void 0;
@@ -1181,40 +1176,37 @@ var KeystoneAdapter = class _KeystoneAdapter {
1181
1176
  const messageHex = params.hex ? stripHex(params.message) : Buffer.from(params.message, "utf8").toString("hex");
1182
1177
  const path = normalizePath(params.path);
1183
1178
  try {
1184
- return await this._jobQueue.enqueue(
1185
- deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1186
- async (signal) => {
1187
- const { record } = await this._ensureWalletKnown(connectId, deviceId, "evm", signal);
1188
- _KeystoneAdapter._throwIfAborted(signal);
1189
- const requestId = uuidv4();
1190
- const requestUr = this.urEngine.buildEthSignRequest({
1191
- requestId,
1192
- unsignedTxHex: messageHex,
1193
- dataType: "personalMessage",
1194
- path,
1195
- xfp: record.masterFingerprint,
1196
- chainId: params.chainId
1197
- });
1198
- const responseUr = await this._resolveUr(
1199
- record,
1200
- requestUr,
1201
- true,
1202
- connectId,
1203
- signal,
1204
- "evmSignMessage"
1205
- );
1206
- _KeystoneAdapter._throwIfAborted(signal);
1207
- const sig = this.urEngine.parseEthSignature(responseUr);
1208
- _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1209
- return success({ signature: ensure0x(sig.r + sig.s + sig.v) });
1210
- }
1211
- );
1179
+ return await this._jobQueue.enqueue(getKeystoneJobId(connectId, deviceId), async (signal) => {
1180
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "evm", signal);
1181
+ _KeystoneAdapter._throwIfAborted(signal);
1182
+ const requestId = uuidv4();
1183
+ const requestUr = this.urEngine.buildEthSignRequest({
1184
+ requestId,
1185
+ unsignedTxHex: messageHex,
1186
+ dataType: "personalMessage",
1187
+ path,
1188
+ xfp: record.masterFingerprint,
1189
+ chainId: params.chainId
1190
+ });
1191
+ const responseUr = await this._resolveUr(
1192
+ record,
1193
+ requestUr,
1194
+ true,
1195
+ connectId,
1196
+ signal,
1197
+ "evmSignMessage"
1198
+ );
1199
+ _KeystoneAdapter._throwIfAborted(signal);
1200
+ const sig = this.urEngine.parseEthSignature(responseUr);
1201
+ _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1202
+ return success({ signature: ensure0x(sig.r + sig.s + sig.v) });
1203
+ });
1212
1204
  } catch (err) {
1213
1205
  return this._errorToFailure(err);
1214
1206
  }
1215
1207
  }
1216
1208
  async evmSignTypedData(connectIdArg, deviceIdArg, paramsArg) {
1217
- const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1209
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.operationId);
1218
1210
  if (!operationTarget.success) return operationTarget;
1219
1211
  const connectId = operationTarget.payload.targetId;
1220
1212
  const deviceId = deviceIdArg ?? void 0;
@@ -1230,37 +1222,37 @@ var KeystoneAdapter = class _KeystoneAdapter {
1230
1222
  "Keystone always displays the full EIP-712 payload for on-device review \u2014 pre-hashed signing is not supported"
1231
1223
  );
1232
1224
  }
1233
- const signDataHex = Buffer.from(JSON.stringify(params.data), "utf8").toString("hex");
1225
+ const signDataHex = Buffer.from(
1226
+ params.dataJson ?? JSON.stringify(params.data),
1227
+ "utf8"
1228
+ ).toString("hex");
1234
1229
  const path = normalizePath(params.path);
1235
1230
  try {
1236
- return await this._jobQueue.enqueue(
1237
- deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1238
- async (signal) => {
1239
- const { record } = await this._ensureWalletKnown(connectId, deviceId, "evm", signal);
1240
- _KeystoneAdapter._throwIfAborted(signal);
1241
- const requestId = uuidv4();
1242
- const requestUr = this.urEngine.buildEthSignRequest({
1243
- requestId,
1244
- unsignedTxHex: signDataHex,
1245
- dataType: "typedData",
1246
- path,
1247
- xfp: record.masterFingerprint,
1248
- chainId: params.chainId
1249
- });
1250
- const responseUr = await this._resolveUr(
1251
- record,
1252
- requestUr,
1253
- true,
1254
- connectId,
1255
- signal,
1256
- "evmSignTypedData"
1257
- );
1258
- _KeystoneAdapter._throwIfAborted(signal);
1259
- const sig = this.urEngine.parseEthSignature(responseUr);
1260
- _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1261
- return success({ signature: ensure0x(sig.r + sig.s + sig.v) });
1262
- }
1263
- );
1231
+ return await this._jobQueue.enqueue(getKeystoneJobId(connectId, deviceId), async (signal) => {
1232
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "evm", signal);
1233
+ _KeystoneAdapter._throwIfAborted(signal);
1234
+ const requestId = uuidv4();
1235
+ const requestUr = this.urEngine.buildEthSignRequest({
1236
+ requestId,
1237
+ unsignedTxHex: signDataHex,
1238
+ dataType: "typedData",
1239
+ path,
1240
+ xfp: record.masterFingerprint,
1241
+ chainId: params.chainId
1242
+ });
1243
+ const responseUr = await this._resolveUr(
1244
+ record,
1245
+ requestUr,
1246
+ true,
1247
+ connectId,
1248
+ signal,
1249
+ "evmSignTypedData"
1250
+ );
1251
+ _KeystoneAdapter._throwIfAborted(signal);
1252
+ const sig = this.urEngine.parseEthSignature(responseUr);
1253
+ _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1254
+ return success({ signature: ensure0x(sig.r + sig.s + sig.v) });
1255
+ });
1264
1256
  } catch (err) {
1265
1257
  return this._errorToFailure(err);
1266
1258
  }
@@ -1272,7 +1264,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
1272
1264
  // PSBT construction. Both are real, bounded follow-ups, not silent gaps.
1273
1265
  // ---------------------------------------------------------------------------
1274
1266
  async btcGetAddress(connectIdArg, deviceIdArg, paramsArg, book) {
1275
- const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1267
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.operationId);
1276
1268
  if (!operationTarget.success) return operationTarget;
1277
1269
  const connectId = operationTarget.payload.targetId;
1278
1270
  const deviceId = deviceIdArg ?? void 0;
@@ -1305,32 +1297,29 @@ var KeystoneAdapter = class _KeystoneAdapter {
1305
1297
  return failure(HardwareErrorCode.DevicePathForbidden, KEYSTONE_BTC_ACCOUNT_FORBIDDEN_MESSAGE);
1306
1298
  }
1307
1299
  try {
1308
- return await this._jobQueue.enqueue(
1309
- deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1310
- async (signal) => {
1311
- const { account } = await this._fetchAccount(
1312
- connectId,
1313
- deviceId,
1314
- "btc",
1315
- accountPath,
1316
- signal,
1317
- { book }
1318
- );
1319
- _KeystoneAdapter._throwIfAborted(signal);
1320
- if (!account.extendedPublicKey) {
1321
- throw createHwkError({
1322
- code: HardwareErrorCode.MethodNotSupported,
1323
- message: "Keystone did not return an extended public key for this account path"
1324
- });
1325
- }
1326
- const address = this.urEngine.deriveBtcAddressFromXpub(
1327
- account.extendedPublicKey,
1328
- relativeDerivePath,
1329
- scriptType
1330
- );
1331
- return success({ address, path: normalizedPath });
1300
+ return await this._jobQueue.enqueue(getKeystoneJobId(connectId, deviceId), async (signal) => {
1301
+ const { account } = await this._fetchAccount(
1302
+ connectId,
1303
+ deviceId,
1304
+ "btc",
1305
+ accountPath,
1306
+ signal,
1307
+ { book }
1308
+ );
1309
+ _KeystoneAdapter._throwIfAborted(signal);
1310
+ if (!account.extendedPublicKey) {
1311
+ throw createHwkError({
1312
+ code: HardwareErrorCode.MethodNotSupported,
1313
+ message: "Keystone did not return an extended public key for this account path"
1314
+ });
1332
1315
  }
1333
- );
1316
+ const address = this.urEngine.deriveBtcAddressFromXpub(
1317
+ account.extendedPublicKey,
1318
+ relativeDerivePath,
1319
+ scriptType
1320
+ );
1321
+ return success({ address, path: normalizedPath });
1322
+ });
1334
1323
  } catch (err) {
1335
1324
  return this._errorToFailure(err);
1336
1325
  }
@@ -1345,7 +1334,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
1345
1334
  * this package doesn't wire in.
1346
1335
  */
1347
1336
  async btcGetPublicKey(connectIdArg, deviceIdArg, paramsArg, book) {
1348
- const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1337
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.operationId);
1349
1338
  if (!operationTarget.success) return operationTarget;
1350
1339
  const connectId = operationTarget.payload.targetId;
1351
1340
  const deviceId = deviceIdArg ?? void 0;
@@ -1364,35 +1353,32 @@ var KeystoneAdapter = class _KeystoneAdapter {
1364
1353
  return failure(HardwareErrorCode.DevicePathForbidden, KEYSTONE_BTC_ACCOUNT_FORBIDDEN_MESSAGE);
1365
1354
  }
1366
1355
  try {
1367
- return await this._jobQueue.enqueue(
1368
- deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1369
- async (signal) => {
1370
- const { account } = await this._fetchAccount(
1371
- connectId,
1372
- deviceId,
1373
- "btc",
1374
- accountPath,
1375
- signal,
1376
- { book }
1377
- );
1378
- _KeystoneAdapter._throwIfAborted(signal);
1379
- if (!account.extendedPublicKey) {
1380
- throw createHwkError({
1381
- code: HardwareErrorCode.MethodNotSupported,
1382
- message: "Keystone did not return an extended public key for this account path"
1383
- });
1384
- }
1385
- const meta = this.urEngine.parseXpubMeta(account.extendedPublicKey);
1386
- return success({
1387
- xpub: account.extendedPublicKey,
1388
- publicKey: meta.publicKey,
1389
- chainCode: meta.chainCode,
1390
- depth: meta.depth,
1391
- fingerprint: meta.parentFingerprint,
1392
- path: normalizePath(accountPath)
1356
+ return await this._jobQueue.enqueue(getKeystoneJobId(connectId, deviceId), async (signal) => {
1357
+ const { account } = await this._fetchAccount(
1358
+ connectId,
1359
+ deviceId,
1360
+ "btc",
1361
+ accountPath,
1362
+ signal,
1363
+ { book }
1364
+ );
1365
+ _KeystoneAdapter._throwIfAborted(signal);
1366
+ if (!account.extendedPublicKey) {
1367
+ throw createHwkError({
1368
+ code: HardwareErrorCode.MethodNotSupported,
1369
+ message: "Keystone did not return an extended public key for this account path"
1393
1370
  });
1394
1371
  }
1395
- );
1372
+ const meta = this.urEngine.parseXpubMeta(account.extendedPublicKey);
1373
+ return success({
1374
+ xpub: account.extendedPublicKey,
1375
+ publicKey: meta.publicKey,
1376
+ chainCode: meta.chainCode,
1377
+ depth: meta.depth,
1378
+ fingerprint: meta.parentFingerprint,
1379
+ path: normalizePath(accountPath)
1380
+ });
1381
+ });
1396
1382
  } catch (err) {
1397
1383
  return this._errorToFailure(err);
1398
1384
  }
@@ -1404,7 +1390,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
1404
1390
  );
1405
1391
  }
1406
1392
  async btcSignPsbt(connectIdArg, deviceIdArg, paramsArg) {
1407
- const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1393
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.operationId);
1408
1394
  if (!operationTarget.success) return operationTarget;
1409
1395
  const connectId = operationTarget.payload.targetId;
1410
1396
  const deviceId = deviceIdArg ?? void 0;
@@ -1416,31 +1402,28 @@ var KeystoneAdapter = class _KeystoneAdapter {
1416
1402
  return failure(HardwareErrorCode.DevicePathForbidden, KEYSTONE_BTC_ACCOUNT_FORBIDDEN_MESSAGE);
1417
1403
  }
1418
1404
  try {
1419
- return await this._jobQueue.enqueue(
1420
- deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1421
- async (signal) => {
1422
- const { record } = await this._ensureWalletKnown(connectId, deviceId, "btc", signal);
1423
- _KeystoneAdapter._throwIfAborted(signal);
1424
- const requestUr = this.urEngine.buildBtcPsbtRequest(stripHex(params.psbt));
1425
- const responseUr = await this._resolveUr(
1426
- record,
1427
- requestUr,
1428
- true,
1429
- connectId,
1430
- signal,
1431
- "btcSignPsbt"
1432
- );
1433
- _KeystoneAdapter._throwIfAborted(signal);
1434
- const signedPsbt = this.urEngine.parseBtcPsbt(responseUr);
1435
- return success({ signedPsbt });
1436
- }
1437
- );
1405
+ return await this._jobQueue.enqueue(getKeystoneJobId(connectId, deviceId), async (signal) => {
1406
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "btc", signal);
1407
+ _KeystoneAdapter._throwIfAborted(signal);
1408
+ const requestUr = this.urEngine.buildBtcPsbtRequest(stripHex(params.psbt));
1409
+ const responseUr = await this._resolveUr(
1410
+ record,
1411
+ requestUr,
1412
+ true,
1413
+ connectId,
1414
+ signal,
1415
+ "btcSignPsbt"
1416
+ );
1417
+ _KeystoneAdapter._throwIfAborted(signal);
1418
+ const signedPsbt = this.urEngine.parseBtcPsbt(responseUr);
1419
+ return success({ signedPsbt });
1420
+ });
1438
1421
  } catch (err) {
1439
1422
  return this._errorToFailure(err);
1440
1423
  }
1441
1424
  }
1442
1425
  async btcSignMessage(connectIdArg, deviceIdArg, paramsArg) {
1443
- const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1426
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.operationId);
1444
1427
  if (!operationTarget.success) return operationTarget;
1445
1428
  const connectId = operationTarget.payload.targetId;
1446
1429
  const deviceId = deviceIdArg ?? void 0;
@@ -1458,48 +1441,42 @@ var KeystoneAdapter = class _KeystoneAdapter {
1458
1441
  return failure(HardwareErrorCode.DevicePathForbidden, KEYSTONE_BTC_ACCOUNT_FORBIDDEN_MESSAGE);
1459
1442
  }
1460
1443
  try {
1461
- return await this._jobQueue.enqueue(
1462
- deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1463
- async (signal) => {
1464
- const { record } = await this._ensureWalletKnown(connectId, deviceId, "btc", signal);
1465
- _KeystoneAdapter._throwIfAborted(signal);
1466
- const requestId = uuidv4();
1467
- const requestUr = this.urEngine.buildBtcMessageSignRequest({
1468
- requestId,
1469
- messageHex,
1470
- accounts: [{ path, xfp: record.masterFingerprint }]
1471
- });
1472
- const responseUr = await this._resolveUr(
1473
- record,
1474
- requestUr,
1475
- true,
1476
- connectId,
1477
- signal,
1478
- "btcSignMessage"
1479
- );
1480
- _KeystoneAdapter._throwIfAborted(signal);
1481
- const sig = this.urEngine.parseBtcSignature(responseUr);
1482
- _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1483
- return success({ signature: sig.signature });
1484
- }
1485
- );
1444
+ return await this._jobQueue.enqueue(getKeystoneJobId(connectId, deviceId), async (signal) => {
1445
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "btc", signal);
1446
+ _KeystoneAdapter._throwIfAborted(signal);
1447
+ const requestId = uuidv4();
1448
+ const requestUr = this.urEngine.buildBtcMessageSignRequest({
1449
+ requestId,
1450
+ messageHex,
1451
+ accounts: [{ path, xfp: record.masterFingerprint }]
1452
+ });
1453
+ const responseUr = await this._resolveUr(
1454
+ record,
1455
+ requestUr,
1456
+ true,
1457
+ connectId,
1458
+ signal,
1459
+ "btcSignMessage"
1460
+ );
1461
+ _KeystoneAdapter._throwIfAborted(signal);
1462
+ const sig = this.urEngine.parseBtcSignature(responseUr);
1463
+ _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1464
+ return success({ signature: sig.signature });
1465
+ });
1486
1466
  } catch (err) {
1487
1467
  return this._errorToFailure(err);
1488
1468
  }
1489
1469
  }
1490
1470
  async btcGetMasterFingerprint(connectIdArg, deviceIdArg, paramsArg) {
1491
- const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1471
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.operationId);
1492
1472
  if (!operationTarget.success) return operationTarget;
1493
1473
  const connectId = operationTarget.payload.targetId;
1494
1474
  const deviceId = deviceIdArg ?? void 0;
1495
1475
  try {
1496
- return await this._jobQueue.enqueue(
1497
- deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1498
- async (signal) => {
1499
- const { record } = await this._ensureWalletKnown(connectId, deviceId, "btc", signal);
1500
- return success({ masterFingerprint: record.masterFingerprint });
1501
- }
1502
- );
1476
+ return await this._jobQueue.enqueue(getKeystoneJobId(connectId, deviceId), async (signal) => {
1477
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "btc", signal);
1478
+ return success({ masterFingerprint: record.masterFingerprint });
1479
+ });
1503
1480
  } catch (err) {
1504
1481
  return this._errorToFailure(err);
1505
1482
  }
@@ -1508,7 +1485,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
1508
1485
  // SOL
1509
1486
  // ---------------------------------------------------------------------------
1510
1487
  async solGetAddress(connectIdArg, deviceIdArg, paramsArg, book) {
1511
- const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1488
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.operationId);
1512
1489
  if (!operationTarget.success) return operationTarget;
1513
1490
  const connectId = operationTarget.payload.targetId;
1514
1491
  const deviceId = deviceIdArg ?? void 0;
@@ -1518,23 +1495,20 @@ var KeystoneAdapter = class _KeystoneAdapter {
1518
1495
  return failure(HardwareErrorCode.InvalidParams, "solGetAddress requires params.path");
1519
1496
  const path = normalizePath(params.path);
1520
1497
  try {
1521
- return await this._jobQueue.enqueue(
1522
- deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1523
- async (signal) => {
1524
- const { account } = await this._fetchAccount(connectId, deviceId, "sol", path, signal, {
1525
- book
1526
- });
1527
- _KeystoneAdapter._throwIfAborted(signal);
1528
- const address = bs58.encode(Buffer.from(account.publicKey, "hex"));
1529
- return success({ address, path });
1530
- }
1531
- );
1498
+ return await this._jobQueue.enqueue(getKeystoneJobId(connectId, deviceId), async (signal) => {
1499
+ const { account } = await this._fetchAccount(connectId, deviceId, "sol", path, signal, {
1500
+ book
1501
+ });
1502
+ _KeystoneAdapter._throwIfAborted(signal);
1503
+ const address = bs58.encode(Buffer.from(account.publicKey, "hex"));
1504
+ return success({ address, path });
1505
+ });
1532
1506
  } catch (err) {
1533
1507
  return this._errorToFailure(err);
1534
1508
  }
1535
1509
  }
1536
1510
  async solSignTransaction(connectIdArg, deviceIdArg, paramsArg) {
1537
- const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1511
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.operationId);
1538
1512
  if (!operationTarget.success) return operationTarget;
1539
1513
  const connectId = operationTarget.payload.targetId;
1540
1514
  const deviceId = deviceIdArg ?? void 0;
@@ -1549,39 +1523,36 @@ var KeystoneAdapter = class _KeystoneAdapter {
1549
1523
  }
1550
1524
  const path = normalizePath(params.path);
1551
1525
  try {
1552
- return await this._jobQueue.enqueue(
1553
- deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1554
- async (signal) => {
1555
- const { record } = await this._ensureWalletKnown(connectId, deviceId, "sol", signal);
1556
- _KeystoneAdapter._throwIfAborted(signal);
1557
- const requestId = uuidv4();
1558
- const requestUr = this.urEngine.buildSolSignRequest({
1559
- requestId,
1560
- unsignedPayloadHex: stripHex(params.serializedTx),
1561
- dataType: "transaction",
1562
- path,
1563
- xfp: record.masterFingerprint
1564
- });
1565
- const responseUr = await this._resolveUr(
1566
- record,
1567
- requestUr,
1568
- true,
1569
- connectId,
1570
- signal,
1571
- "solSignTransaction"
1572
- );
1573
- _KeystoneAdapter._throwIfAborted(signal);
1574
- const sig = this.urEngine.parseSolSignature(responseUr);
1575
- _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1576
- return success({ signature: sig.signature });
1577
- }
1578
- );
1526
+ return await this._jobQueue.enqueue(getKeystoneJobId(connectId, deviceId), async (signal) => {
1527
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "sol", signal);
1528
+ _KeystoneAdapter._throwIfAborted(signal);
1529
+ const requestId = uuidv4();
1530
+ const requestUr = this.urEngine.buildSolSignRequest({
1531
+ requestId,
1532
+ unsignedPayloadHex: stripHex(params.serializedTx),
1533
+ dataType: "transaction",
1534
+ path,
1535
+ xfp: record.masterFingerprint
1536
+ });
1537
+ const responseUr = await this._resolveUr(
1538
+ record,
1539
+ requestUr,
1540
+ true,
1541
+ connectId,
1542
+ signal,
1543
+ "solSignTransaction"
1544
+ );
1545
+ _KeystoneAdapter._throwIfAborted(signal);
1546
+ const sig = this.urEngine.parseSolSignature(responseUr);
1547
+ _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1548
+ return success({ signature: sig.signature });
1549
+ });
1579
1550
  } catch (err) {
1580
1551
  return this._errorToFailure(err);
1581
1552
  }
1582
1553
  }
1583
1554
  async solSignMessage(connectIdArg, deviceIdArg, paramsArg) {
1584
- const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1555
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.operationId);
1585
1556
  if (!operationTarget.success) return operationTarget;
1586
1557
  const connectId = operationTarget.payload.targetId;
1587
1558
  const deviceId = deviceIdArg ?? void 0;
@@ -1595,33 +1566,30 @@ var KeystoneAdapter = class _KeystoneAdapter {
1595
1566
  }
1596
1567
  const path = normalizePath(params.path);
1597
1568
  try {
1598
- return await this._jobQueue.enqueue(
1599
- deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1600
- async (signal) => {
1601
- const { record } = await this._ensureWalletKnown(connectId, deviceId, "sol", signal);
1602
- _KeystoneAdapter._throwIfAborted(signal);
1603
- const requestId = uuidv4();
1604
- const requestUr = this.urEngine.buildSolSignRequest({
1605
- requestId,
1606
- unsignedPayloadHex: stripHex(params.message),
1607
- dataType: "message",
1608
- path,
1609
- xfp: record.masterFingerprint
1610
- });
1611
- const responseUr = await this._resolveUr(
1612
- record,
1613
- requestUr,
1614
- true,
1615
- connectId,
1616
- signal,
1617
- "solSignMessage"
1618
- );
1619
- _KeystoneAdapter._throwIfAborted(signal);
1620
- const sig = this.urEngine.parseSolSignature(responseUr);
1621
- _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1622
- return success({ signature: sig.signature });
1623
- }
1624
- );
1569
+ return await this._jobQueue.enqueue(getKeystoneJobId(connectId, deviceId), async (signal) => {
1570
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "sol", signal);
1571
+ _KeystoneAdapter._throwIfAborted(signal);
1572
+ const requestId = uuidv4();
1573
+ const requestUr = this.urEngine.buildSolSignRequest({
1574
+ requestId,
1575
+ unsignedPayloadHex: stripHex(params.message),
1576
+ dataType: "message",
1577
+ path,
1578
+ xfp: record.masterFingerprint
1579
+ });
1580
+ const responseUr = await this._resolveUr(
1581
+ record,
1582
+ requestUr,
1583
+ true,
1584
+ connectId,
1585
+ signal,
1586
+ "solSignMessage"
1587
+ );
1588
+ _KeystoneAdapter._throwIfAborted(signal);
1589
+ const sig = this.urEngine.parseSolSignature(responseUr);
1590
+ _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1591
+ return success({ signature: sig.signature });
1592
+ });
1625
1593
  } catch (err) {
1626
1594
  return this._errorToFailure(err);
1627
1595
  }
@@ -1634,7 +1602,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
1634
1602
  // unverified response semantics).
1635
1603
  // ---------------------------------------------------------------------------
1636
1604
  async tronGetAddress(connectIdArg, deviceIdArg, paramsArg, book) {
1637
- const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1605
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.operationId);
1638
1606
  if (!operationTarget.success) return operationTarget;
1639
1607
  const connectId = operationTarget.payload.targetId;
1640
1608
  const deviceId = deviceIdArg ?? void 0;
@@ -1650,37 +1618,34 @@ var KeystoneAdapter = class _KeystoneAdapter {
1650
1618
  );
1651
1619
  }
1652
1620
  try {
1653
- return await this._jobQueue.enqueue(
1654
- deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1655
- async (signal) => {
1656
- const { account } = await this._fetchAccount(
1657
- connectId,
1658
- deviceId,
1659
- "tron",
1660
- accountPath,
1661
- signal,
1662
- { book }
1663
- );
1664
- _KeystoneAdapter._throwIfAborted(signal);
1665
- if (!account.extendedPublicKey) {
1666
- throw createHwkError({
1667
- code: HardwareErrorCode.MethodNotSupported,
1668
- message: "Keystone did not return an extended public key for this account path"
1669
- });
1670
- }
1671
- const address = this.urEngine.deriveTronAddressFromXpub(
1672
- account.extendedPublicKey,
1673
- relativeDerivePath
1674
- );
1675
- return success({ address, path: normalizePath(params.path) });
1621
+ return await this._jobQueue.enqueue(getKeystoneJobId(connectId, deviceId), async (signal) => {
1622
+ const { account } = await this._fetchAccount(
1623
+ connectId,
1624
+ deviceId,
1625
+ "tron",
1626
+ accountPath,
1627
+ signal,
1628
+ { book }
1629
+ );
1630
+ _KeystoneAdapter._throwIfAborted(signal);
1631
+ if (!account.extendedPublicKey) {
1632
+ throw createHwkError({
1633
+ code: HardwareErrorCode.MethodNotSupported,
1634
+ message: "Keystone did not return an extended public key for this account path"
1635
+ });
1676
1636
  }
1677
- );
1637
+ const address = this.urEngine.deriveTronAddressFromXpub(
1638
+ account.extendedPublicKey,
1639
+ relativeDerivePath
1640
+ );
1641
+ return success({ address, path: normalizePath(params.path) });
1642
+ });
1678
1643
  } catch (err) {
1679
1644
  return this._errorToFailure(err);
1680
1645
  }
1681
1646
  }
1682
1647
  async tronSignTransaction(connectIdArg, deviceIdArg, paramsArg) {
1683
- const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1648
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.operationId);
1684
1649
  if (!operationTarget.success) return operationTarget;
1685
1650
  const connectId = operationTarget.payload.targetId;
1686
1651
  const deviceId = deviceIdArg ?? void 0;
@@ -1699,38 +1664,35 @@ var KeystoneAdapter = class _KeystoneAdapter {
1699
1664
  const rawTxHex = stripHex(params.rawTxHex);
1700
1665
  const path = normalizePath(params.path);
1701
1666
  try {
1702
- return await this._jobQueue.enqueue(
1703
- deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1704
- async (signal) => {
1705
- const { record } = await this._ensureWalletKnown(connectId, deviceId, "tron", signal);
1706
- _KeystoneAdapter._throwIfAborted(signal);
1707
- const requestId = uuidv4();
1708
- const requestUr = this.urEngine.buildTronSignRequest({
1709
- requestId,
1710
- rawTxHex,
1711
- path,
1712
- xfp: record.masterFingerprint
1713
- });
1714
- const responseUr = await this._resolveUr(
1715
- record,
1716
- requestUr,
1717
- true,
1718
- connectId,
1719
- signal,
1720
- "tronSignTransaction"
1721
- );
1722
- _KeystoneAdapter._throwIfAborted(signal);
1723
- const sig = this.urEngine.parseTronSignature(responseUr);
1724
- _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1725
- return success({ signature: sig.signature });
1726
- }
1727
- );
1667
+ return await this._jobQueue.enqueue(getKeystoneJobId(connectId, deviceId), async (signal) => {
1668
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "tron", signal);
1669
+ _KeystoneAdapter._throwIfAborted(signal);
1670
+ const requestId = uuidv4();
1671
+ const requestUr = this.urEngine.buildTronSignRequest({
1672
+ requestId,
1673
+ rawTxHex,
1674
+ path,
1675
+ xfp: record.masterFingerprint
1676
+ });
1677
+ const responseUr = await this._resolveUr(
1678
+ record,
1679
+ requestUr,
1680
+ true,
1681
+ connectId,
1682
+ signal,
1683
+ "tronSignTransaction"
1684
+ );
1685
+ _KeystoneAdapter._throwIfAborted(signal);
1686
+ const sig = this.urEngine.parseTronSignature(responseUr);
1687
+ _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1688
+ return success({ signature: sig.signature });
1689
+ });
1728
1690
  } catch (err) {
1729
1691
  return this._errorToFailure(err);
1730
1692
  }
1731
1693
  }
1732
1694
  async tronSignMessage(connectIdArg, deviceIdArg, paramsArg) {
1733
- const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.interactionId);
1695
+ const operationTarget = resolveHardwareOperationTarget(connectIdArg, paramsArg?.operationId);
1734
1696
  if (!operationTarget.success) return operationTarget;
1735
1697
  const connectId = operationTarget.payload.targetId;
1736
1698
  const deviceId = deviceIdArg ?? void 0;
@@ -1751,33 +1713,30 @@ var KeystoneAdapter = class _KeystoneAdapter {
1751
1713
  const messageHex = stripHex(params.messageHex);
1752
1714
  const path = normalizePath(params.path);
1753
1715
  try {
1754
- return await this._jobQueue.enqueue(
1755
- deviceId ?? connectId ?? COLD_START_JOB_LABEL,
1756
- async (signal) => {
1757
- const { record } = await this._ensureWalletKnown(connectId, deviceId, "tron", signal);
1758
- _KeystoneAdapter._throwIfAborted(signal);
1759
- const requestId = uuidv4();
1760
- const requestUr = this.urEngine.buildTronSignRequest({
1761
- requestId,
1762
- rawTxHex: messageHex,
1763
- path,
1764
- xfp: record.masterFingerprint,
1765
- signType: 2 /* PersonalMessage */
1766
- });
1767
- const responseUr = await this._resolveUr(
1768
- record,
1769
- requestUr,
1770
- true,
1771
- connectId,
1772
- signal,
1773
- "tronSignMessage"
1774
- );
1775
- _KeystoneAdapter._throwIfAborted(signal);
1776
- const sig = this.urEngine.parseTronSignature(responseUr);
1777
- _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1778
- return success({ signature: sig.signature });
1779
- }
1780
- );
1716
+ return await this._jobQueue.enqueue(getKeystoneJobId(connectId, deviceId), async (signal) => {
1717
+ const { record } = await this._ensureWalletKnown(connectId, deviceId, "tron", signal);
1718
+ _KeystoneAdapter._throwIfAborted(signal);
1719
+ const requestId = uuidv4();
1720
+ const requestUr = this.urEngine.buildTronSignRequest({
1721
+ requestId,
1722
+ rawTxHex: messageHex,
1723
+ path,
1724
+ xfp: record.masterFingerprint,
1725
+ signType: 2 /* PersonalMessage */
1726
+ });
1727
+ const responseUr = await this._resolveUr(
1728
+ record,
1729
+ requestUr,
1730
+ true,
1731
+ connectId,
1732
+ signal,
1733
+ "tronSignMessage"
1734
+ );
1735
+ _KeystoneAdapter._throwIfAborted(signal);
1736
+ const sig = this.urEngine.parseTronSignature(responseUr);
1737
+ _KeystoneAdapter._assertRequestIdMatches(requestId, sig.requestId);
1738
+ return success({ signature: sig.signature });
1739
+ });
1781
1740
  } catch (err) {
1782
1741
  return this._errorToFailure(err);
1783
1742
  }
@@ -1816,7 +1775,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
1816
1775
  * one-path-at-a-time export flow because the device limits that channel.
1817
1776
  */
1818
1777
  async _prefetchAllNetworkAccounts(connectId, deviceId, params) {
1819
- return this._jobQueue.enqueue(deviceId || connectId || COLD_START_JOB_LABEL, async (signal) => {
1778
+ return this._jobQueue.enqueue(getKeystoneJobId(connectId, deviceId), async (signal) => {
1820
1779
  const target = this._resolveTarget(connectId, deviceId);
1821
1780
  const { record: targetRecord } = target;
1822
1781
  let record = targetRecord;
@@ -1837,19 +1796,29 @@ var KeystoneAdapter = class _KeystoneAdapter {
1837
1796
  _KeystoneAdapter._throwIfAborted(signal);
1838
1797
  }
1839
1798
  if (this._forcedTransport !== "qr" && record?.usbSessionId) {
1799
+ const bundleSessionId = record.usbSessionId;
1800
+ const assertBundleSession = () => {
1801
+ if (record?.usbSessionId !== bundleSessionId) {
1802
+ throw createHwkError({
1803
+ code: HardwareErrorCode.TransportNotAvailable,
1804
+ message: "Keystone USB connection was lost during account export"
1805
+ });
1806
+ }
1807
+ };
1840
1808
  const missingSchemas2 = Array.from(requestedByKey.values());
1841
- for (const [index, schema] of missingSchemas2.entries()) {
1809
+ for (const schema of missingSchemas2) {
1842
1810
  if (!book.has(accountKey(schema.hwkChain, schema.path))) {
1811
+ assertBundleSession();
1843
1812
  const synced = await this._fetchAccount(
1844
1813
  connectId,
1845
1814
  deviceId,
1846
1815
  schema.hwkChain,
1847
1816
  schema.path,
1848
1817
  signal,
1849
- { qrFallbackSchemaPaths: missingSchemas2.slice(index), book }
1818
+ { book }
1850
1819
  );
1851
1820
  record = synced.record;
1852
- if (!record.usbSessionId) break;
1821
+ assertBundleSession();
1853
1822
  }
1854
1823
  }
1855
1824
  for (const schema of missingSchemas2) {
@@ -1918,8 +1887,8 @@ var KeystoneAdapter = class _KeystoneAdapter {
1918
1887
  */
1919
1888
  _resolveTarget(connectId, deviceId) {
1920
1889
  let resolvedConnectId = connectId;
1921
- if (isHardwareInteractionId(connectId)) {
1922
- resolvedConnectId = this._interactions.resolve(connectId).connectId;
1890
+ if (isHardwareOperationId(connectId)) {
1891
+ resolvedConnectId = this._operations.resolve(connectId).connectId;
1923
1892
  }
1924
1893
  const identifiers = [deviceId, resolvedConnectId].filter(
1925
1894
  (identifier) => Boolean(identifier)
@@ -1975,7 +1944,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
1975
1944
  * already has a live session, so this must NOT unconditionally mark
1976
1945
  * `qrSynced`, or a USB-only wallet would wrongly survive a later USB
1977
1946
  * disconnect as a "QR-synced, demote to QR-only" entry instead of being
1978
- * dropped outright (see `releaseInteraction`).
1947
+ * dropped outright (see `releaseOperation`).
1979
1948
  */
1980
1949
  _upsertDeviceRecord(parsed, options) {
1981
1950
  const walletId = deriveKeystoneWalletId(parsed.accounts);
@@ -2113,7 +2082,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
2113
2082
  * then attach and verify the requested wallet when one is present. This is
2114
2083
  * used both after an adapter restart and after a QR-only period, so plugging
2115
2084
  * USB back in affects the next business call without changing an in-flight
2116
- * QR interaction.
2085
+ * QR operation.
2117
2086
  */
2118
2087
  async _tryUsbAttach(expectedWalletId, expectedMasterFingerprint, options) {
2119
2088
  if (!expectedWalletId || this._forcedTransport === "qr" || !this._usbConnector) {
@@ -2167,32 +2136,32 @@ var KeystoneAdapter = class _KeystoneAdapter {
2167
2136
  * `switchTransport('usb')` on a wallet with no live USB session fails
2168
2137
  * closed rather than silently falling back to QR.
2169
2138
  */
2170
- async _resolveUr(record, requestUr, animated, interactionId, signal, operationName) {
2171
- const releaseInteractionRetention = isHardwareInteractionId(interactionId) ? this._interactions.retain(interactionId) : void 0;
2139
+ async _resolveUr(record, requestUr, animated, operationId, signal, operationName) {
2140
+ const releaseOperationRetention = isHardwareOperationId(operationId) ? this._operations.retain(operationId) : void 0;
2172
2141
  try {
2173
2142
  return await this._resolveUrWithRoute(
2174
2143
  record,
2175
2144
  requestUr,
2176
2145
  animated,
2177
- interactionId,
2146
+ operationId,
2178
2147
  signal,
2179
2148
  operationName
2180
2149
  );
2181
2150
  } finally {
2182
- releaseInteractionRetention?.();
2151
+ releaseOperationRetention?.();
2183
2152
  }
2184
2153
  }
2185
- async _resolveUrWithRoute(record, requestUr, animated, interactionId, signal, operationName) {
2154
+ async _resolveUrWithRoute(record, requestUr, animated, operationId, signal, operationName) {
2186
2155
  let interactionRoute;
2187
- if (isHardwareInteractionId(interactionId)) {
2188
- const interaction = this._interactions.resolve(interactionId);
2189
- const route = this._interactionRoutes.get(interaction.connectId);
2190
- if (!route || route.interactionId !== interactionId) {
2191
- this._interactions.end(interactionId, "disconnect");
2156
+ if (isHardwareOperationId(operationId)) {
2157
+ const operation = this._operations.resolve(operationId);
2158
+ const route = this._operationRoutes.get(operation.connectId);
2159
+ if (!route || route.operationId !== operationId) {
2160
+ this._operations.end(operationId, "disconnect");
2192
2161
  throw createHwkError({
2193
- code: HardwareErrorCode.InteractionEnded,
2194
- message: "Keystone hardware interaction is no longer connected",
2195
- params: { interactionId, reason: "disconnect" }
2162
+ code: HardwareErrorCode.OperationEnded,
2163
+ message: "Keystone hardware operation is no longer connected",
2164
+ params: { operationId, reason: "disconnect" }
2196
2165
  });
2197
2166
  }
2198
2167
  interactionRoute = route;
@@ -2206,12 +2175,12 @@ var KeystoneAdapter = class _KeystoneAdapter {
2206
2175
  if (wantUsb) {
2207
2176
  if (!record?.usbSessionId || !this._usbConnector) {
2208
2177
  if (interactionRoute) {
2209
- this._interactions.end(interactionRoute.interactionId, "disconnect");
2178
+ this._operations.end(interactionRoute.operationId, "disconnect");
2210
2179
  throw createHwkError({
2211
- code: HardwareErrorCode.InteractionEnded,
2212
- message: "Keystone interaction USB connection was lost",
2180
+ code: HardwareErrorCode.OperationEnded,
2181
+ message: "Keystone operation USB connection was lost",
2213
2182
  params: {
2214
- interactionId: interactionRoute.interactionId,
2183
+ operationId: interactionRoute.operationId,
2215
2184
  reason: "disconnect"
2216
2185
  }
2217
2186
  });
@@ -2246,16 +2215,16 @@ var KeystoneAdapter = class _KeystoneAdapter {
2246
2215
  }
2247
2216
  record.usbSessionId = void 0;
2248
2217
  if (interactionRoute) {
2249
- this._interactions.end(interactionRoute.interactionId, "disconnect");
2218
+ this._operations.end(interactionRoute.operationId, "disconnect");
2250
2219
  throw createHwkError({
2251
- code: HardwareErrorCode.InteractionEnded,
2252
- message: operationName ? `Keystone ${operationName} may have completed before the USB connection was lost` : "Keystone interaction USB connection was lost",
2220
+ code: HardwareErrorCode.OperationEnded,
2221
+ message: operationName ? `Keystone ${operationName} may have completed before the USB connection was lost` : "Keystone operation USB connection was lost",
2253
2222
  recovery: operationName ? { scope: "unknown" } : void 0,
2254
2223
  params: operationName ? operationMayHaveCompletedParams(operationName, {
2255
- interactionId: interactionRoute.interactionId,
2224
+ operationId: interactionRoute.operationId,
2256
2225
  reason: "disconnect"
2257
2226
  }) : {
2258
- interactionId: interactionRoute.interactionId,
2227
+ operationId: interactionRoute.operationId,
2259
2228
  reason: "disconnect"
2260
2229
  }
2261
2230
  });
@@ -2294,8 +2263,8 @@ var KeystoneAdapter = class _KeystoneAdapter {
2294
2263
  /**
2295
2264
  * Fetch one account's key material from the device for this operation only.
2296
2265
  * `book` lets earlier fetches of the same operation be reused; nothing is
2297
- * retained on the record. On a USB drop the remaining paths fall back to one
2298
- * QR request.
2266
+ * retained on the record. A failed USB export ends this operation without
2267
+ * replaying the request or switching transports.
2299
2268
  */
2300
2269
  async _fetchAccount(connectId, deviceId, hwkChain, syncPath, signal, options) {
2301
2270
  const target = this._resolveTarget(connectId, deviceId);
@@ -2330,56 +2299,8 @@ var KeystoneAdapter = class _KeystoneAdapter {
2330
2299
  })),
2331
2300
  origin: this._origin
2332
2301
  });
2333
- let resolvedViaUsb = useSinglePathUsbExport;
2334
- let responseUr;
2335
- try {
2336
- responseUr = await this._resolveUr(existingRecord, requestUr, false, connectId, signal);
2337
- } catch (error) {
2338
- if (isHardwareInteractionId(connectId) || !useSinglePathUsbExport || !isKeystoneUsbReconnectableError(error)) {
2339
- throw error;
2340
- }
2341
- await waitForKeystoneUsbReattachProbe();
2342
- _KeystoneAdapter._throwIfAborted(signal);
2343
- const recoveredRecord = await this._tryUsbAttach(
2344
- existingRecord?.walletId,
2345
- existingRecord?.masterFingerprint,
2346
- { waitForReenumeration: true }
2347
- );
2348
- _KeystoneAdapter._throwIfAborted(signal);
2349
- if (recoveredRecord?.usbSessionId) {
2350
- try {
2351
- responseUr = await this._resolveUr(recoveredRecord, requestUr, false, connectId, signal);
2352
- existingRecord = recoveredRecord;
2353
- } catch (retryError) {
2354
- if (!isKeystoneUsbReconnectableError(retryError)) throw retryError;
2355
- }
2356
- }
2357
- if (!responseUr) {
2358
- if (this._forcedTransport === "usb") throw error;
2359
- const fallbackSchemaPaths = options?.qrFallbackSchemaPaths ?? [
2360
- { hwkChain, path: syncPath }
2361
- ];
2362
- const qrFallbackSchemas = [
2363
- { hwkChain: "evm", path: KEYSTONE_WALLET_ID_PATH },
2364
- ...fallbackSchemaPaths.filter(
2365
- (schema) => normalizePath(schema.path) !== KEYSTONE_WALLET_ID_PATH
2366
- )
2367
- ].map((schema) => ({
2368
- path: schema.path,
2369
- curve: schema.hwkChain === "sol" ? "ed25519" : "secp256k1"
2370
- }));
2371
- const qrRequestUr = this.urEngine.buildKeyDerivationRequest({
2372
- schemas: qrFallbackSchemas,
2373
- origin: this._origin
2374
- });
2375
- const displayDevice = existingRecord ? toDeviceInfo(existingRecord) : placeholderDeviceInfo();
2376
- responseUr = await this._requestQrDisplayAndAwaitResponse(displayDevice, {
2377
- ...qrRequestUr,
2378
- animated: false
2379
- });
2380
- resolvedViaUsb = false;
2381
- }
2382
- }
2302
+ const resolvedViaUsb = useSinglePathUsbExport;
2303
+ const responseUr = await this._resolveUr(existingRecord, requestUr, false, connectId, signal);
2383
2304
  _KeystoneAdapter._throwIfAborted(signal);
2384
2305
  const parsed = this.urEngine.parseAccountResponse(responseUr);
2385
2306
  let record;
@@ -2608,13 +2529,13 @@ var KeystoneAdapter = class _KeystoneAdapter {
2608
2529
  if (e._tag === UI_REQUEST_CANCELLED_TAG || e._tag === UI_REQUEST_PREEMPTED_TAG) {
2609
2530
  return failure(
2610
2531
  HardwareErrorCode.UserAborted,
2611
- e.message ?? "Keystone QR interaction was cancelled"
2532
+ e.message ?? "Keystone QR operation was cancelled"
2612
2533
  );
2613
2534
  }
2614
2535
  if (e._tag === UI_REQUEST_TIMEOUT_TAG) {
2615
2536
  return failure(
2616
2537
  HardwareErrorCode.OperationTimeout,
2617
- e.message ?? "Keystone QR interaction timed out"
2538
+ e.message ?? "Keystone QR operation timed out"
2618
2539
  );
2619
2540
  }
2620
2541
  }