@onekeyfe/hd-core 1.2.0-alpha.33 → 1.2.0-alpha.35

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.
Files changed (108) hide show
  1. package/__tests__/DeviceCommands.test.ts +84 -0
  2. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +31 -0
  3. package/__tests__/core-dispose.test.ts +3 -3
  4. package/__tests__/device-lifecycle-events.test.ts +52 -0
  5. package/__tests__/device-pool-state.test.ts +14 -2
  6. package/__tests__/device-settings.test.ts +25 -0
  7. package/__tests__/device-state-mapper.test.ts +13 -2
  8. package/__tests__/device-state-projector.test.ts +2 -2
  9. package/__tests__/device-utils.test.ts +1 -0
  10. package/__tests__/device-wallet-session-store.test.ts +137 -17
  11. package/__tests__/evmSignTransaction.test.ts +69 -0
  12. package/__tests__/get-device-state.test.ts +78 -30
  13. package/__tests__/kaspaSignTransaction.test.ts +9 -0
  14. package/__tests__/known-device-public-types.type-test.ts +3 -0
  15. package/__tests__/logBlockEvent.test.ts +89 -5
  16. package/__tests__/open-wallet-session.test.ts +499 -60
  17. package/__tests__/pro2Wallpaper.test.ts +1 -1
  18. package/__tests__/protocol-v2.test.ts +1180 -169
  19. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  20. package/dist/api/FirmwareUpdateV4.d.ts +2 -0
  21. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  22. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  23. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  24. package/dist/api/device/DeviceSettings.d.ts.map +1 -1
  25. package/dist/api/evm/EVMSignTypedData.d.ts.map +1 -1
  26. package/dist/api/evm/protocol.d.ts +3 -0
  27. package/dist/api/evm/protocol.d.ts.map +1 -0
  28. package/dist/api/kaspa/KaspaSignTransaction.d.ts.map +1 -1
  29. package/dist/api/protocol-v2/DeviceGetOnboardingStatus.d.ts +1 -1
  30. package/dist/core/index.d.ts.map +1 -1
  31. package/dist/device/Device.d.ts +10 -4
  32. package/dist/device/Device.d.ts.map +1 -1
  33. package/dist/device/DeviceCommands.d.ts.map +1 -1
  34. package/dist/device/DeviceConnector.d.ts +1 -1
  35. package/dist/device/DeviceConnector.d.ts.map +1 -1
  36. package/dist/device/DevicePool.d.ts +1 -0
  37. package/dist/device/DevicePool.d.ts.map +1 -1
  38. package/dist/device/DeviceStateMapper.d.ts.map +1 -1
  39. package/dist/device/DeviceStateProjector.d.ts.map +1 -1
  40. package/dist/device/DeviceWalletSessionStore.d.ts +7 -0
  41. package/dist/device/DeviceWalletSessionStore.d.ts.map +1 -1
  42. package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
  43. package/dist/deviceProfile/protocolV2DeviceIdentity.d.ts +7 -0
  44. package/dist/deviceProfile/protocolV2DeviceIdentity.d.ts.map +1 -0
  45. package/dist/events/logBlockEvent.d.ts +2 -0
  46. package/dist/events/logBlockEvent.d.ts.map +1 -1
  47. package/dist/index.d.ts +25 -11
  48. package/dist/index.js +1037 -838
  49. package/dist/protocols/protocol-v2/features.d.ts +17 -6
  50. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  51. package/dist/protocols/protocol-v2/index.d.ts +2 -2
  52. package/dist/protocols/protocol-v2/index.d.ts.map +1 -1
  53. package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts +1 -0
  54. package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -1
  55. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -1
  56. package/dist/protocols/protocol-v2/walletSession.d.ts +1 -10
  57. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  58. package/dist/types/api/protocolV2.d.ts +2 -2
  59. package/dist/types/api/protocolV2.d.ts.map +1 -1
  60. package/dist/types/device.d.ts +6 -3
  61. package/dist/types/device.d.ts.map +1 -1
  62. package/dist/types/params.d.ts.map +1 -1
  63. package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
  64. package/dist/utils/deviceFeaturesUtils.d.ts +0 -5
  65. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  66. package/dist/utils/patch.d.ts +1 -1
  67. package/dist/utils/patch.d.ts.map +1 -1
  68. package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
  69. package/package.json +4 -4
  70. package/src/api/CheckAllFirmwareRelease.ts +11 -81
  71. package/src/api/FirmwareUpdateV4.ts +59 -25
  72. package/src/api/GetPassphraseState.ts +11 -2
  73. package/src/api/OpenWalletSession.ts +16 -8
  74. package/src/api/device/DeviceSettings.ts +8 -1
  75. package/src/api/evm/EVMGetAddress.ts +2 -2
  76. package/src/api/evm/EVMGetPublicKey.ts +2 -2
  77. package/src/api/evm/EVMSignMessage.ts +2 -2
  78. package/src/api/evm/EVMSignTransaction.ts +2 -2
  79. package/src/api/evm/EVMSignTypedData.ts +35 -45
  80. package/src/api/evm/EVMVerifyMessage.ts +2 -2
  81. package/src/api/evm/protocol.ts +6 -0
  82. package/src/api/kaspa/KaspaSignTransaction.ts +7 -0
  83. package/src/api/protocol-v2/DeviceGetOnboardingStatus.ts +2 -2
  84. package/src/api/protocol-v2/DeviceUploadWallpaper.ts +1 -1
  85. package/src/core/index.ts +7 -5
  86. package/src/data/messages/messages-protocol-v2.json +393 -485
  87. package/src/device/Device.ts +98 -44
  88. package/src/device/DeviceCommands.ts +12 -2
  89. package/src/device/DeviceConnector.ts +10 -7
  90. package/src/device/DevicePool.ts +5 -3
  91. package/src/device/DeviceStateMapper.ts +5 -3
  92. package/src/device/DeviceStateProjector.ts +0 -7
  93. package/src/device/DeviceWalletSessionStore.ts +43 -4
  94. package/src/deviceProfile/buildDeviceFeatures.ts +11 -4
  95. package/src/deviceProfile/protocolV2DeviceIdentity.ts +32 -0
  96. package/src/events/logBlockEvent.ts +84 -1
  97. package/src/protocols/protocol-v2/deviceSession.ts +1 -1
  98. package/src/protocols/protocol-v2/features.ts +58 -16
  99. package/src/protocols/protocol-v2/index.ts +5 -0
  100. package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +8 -3
  101. package/src/protocols/protocol-v2/unlockRetry.ts +18 -7
  102. package/src/protocols/protocol-v2/walletSession.ts +144 -62
  103. package/src/types/api/protocolV2.ts +2 -2
  104. package/src/types/device.ts +8 -2
  105. package/src/types/params.ts +2 -1
  106. package/src/utils/deviceFeaturesCompat.ts +8 -1
  107. package/src/utils/pro2Wallpaper.ts +3 -9
  108. package/tsconfig.type-tests.json +5 -1
@@ -55,6 +55,7 @@ import { DataManager } from '../data-manager';
55
55
  import TransportManager from '../data-manager/TransportManager';
56
56
  import { toHardened } from '../api/helpers/pathUtils';
57
57
  import {
58
+ PROTOCOL_V2_DEVICE_STATUS_GET_MESSAGE_TYPE,
58
59
  PROTOCOL_V2_FEATURES_DEVICE_INFO_REQUEST,
59
60
  PROTOCOL_V2_FULL_DEVICE_INFO_REQUEST,
60
61
  PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
@@ -62,8 +63,11 @@ import {
62
63
  getProtocolV2RuntimeMode,
63
64
  requestProtocolV2DeviceInfo,
64
65
  requestProtocolV2DeviceStatus,
66
+ requestProtocolV2ProtocolInfo,
67
+ supportsProtocolV2Message,
65
68
  } from '../protocols/protocol-v2/features';
66
69
  import { buildProtocolV1FeaturesPayload } from '../deviceProfile';
70
+ import { resolveProtocolV2DeviceIdentity } from '../deviceProfile/protocolV2DeviceIdentity';
67
71
 
68
72
  import type { PROTO } from '../constants';
69
73
  import type { DeviceStateReadOptions } from '../types/api/getDeviceState';
@@ -77,6 +81,7 @@ import type { Deferred, HardwareConnectProtocol } from '@onekeyfe/hd-shared';
77
81
  import type {
78
82
  OneKeyDeviceInfo as DeviceDescriptor,
79
83
  DeviceStatus,
84
+ ProtocolInfo,
80
85
  ProtocolV2DeviceInfo,
81
86
  Success,
82
87
  } from '@onekeyfe/hd-transport';
@@ -280,7 +285,7 @@ export class Device extends EventEmitter {
280
285
 
281
286
  // simplified object to pass via postMessage
282
287
  toMessageObject(): DeviceTyped | null {
283
- if (this.isUnacquired()) return null;
288
+ if (this.isUnacquired() || !this.features) return null;
284
289
 
285
290
  const env = DataManager.getSettings('env');
286
291
  const deviceType = this.getCurrentDeviceType();
@@ -297,6 +302,8 @@ export class Device extends EventEmitter {
297
302
  return {
298
303
  /** Android uses a MAC address, while iOS and USB use transport-specific identifiers. */
299
304
  connectId: DataManager.isBleConnect(env) ? this.mainId || null : connectId,
305
+ /** Persist this after the first active probe so later calls do not need to guess. */
306
+ connectProtocol: this.originalDescriptor.protocolType,
300
307
  /** Stable physical-device identity. */
301
308
  serialNo,
302
309
  /** @deprecated Use serialNo instead. */
@@ -364,12 +371,12 @@ export class Device extends EventEmitter {
364
371
  }
365
372
 
366
373
  async acquire(
367
- connectProtocol?: HardwareConnectProtocol,
374
+ expectedProtocol?: HardwareConnectProtocol,
368
375
  options?: { throwOnRunPromiseError?: boolean }
369
376
  ) {
370
377
  const env = DataManager.getSettings('env');
371
378
  const mainIdKey = DataManager.isBleConnect(env) ? 'id' : 'session';
372
- const expectedProtocol = connectProtocol ?? this.originalDescriptor.protocolType;
379
+ const protocolHint = expectedProtocol ? undefined : this.originalDescriptor.protocolType;
373
380
  try {
374
381
  let acquireResult: unknown;
375
382
  if (DataManager.isBleConnect(env)) {
@@ -381,7 +388,8 @@ export class Device extends EventEmitter {
381
388
  this.originalDescriptor.id,
382
389
  undefined,
383
390
  true,
384
- expectedProtocol
391
+ expectedProtocol,
392
+ protocolHint
385
393
  );
386
394
  this.mainId = (acquireResult as any)?.uuid ?? '';
387
395
  Log.debug('Expected uuid:', this.mainId);
@@ -390,7 +398,8 @@ export class Device extends EventEmitter {
390
398
  this.originalDescriptor.path,
391
399
  this.originalDescriptor.session,
392
400
  undefined,
393
- expectedProtocol
401
+ expectedProtocol,
402
+ protocolHint
394
403
  );
395
404
  this.mainId = acquireResult as string | undefined;
396
405
  Log.debug('Expected session id:', this.mainId);
@@ -717,13 +726,20 @@ export class Device extends EventEmitter {
717
726
  return deviceWalletSessionStore.get(deviceId, this.passphraseState);
718
727
  }
719
728
 
729
+ getStandardInternalState(_deviceId?: string) {
730
+ const deviceId = this.getSessionCacheDeviceKey(_deviceId);
731
+ if (!deviceId) return undefined;
732
+ return deviceWalletSessionStore.getStandard(deviceId);
733
+ }
734
+
720
735
  // attach to pin to fix internal state
721
736
  updateInternalState(
722
737
  enablePassphrase: boolean,
723
738
  passphraseState: string | undefined,
724
739
  deviceId: string | undefined,
725
740
  sessionId: string | null = null,
726
- featuresSessionId: string | null = null
741
+ featuresSessionId: string | null = null,
742
+ walletType: 'standard' | 'hidden' = 'hidden'
727
743
  ) {
728
744
  Log.debug(
729
745
  'updateInternalState session param: ',
@@ -740,7 +756,15 @@ export class Device extends EventEmitter {
740
756
  if (enablePassphrase) {
741
757
  const walletSessionId =
742
758
  sessionId || featuresSessionId || deviceWalletSessionStore.getPending(cacheDeviceKey);
743
- deviceWalletSessionStore.set(cacheDeviceKey, passphraseState, walletSessionId ?? undefined);
759
+ if (walletType === 'standard') {
760
+ deviceWalletSessionStore.setStandard(
761
+ cacheDeviceKey,
762
+ passphraseState,
763
+ walletSessionId ?? undefined
764
+ );
765
+ } else {
766
+ deviceWalletSessionStore.set(cacheDeviceKey, passphraseState, walletSessionId ?? undefined);
767
+ }
744
768
  }
745
769
 
746
770
  deviceWalletSessionStore.deletePending(cacheDeviceKey);
@@ -779,6 +803,12 @@ export class Device extends EventEmitter {
779
803
  }
780
804
  }
781
805
 
806
+ clearStandardInternalState(_deviceId?: string) {
807
+ const deviceId = this.getSessionCacheDeviceKey(_deviceId);
808
+ if (!deviceId) return;
809
+ deviceWalletSessionStore.deleteStandard(deviceId);
810
+ }
811
+
782
812
  async initialize(options?: InitOptions) {
783
813
  // Protocol V2 does not support legacy Initialize; use its dedicated flow.
784
814
  if (this.isProtocolV2()) {
@@ -810,9 +840,12 @@ export class Device extends EventEmitter {
810
840
 
811
841
  const expectedDeviceId = options?.deviceId;
812
842
  if (expectedDeviceId) {
813
- // Establish the live physical identity before sending wallet-bound state.
843
+ // 先只读校验物理设备身份;钱包上下文仍由下方携带完整参数的
844
+ // Initialize 选择,避免标准钱包请求复用此前的隐藏钱包上下文。
814
845
  this.passphraseState = undefined;
815
- await callInitialize({ is_contains_attach: true });
846
+ const { message } = await this.commands.typedCall('GetFeatures', 'Features', {});
847
+ this._updateFeatures(message);
848
+ await TransportManager.reconfigure(this.features);
816
849
  if (!this.checkDeviceId(expectedDeviceId)) {
817
850
  throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckDeviceIdError);
818
851
  }
@@ -836,15 +869,7 @@ export class Device extends EventEmitter {
836
869
  payload.derive_cardano = true;
837
870
  }
838
871
 
839
- const requiresWalletInitialize =
840
- !expectedDeviceId ||
841
- Boolean(internalState) ||
842
- Boolean(options?.passphraseState) ||
843
- options?.deriveCardano === true ||
844
- options?.initSession === true;
845
- if (requiresWalletInitialize) {
846
- await callInitialize(payload, options?.initSession);
847
- }
872
+ await callInitialize(payload, options?.initSession);
848
873
  } catch (error) {
849
874
  Log.error('Initialization failed:', error);
850
875
  throw error;
@@ -1020,40 +1045,60 @@ export class Device extends EventEmitter {
1020
1045
  }
1021
1046
 
1022
1047
  async probeProtocolV2RuntimeState(deviceInfo: ProtocolV2DeviceInfo, timeoutMs?: number) {
1023
- let deviceStatus: DeviceStatus;
1024
- try {
1025
- deviceStatus = await requestProtocolV2DeviceStatus({
1026
- commands: this.commands,
1027
- timeoutMs,
1028
- });
1029
- } catch (error) {
1030
- const runtimeMode = getProtocolV2RuntimeMode({
1031
- deviceInfo,
1032
- deviceStatusAvailable: false,
1033
- });
1034
- Log.debug('Protocol V2 DeviceStatusGet unavailable; use temporary loader fallback', {
1035
- runtimeMode,
1036
- error: error instanceof Error ? error.message : String(error),
1037
- });
1038
- return this.updateProtocolV2Features(deviceInfo, null, runtimeMode);
1048
+ const protocolInfo = await requestProtocolV2ProtocolInfo({
1049
+ commands: this.commands,
1050
+ timeoutMs,
1051
+ });
1052
+ const runtimeMode = getProtocolV2RuntimeMode(protocolInfo);
1053
+ const protocolV2DeviceType = resolveProtocolV2DeviceIdentity(
1054
+ deviceInfo.hw?.Device_type
1055
+ ).deviceType;
1056
+ if (runtimeMode === 'romloader' && protocolV2DeviceType !== EDeviceType.Pro2) {
1057
+ throw ERRORS.TypedError(
1058
+ HardwareErrorCode.DeviceInitializeFailed,
1059
+ 'Protocol V2 romloader mode is only supported for Pro2.'
1060
+ );
1061
+ }
1062
+ const deviceStatusSupported = supportsProtocolV2Message(
1063
+ protocolInfo,
1064
+ PROTOCOL_V2_DEVICE_STATUS_GET_MESSAGE_TYPE
1065
+ );
1066
+
1067
+ if (runtimeMode === 'bootloader' || runtimeMode === 'romloader') {
1068
+ return this.updateProtocolV2Features(deviceInfo, null, runtimeMode, protocolInfo);
1069
+ }
1070
+
1071
+ if (!deviceStatusSupported) {
1072
+ if (runtimeMode === 'normal') {
1073
+ return this.updateProtocolV2Features(deviceInfo, null, runtimeMode, protocolInfo);
1074
+ }
1075
+ throw ERRORS.TypedError(
1076
+ HardwareErrorCode.DeviceInitializeFailed,
1077
+ `Unknown Protocol V2 build fingerprint without DeviceStatusGet capability: ${protocolInfo.build_fingerprint}`
1078
+ );
1039
1079
  }
1040
- return this.updateProtocolV2Features(deviceInfo, deviceStatus, 'normal');
1080
+
1081
+ const deviceStatus = await requestProtocolV2DeviceStatus({
1082
+ commands: this.commands,
1083
+ timeoutMs,
1084
+ });
1085
+ return this.updateProtocolV2Features(deviceInfo, deviceStatus, 'normal', protocolInfo);
1041
1086
  }
1042
1087
 
1043
1088
  updateProtocolV2Features(
1044
1089
  deviceInfo?: ProtocolV2DeviceInfo,
1045
1090
  deviceStatus?: DeviceStatus | null,
1046
- runtimeMode?: ProtocolV2RuntimeMode
1091
+ runtimeMode?: ProtocolV2RuntimeMode,
1092
+ protocolInfo?: ProtocolInfo
1047
1093
  ) {
1048
1094
  const previousDeviceId = this.getCurrentDeviceId();
1049
- const resolvedMode =
1050
- runtimeMode ??
1051
- (deviceStatus
1052
- ? getProtocolV2RuntimeMode({ deviceInfo, deviceStatusAvailable: true })
1053
- : this.state?.status.mode);
1095
+ const resolvedMode = runtimeMode ?? (deviceStatus ? 'normal' : this.state?.status.mode);
1054
1096
  if (deviceInfo) {
1055
1097
  this.updateState(mapProtocolV2DeviceInfoToState(deviceInfo, resolvedMode), 'device-info');
1056
1098
  }
1099
+ if (protocolInfo) {
1100
+ this.updateState({ raw: { protocolV2ProtocolInfo: protocolInfo } }, 'device-info');
1101
+ }
1057
1102
  if (deviceStatus) {
1058
1103
  this.updateState(mapProtocolV2DeviceStatusToState(deviceStatus), 'device-status');
1059
1104
  }
@@ -1122,7 +1167,7 @@ export class Device extends EventEmitter {
1122
1167
  attachToPinEnabled: null,
1123
1168
  unlockedAttachPin: null,
1124
1169
  },
1125
- raw: { protocolV2DeviceStatus: null },
1170
+ raw: { protocolV2ProtocolInfo: null, protocolV2DeviceStatus: null },
1126
1171
  },
1127
1172
  'transport-reconnect'
1128
1173
  );
@@ -1132,7 +1177,7 @@ export class Device extends EventEmitter {
1132
1177
  this.updateState(
1133
1178
  {
1134
1179
  status: { mode: 'normal', unlocked: null },
1135
- raw: { protocolV2DeviceStatus: null },
1180
+ raw: { protocolV2ProtocolInfo: null, protocolV2DeviceStatus: null },
1136
1181
  },
1137
1182
  'transport-reconnect'
1138
1183
  );
@@ -1378,7 +1423,16 @@ export class Device extends EventEmitter {
1378
1423
 
1379
1424
  isBootloader() {
1380
1425
  if (!this.state) return undefined;
1381
- return this.state.status.mode === 'bootloader' || this.state.status.mode === 'romloader';
1426
+ return this.state.status.mode === 'bootloader';
1427
+ }
1428
+
1429
+ isRomloader() {
1430
+ if (!this.state) return undefined;
1431
+ return (
1432
+ this.isProtocolV2() &&
1433
+ this.getCurrentDeviceType() === EDeviceType.Pro2 &&
1434
+ this.state.status.mode === 'romloader'
1435
+ );
1382
1436
  }
1383
1437
 
1384
1438
  isInitialized() {
@@ -6,6 +6,7 @@ import {
6
6
  type Messages,
7
7
  type Transport,
8
8
  type TransportCallOptions,
9
+ getSafeTransportLogPayload,
9
10
  } from '@onekeyfe/hd-transport';
10
11
 
11
12
  import TransportManager from '../data-manager/TransportManager';
@@ -282,7 +283,11 @@ export class DeviceCommands {
282
283
  ): Promise<DefaultMessageResponse> {
283
284
  const shouldReduceDebug = shouldReduceDebugForCall(type);
284
285
  if (!shouldReduceDebug) {
285
- Log.debug('[DeviceCommands] [call] Sending', type);
286
+ Log.debug(
287
+ '[DeviceCommands] [call] Sending',
288
+ type,
289
+ getSafeTransportLogPayload(msg ?? {}, type)
290
+ );
286
291
  }
287
292
 
288
293
  try {
@@ -290,13 +295,18 @@ export class DeviceCommands {
290
295
  this.callPromise = promise;
291
296
  const res = await promise;
292
297
  if (!shouldReduceDebug) {
293
- LogCore.debug('[DeviceCommands] [call] Received', res.type);
298
+ LogCore.debug(
299
+ '[DeviceCommands] [call] Received',
300
+ res.type,
301
+ getSafeTransportLogPayload(res.message, res.type)
302
+ );
294
303
  }
295
304
  return res;
296
305
  } catch (error) {
297
306
  LogCore.debug('[DeviceCommands] [call] Received error', {
298
307
  request: type,
299
308
  errorCode: error?.errorCode,
309
+ response: getSafeTransportLogPayload(error?.response?.data, type),
300
310
  });
301
311
  if (error.errorCode === HardwareErrorCode.BleDeviceBondError) {
302
312
  return {
@@ -82,9 +82,10 @@ export default class DeviceConnector {
82
82
  path: string,
83
83
  session?: string | null,
84
84
  forceCleanRunPromise?: boolean,
85
- connectProtocol?: HardwareConnectProtocol
85
+ expectedProtocol?: HardwareConnectProtocol,
86
+ protocolHint?: HardwareConnectProtocol
86
87
  ) {
87
- Log.debug('acquire', path, session, connectProtocol);
88
+ Log.debug('acquire', path, session, expectedProtocol, protocolHint);
88
89
  const env = DataManager.getSettings('env');
89
90
  try {
90
91
  let res;
@@ -92,21 +93,23 @@ export default class DeviceConnector {
92
93
  res = await this.transport.acquire({
93
94
  uuid: path,
94
95
  forceCleanRunPromise,
95
- expectedProtocol: connectProtocol,
96
+ expectedProtocol,
97
+ protocolHint,
96
98
  });
97
99
  } else {
98
100
  res = await this.transport.acquire({
99
101
  path,
100
102
  previous: session ?? null,
101
- expectedProtocol: connectProtocol,
103
+ expectedProtocol,
104
+ protocolHint,
102
105
  });
103
106
  }
104
- if (connectProtocol) {
107
+ if (expectedProtocol) {
105
108
  const detectedProtocol = this.transport.getProtocolType(path);
106
- if (detectedProtocol !== connectProtocol) {
109
+ if (detectedProtocol !== expectedProtocol) {
107
110
  throw ERRORS.TypedError(
108
111
  HardwareErrorCode.RuntimeError,
109
- `Device protocol mismatch: expected ${connectProtocol}, detected ${detectedProtocol}`
112
+ `Device protocol mismatch: expected ${expectedProtocol}, detected ${detectedProtocol}`
110
113
  );
111
114
  }
112
115
  }
@@ -306,9 +306,11 @@ export class DevicePool extends EventEmitter {
306
306
  this.disconnectPool = [];
307
307
  this.devicesCache = {};
308
308
 
309
- // Clear all event listeners but keep the emitter instance
310
- this.emitter.removeAllListeners();
311
-
312
309
  Log.debug('DevicePool state has been reset');
313
310
  }
311
+
312
+ static dispose() {
313
+ this.resetState();
314
+ this.emitter.removeAllListeners();
315
+ }
314
316
  }
@@ -1,6 +1,7 @@
1
- import { EDeviceType, EFirmwareType } from '@onekeyfe/hd-shared';
1
+ import { EFirmwareType } from '@onekeyfe/hd-shared';
2
2
 
3
3
  import { buildProtocolV1FeaturesPayload } from '../deviceProfile/buildDeviceFeatures';
4
+ import { resolveProtocolV2DeviceIdentity } from '../deviceProfile/protocolV2DeviceIdentity';
4
5
  import {
5
6
  mapLanguageFromProtocolV2,
6
7
  mapLanguageToProtocolV2,
@@ -211,14 +212,15 @@ export const mapProtocolV2DeviceInfoToState = (
211
212
  mode: DeviceStateMode = 'unknown'
212
213
  ): DeviceStatePatch => {
213
214
  const loader = mode === 'bootloader' || mode === 'romloader';
215
+ const identity = resolveProtocolV2DeviceIdentity(info.hw?.Device_type);
214
216
 
215
217
  return {
216
218
  protocol: 'V2',
217
219
  protocolVersion: info.protocol_version,
218
220
  identity: definedEntries({
219
- deviceType: EDeviceType.Pro2,
221
+ deviceType: identity.deviceType,
220
222
  firmwareType: EFirmwareType.Universal,
221
- model: 'pro2',
223
+ model: identity.model,
222
224
  vendor: 'onekey.so',
223
225
  serialNo: info.hw?.serial_no,
224
226
  bleName: info.coprocessor?.bt_adv_name,
@@ -16,12 +16,6 @@ export const projectFeatures = (state: StoredDeviceState): Features => {
16
16
  delete publicRawFeatures.session_id;
17
17
  delete publicRawFeatures.sessionId;
18
18
  delete publicRawFeatures.passphraseState;
19
- const publicRaw = snapshot.raw
20
- ? {
21
- ...snapshot.raw,
22
- protocolV1Features: publicRawFeatures,
23
- }
24
- : undefined;
25
19
  const rawOneKeyFeatures = snapshot.raw?.protocolV1OneKeyFeatures ?? {};
26
20
  const bootloaderMode =
27
21
  snapshot.protocol === 'V1'
@@ -90,7 +84,6 @@ export const projectFeatures = (state: StoredDeviceState): Features => {
90
84
  se04BootVersion: snapshot.versions.se04Boot,
91
85
  seVersion: snapshot.versions.se ?? null,
92
86
  verify: snapshot.verification,
93
- raw: publicRaw,
94
87
  device_id: snapshot.identity.deviceId ?? undefined,
95
88
  ble_name: snapshot.identity.bleName ?? undefined,
96
89
  passphrase_protection: snapshot.status.passphraseProtection ?? undefined,
@@ -1,6 +1,11 @@
1
1
  export class DeviceWalletSessionStore {
2
2
  private readonly walletSessions = new Map<string, Map<string, string>>();
3
3
 
4
+ private readonly standardWalletSessions = new Map<
5
+ string,
6
+ { passphraseState: string; sessionId: string }
7
+ >();
8
+
4
9
  private readonly pendingSessions = new Map<string, string>();
5
10
 
6
11
  get(deviceKey: string, passphraseState?: string) {
@@ -18,6 +23,17 @@ export class DeviceWalletSessionStore {
18
23
  deviceSessions.set(passphraseState, sessionId);
19
24
  }
20
25
 
26
+ getStandard(deviceKey: string) {
27
+ if (!deviceKey) return undefined;
28
+ return this.standardWalletSessions.get(deviceKey);
29
+ }
30
+
31
+ setStandard(deviceKey: string, passphraseState?: string, sessionId?: string) {
32
+ if (!deviceKey || !passphraseState || !sessionId) return;
33
+ this.set(deviceKey, passphraseState, sessionId);
34
+ this.standardWalletSessions.set(deviceKey, { passphraseState, sessionId });
35
+ }
36
+
21
37
  setPending(deviceKey: string, sessionId?: string) {
22
38
  if (!deviceKey || !sessionId) return;
23
39
  this.pendingSessions.set(deviceKey, sessionId);
@@ -30,6 +46,10 @@ export class DeviceWalletSessionStore {
30
46
 
31
47
  delete(deviceKey: string, passphraseState?: string) {
32
48
  if (!deviceKey || !passphraseState) return;
49
+ const standardWalletSession = this.standardWalletSessions.get(deviceKey);
50
+ if (standardWalletSession?.passphraseState === passphraseState) {
51
+ this.standardWalletSessions.delete(deviceKey);
52
+ }
33
53
  const deviceSessions = this.walletSessions.get(deviceKey);
34
54
  if (!deviceSessions) return;
35
55
  deviceSessions.delete(passphraseState);
@@ -38,6 +58,15 @@ export class DeviceWalletSessionStore {
38
58
  }
39
59
  }
40
60
 
61
+ deleteStandard(deviceKey: string) {
62
+ if (!deviceKey) return;
63
+ const standardWalletSession = this.standardWalletSessions.get(deviceKey);
64
+ this.standardWalletSessions.delete(deviceKey);
65
+ if (standardWalletSession) {
66
+ this.delete(deviceKey, standardWalletSession.passphraseState);
67
+ }
68
+ }
69
+
41
70
  deletePending(deviceKey: string) {
42
71
  if (!deviceKey) return;
43
72
  this.pendingSessions.delete(deviceKey);
@@ -46,6 +75,7 @@ export class DeviceWalletSessionStore {
46
75
  deleteDevice(deviceKey: string) {
47
76
  if (!deviceKey) return;
48
77
  this.walletSessions.delete(deviceKey);
78
+ this.standardWalletSessions.delete(deviceKey);
49
79
  this.pendingSessions.delete(deviceKey);
50
80
  }
51
81
 
@@ -54,16 +84,24 @@ export class DeviceWalletSessionStore {
54
84
 
55
85
  const sourceSessions = this.walletSessions.get(from);
56
86
  if (sourceSessions) {
57
- const targetSessions = this.walletSessions.get(to) ?? new Map<string, string>();
58
- this.walletSessions.set(to, targetSessions);
59
87
  sourceSessions.forEach((sessionId, passphraseState) => {
60
- if (!targetSessions.has(passphraseState)) {
61
- targetSessions.set(passphraseState, sessionId);
88
+ if (!this.get(to, passphraseState)) {
89
+ this.set(to, passphraseState, sessionId);
62
90
  }
63
91
  });
64
92
  this.walletSessions.delete(from);
65
93
  }
66
94
 
95
+ const standardWalletSession = this.standardWalletSessions.get(from);
96
+ if (
97
+ standardWalletSession &&
98
+ !this.standardWalletSessions.has(to) &&
99
+ this.get(to, standardWalletSession.passphraseState) === standardWalletSession.sessionId
100
+ ) {
101
+ this.standardWalletSessions.set(to, standardWalletSession);
102
+ }
103
+ this.standardWalletSessions.delete(from);
104
+
67
105
  const pendingSession = this.pendingSessions.get(from);
68
106
  if (pendingSession && !this.pendingSessions.has(to)) {
69
107
  this.pendingSessions.set(to, pendingSession);
@@ -98,6 +136,7 @@ export class DeviceWalletSessionStore {
98
136
 
99
137
  clear() {
100
138
  this.walletSessions.clear();
139
+ this.standardWalletSessions.clear();
101
140
  this.pendingSessions.clear();
102
141
  }
103
142
  }
@@ -1,4 +1,4 @@
1
- import { EDeviceType, EFirmwareType } from '@onekeyfe/hd-shared';
1
+ import { EFirmwareType } from '@onekeyfe/hd-shared';
2
2
 
3
3
  import {
4
4
  resolveDeviceBleFirmwareVersion,
@@ -11,6 +11,7 @@ import {
11
11
  resolveDeviceType,
12
12
  } from '../utils/deviceFeaturesCompat';
13
13
  import { normalizeSafetyCheckLevel } from '../utils/deviceSettings';
14
+ import { resolveProtocolV2DeviceIdentity } from './protocolV2DeviceIdentity';
14
15
 
15
16
  import type {
16
17
  DeviceFirmwareImageInfo,
@@ -224,6 +225,12 @@ export const buildProtocolV2FeaturesPayload = ({
224
225
  const samePhysicalDevice =
225
226
  !incomingSerialNo || !previous?.serialNo || incomingSerialNo === previous.serialNo;
226
227
  const cached = samePhysicalDevice ? previous : undefined;
228
+ const incomingDeviceType = info?.hw?.Device_type;
229
+ const resolvedIdentity = resolveProtocolV2DeviceIdentity(incomingDeviceType);
230
+ const cachedIdentity =
231
+ incomingDeviceType === undefined || incomingDeviceType === null ? cached : undefined;
232
+ const deviceType = cachedIdentity ? cachedIdentity.deviceType : resolvedIdentity.deviceType;
233
+ const model = cachedIdentity ? cachedIdentity.model : resolvedIdentity.model;
227
234
 
228
235
  const firmwareVersion = firstMeaningfulVersion(
229
236
  getImageVersion(fwApplication),
@@ -253,7 +260,7 @@ export const buildProtocolV2FeaturesPayload = ({
253
260
  const attachToPinEnabled = status?.attach_to_pin_enabled ?? cached?.attachToPinEnabled ?? null;
254
261
  const unlockedAttachPin =
255
262
  status?.unlocked_by_attach_to_pin ?? cached?.unlockedAttachPin ?? undefined;
256
- const bootloaderMode = runtimeMode === 'bootloader';
263
+ const bootloaderMode = runtimeMode === 'bootloader' || runtimeMode === 'romloader';
257
264
  let mode: DeviceFeaturesMode = 'unknown';
258
265
  if (runtimeMode) {
259
266
  mode = runtimeMode;
@@ -270,9 +277,9 @@ export const buildProtocolV2FeaturesPayload = ({
270
277
  return {
271
278
  protocol: 'V2',
272
279
  protocolVersion: deviceInfo?.protocol_version ?? cached?.protocolVersion ?? null,
273
- deviceType: EDeviceType.Pro2,
280
+ deviceType,
274
281
  firmwareType: cached?.firmwareType ?? EFirmwareType.Universal,
275
- model: 'pro2',
282
+ model,
276
283
  vendor: 'onekey.so',
277
284
  deviceId,
278
285
  serialNo,
@@ -0,0 +1,32 @@
1
+ import { EDeviceType } from '@onekeyfe/hd-shared';
2
+ import { DeviceType } from '@onekeyfe/hd-transport';
3
+
4
+ export const resolveProtocolV2DeviceIdentity = (
5
+ deviceType?: DeviceType | keyof typeof DeviceType | null
6
+ ): { deviceType: EDeviceType; model: string | null } => {
7
+ switch (deviceType) {
8
+ case DeviceType.CLASSIC1:
9
+ case 'CLASSIC1':
10
+ return { deviceType: EDeviceType.Classic, model: 'classic' };
11
+ case DeviceType.CLASSIC1S:
12
+ case 'CLASSIC1S':
13
+ return { deviceType: EDeviceType.Classic1s, model: 'classic1s' };
14
+ case DeviceType.CLASSIC1S_PURE:
15
+ case 'CLASSIC1S_PURE':
16
+ return { deviceType: EDeviceType.ClassicPure, model: 'classicpure' };
17
+ case DeviceType.MINI:
18
+ case 'MINI':
19
+ return { deviceType: EDeviceType.Mini, model: 'mini' };
20
+ case DeviceType.TOUCH:
21
+ case 'TOUCH':
22
+ return { deviceType: EDeviceType.Touch, model: 'touch' };
23
+ case DeviceType.PRO:
24
+ case 'PRO':
25
+ return { deviceType: EDeviceType.Pro, model: 'pro' };
26
+ case DeviceType.PRO2:
27
+ case 'PRO2':
28
+ return { deviceType: EDeviceType.Pro2, model: 'pro2' };
29
+ default:
30
+ return { deviceType: EDeviceType.Unknown, model: null };
31
+ }
32
+ };