@onekeyfe/hd-core 1.2.0-alpha.23 → 1.2.0-alpha.25

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 (445) hide show
  1. package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +2 -0
  2. package/__tests__/DeviceCommands.test.ts +35 -0
  3. package/__tests__/chain-params-onekey-compatibility.test.ts +229 -0
  4. package/__tests__/device-lifecycle-events.test.ts +59 -0
  5. package/__tests__/device-state-events.test.ts +124 -0
  6. package/__tests__/evmLedgerLegacySafety.test.ts +3 -1
  7. package/__tests__/firmware-update/check-all-firmware-release.test.ts +68 -27
  8. package/__tests__/firmware-update/firmware-update-plan.test.ts +28 -0
  9. package/__tests__/kaspa-public-types.type-test.ts +16 -0
  10. package/__tests__/kaspaSignTransaction.test.ts +4 -3
  11. package/__tests__/method-protocol-support.test.ts +113 -0
  12. package/__tests__/open-wallet-session.test.ts +192 -129
  13. package/__tests__/protocol-v2-ping.test.ts +28 -0
  14. package/__tests__/protocol-v2.test.ts +346 -230
  15. package/__tests__/public-device-state-api.test.ts +10 -8
  16. package/__tests__/public-pro2-api-boundary.test.ts +22 -0
  17. package/__tests__/tron-sign-message-init.test.ts +46 -0
  18. package/dist/api/BaseMethod.d.ts +6 -2
  19. package/dist/api/BaseMethod.d.ts.map +1 -1
  20. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  21. package/dist/api/CipherKeyValue.d.ts +1 -0
  22. package/dist/api/CipherKeyValue.d.ts.map +1 -1
  23. package/dist/api/DirList.d.ts +1 -0
  24. package/dist/api/DirList.d.ts.map +1 -1
  25. package/dist/api/DirMake.d.ts +1 -0
  26. package/dist/api/DirMake.d.ts.map +1 -1
  27. package/dist/api/DirRemove.d.ts +1 -0
  28. package/dist/api/DirRemove.d.ts.map +1 -1
  29. package/dist/api/FileDelete.d.ts +1 -0
  30. package/dist/api/FileDelete.d.ts.map +1 -1
  31. package/dist/api/FileRead.d.ts +1 -0
  32. package/dist/api/FileRead.d.ts.map +1 -1
  33. package/dist/api/FileWrite.d.ts +1 -0
  34. package/dist/api/FileWrite.d.ts.map +1 -1
  35. package/dist/api/FirmwareUpdate.d.ts.map +1 -1
  36. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  37. package/dist/api/FirmwareUpdateV4.d.ts +2 -0
  38. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  39. package/dist/api/GetDeviceState.d.ts +1 -0
  40. package/dist/api/GetDeviceState.d.ts.map +1 -1
  41. package/dist/api/GetFeatures.d.ts.map +1 -1
  42. package/dist/api/GetOnekeyFeatures.d.ts.map +1 -1
  43. package/dist/api/GetPassphraseState.d.ts +1 -0
  44. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  45. package/dist/api/OpenWalletSession.d.ts +2 -8
  46. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  47. package/dist/api/PathInfo.d.ts +1 -0
  48. package/dist/api/PathInfo.d.ts.map +1 -1
  49. package/dist/api/alephium/AlephiumGetAddress.d.ts.map +1 -1
  50. package/dist/api/alephium/AlephiumSignMessage.d.ts.map +1 -1
  51. package/dist/api/alephium/AlephiumSignTransaction.d.ts.map +1 -1
  52. package/dist/api/algo/AlgoGetAddress.d.ts +1 -0
  53. package/dist/api/algo/AlgoGetAddress.d.ts.map +1 -1
  54. package/dist/api/algo/AlgoSignTransaction.d.ts +1 -0
  55. package/dist/api/algo/AlgoSignTransaction.d.ts.map +1 -1
  56. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts +1 -0
  57. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  58. package/dist/api/aptos/AptosGetAddress.d.ts +1 -0
  59. package/dist/api/aptos/AptosGetAddress.d.ts.map +1 -1
  60. package/dist/api/aptos/AptosGetPublicKey.d.ts +1 -0
  61. package/dist/api/aptos/AptosGetPublicKey.d.ts.map +1 -1
  62. package/dist/api/aptos/AptosSignInMessage.d.ts +1 -0
  63. package/dist/api/aptos/AptosSignInMessage.d.ts.map +1 -1
  64. package/dist/api/aptos/AptosSignMessage.d.ts +1 -0
  65. package/dist/api/aptos/AptosSignMessage.d.ts.map +1 -1
  66. package/dist/api/aptos/AptosSignTransaction.d.ts +1 -0
  67. package/dist/api/aptos/AptosSignTransaction.d.ts.map +1 -1
  68. package/dist/api/benfen/BenfenGetAddress.d.ts.map +1 -1
  69. package/dist/api/benfen/BenfenGetPublicKey.d.ts.map +1 -1
  70. package/dist/api/benfen/BenfenSignMessage.d.ts.map +1 -1
  71. package/dist/api/benfen/BenfenSignTransaction.d.ts.map +1 -1
  72. package/dist/api/btc/BTCGetAddress.d.ts +1 -0
  73. package/dist/api/btc/BTCGetAddress.d.ts.map +1 -1
  74. package/dist/api/btc/BTCGetPublicKey.d.ts +1 -0
  75. package/dist/api/btc/BTCGetPublicKey.d.ts.map +1 -1
  76. package/dist/api/btc/BTCSignMessage.d.ts +1 -0
  77. package/dist/api/btc/BTCSignMessage.d.ts.map +1 -1
  78. package/dist/api/btc/BTCSignPsbt.d.ts +1 -0
  79. package/dist/api/btc/BTCSignPsbt.d.ts.map +1 -1
  80. package/dist/api/btc/BTCSignTransaction.d.ts +1 -0
  81. package/dist/api/btc/BTCSignTransaction.d.ts.map +1 -1
  82. package/dist/api/btc/BTCVerifyMessage.d.ts +1 -0
  83. package/dist/api/btc/BTCVerifyMessage.d.ts.map +1 -1
  84. package/dist/api/btc/helpers/versionLimit.d.ts +2 -0
  85. package/dist/api/btc/helpers/versionLimit.d.ts.map +1 -1
  86. package/dist/api/cardano/CardanoGetAddress.d.ts +1 -0
  87. package/dist/api/cardano/CardanoGetAddress.d.ts.map +1 -1
  88. package/dist/api/cardano/CardanoGetPublicKey.d.ts +1 -0
  89. package/dist/api/cardano/CardanoGetPublicKey.d.ts.map +1 -1
  90. package/dist/api/cardano/CardanoSignMessage.d.ts +1 -0
  91. package/dist/api/cardano/CardanoSignMessage.d.ts.map +1 -1
  92. package/dist/api/cardano/CardanoSignTransaction.d.ts +1 -0
  93. package/dist/api/cardano/CardanoSignTransaction.d.ts.map +1 -1
  94. package/dist/api/conflux/ConfluxGetAddress.d.ts +1 -0
  95. package/dist/api/conflux/ConfluxGetAddress.d.ts.map +1 -1
  96. package/dist/api/conflux/ConfluxSignMessage.d.ts +1 -0
  97. package/dist/api/conflux/ConfluxSignMessage.d.ts.map +1 -1
  98. package/dist/api/conflux/ConfluxSignMessageCIP23.d.ts +1 -0
  99. package/dist/api/conflux/ConfluxSignMessageCIP23.d.ts.map +1 -1
  100. package/dist/api/conflux/ConfluxSignTransaction.d.ts +1 -0
  101. package/dist/api/conflux/ConfluxSignTransaction.d.ts.map +1 -1
  102. package/dist/api/cosmos/CosmosGetAddress.d.ts +1 -0
  103. package/dist/api/cosmos/CosmosGetAddress.d.ts.map +1 -1
  104. package/dist/api/cosmos/CosmosGetPublicKey.d.ts +1 -0
  105. package/dist/api/cosmos/CosmosGetPublicKey.d.ts.map +1 -1
  106. package/dist/api/cosmos/CosmosSignTransaction.d.ts +1 -0
  107. package/dist/api/cosmos/CosmosSignTransaction.d.ts.map +1 -1
  108. package/dist/api/device/DeviceCancel.d.ts +1 -0
  109. package/dist/api/device/DeviceCancel.d.ts.map +1 -1
  110. package/dist/api/device/DeviceChangePin.d.ts +1 -0
  111. package/dist/api/device/DeviceChangePin.d.ts.map +1 -1
  112. package/dist/api/device/DeviceLock.d.ts +1 -0
  113. package/dist/api/device/DeviceLock.d.ts.map +1 -1
  114. package/dist/api/device/DeviceRebootToBoardloader.d.ts +1 -0
  115. package/dist/api/device/DeviceRebootToBoardloader.d.ts.map +1 -1
  116. package/dist/api/device/DeviceRebootToBootloader.d.ts +1 -0
  117. package/dist/api/device/DeviceRebootToBootloader.d.ts.map +1 -1
  118. package/dist/api/device/DeviceSettings.d.ts +1 -0
  119. package/dist/api/device/DeviceSettings.d.ts.map +1 -1
  120. package/dist/api/device/DeviceSupportFeatures.d.ts +1 -0
  121. package/dist/api/device/DeviceSupportFeatures.d.ts.map +1 -1
  122. package/dist/api/device/DeviceUnlock.d.ts +1 -0
  123. package/dist/api/device/DeviceUnlock.d.ts.map +1 -1
  124. package/dist/api/device/DeviceWipe.d.ts +1 -0
  125. package/dist/api/device/DeviceWipe.d.ts.map +1 -1
  126. package/dist/api/device/PreInitialize.d.ts +1 -0
  127. package/dist/api/device/PreInitialize.d.ts.map +1 -1
  128. package/dist/api/dynex/DnxGetAddress.d.ts.map +1 -1
  129. package/dist/api/dynex/DnxSignTransaction.d.ts.map +1 -1
  130. package/dist/api/evm/EVMGetAddress.d.ts +1 -0
  131. package/dist/api/evm/EVMGetAddress.d.ts.map +1 -1
  132. package/dist/api/evm/EVMGetPublicKey.d.ts +1 -0
  133. package/dist/api/evm/EVMGetPublicKey.d.ts.map +1 -1
  134. package/dist/api/evm/EVMSignMessage.d.ts +1 -0
  135. package/dist/api/evm/EVMSignMessage.d.ts.map +1 -1
  136. package/dist/api/evm/EVMSignMessageEIP712.d.ts.map +1 -1
  137. package/dist/api/evm/EVMSignTransaction.d.ts +1 -0
  138. package/dist/api/evm/EVMSignTransaction.d.ts.map +1 -1
  139. package/dist/api/evm/EVMSignTypedData.d.ts +1 -0
  140. package/dist/api/evm/EVMSignTypedData.d.ts.map +1 -1
  141. package/dist/api/evm/EVMVerifyMessage.d.ts +1 -0
  142. package/dist/api/evm/EVMVerifyMessage.d.ts.map +1 -1
  143. package/dist/api/filecoin/FilecoinGetAddress.d.ts +1 -0
  144. package/dist/api/filecoin/FilecoinGetAddress.d.ts.map +1 -1
  145. package/dist/api/filecoin/FilecoinSignTransaction.d.ts +1 -0
  146. package/dist/api/filecoin/FilecoinSignTransaction.d.ts.map +1 -1
  147. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -1
  148. package/dist/api/index.d.ts +1 -0
  149. package/dist/api/index.d.ts.map +1 -1
  150. package/dist/api/kaspa/KaspaGetAddress.d.ts +1 -0
  151. package/dist/api/kaspa/KaspaGetAddress.d.ts.map +1 -1
  152. package/dist/api/kaspa/KaspaSignTransaction.d.ts +1 -0
  153. package/dist/api/kaspa/KaspaSignTransaction.d.ts.map +1 -1
  154. package/dist/api/kaspa/helpers/TransferSerialize.d.ts.map +1 -1
  155. package/dist/api/lightning/LnurlAuth.d.ts +0 -4
  156. package/dist/api/lightning/LnurlAuth.d.ts.map +1 -1
  157. package/dist/api/near/NearGetAddress.d.ts +1 -0
  158. package/dist/api/near/NearGetAddress.d.ts.map +1 -1
  159. package/dist/api/near/NearSignTransaction.d.ts +1 -0
  160. package/dist/api/near/NearSignTransaction.d.ts.map +1 -1
  161. package/dist/api/nem/NEMGetAddress.d.ts +1 -0
  162. package/dist/api/nem/NEMGetAddress.d.ts.map +1 -1
  163. package/dist/api/nem/NEMSignTransaction.d.ts +1 -0
  164. package/dist/api/nem/NEMSignTransaction.d.ts.map +1 -1
  165. package/dist/api/neo/NeoGetAddress.d.ts.map +1 -1
  166. package/dist/api/neo/NeoSignTransaction.d.ts.map +1 -1
  167. package/dist/api/nervos/NervosGetAddress.d.ts.map +1 -1
  168. package/dist/api/nervos/NervosSignTransaction.d.ts.map +1 -1
  169. package/dist/api/nexa/NexaGetAddress.d.ts.map +1 -1
  170. package/dist/api/nexa/NexaSignTransaction.d.ts.map +1 -1
  171. package/dist/api/nostr/NostrDecryptMessage.d.ts +1 -0
  172. package/dist/api/nostr/NostrDecryptMessage.d.ts.map +1 -1
  173. package/dist/api/nostr/NostrEncryptMessage.d.ts +1 -0
  174. package/dist/api/nostr/NostrEncryptMessage.d.ts.map +1 -1
  175. package/dist/api/nostr/NostrGetPublicKey.d.ts +1 -0
  176. package/dist/api/nostr/NostrGetPublicKey.d.ts.map +1 -1
  177. package/dist/api/nostr/NostrSignEvent.d.ts +1 -0
  178. package/dist/api/nostr/NostrSignEvent.d.ts.map +1 -1
  179. package/dist/api/nostr/NostrSignSchnorr.d.ts +1 -0
  180. package/dist/api/nostr/NostrSignSchnorr.d.ts.map +1 -1
  181. package/dist/api/polkadot/PolkadotGetAddress.d.ts +1 -0
  182. package/dist/api/polkadot/PolkadotGetAddress.d.ts.map +1 -1
  183. package/dist/api/polkadot/PolkadotSignTransaction.d.ts +1 -0
  184. package/dist/api/polkadot/PolkadotSignTransaction.d.ts.map +1 -1
  185. package/dist/api/protocol-v2/DeviceFactoryInfoGet.d.ts +1 -0
  186. package/dist/api/protocol-v2/DeviceFactoryInfoGet.d.ts.map +1 -1
  187. package/dist/api/protocol-v2/DeviceFactoryInfoSet.d.ts +1 -0
  188. package/dist/api/protocol-v2/DeviceFactoryInfoSet.d.ts.map +1 -1
  189. package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts +1 -0
  190. package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts.map +1 -1
  191. package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts +1 -0
  192. package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts.map +1 -1
  193. package/dist/api/protocol-v2/DeviceGetOnboardingStatus.d.ts +1 -0
  194. package/dist/api/protocol-v2/DeviceGetOnboardingStatus.d.ts.map +1 -1
  195. package/dist/api/protocol-v2/DeviceInfoGet.d.ts +1 -0
  196. package/dist/api/protocol-v2/DeviceInfoGet.d.ts.map +1 -1
  197. package/dist/api/protocol-v2/DeviceReboot.d.ts +1 -0
  198. package/dist/api/protocol-v2/DeviceReboot.d.ts.map +1 -1
  199. package/dist/api/protocol-v2/DeviceStatusGet.d.ts +1 -0
  200. package/dist/api/protocol-v2/DeviceStatusGet.d.ts.map +1 -1
  201. package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts +1 -0
  202. package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts.map +1 -1
  203. package/dist/api/protocol-v2/FilesystemFormat.d.ts +1 -0
  204. package/dist/api/protocol-v2/FilesystemFormat.d.ts.map +1 -1
  205. package/dist/api/protocol-v2/FilesystemPermissionFix.d.ts +1 -0
  206. package/dist/api/protocol-v2/FilesystemPermissionFix.d.ts.map +1 -1
  207. package/dist/api/protocol-v2/Ping.d.ts +3 -0
  208. package/dist/api/protocol-v2/Ping.d.ts.map +1 -1
  209. package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts +1 -0
  210. package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
  211. package/dist/api/scdo/ScdoGetAddress.d.ts.map +1 -1
  212. package/dist/api/scdo/ScdoSignMessage.d.ts.map +1 -1
  213. package/dist/api/scdo/ScdoSignTransaction.d.ts.map +1 -1
  214. package/dist/api/solana/SolGetAddress.d.ts +1 -0
  215. package/dist/api/solana/SolGetAddress.d.ts.map +1 -1
  216. package/dist/api/solana/SolSignMessage.d.ts +1 -0
  217. package/dist/api/solana/SolSignMessage.d.ts.map +1 -1
  218. package/dist/api/solana/SolSignOffchainMessage.d.ts +1 -0
  219. package/dist/api/solana/SolSignOffchainMessage.d.ts.map +1 -1
  220. package/dist/api/solana/SolSignTransaction.d.ts +1 -0
  221. package/dist/api/solana/SolSignTransaction.d.ts.map +1 -1
  222. package/dist/api/starcoin/StarcoinGetAddress.d.ts +1 -0
  223. package/dist/api/starcoin/StarcoinGetAddress.d.ts.map +1 -1
  224. package/dist/api/starcoin/StarcoinGetPublicKey.d.ts +1 -0
  225. package/dist/api/starcoin/StarcoinGetPublicKey.d.ts.map +1 -1
  226. package/dist/api/starcoin/StarcoinSignMessage.d.ts +1 -0
  227. package/dist/api/starcoin/StarcoinSignMessage.d.ts.map +1 -1
  228. package/dist/api/starcoin/StarcoinSignTransaction.d.ts +1 -0
  229. package/dist/api/starcoin/StarcoinSignTransaction.d.ts.map +1 -1
  230. package/dist/api/starcoin/StarcoinVerifyMessage.d.ts +1 -0
  231. package/dist/api/starcoin/StarcoinVerifyMessage.d.ts.map +1 -1
  232. package/dist/api/stellar/StellarGetAddress.d.ts +1 -2
  233. package/dist/api/stellar/StellarGetAddress.d.ts.map +1 -1
  234. package/dist/api/stellar/StellarSignTransaction.d.ts +1 -2
  235. package/dist/api/stellar/StellarSignTransaction.d.ts.map +1 -1
  236. package/dist/api/sui/SuiGetAddress.d.ts +1 -0
  237. package/dist/api/sui/SuiGetAddress.d.ts.map +1 -1
  238. package/dist/api/sui/SuiGetPublicKey.d.ts +1 -0
  239. package/dist/api/sui/SuiGetPublicKey.d.ts.map +1 -1
  240. package/dist/api/sui/SuiSignMessage.d.ts +1 -0
  241. package/dist/api/sui/SuiSignMessage.d.ts.map +1 -1
  242. package/dist/api/sui/SuiSignTransaction.d.ts +1 -0
  243. package/dist/api/sui/SuiSignTransaction.d.ts.map +1 -1
  244. package/dist/api/ton/TonGetAddress.d.ts +1 -0
  245. package/dist/api/ton/TonGetAddress.d.ts.map +1 -1
  246. package/dist/api/ton/TonSignData.d.ts +1 -0
  247. package/dist/api/ton/TonSignData.d.ts.map +1 -1
  248. package/dist/api/ton/TonSignMessage.d.ts +1 -0
  249. package/dist/api/ton/TonSignMessage.d.ts.map +1 -1
  250. package/dist/api/ton/TonSignProof.d.ts +1 -0
  251. package/dist/api/ton/TonSignProof.d.ts.map +1 -1
  252. package/dist/api/tron/TronGetAddress.d.ts +1 -0
  253. package/dist/api/tron/TronGetAddress.d.ts.map +1 -1
  254. package/dist/api/tron/TronSignMessage.d.ts +2 -0
  255. package/dist/api/tron/TronSignMessage.d.ts.map +1 -1
  256. package/dist/api/tron/TronSignTransaction.d.ts +1 -0
  257. package/dist/api/tron/TronSignTransaction.d.ts.map +1 -1
  258. package/dist/api/xrp/XrpGetAddress.d.ts +1 -0
  259. package/dist/api/xrp/XrpGetAddress.d.ts.map +1 -1
  260. package/dist/api/xrp/XrpSignTransaction.d.ts +1 -0
  261. package/dist/api/xrp/XrpSignTransaction.d.ts.map +1 -1
  262. package/dist/core/index.d.ts.map +1 -1
  263. package/dist/device/Device.d.ts +3 -1
  264. package/dist/device/Device.d.ts.map +1 -1
  265. package/dist/device/DeviceCommands.d.ts.map +1 -1
  266. package/dist/index.d.ts +25 -25
  267. package/dist/index.js +669 -367
  268. package/dist/inject.d.ts.map +1 -1
  269. package/dist/protocols/protocol-v2/unlockRetry.d.ts +2 -3
  270. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -1
  271. package/dist/protocols/protocol-v2/walletSession.d.ts +12 -0
  272. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  273. package/dist/types/api/export.d.ts +1 -1
  274. package/dist/types/api/export.d.ts.map +1 -1
  275. package/dist/types/api/index.d.ts +3 -1
  276. package/dist/types/api/index.d.ts.map +1 -1
  277. package/dist/types/api/kaspaSignTransaction.d.ts +15 -2
  278. package/dist/types/api/kaspaSignTransaction.d.ts.map +1 -1
  279. package/dist/types/api/openWalletSession.d.ts +0 -12
  280. package/dist/types/api/openWalletSession.d.ts.map +1 -1
  281. package/dist/types/api/protocolV2.d.ts +4 -0
  282. package/dist/types/api/protocolV2.d.ts.map +1 -1
  283. package/dist/types/device.d.ts +0 -1
  284. package/dist/types/device.d.ts.map +1 -1
  285. package/dist/utils/deviceInfoUtils.d.ts +0 -1
  286. package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
  287. package/dist/utils/deviceVersionUtils.d.ts +1 -0
  288. package/dist/utils/deviceVersionUtils.d.ts.map +1 -1
  289. package/dist/utils/index.d.ts +1 -1
  290. package/dist/utils/index.d.ts.map +1 -1
  291. package/dist/utils/patch.d.ts +1 -1
  292. package/dist/utils/patch.d.ts.map +1 -1
  293. package/package.json +4 -4
  294. package/src/api/BaseMethod.ts +21 -18
  295. package/src/api/CheckAllFirmwareRelease.ts +23 -3
  296. package/src/api/CipherKeyValue.ts +4 -0
  297. package/src/api/DirList.ts +4 -1
  298. package/src/api/DirMake.ts +4 -1
  299. package/src/api/DirRemove.ts +4 -1
  300. package/src/api/FileDelete.ts +4 -1
  301. package/src/api/FileRead.ts +4 -1
  302. package/src/api/FileWrite.ts +4 -1
  303. package/src/api/FirmwareUpdate.ts +0 -8
  304. package/src/api/FirmwareUpdateV3.ts +0 -6
  305. package/src/api/FirmwareUpdateV4.ts +36 -18
  306. package/src/api/GetDeviceState.ts +4 -0
  307. package/src/api/GetFeatures.ts +1 -4
  308. package/src/api/GetOnekeyFeatures.ts +0 -5
  309. package/src/api/GetPassphraseState.ts +4 -0
  310. package/src/api/OpenWalletSession.ts +27 -86
  311. package/src/api/PathInfo.ts +4 -1
  312. package/src/api/alephium/AlephiumGetAddress.ts +0 -4
  313. package/src/api/alephium/AlephiumSignMessage.ts +0 -4
  314. package/src/api/alephium/AlephiumSignTransaction.ts +0 -4
  315. package/src/api/algo/AlgoGetAddress.ts +4 -0
  316. package/src/api/algo/AlgoSignTransaction.ts +4 -0
  317. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +5 -13
  318. package/src/api/aptos/AptosGetAddress.ts +4 -0
  319. package/src/api/aptos/AptosGetPublicKey.ts +4 -0
  320. package/src/api/aptos/AptosSignInMessage.ts +4 -0
  321. package/src/api/aptos/AptosSignMessage.ts +4 -0
  322. package/src/api/aptos/AptosSignTransaction.ts +4 -0
  323. package/src/api/benfen/BenfenGetAddress.ts +11 -7
  324. package/src/api/benfen/BenfenGetPublicKey.ts +0 -4
  325. package/src/api/benfen/BenfenSignMessage.ts +0 -4
  326. package/src/api/benfen/BenfenSignTransaction.ts +0 -4
  327. package/src/api/btc/BTCGetAddress.ts +8 -1
  328. package/src/api/btc/BTCGetPublicKey.ts +8 -1
  329. package/src/api/btc/BTCSignMessage.ts +8 -1
  330. package/src/api/btc/BTCSignPsbt.ts +4 -0
  331. package/src/api/btc/BTCSignTransaction.ts +8 -1
  332. package/src/api/btc/BTCVerifyMessage.ts +8 -1
  333. package/src/api/btc/helpers/versionLimit.ts +7 -4
  334. package/src/api/cardano/CardanoGetAddress.ts +4 -0
  335. package/src/api/cardano/CardanoGetPublicKey.ts +4 -0
  336. package/src/api/cardano/CardanoSignMessage.ts +4 -0
  337. package/src/api/cardano/CardanoSignTransaction.ts +4 -0
  338. package/src/api/conflux/ConfluxGetAddress.ts +4 -0
  339. package/src/api/conflux/ConfluxSignMessage.ts +4 -0
  340. package/src/api/conflux/ConfluxSignMessageCIP23.ts +4 -0
  341. package/src/api/conflux/ConfluxSignTransaction.ts +6 -5
  342. package/src/api/cosmos/CosmosGetAddress.ts +4 -0
  343. package/src/api/cosmos/CosmosGetPublicKey.ts +4 -0
  344. package/src/api/cosmos/CosmosSignTransaction.ts +4 -0
  345. package/src/api/device/DeviceCancel.ts +4 -0
  346. package/src/api/device/DeviceChangePin.ts +4 -0
  347. package/src/api/device/DeviceLock.ts +4 -0
  348. package/src/api/device/DeviceRebootToBoardloader.ts +4 -0
  349. package/src/api/device/DeviceRebootToBootloader.ts +4 -0
  350. package/src/api/device/DeviceSettings.ts +4 -0
  351. package/src/api/device/DeviceSupportFeatures.ts +4 -0
  352. package/src/api/device/DeviceUnlock.ts +4 -0
  353. package/src/api/device/DeviceWipe.ts +4 -0
  354. package/src/api/device/PreInitialize.ts +4 -0
  355. package/src/api/dynex/DnxGetAddress.ts +0 -6
  356. package/src/api/dynex/DnxSignTransaction.ts +0 -6
  357. package/src/api/evm/EVMGetAddress.ts +4 -0
  358. package/src/api/evm/EVMGetPublicKey.ts +4 -0
  359. package/src/api/evm/EVMSignMessage.ts +4 -0
  360. package/src/api/evm/EVMSignMessageEIP712.ts +1 -11
  361. package/src/api/evm/EVMSignTransaction.ts +4 -0
  362. package/src/api/evm/EVMSignTypedData.ts +4 -0
  363. package/src/api/evm/EVMVerifyMessage.ts +4 -0
  364. package/src/api/filecoin/FilecoinGetAddress.ts +4 -0
  365. package/src/api/filecoin/FilecoinSignTransaction.ts +4 -0
  366. package/src/api/firmware/FirmwareUpdatePlan.ts +8 -1
  367. package/src/api/index.ts +1 -0
  368. package/src/api/kaspa/KaspaGetAddress.ts +4 -0
  369. package/src/api/kaspa/KaspaSignTransaction.ts +37 -15
  370. package/src/api/kaspa/helpers/TransferSerialize.ts +3 -7
  371. package/src/api/lightning/LnurlAuth.ts +0 -4
  372. package/src/api/near/NearGetAddress.ts +4 -0
  373. package/src/api/near/NearSignTransaction.ts +4 -0
  374. package/src/api/nem/NEMGetAddress.ts +4 -0
  375. package/src/api/nem/NEMSignTransaction.ts +4 -0
  376. package/src/api/neo/NeoGetAddress.ts +0 -4
  377. package/src/api/neo/NeoSignTransaction.ts +0 -4
  378. package/src/api/nervos/NervosGetAddress.ts +0 -4
  379. package/src/api/nervos/NervosSignTransaction.ts +0 -4
  380. package/src/api/nexa/NexaGetAddress.ts +0 -4
  381. package/src/api/nexa/NexaSignTransaction.ts +0 -4
  382. package/src/api/nostr/NostrDecryptMessage.ts +4 -0
  383. package/src/api/nostr/NostrEncryptMessage.ts +4 -0
  384. package/src/api/nostr/NostrGetPublicKey.ts +4 -0
  385. package/src/api/nostr/NostrSignEvent.ts +4 -0
  386. package/src/api/nostr/NostrSignSchnorr.ts +4 -0
  387. package/src/api/polkadot/PolkadotGetAddress.ts +4 -0
  388. package/src/api/polkadot/PolkadotSignTransaction.ts +4 -0
  389. package/src/api/protocol-v2/DeviceFactoryInfoGet.ts +4 -1
  390. package/src/api/protocol-v2/DeviceFactoryInfoSet.ts +4 -1
  391. package/src/api/protocol-v2/DeviceFirmwareUpdate.ts +4 -1
  392. package/src/api/protocol-v2/DeviceGetFirmwareUpdateStatus.ts +4 -1
  393. package/src/api/protocol-v2/DeviceGetOnboardingStatus.ts +4 -1
  394. package/src/api/protocol-v2/DeviceInfoGet.ts +4 -8
  395. package/src/api/protocol-v2/DeviceReboot.ts +4 -2
  396. package/src/api/protocol-v2/DeviceStatusGet.ts +4 -1
  397. package/src/api/protocol-v2/DeviceUploadWallpaper.ts +4 -1
  398. package/src/api/protocol-v2/FilesystemFormat.ts +4 -1
  399. package/src/api/protocol-v2/FilesystemPermissionFix.ts +4 -1
  400. package/src/api/protocol-v2/Ping.ts +36 -2
  401. package/src/api/protocol-v2/ProtocolInfoRequest.ts +4 -1
  402. package/src/api/scdo/ScdoGetAddress.ts +0 -4
  403. package/src/api/scdo/ScdoSignMessage.ts +0 -4
  404. package/src/api/scdo/ScdoSignTransaction.ts +0 -4
  405. package/src/api/solana/SolGetAddress.ts +4 -0
  406. package/src/api/solana/SolSignMessage.ts +4 -0
  407. package/src/api/solana/SolSignOffchainMessage.ts +4 -0
  408. package/src/api/solana/SolSignTransaction.ts +4 -0
  409. package/src/api/starcoin/StarcoinGetAddress.ts +4 -0
  410. package/src/api/starcoin/StarcoinGetPublicKey.ts +4 -0
  411. package/src/api/starcoin/StarcoinSignMessage.ts +4 -0
  412. package/src/api/starcoin/StarcoinSignTransaction.ts +4 -0
  413. package/src/api/starcoin/StarcoinVerifyMessage.ts +4 -0
  414. package/src/api/stellar/StellarGetAddress.ts +1 -10
  415. package/src/api/stellar/StellarSignTransaction.ts +1 -14
  416. package/src/api/sui/SuiGetAddress.ts +4 -0
  417. package/src/api/sui/SuiGetPublicKey.ts +4 -0
  418. package/src/api/sui/SuiSignMessage.ts +4 -0
  419. package/src/api/sui/SuiSignTransaction.ts +4 -0
  420. package/src/api/ton/TonGetAddress.ts +4 -0
  421. package/src/api/ton/TonSignData.ts +5 -1
  422. package/src/api/ton/TonSignMessage.ts +4 -0
  423. package/src/api/ton/TonSignProof.ts +4 -0
  424. package/src/api/tron/TronGetAddress.ts +4 -0
  425. package/src/api/tron/TronSignMessage.ts +15 -7
  426. package/src/api/tron/TronSignTransaction.ts +4 -0
  427. package/src/api/xrp/XrpGetAddress.ts +4 -0
  428. package/src/api/xrp/XrpSignTransaction.ts +5 -1
  429. package/src/core/index.ts +43 -24
  430. package/src/data/messages/messages-protocol-v2.json +33 -1
  431. package/src/device/Device.ts +60 -62
  432. package/src/device/DeviceCommands.ts +19 -0
  433. package/src/inject.ts +2 -0
  434. package/src/protocols/protocol-v2/unlockRetry.ts +20 -3
  435. package/src/protocols/protocol-v2/walletSession.ts +26 -8
  436. package/src/types/api/export.ts +2 -0
  437. package/src/types/api/index.ts +3 -0
  438. package/src/types/api/kaspaSignTransaction.ts +20 -2
  439. package/src/types/api/openWalletSession.ts +0 -19
  440. package/src/types/api/protocolV2.ts +10 -0
  441. package/src/types/device.ts +0 -1
  442. package/src/utils/deviceInfoUtils.ts +15 -6
  443. package/src/utils/deviceVersionUtils.ts +1 -1
  444. package/src/utils/index.ts +0 -1
  445. package/tsconfig.type-tests.json +8 -0
@@ -50,7 +50,7 @@ import TonSignProof from '../src/api/ton/TonSignProof';
50
50
  import TronGetAddress from '../src/api/tron/TronGetAddress';
51
51
  import StellarGetAddress from '../src/api/stellar/StellarGetAddress';
52
52
  import BenfenSignMessage from '../src/api/benfen/BenfenSignMessage';
53
- import { getBitcoinForkVersionRange } from '../src/api/btc/helpers/versionLimit';
53
+ import { getBitcoinForkSupportedProtocols } from '../src/api/btc/helpers/versionLimit';
54
54
  import { DataManager } from '../src/data-manager';
55
55
  import { createCoreApi } from '../src/inject';
56
56
  import { Device, preloadSessionCache } from '../src/device/Device';
@@ -80,7 +80,6 @@ import {
80
80
  getFirmwareUpdateField,
81
81
  getFirmwareUpdateFieldArray,
82
82
  getMethodVersionRange,
83
- isMethodVersionRangeUnsupported,
84
83
  } from '../src/utils';
85
84
  import { getDeviceFirmwareVersion } from '../src/utils/deviceVersionUtils';
86
85
  import { openFirmwareByteSource } from '../src/api/firmware/FirmwareArtifactSource';
@@ -98,6 +97,14 @@ jest.mock('../src/data/config', () => ({
98
97
  DEFAULT_DOMAIN: 'https://jssdk.onekey.so/1.0.0/',
99
98
  }));
100
99
 
100
+ const createWalletSessionTypedCall = (implementation = jest.fn()) =>
101
+ jest.fn((request: string, ...args: unknown[]) => {
102
+ if (request === 'ProtocolInfoRequest') {
103
+ return Promise.resolve({ message: { version: 2 } });
104
+ }
105
+ return implementation(request, ...args);
106
+ });
107
+
101
108
  describe('DeviceUploadWallpaper', () => {
102
109
  test('encodes, uploads and applies a Pro2 wallpaper', async () => {
103
110
  const rgba = new Uint8Array(604 * 1024 * 4).fill(255);
@@ -122,7 +129,7 @@ describe('DeviceUploadWallpaper', () => {
122
129
  method.init();
123
130
  const result = await method.run();
124
131
 
125
- expect(method.requireProtocolV2).toBe(true);
132
+ expect(method.getSupportedProtocols()).toEqual(['V2']);
126
133
  expect(method.unlockPolicy).toBe('unlock-before-run');
127
134
  expect(typedCall).toHaveBeenNthCalledWith(1, 'FilesystemDirMake', 'Success', {
128
135
  path: 'vol1:/wallpapers',
@@ -690,13 +697,15 @@ describe('Protocol V2 feature adapter', () => {
690
697
  const features = normalizeProtocolV2Features(descriptor as any);
691
698
  features.firmwareVersion = '1.2.3';
692
699
  features.passphraseProtection = true;
693
- const typedCall = jest.fn().mockResolvedValue({
694
- type: 'DeviceSession',
695
- message: {
696
- btc_test_address: 'state-1',
697
- session_id: 'session-1',
698
- },
699
- });
700
+ const typedCall = createWalletSessionTypedCall(
701
+ jest.fn().mockResolvedValue({
702
+ type: 'DeviceSession',
703
+ message: {
704
+ btc_test_address: 'state-1',
705
+ session_id: 'session-1',
706
+ },
707
+ })
708
+ );
700
709
  const commands = { typedCall } as unknown as DeviceCommands;
701
710
  const device = Device.fromDescriptor({ ...descriptor, protocolType: 'V2' } as any);
702
711
  (device as any).features = features;
@@ -724,13 +733,15 @@ describe('Protocol V2 feature adapter', () => {
724
733
  { ...descriptor, protocolType: 'V2' } as any,
725
734
  { status: { passphrase_enabled: false, unlocked: true } }
726
735
  );
727
- const typedCall = jest.fn().mockResolvedValue({
728
- type: 'DeviceSession',
729
- message: {
730
- btc_test_address: 'main-wallet-state',
731
- session_id: 'main-wallet-session',
732
- },
733
- });
736
+ const typedCall = createWalletSessionTypedCall(
737
+ jest.fn().mockResolvedValue({
738
+ type: 'DeviceSession',
739
+ message: {
740
+ btc_test_address: 'main-wallet-state',
741
+ session_id: 'main-wallet-session',
742
+ },
743
+ })
744
+ );
734
745
  const promptPassphrase = jest
735
746
  .fn()
736
747
  .mockResolvedValue({ passphrase: 'hidden-wallet-with-disabled-flag' });
@@ -800,17 +811,16 @@ describe('Protocol V2 feature adapter', () => {
800
811
  },
801
812
  }
802
813
  );
803
- const typedCall = jest.fn().mockImplementation((request: string) => {
804
- if (request === 'ProtocolInfoRequest') {
805
- return Promise.resolve({ message: { version: 2 } });
806
- }
807
- if (request === 'DeviceStatusGet') {
808
- return Promise.resolve({
809
- message: { passphrase_enabled: false, unlocked: true },
810
- });
811
- }
812
- throw new Error(`Unexpected request: ${request}`);
813
- });
814
+ const typedCall = createWalletSessionTypedCall(
815
+ jest.fn().mockImplementation((request: string) => {
816
+ if (request === 'DeviceStatusGet') {
817
+ return Promise.resolve({
818
+ message: { passphrase_enabled: false, unlocked: true },
819
+ });
820
+ }
821
+ throw new Error(`Unexpected request: ${request}`);
822
+ })
823
+ );
814
824
  const promptPassphrase = jest.fn().mockResolvedValue({ passphrase: 'hidden-after-unlock' });
815
825
  const unlockDevice = jest.spyOn(device, 'unlockDevice').mockImplementation(() => {
816
826
  (device as any).features = {
@@ -844,13 +854,15 @@ describe('Protocol V2 feature adapter', () => {
844
854
  );
845
855
  device.passphraseState = 'hidden-state';
846
856
  preloadSessionCache('main-wallet-device', 'hidden-state', 'hidden-session');
847
- const typedCall = jest.fn().mockResolvedValue({
848
- type: 'DeviceSession',
849
- message: {
850
- btc_test_address: 'main-wallet-state',
851
- session_id: 'main-wallet-session',
852
- },
853
- });
857
+ const typedCall = createWalletSessionTypedCall(
858
+ jest.fn().mockResolvedValue({
859
+ type: 'DeviceSession',
860
+ message: {
861
+ btc_test_address: 'main-wallet-state',
862
+ session_id: 'main-wallet-session',
863
+ },
864
+ })
865
+ );
854
866
  (device as any).commands = { typedCall };
855
867
 
856
868
  await expect(
@@ -885,11 +897,13 @@ describe('Protocol V2 feature adapter', () => {
885
897
  },
886
898
  }
887
899
  );
888
- const typedCall = jest.fn().mockResolvedValue({
889
- type: 'DeviceSession',
890
- message: { session_id: 'hidden-session', btc_test_address: 'hidden-state' },
891
- });
892
- const promptPassphrase = jest.fn().mockResolvedValue({ passphrase: 'hidden secret' });
900
+ const typedCall = createWalletSessionTypedCall(
901
+ jest.fn().mockResolvedValue({
902
+ type: 'DeviceSession',
903
+ message: { session_id: 'hidden-session', btc_test_address: 'hidden-state' },
904
+ })
905
+ );
906
+ const promptPassphrase = jest.fn().mockResolvedValue({ passphraseOnDevice: true });
893
907
  (device as any).commands = { typedCall, promptPassphrase };
894
908
 
895
909
  await expect(getProtocolV2WalletSession(device)).resolves.toMatchObject({
@@ -898,14 +912,7 @@ describe('Protocol V2 feature adapter', () => {
898
912
  });
899
913
 
900
914
  expect(promptPassphrase).toHaveBeenCalled();
901
- expect(typedCall).toHaveBeenCalledWith(
902
- 'DeviceSessionAskPassphrase',
903
- 'Success',
904
- {},
905
- {
906
- timeoutMs: 120_000,
907
- }
908
- );
915
+ expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {});
909
916
  expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {});
910
917
  });
911
918
 
@@ -964,7 +971,7 @@ describe('Protocol V2 feature adapter', () => {
964
971
  wallet_initialized: false,
965
972
  });
966
973
  expect(typedCall).toHaveBeenCalledWith('DevGetOnboardingStatus', 'DevOnboardingStatus', {});
967
- expect(method.requireProtocolV2).toBe(true);
974
+ expect(method.getSupportedProtocols()).toEqual(['V2']);
968
975
  });
969
976
 
970
977
  test('routes onboarding without exposing the raw session command through CoreApi', async () => {
@@ -999,10 +1006,12 @@ describe('Protocol V2 feature adapter', () => {
999
1006
  );
1000
1007
  device.passphraseState = 'state-a';
1001
1008
  preloadSessionCache('stable-device-1', 'state-a', 'session-a');
1002
- const typedCall = jest.fn().mockResolvedValue({
1003
- type: 'DeviceSession',
1004
- message: { session_id: 'session-b', btc_test_address: 'state-a' },
1005
- });
1009
+ const typedCall = createWalletSessionTypedCall(
1010
+ jest.fn().mockResolvedValue({
1011
+ type: 'DeviceSession',
1012
+ message: { session_id: 'session-b', btc_test_address: 'state-a' },
1013
+ })
1014
+ );
1006
1015
  (device as any).commands = { typedCall };
1007
1016
 
1008
1017
  await expect(getProtocolV2WalletSession(device)).resolves.toMatchObject({
@@ -1027,13 +1036,15 @@ describe('Protocol V2 feature adapter', () => {
1027
1036
  { status: { device_id: 'stable-device-2', unlocked: true } }
1028
1037
  );
1029
1038
  preloadSessionCache('stable-device-2', 'state-a', 'session-a');
1030
- const typedCall = jest.fn().mockResolvedValue({
1031
- type: 'DeviceSession',
1032
- message: {
1033
- session_id: 'main-session',
1034
- btc_test_address: 'main-wallet-state',
1035
- },
1036
- });
1039
+ const typedCall = createWalletSessionTypedCall(
1040
+ jest.fn().mockResolvedValue({
1041
+ type: 'DeviceSession',
1042
+ message: {
1043
+ session_id: 'main-session',
1044
+ btc_test_address: 'main-wallet-state',
1045
+ },
1046
+ })
1047
+ );
1037
1048
  (device as any).commands = { typedCall };
1038
1049
 
1039
1050
  await getProtocolV2WalletSession(device, { onlyMainPin: true });
@@ -1062,14 +1073,13 @@ describe('Protocol V2 feature adapter', () => {
1062
1073
  );
1063
1074
  device.passphraseState = 'state-a';
1064
1075
  preloadSessionCache('stable-device-3', 'state-a', 'session-a');
1065
- const typedCall = jest
1066
- .fn()
1067
- .mockResolvedValueOnce({ message: { version: 2 } })
1068
- .mockRejectedValue(
1076
+ const typedCall = createWalletSessionTypedCall(
1077
+ jest.fn().mockRejectedValue(
1069
1078
  Object.assign(new Error('SE request failed'), {
1070
1079
  errorCode: HardwareErrorCode.RuntimeError,
1071
1080
  })
1072
- );
1081
+ )
1082
+ );
1073
1083
  const promptPassphrase = jest.fn();
1074
1084
  (device as any).commands = { typedCall, promptPassphrase };
1075
1085
 
@@ -1100,17 +1110,16 @@ describe('Protocol V2 feature adapter', () => {
1100
1110
  },
1101
1111
  }
1102
1112
  );
1103
- const typedCall = jest
1104
- .fn()
1105
- .mockResolvedValueOnce({ message: { version: 2 } })
1106
- .mockRejectedValue(
1113
+ const typedCall = createWalletSessionTypedCall(
1114
+ jest.fn().mockRejectedValue(
1107
1115
  Object.assign(new Error('Invalid session'), {
1108
1116
  errorCode: HardwareErrorCode.WalletSessionInvalid,
1109
1117
  })
1110
- );
1118
+ )
1119
+ );
1111
1120
  (device as any).commands = {
1112
1121
  typedCall,
1113
- promptPassphrase: jest.fn().mockResolvedValue({ passphrase: 'new-secret' }),
1122
+ promptPassphrase: jest.fn().mockResolvedValue({ passphraseOnDevice: true }),
1114
1123
  };
1115
1124
 
1116
1125
  await expect(getProtocolV2WalletSession(device)).rejects.toMatchObject({
@@ -1118,7 +1127,7 @@ describe('Protocol V2 feature adapter', () => {
1118
1127
  });
1119
1128
  expect(typedCall.mock.calls).toEqual([
1120
1129
  ['ProtocolInfoRequest', 'ProtocolInfo', { eventless_wallet_session: true }],
1121
- ['DeviceSessionAskPassphrase', 'Success', {}, { timeoutMs: 120_000 }],
1130
+ ['DeviceSessionAskPassphrase', 'Success', {}],
1122
1131
  ]);
1123
1132
  });
1124
1133
 
@@ -1141,10 +1150,12 @@ describe('Protocol V2 feature adapter', () => {
1141
1150
  device.passphraseState = 'state-a';
1142
1151
  preloadSessionCache('stable-device-mismatch', 'state-a', 'session-a');
1143
1152
  (device as any).commands = {
1144
- typedCall: jest.fn().mockResolvedValue({
1145
- type: 'DeviceSession',
1146
- message: { session_id: 'session-b', btc_test_address: 'state-b' },
1147
- }),
1153
+ typedCall: createWalletSessionTypedCall(
1154
+ jest.fn().mockResolvedValue({
1155
+ type: 'DeviceSession',
1156
+ message: { session_id: 'session-b', btc_test_address: 'state-b' },
1157
+ })
1158
+ ),
1148
1159
  };
1149
1160
 
1150
1161
  await expect(
@@ -1170,20 +1181,21 @@ describe('Protocol V2 feature adapter', () => {
1170
1181
  const lockedError = Object.assign(new Error('Device is locked'), {
1171
1182
  errorCode: HardwareErrorCode.DeviceLocked,
1172
1183
  });
1173
- const typedCall = jest
1174
- .fn()
1175
- .mockResolvedValueOnce({ message: { version: 2 } })
1176
- .mockRejectedValueOnce(lockedError)
1177
- .mockResolvedValueOnce({ message: { message: 'passphrase prepared' } })
1178
- .mockResolvedValueOnce({
1179
- message: {
1180
- session_id: 'session-after-unlock',
1181
- btc_test_address: 'state-after-unlock',
1182
- },
1183
- });
1184
+ const typedCall = createWalletSessionTypedCall(
1185
+ jest
1186
+ .fn()
1187
+ .mockRejectedValueOnce(lockedError)
1188
+ .mockResolvedValueOnce({ message: { message: 'passphrase prepared' } })
1189
+ .mockResolvedValueOnce({
1190
+ message: {
1191
+ session_id: 'session-after-unlock',
1192
+ btc_test_address: 'state-after-unlock',
1193
+ },
1194
+ })
1195
+ );
1184
1196
  (device as any).commands = {
1185
1197
  typedCall,
1186
- promptPassphrase: jest.fn().mockResolvedValue({ passphrase: 'hidden secret' }),
1198
+ promptPassphrase: jest.fn().mockResolvedValue({ passphraseOnDevice: true }),
1187
1199
  };
1188
1200
  const unlockDevice = jest.spyOn(device, 'unlockDevice').mockResolvedValue(undefined as any);
1189
1201
 
@@ -1335,7 +1347,7 @@ describe('Protocol V2 feature adapter', () => {
1335
1347
  };
1336
1348
  const typedCall = jest
1337
1349
  .fn()
1338
- .mockResolvedValueOnce({ message: { eventless_wallet_session: true } })
1350
+ .mockResolvedValueOnce({ message: { version: 2 } })
1339
1351
  .mockResolvedValueOnce({ message: { message: 'passphrase prepared' } })
1340
1352
  .mockResolvedValueOnce({
1341
1353
  type: 'DeviceSession',
@@ -1346,7 +1358,7 @@ describe('Protocol V2 feature adapter', () => {
1346
1358
  });
1347
1359
  const updateInternalState = jest.fn();
1348
1360
  const getFeatures = jest.fn().mockResolvedValue(features);
1349
- const promptPassphrase = jest.fn().mockResolvedValue({ passphrase: 'legacy app secret' });
1361
+ const promptPassphrase = jest.fn().mockResolvedValue({ passphraseOnDevice: true });
1350
1362
  const method = new GetPassphraseState({
1351
1363
  payload: {
1352
1364
  method: 'getPassphraseState',
@@ -1370,8 +1382,12 @@ describe('Protocol V2 feature adapter', () => {
1370
1382
 
1371
1383
  await expect(method.run()).resolves.toBe('state-pro2');
1372
1384
  expect(promptPassphrase).toHaveBeenCalledWith(
1373
- expect.objectContaining({ deviceOnly: true }),
1374
- expect.anything()
1385
+ {
1386
+ existsAttachPinUser: false,
1387
+ source: 'wallet-session-coordinator',
1388
+ reason: 'open-wallet',
1389
+ },
1390
+ { cancelDeviceOnReject: false }
1375
1391
  );
1376
1392
  expect(updateInternalState).toHaveBeenCalledWith(
1377
1393
  true,
@@ -1388,7 +1404,7 @@ describe('Protocol V2 feature adapter', () => {
1388
1404
  const device = Device.fromDescriptor({ ...descriptor, protocolType: 'V2' } as any);
1389
1405
  const typedCall = jest.fn().mockImplementation((request: string) => {
1390
1406
  if (request === 'ProtocolInfoRequest') {
1391
- return Promise.resolve({ message: { eventless_wallet_session: true } });
1407
+ return Promise.resolve({ message: { version: 2 } });
1392
1408
  }
1393
1409
  if (request === 'DeviceSessionAskPassphrase') {
1394
1410
  return Promise.resolve({ message: { message: 'passphrase prepared' } });
@@ -1451,7 +1467,7 @@ describe('Protocol V2 feature adapter', () => {
1451
1467
  passphraseProtection: false,
1452
1468
  unlocked: true,
1453
1469
  };
1454
- const typedCall = jest.fn();
1470
+ const typedCall = createWalletSessionTypedCall();
1455
1471
  const updateInternalState = jest.fn();
1456
1472
  const method = new GetPassphraseState({
1457
1473
  payload: {
@@ -1465,7 +1481,7 @@ describe('Protocol V2 feature adapter', () => {
1465
1481
  features,
1466
1482
  commands: {
1467
1483
  typedCall,
1468
- promptPassphrase: jest.fn().mockResolvedValue({ passphrase: 'mock-hidden-wallet' }),
1484
+ promptPassphrase: jest.fn().mockResolvedValue({ passphraseOnDevice: true }),
1469
1485
  },
1470
1486
  updateInternalState,
1471
1487
  getCurrentDeviceType: () => 'pro2',
@@ -1491,7 +1507,7 @@ describe('Protocol V2 feature adapter', () => {
1491
1507
  };
1492
1508
  const typedCall = jest
1493
1509
  .fn()
1494
- .mockResolvedValueOnce({ message: { eventless_wallet_session: true } })
1510
+ .mockResolvedValueOnce({ message: { version: 2 } })
1495
1511
  .mockResolvedValueOnce({ message: { message: 'passphrase prepared' } })
1496
1512
  .mockResolvedValueOnce({
1497
1513
  type: 'DeviceSession',
@@ -1515,7 +1531,7 @@ describe('Protocol V2 feature adapter', () => {
1515
1531
  passphraseState: 'state-pro2-old',
1516
1532
  commands: {
1517
1533
  typedCall,
1518
- promptPassphrase: jest.fn().mockResolvedValue({ passphrase: 'state-pro2-new-secret' }),
1534
+ promptPassphrase: jest.fn().mockResolvedValue({ passphraseOnDevice: true }),
1519
1535
  },
1520
1536
  emit: jest.fn(),
1521
1537
  clearInternalState,
@@ -1538,13 +1554,15 @@ describe('Protocol V2 feature adapter', () => {
1538
1554
 
1539
1555
  test('stores Pro2 passphrase session cache without synthetic device id', async () => {
1540
1556
  const device = Device.fromDescriptor({ ...descriptor, protocolType: 'V2' } as any);
1541
- const typedCall = jest.fn().mockResolvedValue({
1542
- type: 'DeviceSession',
1543
- message: {
1544
- btc_test_address: 'state-profile',
1545
- session_id: 'session-profile',
1546
- },
1547
- });
1557
+ const typedCall = createWalletSessionTypedCall(
1558
+ jest.fn().mockResolvedValue({
1559
+ type: 'DeviceSession',
1560
+ message: {
1561
+ btc_test_address: 'state-profile',
1562
+ session_id: 'session-profile',
1563
+ },
1564
+ })
1565
+ );
1548
1566
 
1549
1567
  (device as any).features = {
1550
1568
  ...normalizeProtocolV2Features({ ...descriptor, protocolType: 'V2' } as any, {
@@ -1556,7 +1574,7 @@ describe('Protocol V2 feature adapter', () => {
1556
1574
  };
1557
1575
  (device as any).commands = {
1558
1576
  typedCall,
1559
- promptPassphrase: jest.fn().mockResolvedValue({ passphrase: 'state-profile-secret' }),
1577
+ promptPassphrase: jest.fn().mockResolvedValue({ passphraseOnDevice: true }),
1560
1578
  };
1561
1579
 
1562
1580
  await getPassphraseStateWithRefreshDeviceInfo(device);
@@ -1568,13 +1586,15 @@ describe('Protocol V2 feature adapter', () => {
1568
1586
 
1569
1587
  test('stores Pro2 passphrase sessions without selecting them implicitly', async () => {
1570
1588
  const device = Device.fromDescriptor({ ...descriptor, protocolType: 'V2' } as any);
1571
- const typedCall = jest.fn().mockResolvedValue({
1572
- type: 'DeviceSession',
1573
- message: {
1574
- btc_test_address: 'state-auto',
1575
- session_id: 'session-auto',
1576
- },
1577
- });
1589
+ const typedCall = createWalletSessionTypedCall(
1590
+ jest.fn().mockResolvedValue({
1591
+ type: 'DeviceSession',
1592
+ message: {
1593
+ btc_test_address: 'state-auto',
1594
+ session_id: 'session-auto',
1595
+ },
1596
+ })
1597
+ );
1578
1598
 
1579
1599
  (device as any).features = normalizeProtocolV2Features(
1580
1600
  {
@@ -1594,7 +1614,7 @@ describe('Protocol V2 feature adapter', () => {
1594
1614
  );
1595
1615
  (device as any).commands = {
1596
1616
  typedCall,
1597
- promptPassphrase: jest.fn().mockResolvedValue({ passphrase: 'state-auto-secret' }),
1617
+ promptPassphrase: jest.fn().mockResolvedValue({ passphraseOnDevice: true }),
1598
1618
  };
1599
1619
 
1600
1620
  await expect(getPassphraseStateWithRefreshDeviceInfo(device)).resolves.toMatchObject({
@@ -1613,13 +1633,15 @@ describe('Protocol V2 feature adapter', () => {
1613
1633
 
1614
1634
  test('does not mark Pro2 passphrase enabled from a main PIN session alone', async () => {
1615
1635
  const device = Device.fromDescriptor({ ...descriptor, protocolType: 'V2' } as any);
1616
- const typedCall = jest.fn().mockResolvedValue({
1617
- type: 'DeviceSession',
1618
- message: {
1619
- session_id: 'main-pin-session',
1620
- btc_test_address: 'main-wallet-state',
1621
- },
1622
- });
1636
+ const typedCall = createWalletSessionTypedCall(
1637
+ jest.fn().mockResolvedValue({
1638
+ type: 'DeviceSession',
1639
+ message: {
1640
+ session_id: 'main-pin-session',
1641
+ btc_test_address: 'main-wallet-state',
1642
+ },
1643
+ })
1644
+ );
1623
1645
 
1624
1646
  (device as any).features = normalizeProtocolV2Features(
1625
1647
  {
@@ -1654,13 +1676,15 @@ describe('Protocol V2 feature adapter', () => {
1654
1676
 
1655
1677
  test('does not let skipPassphraseCheck hide Pro2 passphrase state mismatch', async () => {
1656
1678
  const device = Device.fromDescriptor({ ...descriptor, protocolType: 'V2' } as any);
1657
- const typedCall = jest.fn().mockResolvedValue({
1658
- type: 'DeviceSession',
1659
- message: {
1660
- btc_test_address: 'wrong-state',
1661
- session_id: 'wrong-session',
1662
- },
1663
- });
1679
+ const typedCall = createWalletSessionTypedCall(
1680
+ jest.fn().mockResolvedValue({
1681
+ type: 'DeviceSession',
1682
+ message: {
1683
+ btc_test_address: 'wrong-state',
1684
+ session_id: 'wrong-session',
1685
+ },
1686
+ })
1687
+ );
1664
1688
 
1665
1689
  (device as any).features = normalizeProtocolV2Features({
1666
1690
  ...descriptor,
@@ -1671,7 +1695,7 @@ describe('Protocol V2 feature adapter', () => {
1671
1695
  (device as any).features.unlocked = true;
1672
1696
  (device as any).commands = {
1673
1697
  typedCall,
1674
- promptPassphrase: jest.fn().mockResolvedValue({ passphrase: 'expected-secret' }),
1698
+ promptPassphrase: jest.fn().mockResolvedValue({ passphraseOnDevice: true }),
1675
1699
  };
1676
1700
 
1677
1701
  await expect(device.checkPassphraseStateSafety('expected-state', false, true)).rejects.toEqual(
@@ -1681,26 +1705,20 @@ describe('Protocol V2 feature adapter', () => {
1681
1705
  );
1682
1706
 
1683
1707
  expect(device.getInternalState()).toBeUndefined();
1684
- expect(typedCall).toHaveBeenNthCalledWith(
1685
- 2,
1686
- 'DeviceSessionAskPassphrase',
1687
- 'Success',
1688
- {},
1689
- {
1690
- timeoutMs: 120_000,
1691
- }
1692
- );
1708
+ expect(typedCall).toHaveBeenNthCalledWith(2, 'DeviceSessionAskPassphrase', 'Success', {});
1693
1709
  });
1694
1710
 
1695
1711
  test('useEmptyPassphrase ignores a stale hidden-wallet state during Protocol V2 safety check', async () => {
1696
1712
  const device = Device.fromDescriptor({ ...descriptor, protocolType: 'V2' } as any);
1697
- const typedCall = jest.fn().mockResolvedValue({
1698
- type: 'DeviceSession',
1699
- message: {
1700
- session_id: 'main-wallet-session',
1701
- btc_test_address: 'main-wallet-state',
1702
- },
1703
- });
1713
+ const typedCall = createWalletSessionTypedCall(
1714
+ jest.fn().mockResolvedValue({
1715
+ type: 'DeviceSession',
1716
+ message: {
1717
+ session_id: 'main-wallet-session',
1718
+ btc_test_address: 'main-wallet-state',
1719
+ },
1720
+ })
1721
+ );
1704
1722
 
1705
1723
  (device as any).features = normalizeProtocolV2Features(
1706
1724
  { ...descriptor, protocolType: 'V2' } as any,
@@ -1800,7 +1818,7 @@ describe('Protocol V2 feature adapter', () => {
1800
1818
  expect(device.hasUsePassphrase()).toBe(true);
1801
1819
  });
1802
1820
 
1803
- test('keeps an empty Protocol V2 label distinct from the BLE name', () => {
1821
+ test('uses the BLE name as the Protocol V2 display label while preserving the raw label', () => {
1804
1822
  const device = Device.fromDescriptor({ ...descriptor, protocolType: 'V2' } as any);
1805
1823
  (device as any).features = {
1806
1824
  ...normalizeProtocolV2Features({ ...descriptor, protocolType: 'V2' } as any),
@@ -1813,8 +1831,9 @@ describe('Protocol V2 feature adapter', () => {
1813
1831
  serialNo: 'PR9999999999',
1814
1832
  bleName: 'Pro2 6136',
1815
1833
  name: 'Pro2 6136',
1816
- label: '',
1834
+ label: 'Pro2 6136',
1817
1835
  });
1836
+ expect(device.features?.label).toBeNull();
1818
1837
  });
1819
1838
 
1820
1839
  test('prefers the real Protocol V2 label over the BLE name for display', () => {
@@ -1938,13 +1957,6 @@ describe('Protocol V2 feature adapter', () => {
1938
1957
  });
1939
1958
 
1940
1959
  test('marks known unsupported public-chain methods as unsupported on Protocol V2', () => {
1941
- const features = normalizeProtocolV2Features({ ...descriptor, protocolType: 'V2' } as any, {
1942
- fw: {
1943
- application: {
1944
- version: '9.9.9',
1945
- },
1946
- },
1947
- });
1948
1960
  const stellar = new StellarGetAddress({
1949
1961
  id: 1,
1950
1962
  payload: {
@@ -1973,21 +1985,10 @@ describe('Protocol V2 feature adapter', () => {
1973
1985
  benfen.init();
1974
1986
  lnurlAuth.init();
1975
1987
 
1976
- const stellarRange = getMethodVersionRange(features, type => stellar.getVersionRange()[type]);
1977
- const benfenRange = getMethodVersionRange(features, type => benfen.getVersionRange()[type]);
1978
- const lnurlAuthRange = getMethodVersionRange(
1979
- features,
1980
- type => lnurlAuth.getVersionRange()[type]
1981
- );
1982
- const neuraiRange = getMethodVersionRange(
1983
- features,
1984
- type => getBitcoinForkVersionRange(['Neurai'])[type]
1985
- );
1986
-
1987
- expect(isMethodVersionRangeUnsupported(stellarRange)).toBe(true);
1988
- expect(isMethodVersionRangeUnsupported(benfenRange)).toBe(true);
1989
- expect(isMethodVersionRangeUnsupported(lnurlAuthRange)).toBe(true);
1990
- expect(isMethodVersionRangeUnsupported(neuraiRange)).toBe(true);
1988
+ expect(stellar.supportsProtocol('V2')).toBe(false);
1989
+ expect(benfen.supportsProtocol('V2')).toBe(false);
1990
+ expect(lnurlAuth.supportsProtocol('V2')).toBe(false);
1991
+ expect(getBitcoinForkSupportedProtocols(['Neurai'])).toEqual(['V1']);
1991
1992
  });
1992
1993
 
1993
1994
  test('does not block batch public key support checks on Protocol V2', async () => {
@@ -2026,7 +2027,7 @@ describe('Protocol V2 feature adapter', () => {
2026
2027
  });
2027
2028
  });
2028
2029
 
2029
- test('rejects legacy getOnekeyFeatures for Protocol V2 devices', async () => {
2030
+ test('declares legacy getOnekeyFeatures unsupported on Protocol V2', () => {
2030
2031
  const method = new GetOnekeyFeatures({
2031
2032
  id: 1,
2032
2033
  payload: {
@@ -2040,9 +2041,9 @@ describe('Protocol V2 feature adapter', () => {
2040
2041
  commands: { typedCall },
2041
2042
  });
2042
2043
 
2043
- await expect(method.run()).rejects.toMatchObject({
2044
- errorCode: expect.any(Number),
2045
- });
2044
+ expect(() => method.assertProtocolSupported('V2', EFirmwareType.Universal)).toThrow(
2045
+ expect.objectContaining({ errorCode: HardwareErrorCode.DeviceNotSupportMethod })
2046
+ );
2046
2047
  expect(typedCall).not.toHaveBeenCalled();
2047
2048
  });
2048
2049
 
@@ -2333,12 +2334,7 @@ describe('Protocol V2 feature adapter', () => {
2333
2334
  const features = await device.unlockDevice();
2334
2335
 
2335
2336
  expect(typedCall.mock.calls).toEqual([
2336
- [
2337
- 'DeviceSessionAskPin',
2338
- 'Success',
2339
- { type: DeviceSessionPinType.Main },
2340
- { timeoutMs: 120_000 },
2341
- ],
2337
+ ['DeviceSessionAskPin', 'Success', { type: DeviceSessionPinType.Main }],
2342
2338
  ['DeviceStatusGet', 'DeviceStatus', {}],
2343
2339
  ]);
2344
2340
  expect(typedCall).not.toHaveBeenCalledWith('GetAddress', 'Address', expect.anything());
@@ -2386,12 +2382,7 @@ describe('Protocol V2 feature adapter', () => {
2386
2382
  await device.unlockDevice();
2387
2383
 
2388
2384
  expect(typedCall.mock.calls).toEqual([
2389
- [
2390
- 'DeviceSessionAskPin',
2391
- 'Success',
2392
- { type: DeviceSessionPinType.Main },
2393
- { timeoutMs: 120_000 },
2394
- ],
2385
+ ['DeviceSessionAskPin', 'Success', { type: DeviceSessionPinType.Main }],
2395
2386
  ['DeviceStatusGet', 'DeviceStatus', {}],
2396
2387
  ]);
2397
2388
  expect((device as any).profile).toBeUndefined();
@@ -2421,12 +2412,7 @@ describe('Protocol V2 feature adapter', () => {
2421
2412
  );
2422
2413
  expect(typedCall).toHaveBeenCalledTimes(1);
2423
2414
  expect(typedCall.mock.calls).toEqual([
2424
- [
2425
- 'DeviceSessionAskPin',
2426
- 'Success',
2427
- { type: DeviceSessionPinType.Main },
2428
- { timeoutMs: 120_000 },
2429
- ],
2415
+ ['DeviceSessionAskPin', 'Success', { type: DeviceSessionPinType.Main }],
2430
2416
  ]);
2431
2417
  expect(typedCall).not.toHaveBeenCalledWith(
2432
2418
  'DeviceSessionGet',
@@ -2590,16 +2576,8 @@ describe('API compatibility handling', () => {
2590
2576
 
2591
2577
  polkadotGetAddressMethod.init();
2592
2578
 
2593
- expect(
2594
- isMethodVersionRangeUnsupported(
2595
- getMethodVersionRange(features, type => tronMethod.getVersionRange()[type])
2596
- )
2597
- ).toBe(false);
2598
- expect(
2599
- isMethodVersionRangeUnsupported(
2600
- getMethodVersionRange(features, type => solMethod.getVersionRange()[type])
2601
- )
2602
- ).toBe(false);
2579
+ expect(tronMethod.supportsProtocol('V2')).toBe(true);
2580
+ expect(solMethod.supportsProtocol('V2')).toBe(true);
2603
2581
  expect(
2604
2582
  getMethodVersionRange(features, type => tonGetAddressMethod.getVersionRange()[type])
2605
2583
  ).toEqual({
@@ -2755,7 +2733,7 @@ describe('API compatibility handling', () => {
2755
2733
  expect(params.data_initial_chunk).toHaveLength(2048);
2756
2734
  });
2757
2735
 
2758
- test('returns a typed unsupported error for Dynex signing on Protocol V2', async () => {
2736
+ test('declares Dynex signing unsupported on Protocol V2', () => {
2759
2737
  const method = new DnxSignTransaction({
2760
2738
  id: 1,
2761
2739
  payload: {
@@ -2777,17 +2755,14 @@ describe('API compatibility handling', () => {
2777
2755
  });
2778
2756
 
2779
2757
  method.init();
2780
- (method as any).device = stubDevice({
2781
- originalDescriptor: { protocolType: 'V2' },
2782
- features: normalizeProtocolV2Features({ ...descriptor, protocolType: 'V2' } as any),
2783
- });
2784
-
2785
- await expect(method.run()).rejects.toMatchObject({
2786
- errorCode: HardwareErrorCode.DeviceNotSupportMethod,
2787
- });
2758
+ expect(() => method.assertProtocolSupported('V2', EFirmwareType.Universal)).toThrow(
2759
+ expect.objectContaining({
2760
+ errorCode: HardwareErrorCode.DeviceNotSupportMethod,
2761
+ })
2762
+ );
2788
2763
  });
2789
2764
 
2790
- test('returns a typed unsupported error for Dynex address on Protocol V2', async () => {
2765
+ test('declares Dynex address unsupported on Protocol V2', () => {
2791
2766
  const method = new DnxGetAddress({
2792
2767
  id: 1,
2793
2768
  payload: {
@@ -2798,14 +2773,11 @@ describe('API compatibility handling', () => {
2798
2773
  });
2799
2774
 
2800
2775
  method.init();
2801
- (method as any).device = stubDevice({
2802
- originalDescriptor: { protocolType: 'V2' },
2803
- features: normalizeProtocolV2Features({ ...descriptor, protocolType: 'V2' } as any),
2804
- });
2805
-
2806
- await expect(method.run()).rejects.toMatchObject({
2807
- errorCode: HardwareErrorCode.DeviceNotSupportMethod,
2808
- });
2776
+ expect(() => method.assertProtocolSupported('V2', EFirmwareType.Universal)).toThrow(
2777
+ expect.objectContaining({
2778
+ errorCode: HardwareErrorCode.DeviceNotSupportMethod,
2779
+ })
2780
+ );
2809
2781
  });
2810
2782
  });
2811
2783
 
@@ -2844,18 +2816,16 @@ describe('Protocol V2 firmware update targets', () => {
2844
2816
  return header;
2845
2817
  };
2846
2818
 
2847
- test('keeps Protocol V2 firmware updates off the firmwareUpdateV3 path', async () => {
2819
+ test('keeps Protocol V2 firmware updates off the firmwareUpdateV3 path', () => {
2848
2820
  const method = new FirmwareUpdateV3({
2849
2821
  id: 1,
2850
2822
  payload: {
2851
2823
  method: 'firmwareUpdateV3',
2852
2824
  },
2853
2825
  });
2854
- (method as any).device = stubDevice({
2855
- originalDescriptor: { protocolType: 'V2' },
2856
- });
2857
-
2858
- await expect(method.run()).rejects.toThrow('firmwareUpdateV4');
2826
+ expect(() => method.assertProtocolSupported('V2', EFirmwareType.Universal)).toThrow(
2827
+ expect.objectContaining({ errorCode: HardwareErrorCode.DeviceNotSupportMethod })
2828
+ );
2859
2829
  });
2860
2830
 
2861
2831
  test('uses Protocol V2 features after BLE final reconnect without V1 Initialize', async () => {
@@ -3459,10 +3429,36 @@ describe('Protocol V2 firmware update targets', () => {
3459
3429
  minor_version: 0,
3460
3430
  patch_version: 0,
3461
3431
  };
3432
+ (method as any).protocolV2FinalStatusVerified = true;
3462
3433
 
3463
3434
  expect(() => (method as any).assertExpectedProtocolV2Versions()).not.toThrow();
3464
3435
  });
3465
3436
 
3437
+ test('rejects unobservable final versions after the status endpoint fallback', () => {
3438
+ const method = new FirmwareUpdateV4({
3439
+ id: 1,
3440
+ payload: {
3441
+ method: 'firmwareUpdateV4',
3442
+ platform: 'desktop',
3443
+ targetsToUpdate: ['app_v1', 'app_v2'],
3444
+ expectedTargetVersions: {
3445
+ app_v1: '1.0.0',
3446
+ app_v2: '2.0.0',
3447
+ },
3448
+ },
3449
+ });
3450
+ method.init();
3451
+ (method as any).protocolV2LatestFinalFeatures = {
3452
+ major_version: 3,
3453
+ minor_version: 0,
3454
+ patch_version: 0,
3455
+ };
3456
+
3457
+ expect(() => (method as any).assertExpectedProtocolV2Versions()).toThrow(
3458
+ 'has no observable final version after status fallback'
3459
+ );
3460
+ });
3461
+
3466
3462
  test('polls target status after update ACK and finishes when all targets complete', async () => {
3467
3463
  const method = new FirmwareUpdateV4({
3468
3464
  id: 1,
@@ -5029,10 +5025,16 @@ describe('Protocol V2 firmware reconnect identity', () => {
5029
5025
  ).not.toThrow();
5030
5026
  });
5031
5027
 
5032
- test('allows firmware update when the optional physical serial is unavailable', () => {
5033
- expect(() => assertProtocolV2ReconnectIdentity('expected-serial', undefined)).not.toThrow();
5034
- expect(() => assertProtocolV2ReconnectIdentity(undefined, 'actual-serial')).not.toThrow();
5035
- expect(() => assertProtocolV2ReconnectIdentity(undefined, undefined)).not.toThrow();
5028
+ test('fails closed when the physical serial is unavailable', () => {
5029
+ expect(() => assertProtocolV2ReconnectIdentity('expected-serial', undefined)).toThrow(
5030
+ expect.objectContaining({ errorCode: HardwareErrorCode.DeviceNotFound })
5031
+ );
5032
+ expect(() => assertProtocolV2ReconnectIdentity(undefined, 'actual-serial')).toThrow(
5033
+ expect.objectContaining({ errorCode: HardwareErrorCode.DeviceNotFound })
5034
+ );
5035
+ expect(() => assertProtocolV2ReconnectIdentity(undefined, undefined)).toThrow(
5036
+ expect.objectContaining({ errorCode: HardwareErrorCode.DeviceNotFound })
5037
+ );
5036
5038
  });
5037
5039
 
5038
5040
  test('captures physical identity from active DeviceInfo instead of wallet deviceId', async () => {
@@ -5064,6 +5066,54 @@ describe('Protocol V2 firmware reconnect identity', () => {
5064
5066
  { timeoutMs: 5000 }
5065
5067
  );
5066
5068
  });
5069
+
5070
+ test('rejects firmware update startup when DeviceInfo has no physical serial', async () => {
5071
+ const method = new FirmwareUpdateV4({
5072
+ id: 1,
5073
+ payload: { method: 'firmwareUpdateV4' },
5074
+ });
5075
+ const typedCall = jest.fn().mockResolvedValue({
5076
+ type: 'DeviceInfo',
5077
+ message: { protocol_version: 1, hw: {} },
5078
+ });
5079
+ (method as any).device = stubDevice({
5080
+ getCommands: () => ({ typedCall }),
5081
+ });
5082
+
5083
+ await expect((method as any).captureProtocolV2PhysicalIdentity()).rejects.toMatchObject({
5084
+ errorCode: HardwareErrorCode.DeviceNotFound,
5085
+ });
5086
+ });
5087
+
5088
+ test('uses the BLE read limit when reading an existing firmware bundle header', async () => {
5089
+ const method = new FirmwareUpdateV4({
5090
+ id: 1,
5091
+ payload: {
5092
+ method: 'firmwareUpdateV4',
5093
+ platform: 'native',
5094
+ chunkSize: 1800,
5095
+ },
5096
+ });
5097
+ method.init();
5098
+ const readChunkLengths: number[] = [];
5099
+ const typedCall = jest.fn((requestType: string, _responseType: string, request: any) => {
5100
+ if (requestType === 'FilesystemPathInfoQuery') {
5101
+ return Promise.resolve({ message: { exist: true, directory: false, size: 0x52a0 } });
5102
+ }
5103
+ if (requestType === 'FilesystemFileRead') {
5104
+ readChunkLengths.push(request.chunk_len);
5105
+ return Promise.resolve({ message: { data: new Uint8Array(request.chunk_len) } });
5106
+ }
5107
+ throw new Error(`Unexpected request: ${requestType}`);
5108
+ });
5109
+ (method as any).device = stubDevice({
5110
+ getCommands: () => ({ typedCall }),
5111
+ });
5112
+
5113
+ await expect((method as any).readProtocolV2DeviceFileHeader('bundle.okpp')).resolves.toBeNull();
5114
+ expect(readChunkLengths.length).toBeGreaterThan(1);
5115
+ expect(Math.max(...readChunkLengths)).toBe(900);
5116
+ });
5067
5117
  });
5068
5118
 
5069
5119
  describe('Protocol V2 explicit USB device selection', () => {
@@ -5245,6 +5295,70 @@ describe('Protocol V2 protected method execution', () => {
5245
5295
  ]);
5246
5296
  });
5247
5297
 
5298
+ test('restores the expected hidden-wallet session before retrying after unlock', async () => {
5299
+ const calls: string[] = [];
5300
+ const method = {
5301
+ name: 'evmSignMessage',
5302
+ payload: { passphraseState: 'hidden-state' },
5303
+ useDevicePassphraseState: true,
5304
+ unlockPolicy: 'retry-on-locked',
5305
+ run: jest
5306
+ .fn()
5307
+ .mockImplementationOnce(() => {
5308
+ calls.push('run-1');
5309
+ return Promise.reject(deviceLockedError());
5310
+ })
5311
+ .mockImplementationOnce(() => {
5312
+ calls.push('run-2');
5313
+ return Promise.resolve({ message: 'ok' });
5314
+ }),
5315
+ };
5316
+ const typedCall = jest.fn((requestType: string, _responseType: string, request: any) => {
5317
+ if (requestType === 'ProtocolInfoRequest') {
5318
+ calls.push('negotiate-session');
5319
+ return Promise.resolve({ message: { version: 2 } });
5320
+ }
5321
+ if (requestType === 'DeviceSessionGet') {
5322
+ calls.push('resume-hidden-session');
5323
+ expect(request).toEqual({ session_id: 'hidden-session' });
5324
+ return Promise.resolve({
5325
+ message: {
5326
+ session_id: 'hidden-session',
5327
+ btc_test_address: 'hidden-state',
5328
+ },
5329
+ });
5330
+ }
5331
+ throw new Error(`Unexpected request: ${requestType}`);
5332
+ });
5333
+ const device = {
5334
+ features: { unlocked: true, passphraseProtection: true },
5335
+ passphraseState: 'hidden-state',
5336
+ commands: { typedCall },
5337
+ isProtocolV2: () => true,
5338
+ unlockDevice: jest.fn(() => {
5339
+ calls.push('unlock');
5340
+ return Promise.resolve();
5341
+ }),
5342
+ getCurrentPassphraseProtection: () => true,
5343
+ getInternalState: () => 'hidden-session',
5344
+ clearInternalState: jest.fn(),
5345
+ getCurrentDeviceId: () => 'wallet-device-id',
5346
+ updateInternalState: jest.fn(() => calls.push('validate-hidden-session')),
5347
+ };
5348
+
5349
+ await expect(runMethodWithUnlockRetry(method as any, device as any)).resolves.toEqual({
5350
+ message: 'ok',
5351
+ });
5352
+ expect(calls).toEqual([
5353
+ 'run-1',
5354
+ 'unlock',
5355
+ 'negotiate-session',
5356
+ 'resume-hidden-session',
5357
+ 'validate-hidden-session',
5358
+ 'run-2',
5359
+ ]);
5360
+ });
5361
+
5248
5362
  test('unlocks before showing the method interaction when cached status is locked', async () => {
5249
5363
  const calls: string[] = [];
5250
5364
  const method = {
@@ -5817,7 +5931,7 @@ describe('Protocol V2 raw device info method', () => {
5817
5931
  );
5818
5932
  });
5819
5933
 
5820
- test('rejects on Protocol V1 devices instead of sending an unknown message', async () => {
5934
+ test('rejects on Protocol V1 devices instead of sending an unknown message', () => {
5821
5935
  const method = buildMethod();
5822
5936
  const typedCall = jest.fn();
5823
5937
  (method as any).device = stubDevice({
@@ -5825,7 +5939,9 @@ describe('Protocol V2 raw device info method', () => {
5825
5939
  commands: { typedCall },
5826
5940
  });
5827
5941
 
5828
- await expect(method.run()).rejects.toThrow();
5942
+ expect(() => method.assertProtocolSupported('V1', EFirmwareType.Universal)).toThrow(
5943
+ expect.objectContaining({ errorCode: HardwareErrorCode.DeviceNotSupportMethod })
5944
+ );
5829
5945
  expect(typedCall).not.toHaveBeenCalled();
5830
5946
  });
5831
5947
  });