@onekeyfe/hd-core 1.2.0-alpha.52 → 1.2.0-alpha.53

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 (251) hide show
  1. package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +78 -0
  2. package/__tests__/DeviceCommands.test.ts +45 -0
  3. package/__tests__/DeviceEventRegistration.test.ts +6 -0
  4. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +198 -3
  5. package/__tests__/connectSettings.test.ts +5 -47
  6. package/__tests__/device-lifecycle-events.test.ts +105 -3
  7. package/__tests__/deviceUploadNft.test.ts +293 -0
  8. package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +31 -59
  9. package/__tests__/get-device-state.test.ts +132 -12
  10. package/__tests__/homescreen.test.ts +41 -1
  11. package/__tests__/logBlockEvent.test.ts +1 -1
  12. package/__tests__/method-protocol-support.test.ts +19 -0
  13. package/__tests__/open-wallet-session.test.ts +446 -33
  14. package/__tests__/pro2Nft.test.ts +108 -0
  15. package/__tests__/protocol-binding.test.ts +89 -0
  16. package/__tests__/protocol-v2-resources.test.ts +284 -0
  17. package/__tests__/protocol-v2-ui-lifecycle.test.ts +91 -0
  18. package/__tests__/protocol-v2-unlock-policy.test.ts +201 -35
  19. package/__tests__/protocol-v2.test.ts +1349 -1005
  20. package/__tests__/protocolV2UiInteraction.test.ts +63 -0
  21. package/__tests__/public-pro2-api-boundary.test.ts +1 -0
  22. package/__tests__/search-devices.test.ts +12 -3
  23. package/__tests__/uiProgressThrottle.test.ts +74 -0
  24. package/__tests__/uiPromiseRegistry.test.ts +86 -0
  25. package/dist/api/BaseMethod.d.ts +3 -1
  26. package/dist/api/BaseMethod.d.ts.map +1 -1
  27. package/dist/api/CheckAllFirmwareRelease.d.ts +2 -1
  28. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  29. package/dist/api/DetectDeviceConnectProtocol.d.ts +7 -0
  30. package/dist/api/DetectDeviceConnectProtocol.d.ts.map +1 -0
  31. package/dist/api/FirmwareUpdate.d.ts.map +1 -1
  32. package/dist/api/FirmwareUpdateV2.d.ts +0 -11
  33. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  34. package/dist/api/FirmwareUpdateV3.d.ts +3 -7
  35. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  36. package/dist/api/FirmwareUpdateV4.d.ts +11 -25
  37. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  38. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  39. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  40. package/dist/api/SearchDevices.d.ts.map +1 -1
  41. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  42. package/dist/api/device/DeviceUnlock.d.ts +2 -2
  43. package/dist/api/device/DeviceUnlock.d.ts.map +1 -1
  44. package/dist/api/device/DeviceUpdateBootloader.d.ts +1 -5
  45. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  46. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +0 -9
  47. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  48. package/dist/api/firmware/getBinary.d.ts +0 -7
  49. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  50. package/dist/api/firmware/updateBootloader.d.ts +0 -2
  51. package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
  52. package/dist/api/firmware/uploadFirmware.d.ts +1 -9
  53. package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
  54. package/dist/api/helpers/protocolV2FileWrite.d.ts +2 -0
  55. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
  56. package/dist/api/index.d.ts +2 -0
  57. package/dist/api/index.d.ts.map +1 -1
  58. package/dist/api/protocol-v2/DeviceUploadNft.d.ts +31 -0
  59. package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -0
  60. package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
  61. package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
  62. package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
  63. package/dist/core/deviceEventRegistration.d.ts +2 -0
  64. package/dist/core/deviceEventRegistration.d.ts.map +1 -1
  65. package/dist/core/index.d.ts.map +1 -1
  66. package/dist/core/uiPromiseRegistry.d.ts +4 -0
  67. package/dist/core/uiPromiseRegistry.d.ts.map +1 -0
  68. package/dist/data-manager/DataManager.d.ts +4 -2
  69. package/dist/data-manager/DataManager.d.ts.map +1 -1
  70. package/dist/data-manager/connectSettings.d.ts.map +1 -1
  71. package/dist/device/Device.d.ts +29 -6
  72. package/dist/device/Device.d.ts.map +1 -1
  73. package/dist/device/DeviceCommands.d.ts +4 -4
  74. package/dist/device/DeviceCommands.d.ts.map +1 -1
  75. package/dist/device/DevicePool.d.ts.map +1 -1
  76. package/dist/events/device.d.ts +4 -0
  77. package/dist/events/device.d.ts.map +1 -1
  78. package/dist/events/logBlockEvent.d.ts.map +1 -1
  79. package/dist/events/ui-promise.d.ts +4 -2
  80. package/dist/events/ui-promise.d.ts.map +1 -1
  81. package/dist/events/ui-request.d.ts +31 -2
  82. package/dist/events/ui-request.d.ts.map +1 -1
  83. package/dist/events/ui-response.d.ts +10 -2
  84. package/dist/events/ui-response.d.ts.map +1 -1
  85. package/dist/index.d.ts +214 -231
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +2559 -3497
  88. package/dist/inject.d.ts +6 -1
  89. package/dist/inject.d.ts.map +1 -1
  90. package/dist/lowLevelInject.d.ts.map +1 -1
  91. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  92. package/dist/protocols/protocol-v2/resources.d.ts +30 -0
  93. package/dist/protocols/protocol-v2/resources.d.ts.map +1 -0
  94. package/dist/protocols/protocol-v2/uiInteraction.d.ts +7 -4
  95. package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -1
  96. package/dist/protocols/protocol-v2/unlockPolicy.d.ts +1 -3
  97. package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -1
  98. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +22 -0
  99. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -0
  100. package/dist/protocols/protocol-v2/walletSession.d.ts +5 -1
  101. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  102. package/dist/topLevelInject.d.ts.map +1 -1
  103. package/dist/types/api/checkAllFirmwareRelease.d.ts +2 -4
  104. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  105. package/dist/types/api/detectDeviceConnectProtocol.d.ts +4 -0
  106. package/dist/types/api/detectDeviceConnectProtocol.d.ts.map +1 -0
  107. package/dist/types/api/deviceUnlock.d.ts +5 -1
  108. package/dist/types/api/deviceUnlock.d.ts.map +1 -1
  109. package/dist/types/api/deviceUpdateBootloader.d.ts +0 -6
  110. package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
  111. package/dist/types/api/export.d.ts +2 -4
  112. package/dist/types/api/export.d.ts.map +1 -1
  113. package/dist/types/api/firmwareUpdate.d.ts +2 -70
  114. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  115. package/dist/types/api/index.d.ts +7 -10
  116. package/dist/types/api/index.d.ts.map +1 -1
  117. package/dist/types/api/protocolV2.d.ts +3 -0
  118. package/dist/types/api/protocolV2.d.ts.map +1 -1
  119. package/dist/types/device.d.ts.map +1 -1
  120. package/dist/types/params.d.ts +1 -0
  121. package/dist/types/params.d.ts.map +1 -1
  122. package/dist/types/settings.d.ts +22 -13
  123. package/dist/types/settings.d.ts.map +1 -1
  124. package/dist/utils/deviceFeaturesCompat.d.ts +0 -1
  125. package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
  126. package/dist/utils/deviceFeaturesUtils.d.ts +4 -0
  127. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  128. package/dist/utils/homescreen.d.ts +4 -0
  129. package/dist/utils/homescreen.d.ts.map +1 -1
  130. package/dist/utils/index.d.ts +1 -1
  131. package/dist/utils/index.d.ts.map +1 -1
  132. package/dist/utils/patch.d.ts +1 -1
  133. package/dist/utils/patch.d.ts.map +1 -1
  134. package/dist/utils/pro2Nft.d.ts +31 -0
  135. package/dist/utils/pro2Nft.d.ts.map +1 -0
  136. package/dist/utils/pro2Wallpaper.d.ts +10 -0
  137. package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
  138. package/dist/utils/uiProgressThrottle.d.ts +3 -0
  139. package/dist/utils/uiProgressThrottle.d.ts.map +1 -0
  140. package/package.json +4 -4
  141. package/src/api/BaseMethod.ts +8 -10
  142. package/src/api/CheckAllFirmwareRelease.ts +54 -57
  143. package/src/api/DetectDeviceConnectProtocol.ts +18 -0
  144. package/src/api/FirmwareUpdate.ts +7 -15
  145. package/src/api/FirmwareUpdateV2.ts +126 -316
  146. package/src/api/FirmwareUpdateV3.ts +63 -265
  147. package/src/api/FirmwareUpdateV4.ts +566 -965
  148. package/src/api/GetPassphraseState.ts +7 -1
  149. package/src/api/OpenWalletSession.ts +54 -17
  150. package/src/api/SearchDevices.ts +3 -1
  151. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +32 -11
  152. package/src/api/device/DeviceUnlock.ts +8 -3
  153. package/src/api/device/DeviceUpdateBootloader.ts +6 -122
  154. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +16 -83
  155. package/src/api/firmware/updateBootloader.ts +4 -19
  156. package/src/api/firmware/uploadFirmware.ts +39 -144
  157. package/src/api/helpers/protocolV2FileWrite.ts +11 -4
  158. package/src/api/index.ts +2 -0
  159. package/src/api/protocol-v2/DeviceUploadNft.ts +189 -0
  160. package/src/api/protocol-v2/ProtocolInfoRequest.ts +3 -1
  161. package/src/api/protocol-v2/helpers.ts +1 -0
  162. package/src/core/deviceEventRegistration.ts +4 -0
  163. package/src/core/index.ts +167 -83
  164. package/src/core/uiPromiseRegistry.ts +41 -0
  165. package/src/data/messages/messages-protocol-v2.json +25 -0
  166. package/src/data-manager/DataManager.ts +67 -38
  167. package/src/data-manager/connectSettings.ts +0 -11
  168. package/src/device/Device.ts +258 -42
  169. package/src/device/DeviceCommands.ts +7 -1
  170. package/src/device/DevicePool.ts +7 -2
  171. package/src/events/device.ts +4 -0
  172. package/src/events/logBlockEvent.ts +1 -0
  173. package/src/events/ui-promise.ts +4 -2
  174. package/src/events/ui-request.ts +36 -2
  175. package/src/events/ui-response.ts +12 -2
  176. package/src/index.ts +0 -5
  177. package/src/inject.ts +60 -24
  178. package/src/lowLevelInject.ts +7 -8
  179. package/src/protocols/protocol-v2/features.ts +10 -3
  180. package/src/protocols/protocol-v2/resources.ts +359 -0
  181. package/src/protocols/protocol-v2/uiInteraction.ts +46 -6
  182. package/src/protocols/protocol-v2/unlockPolicy.ts +1 -105
  183. package/src/protocols/protocol-v2/unlockPolicyRunner.ts +118 -0
  184. package/src/protocols/protocol-v2/walletSession.ts +180 -30
  185. package/src/topLevelInject.ts +7 -8
  186. package/src/types/api/checkAllFirmwareRelease.ts +2 -4
  187. package/src/types/api/detectDeviceConnectProtocol.ts +7 -0
  188. package/src/types/api/deviceUnlock.ts +12 -1
  189. package/src/types/api/deviceUpdateBootloader.ts +0 -6
  190. package/src/types/api/export.ts +1 -18
  191. package/src/types/api/firmwareUpdate.ts +3 -76
  192. package/src/types/api/index.ts +13 -14
  193. package/src/types/api/protocolV2.ts +13 -0
  194. package/src/types/device.ts +3 -0
  195. package/src/types/params.ts +7 -1
  196. package/src/types/settings.ts +42 -13
  197. package/src/utils/deviceFeaturesCompat.ts +0 -6
  198. package/src/utils/deviceFeaturesUtils.ts +8 -0
  199. package/src/utils/homescreen.ts +32 -6
  200. package/src/utils/index.ts +6 -1
  201. package/src/utils/pro2Nft.ts +142 -0
  202. package/src/utils/pro2Wallpaper.ts +35 -8
  203. package/src/utils/uiProgressThrottle.ts +63 -0
  204. package/__tests__/device-initialize-timeout.test.ts +0 -56
  205. package/__tests__/firmware-update/check-all-firmware-release.test.ts +0 -175
  206. package/__tests__/firmware-update/firmware-artifact-source.test.ts +0 -119
  207. package/__tests__/firmware-update/firmware-host-binding.test.ts +0 -70
  208. package/__tests__/firmware-update/firmware-preparation-error.test.ts +0 -27
  209. package/__tests__/firmware-update/firmware-update-bootloader-poll.test.ts +0 -200
  210. package/__tests__/firmware-update/firmware-update-capabilities.test.ts +0 -13
  211. package/__tests__/firmware-update/firmware-update-plan-bootloader-identity.test.ts +0 -294
  212. package/__tests__/firmware-update/firmware-update-plan.test.ts +0 -593
  213. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +0 -213
  214. package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +0 -58
  215. package/__tests__/firmware-update/firmware-upload-source.test.ts +0 -70
  216. package/dist/api/firmware/FirmwareArtifactSource.d.ts +0 -25
  217. package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +0 -1
  218. package/dist/api/firmware/FirmwareHostBinding.d.ts +0 -6
  219. package/dist/api/firmware/FirmwareHostBinding.d.ts.map +0 -1
  220. package/dist/api/firmware/FirmwarePreparationError.d.ts +0 -3
  221. package/dist/api/firmware/FirmwarePreparationError.d.ts.map +0 -1
  222. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +0 -3
  223. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +0 -1
  224. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -25
  225. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +0 -1
  226. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +0 -32
  227. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +0 -1
  228. package/dist/api/firmware/progressThrottle.d.ts +0 -3
  229. package/dist/api/firmware/progressThrottle.d.ts.map +0 -1
  230. package/dist/protocols/protocol-v2/lockedError.d.ts +0 -2
  231. package/dist/protocols/protocol-v2/lockedError.d.ts.map +0 -1
  232. package/dist/protocols/protocol-v2/unlockRetry.d.ts +0 -10
  233. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +0 -1
  234. package/dist/types/api/firmwareUpdateCapabilities.d.ts +0 -9
  235. package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +0 -1
  236. package/dist/types/api/firmwareUpdatePlan.d.ts +0 -28
  237. package/dist/types/api/firmwareUpdatePlan.d.ts.map +0 -1
  238. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +0 -42
  239. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +0 -1
  240. package/src/api/firmware/FirmwareArtifactSource.ts +0 -278
  241. package/src/api/firmware/FirmwareHostBinding.ts +0 -100
  242. package/src/api/firmware/FirmwarePreparationError.ts +0 -12
  243. package/src/api/firmware/FirmwareUpdateCapabilities.ts +0 -9
  244. package/src/api/firmware/FirmwareUpdatePlan.ts +0 -772
  245. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +0 -415
  246. package/src/api/firmware/progressThrottle.ts +0 -44
  247. package/src/protocols/protocol-v2/lockedError.ts +0 -10
  248. package/src/protocols/protocol-v2/unlockRetry.ts +0 -109
  249. package/src/types/api/firmwareUpdateCapabilities.ts +0 -9
  250. package/src/types/api/firmwareUpdatePlan.ts +0 -38
  251. package/src/types/api/firmwareUpdatePreparedPlan.ts +0 -53
@@ -10,7 +10,6 @@ import { bytesToHex } from '../helpers/hexUtils';
10
10
  import { DataManager } from '../../data-manager';
11
11
  import { DevicePool } from '../../device/DevicePool';
12
12
  import { buildProtocolV1FeaturesPayload } from '../../deviceProfile';
13
- import { openFirmwareByteSource, readFirmwareByteSourceFully } from './FirmwareArtifactSource';
14
13
 
15
14
  import type { KnownDevice } from '../../types';
16
15
  import type { TypedCall, TypedResponseMessage } from '../../device/DeviceCommands';
@@ -18,7 +17,6 @@ import type { PROTO } from '../../constants';
18
17
  import type { CoreMessage, IFirmwareUpdateProgressType } from '../../events';
19
18
  import type { Success } from '@onekeyfe/hd-transport';
20
19
  import type { Device } from '../../device/Device';
21
- import type { FirmwareByteSource } from './FirmwareArtifactSource';
22
20
 
23
21
  const NEW_BOOT_UPRATE_FIRMWARE_VERSION = '2.4.5';
24
22
  const SESSION_ERROR = 'session not found';
@@ -90,20 +88,17 @@ export const waitBleInstall = async (updateType: string) => {
90
88
  }
91
89
  };
92
90
 
93
- const toArrayBuffer = (payload: ArrayBuffer | Buffer): ArrayBuffer => {
94
- if (payload instanceof ArrayBuffer) {
95
- return payload;
96
- }
97
- return new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength).slice().buffer;
98
- };
99
-
100
- export const uploadFirmwareFromSource = async (
91
+ export const uploadFirmware = async (
101
92
  updateType: 'firmware' | 'ble',
102
93
  typedCall: TypedCall,
103
94
  postMessage: (message: CoreMessage) => void,
104
95
  device: Device,
105
- source: FirmwareByteSource,
106
- rebootOnSuccess?: boolean,
96
+ {
97
+ payload,
98
+ rebootOnSuccess,
99
+ }: PROTO.FirmwareUpload & {
100
+ rebootOnSuccess?: boolean;
101
+ },
107
102
  isUpdateBootloader?: boolean
108
103
  ) => {
109
104
  const deviceType = device.getCurrentDeviceType();
@@ -124,20 +119,20 @@ export const uploadFirmwareFromSource = async (
124
119
  if (supportUpgradeFileHeader) {
125
120
  // Extract and validate firmware header (first 1KB)
126
121
  const HEADER_SIZE = 1024;
127
- if (source.size < HEADER_SIZE) {
122
+ if (payload.byteLength < HEADER_SIZE) {
128
123
  throw ERRORS.TypedError(
129
124
  HardwareErrorCode.RuntimeError,
130
- `firmware payload too small: ${source.size} bytes, expected at least ${HEADER_SIZE} bytes`
125
+ `firmware payload too small: ${payload.byteLength} bytes, expected at least ${HEADER_SIZE} bytes`
131
126
  );
132
127
  }
133
128
 
134
129
  Log.debug('Uploading firmware header:', {
135
130
  size: HEADER_SIZE,
136
- totalSize: source.size,
131
+ totalSize: payload.byteLength,
137
132
  });
138
133
  postProgressTip(device, 'UploadingFirmwareHeader', postMessage);
139
134
 
140
- const header = new Uint8Array(await source.readAt(0, HEADER_SIZE));
135
+ const header = new Uint8Array(payload.slice(0, HEADER_SIZE));
141
136
 
142
137
  try {
143
138
  const headerRes = await typedCall('UpgradeFileHeader', 'Success', {
@@ -174,9 +169,6 @@ export const uploadFirmwareFromSource = async (
174
169
  postProgressMessage(device, 0, 'installingFirmware', postMessage);
175
170
  let updateResponse: TypedResponseMessage<'Success'>;
176
171
  try {
177
- // Classic/Mini bootloaders accept one protobuf payload and do not expose
178
- // a request-range protocol. Other device families remain fully streamed.
179
- const payload = await readFirmwareByteSourceFully(source);
180
172
  updateResponse = await typedCall('FirmwareUpload', 'Success', {
181
173
  payload,
182
174
  });
@@ -208,7 +200,9 @@ export const uploadFirmwareFromSource = async (
208
200
  updateType,
209
201
  postMessage,
210
202
  device,
211
- source,
203
+ {
204
+ payload,
205
+ },
212
206
  rebootOnSuccess
213
207
  );
214
208
  return response.message;
@@ -217,7 +211,7 @@ export const uploadFirmwareFromSource = async (
217
211
 
218
212
  postConfirmationMessage(device);
219
213
  postProgressTip(device, 'ConfirmOnDevice', postMessage);
220
- const length = source.size;
214
+ const length = payload.byteLength;
221
215
 
222
216
  let response = await typedCall('FirmwareErase', ['FirmwareRequest', 'Success'], { length });
223
217
  postProgressTip(device, 'FirmwareEraseSuccess', postMessage);
@@ -226,7 +220,7 @@ export const uploadFirmwareFromSource = async (
226
220
  const start = response.message.offset!;
227
221
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
228
222
  const end = response.message.offset! + response.message.length!;
229
- const chunk = await source.readAt(start, end - start);
223
+ const chunk = payload.slice(start, end);
230
224
 
231
225
  if (start > 0) {
232
226
  postProgressMessage(
@@ -255,45 +249,11 @@ export const uploadFirmwareFromSource = async (
255
249
  throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'uploadFirmware: unknown device model');
256
250
  };
257
251
 
258
- export const uploadFirmware = async (
259
- updateType: 'firmware' | 'ble',
260
- typedCall: TypedCall,
261
- postMessage: (message: CoreMessage) => void,
262
- device: Device,
263
- {
264
- payload,
265
- rebootOnSuccess,
266
- }: PROTO.FirmwareUpload & {
267
- rebootOnSuccess?: boolean;
268
- },
269
- isUpdateBootloader?: boolean
270
- ) => {
271
- const source = await openFirmwareByteSource({
272
- binary: toArrayBuffer(payload),
273
- });
274
- if (!source) {
275
- throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'firmware payload is empty');
276
- }
277
- try {
278
- return await uploadFirmwareFromSource(
279
- updateType,
280
- typedCall,
281
- postMessage,
282
- device,
283
- source,
284
- rebootOnSuccess,
285
- isUpdateBootloader
286
- );
287
- } finally {
288
- await source.close();
289
- }
290
- };
291
-
292
252
  const newTouchUpdateProcess = async (
293
253
  updateType: 'firmware' | 'ble',
294
254
  postMessage: (message: CoreMessage) => void,
295
255
  device: Device,
296
- source: FirmwareByteSource,
256
+ { payload }: PROTO.FirmwareUpload,
297
257
  rebootOnSuccess = true
298
258
  ) => {
299
259
  let typedCall = device.getCommands().typedCall.bind(device.getCommands());
@@ -303,13 +263,13 @@ const newTouchUpdateProcess = async (
303
263
  const env = DataManager.getSettings('env');
304
264
  const perPackageSize = DataManager.isBleConnect(env) ? 16 : 128;
305
265
  const chunkSize = 1024 * perPackageSize;
306
- const totalChunks = Math.ceil(source.size / chunkSize);
266
+ const totalChunks = Math.ceil(payload.byteLength / chunkSize);
307
267
  let offset = 0;
308
268
  for (let i = 0; i < totalChunks; i++) {
309
269
  const chunkStart = i * chunkSize;
310
- const chunkEnd = Math.min(chunkStart + chunkSize, source.size);
270
+ const chunkEnd = Math.min(chunkStart + chunkSize, payload.byteLength);
311
271
  const chunkLength = chunkEnd - chunkStart;
312
- const chunk = await source.readAt(chunkStart, chunkLength);
272
+ const chunk = payload.slice(chunkStart, chunkEnd);
313
273
  const overwrite = i === 0;
314
274
  const progress = Math.round(((i + 1) / totalChunks) * 100);
315
275
  const writeRes = await emmcFileWriteWithRetry(
@@ -362,7 +322,12 @@ const newTouchUpdateProcess = async (
362
322
  try {
363
323
  if (isBleReconnect) {
364
324
  try {
365
- await device.deviceConnector?.acquire(device.originalDescriptor.id, null, true);
325
+ await device.deviceConnector?.acquire(
326
+ device.originalDescriptor.id,
327
+ null,
328
+ true,
329
+ device.originalDescriptor.protocolType
330
+ );
366
331
  const typedCall = device.getCommands().typedCall.bind(device.getCommands());
367
332
  await Promise.race([
368
333
  typedCall('Initialize', 'Features', {}),
@@ -381,7 +346,8 @@ const newTouchUpdateProcess = async (
381
346
  const devicesDescriptor = deviceDiff?.descriptors ?? [];
382
347
  const { deviceList } = await DevicePool.getDevices(
383
348
  devicesDescriptor,
384
- device.originalDescriptor.id
349
+ device.originalDescriptor.id,
350
+ { connectProtocol: device.originalDescriptor.protocolType }
385
351
  );
386
352
  if (deviceList.length === 1) {
387
353
  device.updateFromCache(deviceList[0]);
@@ -456,7 +422,12 @@ const emmcFileWriteWithRetry = async (
456
422
  const env = DataManager.getSettings('env');
457
423
  if (DataManager.isBleConnect(env)) {
458
424
  await wait(3000);
459
- await device.deviceConnector?.acquire(device.originalDescriptor.id, null, true);
425
+ await device.deviceConnector?.acquire(
426
+ device.originalDescriptor.id,
427
+ null,
428
+ true,
429
+ device.originalDescriptor.protocolType
430
+ );
460
431
  await device.initialize();
461
432
  } else if (
462
433
  error?.message?.indexOf(SESSION_ERROR) > -1 ||
@@ -464,7 +435,9 @@ const emmcFileWriteWithRetry = async (
464
435
  ) {
465
436
  const deviceDiff = await device.deviceConnector?.enumerate();
466
437
  const devicesDescriptor = deviceDiff?.descriptors ?? [];
467
- const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined);
438
+ const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined, {
439
+ connectProtocol: device.originalDescriptor.protocolType,
440
+ });
468
441
  if (deviceList.length === 1 && deviceList[0]?.isBootloader()) {
469
442
  device.updateFromCache(deviceList[0]);
470
443
  await device.acquire();
@@ -530,67 +503,6 @@ export const updateResource = async (
530
503
  return processResourceRequest(typedCall, res, data);
531
504
  };
532
505
 
533
- export const updateResourceFromSource = async (
534
- typedCall: TypedCall,
535
- fileName: string,
536
- source: FirmwareByteSource,
537
- onConfirmAfter?: () => void
538
- ) => {
539
- const initialLength = Math.min(INIT_DATA_CHUNK_SIZE, source.size);
540
- const initialChunk = new Uint8Array(await source.readAt(0, initialLength));
541
- let response = await typedCall('ResourceUpdate', ['ResourceRequest', 'Success'], {
542
- file_name: fileName,
543
- data_length: source.size,
544
- initial_data_chunk: bytesToHex(initialChunk),
545
- hash: bytesToHex(blake2s(initialChunk)),
546
- });
547
- onConfirmAfter?.();
548
-
549
- while (response.type !== 'Success') {
550
- const { offset, data_length: dataLength } = response.message;
551
- if (
552
- !Number.isSafeInteger(offset) ||
553
- offset === undefined ||
554
- offset < 0 ||
555
- !Number.isSafeInteger(dataLength) ||
556
- dataLength === undefined ||
557
- dataLength <= 0 ||
558
- offset + dataLength > source.size
559
- ) {
560
- throw ERRORS.TypedError(
561
- HardwareErrorCode.RuntimeError,
562
- 'Device requested an invalid firmware resource range'
563
- );
564
- }
565
- const chunk = new Uint8Array(await source.readAt(offset, dataLength));
566
- response = await typedCall('ResourceAck', ['ResourceRequest', 'Success'], {
567
- data_chunk: bytesToHex(chunk),
568
- hash: bytesToHex(blake2s(chunk)),
569
- });
570
- }
571
- return response.message;
572
- };
573
-
574
- export const updateResourcesFromSources = async (
575
- typedCall: TypedCall,
576
- postMessage: (message: CoreMessage) => void,
577
- device: Device,
578
- entries: ReadonlyArray<{ entryName: string; source: FirmwareByteSource }>
579
- ) => {
580
- postProgressTip(device, 'UpdateSysResource', postMessage);
581
- for (const [index, entry] of entries.entries()) {
582
- await updateResourceFromSource(typedCall, entry.entryName, entry.source);
583
- postProgressMessage(
584
- device,
585
- Math.floor(((index + 1) / entries.length) * 100),
586
- 'installingFirmware',
587
- postMessage
588
- );
589
- }
590
- postProgressTip(device, 'UpdateSysResourceSuccess', postMessage);
591
- return true;
592
- };
593
-
594
506
  export const updateResources = async (
595
507
  typedCall: TypedCall,
596
508
  postMessage: (message: CoreMessage) => void,
@@ -625,28 +537,11 @@ export const updateBootloader = async (
625
537
  typedCall: TypedCall,
626
538
  postMessage: (message: CoreMessage) => void,
627
539
  device: Device,
628
- data: ArrayBuffer
629
- ) => {
630
- const source = await openFirmwareByteSource({ binary: data });
631
- if (!source) {
632
- throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'bootloader payload is empty');
633
- }
634
- try {
635
- return await updateBootloaderFromSource(typedCall, postMessage, device, source);
636
- } finally {
637
- await source.close();
638
- }
639
- };
640
-
641
- export const updateBootloaderFromSource = async (
642
- typedCall: TypedCall,
643
- postMessage: (message: CoreMessage) => void,
644
- device: Device,
645
- source: FirmwareByteSource
540
+ source: ArrayBuffer
646
541
  ) => {
647
542
  postProgressTip(device, 'UpdateBootloader', postMessage);
648
543
  postProgressMessage(device, Math.floor(0), 'installingFirmware', postMessage);
649
- await updateResourceFromSource(typedCall, 'bootloader.bin', source, () => {
544
+ await updateResource(typedCall, 'bootloader.bin', source, () => {
650
545
  postProcessingMessage('resource', postMessage);
651
546
  });
652
547
  postProgressMessage(device, Math.floor(100), 'installingFirmware', postMessage);
@@ -31,19 +31,21 @@ export type ProtocolV2FileWriteOptions = {
31
31
  uiPercentage?: number;
32
32
  timeoutMs?: number;
33
33
  maxChunkRetries?: number;
34
+ paceMs?: number;
34
35
  throwIfAborted?: () => void;
35
36
  onProgress?: (progress: ProtocolV2FileWriteProgress) => void;
36
37
  };
37
38
 
38
39
  const MIN_FILE_CHUNK_SIZE = 64;
39
40
 
40
- function isRetryableFileWriteTimeout(error: unknown) {
41
+ export function isProtocolV2ResponseTimeout(error: unknown) {
41
42
  if (!error || typeof error !== 'object') return false;
42
- const candidate = error as { errorCode?: number; code?: number; message?: string };
43
+ const candidate = error as { errorCode?: number; code?: number | string; message?: string };
43
44
  const code = candidate.errorCode ?? candidate.code;
44
45
  return (
45
46
  code === HardwareErrorCode.BleTimeoutError ||
46
- /Lowlevel response timeout/i.test(candidate.message ?? '')
47
+ code === 'response-timeout' ||
48
+ /(?:BLE|Lowlevel|Protocol V2) response timeout/i.test(candidate.message ?? '')
47
49
  );
48
50
  }
49
51
 
@@ -147,7 +149,7 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
147
149
  );
148
150
  isWritePending = false;
149
151
  } catch (error) {
150
- if (retryCount >= maxChunkRetries || !isRetryableFileWriteTimeout(error)) throw error;
152
+ if (retryCount >= maxChunkRetries || !isProtocolV2ResponseTimeout(error)) throw error;
151
153
  retryCount += 1;
152
154
  options.throwIfAborted?.();
153
155
  }
@@ -186,6 +188,11 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
186
188
  elapsedMs > 0 ? Math.round((transferredBytes / elapsedMs) * 1000) : undefined,
187
189
  elapsedMs,
188
190
  });
191
+ if (options.paceMs && options.paceMs > 0) {
192
+ await new Promise(resolve => {
193
+ setTimeout(resolve, options.paceMs);
194
+ });
195
+ }
189
196
  }
190
197
 
191
198
  return {
package/src/api/index.ts CHANGED
@@ -3,6 +3,7 @@ export { default as testProtocolV2Ping } from './protocol-v2/Ping';
3
3
  export { default as preInitialize } from './device/PreInitialize';
4
4
 
5
5
  export { default as searchDevices } from './SearchDevices';
6
+ export { default as detectDeviceConnectProtocol } from './DetectDeviceConnectProtocol';
6
7
  export { default as getFeatures } from './GetFeatures';
7
8
  export { default as getDeviceState } from './GetDeviceState';
8
9
  export { default as getOnekeyFeatures } from './GetOnekeyFeatures';
@@ -49,6 +50,7 @@ export { default as promptWebDeviceAccess } from './PromptWebDeviceAccess';
49
50
  export { default as deviceReboot } from './protocol-v2/DeviceReboot';
50
51
  export { default as deviceGetOnboardingStatus } from './protocol-v2/DeviceGetOnboardingStatus';
51
52
  export { default as deviceUploadWallpaper } from './protocol-v2/DeviceUploadWallpaper';
53
+ export { default as deviceUploadNft } from './protocol-v2/DeviceUploadNft';
52
54
  export { default as uploadPortfolio } from './UploadPortfolio';
53
55
 
54
56
  export { default as cipherKeyValue } from './CipherKeyValue';
@@ -0,0 +1,189 @@
1
+ import { ERRORS, HardwareErrorCode, createDeviceNotSupportMethodError } from '@onekeyfe/hd-shared';
2
+
3
+ import { UI_REQUEST, createUiMessage } from '../../events/ui-request';
4
+ import { supportsProtocolV2Message } from '../../protocols/protocol-v2/features';
5
+ import {
6
+ PRO2_NFT_DEFAULT_CHUNK_SIZE,
7
+ PRO2_NFT_DEFAULT_PACE_MS,
8
+ PRO2_NFT_DEFAULT_TIMEOUT_MS,
9
+ PRO2_NFT_DIRECTORY,
10
+ PRO2_NFT_MAX_CHUNK_SIZE,
11
+ PRO2_NFT_MAX_ITEMS,
12
+ PRO2_NFT_MIN_CHUNK_SIZE,
13
+ type Pro2NftBundle,
14
+ type Pro2NftImage,
15
+ buildPro2NftBundle,
16
+ getCompletePro2NftBasenames,
17
+ } from '../../utils/pro2Nft';
18
+ import { BaseMethod } from '../BaseMethod';
19
+ import { invalidParameter } from '../helpers/filesystemValidation';
20
+ import { isProtocolV2ResponseTimeout, writeProtocolV2File } from '../helpers/protocolV2FileWrite';
21
+
22
+ export type DeviceUploadNftParams = {
23
+ image: Pro2NftImage;
24
+ thumbnail: Pro2NftImage;
25
+ title: string;
26
+ subtitle: string;
27
+ timestampMs?: number;
28
+ chunkSize?: number;
29
+ paceMs?: number;
30
+ timeoutMs?: number;
31
+ };
32
+
33
+ export type DeviceUploadNftResponse = {
34
+ basename: string;
35
+ imagePath: string;
36
+ thumbnailPath: string;
37
+ metadataPath: string;
38
+ totalSize: number;
39
+ nftUpdated: true;
40
+ message?: string;
41
+ };
42
+
43
+ const FILESYSTEM_FILE_WRITE_MESSAGE_TYPE = 60805;
44
+ const FILESYSTEM_DIR_LIST_MESSAGE_TYPE = 60808;
45
+ const NFT_UPDATE_MESSAGE_TYPE = 61500;
46
+
47
+ export default class DeviceUploadNft extends BaseMethod<DeviceUploadNftParams> {
48
+ private bundle?: Pro2NftBundle;
49
+
50
+ getSupportedProtocols() {
51
+ return ['V2'] as const;
52
+ }
53
+
54
+ init() {
55
+ const {
56
+ image,
57
+ thumbnail,
58
+ title,
59
+ subtitle,
60
+ timestampMs = Date.now(),
61
+ chunkSize = PRO2_NFT_DEFAULT_CHUNK_SIZE,
62
+ paceMs = PRO2_NFT_DEFAULT_PACE_MS,
63
+ timeoutMs = PRO2_NFT_DEFAULT_TIMEOUT_MS,
64
+ } = this.payload;
65
+ if (
66
+ !Number.isInteger(chunkSize) ||
67
+ chunkSize < PRO2_NFT_MIN_CHUNK_SIZE ||
68
+ chunkSize > PRO2_NFT_MAX_CHUNK_SIZE
69
+ ) {
70
+ throw invalidParameter(
71
+ `Parameter [chunkSize] must be an integer between ${PRO2_NFT_MIN_CHUNK_SIZE} and ${PRO2_NFT_MAX_CHUNK_SIZE}.`
72
+ );
73
+ }
74
+ if (!Number.isInteger(paceMs) || paceMs < 0) {
75
+ throw invalidParameter('Parameter [paceMs] must be a non-negative integer.');
76
+ }
77
+ if (!Number.isInteger(timeoutMs) || timeoutMs <= 0) {
78
+ throw invalidParameter('Parameter [timeoutMs] must be a positive integer.');
79
+ }
80
+
81
+ this.bundle = buildPro2NftBundle({ image, thumbnail, title, subtitle, timestampMs });
82
+ this.params = { image, thumbnail, title, subtitle, timestampMs, chunkSize, paceMs, timeoutMs };
83
+ this.unlockPolicy = 'none';
84
+ this.skipForceUpdateCheck = true;
85
+ this.useDevicePassphraseState = false;
86
+ }
87
+
88
+ private async assertCapabilities() {
89
+ const protocolInfo = await this.device.ensureProtocolV2RuntimeContext();
90
+ const hasFileWrite = supportsProtocolV2Message(
91
+ protocolInfo,
92
+ FILESYSTEM_FILE_WRITE_MESSAGE_TYPE
93
+ );
94
+ const hasDirList = supportsProtocolV2Message(protocolInfo, FILESYSTEM_DIR_LIST_MESSAGE_TYPE);
95
+ const hasNftUpdate = supportsProtocolV2Message(protocolInfo, NFT_UPDATE_MESSAGE_TYPE);
96
+ if (!hasFileWrite || !hasDirList || !hasNftUpdate) {
97
+ throw createDeviceNotSupportMethodError(this.name, this.device.getCurrentFirmwareType());
98
+ }
99
+ }
100
+
101
+ private async assertStorageCapacity(basename: string) {
102
+ const { message } = await this.device.commands.typedCall(
103
+ 'FilesystemDirList',
104
+ 'FilesystemDir',
105
+ { path: PRO2_NFT_DIRECTORY, depth: 1 },
106
+ { timeoutMs: this.params.timeoutMs }
107
+ );
108
+ const existingBasenames = getCompletePro2NftBasenames(message.child_files);
109
+ if (existingBasenames.size >= PRO2_NFT_MAX_ITEMS && !existingBasenames.has(basename)) {
110
+ throw ERRORS.TypedError(HardwareErrorCode.NftStorageLimitReached, undefined, {
111
+ count: existingBasenames.size,
112
+ limit: PRO2_NFT_MAX_ITEMS,
113
+ });
114
+ }
115
+ }
116
+
117
+ private async updateNft(basename: string) {
118
+ const params = { file_name_no_ext: basename };
119
+ const options = { timeoutMs: this.params.timeoutMs };
120
+ try {
121
+ return await this.device.commands.typedCall('NftUpdate', 'Success', params, options);
122
+ } catch (error) {
123
+ if (!isProtocolV2ResponseTimeout(error)) {
124
+ throw error;
125
+ }
126
+ this.throwIfAborted();
127
+ return this.device.commands.typedCall('NftUpdate', 'Success', params, options);
128
+ }
129
+ }
130
+
131
+ async run(): Promise<DeviceUploadNftResponse> {
132
+ const { bundle } = this;
133
+ if (!bundle) throw invalidParameter('NFT data has not been initialized.');
134
+
135
+ await this.assertCapabilities();
136
+ this.throwIfAborted();
137
+ await this.assertStorageCapacity(bundle.basename);
138
+ this.throwIfAborted();
139
+
140
+ const files = [
141
+ { path: `${PRO2_NFT_DIRECTORY}/${bundle.basename}.bin`, data: bundle.image },
142
+ { path: `${PRO2_NFT_DIRECTORY}/${bundle.basename}_m.bin`, data: bundle.thumbnail },
143
+ { path: `${PRO2_NFT_DIRECTORY}/${bundle.basename}.json`, data: bundle.metadata },
144
+ ];
145
+ const totalSize = files.reduce((sum, file) => sum + file.data.byteLength, 0);
146
+ let transferredBeforeFile = 0;
147
+
148
+ for (const file of files) {
149
+ const transferredAtFileStart = transferredBeforeFile;
150
+ await writeProtocolV2File({
151
+ commands: this.device.commands,
152
+ path: file.path,
153
+ data: file.data,
154
+ totalSize: file.data.byteLength,
155
+ chunkSize: this.params.chunkSize,
156
+ timeoutMs: this.params.timeoutMs,
157
+ paceMs: this.params.paceMs,
158
+ overwrite: true,
159
+ append: false,
160
+ throwIfAborted: () => this.throwIfAborted(),
161
+ onProgress: progress => {
162
+ if (typeof this.postMessage !== 'function') return;
163
+ const transferredBytes = transferredAtFileStart + progress.transferredBytes;
164
+ this.postMessage(
165
+ createUiMessage(UI_REQUEST.DEVICE_PROGRESS, {
166
+ ...progress,
167
+ progress: Math.floor((transferredBytes / totalSize) * 100),
168
+ transferredBytes,
169
+ totalBytes: totalSize,
170
+ })
171
+ );
172
+ },
173
+ });
174
+ transferredBeforeFile += file.data.byteLength;
175
+ }
176
+
177
+ this.throwIfAborted();
178
+ const response = await this.updateNft(bundle.basename);
179
+ return {
180
+ basename: bundle.basename,
181
+ imagePath: files[0].path,
182
+ thumbnailPath: files[1].path,
183
+ metadataPath: files[2].path,
184
+ totalSize,
185
+ nftUpdated: true,
186
+ message: response.message?.message,
187
+ };
188
+ }
189
+ }
@@ -13,7 +13,9 @@ export default class ProtocolInfoRequest extends BaseMethod {
13
13
  }
14
14
 
15
15
  async run() {
16
- const res = await this.device.commands.typedCall('ProtocolInfoRequest', 'ProtocolInfo', {});
16
+ const res = await this.device.commands.typedCall('ProtocolInfoRequest', 'ProtocolInfo', {
17
+ eventless_wallet_session: true,
18
+ });
17
19
  return Promise.resolve(res.message);
18
20
  }
19
21
  }
@@ -118,6 +118,7 @@ export const isProtocolV2DeviceDisconnectedError = (error: unknown) => {
118
118
  message.includes('connection has timed out unexpectedly') ||
119
119
  message.includes('connection error has occured') ||
120
120
  message.includes('connection error has occurred') ||
121
+ message.includes('react native ble transport released') ||
121
122
  message.includes('multiplatformbleadapter') ||
122
123
  message.includes('multipalformebleadapter') ||
123
124
  compactMessage.includes('rxerrorerror6') ||
@@ -4,6 +4,8 @@ import type { Device, DeviceEvents } from '../device/Device';
4
4
 
5
5
  export type HardwareUiEventHandlers = {
6
6
  pin: (...event: DeviceEvents[typeof DEVICE.PIN]) => void;
7
+ pinOnDevice: (...event: DeviceEvents[typeof DEVICE.PIN_ON_DEVICE]) => void;
8
+ pinOnDeviceComplete: (...event: DeviceEvents[typeof DEVICE.PIN_ON_DEVICE_COMPLETE]) => void;
7
9
  button: (...event: DeviceEvents[typeof DEVICE.BUTTON]) => void;
8
10
  passphrase: (...event: DeviceEvents[typeof DEVICE.PASSPHRASE]) => void;
9
11
  passphraseOnDevice: (...event: DeviceEvents[typeof DEVICE.PASSPHRASE_ON_DEVICE]) => void;
@@ -15,6 +17,8 @@ export function registerHardwareUiEventListeners(
15
17
  handlers: HardwareUiEventHandlers
16
18
  ) {
17
19
  device.on(DEVICE.PIN, handlers.pin);
20
+ device.on(DEVICE.PIN_ON_DEVICE, handlers.pinOnDevice);
21
+ device.on(DEVICE.PIN_ON_DEVICE_COMPLETE, handlers.pinOnDeviceComplete);
18
22
  device.on(DEVICE.BUTTON, handlers.button);
19
23
  device.on(DEVICE.PASSPHRASE, handlers.passphrase);
20
24
  device.on(DEVICE.PASSPHRASE_ON_DEVICE, handlers.passphraseOnDevice);