@onekeyfe/hd-core 1.2.0-alpha.67 → 1.2.0-alpha.68

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 (254) 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__/core-initialization.test.ts +23 -0
  6. package/__tests__/device-connector-protocol.test.ts +81 -0
  7. package/__tests__/device-lifecycle-events.test.ts +105 -3
  8. package/__tests__/device-pool-state.test.ts +22 -0
  9. package/__tests__/device-settings.test.ts +39 -18
  10. package/__tests__/device-state-contract.test.ts +1 -0
  11. package/__tests__/device-state-mapper.test.ts +13 -1
  12. package/__tests__/device-utils.test.ts +48 -1
  13. package/__tests__/deviceSettings.test.ts +11 -1
  14. package/__tests__/deviceUploadNft.test.ts +316 -0
  15. package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +5 -0
  16. package/__tests__/get-device-state.test.ts +132 -12
  17. package/__tests__/homescreen.test.ts +41 -1
  18. package/__tests__/kaspa-use-tweak-pro2.test.ts +2 -2
  19. package/__tests__/kaspaSignTransaction.test.ts +3 -26
  20. package/__tests__/logBlockEvent.test.ts +1 -1
  21. package/__tests__/method-protocol-support.test.ts +19 -0
  22. package/__tests__/open-wallet-session.test.ts +568 -37
  23. package/__tests__/pro2Nft.test.ts +108 -0
  24. package/__tests__/protocol-binding.test.ts +89 -0
  25. package/__tests__/protocol-v2-resources.test.ts +340 -0
  26. package/__tests__/protocol-v2-ui-lifecycle.test.ts +91 -0
  27. package/__tests__/protocol-v2-unlock-policy.test.ts +300 -37
  28. package/__tests__/protocol-v2.test.ts +1449 -867
  29. package/__tests__/protocolV2FileWrite.test.ts +152 -0
  30. package/__tests__/protocolV2UiInteraction.test.ts +63 -0
  31. package/__tests__/public-pro2-api-boundary.test.ts +1 -0
  32. package/__tests__/search-devices.test.ts +12 -3
  33. package/__tests__/tron-sign-message-init.test.ts +2 -2
  34. package/__tests__/uiProgressThrottle.test.ts +74 -0
  35. package/__tests__/uiPromiseRegistry.test.ts +115 -0
  36. package/dist/api/BaseMethod.d.ts +3 -1
  37. package/dist/api/BaseMethod.d.ts.map +1 -1
  38. package/dist/api/CheckAllFirmwareRelease.d.ts +2 -1
  39. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  40. package/dist/api/DetectDeviceConnectProtocol.d.ts +7 -0
  41. package/dist/api/DetectDeviceConnectProtocol.d.ts.map +1 -0
  42. package/dist/api/FirmwareUpdate.d.ts.map +1 -1
  43. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  44. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  45. package/dist/api/FirmwareUpdateV4.d.ts +11 -4
  46. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  47. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  48. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  49. package/dist/api/SearchDevices.d.ts.map +1 -1
  50. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  51. package/dist/api/device/DeviceSettings.d.ts.map +1 -1
  52. package/dist/api/device/DeviceUnlock.d.ts +2 -2
  53. package/dist/api/device/DeviceUnlock.d.ts.map +1 -1
  54. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +4 -3
  55. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  56. package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
  57. package/dist/api/helpers/protocolV2FileWrite.d.ts +9 -0
  58. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
  59. package/dist/api/index.d.ts +2 -0
  60. package/dist/api/index.d.ts.map +1 -1
  61. package/dist/api/kaspa/KaspaGetAddress.d.ts +1 -1
  62. package/dist/api/kaspa/KaspaSignTransaction.d.ts +1 -1
  63. package/dist/api/kaspa/KaspaSignTransaction.d.ts.map +1 -1
  64. package/dist/api/polkadot/PolkadotGetAddress.d.ts +1 -1
  65. package/dist/api/polkadot/networks.d.ts +1 -1
  66. package/dist/api/protocol-v2/DeviceUploadNft.d.ts +31 -0
  67. package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -0
  68. package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
  69. package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
  70. package/dist/api/solana/SolSignMessage.d.ts +1 -1
  71. package/dist/api/solana/SolSignOffchainMessage.d.ts +1 -1
  72. package/dist/api/solana/SolSignTransaction.d.ts +2 -2
  73. package/dist/api/sui/SuiGetAddress.d.ts +1 -1
  74. package/dist/api/sui/SuiGetPublicKey.d.ts +1 -1
  75. package/dist/api/sui/SuiSignMessage.d.ts +1 -1
  76. package/dist/api/sui/SuiSignTransaction.d.ts +1 -1
  77. package/dist/api/ton/TonGetAddress.d.ts +1 -1
  78. package/dist/api/ton/TonSignMessage.d.ts +1 -1
  79. package/dist/api/ton/TonSignProof.d.ts +1 -1
  80. package/dist/api/tron/TronSignMessage.d.ts +2 -2
  81. package/dist/api/tron/TronSignTransaction.d.ts +1 -1
  82. package/dist/core/deviceEventRegistration.d.ts +2 -0
  83. package/dist/core/deviceEventRegistration.d.ts.map +1 -1
  84. package/dist/core/index.d.ts.map +1 -1
  85. package/dist/core/uiPromiseRegistry.d.ts +6 -0
  86. package/dist/core/uiPromiseRegistry.d.ts.map +1 -0
  87. package/dist/data-manager/DataManager.d.ts +9 -3
  88. package/dist/data-manager/DataManager.d.ts.map +1 -1
  89. package/dist/data-manager/TransportManager.d.ts.map +1 -1
  90. package/dist/device/Device.d.ts +29 -5
  91. package/dist/device/Device.d.ts.map +1 -1
  92. package/dist/device/DeviceCommands.d.ts +4 -4
  93. package/dist/device/DeviceCommands.d.ts.map +1 -1
  94. package/dist/device/DeviceConnector.d.ts +2 -1
  95. package/dist/device/DeviceConnector.d.ts.map +1 -1
  96. package/dist/device/DevicePool.d.ts.map +1 -1
  97. package/dist/deviceProfile/protocolV2DeviceIdentity.d.ts.map +1 -1
  98. package/dist/events/device.d.ts +4 -0
  99. package/dist/events/device.d.ts.map +1 -1
  100. package/dist/events/logBlockEvent.d.ts.map +1 -1
  101. package/dist/events/ui-promise.d.ts +4 -2
  102. package/dist/events/ui-promise.d.ts.map +1 -1
  103. package/dist/events/ui-request.d.ts +31 -2
  104. package/dist/events/ui-request.d.ts.map +1 -1
  105. package/dist/events/ui-response.d.ts +10 -2
  106. package/dist/events/ui-response.d.ts.map +1 -1
  107. package/dist/index.d.ts +243 -69
  108. package/dist/index.js +2563 -1217
  109. package/dist/inject.d.ts +6 -1
  110. package/dist/inject.d.ts.map +1 -1
  111. package/dist/lowLevelInject.d.ts.map +1 -1
  112. package/dist/protocols/protocol-v2/features.d.ts +0 -4
  113. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  114. package/dist/protocols/protocol-v2/firmware.d.ts.map +1 -1
  115. package/dist/protocols/protocol-v2/resources.d.ts +30 -0
  116. package/dist/protocols/protocol-v2/resources.d.ts.map +1 -0
  117. package/dist/protocols/protocol-v2/uiInteraction.d.ts +7 -4
  118. package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -1
  119. package/dist/protocols/protocol-v2/unlockPolicy.d.ts +1 -3
  120. package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -1
  121. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +22 -0
  122. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -0
  123. package/dist/protocols/protocol-v2/walletSession.d.ts +6 -1
  124. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  125. package/dist/topLevelInject.d.ts.map +1 -1
  126. package/dist/types/api/checkAllFirmwareRelease.d.ts +3 -1
  127. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  128. package/dist/types/api/detectDeviceConnectProtocol.d.ts +4 -0
  129. package/dist/types/api/detectDeviceConnectProtocol.d.ts.map +1 -0
  130. package/dist/types/api/deviceUnlock.d.ts +5 -1
  131. package/dist/types/api/deviceUnlock.d.ts.map +1 -1
  132. package/dist/types/api/export.d.ts +1 -0
  133. package/dist/types/api/export.d.ts.map +1 -1
  134. package/dist/types/api/firmwareUpdate.d.ts +4 -2
  135. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  136. package/dist/types/api/index.d.ts +6 -1
  137. package/dist/types/api/index.d.ts.map +1 -1
  138. package/dist/types/api/protocolV2.d.ts +3 -0
  139. package/dist/types/api/protocolV2.d.ts.map +1 -1
  140. package/dist/types/device.d.ts +2 -2
  141. package/dist/types/device.d.ts.map +1 -1
  142. package/dist/types/params.d.ts +1 -0
  143. package/dist/types/params.d.ts.map +1 -1
  144. package/dist/types/settings.d.ts +38 -8
  145. package/dist/types/settings.d.ts.map +1 -1
  146. package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
  147. package/dist/utils/deviceFeaturesUtils.d.ts +4 -0
  148. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  149. package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
  150. package/dist/utils/deviceSettings.d.ts.map +1 -1
  151. package/dist/utils/homescreen.d.ts +4 -0
  152. package/dist/utils/homescreen.d.ts.map +1 -1
  153. package/dist/utils/index.d.ts +1 -1
  154. package/dist/utils/index.d.ts.map +1 -1
  155. package/dist/utils/patch.d.ts +1 -1
  156. package/dist/utils/patch.d.ts.map +1 -1
  157. package/dist/utils/pro2Nft.d.ts +31 -0
  158. package/dist/utils/pro2Nft.d.ts.map +1 -0
  159. package/dist/utils/pro2Wallpaper.d.ts +10 -0
  160. package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
  161. package/dist/utils/uiProgressThrottle.d.ts +3 -0
  162. package/dist/utils/uiProgressThrottle.d.ts.map +1 -0
  163. package/package.json +4 -4
  164. package/src/api/BaseMethod.ts +8 -10
  165. package/src/api/CheckAllFirmwareRelease.ts +61 -11
  166. package/src/api/DetectDeviceConnectProtocol.ts +18 -0
  167. package/src/api/FirmwareUpdate.ts +6 -2
  168. package/src/api/FirmwareUpdateV2.ts +5 -2
  169. package/src/api/FirmwareUpdateV3.ts +6 -2
  170. package/src/api/FirmwareUpdateV4.ts +463 -258
  171. package/src/api/GetPassphraseState.ts +7 -1
  172. package/src/api/OpenWalletSession.ts +71 -17
  173. package/src/api/SearchDevices.ts +3 -1
  174. package/src/api/allnetwork/AllNetworkGetAddress.ts +21 -21
  175. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +36 -11
  176. package/src/api/device/DeviceSettings.ts +5 -4
  177. package/src/api/device/DeviceUnlock.ts +8 -3
  178. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +27 -12
  179. package/src/api/firmware/uploadFirmware.ts +17 -4
  180. package/src/api/helpers/protocolV2FileWrite.ts +202 -63
  181. package/src/api/index.ts +2 -0
  182. package/src/api/kaspa/KaspaGetAddress.ts +1 -1
  183. package/src/api/kaspa/KaspaSignTransaction.ts +2 -13
  184. package/src/api/polkadot/networks.ts +3 -3
  185. package/src/api/protocol-v2/DeviceUploadNft.ts +197 -0
  186. package/src/api/protocol-v2/ProtocolInfoRequest.ts +3 -1
  187. package/src/api/protocol-v2/helpers.ts +1 -1
  188. package/src/api/solana/SolSignMessage.ts +1 -1
  189. package/src/api/solana/SolSignOffchainMessage.ts +1 -1
  190. package/src/api/solana/SolSignTransaction.ts +2 -2
  191. package/src/api/sui/SuiGetAddress.ts +1 -1
  192. package/src/api/sui/SuiGetPublicKey.ts +1 -1
  193. package/src/api/sui/SuiSignMessage.ts +1 -1
  194. package/src/api/sui/SuiSignTransaction.ts +1 -1
  195. package/src/api/ton/TonGetAddress.ts +1 -1
  196. package/src/api/ton/TonSignMessage.ts +1 -1
  197. package/src/api/ton/TonSignProof.ts +1 -1
  198. package/src/api/tron/TronSignMessage.ts +2 -2
  199. package/src/api/tron/TronSignTransaction.ts +1 -1
  200. package/src/core/deviceEventRegistration.ts +4 -0
  201. package/src/core/index.ts +213 -111
  202. package/src/core/uiPromiseRegistry.ts +63 -0
  203. package/src/data/messages/messages-protocol-v2.json +25 -0
  204. package/src/data-manager/DataManager.ts +88 -11
  205. package/src/data-manager/TransportManager.ts +6 -0
  206. package/src/device/Device.ts +273 -43
  207. package/src/device/DeviceCommands.ts +31 -4
  208. package/src/device/DeviceConnector.ts +33 -13
  209. package/src/device/DevicePool.ts +21 -7
  210. package/src/deviceProfile/buildDeviceFeatures.ts +2 -2
  211. package/src/deviceProfile/protocolV2DeviceIdentity.ts +3 -0
  212. package/src/events/device.ts +4 -0
  213. package/src/events/logBlockEvent.ts +1 -0
  214. package/src/events/ui-promise.ts +4 -2
  215. package/src/events/ui-request.ts +36 -2
  216. package/src/events/ui-response.ts +12 -2
  217. package/src/inject.ts +58 -2
  218. package/src/lowLevelInject.ts +6 -3
  219. package/src/protocols/protocol-v2/features.ts +10 -7
  220. package/src/protocols/protocol-v2/firmware.ts +2 -0
  221. package/src/protocols/protocol-v2/resources.ts +390 -0
  222. package/src/protocols/protocol-v2/uiInteraction.ts +46 -6
  223. package/src/protocols/protocol-v2/unlockPolicy.ts +1 -105
  224. package/src/protocols/protocol-v2/unlockPolicyRunner.ts +131 -0
  225. package/src/protocols/protocol-v2/walletSession.ts +214 -36
  226. package/src/topLevelInject.ts +6 -3
  227. package/src/types/api/checkAllFirmwareRelease.ts +3 -1
  228. package/src/types/api/detectDeviceConnectProtocol.ts +6 -0
  229. package/src/types/api/deviceUnlock.ts +12 -1
  230. package/src/types/api/export.ts +1 -0
  231. package/src/types/api/firmwareUpdate.ts +6 -3
  232. package/src/types/api/index.ts +13 -0
  233. package/src/types/api/protocolV2.ts +13 -0
  234. package/src/types/device.ts +15 -3
  235. package/src/types/params.ts +7 -1
  236. package/src/types/settings.ts +60 -9
  237. package/src/utils/deviceFeaturesCompat.ts +5 -0
  238. package/src/utils/deviceFeaturesUtils.ts +14 -3
  239. package/src/utils/deviceInfoUtils.ts +2 -0
  240. package/src/utils/deviceSettings.ts +3 -0
  241. package/src/utils/homescreen.ts +32 -6
  242. package/src/utils/index.ts +6 -1
  243. package/src/utils/pro2Nft.ts +142 -0
  244. package/src/utils/pro2Wallpaper.ts +35 -8
  245. package/src/utils/uiProgressThrottle.ts +63 -0
  246. package/dist/api/firmware/progressThrottle.d.ts +0 -3
  247. package/dist/api/firmware/progressThrottle.d.ts.map +0 -1
  248. package/dist/protocols/protocol-v2/lockedError.d.ts +0 -2
  249. package/dist/protocols/protocol-v2/lockedError.d.ts.map +0 -1
  250. package/dist/protocols/protocol-v2/unlockRetry.d.ts +0 -10
  251. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +0 -1
  252. package/src/api/firmware/progressThrottle.ts +0 -44
  253. package/src/protocols/protocol-v2/lockedError.ts +0 -10
  254. package/src/protocols/protocol-v2/unlockRetry.ts +0 -109
@@ -1,4 +1,5 @@
1
1
  import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
+ import { DeviceSessionPinType } from '@onekeyfe/hd-transport';
2
3
 
3
4
  import { UI_REQUEST } from '../constants/ui-request';
4
5
  import { refreshProtocolV2DeviceStatus } from '../protocols/protocol-v2/walletSession';
@@ -24,7 +25,12 @@ export default class GetPassphraseState extends BaseMethod {
24
25
  if (isProtocolV2 && this.payload.useEmptyPassphrase !== true) {
25
26
  const features = await refreshProtocolV2DeviceStatus(this.device);
26
27
  if (features.unlocked === false) {
27
- await this.device.unlockDevice();
28
+ await this.device.unlockDevice(DeviceSessionPinType.Main, {
29
+ source: 'unlock-coordinator',
30
+ reason: 'device-locked',
31
+ deviceOnly: true,
32
+ method: 'getPassphraseState',
33
+ });
28
34
  }
29
35
  }
30
36
  const { passphraseState } = await getPassphraseStateWithRefreshDeviceInfo(
@@ -1,4 +1,5 @@
1
1
  import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
+ import { DeviceSessionPinType } from '@onekeyfe/hd-transport';
2
3
 
3
4
  import { deviceWalletSessionStore } from '../device/DeviceWalletSessionStore';
4
5
  import { getProtocolV2WalletSession } from '../protocols/protocol-v2/walletSession';
@@ -83,6 +84,7 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
83
84
 
84
85
  init() {
85
86
  this.useDevicePassphraseState = false;
87
+ this.unlockPolicy = 'unlock-before-run';
86
88
  this.skipForceUpdateCheck = true;
87
89
  this.params = normalizeParams(this.payload as unknown as Record<string, unknown>);
88
90
  this.payload.useEmptyPassphrase = this.params.mode === OpenWalletSessionMode.Standard;
@@ -90,23 +92,40 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
90
92
 
91
93
  async run(): Promise<OpenWalletSessionPayload> {
92
94
  const isProtocolV2 = this.device.isProtocolV2();
93
- const state = await this.device.getDeviceState({ refreshSections: ['status'] });
95
+ let state = await this.device.getDeviceState({ refreshSections: ['status'] });
94
96
  let currentDeviceId = state.identity.deviceId;
97
+ const hasAuthoritativeProtocolV2WalletStatus = (candidate: typeof state) =>
98
+ candidate.status.unlocked === true &&
99
+ typeof candidate.status.passphraseProtection === 'boolean' &&
100
+ typeof candidate.status.unlockedAttachPin === 'boolean';
101
+ const requireAuthoritativeProtocolV2WalletStatus = (candidate: typeof state) => {
102
+ if (!hasAuthoritativeProtocolV2WalletStatus(candidate)) {
103
+ throw ERRORS.TypedError(HardwareErrorCode.DeviceInitializeFailed);
104
+ }
105
+ return candidate;
106
+ };
95
107
  const requireDeviceId = () => {
96
108
  if (!currentDeviceId) {
97
109
  throw ERRORS.TypedError(HardwareErrorCode.DeviceInitializeFailed);
98
110
  }
99
111
  return currentDeviceId;
100
112
  };
101
- const refreshProtocolV2DeviceId = async () => {
102
- const refreshedState = await this.device.getDeviceState({ refreshSections: ['status'] });
103
- currentDeviceId = refreshedState.identity.deviceId;
104
- return requireDeviceId();
113
+ const refreshProtocolV2DeviceState = async () => {
114
+ state = await this.device.getDeviceState({ refreshSections: ['status'] });
115
+ currentDeviceId = state.identity.deviceId;
116
+ return state;
105
117
  };
106
- const unlockProtocolV2IfLocked = async () => {
107
- if (isProtocolV2 && state.status.unlocked === false) {
108
- await this.device.unlockDevice();
118
+ const ensureProtocolV2WalletStatus = async () => {
119
+ if (isProtocolV2 && !hasAuthoritativeProtocolV2WalletStatus(state)) {
120
+ await this.device.unlockDevice(DeviceSessionPinType.Main, {
121
+ source: 'unlock-coordinator',
122
+ reason: 'device-locked',
123
+ deviceOnly: true,
124
+ method: 'openWalletSession',
125
+ });
126
+ requireAuthoritativeProtocolV2WalletStatus(await refreshProtocolV2DeviceState());
109
127
  }
128
+ return state;
110
129
  };
111
130
 
112
131
  const protocol = isProtocolV2 ? 'V2' : 'V1';
@@ -114,13 +133,25 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
114
133
  if (this.params.mode === OpenWalletSessionMode.Standard) {
115
134
  this.device.passphraseState = undefined;
116
135
  const session = isProtocolV2
117
- ? await getProtocolV2WalletSession(this.device, { onlyMainPin: true })
136
+ ? await getProtocolV2WalletSession(this.device, {
137
+ onlyMainPin: true,
138
+ deriveCardano: this.payload.deriveCardano,
139
+ selectMainWalletBeforeRestore:
140
+ !hasAuthoritativeProtocolV2WalletStatus(state) ||
141
+ state.status.unlockedAttachPin === true,
142
+ })
118
143
  : await getPassphraseStateWithRefreshDeviceInfo(this.device, {
119
144
  onlyMainPin: true,
120
145
  initSession: this.payload.initSession,
121
146
  });
122
- const deviceId = isProtocolV2 ? await refreshProtocolV2DeviceId() : requireDeviceId();
123
- if (session.unlockedAttachPin) {
147
+ const refreshedState = isProtocolV2
148
+ ? requireAuthoritativeProtocolV2WalletStatus(await refreshProtocolV2DeviceState())
149
+ : state;
150
+ const deviceId = requireDeviceId();
151
+ if (
152
+ session.unlockedAttachPin ||
153
+ (isProtocolV2 && refreshedState.status.unlockedAttachPin === true)
154
+ ) {
124
155
  try {
125
156
  await this.device.lockDevice();
126
157
  } catch {
@@ -140,8 +171,8 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
140
171
 
141
172
  if (this.params.mode === OpenWalletSessionMode.ResumeHidden) {
142
173
  if (isProtocolV2) {
143
- await unlockProtocolV2IfLocked();
144
- const refreshedDeviceId = await refreshProtocolV2DeviceId();
174
+ await ensureProtocolV2WalletStatus();
175
+ const refreshedDeviceId = requireDeviceId();
145
176
  if (refreshedDeviceId !== this.params.deviceId) {
146
177
  deviceWalletSessionStore.delete(this.params.deviceId, this.params.passphraseState);
147
178
  throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckDeviceIdError);
@@ -166,6 +197,7 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
166
197
  const session = isProtocolV2
167
198
  ? await getProtocolV2WalletSession(this.device, {
168
199
  expectedPassphraseState: this.params.passphraseState,
200
+ deriveCardano: this.payload.deriveCardano,
169
201
  })
170
202
  : await getPassphraseStateWithRefreshDeviceInfo(this.device, {
171
203
  expectPassphraseState: this.params.passphraseState,
@@ -185,15 +217,37 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
185
217
  }
186
218
 
187
219
  this.device.passphraseState = undefined;
188
- await unlockProtocolV2IfLocked();
220
+ const walletStatus = await ensureProtocolV2WalletStatus();
221
+ if (isProtocolV2 && walletStatus.status.passphraseProtection !== true) {
222
+ this.device.clearInternalState();
223
+ throw ERRORS.TypedError(HardwareErrorCode.DeviceNotOpenedPassphrase);
224
+ }
225
+ const readCurrentAttachPinSession =
226
+ isProtocolV2 && walletStatus.status.unlockedAttachPin === true;
189
227
  const session = isProtocolV2
190
- ? await getProtocolV2WalletSession(this.device, { forceWalletSelection: true })
228
+ ? await getProtocolV2WalletSession(this.device, {
229
+ ...(readCurrentAttachPinSession
230
+ ? { readCurrentAttachPinSession: true }
231
+ : { forceWalletSelection: true }),
232
+ deriveCardano: this.payload.deriveCardano,
233
+ })
191
234
  : await getPassphraseStateWithRefreshDeviceInfo(this.device, { initSession: true });
192
- const deviceId = isProtocolV2 ? await refreshProtocolV2DeviceId() : requireDeviceId();
193
- if (isProtocolV2 && this.device.getCurrentPassphraseProtection() !== true) {
235
+ const refreshedState = isProtocolV2
236
+ ? requireAuthoritativeProtocolV2WalletStatus(await refreshProtocolV2DeviceState())
237
+ : state;
238
+ const deviceId = requireDeviceId();
239
+ if (isProtocolV2 && refreshedState.status.passphraseProtection !== true) {
194
240
  this.device.clearInternalState();
195
241
  throw ERRORS.TypedError(HardwareErrorCode.DeviceNotOpenedPassphrase);
196
242
  }
243
+ if (
244
+ isProtocolV2 &&
245
+ readCurrentAttachPinSession &&
246
+ refreshedState.status.unlockedAttachPin !== true
247
+ ) {
248
+ this.device.clearInternalState();
249
+ throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckUnlockTypeError);
250
+ }
197
251
  const responseBase = {
198
252
  protocol,
199
253
  deviceId,
@@ -59,7 +59,9 @@ export default class SearchDevices extends BaseMethod {
59
59
  // Discovery is best effort. Browsers may retain WebUSB grants for devices that
60
60
  // are offline, busy, or not ready, so one descriptor must not abort the scan.
61
61
  const result = await DevicePool.getDevices([descriptor], descriptor.path, {
62
- connectProtocol: this.payload.connectProtocol,
62
+ // Discovery must actively identify the protocol instead of trusting a caller hint.
63
+ connectProtocol: undefined,
64
+ forceProtocolDetection: true,
63
65
  refreshRuntimeState: true,
64
66
  });
65
67
  deviceList.push(...result.deviceList);
@@ -24,24 +24,28 @@ export default class AllNetworkGetAddress extends AllNetworkGetAddressBase {
24
24
  const resultMap: Record<string, AllNetworkAddress> = {};
25
25
  const { bundle } = this.payload as AllNetworkGetAddressParams;
26
26
 
27
- const methodGroups = bundle
28
- .map((param, index) =>
29
- this.generateMethodName({
30
- network: param.network,
31
- payload: param,
32
- originalIndex: index,
33
- })
34
- )
35
- .reduce((acc, cur) => {
36
- if (!acc[cur.methodName]) {
37
- acc[cur.methodName] = [];
38
- }
39
- acc[cur.methodName].push(cur);
40
- return acc;
41
- }, {} as Record<keyof CoreApi, MethodParams[]>);
27
+ const methodParams = bundle.map((param, index) =>
28
+ this.generateMethodName({
29
+ network: param.network,
30
+ payload: param,
31
+ originalIndex: index,
32
+ })
33
+ );
34
+ const groupedMethodParams = methodParams.reduce((groups, param) => {
35
+ const group = groups.get(param.methodName) ?? [];
36
+ group.push(param);
37
+ groups.set(param.methodName, group);
38
+ return groups;
39
+ }, new Map<keyof CoreApi, MethodParams[]>());
40
+ const requiresProtocolV2WalletHandoff =
41
+ this.device.isProtocolV2() &&
42
+ (this.payload.useEmptyPassphrase === true || !!this.payload.passphraseState);
43
+ const methodGroups: [keyof CoreApi, MethodParams[]][] = requiresProtocolV2WalletHandoff
44
+ ? methodParams.map(param => [param.methodName, [param]])
45
+ : Array.from(groupedMethodParams.entries());
42
46
 
43
47
  let i = 0;
44
- for (const [methodName, params] of Object.entries(methodGroups)) {
48
+ for (const [methodName, params] of methodGroups) {
45
49
  const methodParams = {
46
50
  bundle: params.map(param => ({
47
51
  ...param.params,
@@ -52,11 +56,7 @@ export default class AllNetworkGetAddress extends AllNetworkGetAddressBase {
52
56
  throw new Error(HardwareErrorCodeMessage[HardwareErrorCode.RepeatUnlocking]);
53
57
  }
54
58
  // call method
55
- const response = await this.callMethod(
56
- methodName as keyof CoreApi,
57
- methodParams,
58
- rootFingerprint
59
- );
59
+ const response = await this.callMethod(methodName, methodParams, rootFingerprint);
60
60
 
61
61
  if (this.abortController?.signal.aborted) {
62
62
  throw new Error(HardwareErrorCodeMessage[HardwareErrorCode.RepeatUnlocking]);
@@ -14,6 +14,7 @@ import { findMethod } from '../utils';
14
14
  import { DEVICE, IFRAME, createUiMessage } from '../../events';
15
15
  import { UI_REQUEST } from '../../constants/ui-request';
16
16
  import { onDeviceButtonHandler } from '../../core';
17
+ import { runMethodWithUnlockPolicy } from '../../protocols/protocol-v2/unlockPolicyRunner';
17
18
  import {
18
19
  completeRequestContext,
19
20
  createRequestContext,
@@ -375,16 +376,38 @@ export default abstract class AllNetworkGetAddressBase extends BaseMethod<
375
376
  this.device.on(DEVICE.PASSPHRASE, onSignalAbort);
376
377
 
377
378
  preCheckDeviceSupport(this.device, method);
378
- if (this.temporarySafetyCheckPrompted) {
379
- method.temporarySafetyCheckPrompted = true;
380
- } else {
381
- const appliedTemporarySafetyCheck = await method.checkSafetyLevelOnTestNet();
382
- if (appliedTemporarySafetyCheck) {
383
- this.temporarySafetyCheckPrompted = true;
384
- }
385
- }
386
-
387
- const response = await method.run();
379
+ const response = await runMethodWithUnlockPolicy<any[]>(method, this.device, {
380
+ context: this.protocolV2UnlockContext,
381
+ prepare: async () => {
382
+ if (this.temporarySafetyCheckPrompted) {
383
+ method.temporarySafetyCheckPrompted = true;
384
+ } else {
385
+ const appliedTemporarySafetyCheck = await method.checkSafetyLevelOnTestNet();
386
+ if (appliedTemporarySafetyCheck) {
387
+ this.temporarySafetyCheckPrompted = true;
388
+ }
389
+ }
390
+
391
+ // Protocol V2 hands a wallet session to exactly one blockchain request.
392
+ // The parent all-network call consumes its first handoff while fetching
393
+ // the root fingerprint, so each nested chain method must resume the
394
+ // requested standard or hidden wallet before sending its device command.
395
+ const useEmptyPassphrase = this.payload.useEmptyPassphrase === true;
396
+ const deriveCardano = method.name.startsWith('cardano');
397
+ const shouldResumeWalletSession = useEmptyPassphrase || !!this.payload.passphraseState;
398
+ if (this.device.isProtocolV2() && shouldResumeWalletSession) {
399
+ const passphraseStateSafety = await this.device.checkPassphraseStateSafety(
400
+ this.payload.passphraseState,
401
+ useEmptyPassphrase,
402
+ this.payload.skipPassphraseCheck,
403
+ deriveCardano
404
+ );
405
+ if (!passphraseStateSafety) {
406
+ throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckPassphraseStateError);
407
+ }
408
+ }
409
+ },
410
+ });
388
411
 
389
412
  if (!Array.isArray(response) || response.length === 0) {
390
413
  throw new Error('No response');
@@ -439,7 +462,9 @@ export default abstract class AllNetworkGetAddressBase extends BaseMethod<
439
462
  show_display: false,
440
463
  });
441
464
 
442
- this.postMessage(createUiMessage(UI_REQUEST.CLOSE_UI_PIN_WINDOW));
465
+ if (!this.device.isProtocolV2()) {
466
+ this.postMessage(createUiMessage(UI_REQUEST.CLOSE_UI_PIN_WINDOW));
467
+ }
443
468
 
444
469
  if (res.message.root_fingerprint == null) {
445
470
  throw ERRORS.TypedError(HardwareErrorCode.CallMethodInvalidParameter);
@@ -7,7 +7,6 @@ import { validateParams } from '../helpers/paramsValidator';
7
7
  import {
8
8
  mapApplySettingsToState,
9
9
  mapCommonSettingsToProtocolV2,
10
- mapDeviceSettingsToState,
11
10
  } from '../../device/DeviceStateMapper';
12
11
  import { getProtocolV2SettingsBehavior } from '../../protocols/protocol-v2/settingsUnlockPolicy';
13
12
  import {
@@ -163,6 +162,8 @@ export default class DeviceSettings extends BaseMethod<ApplySettings> {
163
162
  async run() {
164
163
  try {
165
164
  if (this.device.isProtocolV2()) {
165
+ const refreshStatusAndSettings = () =>
166
+ this.device.getDeviceState({ refreshSections: ['status', 'settings'] });
166
167
  assertSettingsSupported(this.payload, DEVICE_SETTINGS_V1_ONLY_FIELDS, 'Protocol V2');
167
168
  const capabilities = getDeviceSettingsCapabilities(
168
169
  this.device.getCurrentDeviceType(),
@@ -194,7 +195,7 @@ export default class DeviceSettings extends BaseMethod<ApplySettings> {
194
195
  const res = await this.device.commands.typedCall('DeviceSettingsPageShow', 'Success', {
195
196
  page: DeviceSettingsPage.DevicePassphrase,
196
197
  });
197
- const updated = await this.device.getDeviceState({ refreshSections: ['status'] });
198
+ const updated = await refreshStatusAndSettings();
198
199
  const lockedAfterDisabling =
199
200
  requestedPassphrase === false &&
200
201
  current.status.unlocked === true &&
@@ -219,7 +220,7 @@ export default class DeviceSettings extends BaseMethod<ApplySettings> {
219
220
  const res = await this.device.commands.typedCall('DeviceSettingsPageShow', 'Success', {
220
221
  page: DeviceSettingsPage.DeviceAirgap,
221
222
  });
222
- const updated = await this.device.getDeviceState({ refreshSections: ['settings'] });
223
+ const updated = await refreshStatusAndSettings();
223
224
  if (updated.settings.airgapMode !== requestedAirgap) {
224
225
  throw TypedError(
225
226
  HardwareErrorCode.RuntimeError,
@@ -235,7 +236,7 @@ export default class DeviceSettings extends BaseMethod<ApplySettings> {
235
236
  const res = await this.device.commands.typedCall('DeviceSettingsSet', 'Success', {
236
237
  settings,
237
238
  });
238
- this.device.updateState(mapDeviceSettingsToState(settings), 'settings-write');
239
+ await refreshStatusAndSettings();
239
240
  return res.message;
240
241
  }
241
242
 
@@ -1,13 +1,18 @@
1
+ import { DeviceSessionPinType } from '@onekeyfe/hd-transport';
2
+
1
3
  import { BaseMethod } from '../BaseMethod';
2
4
 
3
- import type { LockDevice } from '@onekeyfe/hd-transport';
5
+ import type { DeviceUnlockParams } from '../../types/api/deviceUnlock';
4
6
 
5
- export default class DeviceUnlock extends BaseMethod<LockDevice> {
7
+ export default class DeviceUnlock extends BaseMethod<DeviceUnlockParams> {
6
8
  getSupportedProtocols() {
7
9
  return ['V1', 'V2'] as const;
8
10
  }
9
11
 
10
12
  init() {
13
+ this.params = {
14
+ pinType: this.payload.pinType ?? DeviceSessionPinType.Main,
15
+ };
11
16
  this.useDevicePassphraseState = false;
12
17
  this.unlockPolicy = 'none';
13
18
  this.protocolV2UiInteraction = {
@@ -21,6 +26,6 @@ export default class DeviceUnlock extends BaseMethod<LockDevice> {
21
26
  }
22
27
 
23
28
  async run() {
24
- return this.device.unlockDevice();
29
+ return this.device.unlockDevice(this.params.pinType, { emitUiEvent: false });
25
30
  }
26
31
  }
@@ -13,10 +13,10 @@ import { DeviceModelToTypes } from '../../types';
13
13
  import { DataManager } from '../../data-manager';
14
14
  import { BaseMethod } from '../BaseMethod';
15
15
  import { DEVICE } from '../../events';
16
- import { createFirmwareProgressThrottle } from './progressThrottle';
17
16
  import { writeFirmwareByteSource } from './FirmwareArtifactSource';
18
17
 
19
18
  import type {
19
+ FirmwareProgress,
20
20
  IFirmwareUpdateProgressType,
21
21
  IFirmwareUpdateTipMessage,
22
22
  } from '../../events/ui-request';
@@ -41,6 +41,11 @@ const FIRMWARE_UPDATE_CONFIRM = 'Firmware install confirmed';
41
41
  */
42
42
  export const BOOTLOADER_POLL_INITIALIZE_TIMEOUT_MS = 5000;
43
43
 
44
+ type FirmwareTransferMetrics = Pick<
45
+ FirmwareProgress['payload'],
46
+ 'transferredBytes' | 'totalBytes' | 'rateBytesPerSecond' | 'elapsedMs'
47
+ >;
48
+
44
49
  const isDeviceDisconnectedError = (error: unknown) => {
45
50
  const message = error instanceof Error ? error.message : String(error ?? '');
46
51
  return (
@@ -53,8 +58,6 @@ const isDeviceDisconnectedError = (error: unknown) => {
53
58
  export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
54
59
  checkPromise: Deferred<any> | null = null;
55
60
 
56
- private shouldPostFirmwareProgress = createFirmwareProgressThrottle();
57
-
58
61
  init(): void {}
59
62
 
60
63
  run(): Promise<any> {
@@ -97,16 +100,17 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
97
100
  * @description Post the progress message
98
101
  * @param progress Post the percentage of the progress
99
102
  */
100
- postProgressMessage = (progress: number, progressType: IFirmwareUpdateProgressType) => {
101
- if (!this.shouldPostFirmwareProgress(progress, progressType)) {
102
- return;
103
- }
104
-
103
+ postProgressMessage = (
104
+ progress: number,
105
+ progressType: IFirmwareUpdateProgressType,
106
+ metrics?: FirmwareTransferMetrics
107
+ ) => {
105
108
  this.postMessage(
106
109
  createUiMessage(UI_REQUEST.FIRMWARE_PROGRESS, {
107
110
  device: this.device.toMessageObject() as KnownDevice,
108
111
  progress,
109
112
  progressType,
113
+ ...metrics,
110
114
  })
111
115
  );
112
116
  };
@@ -216,7 +220,8 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
216
220
  await this.device.deviceConnector?.acquire(
217
221
  this.device.originalDescriptor.id,
218
222
  null,
219
- true
223
+ true,
224
+ this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType
220
225
  );
221
226
  // Bound each probe so a request the rebooting device never received
222
227
  // frees the slot for the next tick instead of hanging into the
@@ -255,7 +260,9 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
255
260
  ) {
256
261
  const deviceDiff = await this.device.deviceConnector?.enumerate();
257
262
  const devicesDescriptor = deviceDiff?.descriptors ?? [];
258
- const { deviceList } = await DevicePool.getDevices(devicesDescriptor, connectId);
263
+ const { deviceList } = await DevicePool.getDevices(devicesDescriptor, connectId, {
264
+ connectProtocol: this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType,
265
+ });
259
266
 
260
267
  if (deviceList.length === 1 && deviceList[0]?.isBootloader()) {
261
268
  // should update current device from cache
@@ -512,7 +519,12 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
512
519
  const env = DataManager.getSettings('env');
513
520
  if (DataManager.isBleConnect(env)) {
514
521
  await wait(3000);
515
- await this.device.deviceConnector?.acquire(this.device.originalDescriptor.id, null, true);
522
+ await this.device.deviceConnector?.acquire(
523
+ this.device.originalDescriptor.id,
524
+ null,
525
+ true,
526
+ this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType
527
+ );
516
528
  await this.device.initialize();
517
529
  } else if (
518
530
  error?.message?.indexOf(SESSION_ERROR) > -1 ||
@@ -520,7 +532,10 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
520
532
  ) {
521
533
  const deviceDiff = await this.device.deviceConnector?.enumerate();
522
534
  const devicesDescriptor = deviceDiff?.descriptors ?? [];
523
- const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined);
535
+ const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined, {
536
+ connectProtocol:
537
+ this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType,
538
+ });
524
539
  if (deviceList.length === 1 && deviceList[0]?.isBootloader()) {
525
540
  this.device.updateFromCache(deviceList[0]);
526
541
  await this.device.acquire();
@@ -362,7 +362,12 @@ const newTouchUpdateProcess = async (
362
362
  try {
363
363
  if (isBleReconnect) {
364
364
  try {
365
- await device.deviceConnector?.acquire(device.originalDescriptor.id, null, true);
365
+ await device.deviceConnector?.acquire(
366
+ device.originalDescriptor.id,
367
+ null,
368
+ true,
369
+ device.originalDescriptor.protocolType
370
+ );
366
371
  const typedCall = device.getCommands().typedCall.bind(device.getCommands());
367
372
  await Promise.race([
368
373
  typedCall('Initialize', 'Features', {}),
@@ -381,7 +386,8 @@ const newTouchUpdateProcess = async (
381
386
  const devicesDescriptor = deviceDiff?.descriptors ?? [];
382
387
  const { deviceList } = await DevicePool.getDevices(
383
388
  devicesDescriptor,
384
- device.originalDescriptor.id
389
+ device.originalDescriptor.id,
390
+ { connectProtocol: device.originalDescriptor.protocolType }
385
391
  );
386
392
  if (deviceList.length === 1) {
387
393
  device.updateFromCache(deviceList[0]);
@@ -456,7 +462,12 @@ const emmcFileWriteWithRetry = async (
456
462
  const env = DataManager.getSettings('env');
457
463
  if (DataManager.isBleConnect(env)) {
458
464
  await wait(3000);
459
- await device.deviceConnector?.acquire(device.originalDescriptor.id, null, true);
465
+ await device.deviceConnector?.acquire(
466
+ device.originalDescriptor.id,
467
+ null,
468
+ true,
469
+ device.originalDescriptor.protocolType
470
+ );
460
471
  await device.initialize();
461
472
  } else if (
462
473
  error?.message?.indexOf(SESSION_ERROR) > -1 ||
@@ -464,7 +475,9 @@ const emmcFileWriteWithRetry = async (
464
475
  ) {
465
476
  const deviceDiff = await device.deviceConnector?.enumerate();
466
477
  const devicesDescriptor = deviceDiff?.descriptors ?? [];
467
- const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined);
478
+ const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined, {
479
+ connectProtocol: device.originalDescriptor.protocolType,
480
+ });
468
481
  if (deviceList.length === 1 && deviceList[0]?.isBootloader()) {
469
482
  device.updateFromCache(deviceList[0]);
470
483
  await device.acquire();