@onekeyfe/hd-core 1.2.0-alpha.56 → 1.2.0-alpha.62

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 (262) hide show
  1. package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +0 -231
  2. package/__tests__/DeviceCommands.test.ts +0 -45
  3. package/__tests__/DeviceEventRegistration.test.ts +0 -6
  4. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +3 -198
  5. package/__tests__/connectSettings.test.ts +47 -5
  6. package/__tests__/device-initialize-timeout.test.ts +56 -0
  7. package/__tests__/device-lifecycle-events.test.ts +3 -105
  8. package/__tests__/device-state-contract.test.ts +0 -1
  9. package/__tests__/device-state-mapper.test.ts +1 -1
  10. package/__tests__/deviceSettings.test.ts +1 -1
  11. package/__tests__/firmware-update/check-all-firmware-release.test.ts +175 -0
  12. package/__tests__/firmware-update/firmware-artifact-source.test.ts +119 -0
  13. package/__tests__/firmware-update/firmware-host-binding.test.ts +70 -0
  14. package/__tests__/firmware-update/firmware-preparation-error.test.ts +27 -0
  15. package/__tests__/firmware-update/firmware-update-bootloader-poll.test.ts +200 -0
  16. package/__tests__/firmware-update/firmware-update-capabilities.test.ts +13 -0
  17. package/__tests__/firmware-update/firmware-update-plan-bootloader-identity.test.ts +294 -0
  18. package/__tests__/firmware-update/firmware-update-plan.test.ts +593 -0
  19. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +213 -0
  20. package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +59 -31
  21. package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +58 -0
  22. package/__tests__/firmware-update/firmware-upload-source.test.ts +70 -0
  23. package/__tests__/get-device-state.test.ts +12 -132
  24. package/__tests__/homescreen.test.ts +1 -41
  25. package/__tests__/kaspaSignTransaction.test.ts +26 -3
  26. package/__tests__/logBlockEvent.test.ts +1 -1
  27. package/__tests__/method-protocol-support.test.ts +0 -19
  28. package/__tests__/open-wallet-session.test.ts +37 -568
  29. package/__tests__/protocol-v2-unlock-policy.test.ts +35 -201
  30. package/__tests__/protocol-v2.test.ts +1046 -1388
  31. package/__tests__/protocolV2FileWrite.test.ts +0 -39
  32. package/__tests__/protocolV2UiInteraction.test.ts +0 -63
  33. package/__tests__/public-pro2-api-boundary.test.ts +0 -1
  34. package/__tests__/search-devices.test.ts +3 -12
  35. package/dist/api/BaseMethod.d.ts +1 -3
  36. package/dist/api/BaseMethod.d.ts.map +1 -1
  37. package/dist/api/CheckAllFirmwareRelease.d.ts +1 -2
  38. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  39. package/dist/api/FirmwareUpdate.d.ts.map +1 -1
  40. package/dist/api/FirmwareUpdateV2.d.ts +11 -0
  41. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  42. package/dist/api/FirmwareUpdateV3.d.ts +7 -3
  43. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  44. package/dist/api/FirmwareUpdateV4.d.ts +25 -11
  45. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  46. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  47. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  48. package/dist/api/SearchDevices.d.ts.map +1 -1
  49. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  50. package/dist/api/device/DeviceUnlock.d.ts +2 -2
  51. package/dist/api/device/DeviceUnlock.d.ts.map +1 -1
  52. package/dist/api/device/DeviceUpdateBootloader.d.ts +5 -1
  53. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  54. package/dist/api/firmware/FirmwareArtifactSource.d.ts +25 -0
  55. package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +1 -0
  56. package/dist/api/firmware/FirmwareHostBinding.d.ts +6 -0
  57. package/dist/api/firmware/FirmwareHostBinding.d.ts.map +1 -0
  58. package/dist/api/firmware/FirmwarePreparationError.d.ts +3 -0
  59. package/dist/api/firmware/FirmwarePreparationError.d.ts.map +1 -0
  60. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +9 -0
  61. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  62. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +3 -0
  63. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +1 -0
  64. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +25 -0
  65. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -0
  66. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +32 -0
  67. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -0
  68. package/dist/api/firmware/getBinary.d.ts +7 -0
  69. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  70. package/dist/api/firmware/progressThrottle.d.ts +3 -0
  71. package/dist/api/firmware/progressThrottle.d.ts.map +1 -0
  72. package/dist/api/firmware/updateBootloader.d.ts +2 -0
  73. package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
  74. package/dist/api/firmware/uploadFirmware.d.ts +9 -1
  75. package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
  76. package/dist/api/helpers/protocolV2FileWrite.d.ts +0 -2
  77. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
  78. package/dist/api/index.d.ts +0 -2
  79. package/dist/api/index.d.ts.map +1 -1
  80. package/dist/api/kaspa/KaspaSignTransaction.d.ts.map +1 -1
  81. package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
  82. package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
  83. package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
  84. package/dist/core/deviceEventRegistration.d.ts +0 -2
  85. package/dist/core/deviceEventRegistration.d.ts.map +1 -1
  86. package/dist/core/index.d.ts.map +1 -1
  87. package/dist/data-manager/DataManager.d.ts +2 -4
  88. package/dist/data-manager/DataManager.d.ts.map +1 -1
  89. package/dist/data-manager/connectSettings.d.ts.map +1 -1
  90. package/dist/device/Device.d.ts +6 -29
  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/DevicePool.d.ts.map +1 -1
  95. package/dist/events/device.d.ts +0 -4
  96. package/dist/events/device.d.ts.map +1 -1
  97. package/dist/events/logBlockEvent.d.ts.map +1 -1
  98. package/dist/events/ui-promise.d.ts +2 -4
  99. package/dist/events/ui-promise.d.ts.map +1 -1
  100. package/dist/events/ui-request.d.ts +2 -31
  101. package/dist/events/ui-request.d.ts.map +1 -1
  102. package/dist/events/ui-response.d.ts +2 -10
  103. package/dist/events/ui-response.d.ts.map +1 -1
  104. package/dist/index.d.ts +231 -214
  105. package/dist/index.d.ts.map +1 -1
  106. package/dist/index.js +3530 -2634
  107. package/dist/inject.d.ts +1 -6
  108. package/dist/inject.d.ts.map +1 -1
  109. package/dist/lowLevelInject.d.ts.map +1 -1
  110. package/dist/protocols/protocol-v2/features.d.ts +4 -0
  111. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  112. package/dist/protocols/protocol-v2/firmware.d.ts.map +1 -1
  113. package/dist/protocols/protocol-v2/lockedError.d.ts +2 -0
  114. package/dist/protocols/protocol-v2/lockedError.d.ts.map +1 -0
  115. package/dist/protocols/protocol-v2/uiInteraction.d.ts +4 -7
  116. package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -1
  117. package/dist/protocols/protocol-v2/unlockPolicy.d.ts +3 -1
  118. package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -1
  119. package/dist/protocols/protocol-v2/unlockRetry.d.ts +10 -0
  120. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -0
  121. package/dist/protocols/protocol-v2/walletSession.d.ts +1 -6
  122. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  123. package/dist/topLevelInject.d.ts.map +1 -1
  124. package/dist/types/api/checkAllFirmwareRelease.d.ts +4 -2
  125. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  126. package/dist/types/api/deviceUnlock.d.ts +1 -5
  127. package/dist/types/api/deviceUnlock.d.ts.map +1 -1
  128. package/dist/types/api/deviceUpdateBootloader.d.ts +6 -0
  129. package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
  130. package/dist/types/api/export.d.ts +4 -2
  131. package/dist/types/api/export.d.ts.map +1 -1
  132. package/dist/types/api/firmwareUpdate.d.ts +70 -2
  133. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  134. package/dist/types/api/firmwareUpdateCapabilities.d.ts +9 -0
  135. package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +1 -0
  136. package/dist/types/api/firmwareUpdatePlan.d.ts +28 -0
  137. package/dist/types/api/firmwareUpdatePlan.d.ts.map +1 -0
  138. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +42 -0
  139. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +1 -0
  140. package/dist/types/api/index.d.ts +10 -7
  141. package/dist/types/api/index.d.ts.map +1 -1
  142. package/dist/types/api/protocolV2.d.ts +0 -3
  143. package/dist/types/api/protocolV2.d.ts.map +1 -1
  144. package/dist/types/device.d.ts.map +1 -1
  145. package/dist/types/params.d.ts +0 -1
  146. package/dist/types/params.d.ts.map +1 -1
  147. package/dist/types/settings.d.ts +13 -22
  148. package/dist/types/settings.d.ts.map +1 -1
  149. package/dist/utils/deviceFeaturesCompat.d.ts +1 -0
  150. package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
  151. package/dist/utils/deviceFeaturesUtils.d.ts +0 -4
  152. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  153. package/dist/utils/homescreen.d.ts +0 -4
  154. package/dist/utils/homescreen.d.ts.map +1 -1
  155. package/dist/utils/index.d.ts +1 -1
  156. package/dist/utils/index.d.ts.map +1 -1
  157. package/dist/utils/patch.d.ts +1 -1
  158. package/dist/utils/patch.d.ts.map +1 -1
  159. package/dist/utils/pro2Wallpaper.d.ts +0 -10
  160. package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
  161. package/package.json +4 -4
  162. package/src/api/BaseMethod.ts +10 -8
  163. package/src/api/CheckAllFirmwareRelease.ts +57 -54
  164. package/src/api/FirmwareUpdate.ts +15 -7
  165. package/src/api/FirmwareUpdateV2.ts +316 -126
  166. package/src/api/FirmwareUpdateV3.ts +265 -63
  167. package/src/api/FirmwareUpdateV4.ts +975 -584
  168. package/src/api/GetPassphraseState.ts +1 -7
  169. package/src/api/OpenWalletSession.ts +17 -70
  170. package/src/api/SearchDevices.ts +1 -3
  171. package/src/api/allnetwork/AllNetworkGetAddress.ts +21 -21
  172. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +11 -34
  173. package/src/api/device/DeviceUnlock.ts +3 -8
  174. package/src/api/device/DeviceUpdateBootloader.ts +122 -6
  175. package/src/api/firmware/FirmwareArtifactSource.ts +278 -0
  176. package/src/api/firmware/FirmwareHostBinding.ts +100 -0
  177. package/src/api/firmware/FirmwarePreparationError.ts +12 -0
  178. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +83 -16
  179. package/src/api/firmware/FirmwareUpdateCapabilities.ts +9 -0
  180. package/src/api/firmware/FirmwareUpdatePlan.ts +772 -0
  181. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +415 -0
  182. package/src/api/firmware/progressThrottle.ts +44 -0
  183. package/src/api/firmware/updateBootloader.ts +19 -4
  184. package/src/api/firmware/uploadFirmware.ts +144 -39
  185. package/src/api/helpers/protocolV2FileWrite.ts +7 -27
  186. package/src/api/index.ts +0 -2
  187. package/src/api/kaspa/KaspaSignTransaction.ts +12 -1
  188. package/src/api/protocol-v2/ProtocolInfoRequest.ts +1 -3
  189. package/src/api/protocol-v2/helpers.ts +0 -1
  190. package/src/core/deviceEventRegistration.ts +0 -4
  191. package/src/core/index.ts +83 -167
  192. package/src/data/messages/messages-protocol-v2.json +0 -25
  193. package/src/data-manager/DataManager.ts +39 -71
  194. package/src/data-manager/connectSettings.ts +11 -0
  195. package/src/device/Device.ts +43 -259
  196. package/src/device/DeviceCommands.ts +1 -7
  197. package/src/device/DevicePool.ts +2 -7
  198. package/src/events/device.ts +0 -4
  199. package/src/events/logBlockEvent.ts +0 -1
  200. package/src/events/ui-promise.ts +2 -4
  201. package/src/events/ui-request.ts +2 -36
  202. package/src/events/ui-response.ts +2 -12
  203. package/src/index.ts +5 -0
  204. package/src/inject.ts +24 -60
  205. package/src/lowLevelInject.ts +8 -7
  206. package/src/protocols/protocol-v2/features.ts +7 -10
  207. package/src/protocols/protocol-v2/firmware.ts +0 -2
  208. package/src/protocols/protocol-v2/lockedError.ts +10 -0
  209. package/src/protocols/protocol-v2/uiInteraction.ts +6 -46
  210. package/src/protocols/protocol-v2/unlockPolicy.ts +105 -1
  211. package/src/protocols/protocol-v2/unlockRetry.ts +109 -0
  212. package/src/protocols/protocol-v2/walletSession.ts +36 -214
  213. package/src/topLevelInject.ts +8 -7
  214. package/src/types/api/checkAllFirmwareRelease.ts +4 -2
  215. package/src/types/api/deviceUnlock.ts +1 -12
  216. package/src/types/api/deviceUpdateBootloader.ts +6 -0
  217. package/src/types/api/export.ts +18 -1
  218. package/src/types/api/firmwareUpdate.ts +76 -3
  219. package/src/types/api/firmwareUpdateCapabilities.ts +9 -0
  220. package/src/types/api/firmwareUpdatePlan.ts +38 -0
  221. package/src/types/api/firmwareUpdatePreparedPlan.ts +53 -0
  222. package/src/types/api/index.ts +14 -13
  223. package/src/types/api/protocolV2.ts +0 -13
  224. package/src/types/device.ts +0 -3
  225. package/src/types/params.ts +1 -7
  226. package/src/types/settings.ts +13 -42
  227. package/src/utils/deviceFeaturesCompat.ts +6 -0
  228. package/src/utils/deviceFeaturesUtils.ts +0 -8
  229. package/src/utils/homescreen.ts +6 -32
  230. package/src/utils/index.ts +1 -6
  231. package/src/utils/pro2Wallpaper.ts +8 -35
  232. package/__tests__/deviceUploadNft.test.ts +0 -293
  233. package/__tests__/pro2Nft.test.ts +0 -108
  234. package/__tests__/protocol-binding.test.ts +0 -89
  235. package/__tests__/protocol-v2-resources.test.ts +0 -286
  236. package/__tests__/protocol-v2-ui-lifecycle.test.ts +0 -91
  237. package/__tests__/uiProgressThrottle.test.ts +0 -74
  238. package/__tests__/uiPromiseRegistry.test.ts +0 -86
  239. package/dist/api/DetectDeviceConnectProtocol.d.ts +0 -7
  240. package/dist/api/DetectDeviceConnectProtocol.d.ts.map +0 -1
  241. package/dist/api/protocol-v2/DeviceUploadNft.d.ts +0 -31
  242. package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +0 -1
  243. package/dist/core/uiPromiseRegistry.d.ts +0 -4
  244. package/dist/core/uiPromiseRegistry.d.ts.map +0 -1
  245. package/dist/protocols/protocol-v2/resources.d.ts +0 -30
  246. package/dist/protocols/protocol-v2/resources.d.ts.map +0 -1
  247. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +0 -22
  248. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +0 -1
  249. package/dist/types/api/detectDeviceConnectProtocol.d.ts +0 -4
  250. package/dist/types/api/detectDeviceConnectProtocol.d.ts.map +0 -1
  251. package/dist/utils/pro2Nft.d.ts +0 -31
  252. package/dist/utils/pro2Nft.d.ts.map +0 -1
  253. package/dist/utils/uiProgressThrottle.d.ts +0 -3
  254. package/dist/utils/uiProgressThrottle.d.ts.map +0 -1
  255. package/src/api/DetectDeviceConnectProtocol.ts +0 -18
  256. package/src/api/protocol-v2/DeviceUploadNft.ts +0 -189
  257. package/src/core/uiPromiseRegistry.ts +0 -41
  258. package/src/protocols/protocol-v2/resources.ts +0 -359
  259. package/src/protocols/protocol-v2/unlockPolicyRunner.ts +0 -118
  260. package/src/types/api/detectDeviceConnectProtocol.ts +0 -6
  261. package/src/utils/pro2Nft.ts +0 -142
  262. package/src/utils/uiProgressThrottle.ts +0 -63
@@ -10,6 +10,7 @@ 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';
13
14
 
14
15
  import type { KnownDevice } from '../../types';
15
16
  import type { TypedCall, TypedResponseMessage } from '../../device/DeviceCommands';
@@ -17,6 +18,7 @@ import type { PROTO } from '../../constants';
17
18
  import type { CoreMessage, IFirmwareUpdateProgressType } from '../../events';
18
19
  import type { Success } from '@onekeyfe/hd-transport';
19
20
  import type { Device } from '../../device/Device';
21
+ import type { FirmwareByteSource } from './FirmwareArtifactSource';
20
22
 
21
23
  const NEW_BOOT_UPRATE_FIRMWARE_VERSION = '2.4.5';
22
24
  const SESSION_ERROR = 'session not found';
@@ -88,17 +90,20 @@ export const waitBleInstall = async (updateType: string) => {
88
90
  }
89
91
  };
90
92
 
91
- export const uploadFirmware = async (
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 (
92
101
  updateType: 'firmware' | 'ble',
93
102
  typedCall: TypedCall,
94
103
  postMessage: (message: CoreMessage) => void,
95
104
  device: Device,
96
- {
97
- payload,
98
- rebootOnSuccess,
99
- }: PROTO.FirmwareUpload & {
100
- rebootOnSuccess?: boolean;
101
- },
105
+ source: FirmwareByteSource,
106
+ rebootOnSuccess?: boolean,
102
107
  isUpdateBootloader?: boolean
103
108
  ) => {
104
109
  const deviceType = device.getCurrentDeviceType();
@@ -119,20 +124,20 @@ export const uploadFirmware = async (
119
124
  if (supportUpgradeFileHeader) {
120
125
  // Extract and validate firmware header (first 1KB)
121
126
  const HEADER_SIZE = 1024;
122
- if (payload.byteLength < HEADER_SIZE) {
127
+ if (source.size < HEADER_SIZE) {
123
128
  throw ERRORS.TypedError(
124
129
  HardwareErrorCode.RuntimeError,
125
- `firmware payload too small: ${payload.byteLength} bytes, expected at least ${HEADER_SIZE} bytes`
130
+ `firmware payload too small: ${source.size} bytes, expected at least ${HEADER_SIZE} bytes`
126
131
  );
127
132
  }
128
133
 
129
134
  Log.debug('Uploading firmware header:', {
130
135
  size: HEADER_SIZE,
131
- totalSize: payload.byteLength,
136
+ totalSize: source.size,
132
137
  });
133
138
  postProgressTip(device, 'UploadingFirmwareHeader', postMessage);
134
139
 
135
- const header = new Uint8Array(payload.slice(0, HEADER_SIZE));
140
+ const header = new Uint8Array(await source.readAt(0, HEADER_SIZE));
136
141
 
137
142
  try {
138
143
  const headerRes = await typedCall('UpgradeFileHeader', 'Success', {
@@ -169,6 +174,9 @@ export const uploadFirmware = async (
169
174
  postProgressMessage(device, 0, 'installingFirmware', postMessage);
170
175
  let updateResponse: TypedResponseMessage<'Success'>;
171
176
  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);
172
180
  updateResponse = await typedCall('FirmwareUpload', 'Success', {
173
181
  payload,
174
182
  });
@@ -200,9 +208,7 @@ export const uploadFirmware = async (
200
208
  updateType,
201
209
  postMessage,
202
210
  device,
203
- {
204
- payload,
205
- },
211
+ source,
206
212
  rebootOnSuccess
207
213
  );
208
214
  return response.message;
@@ -211,7 +217,7 @@ export const uploadFirmware = async (
211
217
 
212
218
  postConfirmationMessage(device);
213
219
  postProgressTip(device, 'ConfirmOnDevice', postMessage);
214
- const length = payload.byteLength;
220
+ const length = source.size;
215
221
 
216
222
  let response = await typedCall('FirmwareErase', ['FirmwareRequest', 'Success'], { length });
217
223
  postProgressTip(device, 'FirmwareEraseSuccess', postMessage);
@@ -220,7 +226,7 @@ export const uploadFirmware = async (
220
226
  const start = response.message.offset!;
221
227
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
222
228
  const end = response.message.offset! + response.message.length!;
223
- const chunk = payload.slice(start, end);
229
+ const chunk = await source.readAt(start, end - start);
224
230
 
225
231
  if (start > 0) {
226
232
  postProgressMessage(
@@ -249,11 +255,45 @@ export const uploadFirmware = async (
249
255
  throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'uploadFirmware: unknown device model');
250
256
  };
251
257
 
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
+
252
292
  const newTouchUpdateProcess = async (
253
293
  updateType: 'firmware' | 'ble',
254
294
  postMessage: (message: CoreMessage) => void,
255
295
  device: Device,
256
- { payload }: PROTO.FirmwareUpload,
296
+ source: FirmwareByteSource,
257
297
  rebootOnSuccess = true
258
298
  ) => {
259
299
  let typedCall = device.getCommands().typedCall.bind(device.getCommands());
@@ -263,13 +303,13 @@ const newTouchUpdateProcess = async (
263
303
  const env = DataManager.getSettings('env');
264
304
  const perPackageSize = DataManager.isBleConnect(env) ? 16 : 128;
265
305
  const chunkSize = 1024 * perPackageSize;
266
- const totalChunks = Math.ceil(payload.byteLength / chunkSize);
306
+ const totalChunks = Math.ceil(source.size / chunkSize);
267
307
  let offset = 0;
268
308
  for (let i = 0; i < totalChunks; i++) {
269
309
  const chunkStart = i * chunkSize;
270
- const chunkEnd = Math.min(chunkStart + chunkSize, payload.byteLength);
310
+ const chunkEnd = Math.min(chunkStart + chunkSize, source.size);
271
311
  const chunkLength = chunkEnd - chunkStart;
272
- const chunk = payload.slice(chunkStart, chunkEnd);
312
+ const chunk = await source.readAt(chunkStart, chunkLength);
273
313
  const overwrite = i === 0;
274
314
  const progress = Math.round(((i + 1) / totalChunks) * 100);
275
315
  const writeRes = await emmcFileWriteWithRetry(
@@ -322,12 +362,7 @@ const newTouchUpdateProcess = async (
322
362
  try {
323
363
  if (isBleReconnect) {
324
364
  try {
325
- await device.deviceConnector?.acquire(
326
- device.originalDescriptor.id,
327
- null,
328
- true,
329
- device.originalDescriptor.protocolType
330
- );
365
+ await device.deviceConnector?.acquire(device.originalDescriptor.id, null, true);
331
366
  const typedCall = device.getCommands().typedCall.bind(device.getCommands());
332
367
  await Promise.race([
333
368
  typedCall('Initialize', 'Features', {}),
@@ -346,8 +381,7 @@ const newTouchUpdateProcess = async (
346
381
  const devicesDescriptor = deviceDiff?.descriptors ?? [];
347
382
  const { deviceList } = await DevicePool.getDevices(
348
383
  devicesDescriptor,
349
- device.originalDescriptor.id,
350
- { connectProtocol: device.originalDescriptor.protocolType }
384
+ device.originalDescriptor.id
351
385
  );
352
386
  if (deviceList.length === 1) {
353
387
  device.updateFromCache(deviceList[0]);
@@ -422,12 +456,7 @@ const emmcFileWriteWithRetry = async (
422
456
  const env = DataManager.getSettings('env');
423
457
  if (DataManager.isBleConnect(env)) {
424
458
  await wait(3000);
425
- await device.deviceConnector?.acquire(
426
- device.originalDescriptor.id,
427
- null,
428
- true,
429
- device.originalDescriptor.protocolType
430
- );
459
+ await device.deviceConnector?.acquire(device.originalDescriptor.id, null, true);
431
460
  await device.initialize();
432
461
  } else if (
433
462
  error?.message?.indexOf(SESSION_ERROR) > -1 ||
@@ -435,9 +464,7 @@ const emmcFileWriteWithRetry = async (
435
464
  ) {
436
465
  const deviceDiff = await device.deviceConnector?.enumerate();
437
466
  const devicesDescriptor = deviceDiff?.descriptors ?? [];
438
- const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined, {
439
- connectProtocol: device.originalDescriptor.protocolType,
440
- });
467
+ const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined);
441
468
  if (deviceList.length === 1 && deviceList[0]?.isBootloader()) {
442
469
  device.updateFromCache(deviceList[0]);
443
470
  await device.acquire();
@@ -503,6 +530,67 @@ export const updateResource = async (
503
530
  return processResourceRequest(typedCall, res, data);
504
531
  };
505
532
 
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
+
506
594
  export const updateResources = async (
507
595
  typedCall: TypedCall,
508
596
  postMessage: (message: CoreMessage) => void,
@@ -537,11 +625,28 @@ export const updateBootloader = async (
537
625
  typedCall: TypedCall,
538
626
  postMessage: (message: CoreMessage) => void,
539
627
  device: Device,
540
- source: ArrayBuffer
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
541
646
  ) => {
542
647
  postProgressTip(device, 'UpdateBootloader', postMessage);
543
648
  postProgressMessage(device, Math.floor(0), 'installingFirmware', postMessage);
544
- await updateResource(typedCall, 'bootloader.bin', source, () => {
649
+ await updateResourceFromSource(typedCall, 'bootloader.bin', source, () => {
545
650
  postProcessingMessage('resource', postMessage);
546
651
  });
547
652
  postProgressMessage(device, Math.floor(100), 'installingFirmware', postMessage);
@@ -31,22 +31,19 @@ export type ProtocolV2FileWriteOptions = {
31
31
  uiPercentage?: number;
32
32
  timeoutMs?: number;
33
33
  maxChunkRetries?: number;
34
- paceMs?: number;
35
34
  throwIfAborted?: () => void;
36
35
  onProgress?: (progress: ProtocolV2FileWriteProgress) => void;
37
36
  };
38
37
 
39
38
  const MIN_FILE_CHUNK_SIZE = 64;
40
- const FILE_TRANSFER_RATE_WINDOW_MS = 1000;
41
39
 
42
- export function isProtocolV2ResponseTimeout(error: unknown) {
40
+ function isRetryableFileWriteTimeout(error: unknown) {
43
41
  if (!error || typeof error !== 'object') return false;
44
- const candidate = error as { errorCode?: number; code?: number | string; message?: string };
42
+ const candidate = error as { errorCode?: number; code?: number; message?: string };
45
43
  const code = candidate.errorCode ?? candidate.code;
46
44
  return (
47
45
  code === HardwareErrorCode.BleTimeoutError ||
48
- code === 'response-timeout' ||
49
- /(?:BLE|Lowlevel|Protocol V2) response timeout/i.test(candidate.message ?? '')
46
+ /Lowlevel response timeout/i.test(candidate.message ?? '')
50
47
  );
51
48
  }
52
49
 
@@ -122,9 +119,6 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
122
119
  let chunks = 0;
123
120
  let lastMessage: Record<string, unknown> | undefined;
124
121
  const startTime = Date.now();
125
- let rateWindowStartedAt = startTime;
126
- let rateWindowStartedBytes = 0;
127
- let rateBytesPerSecond: number | undefined;
128
122
 
129
123
  while (written < dataLength) {
130
124
  options.throwIfAborted?.();
@@ -153,7 +147,7 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
153
147
  );
154
148
  isWritePending = false;
155
149
  } catch (error) {
156
- if (retryCount >= maxChunkRetries || !isProtocolV2ResponseTimeout(error)) throw error;
150
+ if (retryCount >= maxChunkRetries || !isRetryableFileWriteTimeout(error)) throw error;
157
151
  retryCount += 1;
158
152
  options.throwIfAborted?.();
159
153
  }
@@ -182,30 +176,16 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
182
176
  written =
183
177
  rawProcessedByte === undefined ? written + chunk.byteLength : processedByte - startOffset;
184
178
  chunks += 1;
185
- const now = Date.now();
186
- const elapsedMs = now - startTime;
179
+ const elapsedMs = Date.now() - startTime;
187
180
  const transferredBytes = Math.min(written, dataLength);
188
- const rateWindowElapsedMs = now - rateWindowStartedAt;
189
- if (rateWindowElapsedMs >= FILE_TRANSFER_RATE_WINDOW_MS) {
190
- const rateWindowBytes = Math.max(transferredBytes - rateWindowStartedBytes, 0);
191
- rateBytesPerSecond = Math.round((rateWindowBytes / rateWindowElapsedMs) * 1000);
192
- rateWindowStartedAt = now;
193
- rateWindowStartedBytes = transferredBytes;
194
- } else if (rateBytesPerSecond === undefined && elapsedMs > 0) {
195
- rateBytesPerSecond = Math.round((transferredBytes / elapsedMs) * 1000);
196
- }
197
181
  options.onProgress?.({
198
182
  progress: getConfirmedProgress(startOffset + written, totalSize, written, dataLength),
199
183
  transferredBytes,
200
184
  totalBytes: dataLength,
201
- rateBytesPerSecond,
185
+ rateBytesPerSecond:
186
+ elapsedMs > 0 ? Math.round((transferredBytes / elapsedMs) * 1000) : undefined,
202
187
  elapsedMs,
203
188
  });
204
- if (options.paceMs && options.paceMs > 0) {
205
- await new Promise(resolve => {
206
- setTimeout(resolve, options.paceMs);
207
- });
208
- }
209
189
  }
210
190
 
211
191
  return {
package/src/api/index.ts CHANGED
@@ -3,7 +3,6 @@ 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';
7
6
  export { default as getFeatures } from './GetFeatures';
8
7
  export { default as getDeviceState } from './GetDeviceState';
9
8
  export { default as getOnekeyFeatures } from './GetOnekeyFeatures';
@@ -50,7 +49,6 @@ export { default as promptWebDeviceAccess } from './PromptWebDeviceAccess';
50
49
  export { default as deviceReboot } from './protocol-v2/DeviceReboot';
51
50
  export { default as deviceGetOnboardingStatus } from './protocol-v2/DeviceGetOnboardingStatus';
52
51
  export { default as deviceUploadWallpaper } from './protocol-v2/DeviceUploadWallpaper';
53
- export { default as deviceUploadNft } from './protocol-v2/DeviceUploadNft';
54
52
  export { default as uploadPortfolio } from './UploadPortfolio';
55
53
 
56
54
  export { default as cipherKeyValue } from './CipherKeyValue';
@@ -506,7 +506,18 @@ export default class KaspaSignTransaction extends BaseMethod<KaspaSignTransactio
506
506
  'KaspaSignTransaction: device firmware uses the streaming protocol; every output requires address or addressN'
507
507
  );
508
508
  }
509
- return this.signTxStream(typedCall, response);
509
+ try {
510
+ return await this.signTxStream(typedCall, response);
511
+ } catch (error) {
512
+ // Device rejected our refTxs; the caller decides whether to sign without them.
513
+ if (
514
+ error instanceof HardwareError &&
515
+ String(error.message).toLowerCase().includes('previous transaction id mismatch')
516
+ ) {
517
+ throw ERRORS.TypedError(HardwareErrorCode.KaspaPrevTxIdMismatch, String(error.message));
518
+ }
519
+ throw error;
520
+ }
510
521
  }
511
522
 
512
523
  // Legacy answer to a streaming-only packet: no prehash material exists.
@@ -13,9 +13,7 @@ export default class ProtocolInfoRequest extends BaseMethod {
13
13
  }
14
14
 
15
15
  async run() {
16
- const res = await this.device.commands.typedCall('ProtocolInfoRequest', 'ProtocolInfo', {
17
- eventless_wallet_session: true,
18
- });
16
+ const res = await this.device.commands.typedCall('ProtocolInfoRequest', 'ProtocolInfo', {});
19
17
  return Promise.resolve(res.message);
20
18
  }
21
19
  }
@@ -118,7 +118,6 @@ 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') ||
122
121
  message.includes('multiplatformbleadapter') ||
123
122
  message.includes('multipalformebleadapter') ||
124
123
  compactMessage.includes('rxerrorerror6') ||
@@ -4,8 +4,6 @@ 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;
9
7
  button: (...event: DeviceEvents[typeof DEVICE.BUTTON]) => void;
10
8
  passphrase: (...event: DeviceEvents[typeof DEVICE.PASSPHRASE]) => void;
11
9
  passphraseOnDevice: (...event: DeviceEvents[typeof DEVICE.PASSPHRASE_ON_DEVICE]) => void;
@@ -17,8 +15,6 @@ export function registerHardwareUiEventListeners(
17
15
  handlers: HardwareUiEventHandlers
18
16
  ) {
19
17
  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);
22
18
  device.on(DEVICE.BUTTON, handlers.button);
23
19
  device.on(DEVICE.PASSPHRASE, handlers.passphrase);
24
20
  device.on(DEVICE.PASSPHRASE_ON_DEVICE, handlers.passphraseOnDevice);