@onekeyfe/hd-core 1.2.0-alpha.65 → 1.2.0-alpha.66

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 (314) hide show
  1. package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +313 -0
  2. package/__tests__/DeviceCommands.test.ts +59 -13
  3. package/__tests__/DeviceEventRegistration.test.ts +6 -0
  4. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +198 -3
  5. package/__tests__/connectSettings.test.ts +5 -47
  6. package/__tests__/core-initialization.test.ts +23 -0
  7. package/__tests__/device-connector-protocol.test.ts +81 -0
  8. package/__tests__/device-lifecycle-events.test.ts +105 -3
  9. package/__tests__/device-pool-state.test.ts +22 -0
  10. package/__tests__/device-settings.test.ts +39 -18
  11. package/__tests__/device-state-contract.test.ts +1 -0
  12. package/__tests__/device-state-mapper.test.ts +13 -1
  13. package/__tests__/device-utils.test.ts +48 -1
  14. package/__tests__/deviceSettings.test.ts +11 -1
  15. package/__tests__/deviceUploadNft.test.ts +316 -0
  16. package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +31 -59
  17. package/__tests__/get-device-state.test.ts +132 -12
  18. package/__tests__/homescreen.test.ts +41 -1
  19. package/__tests__/kaspa-use-tweak-pro2.test.ts +2 -2
  20. package/__tests__/kaspaSignTransaction.test.ts +3 -26
  21. package/__tests__/logBlockEvent.test.ts +1 -1
  22. package/__tests__/method-protocol-support.test.ts +19 -0
  23. package/__tests__/open-wallet-session.test.ts +568 -37
  24. package/__tests__/pro2Nft.test.ts +108 -0
  25. package/__tests__/protocol-binding.test.ts +89 -0
  26. package/__tests__/protocol-v2-resources.test.ts +340 -0
  27. package/__tests__/protocol-v2-ui-lifecycle.test.ts +91 -0
  28. package/__tests__/protocol-v2-unlock-policy.test.ts +300 -37
  29. package/__tests__/protocol-v2.test.ts +1506 -1097
  30. package/__tests__/protocolV2FileWrite.test.ts +152 -0
  31. package/__tests__/protocolV2UiInteraction.test.ts +63 -0
  32. package/__tests__/public-pro2-api-boundary.test.ts +1 -0
  33. package/__tests__/search-devices.test.ts +12 -3
  34. package/__tests__/tron-sign-message-init.test.ts +2 -2
  35. package/__tests__/uiProgressThrottle.test.ts +74 -0
  36. package/__tests__/uiPromiseRegistry.test.ts +115 -0
  37. package/dist/api/BaseMethod.d.ts +3 -1
  38. package/dist/api/BaseMethod.d.ts.map +1 -1
  39. package/dist/api/CheckAllFirmwareRelease.d.ts +2 -1
  40. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  41. package/dist/api/DetectDeviceConnectProtocol.d.ts +7 -0
  42. package/dist/api/DetectDeviceConnectProtocol.d.ts.map +1 -0
  43. package/dist/api/FirmwareUpdate.d.ts.map +1 -1
  44. package/dist/api/FirmwareUpdateV2.d.ts +0 -11
  45. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  46. package/dist/api/FirmwareUpdateV3.d.ts +3 -7
  47. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  48. package/dist/api/FirmwareUpdateV4.d.ts +13 -27
  49. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  50. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  51. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  52. package/dist/api/SearchDevices.d.ts.map +1 -1
  53. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  54. package/dist/api/device/DeviceSettings.d.ts.map +1 -1
  55. package/dist/api/device/DeviceUnlock.d.ts +2 -2
  56. package/dist/api/device/DeviceUnlock.d.ts.map +1 -1
  57. package/dist/api/device/DeviceUpdateBootloader.d.ts +1 -5
  58. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  59. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +4 -11
  60. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  61. package/dist/api/firmware/getBinary.d.ts +0 -7
  62. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  63. package/dist/api/firmware/updateBootloader.d.ts +0 -2
  64. package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
  65. package/dist/api/firmware/uploadFirmware.d.ts +1 -9
  66. package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
  67. package/dist/api/helpers/protocolV2FileWrite.d.ts +9 -0
  68. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
  69. package/dist/api/index.d.ts +2 -0
  70. package/dist/api/index.d.ts.map +1 -1
  71. package/dist/api/kaspa/KaspaGetAddress.d.ts +1 -1
  72. package/dist/api/kaspa/KaspaSignTransaction.d.ts +1 -1
  73. package/dist/api/kaspa/KaspaSignTransaction.d.ts.map +1 -1
  74. package/dist/api/polkadot/PolkadotGetAddress.d.ts +1 -1
  75. package/dist/api/polkadot/networks.d.ts +1 -1
  76. package/dist/api/protocol-v2/DeviceUploadNft.d.ts +31 -0
  77. package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -0
  78. package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
  79. package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
  80. package/dist/api/solana/SolSignMessage.d.ts +1 -1
  81. package/dist/api/solana/SolSignOffchainMessage.d.ts +1 -1
  82. package/dist/api/solana/SolSignTransaction.d.ts +2 -2
  83. package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
  84. package/dist/api/sui/SuiGetAddress.d.ts +1 -1
  85. package/dist/api/sui/SuiGetPublicKey.d.ts +1 -1
  86. package/dist/api/sui/SuiSignMessage.d.ts +1 -1
  87. package/dist/api/sui/SuiSignTransaction.d.ts +1 -1
  88. package/dist/api/ton/TonGetAddress.d.ts +1 -1
  89. package/dist/api/ton/TonSignMessage.d.ts +1 -1
  90. package/dist/api/ton/TonSignProof.d.ts +1 -1
  91. package/dist/api/tron/TronSignMessage.d.ts +2 -2
  92. package/dist/api/tron/TronSignTransaction.d.ts +1 -1
  93. package/dist/core/deviceEventRegistration.d.ts +2 -0
  94. package/dist/core/deviceEventRegistration.d.ts.map +1 -1
  95. package/dist/core/index.d.ts.map +1 -1
  96. package/dist/core/uiPromiseRegistry.d.ts +6 -0
  97. package/dist/core/uiPromiseRegistry.d.ts.map +1 -0
  98. package/dist/data-manager/DataManager.d.ts +9 -4
  99. package/dist/data-manager/DataManager.d.ts.map +1 -1
  100. package/dist/data-manager/TransportManager.d.ts.map +1 -1
  101. package/dist/data-manager/connectSettings.d.ts.map +1 -1
  102. package/dist/device/Device.d.ts +29 -6
  103. package/dist/device/Device.d.ts.map +1 -1
  104. package/dist/device/DeviceCommands.d.ts +4 -4
  105. package/dist/device/DeviceCommands.d.ts.map +1 -1
  106. package/dist/device/DeviceConnector.d.ts +2 -1
  107. package/dist/device/DeviceConnector.d.ts.map +1 -1
  108. package/dist/device/DevicePool.d.ts.map +1 -1
  109. package/dist/deviceProfile/protocolV2DeviceIdentity.d.ts.map +1 -1
  110. package/dist/events/device.d.ts +4 -0
  111. package/dist/events/device.d.ts.map +1 -1
  112. package/dist/events/logBlockEvent.d.ts.map +1 -1
  113. package/dist/events/ui-promise.d.ts +4 -2
  114. package/dist/events/ui-promise.d.ts.map +1 -1
  115. package/dist/events/ui-request.d.ts +31 -2
  116. package/dist/events/ui-request.d.ts.map +1 -1
  117. package/dist/events/ui-response.d.ts +10 -2
  118. package/dist/events/ui-response.d.ts.map +1 -1
  119. package/dist/index.d.ts +243 -248
  120. package/dist/index.d.ts.map +1 -1
  121. package/dist/index.js +3051 -3774
  122. package/dist/inject.d.ts +6 -1
  123. package/dist/inject.d.ts.map +1 -1
  124. package/dist/lowLevelInject.d.ts.map +1 -1
  125. package/dist/protocols/protocol-v2/features.d.ts +0 -4
  126. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  127. package/dist/protocols/protocol-v2/firmware.d.ts.map +1 -1
  128. package/dist/protocols/protocol-v2/resources.d.ts +30 -0
  129. package/dist/protocols/protocol-v2/resources.d.ts.map +1 -0
  130. package/dist/protocols/protocol-v2/uiInteraction.d.ts +7 -4
  131. package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -1
  132. package/dist/protocols/protocol-v2/unlockPolicy.d.ts +1 -3
  133. package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -1
  134. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +22 -0
  135. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -0
  136. package/dist/protocols/protocol-v2/walletSession.d.ts +6 -1
  137. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  138. package/dist/topLevelInject.d.ts.map +1 -1
  139. package/dist/types/api/checkAllFirmwareRelease.d.ts +3 -5
  140. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  141. package/dist/types/api/detectDeviceConnectProtocol.d.ts +4 -0
  142. package/dist/types/api/detectDeviceConnectProtocol.d.ts.map +1 -0
  143. package/dist/types/api/deviceUnlock.d.ts +5 -1
  144. package/dist/types/api/deviceUnlock.d.ts.map +1 -1
  145. package/dist/types/api/deviceUpdateBootloader.d.ts +0 -6
  146. package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
  147. package/dist/types/api/export.d.ts +2 -4
  148. package/dist/types/api/export.d.ts.map +1 -1
  149. package/dist/types/api/firmwareUpdate.d.ts +4 -71
  150. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  151. package/dist/types/api/index.d.ts +7 -10
  152. package/dist/types/api/index.d.ts.map +1 -1
  153. package/dist/types/api/protocolV2.d.ts +3 -0
  154. package/dist/types/api/protocolV2.d.ts.map +1 -1
  155. package/dist/types/device.d.ts +2 -2
  156. package/dist/types/device.d.ts.map +1 -1
  157. package/dist/types/params.d.ts +1 -0
  158. package/dist/types/params.d.ts.map +1 -1
  159. package/dist/types/settings.d.ts +38 -21
  160. package/dist/types/settings.d.ts.map +1 -1
  161. package/dist/utils/deviceFeaturesCompat.d.ts +0 -1
  162. package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
  163. package/dist/utils/deviceFeaturesUtils.d.ts +4 -0
  164. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  165. package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
  166. package/dist/utils/deviceSettings.d.ts.map +1 -1
  167. package/dist/utils/homescreen.d.ts +4 -0
  168. package/dist/utils/homescreen.d.ts.map +1 -1
  169. package/dist/utils/index.d.ts +1 -1
  170. package/dist/utils/index.d.ts.map +1 -1
  171. package/dist/utils/patch.d.ts +1 -1
  172. package/dist/utils/patch.d.ts.map +1 -1
  173. package/dist/utils/pro2Nft.d.ts +31 -0
  174. package/dist/utils/pro2Nft.d.ts.map +1 -0
  175. package/dist/utils/pro2Wallpaper.d.ts +10 -0
  176. package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
  177. package/dist/utils/uiProgressThrottle.d.ts +3 -0
  178. package/dist/utils/uiProgressThrottle.d.ts.map +1 -0
  179. package/package.json +4 -4
  180. package/src/api/BaseMethod.ts +8 -10
  181. package/src/api/CheckAllFirmwareRelease.ts +59 -60
  182. package/src/api/DetectDeviceConnectProtocol.ts +18 -0
  183. package/src/api/FirmwareUpdate.ts +7 -15
  184. package/src/api/FirmwareUpdateV2.ts +126 -316
  185. package/src/api/FirmwareUpdateV3.ts +63 -265
  186. package/src/api/FirmwareUpdateV4.ts +597 -1005
  187. package/src/api/GetPassphraseState.ts +7 -1
  188. package/src/api/OpenWalletSession.ts +71 -17
  189. package/src/api/SearchDevices.ts +3 -1
  190. package/src/api/allnetwork/AllNetworkGetAddress.ts +21 -21
  191. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +36 -11
  192. package/src/api/device/DeviceSettings.ts +5 -4
  193. package/src/api/device/DeviceUnlock.ts +8 -3
  194. package/src/api/device/DeviceUpdateBootloader.ts +6 -125
  195. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +27 -83
  196. package/src/api/firmware/updateBootloader.ts +4 -19
  197. package/src/api/firmware/uploadFirmware.ts +39 -144
  198. package/src/api/helpers/protocolV2FileWrite.ts +202 -63
  199. package/src/api/index.ts +2 -0
  200. package/src/api/kaspa/KaspaGetAddress.ts +1 -1
  201. package/src/api/kaspa/KaspaSignTransaction.ts +2 -13
  202. package/src/api/polkadot/networks.ts +3 -3
  203. package/src/api/protocol-v2/DeviceUploadNft.ts +197 -0
  204. package/src/api/protocol-v2/ProtocolInfoRequest.ts +3 -1
  205. package/src/api/protocol-v2/helpers.ts +1 -1
  206. package/src/api/solana/SolSignMessage.ts +1 -1
  207. package/src/api/solana/SolSignOffchainMessage.ts +1 -1
  208. package/src/api/solana/SolSignTransaction.ts +2 -2
  209. package/src/api/sui/SuiGetAddress.ts +1 -1
  210. package/src/api/sui/SuiGetPublicKey.ts +1 -1
  211. package/src/api/sui/SuiSignMessage.ts +1 -1
  212. package/src/api/sui/SuiSignTransaction.ts +1 -1
  213. package/src/api/ton/TonGetAddress.ts +1 -1
  214. package/src/api/ton/TonSignMessage.ts +1 -1
  215. package/src/api/ton/TonSignProof.ts +1 -1
  216. package/src/api/tron/TronSignMessage.ts +2 -2
  217. package/src/api/tron/TronSignTransaction.ts +1 -1
  218. package/src/core/deviceEventRegistration.ts +4 -0
  219. package/src/core/index.ts +213 -111
  220. package/src/core/uiPromiseRegistry.ts +63 -0
  221. package/src/data/messages/messages-protocol-v2.json +25 -0
  222. package/src/data-manager/DataManager.ts +113 -41
  223. package/src/data-manager/TransportManager.ts +6 -0
  224. package/src/data-manager/connectSettings.ts +0 -11
  225. package/src/device/Device.ts +274 -49
  226. package/src/device/DeviceCommands.ts +31 -4
  227. package/src/device/DeviceConnector.ts +33 -13
  228. package/src/device/DevicePool.ts +21 -7
  229. package/src/deviceProfile/buildDeviceFeatures.ts +2 -2
  230. package/src/deviceProfile/protocolV2DeviceIdentity.ts +3 -0
  231. package/src/events/device.ts +4 -0
  232. package/src/events/logBlockEvent.ts +1 -0
  233. package/src/events/ui-promise.ts +4 -2
  234. package/src/events/ui-request.ts +36 -2
  235. package/src/events/ui-response.ts +12 -2
  236. package/src/index.ts +0 -5
  237. package/src/inject.ts +60 -24
  238. package/src/lowLevelInject.ts +7 -8
  239. package/src/protocols/protocol-v2/features.ts +10 -7
  240. package/src/protocols/protocol-v2/firmware.ts +2 -0
  241. package/src/protocols/protocol-v2/resources.ts +390 -0
  242. package/src/protocols/protocol-v2/uiInteraction.ts +46 -6
  243. package/src/protocols/protocol-v2/unlockPolicy.ts +1 -105
  244. package/src/protocols/protocol-v2/unlockPolicyRunner.ts +131 -0
  245. package/src/protocols/protocol-v2/walletSession.ts +214 -36
  246. package/src/topLevelInject.ts +7 -8
  247. package/src/types/api/checkAllFirmwareRelease.ts +3 -5
  248. package/src/types/api/detectDeviceConnectProtocol.ts +6 -0
  249. package/src/types/api/deviceUnlock.ts +12 -1
  250. package/src/types/api/deviceUpdateBootloader.ts +0 -6
  251. package/src/types/api/export.ts +1 -18
  252. package/src/types/api/firmwareUpdate.ts +6 -79
  253. package/src/types/api/index.ts +13 -14
  254. package/src/types/api/protocolV2.ts +13 -0
  255. package/src/types/device.ts +15 -3
  256. package/src/types/params.ts +7 -1
  257. package/src/types/settings.ts +60 -22
  258. package/src/utils/deviceFeaturesCompat.ts +5 -6
  259. package/src/utils/deviceFeaturesUtils.ts +14 -3
  260. package/src/utils/deviceInfoUtils.ts +2 -0
  261. package/src/utils/deviceSettings.ts +3 -0
  262. package/src/utils/homescreen.ts +32 -6
  263. package/src/utils/index.ts +6 -1
  264. package/src/utils/pro2Nft.ts +142 -0
  265. package/src/utils/pro2Wallpaper.ts +35 -8
  266. package/src/utils/uiProgressThrottle.ts +63 -0
  267. package/__tests__/device-initialize-timeout.test.ts +0 -56
  268. package/__tests__/firmware-update/check-all-firmware-release.test.ts +0 -175
  269. package/__tests__/firmware-update/firmware-artifact-source.test.ts +0 -119
  270. package/__tests__/firmware-update/firmware-host-binding.test.ts +0 -70
  271. package/__tests__/firmware-update/firmware-preparation-error.test.ts +0 -27
  272. package/__tests__/firmware-update/firmware-update-bootloader-poll.test.ts +0 -200
  273. package/__tests__/firmware-update/firmware-update-capabilities.test.ts +0 -13
  274. package/__tests__/firmware-update/firmware-update-plan-bootloader-identity.test.ts +0 -394
  275. package/__tests__/firmware-update/firmware-update-plan.test.ts +0 -593
  276. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +0 -213
  277. package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +0 -58
  278. package/__tests__/firmware-update/firmware-upload-source.test.ts +0 -70
  279. package/dist/api/firmware/FirmwareArtifactSource.d.ts +0 -25
  280. package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +0 -1
  281. package/dist/api/firmware/FirmwareHostBinding.d.ts +0 -6
  282. package/dist/api/firmware/FirmwareHostBinding.d.ts.map +0 -1
  283. package/dist/api/firmware/FirmwarePreparationError.d.ts +0 -3
  284. package/dist/api/firmware/FirmwarePreparationError.d.ts.map +0 -1
  285. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +0 -3
  286. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +0 -1
  287. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -25
  288. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +0 -1
  289. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +0 -32
  290. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +0 -1
  291. package/dist/api/firmware/progressThrottle.d.ts +0 -3
  292. package/dist/api/firmware/progressThrottle.d.ts.map +0 -1
  293. package/dist/protocols/protocol-v2/lockedError.d.ts +0 -2
  294. package/dist/protocols/protocol-v2/lockedError.d.ts.map +0 -1
  295. package/dist/protocols/protocol-v2/unlockRetry.d.ts +0 -10
  296. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +0 -1
  297. package/dist/types/api/firmwareUpdateCapabilities.d.ts +0 -9
  298. package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +0 -1
  299. package/dist/types/api/firmwareUpdatePlan.d.ts +0 -28
  300. package/dist/types/api/firmwareUpdatePlan.d.ts.map +0 -1
  301. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +0 -42
  302. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +0 -1
  303. package/src/api/firmware/FirmwareArtifactSource.ts +0 -278
  304. package/src/api/firmware/FirmwareHostBinding.ts +0 -100
  305. package/src/api/firmware/FirmwarePreparationError.ts +0 -12
  306. package/src/api/firmware/FirmwareUpdateCapabilities.ts +0 -9
  307. package/src/api/firmware/FirmwareUpdatePlan.ts +0 -772
  308. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +0 -449
  309. package/src/api/firmware/progressThrottle.ts +0 -44
  310. package/src/protocols/protocol-v2/lockedError.ts +0 -10
  311. package/src/protocols/protocol-v2/unlockRetry.ts +0 -109
  312. package/src/types/api/firmwareUpdateCapabilities.ts +0 -9
  313. package/src/types/api/firmwareUpdatePlan.ts +0 -38
  314. package/src/types/api/firmwareUpdatePreparedPlan.ts +0 -53
@@ -74,7 +74,9 @@ import type { DeviceStateReadOptions } from '../types/api/getDeviceState';
74
74
  import type {
75
75
  DeviceButtonRequestPayload,
76
76
  DeviceFeaturesPayload,
77
+ HardwareUiInteractionMeta,
77
78
  PassphraseRequestPayload,
79
+ ProtocolV2UiEventMetadata,
78
80
  } from '../events';
79
81
  import type { PassphrasePromptResponse } from './DeviceCommands';
80
82
  import type { Deferred, HardwareConnectProtocol } from '@onekeyfe/hd-shared';
@@ -93,14 +95,10 @@ export type InitOptions = {
93
95
  passphraseState?: string;
94
96
  deriveCardano?: boolean;
95
97
  connectProtocol?: HardwareConnectProtocol;
98
+ forceProtocolDetection?: boolean;
96
99
  protocolV2DeviceInfoTimeoutMs?: number;
97
100
  /** Refresh Protocol V2 runtime state before returning discovery results. */
98
101
  refreshRuntimeState?: boolean;
99
- /**
100
- * Protocol V1 Initialize response timeout override. Reboot-wait polling passes a
101
- * short value so an unanswered probe settles before the next poll tick.
102
- */
103
- timeoutMs?: number;
104
102
  };
105
103
 
106
104
  export type RunOptions = {
@@ -137,6 +135,8 @@ const isProtocolV2DeviceStatusUnsupportedError = (error: unknown) => {
137
135
 
138
136
  export interface DeviceEvents {
139
137
  [DEVICE.PIN]: [Device, PROTO.PinMatrixRequestType | undefined, (err: any, pin: string) => void];
138
+ [DEVICE.PIN_ON_DEVICE]: [Device, DeviceSessionPinType, ProtocolV2UiEventMetadata?];
139
+ [DEVICE.PIN_ON_DEVICE_COMPLETE]: [Device, HardwareUiInteractionMeta];
140
140
  [DEVICE.PASSPHRASE_ON_DEVICE]: [Device, PassphraseRequestPayload?];
141
141
  [DEVICE.ATTACH_PIN_ON_DEVICE]: [Device, PassphraseRequestPayload?];
142
142
  [DEVICE.BUTTON]: [Device, DeviceButtonRequestPayload];
@@ -235,6 +235,24 @@ export class Device extends EventEmitter {
235
235
  /** Force the next initialization to reload DeviceInfo after reconnect or reboot. */
236
236
  private protocolV2StateNeedsReload = false;
237
237
 
238
+ /** Runtime context negotiated once per active Protocol V2 link. */
239
+ private protocolV2RuntimeContext?: ProtocolInfo;
240
+
241
+ /** Coalesces concurrent first-use runtime negotiation on the same active link. */
242
+ private protocolV2RuntimeContextPromise?: Promise<ProtocolInfo>;
243
+
244
+ /** Invalidates an in-flight runtime-context response without adding a transport epoch. */
245
+ private protocolV2RuntimeContextRequestToken?: object;
246
+
247
+ private protocolV2UiInteraction?: {
248
+ interactionId: string;
249
+ phaseCounter: number;
250
+ sequence: number;
251
+ opened: boolean;
252
+ };
253
+
254
+ private protocolV2UiInteractionCounter = 0;
255
+
238
256
  get state() {
239
257
  return this.stateStore.getState();
240
258
  }
@@ -342,7 +360,7 @@ export class Device extends EventEmitter {
342
360
  deviceId,
343
361
  path: this.originalDescriptor?.path,
344
362
  bleName,
345
- name: displayName || bleName || `OneKey ${deviceType?.toUpperCase()}`,
363
+ name: bleName || displayName || `OneKey ${deviceType?.toUpperCase()}`,
346
364
  // Keep the legacy top-level field string-compatible while preserving
347
365
  // the canonical nullable value at state.identity.label.
348
366
  label: displayName ?? '',
@@ -360,7 +378,10 @@ export class Device extends EventEmitter {
360
378
  * Device connect
361
379
  * @returns {Promise<boolean>}
362
380
  */
363
- connect(connectProtocol?: HardwareConnectProtocol) {
381
+ connect(
382
+ connectProtocol?: HardwareConnectProtocol,
383
+ options?: { forceProtocolDetection?: boolean }
384
+ ) {
364
385
  const env = DataManager.getSettings('env');
365
386
  // eslint-disable-next-line no-async-promise-executor
366
387
  return new Promise<boolean>(async (resolve, reject) => {
@@ -370,7 +391,7 @@ export class Device extends EventEmitter {
370
391
  return;
371
392
  }
372
393
  try {
373
- await this.acquire(connectProtocol);
394
+ await this.acquire(connectProtocol, options);
374
395
  resolve(true);
375
396
  } catch (error) {
376
397
  reject(error);
@@ -380,7 +401,7 @@ export class Device extends EventEmitter {
380
401
  // 不存在 Session ID 或存在 Session ID 但设备在别处使用,都需要 acquire 获取最新 sessionID
381
402
  if (!this.mainId || (!this.isUsedHere() && this.originalDescriptor)) {
382
403
  try {
383
- await this.acquire(connectProtocol);
404
+ await this.acquire(connectProtocol, options);
384
405
  resolve(true);
385
406
  } catch (error) {
386
407
  reject(error);
@@ -397,11 +418,16 @@ export class Device extends EventEmitter {
397
418
 
398
419
  async acquire(
399
420
  expectedProtocol?: HardwareConnectProtocol,
400
- options?: { throwOnRunPromiseError?: boolean }
421
+ options?: { throwOnRunPromiseError?: boolean; forceProtocolDetection?: boolean }
401
422
  ) {
402
423
  const env = DataManager.getSettings('env');
403
424
  const mainIdKey = DataManager.isBleConnect(env) ? 'id' : 'session';
404
- const protocolHint = expectedProtocol ? undefined : this.originalDescriptor.protocolType;
425
+ const previousProtocol = this.originalDescriptor.protocolType;
426
+ // A protocol stored after a successful probe is authoritative. Only the explicit
427
+ // first-connection/recovery path may bypass it and probe both protocols again.
428
+ const strictProtocol = options?.forceProtocolDetection
429
+ ? undefined
430
+ : expectedProtocol ?? this.originalDescriptor.protocolType;
405
431
  try {
406
432
  let acquireResult: unknown;
407
433
  if (DataManager.isBleConnect(env)) {
@@ -413,8 +439,8 @@ export class Device extends EventEmitter {
413
439
  this.originalDescriptor.id,
414
440
  undefined,
415
441
  true,
416
- expectedProtocol,
417
- protocolHint
442
+ strictProtocol,
443
+ undefined
418
444
  );
419
445
  this.mainId = (acquireResult as any)?.uuid ?? '';
420
446
  Log.debug('Expected uuid:', this.mainId);
@@ -423,24 +449,31 @@ export class Device extends EventEmitter {
423
449
  this.originalDescriptor.path,
424
450
  this.originalDescriptor.session,
425
451
  undefined,
426
- expectedProtocol,
427
- protocolHint
452
+ strictProtocol,
453
+ undefined
428
454
  );
429
455
  this.mainId = acquireResult as string | undefined;
430
456
  Log.debug('Expected session id:', this.mainId);
431
457
  }
432
- this.deviceAcquired = true;
433
- this.updateDescriptor({ [mainIdKey]: this.mainId } as unknown as DeviceDescriptor);
434
-
435
458
  // Propagate protocol version detected during acquire.
436
459
  const detectedProtocol =
437
460
  (acquireResult as { protocolType?: HardwareConnectProtocol } | undefined)?.protocolType ??
438
461
  TransportManager.transport?.getProtocolType?.(
439
462
  DataManager.isBleConnect(env) ? this.originalDescriptor.id : this.originalDescriptor.path
440
463
  );
464
+ if (options?.forceProtocolDetection && !detectedProtocol) {
465
+ throw ERRORS.TypedError(
466
+ HardwareErrorCode.RuntimeError,
467
+ `Active protocol detection returned no protocol for ${
468
+ this.originalDescriptor.path || this.originalDescriptor.id
469
+ }`
470
+ );
471
+ }
441
472
  if (detectedProtocol) {
442
473
  this.originalDescriptor.protocolType = detectedProtocol;
443
474
  }
475
+ this.deviceAcquired = true;
476
+ this.updateDescriptor({ [mainIdKey]: this.mainId } as unknown as DeviceDescriptor);
444
477
 
445
478
  if (this.commands) {
446
479
  await this.commands.dispose(false);
@@ -448,6 +481,22 @@ export class Device extends EventEmitter {
448
481
 
449
482
  this.commands = new DeviceCommands(this, this.mainId ?? '');
450
483
  } catch (error) {
484
+ if (options?.forceProtocolDetection) {
485
+ this.originalDescriptor.protocolType = previousProtocol;
486
+ const failedSession = this.mainId;
487
+ this.deviceAcquired = false;
488
+ if (failedSession) {
489
+ try {
490
+ await this.deviceConnector?.release?.(failedSession, false);
491
+ } catch (releaseError) {
492
+ Log.debug('Failed to release an unsuccessful protocol probe', releaseError);
493
+ }
494
+ }
495
+ if (!DataManager.isBleConnect(env)) {
496
+ this.mainId = null;
497
+ this.updateDescriptor({ session: null } as DeviceDescriptor);
498
+ }
499
+ }
451
500
  if (options?.throwOnRunPromiseError) {
452
501
  throw error;
453
502
  }
@@ -647,6 +696,7 @@ export class Device extends EventEmitter {
647
696
  // Most-specific model first; must match getMethodVersionRange in deviceInfoUtils,
648
697
  // otherwise e.g. Classic1s resolves the looser model_mini range before model_classic1s.
649
698
  const modelFallbacks: IDeviceModel[] = [
699
+ 'model_pro2',
650
700
  'model_classic1s',
651
701
  'model_classic',
652
702
  'model_mini',
@@ -666,7 +716,8 @@ export class Device extends EventEmitter {
666
716
  if (
667
717
  deviceType === EDeviceType.Touch ||
668
718
  deviceType === EDeviceType.Pro ||
669
- deviceType === EDeviceType.Pro2
719
+ deviceType === EDeviceType.Pro2 ||
720
+ deviceType === EDeviceType.Neo
670
721
  ) {
671
722
  return { support: true };
672
723
  }
@@ -683,7 +734,8 @@ export class Device extends EventEmitter {
683
734
  if (
684
735
  deviceType === EDeviceType.Touch ||
685
736
  deviceType === EDeviceType.Pro ||
686
- deviceType === EDeviceType.Pro2
737
+ deviceType === EDeviceType.Pro2 ||
738
+ deviceType === EDeviceType.Neo
687
739
  ) {
688
740
  return { support: false };
689
741
  }
@@ -856,7 +908,7 @@ export class Device extends EventEmitter {
856
908
  const initStartAt = Date.now();
857
909
  const { message } = await this.commands.typedCall('Initialize', 'Features', payload, {
858
910
  // iOS BLE bound devices can need close to 20 seconds.
859
- timeoutMs: options?.timeoutMs ?? 25 * 1000,
911
+ timeoutMs: 25 * 1000,
860
912
  });
861
913
  this.setLastInitializeDuration(Date.now() - initStartAt);
862
914
  this._updateFeatures(message, initSession);
@@ -969,7 +1021,10 @@ export class Device extends EventEmitter {
969
1021
  await this.getFeatures();
970
1022
  }
971
1023
 
972
- if (!this.isProtocolV2() && refresh.has('verification')) {
1024
+ const supportsProtocolV1OnekeyFeatures =
1025
+ this.getCurrentDeviceType() === EDeviceType.Touch ||
1026
+ this.getCurrentDeviceType() === EDeviceType.Pro;
1027
+ if (!this.isProtocolV2() && refresh.has('verification') && supportsProtocolV1OnekeyFeatures) {
973
1028
  const { message } = await this.commands.typedCall('OnekeyGetFeatures', 'OnekeyFeatures');
974
1029
  this.updateState(mapProtocolV1OnekeyFeaturesToState(message), 'device-info');
975
1030
  }
@@ -992,13 +1047,7 @@ export class Device extends EventEmitter {
992
1047
  }
993
1048
 
994
1049
  if (refresh.has('status') && !initializedWithDeviceInfo) {
995
- const deviceInfo =
996
- refreshedDeviceInfo ??
997
- (await requestProtocolV2DeviceInfo({
998
- commands: this.commands,
999
- request: getProtocolV2DeviceInfoRequest(),
1000
- }));
1001
- await this.probeProtocolV2RuntimeState(deviceInfo);
1050
+ await this.probeProtocolV2RuntimeState(refreshedDeviceInfo);
1002
1051
  }
1003
1052
 
1004
1053
  if (refresh.has('settings') && this.state?.status.mode === 'normal') {
@@ -1069,19 +1118,66 @@ export class Device extends EventEmitter {
1069
1118
  return this.features;
1070
1119
  }
1071
1120
 
1072
- async probeProtocolV2RuntimeState(deviceInfo: ProtocolV2DeviceInfo, timeoutMs?: number) {
1073
- const protocolInfo = await requestProtocolV2ProtocolInfo({
1074
- commands: this.commands,
1075
- timeoutMs,
1076
- });
1121
+ async ensureProtocolV2RuntimeContext(timeoutMs?: number): Promise<ProtocolInfo> {
1122
+ const cachedProtocolInfo =
1123
+ this.protocolV2RuntimeContext ??
1124
+ (!this.protocolV2StateNeedsReload
1125
+ ? this.state?.raw?.protocolV2ProtocolInfo ?? undefined
1126
+ : undefined);
1127
+ if (cachedProtocolInfo) {
1128
+ this.protocolV2RuntimeContext = cachedProtocolInfo;
1129
+ return cachedProtocolInfo;
1130
+ }
1131
+
1132
+ if (this.protocolV2RuntimeContextPromise) {
1133
+ return this.protocolV2RuntimeContextPromise;
1134
+ }
1135
+
1136
+ const requestToken = {};
1137
+ const pendingRequest = (async () => {
1138
+ const protocolInfo = await requestProtocolV2ProtocolInfo({
1139
+ commands: this.commands,
1140
+ timeoutMs,
1141
+ });
1142
+ if (this.protocolV2RuntimeContextRequestToken !== requestToken) {
1143
+ throw ERRORS.TypedError(
1144
+ HardwareErrorCode.DeviceInitializeFailed,
1145
+ 'Protocol V2 runtime context was invalidated while loading.'
1146
+ );
1147
+ }
1148
+ this.protocolV2RuntimeContext = protocolInfo;
1149
+ return protocolInfo;
1150
+ })();
1151
+ this.protocolV2RuntimeContextRequestToken = requestToken;
1152
+ this.protocolV2RuntimeContextPromise = pendingRequest;
1153
+
1154
+ try {
1155
+ return await pendingRequest;
1156
+ } finally {
1157
+ if (this.protocolV2RuntimeContextPromise === pendingRequest) {
1158
+ this.protocolV2RuntimeContextPromise = undefined;
1159
+ }
1160
+ if (this.protocolV2RuntimeContextRequestToken === requestToken) {
1161
+ this.protocolV2RuntimeContextRequestToken = undefined;
1162
+ }
1163
+ }
1164
+ }
1165
+
1166
+ async probeProtocolV2RuntimeState(deviceInfo?: ProtocolV2DeviceInfo, timeoutMs?: number) {
1167
+ const protocolInfo = await this.ensureProtocolV2RuntimeContext(timeoutMs);
1077
1168
  const runtimeMode = getProtocolV2RuntimeMode(protocolInfo);
1078
- const protocolV2DeviceType = resolveProtocolV2DeviceIdentity(
1079
- deviceInfo.hw?.Device_type
1080
- ).deviceType;
1081
- if (runtimeMode === 'romloader' && protocolV2DeviceType !== EDeviceType.Pro2) {
1169
+ const runtimeDeviceInfo = deviceInfo ?? this.state?.raw?.protocolV2DeviceInfo;
1170
+ const protocolV2DeviceType = runtimeDeviceInfo
1171
+ ? resolveProtocolV2DeviceIdentity(runtimeDeviceInfo.hw?.Device_type).deviceType
1172
+ : this.getCurrentDeviceType();
1173
+ if (
1174
+ runtimeMode === 'romloader' &&
1175
+ protocolV2DeviceType !== EDeviceType.Pro2 &&
1176
+ protocolV2DeviceType !== EDeviceType.Neo
1177
+ ) {
1082
1178
  throw ERRORS.TypedError(
1083
1179
  HardwareErrorCode.DeviceInitializeFailed,
1084
- 'Protocol V2 romloader mode is only supported for Pro2.'
1180
+ 'Protocol V2 romloader mode is only supported for Pro2 and Neo.'
1085
1181
  );
1086
1182
  }
1087
1183
  const deviceStatusSupported = supportsProtocolV2Message(
@@ -1152,6 +1248,9 @@ export class Device extends EventEmitter {
1152
1248
  this.deviceAcquired = false;
1153
1249
  if (!this.isProtocolV2()) return;
1154
1250
  this.protocolV2StateNeedsReload = true;
1251
+ this.protocolV2RuntimeContext = undefined;
1252
+ this.protocolV2RuntimeContextPromise = undefined;
1253
+ this.protocolV2RuntimeContextRequestToken = undefined;
1155
1254
  this.clearPreInitialized();
1156
1255
  }
1157
1256
 
@@ -1160,9 +1259,14 @@ export class Device extends EventEmitter {
1160
1259
  if (deviceId) {
1161
1260
  deviceWalletSessionStore.deleteDevice(deviceId);
1162
1261
  }
1163
- if (this.isProtocolV2() && this.originalDescriptor.path !== deviceId) {
1164
- deviceWalletSessionStore.deleteDevice(this.originalDescriptor.path);
1262
+ if (this.isProtocolV2()) {
1263
+ if (this.originalDescriptor.path !== deviceId) {
1264
+ deviceWalletSessionStore.deleteDevice(this.originalDescriptor.path);
1265
+ }
1165
1266
  this.protocolV2StateNeedsReload = true;
1267
+ this.protocolV2RuntimeContext = undefined;
1268
+ this.protocolV2RuntimeContextPromise = undefined;
1269
+ this.protocolV2RuntimeContextRequestToken = undefined;
1166
1270
  }
1167
1271
 
1168
1272
  this.passphraseState = undefined;
@@ -1175,6 +1279,9 @@ export class Device extends EventEmitter {
1175
1279
  if (!this.isProtocolV2()) return;
1176
1280
 
1177
1281
  this.protocolV2StateNeedsReload = true;
1282
+ this.protocolV2RuntimeContext = undefined;
1283
+ this.protocolV2RuntimeContextPromise = undefined;
1284
+ this.protocolV2RuntimeContextRequestToken = undefined;
1178
1285
  this.clearPreInitialized();
1179
1286
  let loaderMode: 'bootloader' | 'romloader' | undefined;
1180
1287
  if (rebootType === DeviceRebootType.Bootloader) {
@@ -1281,11 +1388,17 @@ export class Device extends EventEmitter {
1281
1388
  }
1282
1389
  };
1283
1390
 
1284
- if (!this.isUsedHere() || this.commands.disposed) {
1285
- const env = DataManager.getSettings('env');
1391
+ const env = DataManager.getSettings('env');
1392
+ if (options.forceProtocolDetection && env !== 'react-native' && this.isUsedHere()) {
1393
+ await this.release();
1394
+ }
1395
+
1396
+ if (options.forceProtocolDetection || !this.isUsedHere() || this.commands.disposed) {
1286
1397
  if (env !== 'react-native') {
1287
1398
  try {
1288
- await this.acquire(options.connectProtocol);
1399
+ await this.acquire(options.connectProtocol, {
1400
+ forceProtocolDetection: options.forceProtocolDetection,
1401
+ });
1289
1402
  } catch (error) {
1290
1403
  clearRunPromise();
1291
1404
  runPromise.reject(error);
@@ -1463,7 +1576,8 @@ export class Device extends EventEmitter {
1463
1576
  if (!this.state) return undefined;
1464
1577
  return (
1465
1578
  this.isProtocolV2() &&
1466
- this.getCurrentDeviceType() === EDeviceType.Pro2 &&
1579
+ (this.getCurrentDeviceType() === EDeviceType.Pro2 ||
1580
+ this.getCurrentDeviceType() === EDeviceType.Neo) &&
1467
1581
  this.state.status.mode === 'romloader'
1468
1582
  );
1469
1583
  }
@@ -1509,7 +1623,8 @@ export class Device extends EventEmitter {
1509
1623
  const isModeT =
1510
1624
  deviceType === EDeviceType.Touch ||
1511
1625
  deviceType === EDeviceType.Pro ||
1512
- deviceType === EDeviceType.Pro2;
1626
+ deviceType === EDeviceType.Pro2 ||
1627
+ deviceType === EDeviceType.Neo;
1513
1628
  const unlocked = this.state?.status.unlocked;
1514
1629
  const preCheckTouch = isModeT && unlocked === false;
1515
1630
  const passphraseProtection = this.getCurrentPassphraseProtection();
@@ -1527,6 +1642,85 @@ export class Device extends EventEmitter {
1527
1642
  return res.message;
1528
1643
  }
1529
1644
 
1645
+ beginProtocolV2UiInteraction() {
1646
+ if (!this.isProtocolV2()) return;
1647
+ this.protocolV2UiInteraction = {
1648
+ interactionId: `${this.instanceId}:${Date.now()}:${++this.protocolV2UiInteractionCounter}`,
1649
+ phaseCounter: 0,
1650
+ sequence: 0,
1651
+ opened: false,
1652
+ };
1653
+ }
1654
+
1655
+ createProtocolV2UiPhaseMetadata(
1656
+ phase: HardwareUiInteractionMeta['phase'],
1657
+ transition: HardwareUiInteractionMeta['transition'],
1658
+ options?: {
1659
+ phaseId?: string;
1660
+ outcome?: HardwareUiInteractionMeta['outcome'];
1661
+ }
1662
+ ): HardwareUiInteractionMeta | undefined {
1663
+ if (!this.isProtocolV2()) return undefined;
1664
+ if (!this.protocolV2UiInteraction) this.beginProtocolV2UiInteraction();
1665
+
1666
+ const interaction = this.protocolV2UiInteraction;
1667
+ if (!interaction) return undefined;
1668
+ const phaseId =
1669
+ options?.phaseId ?? `${interaction.interactionId}:phase-${++interaction.phaseCounter}`;
1670
+ interaction.opened = true;
1671
+ interaction.sequence += 1;
1672
+
1673
+ return {
1674
+ interactionId: interaction.interactionId,
1675
+ phaseId,
1676
+ sequence: interaction.sequence,
1677
+ phase,
1678
+ transition,
1679
+ ...(options?.outcome ? { outcome: options.outcome } : {}),
1680
+ protocol: 'V2',
1681
+ };
1682
+ }
1683
+
1684
+ completeProtocolV2UiPhase(
1685
+ phase: HardwareUiInteractionMeta,
1686
+ outcome: HardwareUiInteractionMeta['outcome'] = 'succeeded'
1687
+ ) {
1688
+ return this.createProtocolV2UiPhaseMetadata(phase.phase, 'complete', {
1689
+ phaseId: phase.phaseId,
1690
+ outcome,
1691
+ });
1692
+ }
1693
+
1694
+ finishProtocolV2UiInteraction(
1695
+ outcome?: HardwareUiInteractionMeta['outcome'],
1696
+ options?: { ensureMetadata?: boolean }
1697
+ ) {
1698
+ const interaction = this.protocolV2UiInteraction;
1699
+ if (!interaction || (!interaction.opened && !options?.ensureMetadata)) {
1700
+ this.protocolV2UiInteraction = undefined;
1701
+ return undefined;
1702
+ }
1703
+
1704
+ const phaseId = `${interaction.interactionId}:phase-${Math.max(interaction.phaseCounter, 1)}`;
1705
+ interaction.opened = true;
1706
+ interaction.sequence += 1;
1707
+ const metadata: HardwareUiInteractionMeta = {
1708
+ interactionId: interaction.interactionId,
1709
+ phaseId,
1710
+ sequence: interaction.sequence,
1711
+ phase: 'processing',
1712
+ transition: 'finish',
1713
+ outcome: outcome ?? 'succeeded',
1714
+ protocol: 'V2',
1715
+ };
1716
+ this.protocolV2UiInteraction = undefined;
1717
+ return metadata;
1718
+ }
1719
+
1720
+ hasOpenProtocolV2UiInteraction() {
1721
+ return this.protocolV2UiInteraction?.opened === true;
1722
+ }
1723
+
1530
1724
  supportUnlockVersionRange(): DeviceFirmwareRange {
1531
1725
  // This range applies to Protocol V1 Pro devices; Pro2 has a dedicated unlock flow.
1532
1726
  return {
@@ -1536,10 +1730,33 @@ export class Device extends EventEmitter {
1536
1730
  };
1537
1731
  }
1538
1732
 
1539
- async unlockDevice(pinType: DeviceSessionPinType = DeviceSessionPinType.Main) {
1733
+ async unlockDevice(
1734
+ pinType?: DeviceSessionPinType,
1735
+ options?: ProtocolV2UiEventMetadata & { emitUiEvent?: boolean }
1736
+ ) {
1540
1737
  if (this.isProtocolV2()) {
1738
+ const requestedPinType = pinType ?? DeviceSessionPinType.Main;
1739
+ const interaction =
1740
+ options?.interaction ??
1741
+ (options?.emitUiEvent === false
1742
+ ? undefined
1743
+ : this.createProtocolV2UiPhaseMetadata('pin', 'start'));
1744
+ if (options?.emitUiEvent !== false) {
1745
+ this.emit(DEVICE.PIN_ON_DEVICE, this, requestedPinType, {
1746
+ source: options?.source ?? 'unlock-coordinator',
1747
+ reason: options?.reason ?? 'device-unlock',
1748
+ deviceOnly: options?.deviceOnly ?? true,
1749
+ completion: options?.completion,
1750
+ method: options?.method,
1751
+ page: options?.page,
1752
+ operation: options?.operation,
1753
+ interaction: options?.interaction ?? interaction,
1754
+ });
1755
+ }
1541
1756
  try {
1542
- await this.commands.typedCall('DeviceSessionAskPin', 'Success', { type: pinType });
1757
+ await this.commands.typedCall('DeviceSessionAskPin', 'Success', {
1758
+ type: requestedPinType,
1759
+ });
1543
1760
  } catch (error) {
1544
1761
  const errorText =
1545
1762
  error instanceof Error
@@ -1551,6 +1768,11 @@ export class Device extends EventEmitter {
1551
1768
  throw error;
1552
1769
  }
1553
1770
 
1771
+ const completion = interaction ? this.completeProtocolV2UiPhase(interaction) : undefined;
1772
+ if (completion) {
1773
+ this.emit(DEVICE.PIN_ON_DEVICE_COMPLETE, this, completion);
1774
+ }
1775
+
1554
1776
  const status = await requestProtocolV2DeviceStatus({ commands: this.commands });
1555
1777
  return this.updateProtocolV2Status(status);
1556
1778
  }
@@ -1612,7 +1834,8 @@ export class Device extends EventEmitter {
1612
1834
  async checkPassphraseStateSafety(
1613
1835
  passphraseState?: string,
1614
1836
  useEmptyPassphrase?: boolean,
1615
- skipPassphraseCheck?: boolean
1837
+ skipPassphraseCheck?: boolean,
1838
+ deriveCardano?: boolean
1616
1839
  ) {
1617
1840
  if (this.isUnacquired()) return false;
1618
1841
 
@@ -1621,6 +1844,8 @@ export class Device extends EventEmitter {
1621
1844
  await getPassphraseStateWithRefreshDeviceInfo(this, {
1622
1845
  expectPassphraseState: expectedPassphraseState,
1623
1846
  onlyMainPin: useEmptyPassphrase,
1847
+ deriveCardano,
1848
+ rejectAttachPinForMainWallet: useEmptyPassphrase === true,
1624
1849
  });
1625
1850
 
1626
1851
  // Main wallet and unlock Attach Pin, throw safe error
@@ -54,9 +54,19 @@ const DEVICE_SESSION_CALLS = new Set([
54
54
  'DeviceSessionAskPin',
55
55
  'DeviceSessionAskPassphrase',
56
56
  ]);
57
+ const DEVICE_CONTROL_CALLS = new Set([
58
+ 'DeviceReboot',
59
+ 'DeviceSettingsGet',
60
+ 'DeviceSettingsSet',
61
+ 'DeviceSettingsPageShow',
62
+ 'DeviceCertificateWrite',
63
+ 'DeviceCertificateRead',
64
+ 'DeviceCertificateSign',
65
+ 'DeviceMiscUsbMscControl',
66
+ ]);
57
67
 
58
- // Protocol V2 subcodes are domain-scoped, so cross-domain cancellation fallback
59
- // must use explicit firmware cancellation messages instead of a global number map.
68
+ // Older Protocol V2 firmware may omit the cancellation subcode, so retain a
69
+ // narrow message fallback for compatibility.
60
70
  const isProtocolV2ActionCancelledMessage = (message: string) =>
61
71
  /^(?:cancel(?:led|ed)(?: on device)?|confirm dismissed|user cancel(?:led|ed)(?:\s+.*)?)$/i.test(
62
72
  message
@@ -435,7 +445,13 @@ export class DeviceCommands {
435
445
  if (!shouldReduceDebugForCall(callType)) {
436
446
  Log.debug('_filterCommonTypes: ', {
437
447
  request: callType,
438
- response: res.type,
448
+ response:
449
+ callType === 'DeviceFirmwareUpdateStatusGet'
450
+ ? {
451
+ type: res.type,
452
+ message: getSafeTransportLogPayload(res.message, res.type),
453
+ }
454
+ : res.type,
439
455
  });
440
456
  }
441
457
  } catch (error) {
@@ -493,6 +509,10 @@ export class DeviceCommands {
493
509
  const normalizedMessage = message?.trim() ?? '';
494
510
  const isProtocolV2ActionCancelledFailure =
495
511
  this.device.isProtocolV2() && isProtocolV2ActionCancelledMessage(normalizedMessage);
512
+ const isProtocolV2DeviceBusyFailure =
513
+ this.device.isProtocolV2() &&
514
+ DEVICE_CONTROL_CALLS.has(callType) &&
515
+ subcode === DeviceErrorCode.DeviceError_Busy;
496
516
  const isLegacyProtocolV2LockedFailure =
497
517
  this.device.isProtocolV2() && /^device (?:is )?locked$/i.test(normalizedMessage);
498
518
  if (
@@ -550,8 +570,15 @@ export class DeviceCommands {
550
570
  subcode,
551
571
  firmwareMessage: message,
552
572
  });
573
+ } else if (isProtocolV2DeviceBusyFailure) {
574
+ error = ERRORS.TypedError(HardwareErrorCode.DeviceBusy, message, {
575
+ failureCode: code,
576
+ subcode,
577
+ firmwareMessage: message,
578
+ });
553
579
  } else if (
554
- subcode === DeviceErrorCode.DeviceError_ActionCancelled ||
580
+ (DEVICE_CONTROL_CALLS.has(callType) &&
581
+ subcode === DeviceErrorCode.DeviceError_ActionCancelled) ||
555
582
  isProtocolV2ActionCancelledFailure
556
583
  ) {
557
584
  error = ERRORS.TypedError(HardwareErrorCode.ActionCancelled, message, {