@onekeyfe/hd-core 1.2.0-alpha.19 → 1.2.0-alpha.20

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 (256) hide show
  1. package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +75 -0
  2. package/__tests__/DeviceCommands.test.ts +143 -7
  3. package/__tests__/RequestQueue.test.ts +106 -0
  4. package/__tests__/UploadPortfolio.test.ts +46 -0
  5. package/__tests__/core-dispose.test.ts +34 -0
  6. package/__tests__/core-error-output.test.ts +39 -0
  7. package/__tests__/device-lifecycle-events.test.ts +117 -0
  8. package/__tests__/device-pool-state.test.ts +20 -1
  9. package/__tests__/device-settings.test.ts +184 -6
  10. package/__tests__/device-state-events.test.ts +1 -2
  11. package/__tests__/device-state-mapper.test.ts +33 -26
  12. package/__tests__/device-state-store.test.ts +1 -34
  13. package/__tests__/device-utils.test.ts +106 -0
  14. package/__tests__/device-wallet-session-store.test.ts +65 -29
  15. package/__tests__/deviceSettings.test.ts +21 -12
  16. package/__tests__/evmLedgerLegacySafety.test.ts +2 -2
  17. package/__tests__/evmSignTypedData.test.ts +80 -0
  18. package/__tests__/filesystemValidation.test.ts +53 -0
  19. package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +402 -0
  20. package/__tests__/get-device-state.test.ts +77 -41
  21. package/__tests__/logBlockEvent.test.ts +24 -11
  22. package/__tests__/networkUtils.test.ts +386 -0
  23. package/__tests__/open-wallet-session-error-response.test.ts +43 -0
  24. package/__tests__/open-wallet-session.test.ts +559 -0
  25. package/__tests__/protocol-v2.test.ts +756 -452
  26. package/__tests__/public-device-state-api.test.ts +113 -13
  27. package/__tests__/public-pro2-api-boundary.test.ts +91 -0
  28. package/__tests__/search-devices.test.ts +43 -0
  29. package/dist/api/BaseMethod.d.ts +3 -0
  30. package/dist/api/BaseMethod.d.ts.map +1 -1
  31. package/dist/api/CheckBootloaderRelease.d.ts.map +1 -1
  32. package/dist/api/CheckFirmwareRelease.d.ts.map +1 -1
  33. package/dist/api/ClearSessionCache.d.ts.map +1 -1
  34. package/dist/api/DirList.d.ts.map +1 -1
  35. package/dist/api/FileRead.d.ts.map +1 -1
  36. package/dist/api/FirmwareUpdateV2.d.ts +2 -2
  37. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  38. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  39. package/dist/api/FirmwareUpdateV4.d.ts +3 -2
  40. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  41. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  42. package/dist/api/OpenWalletSession.d.ts +14 -0
  43. package/dist/api/OpenWalletSession.d.ts.map +1 -0
  44. package/dist/api/PathInfo.d.ts.map +1 -1
  45. package/dist/api/PromptWebDeviceAccess.d.ts.map +1 -1
  46. package/dist/api/SearchDevices.d.ts +3 -0
  47. package/dist/api/SearchDevices.d.ts.map +1 -1
  48. package/dist/api/UploadPortfolio.d.ts.map +1 -1
  49. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  50. package/dist/api/device/DeviceChangePin.d.ts.map +1 -1
  51. package/dist/api/device/DeviceFullyUploadResource.d.ts +1 -2
  52. package/dist/api/device/DeviceFullyUploadResource.d.ts.map +1 -1
  53. package/dist/api/device/DeviceSettings.d.ts.map +1 -1
  54. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  55. package/dist/api/device/DeviceWipe.d.ts.map +1 -1
  56. package/dist/api/evm/EVMSignTypedData.d.ts.map +1 -1
  57. package/dist/api/firmware/getBinary.d.ts +7 -3
  58. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  59. package/dist/api/helpers/filesystemValidation.d.ts +3 -0
  60. package/dist/api/helpers/filesystemValidation.d.ts.map +1 -1
  61. package/dist/api/helpers/paramsValidator.d.ts +1 -0
  62. package/dist/api/helpers/paramsValidator.d.ts.map +1 -1
  63. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
  64. package/dist/api/index.d.ts +7 -11
  65. package/dist/api/index.d.ts.map +1 -1
  66. package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts.map +1 -1
  67. package/dist/api/protocol-v2/DeviceSettingsPageShow.d.ts.map +1 -1
  68. package/dist/api/protocol-v2/DeviceSettingsSet.d.ts.map +1 -1
  69. package/dist/api/utils.d.ts.map +1 -1
  70. package/dist/core/RequestQueue.d.ts +17 -1
  71. package/dist/core/RequestQueue.d.ts.map +1 -1
  72. package/dist/core/index.d.ts +3 -1
  73. package/dist/core/index.d.ts.map +1 -1
  74. package/dist/device/Device.d.ts +6 -5
  75. package/dist/device/Device.d.ts.map +1 -1
  76. package/dist/device/DeviceCommands.d.ts +5 -5
  77. package/dist/device/DeviceCommands.d.ts.map +1 -1
  78. package/dist/device/DevicePool.d.ts +1 -0
  79. package/dist/device/DevicePool.d.ts.map +1 -1
  80. package/dist/device/DeviceStateMapper.d.ts +2 -2
  81. package/dist/device/DeviceStateMapper.d.ts.map +1 -1
  82. package/dist/device/DeviceStateProjector.d.ts +1 -2
  83. package/dist/device/DeviceStateProjector.d.ts.map +1 -1
  84. package/dist/device/DeviceStateStore.d.ts +1 -3
  85. package/dist/device/DeviceStateStore.d.ts.map +1 -1
  86. package/dist/device/DeviceWalletSessionStore.d.ts +6 -1
  87. package/dist/device/DeviceWalletSessionStore.d.ts.map +1 -1
  88. package/dist/device/cloneDeviceState.d.ts +2 -0
  89. package/dist/device/cloneDeviceState.d.ts.map +1 -0
  90. package/dist/deviceProfile/buildDeviceFeatures.d.ts +3 -1
  91. package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
  92. package/dist/events/logBlockEvent.d.ts.map +1 -1
  93. package/dist/index.d.ts +608 -75
  94. package/dist/index.js +2287 -1706
  95. package/dist/inject.d.ts.map +1 -1
  96. package/dist/protocols/protocol-v2/deviceSession.d.ts +7 -0
  97. package/dist/protocols/protocol-v2/deviceSession.d.ts.map +1 -0
  98. package/dist/protocols/protocol-v2/features.d.ts +11 -4
  99. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  100. package/dist/protocols/protocol-v2/index.d.ts +2 -2
  101. package/dist/protocols/protocol-v2/index.d.ts.map +1 -1
  102. package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts +16 -0
  103. package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -0
  104. package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -1
  105. package/dist/protocols/protocol-v2/walletSession.d.ts +8 -3
  106. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  107. package/dist/types/api/checkAllFirmwareRelease.d.ts +1 -2
  108. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  109. package/dist/types/api/deviceSettings.d.ts +1 -0
  110. package/dist/types/api/deviceSettings.d.ts.map +1 -1
  111. package/dist/types/api/deviceUnlock.d.ts +1 -1
  112. package/dist/types/api/deviceUnlock.d.ts.map +1 -1
  113. package/dist/types/api/getFeatures.d.ts.map +1 -1
  114. package/dist/types/api/getOnekeyFeatures.d.ts.map +1 -1
  115. package/dist/types/api/getPassphraseState.d.ts.map +1 -1
  116. package/dist/types/api/index.d.ts +13 -15
  117. package/dist/types/api/index.d.ts.map +1 -1
  118. package/dist/types/api/openWalletSession.d.ts +41 -0
  119. package/dist/types/api/openWalletSession.d.ts.map +1 -0
  120. package/dist/types/api/protocolV2.d.ts +6 -11
  121. package/dist/types/api/protocolV2.d.ts.map +1 -1
  122. package/dist/types/device.d.ts +2 -9
  123. package/dist/types/device.d.ts.map +1 -1
  124. package/dist/utils/assets.d.ts +2 -1
  125. package/dist/utils/assets.d.ts.map +1 -1
  126. package/dist/utils/deviceFeaturesCompat.d.ts +13 -0
  127. package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -0
  128. package/dist/utils/deviceFeaturesUtils.d.ts +11 -1
  129. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  130. package/dist/utils/deviceInfoUtils.d.ts +9 -8
  131. package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
  132. package/dist/utils/deviceSettings.d.ts +2 -0
  133. package/dist/utils/deviceSettings.d.ts.map +1 -1
  134. package/dist/utils/deviceVersionUtils.d.ts +6 -5
  135. package/dist/utils/deviceVersionUtils.d.ts.map +1 -1
  136. package/dist/utils/index.d.ts +2 -2
  137. package/dist/utils/index.d.ts.map +1 -1
  138. package/dist/utils/networkUtils.d.ts +9 -1
  139. package/dist/utils/networkUtils.d.ts.map +1 -1
  140. package/dist/utils/patch.d.ts +1 -1
  141. package/dist/utils/patch.d.ts.map +1 -1
  142. package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
  143. package/package.json +4 -4
  144. package/src/api/BaseMethod.ts +17 -10
  145. package/src/api/CheckBootloaderRelease.ts +1 -2
  146. package/src/api/CheckFirmwareRelease.ts +1 -2
  147. package/src/api/ClearSessionCache.ts +0 -4
  148. package/src/api/DirList.ts +5 -3
  149. package/src/api/DirMake.ts +3 -3
  150. package/src/api/DirRemove.ts +3 -3
  151. package/src/api/FileDelete.ts +3 -3
  152. package/src/api/FileRead.ts +9 -6
  153. package/src/api/FileWrite.ts +3 -3
  154. package/src/api/FirmwareUpdate.ts +4 -4
  155. package/src/api/FirmwareUpdateV2.ts +133 -45
  156. package/src/api/FirmwareUpdateV3.ts +3 -5
  157. package/src/api/FirmwareUpdateV4.ts +192 -154
  158. package/src/api/GetPassphraseState.ts +10 -16
  159. package/src/api/OpenWalletSession.ts +221 -0
  160. package/src/api/PathInfo.ts +5 -3
  161. package/src/api/PromptWebDeviceAccess.ts +2 -3
  162. package/src/api/SearchDevices.ts +6 -2
  163. package/src/api/UploadPortfolio.ts +12 -3
  164. package/src/api/alephium/AlephiumSignTransaction.ts +2 -2
  165. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +4 -8
  166. package/src/api/benfen/BenfenGetAddress.ts +1 -1
  167. package/src/api/btc/BTCGetPublicKey.ts +1 -1
  168. package/src/api/device/DeviceChangePin.ts +1 -0
  169. package/src/api/device/DeviceFullyUploadResource.ts +4 -5
  170. package/src/api/device/DeviceSettings.ts +93 -0
  171. package/src/api/device/DeviceUpdateBootloader.ts +1 -2
  172. package/src/api/device/DeviceWipe.ts +1 -0
  173. package/src/api/evm/EVMSignTypedData.ts +3 -5
  174. package/src/api/evm/legacyV1/getAddress.ts +2 -2
  175. package/src/api/evm/legacyV1/getPublicKey.ts +2 -2
  176. package/src/api/evm/legacyV1/signMessage.ts +2 -2
  177. package/src/api/evm/legacyV1/signTypedData.ts +2 -2
  178. package/src/api/evm/legacyV1/signTypedHash.ts +2 -2
  179. package/src/api/evm/legacyV1/verifyMessage.ts +2 -2
  180. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +3 -3
  181. package/src/api/firmware/getBinary.ts +8 -3
  182. package/src/api/helpers/batchGetPublickeys.ts +2 -2
  183. package/src/api/helpers/filesystemValidation.ts +61 -0
  184. package/src/api/helpers/paramsValidator.ts +1 -1
  185. package/src/api/helpers/protocolV2FileWrite.ts +3 -2
  186. package/src/api/index.ts +9 -12
  187. package/src/api/nervos/NervosSignTransaction.ts +2 -2
  188. package/src/api/nexa/NexaSignTransaction.ts +1 -1
  189. package/src/api/protocol-v2/DeviceFactoryInfoGet.ts +1 -1
  190. package/src/api/protocol-v2/DeviceFactoryInfoSet.ts +1 -1
  191. package/src/api/protocol-v2/DeviceFirmwareUpdate.ts +4 -4
  192. package/src/api/protocol-v2/DeviceGetFirmwareUpdateStatus.ts +6 -5
  193. package/src/api/protocol-v2/DeviceInfoGet.ts +4 -4
  194. package/src/api/protocol-v2/DeviceReboot.ts +1 -1
  195. package/src/api/protocol-v2/DeviceSettingsPageShow.ts +11 -8
  196. package/src/api/protocol-v2/DeviceSettingsSet.ts +4 -11
  197. package/src/api/protocol-v2/FilesystemFormat.ts +1 -1
  198. package/src/api/protocol-v2/FilesystemPermissionFix.ts +1 -1
  199. package/src/api/protocol-v2/Ping.ts +1 -1
  200. package/src/api/protocol-v2/ProtocolInfoRequest.ts +1 -1
  201. package/src/api/utils.ts +1 -3
  202. package/src/core/RequestQueue.ts +107 -6
  203. package/src/core/index.ts +91 -46
  204. package/src/data/messages/messages-protocol-v2.json +25 -79
  205. package/src/data-manager/DataManager.ts +6 -6
  206. package/src/device/Device.ts +186 -102
  207. package/src/device/DeviceCommands.ts +51 -21
  208. package/src/device/DeviceFeaturesState.ts +4 -4
  209. package/src/device/DevicePool.ts +17 -3
  210. package/src/device/DeviceStateMapper.ts +13 -29
  211. package/src/device/DeviceStateProjector.ts +11 -8
  212. package/src/device/DeviceStateStore.ts +11 -52
  213. package/src/device/DeviceWalletSessionStore.ts +31 -4
  214. package/src/device/cloneDeviceState.ts +39 -0
  215. package/src/device/deviceIdentity.ts +2 -2
  216. package/src/deviceProfile/buildDeviceFeatures.ts +29 -88
  217. package/src/events/logBlockEvent.ts +8 -1
  218. package/src/inject.ts +14 -24
  219. package/src/protocols/protocol-v2/deviceSession.ts +24 -0
  220. package/src/protocols/protocol-v2/features.ts +37 -49
  221. package/src/protocols/protocol-v2/firmware.ts +1 -1
  222. package/src/protocols/protocol-v2/index.ts +2 -3
  223. package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +61 -0
  224. package/src/protocols/protocol-v2/uiInteraction.ts +4 -3
  225. package/src/protocols/protocol-v2/walletSession.ts +57 -146
  226. package/src/types/api/checkAllFirmwareRelease.ts +1 -2
  227. package/src/types/api/deviceSettings.ts +1 -0
  228. package/src/types/api/deviceUnlock.ts +1 -1
  229. package/src/types/api/firmwareUpdate.ts +5 -5
  230. package/src/types/api/getDeviceState.ts +1 -1
  231. package/src/types/api/getFeatures.ts +3 -0
  232. package/src/types/api/getOnekeyFeatures.ts +3 -0
  233. package/src/types/api/getPassphraseState.ts +6 -0
  234. package/src/types/api/index.ts +16 -23
  235. package/src/types/api/openWalletSession.ts +64 -0
  236. package/src/types/api/protocolV2.ts +36 -18
  237. package/src/types/device.ts +20 -14
  238. package/src/types/params.ts +1 -1
  239. package/src/types/settings.ts +8 -8
  240. package/src/utils/assets.ts +4 -1
  241. package/src/utils/deviceFeaturesCompat.ts +173 -0
  242. package/src/utils/deviceFeaturesUtils.ts +9 -8
  243. package/src/utils/deviceInfoUtils.ts +26 -64
  244. package/src/utils/deviceSettings.ts +18 -11
  245. package/src/utils/deviceVersionUtils.ts +25 -44
  246. package/src/utils/findDefectiveBatchDevice.ts +3 -3
  247. package/src/utils/index.ts +2 -5
  248. package/src/utils/networkUtils.ts +270 -14
  249. package/src/utils/pro2Wallpaper.ts +11 -13
  250. package/src/utils/tracing.ts +2 -2
  251. package/dist/api/internal.d.ts +0 -4
  252. package/dist/api/internal.d.ts.map +0 -1
  253. package/dist/api/protocol-v2/DeviceSessionOpen.d.ts +0 -28
  254. package/dist/api/protocol-v2/DeviceSessionOpen.d.ts.map +0 -1
  255. package/src/api/internal.ts +0 -9
  256. package/src/api/protocol-v2/DeviceSessionOpen.ts +0 -100
@@ -16,10 +16,11 @@ import {
16
16
  LoggerNames,
17
17
  getDeviceBLEFirmwareVersion,
18
18
  getDeviceBleName,
19
+ getDeviceBootloaderVersion,
19
20
  getDeviceFirmwareVersion,
20
21
  getDeviceLabel,
22
+ getDeviceSerialNo,
21
23
  getDeviceType,
22
- getDeviceUUID,
23
24
  getFirmwareType,
24
25
  getLogger,
25
26
  } from '../utils';
@@ -42,6 +43,7 @@ import {
42
43
  } from './DeviceStateMapper';
43
44
  import { projectFeatures } from './DeviceStateProjector';
44
45
  import { DeviceStateStore, createPublicDeviceState } from './DeviceStateStore';
46
+ import { cloneDeviceState } from './cloneDeviceState';
45
47
  import { deviceWalletSessionStore } from './DeviceWalletSessionStore';
46
48
  import {
47
49
  type DeviceFirmwareRange,
@@ -68,6 +70,8 @@ import {
68
70
  PROTOCOL_V2_FEATURES_DEVICE_INFO_REQUEST,
69
71
  PROTOCOL_V2_FULL_DEVICE_INFO_REQUEST,
70
72
  PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
73
+ type ProtocolV2RuntimeMode,
74
+ getProtocolV2RuntimeMode,
71
75
  requestProtocolV2DeviceInfo,
72
76
  requestProtocolV2DeviceStatus,
73
77
  } from '../protocols/protocol-v2/features';
@@ -97,7 +101,7 @@ export type InitOptions = {
97
101
  deriveCardano?: boolean;
98
102
  connectProtocol?: HardwareConnectProtocol;
99
103
  protocolV2DeviceInfoTimeoutMs?: number;
100
- /** 设备发现内部使用:返回列表前刷新 Protocol V2 运行时状态。 */
104
+ /** Refresh Protocol V2 runtime state before returning discovery results. */
101
105
  refreshRuntimeState?: boolean;
102
106
  };
103
107
 
@@ -206,10 +210,10 @@ export class Device extends EventEmitter {
206
210
  */
207
211
  private deviceAcquired = false;
208
212
 
209
- /** 唯一设备状态缓存。旧 Features 仅通过 getter/setter 做兼容投影。 */
213
+ /** Canonical device-state cache; legacy Features is a compatibility projection. */
210
214
  private stateStore = new DeviceStateStore();
211
215
 
212
- /** 物理重连或重启后,下一次初始化必须重新读取 DeviceInfo */
216
+ /** Force the next initialization to reload DeviceInfo after reconnect or reboot. */
213
217
  private protocolV2StateNeedsReload = false;
214
218
 
215
219
  get state() {
@@ -217,13 +221,38 @@ export class Device extends EventEmitter {
217
221
  }
218
222
 
219
223
  get features(): Features | undefined {
220
- return this.state ? projectFeatures(this.state) : undefined;
224
+ if (!this.state) return undefined;
225
+ const features = projectFeatures(this.state);
226
+ const sessionCacheDeviceKey =
227
+ this.state.identity.deviceId ||
228
+ (this.isProtocolV2()
229
+ ? this.originalDescriptor.path || this.originalDescriptor.id
230
+ : undefined);
231
+ const sessionId =
232
+ sessionCacheDeviceKey && this.passphraseState
233
+ ? deviceWalletSessionStore.get(sessionCacheDeviceKey, this.passphraseState)
234
+ : undefined;
235
+ return sessionId
236
+ ? {
237
+ ...features,
238
+ sessionId,
239
+ session_id: sessionId,
240
+ passphraseState: this.passphraseState,
241
+ }
242
+ : features;
221
243
  }
222
244
 
223
245
  set features(features: Features | undefined) {
224
246
  this.stateStore = new DeviceStateStore();
225
247
  if (features) {
226
248
  this.stateStore.update(mapFeaturesToState(features), 'compatibility');
249
+ const { passphraseState } = features;
250
+ const sessionId = features.sessionId ?? features.session_id;
251
+ const deviceKey = this.getSessionCacheDeviceKey(features.deviceId ?? undefined);
252
+ if (passphraseState && sessionId && deviceKey) {
253
+ this.passphraseState = passphraseState;
254
+ deviceWalletSessionStore.set(deviceKey, passphraseState, sessionId);
255
+ }
227
256
  }
228
257
  }
229
258
 
@@ -294,9 +323,11 @@ export class Device extends EventEmitter {
294
323
  const state = this.state ? createPublicDeviceState(this.state) : undefined;
295
324
 
296
325
  return {
297
- /** Android uses Mac address, iOS uses uuid, USB uses uuid */
326
+ /** Android uses a MAC address, while iOS and USB use transport-specific identifiers. */
298
327
  connectId: DataManager.isBleConnect(env) ? this.mainId || null : connectId,
299
- /** Hardware ID, will not change at any time */
328
+ /** Stable physical-device identity. */
329
+ serialNo,
330
+ /** @deprecated Use serialNo instead. */
300
331
  uuid: serialNo,
301
332
  commType: this.originalDescriptor.commType,
302
333
  sdkInstanceId: this.sdkInstanceId,
@@ -308,12 +339,10 @@ export class Device extends EventEmitter {
308
339
  path: this.originalDescriptor?.path,
309
340
  bleName,
310
341
  name: bleName || label || `OneKey ${deviceType?.toUpperCase()}`,
311
- displayName: label || bleName || `OneKey ${deviceType?.toUpperCase()}`,
312
342
  label: label || 'OneKey',
313
343
  mode: this.getMode(),
314
344
  features,
315
345
  state,
316
- sessionId: this.features?.sessionId ?? null,
317
346
  firmwareVersion: this.getFirmwareVersion(),
318
347
  bleFirmwareVersion: this.getBLEFirmwareVersion(),
319
348
  unavailableCapabilities: this.unavailableCapabilities,
@@ -365,11 +394,10 @@ export class Device extends EventEmitter {
365
394
  try {
366
395
  let acquireResult: unknown;
367
396
  if (DataManager.isBleConnect(env)) {
368
- // forceCleanRunPromise=true(自 e21b83c6 引入,修复 Pro2 BLE 重连):
369
- // acquire 意味着开启一个全新会话,transport 里残留的上一次 runPromise
370
- // 必然属于已死亡的会话(如固件升级重启、探测中断),不清理会让新会话的
371
- // 调用被旧 promise 卡死。无法在 Device 层面区分“重连恢复”与普通 acquire,
372
- // 因此对 BLE acquire 恒清理是有意为之。
397
+ // acquire starts a new BLE session. Any previous runPromise belongs to a dead
398
+ // session, such as an interrupted probe or firmware-update reboot, and would
399
+ // otherwise block the new session. Device cannot distinguish recovery from a
400
+ // regular acquire, so BLE always clears it intentionally.
373
401
  acquireResult = await this.deviceConnector?.acquire(
374
402
  this.originalDescriptor.id,
375
403
  undefined,
@@ -510,12 +538,11 @@ export class Device extends EventEmitter {
510
538
  }
511
539
 
512
540
  /**
513
- * 唯一协议判别器。
541
+ * Canonical protocol discriminator.
514
542
  *
515
- * descriptor.protocolType 是协议探测后的结果;V2 features DeviceInfoGet
516
- * 映射产生。
517
- * SDK 的协议分支都必须走这里,不要直接读 originalDescriptor.protocolType
518
- * 或从 features 反推。
543
+ * descriptor.protocolType is established by active probing; V2 features are mapped
544
+ * from DeviceInfoGet. All protocol branches must use this method instead of reading
545
+ * originalDescriptor.protocolType directly or inferring a protocol from features.
519
546
  */
520
547
  getProtocol(): 'V1' | 'V2' {
521
548
  return this.originalDescriptor.protocolType === 'V2' ? 'V2' : 'V1';
@@ -534,15 +561,15 @@ export class Device extends EventEmitter {
534
561
  }
535
562
 
536
563
  getCurrentSerialNo() {
537
- return this.features ? getDeviceUUID(this.features) : '';
564
+ return getDeviceSerialNo(this.features);
538
565
  }
539
566
 
540
567
  getConnectId() {
541
568
  const serialNo = this.getCurrentSerialNo();
542
569
  if (serialNo) return serialNo;
543
570
 
544
- // connectId SDK 内部连接路由 key。这里兜底到 transport descriptor
545
- // 不改变 features.serialNo / deviceId 的业务语义。
571
+ // connectId is an internal routing key. Falling back to the transport descriptor
572
+ // does not change the business meaning of features.serialNo or deviceId.
546
573
  return this.originalDescriptor.path || this.originalDescriptor.id || '';
547
574
  }
548
575
 
@@ -571,6 +598,11 @@ export class Device extends EventEmitter {
571
598
  return getDeviceBLEFirmwareVersion(this.features).join('.');
572
599
  }
573
600
 
601
+ getCurrentBootloaderVersionString() {
602
+ if (!this.features) return undefined;
603
+ return getDeviceBootloaderVersion(this.features).join('.');
604
+ }
605
+
574
606
  getCurrentSafetyChecks() {
575
607
  return this.features?.safetyChecks;
576
608
  }
@@ -636,9 +668,8 @@ export class Device extends EventEmitter {
636
668
  }
637
669
 
638
670
  supportModifyHomescreen(): SupportFeatureType {
639
- // Pro2 走独立 1.x 版本线,不能套用 Touch/Pro 3.4.0 门槛(恒 false 且未来会误判)。
640
- // 依据:firmware-pro2 协议 schema(messages-protocol-v2.json)的 ApplySettings
641
- // 包含 homescreen 字段,V2 固件从首个版本即支持修改主屏。
671
+ // Pro2 has an independent 1.x version line and must not use the Touch/Pro 3.4.0
672
+ // threshold. ApplySettings includes homescreen from the first V2 firmware version.
642
673
  if (this.isProtocolV2()) {
643
674
  return { support: true };
644
675
  }
@@ -665,12 +696,22 @@ export class Device extends EventEmitter {
665
696
  return undefined;
666
697
  }
667
698
 
699
+ private reconcileSessionCacheDeviceIdentity(previousDeviceId?: string) {
700
+ deviceWalletSessionStore.reconcileDeviceIdentity({
701
+ temporaryKey: this.isProtocolV2()
702
+ ? this.originalDescriptor.path || this.originalDescriptor.id
703
+ : undefined,
704
+ previousDeviceId,
705
+ nextDeviceId: this.getCurrentDeviceId(),
706
+ });
707
+ }
708
+
668
709
  getInternalState(_deviceId?: string) {
669
710
  Log.debug(
670
711
  'getInternalState session param: ',
671
712
  `device_id: ${_deviceId}`,
672
713
  `features.deviceId: ${this.features?.deviceId}`,
673
- `passphraseState: ${this.passphraseState}`
714
+ `hasPassphraseState: ${Boolean(this.passphraseState)}`
674
715
  );
675
716
 
676
717
  const deviceId = this.getSessionCacheDeviceKey(_deviceId);
@@ -698,7 +739,7 @@ export class Device extends EventEmitter {
698
739
  'updateInternalState session param: ',
699
740
  `device_id: ${deviceId}`,
700
741
  `enablePassphrase: ${enablePassphrase}`,
701
- `passphraseState: ${passphraseState}`,
742
+ `hasPassphraseState: ${Boolean(passphraseState)}`,
702
743
  `hasSessionId: ${Boolean(sessionId)}`,
703
744
  `hasFeaturesSessionId: ${Boolean(featuresSessionId)}`
704
745
  );
@@ -721,7 +762,7 @@ export class Device extends EventEmitter {
721
762
  `hasState: ${Boolean(state)}`,
722
763
  `initSession: ${initSession}`,
723
764
  `deviceId: ${this.features?.deviceId}`,
724
- `passphraseState: ${this.passphraseState}`
765
+ `hasPassphraseState: ${Boolean(this.passphraseState)}`
725
766
  );
726
767
 
727
768
  if (!this.passphraseState && !initSession) return;
@@ -749,15 +790,15 @@ export class Device extends EventEmitter {
749
790
  }
750
791
 
751
792
  async initialize(options?: InitOptions) {
752
- // Protocol V2 不支持传统 Initialize,直接使用协议专用初始化流程。
793
+ // Protocol V2 does not support legacy Initialize; use its dedicated flow.
753
794
  if (this.isProtocolV2()) {
754
795
  this.passphraseState = options?.passphraseState;
755
796
  if (this.state && !options?.initSession && !this.protocolV2StateNeedsReload) {
756
797
  if (this.features?.bootloaderMode) {
757
798
  return;
758
799
  }
759
- // 普通业务调用复用缓存。动态状态由显式 getDeviceState refresh、
760
- // 解锁流程和设备事件刷新,避免每个 SDK 方法都额外轮询 DeviceStatus。
800
+ // Normal calls reuse the cache. Explicit getDeviceState refreshes, unlock flow,
801
+ // and device events update dynamic state without polling on every SDK call.
761
802
  return;
762
803
  }
763
804
  await this._initializeProtocolV2(options);
@@ -811,23 +852,25 @@ export class Device extends EventEmitter {
811
852
  /**
812
853
  * Device initialization over Protocol V2.
813
854
  *
814
- * Protocol V2 不走传统 Initialize/GetFeatures;直接用 DeviceInfoGet
815
- * 生成唯一的 features 状态。
855
+ * Protocol V2 bypasses legacy Initialize/GetFeatures and builds its canonical
856
+ * features state directly from DeviceInfoGet.
816
857
  */
817
858
  private async _initializeProtocolV2(options?: InitOptions) {
818
859
  Log.debug('Initialize device via Protocol V2 features adapter');
819
860
 
820
861
  try {
821
- // 超时由 requestProtocolV2DeviceInfo 内部的 typedCall timeoutMs(默认 10s)负责,
822
- // 不再额外包一层 Promise.race:外层 race timer 不会清理,
823
- // 且 reject 后底层调用仍会残留。
862
+ // typedCall applies the request timeout. An outer Promise.race would leak its
863
+ // timer and leave the underlying call active after rejection.
824
864
  const deviceInfo = await requestProtocolV2DeviceInfo({
825
865
  commands: this.commands,
826
866
  timeoutMs: options?.protocolV2DeviceInfoTimeoutMs,
827
867
  });
828
- // 默认请求不含 SE/hash 数据,scope 如实标注为 basic
829
- // 完整版本与校验数据由公共 getDeviceState({ scope: 'firmware' }) 显式获取。
830
- const features = this.updateProtocolV2Features(deviceInfo, null);
868
+ // The default request excludes SE/hash data and therefore uses basic scope.
869
+ // Full version and verification data require getDeviceState({ scope: 'firmware' }).
870
+ const features = await this.probeProtocolV2RuntimeState(
871
+ deviceInfo,
872
+ options?.protocolV2DeviceInfoTimeoutMs
873
+ );
831
874
  Log.debug('Protocol V2 features:', features);
832
875
  } catch (error) {
833
876
  Log.error('Protocol V2 initialization failed:', error);
@@ -840,7 +883,7 @@ export class Device extends EventEmitter {
840
883
  const deviceInfo = await requestProtocolV2DeviceInfo({
841
884
  commands: this.commands,
842
885
  });
843
- return this.updateProtocolV2Features(deviceInfo, null);
886
+ return this.probeProtocolV2RuntimeState(deviceInfo);
844
887
  }
845
888
 
846
889
  const { message } = await this.commands.typedCall('GetFeatures', 'Features', {});
@@ -856,6 +899,7 @@ export class Device extends EventEmitter {
856
899
  return PROTOCOL_V2_FEATURES_DEVICE_INFO_REQUEST;
857
900
  };
858
901
  let initializedWithDeviceInfo = false;
902
+ let refreshedDeviceInfo: ProtocolV2DeviceInfo | undefined;
859
903
 
860
904
  if (!this.state) {
861
905
  if (this.isProtocolV2()) {
@@ -863,7 +907,8 @@ export class Device extends EventEmitter {
863
907
  commands: this.commands,
864
908
  request: getProtocolV2DeviceInfoRequest(),
865
909
  });
866
- this.updateState(mapProtocolV2DeviceInfoToState(deviceInfo), 'device-info');
910
+ await this.probeProtocolV2RuntimeState(deviceInfo);
911
+ refreshedDeviceInfo = deviceInfo;
867
912
  initializedWithDeviceInfo = true;
868
913
  } else {
869
914
  await this.getFeatures();
@@ -885,15 +930,23 @@ export class Device extends EventEmitter {
885
930
  commands: this.commands,
886
931
  request: getProtocolV2DeviceInfoRequest(),
887
932
  });
888
- this.updateState(
889
- mapProtocolV2DeviceInfoToState(deviceInfo, this.state?.status.mode),
890
- 'device-info'
891
- );
933
+ refreshedDeviceInfo = deviceInfo;
934
+ if (!refresh.has('status')) {
935
+ this.updateState(
936
+ mapProtocolV2DeviceInfoToState(deviceInfo, this.state?.status.mode),
937
+ 'device-info'
938
+ );
939
+ }
892
940
  }
893
941
 
894
- if (refresh.has('status') && this.state?.status.mode === 'normal') {
895
- const status = await requestProtocolV2DeviceStatus({ commands: this.commands });
896
- this.updateState(mapProtocolV2DeviceStatusToState(status), 'device-status');
942
+ if (refresh.has('status') && !initializedWithDeviceInfo) {
943
+ const deviceInfo =
944
+ refreshedDeviceInfo ??
945
+ (await requestProtocolV2DeviceInfo({
946
+ commands: this.commands,
947
+ request: getProtocolV2DeviceInfoRequest(),
948
+ }));
949
+ await this.probeProtocolV2RuntimeState(deviceInfo);
897
950
  }
898
951
 
899
952
  if (refresh.has('settings') && this.state?.status.mode === 'normal') {
@@ -909,11 +962,11 @@ export class Device extends EventEmitter {
909
962
  if (!this.state) {
910
963
  throw ERRORS.TypedError(HardwareErrorCode.DeviceInitializeFailed);
911
964
  }
912
- return params.includeRaw ? structuredClone(this.state) : createPublicDeviceState(this.state);
965
+ return params.includeRaw ? cloneDeviceState(this.state) : createPublicDeviceState(this.state);
913
966
  }
914
967
 
915
968
  _updateFeatures(protoFeatures: PROTO.Features | Features, initSession?: boolean) {
916
- const previousCacheDeviceKey = this.getSessionCacheDeviceKey();
969
+ const previousDeviceId = this.getCurrentDeviceId();
917
970
  let feat =
918
971
  'protocol' in protoFeatures
919
972
  ? protoFeatures
@@ -928,10 +981,7 @@ export class Device extends EventEmitter {
928
981
  feat = fixFeaturesFirmwareVersion(feat);
929
982
 
930
983
  this.updateState(mapFeaturesToState(feat), 'initialize');
931
- const nextCacheDeviceKey = this.getSessionCacheDeviceKey();
932
- if (previousCacheDeviceKey && nextCacheDeviceKey) {
933
- deviceWalletSessionStore.migrateDeviceKey(previousCacheDeviceKey, nextCacheDeviceKey);
934
- }
984
+ this.reconcileSessionCacheDeviceIdentity(previousDeviceId);
935
985
  if (feat.deviceId && feat.sessionId) {
936
986
  this.setInternalState(feat.sessionId, initSession);
937
987
  }
@@ -959,14 +1009,6 @@ export class Device extends EventEmitter {
959
1009
  return result.state;
960
1010
  }
961
1011
 
962
- clearCachedSession(deviceId?: string, passphraseState?: string) {
963
- const current = this.state;
964
- if (!current?.session) return false;
965
- if (deviceId && current.identity.deviceId !== deviceId) return false;
966
- if (passphraseState && current.session.passphraseState !== passphraseState) return false;
967
- return this.stateStore.clearSession('session-clear') !== undefined;
968
- }
969
-
970
1012
  updateFeaturesPatch(patch: Partial<Features>, source: DeviceStateUpdateSource) {
971
1013
  const currentFeatures = this.features;
972
1014
  if (!currentFeatures) return undefined;
@@ -979,21 +1021,45 @@ export class Device extends EventEmitter {
979
1021
  return this.features;
980
1022
  }
981
1023
 
982
- updateProtocolV2Features(deviceInfo?: ProtocolV2DeviceInfo, deviceStatus?: DeviceStatus | null) {
983
- const previousCacheDeviceKey = this.getSessionCacheDeviceKey();
984
- if (deviceStatus) {
985
- this.updateState(mapProtocolV2DeviceStatusToState(deviceStatus), 'device-status');
1024
+ async probeProtocolV2RuntimeState(deviceInfo: ProtocolV2DeviceInfo, timeoutMs?: number) {
1025
+ let deviceStatus: DeviceStatus;
1026
+ try {
1027
+ deviceStatus = await requestProtocolV2DeviceStatus({
1028
+ commands: this.commands,
1029
+ timeoutMs,
1030
+ });
1031
+ } catch (error) {
1032
+ const runtimeMode = getProtocolV2RuntimeMode({
1033
+ deviceInfo,
1034
+ deviceStatusAvailable: false,
1035
+ });
1036
+ Log.debug('Protocol V2 DeviceStatusGet unavailable; use temporary loader fallback', {
1037
+ runtimeMode,
1038
+ error: error instanceof Error ? error.message : String(error),
1039
+ });
1040
+ return this.updateProtocolV2Features(deviceInfo, null, runtimeMode);
986
1041
  }
1042
+ return this.updateProtocolV2Features(deviceInfo, deviceStatus, 'normal');
1043
+ }
1044
+
1045
+ updateProtocolV2Features(
1046
+ deviceInfo?: ProtocolV2DeviceInfo,
1047
+ deviceStatus?: DeviceStatus | null,
1048
+ runtimeMode?: ProtocolV2RuntimeMode
1049
+ ) {
1050
+ const previousDeviceId = this.getCurrentDeviceId();
1051
+ const resolvedMode =
1052
+ runtimeMode ??
1053
+ (deviceStatus
1054
+ ? getProtocolV2RuntimeMode({ deviceInfo, deviceStatusAvailable: true })
1055
+ : this.state?.status.mode);
987
1056
  if (deviceInfo) {
988
- this.updateState(
989
- mapProtocolV2DeviceInfoToState(deviceInfo, this.state?.status.mode),
990
- 'device-info'
991
- );
1057
+ this.updateState(mapProtocolV2DeviceInfoToState(deviceInfo, resolvedMode), 'device-info');
992
1058
  }
993
- const nextCacheDeviceKey = this.getSessionCacheDeviceKey();
994
- if (previousCacheDeviceKey && nextCacheDeviceKey) {
995
- deviceWalletSessionStore.migrateDeviceKey(previousCacheDeviceKey, nextCacheDeviceKey);
1059
+ if (deviceStatus) {
1060
+ this.updateState(mapProtocolV2DeviceStatusToState(deviceStatus), 'device-status');
996
1061
  }
1062
+ this.reconcileSessionCacheDeviceIdentity(previousDeviceId);
997
1063
  return this.features as Features;
998
1064
  }
999
1065
 
@@ -1010,7 +1076,6 @@ export class Device extends EventEmitter {
1010
1076
  if (!this.isProtocolV2()) return;
1011
1077
  this.protocolV2StateNeedsReload = true;
1012
1078
  this.clearPreInitialized();
1013
- this.clearCachedSession();
1014
1079
  }
1015
1080
 
1016
1081
  markProtocolV2Reboot(rebootType: DeviceRebootType) {
@@ -1042,7 +1107,6 @@ export class Device extends EventEmitter {
1042
1107
  attachToPinEnabled: null,
1043
1108
  unlockedAttachPin: null,
1044
1109
  },
1045
- session: null,
1046
1110
  raw: { protocolV2DeviceStatus: null },
1047
1111
  },
1048
1112
  'transport-reconnect'
@@ -1053,7 +1117,6 @@ export class Device extends EventEmitter {
1053
1117
  this.updateState(
1054
1118
  {
1055
1119
  status: { mode: 'normal', unlocked: null },
1056
- session: null,
1057
1120
  raw: { protocolV2DeviceStatus: null },
1058
1121
  },
1059
1122
  'transport-reconnect'
@@ -1078,8 +1141,7 @@ export class Device extends EventEmitter {
1078
1141
  }
1079
1142
 
1080
1143
  if (forceUpdate) {
1081
- // 枚举得到的 descriptor 可能不带 protocolType(如 WebUSB enumerate),
1082
- // 不能让覆盖丢掉已探测的协议结果。
1144
+ // Enumerated descriptors may omit protocolType, so preserve an actively probed value.
1083
1145
  this.originalDescriptor = {
1084
1146
  ...descriptor,
1085
1147
  protocolType: descriptor.protocolType ?? this.originalDescriptor.protocolType,
@@ -1104,19 +1166,37 @@ export class Device extends EventEmitter {
1104
1166
 
1105
1167
  options = parseRunOptions(options);
1106
1168
 
1107
- this.runPromise = createDeferred(this._runInner.bind(this, fn, options));
1108
- return this.runPromise.promise;
1169
+ const runPromise = createDeferred<void>();
1170
+ this.runPromise = runPromise;
1171
+ this._runInner(fn, options, runPromise).catch(error => {
1172
+ if (this.runPromise === runPromise) {
1173
+ this.runPromise = null;
1174
+ }
1175
+ runPromise.reject(error);
1176
+ });
1177
+ return runPromise.promise;
1109
1178
  }
1110
1179
 
1111
- async _runInner<T>(fn: (() => Promise<T>) | undefined, options: RunOptions) {
1180
+ async _runInner<T>(
1181
+ fn: (() => Promise<T>) | undefined,
1182
+ options: RunOptions,
1183
+ runPromise: Deferred<void>
1184
+ ) {
1185
+ const clearRunPromise = () => {
1186
+ if (this.runPromise === runPromise) {
1187
+ this.runPromise = null;
1188
+ }
1189
+ };
1190
+
1112
1191
  if (!this.isUsedHere() || this.commands.disposed) {
1113
1192
  const env = DataManager.getSettings('env');
1114
1193
  if (env !== 'react-native') {
1115
1194
  try {
1116
1195
  await this.acquire(options.connectProtocol);
1117
1196
  } catch (error) {
1118
- this.runPromise = null;
1119
- return Promise.reject(error);
1197
+ clearRunPromise();
1198
+ runPromise.reject(error);
1199
+ return;
1120
1200
  }
1121
1201
 
1122
1202
  try {
@@ -1127,16 +1207,18 @@ export class Device extends EventEmitter {
1127
1207
  }
1128
1208
  } catch (error) {
1129
1209
  await this.release();
1130
- this.runPromise = null;
1210
+ clearRunPromise();
1131
1211
  if (error instanceof HardwareError) {
1132
- return Promise.reject(error);
1212
+ runPromise.reject(error);
1213
+ return;
1133
1214
  }
1134
- return Promise.reject(
1215
+ runPromise.reject(
1135
1216
  ERRORS.TypedError(
1136
1217
  HardwareErrorCode.DeviceInitializeFailed,
1137
1218
  `Initialize failed: ${error.message as string}, code: ${error.code as string}`
1138
1219
  )
1139
1220
  );
1221
+ return;
1140
1222
  }
1141
1223
  } else if (env === 'react-native') {
1142
1224
  // TODO: implement react-native acquire
@@ -1155,9 +1237,7 @@ export class Device extends EventEmitter {
1155
1237
  try {
1156
1238
  await fn();
1157
1239
  } catch (e) {
1158
- if (this.runPromise) {
1159
- this.runPromise.reject(e);
1160
- }
1240
+ runPromise.reject(e);
1161
1241
 
1162
1242
  if (
1163
1243
  e instanceof HardwareError &&
@@ -1170,7 +1250,7 @@ export class Device extends EventEmitter {
1170
1250
  Log.debug(`error code ${e.errorCode} release device, mainId: ${this.mainId}`);
1171
1251
  }
1172
1252
 
1173
- this.runPromise = null;
1253
+ clearRunPromise();
1174
1254
  return;
1175
1255
  }
1176
1256
  }
@@ -1184,11 +1264,8 @@ export class Device extends EventEmitter {
1184
1264
  Log.debug('release device, mainId: ', this.mainId);
1185
1265
  }
1186
1266
 
1187
- if (this.runPromise) {
1188
- this.runPromise.resolve();
1189
- }
1190
-
1191
- this.runPromise = null;
1267
+ runPromise.resolve();
1268
+ clearRunPromise();
1192
1269
  }
1193
1270
 
1194
1271
  async interruptionFromOutside() {
@@ -1343,7 +1420,7 @@ export class Device extends EventEmitter {
1343
1420
  }
1344
1421
 
1345
1422
  supportUnlockVersionRange(): DeviceFirmwareRange {
1346
- // 仅适用于 Protocol V1 Pro 系列;Pro2 走独立的 Protocol V2 解锁流程。
1423
+ // This range applies to Protocol V1 Pro devices; Pro2 has a dedicated unlock flow.
1347
1424
  return {
1348
1425
  pro: {
1349
1426
  min: '4.15.0',
@@ -1368,7 +1445,8 @@ export class Device extends EventEmitter {
1368
1445
  throw error;
1369
1446
  }
1370
1447
 
1371
- return this.updateFeaturesPatch({ unlocked: true }, 'unlock');
1448
+ const status = await requestProtocolV2DeviceStatus({ commands: this.commands });
1449
+ return this.updateProtocolV2Status(status);
1372
1450
  }
1373
1451
 
1374
1452
  const firmwareVersion = this.getCurrentFirmwareVersionString() ?? '0.0.0';
@@ -1433,21 +1511,27 @@ export class Device extends EventEmitter {
1433
1511
  ) {
1434
1512
  if (this.isUnacquired()) return false;
1435
1513
 
1514
+ const expectedPassphraseState = useEmptyPassphrase ? undefined : passphraseState;
1436
1515
  const { passphraseState: newPassphraseState, unlockedAttachPin } =
1437
1516
  await getPassphraseStateWithRefreshDeviceInfo(this, {
1438
- expectPassphraseState: passphraseState,
1517
+ expectPassphraseState: expectedPassphraseState,
1439
1518
  onlyMainPin: useEmptyPassphrase,
1440
1519
  });
1441
1520
 
1442
1521
  // Main wallet and unlock Attach Pin, throw safe error
1443
1522
  const mainWalletUseAttachPin = unlockedAttachPin && useEmptyPassphrase;
1444
1523
  const useErrorAttachPin =
1445
- unlockedAttachPin && passphraseState && passphraseState !== newPassphraseState;
1446
- const passphraseStateMismatch = !!passphraseState && passphraseState !== newPassphraseState;
1524
+ unlockedAttachPin &&
1525
+ expectedPassphraseState &&
1526
+ expectedPassphraseState !== newPassphraseState;
1527
+ const passphraseStateMismatch =
1528
+ !!expectedPassphraseState && expectedPassphraseState !== newPassphraseState;
1447
1529
 
1448
1530
  Log.debug('Check passphrase state safety: ', {
1449
- passphraseState,
1450
- newPassphraseState,
1531
+ hasExpectedPassphraseState: Boolean(expectedPassphraseState),
1532
+ hasNewPassphraseState: Boolean(newPassphraseState),
1533
+ passphraseStateMatches:
1534
+ Boolean(expectedPassphraseState) && expectedPassphraseState === newPassphraseState,
1451
1535
  unlockedAttachPin,
1452
1536
  useEmptyPassphrase,
1453
1537
  });