@onekeyfe/hwk-ledger-adapter 1.2.5-alpha.4 → 1.2.6-alpha.0

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
@@ -874,6 +874,8 @@ var _LedgerAdapter = class _LedgerAdapter {
874
874
  this._operations = new OperationRegistry({
875
875
  vendor: "ledger",
876
876
  onEnded: (operation, reason) => {
877
+ this._discardPendingBinding(this._pendingOperationBindings.get(operation.operationId));
878
+ this._pendingOperationBindings.delete(operation.operationId);
877
879
  this.emitter.emit(SDK.OPERATION_ENDED, {
878
880
  type: SDK.OPERATION_ENDED,
879
881
  payload: { operationId: operation.operationId, reason }
@@ -885,6 +887,11 @@ var _LedgerAdapter = class _LedgerAdapter {
885
887
  });
886
888
  this._discoveredDevices = /* @__PURE__ */ new Map();
887
889
  this._sessions = /* @__PURE__ */ new Map();
890
+ // An operation's BLE pick is saved by its first call that gets past the wallet check.
891
+ this._pendingOperationBindings = /* @__PURE__ */ new Map();
892
+ // A one-shot call's unchecked BLE pick, by connectId. It outlives the call only
893
+ // through an unlock retry; any other failure drops it with its session.
894
+ this._pendingPickBindings = /* @__PURE__ */ new Map();
888
895
  // Transport each session was opened on, by sessionId. The adapter-wide
889
896
  // `_activeConnectionType` moves with every discovery and can go stale.
890
897
  this._sessionTransports = /* @__PURE__ */ new Map();
@@ -1013,6 +1020,12 @@ var _LedgerAdapter = class _LedgerAdapter {
1013
1020
  this._jobQueue = new DeviceJobQueue();
1014
1021
  this.registerEventListeners();
1015
1022
  }
1023
+ _discardPendingBinding(owner, status = "cancelled") {
1024
+ const pending = owner?.pendingBinding;
1025
+ if (!owner || !pending) return;
1026
+ owner.pendingBinding = void 0;
1027
+ if (pending.requestId === this._bindingSelectionRequestId) this._finishBleBinding(status);
1028
+ }
1016
1029
  _finishBleBinding(status) {
1017
1030
  const selectionRequestId = this._bindingSelectionRequestId;
1018
1031
  this._bindingSelectionRequestId = void 0;
@@ -1063,6 +1076,8 @@ var _LedgerAdapter = class _LedgerAdapter {
1063
1076
  this._discoveredDevices.clear();
1064
1077
  this._sessions.clear();
1065
1078
  this._sessionTransports.clear();
1079
+ this._pendingOperationBindings.clear();
1080
+ this._pendingPickBindings.clear();
1066
1081
  this._selectedBleReconnectTargets.clear();
1067
1082
  this._connectingPromise = null;
1068
1083
  this._doConnectAbortController = null;
@@ -1207,8 +1222,9 @@ var _LedgerAdapter = class _LedgerAdapter {
1207
1222
  return this.errorToFailure(error);
1208
1223
  }
1209
1224
  }
1210
- /** Ledger binds whichever BLE device the user picks; its wallet is not checked. */
1225
+ /** Binds the picked BLE device; with a recorded wallet identity it must match first. */
1211
1226
  async bindBleDevice(params) {
1227
+ const identity = params.identity?.vendor === "ledger" ? params.identity : void 0;
1212
1228
  try {
1213
1229
  return await this._jobQueue.enqueue(
1214
1230
  "__ledger_bind_ble__",
@@ -1223,7 +1239,8 @@ var _LedgerAdapter = class _LedgerAdapter {
1223
1239
  await this._ensureDevicePermission(void 0, void 0, signal);
1224
1240
  const attempt = {
1225
1241
  extra: params.extra,
1226
- bindingReason: "manual-rebind"
1242
+ bindingReason: "manual-rebind",
1243
+ deferBindingSave: Boolean(identity)
1227
1244
  };
1228
1245
  try {
1229
1246
  const connectId = await this._connectFirstOrSelect(
@@ -1234,6 +1251,45 @@ var _LedgerAdapter = class _LedgerAdapter {
1234
1251
  attempt,
1235
1252
  signal
1236
1253
  );
1254
+ const pending = attempt.pendingBinding;
1255
+ if (identity && pending) {
1256
+ attempt.pendingBinding = void 0;
1257
+ const sessionId = this._sessions.get(connectId);
1258
+ if (!sessionId) {
1259
+ throw createHwkError({
1260
+ code: HardwareErrorCode3.DeviceDisconnected,
1261
+ message: "Selected Ledger connection ended"
1262
+ });
1263
+ }
1264
+ const fingerprint = await this._computeChainFingerprint(
1265
+ identity.chain,
1266
+ (method, callParams) => this._runConnectorCall(
1267
+ connectId,
1268
+ method,
1269
+ callParams,
1270
+ signal,
1271
+ void 0,
1272
+ void 0,
1273
+ { autoInstallApp: true },
1274
+ { connection: { connectId, sessionId } }
1275
+ )
1276
+ );
1277
+ if (fingerprint !== identity.value) {
1278
+ await this._dropSession(connectId, signal);
1279
+ throw createHwkError({
1280
+ code: HardwareErrorCode3.DeviceMismatch,
1281
+ message: formatDeviceMismatchError(identity.value, fingerprint)
1282
+ });
1283
+ }
1284
+ await this._saveSelectedBleBinding(
1285
+ connectId,
1286
+ pending.requestId,
1287
+ attempt,
1288
+ void 0,
1289
+ signal,
1290
+ identity
1291
+ );
1292
+ }
1237
1293
  if (!attempt.bindingSaved) {
1238
1294
  await this._dropSession(connectId, signal);
1239
1295
  throw createHwkError({
@@ -1271,7 +1327,9 @@ var _LedgerAdapter = class _LedgerAdapter {
1271
1327
  await this._ensureDevicePermission(target, void 0, signal);
1272
1328
  const attempt = {
1273
1329
  ...context,
1274
- extra: context.extra ? { ...context.extra } : void 0
1330
+ extra: context.extra ? { ...context.extra } : void 0,
1331
+ // The operation's calls decide whether the pick is the right wallet.
1332
+ deferBindingSave: true
1275
1333
  };
1276
1334
  try {
1277
1335
  const resolvedConnectId = await this.ensureConnected(
@@ -1282,7 +1340,11 @@ var _LedgerAdapter = class _LedgerAdapter {
1282
1340
  attempt
1283
1341
  );
1284
1342
  _LedgerAdapter._throwIfAborted(signal);
1285
- return this._createOperation(connectId, resolvedConnectId);
1343
+ const result = this._createOperation(connectId, resolvedConnectId);
1344
+ if (result.success && attempt.pendingBinding) {
1345
+ this._pendingOperationBindings.set(result.payload, attempt);
1346
+ }
1347
+ return result;
1286
1348
  } catch (error) {
1287
1349
  this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
1288
1350
  throw error;
@@ -1897,6 +1959,8 @@ var _LedgerAdapter = class _LedgerAdapter {
1897
1959
  this._uiRegistry.cancel(void 0, void 0, pendingOperationId);
1898
1960
  }
1899
1961
  this._finishBleBinding("cancelled");
1962
+ if (!connectId) this._pendingOperationBindings.clear();
1963
+ else if (pendingOperationId) this._pendingOperationBindings.delete(pendingOperationId);
1900
1964
  const queueKeys = /* @__PURE__ */ new Set();
1901
1965
  if (connectId) queueKeys.add(ledgerQueueKey({ connectId }));
1902
1966
  if (pendingOperationId) queueKeys.add(ledgerQueueKey({ operationId: pendingOperationId }));
@@ -1948,8 +2012,8 @@ var _LedgerAdapter = class _LedgerAdapter {
1948
2012
  return this.errorToFailure(err);
1949
2013
  }
1950
2014
  }
1951
- /** Ledger takes the selected BLE endpoint as the device and binds it right away. */
1952
- async _saveSelectedBleBinding(connectId, selectionRequestId, context, operationId, signal) {
2015
+ /** Saves a picked BLE endpoint; `identity` is set when its wallet was just checked. */
2016
+ async _saveSelectedBleBinding(connectId, selectionRequestId, context, operationId, signal, identity) {
1953
2017
  try {
1954
2018
  const outcome = await requestSaveDeviceBinding(
1955
2019
  this.emitter,
@@ -1957,6 +2021,7 @@ var _LedgerAdapter = class _LedgerAdapter {
1957
2021
  {
1958
2022
  selectionRequestId,
1959
2023
  connection: { transport: "ble", connectId },
2024
+ ...identity ? { identity } : {},
1960
2025
  extra: context?.extra,
1961
2026
  operationId
1962
2027
  },
@@ -2410,13 +2475,17 @@ var _LedgerAdapter = class _LedgerAdapter {
2410
2475
  signal
2411
2476
  );
2412
2477
  if (context) context.selectedConnection = { connectId: connected, requestId };
2413
- await this._saveSelectedBleBinding(
2414
- connected,
2415
- requestId,
2416
- context,
2417
- preserveOperationId,
2418
- signal
2419
- );
2478
+ if (context?.deferBindingSave) {
2479
+ context.pendingBinding = { connectId: connected, requestId };
2480
+ } else {
2481
+ await this._saveSelectedBleBinding(
2482
+ connected,
2483
+ requestId,
2484
+ context,
2485
+ preserveOperationId,
2486
+ signal
2487
+ );
2488
+ }
2420
2489
  return connected;
2421
2490
  }
2422
2491
  if (devices.length > 0 && (devices.length > 1 || requiresBleSelection)) {
@@ -2612,7 +2681,13 @@ var _LedgerAdapter = class _LedgerAdapter {
2612
2681
  operationId
2613
2682
  );
2614
2683
  } catch (error) {
2615
- this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
2684
+ const status = signal.aborted ? "cancelled" : "failed";
2685
+ for (const [pickedConnectId, owner] of this._pendingPickBindings) {
2686
+ this._pendingPickBindings.delete(pickedConnectId);
2687
+ this._discardPendingBinding(owner, status);
2688
+ await this._dropSession(pickedConnectId, signal);
2689
+ }
2690
+ this._finishBleBinding(status);
2616
2691
  throw error;
2617
2692
  } finally {
2618
2693
  if (operationId) {
@@ -2719,7 +2794,13 @@ var _LedgerAdapter = class _LedgerAdapter {
2719
2794
  );
2720
2795
  const inputConnectId = hintedConnectId && hintedConnectId.transport !== "qr" ? hintedConnectId.connectId : connectId;
2721
2796
  const preferredConnectId = fingerprint && !fingerprint.skipFingerprint && selectedBleTarget?.chain === fingerprint.chain && selectedBleTarget.fingerprint === fingerprint.deviceId ? selectedBleTarget.connectId : inputConnectId;
2722
- const connectionAttempt = { ...commonParams };
2797
+ const checksWallet = Boolean(
2798
+ fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId
2799
+ );
2800
+ const connectionAttempt = {
2801
+ ...commonParams,
2802
+ deferBindingSave: checksWallet
2803
+ };
2723
2804
  const bundleConnection = installContext?.connection;
2724
2805
  if (bundleConnection && this._sessions.get(bundleConnection.connectId) !== bundleConnection.sessionId) {
2725
2806
  throw createHwkError({
@@ -2753,7 +2834,12 @@ var _LedgerAdapter = class _LedgerAdapter {
2753
2834
  }
2754
2835
  try {
2755
2836
  const isBleSession = this._sessionTransports.get(sessionId) === "ble";
2756
- if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId && !isBleSession) {
2837
+ if (!operationId && connectionAttempt.pendingBinding) {
2838
+ this._pendingPickBindings.set(resolvedConnectId, connectionAttempt);
2839
+ }
2840
+ const bindingOwner = operationId ? this._pendingOperationBindings.get(operationId) : this._pendingPickBindings.get(resolvedConnectId);
2841
+ const pendingBinding = bindingOwner?.pendingBinding?.connectId === resolvedConnectId ? bindingOwner.pendingBinding : void 0;
2842
+ if (fingerprint && checksWallet) {
2757
2843
  const fp = await this._abortable(
2758
2844
  signal,
2759
2845
  this._verifyDeviceFingerprintWithSession(
@@ -2763,11 +2849,38 @@ var _LedgerAdapter = class _LedgerAdapter {
2763
2849
  )
2764
2850
  );
2765
2851
  if (!fp.success) {
2852
+ if (pendingBinding) {
2853
+ this._discardPendingBinding(bindingOwner, "failed");
2854
+ this._pendingPickBindings.delete(resolvedConnectId);
2855
+ if (operationId) {
2856
+ this._pendingOperationBindings.delete(operationId);
2857
+ this._operations.end(operationId, "explicit");
2858
+ await this._dropSession(resolvedConnectId, signal);
2859
+ }
2860
+ }
2766
2861
  throw Object.assign(new Error(formatDeviceMismatchError(fp.expected, fp.actual)), {
2767
2862
  code: HardwareErrorCode3.DeviceMismatch
2768
2863
  });
2769
2864
  }
2770
2865
  }
2866
+ if (pendingBinding && bindingOwner) {
2867
+ bindingOwner.pendingBinding = void 0;
2868
+ if (operationId) this._pendingOperationBindings.delete(operationId);
2869
+ else this._pendingPickBindings.delete(resolvedConnectId);
2870
+ await this._saveSelectedBleBinding(
2871
+ pendingBinding.connectId,
2872
+ pendingBinding.requestId,
2873
+ bindingOwner,
2874
+ operationId,
2875
+ signal,
2876
+ fingerprint && checksWallet ? {
2877
+ vendor: "ledger",
2878
+ type: "chainFingerprint",
2879
+ chain: fingerprint.chain,
2880
+ value: fingerprint.deviceId
2881
+ } : void 0
2882
+ );
2883
+ }
2771
2884
  if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId && !operationId && isBleSession && connectionAttempt.selectedConnection?.connectId === resolvedConnectId) {
2772
2885
  this._selectedBleReconnectTargets.set(connectId, {
2773
2886
  connectId: resolvedConnectId,
@@ -2856,6 +2969,7 @@ var _LedgerAdapter = class _LedgerAdapter {
2856
2969
  }
2857
2970
  if (!operationId && errObj?.code === HardwareErrorCode3.DeviceMismatch) {
2858
2971
  this._sessions.delete(resolvedConnectId);
2972
+ this._sessionTransports.delete(sessionId);
2859
2973
  this._discoveredDevices.delete(resolvedConnectId);
2860
2974
  await this.connector.disconnect(sessionId).catch(() => void 0);
2861
2975
  throw err;