@onekeyfe/hd-core 1.2.0-alpha.64 → 1.2.0-alpha.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +313 -0
- package/__tests__/DeviceCommands.test.ts +59 -13
- package/__tests__/DeviceEventRegistration.test.ts +6 -0
- package/__tests__/check-all-firmware-release-protocol-v2.test.ts +198 -3
- package/__tests__/connectSettings.test.ts +5 -47
- package/__tests__/core-initialization.test.ts +23 -0
- package/__tests__/device-connector-protocol.test.ts +81 -0
- package/__tests__/device-lifecycle-events.test.ts +105 -3
- package/__tests__/device-pool-state.test.ts +22 -0
- package/__tests__/device-settings.test.ts +39 -18
- package/__tests__/device-state-contract.test.ts +1 -0
- package/__tests__/device-state-mapper.test.ts +13 -1
- package/__tests__/device-utils.test.ts +48 -1
- package/__tests__/deviceSettings.test.ts +11 -1
- package/__tests__/deviceUploadNft.test.ts +316 -0
- package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +31 -59
- package/__tests__/get-device-state.test.ts +132 -12
- package/__tests__/homescreen.test.ts +41 -1
- package/__tests__/kaspa-use-tweak-pro2.test.ts +2 -2
- package/__tests__/kaspaSignTransaction.test.ts +3 -26
- package/__tests__/logBlockEvent.test.ts +1 -1
- package/__tests__/method-protocol-support.test.ts +19 -0
- package/__tests__/open-wallet-session.test.ts +568 -37
- package/__tests__/pro2Nft.test.ts +108 -0
- package/__tests__/protocol-binding.test.ts +89 -0
- package/__tests__/protocol-v2-resources.test.ts +340 -0
- package/__tests__/protocol-v2-ui-lifecycle.test.ts +91 -0
- package/__tests__/protocol-v2-unlock-policy.test.ts +300 -37
- package/__tests__/protocol-v2.test.ts +1506 -1097
- package/__tests__/protocolV2FileWrite.test.ts +152 -0
- package/__tests__/protocolV2UiInteraction.test.ts +63 -0
- package/__tests__/public-pro2-api-boundary.test.ts +1 -0
- package/__tests__/search-devices.test.ts +12 -3
- package/__tests__/tron-sign-message-init.test.ts +2 -2
- package/__tests__/uiProgressThrottle.test.ts +74 -0
- package/__tests__/uiPromiseRegistry.test.ts +115 -0
- package/dist/api/BaseMethod.d.ts +3 -1
- package/dist/api/BaseMethod.d.ts.map +1 -1
- package/dist/api/CheckAllFirmwareRelease.d.ts +2 -1
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/DetectDeviceConnectProtocol.d.ts +7 -0
- package/dist/api/DetectDeviceConnectProtocol.d.ts.map +1 -0
- package/dist/api/FirmwareUpdate.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts +0 -11
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts +3 -7
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +13 -27
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/GetPassphraseState.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts.map +1 -1
- package/dist/api/SearchDevices.d.ts.map +1 -1
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
- package/dist/api/device/DeviceSettings.d.ts.map +1 -1
- package/dist/api/device/DeviceUnlock.d.ts +2 -2
- package/dist/api/device/DeviceUnlock.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts +1 -5
- package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +4 -11
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- package/dist/api/firmware/getBinary.d.ts +0 -7
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/firmware/updateBootloader.d.ts +0 -2
- package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/uploadFirmware.d.ts +1 -9
- package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
- package/dist/api/helpers/protocolV2FileWrite.d.ts +9 -0
- package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/kaspa/KaspaGetAddress.d.ts +1 -1
- package/dist/api/kaspa/KaspaSignTransaction.d.ts +1 -1
- package/dist/api/kaspa/KaspaSignTransaction.d.ts.map +1 -1
- package/dist/api/polkadot/PolkadotGetAddress.d.ts +1 -1
- package/dist/api/polkadot/networks.d.ts +1 -1
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts +31 -0
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -0
- package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
- package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
- package/dist/api/solana/SolSignMessage.d.ts +1 -1
- package/dist/api/solana/SolSignOffchainMessage.d.ts +1 -1
- package/dist/api/solana/SolSignTransaction.d.ts +2 -2
- package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
- package/dist/api/sui/SuiGetAddress.d.ts +1 -1
- package/dist/api/sui/SuiGetPublicKey.d.ts +1 -1
- package/dist/api/sui/SuiSignMessage.d.ts +1 -1
- package/dist/api/sui/SuiSignTransaction.d.ts +1 -1
- package/dist/api/ton/TonGetAddress.d.ts +1 -1
- package/dist/api/ton/TonSignMessage.d.ts +1 -1
- package/dist/api/ton/TonSignProof.d.ts +1 -1
- package/dist/api/tron/TronSignMessage.d.ts +2 -2
- package/dist/api/tron/TronSignTransaction.d.ts +1 -1
- package/dist/core/deviceEventRegistration.d.ts +2 -0
- package/dist/core/deviceEventRegistration.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/uiPromiseRegistry.d.ts +6 -0
- package/dist/core/uiPromiseRegistry.d.ts.map +1 -0
- package/dist/data-manager/DataManager.d.ts +9 -4
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/data-manager/TransportManager.d.ts.map +1 -1
- package/dist/data-manager/connectSettings.d.ts.map +1 -1
- package/dist/device/Device.d.ts +29 -6
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts +4 -4
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/device/DeviceConnector.d.ts +2 -1
- package/dist/device/DeviceConnector.d.ts.map +1 -1
- package/dist/device/DevicePool.d.ts.map +1 -1
- package/dist/deviceProfile/protocolV2DeviceIdentity.d.ts.map +1 -1
- package/dist/events/device.d.ts +4 -0
- package/dist/events/device.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/events/ui-promise.d.ts +4 -2
- package/dist/events/ui-promise.d.ts.map +1 -1
- package/dist/events/ui-request.d.ts +31 -2
- package/dist/events/ui-request.d.ts.map +1 -1
- package/dist/events/ui-response.d.ts +10 -2
- package/dist/events/ui-response.d.ts.map +1 -1
- package/dist/index.d.ts +243 -248
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3051 -3774
- package/dist/inject.d.ts +6 -1
- package/dist/inject.d.ts.map +1 -1
- package/dist/lowLevelInject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/features.d.ts +0 -4
- package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/firmware.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/resources.d.ts +30 -0
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/uiInteraction.d.ts +7 -4
- package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockPolicy.d.ts +1 -3
- package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +22 -0
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/walletSession.d.ts +6 -1
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/dist/topLevelInject.d.ts.map +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts +3 -5
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/detectDeviceConnectProtocol.d.ts +4 -0
- package/dist/types/api/detectDeviceConnectProtocol.d.ts.map +1 -0
- package/dist/types/api/deviceUnlock.d.ts +5 -1
- package/dist/types/api/deviceUnlock.d.ts.map +1 -1
- package/dist/types/api/deviceUpdateBootloader.d.ts +0 -6
- package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +2 -4
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +4 -71
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +7 -10
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/protocolV2.d.ts +3 -0
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/types/device.d.ts +2 -2
- package/dist/types/device.d.ts.map +1 -1
- package/dist/types/params.d.ts +1 -0
- package/dist/types/params.d.ts.map +1 -1
- package/dist/types/settings.d.ts +38 -21
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesCompat.d.ts +0 -1
- package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesUtils.d.ts +4 -0
- package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
- package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
- package/dist/utils/deviceSettings.d.ts.map +1 -1
- package/dist/utils/homescreen.d.ts +4 -0
- package/dist/utils/homescreen.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/dist/utils/pro2Nft.d.ts +31 -0
- package/dist/utils/pro2Nft.d.ts.map +1 -0
- package/dist/utils/pro2Wallpaper.d.ts +10 -0
- package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
- package/dist/utils/uiProgressThrottle.d.ts +3 -0
- package/dist/utils/uiProgressThrottle.d.ts.map +1 -0
- package/package.json +4 -4
- package/src/api/BaseMethod.ts +8 -10
- package/src/api/CheckAllFirmwareRelease.ts +59 -60
- package/src/api/DetectDeviceConnectProtocol.ts +18 -0
- package/src/api/FirmwareUpdate.ts +7 -15
- package/src/api/FirmwareUpdateV2.ts +126 -316
- package/src/api/FirmwareUpdateV3.ts +63 -265
- package/src/api/FirmwareUpdateV4.ts +597 -1005
- package/src/api/GetPassphraseState.ts +7 -1
- package/src/api/OpenWalletSession.ts +71 -17
- package/src/api/SearchDevices.ts +3 -1
- package/src/api/allnetwork/AllNetworkGetAddress.ts +21 -21
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +36 -11
- package/src/api/device/DeviceSettings.ts +5 -4
- package/src/api/device/DeviceUnlock.ts +8 -3
- package/src/api/device/DeviceUpdateBootloader.ts +6 -125
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +27 -83
- package/src/api/firmware/updateBootloader.ts +4 -19
- package/src/api/firmware/uploadFirmware.ts +39 -144
- package/src/api/helpers/protocolV2FileWrite.ts +202 -63
- package/src/api/index.ts +2 -0
- package/src/api/kaspa/KaspaGetAddress.ts +1 -1
- package/src/api/kaspa/KaspaSignTransaction.ts +2 -13
- package/src/api/polkadot/networks.ts +3 -3
- package/src/api/protocol-v2/DeviceUploadNft.ts +197 -0
- package/src/api/protocol-v2/ProtocolInfoRequest.ts +3 -1
- package/src/api/protocol-v2/helpers.ts +1 -1
- package/src/api/solana/SolSignMessage.ts +1 -1
- package/src/api/solana/SolSignOffchainMessage.ts +1 -1
- package/src/api/solana/SolSignTransaction.ts +2 -2
- package/src/api/sui/SuiGetAddress.ts +1 -1
- package/src/api/sui/SuiGetPublicKey.ts +1 -1
- package/src/api/sui/SuiSignMessage.ts +1 -1
- package/src/api/sui/SuiSignTransaction.ts +1 -1
- package/src/api/ton/TonGetAddress.ts +1 -1
- package/src/api/ton/TonSignMessage.ts +1 -1
- package/src/api/ton/TonSignProof.ts +1 -1
- package/src/api/tron/TronSignMessage.ts +2 -2
- package/src/api/tron/TronSignTransaction.ts +1 -1
- package/src/core/deviceEventRegistration.ts +4 -0
- package/src/core/index.ts +213 -111
- package/src/core/uiPromiseRegistry.ts +63 -0
- package/src/data/messages/messages-protocol-v2.json +25 -0
- package/src/data-manager/DataManager.ts +113 -41
- package/src/data-manager/TransportManager.ts +6 -0
- package/src/data-manager/connectSettings.ts +0 -11
- package/src/device/Device.ts +274 -49
- package/src/device/DeviceCommands.ts +31 -4
- package/src/device/DeviceConnector.ts +33 -13
- package/src/device/DevicePool.ts +21 -7
- package/src/deviceProfile/buildDeviceFeatures.ts +2 -2
- package/src/deviceProfile/protocolV2DeviceIdentity.ts +3 -0
- package/src/events/device.ts +4 -0
- package/src/events/logBlockEvent.ts +1 -0
- package/src/events/ui-promise.ts +4 -2
- package/src/events/ui-request.ts +36 -2
- package/src/events/ui-response.ts +12 -2
- package/src/index.ts +0 -5
- package/src/inject.ts +60 -24
- package/src/lowLevelInject.ts +7 -8
- package/src/protocols/protocol-v2/features.ts +10 -7
- package/src/protocols/protocol-v2/firmware.ts +2 -0
- package/src/protocols/protocol-v2/resources.ts +390 -0
- package/src/protocols/protocol-v2/uiInteraction.ts +46 -6
- package/src/protocols/protocol-v2/unlockPolicy.ts +1 -105
- package/src/protocols/protocol-v2/unlockPolicyRunner.ts +131 -0
- package/src/protocols/protocol-v2/walletSession.ts +214 -36
- package/src/topLevelInject.ts +7 -8
- package/src/types/api/checkAllFirmwareRelease.ts +3 -5
- package/src/types/api/detectDeviceConnectProtocol.ts +6 -0
- package/src/types/api/deviceUnlock.ts +12 -1
- package/src/types/api/deviceUpdateBootloader.ts +0 -6
- package/src/types/api/export.ts +1 -18
- package/src/types/api/firmwareUpdate.ts +6 -79
- package/src/types/api/index.ts +13 -14
- package/src/types/api/protocolV2.ts +13 -0
- package/src/types/device.ts +15 -3
- package/src/types/params.ts +7 -1
- package/src/types/settings.ts +60 -22
- package/src/utils/deviceFeaturesCompat.ts +5 -6
- package/src/utils/deviceFeaturesUtils.ts +14 -3
- package/src/utils/deviceInfoUtils.ts +2 -0
- package/src/utils/deviceSettings.ts +3 -0
- package/src/utils/homescreen.ts +32 -6
- package/src/utils/index.ts +6 -1
- package/src/utils/pro2Nft.ts +142 -0
- package/src/utils/pro2Wallpaper.ts +35 -8
- package/src/utils/uiProgressThrottle.ts +63 -0
- package/__tests__/device-initialize-timeout.test.ts +0 -56
- package/__tests__/firmware-update/check-all-firmware-release.test.ts +0 -175
- package/__tests__/firmware-update/firmware-artifact-source.test.ts +0 -119
- package/__tests__/firmware-update/firmware-host-binding.test.ts +0 -70
- package/__tests__/firmware-update/firmware-preparation-error.test.ts +0 -27
- package/__tests__/firmware-update/firmware-update-bootloader-poll.test.ts +0 -200
- package/__tests__/firmware-update/firmware-update-capabilities.test.ts +0 -13
- package/__tests__/firmware-update/firmware-update-plan-bootloader-identity.test.ts +0 -394
- package/__tests__/firmware-update/firmware-update-plan.test.ts +0 -593
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +0 -213
- package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +0 -58
- package/__tests__/firmware-update/firmware-upload-source.test.ts +0 -70
- package/dist/api/firmware/FirmwareArtifactSource.d.ts +0 -25
- package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareHostBinding.d.ts +0 -6
- package/dist/api/firmware/FirmwareHostBinding.d.ts.map +0 -1
- package/dist/api/firmware/FirmwarePreparationError.d.ts +0 -3
- package/dist/api/firmware/FirmwarePreparationError.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +0 -3
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -25
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +0 -32
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +0 -1
- package/dist/api/firmware/progressThrottle.d.ts +0 -3
- package/dist/api/firmware/progressThrottle.d.ts.map +0 -1
- package/dist/protocols/protocol-v2/lockedError.d.ts +0 -2
- package/dist/protocols/protocol-v2/lockedError.d.ts.map +0 -1
- package/dist/protocols/protocol-v2/unlockRetry.d.ts +0 -10
- package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdateCapabilities.d.ts +0 -9
- package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdatePlan.d.ts +0 -28
- package/dist/types/api/firmwareUpdatePlan.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +0 -42
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +0 -1
- package/src/api/firmware/FirmwareArtifactSource.ts +0 -278
- package/src/api/firmware/FirmwareHostBinding.ts +0 -100
- package/src/api/firmware/FirmwarePreparationError.ts +0 -12
- package/src/api/firmware/FirmwareUpdateCapabilities.ts +0 -9
- package/src/api/firmware/FirmwareUpdatePlan.ts +0 -772
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +0 -449
- package/src/api/firmware/progressThrottle.ts +0 -44
- package/src/protocols/protocol-v2/lockedError.ts +0 -10
- package/src/protocols/protocol-v2/unlockRetry.ts +0 -109
- package/src/types/api/firmwareUpdateCapabilities.ts +0 -9
- package/src/types/api/firmwareUpdatePlan.ts +0 -38
- package/src/types/api/firmwareUpdatePreparedPlan.ts +0 -53
|
@@ -5,9 +5,12 @@ import {
|
|
|
5
5
|
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
6
6
|
|
|
7
7
|
import { DataManager } from '../../data-manager';
|
|
8
|
+
import { LoggerNames, getLogger } from '../../utils/logger';
|
|
8
9
|
|
|
9
10
|
import type { DeviceCommands } from '../../device/DeviceCommands';
|
|
10
11
|
|
|
12
|
+
const Log = getLogger(LoggerNames.Method);
|
|
13
|
+
|
|
11
14
|
export type ProtocolV2FileWriteData = ArrayBuffer | Uint8Array | Blob | string;
|
|
12
15
|
|
|
13
16
|
export type ProtocolV2FileWriteProgress = {
|
|
@@ -18,6 +21,12 @@ export type ProtocolV2FileWriteProgress = {
|
|
|
18
21
|
elapsedMs: number;
|
|
19
22
|
};
|
|
20
23
|
|
|
24
|
+
export type ProtocolV2FileWriteChunkContext = {
|
|
25
|
+
offset: number;
|
|
26
|
+
chunkLength: number;
|
|
27
|
+
totalSize: number;
|
|
28
|
+
};
|
|
29
|
+
|
|
21
30
|
export type ProtocolV2FileWriteOptions = {
|
|
22
31
|
commands: Pick<DeviceCommands, 'typedCall'>;
|
|
23
32
|
path: string;
|
|
@@ -30,20 +39,63 @@ export type ProtocolV2FileWriteOptions = {
|
|
|
30
39
|
append?: boolean;
|
|
31
40
|
uiPercentage?: number;
|
|
32
41
|
timeoutMs?: number;
|
|
42
|
+
writeWithResponse?: boolean;
|
|
33
43
|
maxChunkRetries?: number;
|
|
44
|
+
paceMs?: number;
|
|
34
45
|
throwIfAborted?: () => void;
|
|
46
|
+
getUiPercentage?: (context: ProtocolV2FileWriteChunkContext) => number | undefined;
|
|
35
47
|
onProgress?: (progress: ProtocolV2FileWriteProgress) => void;
|
|
36
48
|
};
|
|
37
49
|
|
|
38
50
|
const MIN_FILE_CHUNK_SIZE = 64;
|
|
51
|
+
const FILE_TRANSFER_RATE_WINDOW_MS = 1000;
|
|
52
|
+
const FILE_TRANSFER_LOG_INTERVAL_MS = 10_000;
|
|
53
|
+
const SESSION_ERROR = 'session not found';
|
|
54
|
+
|
|
55
|
+
function formatFileTransferRate(bytesPerSecond: number) {
|
|
56
|
+
return (Math.max(bytesPerSecond, 0) / 1024).toFixed(2);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function getAverageFileTransferRate(transferredBytes: number, elapsedMs: number) {
|
|
60
|
+
if (elapsedMs <= 0) return 0;
|
|
61
|
+
return Math.round((Math.max(transferredBytes, 0) / elapsedMs) * 1000);
|
|
62
|
+
}
|
|
39
63
|
|
|
40
|
-
function
|
|
64
|
+
function getFileTransferTransport() {
|
|
65
|
+
const env = DataManager.getSettings('env');
|
|
66
|
+
return env && DataManager.isBleConnect(env) ? 'BLE' : String(env ?? 'unknown');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function logFileTransferMetrics({
|
|
70
|
+
transport,
|
|
71
|
+
status,
|
|
72
|
+
transferredBytes,
|
|
73
|
+
totalBytes,
|
|
74
|
+
elapsedMs,
|
|
75
|
+
rateBytesPerSecond,
|
|
76
|
+
}: {
|
|
77
|
+
transport: string;
|
|
78
|
+
status: 'progress' | 'completed' | 'failed';
|
|
79
|
+
transferredBytes: number;
|
|
80
|
+
totalBytes: number;
|
|
81
|
+
elapsedMs: number;
|
|
82
|
+
rateBytesPerSecond: number;
|
|
83
|
+
}) {
|
|
84
|
+
Log.log(
|
|
85
|
+
`[FileWrite] metrics transport=${transport} status=${status} bytes=${transferredBytes}/${totalBytes} elapsed=${(
|
|
86
|
+
elapsedMs / 1000
|
|
87
|
+
).toFixed(2)}s speed=${formatFileTransferRate(rateBytesPerSecond)} KiB/s`
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function isProtocolV2ResponseTimeout(error: unknown) {
|
|
41
92
|
if (!error || typeof error !== 'object') return false;
|
|
42
|
-
const candidate = error as { errorCode?: number; code?: number; message?: string };
|
|
93
|
+
const candidate = error as { errorCode?: number; code?: number | string; message?: string };
|
|
43
94
|
const code = candidate.errorCode ?? candidate.code;
|
|
44
95
|
return (
|
|
45
96
|
code === HardwareErrorCode.BleTimeoutError ||
|
|
46
|
-
|
|
97
|
+
code === 'response-timeout' ||
|
|
98
|
+
/(?:BLE|Lowlevel|Protocol V2) response timeout/i.test(candidate.message ?? '')
|
|
47
99
|
);
|
|
48
100
|
}
|
|
49
101
|
|
|
@@ -119,75 +171,162 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
|
|
|
119
171
|
let chunks = 0;
|
|
120
172
|
let lastMessage: Record<string, unknown> | undefined;
|
|
121
173
|
const startTime = Date.now();
|
|
174
|
+
let rateWindowStartedAt = startTime;
|
|
175
|
+
let rateWindowStartedBytes = 0;
|
|
176
|
+
let rateBytesPerSecond: number | undefined;
|
|
177
|
+
let lastConfirmedAt = startTime;
|
|
178
|
+
let logWindowStartedAt = startTime;
|
|
179
|
+
let logWindowStartedBytes = 0;
|
|
180
|
+
const transport = getFileTransferTransport();
|
|
122
181
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
182
|
+
try {
|
|
183
|
+
while (written < dataLength) {
|
|
184
|
+
options.throwIfAborted?.();
|
|
185
|
+
const chunk = data.slice(written, Math.min(written + chunkSize, dataLength));
|
|
186
|
+
const offset = startOffset + written;
|
|
187
|
+
const progress =
|
|
188
|
+
options.uiPercentage ??
|
|
189
|
+
options.getUiPercentage?.({
|
|
190
|
+
offset,
|
|
191
|
+
chunkLength: chunk.byteLength,
|
|
192
|
+
totalSize,
|
|
193
|
+
}) ??
|
|
194
|
+
getDeviceTransferProgress(offset, offset + chunk.byteLength, totalSize);
|
|
195
|
+
const request = {
|
|
196
|
+
file: { path: options.path, offset, total_size: totalSize, data: chunk },
|
|
197
|
+
overwrite: chunks === 0 ? options.overwrite ?? false : false,
|
|
198
|
+
append: options.append ?? false,
|
|
199
|
+
ui_percentage: progress,
|
|
200
|
+
};
|
|
201
|
+
const maxChunkRetries = Math.max(Math.floor(options.maxChunkRetries ?? 0), 0);
|
|
202
|
+
let retryCount = 0;
|
|
203
|
+
let response;
|
|
204
|
+
let isWritePending = true;
|
|
205
|
+
while (isWritePending) {
|
|
206
|
+
try {
|
|
207
|
+
const callOptions =
|
|
208
|
+
options.writeWithResponse === undefined
|
|
209
|
+
? { timeoutMs: options.timeoutMs }
|
|
210
|
+
: {
|
|
211
|
+
...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
|
|
212
|
+
writeWithResponse: options.writeWithResponse,
|
|
213
|
+
};
|
|
214
|
+
response = await options.commands.typedCall(
|
|
215
|
+
'FilesystemFileWrite',
|
|
216
|
+
'FilesystemFile',
|
|
217
|
+
request,
|
|
218
|
+
callOptions
|
|
219
|
+
);
|
|
220
|
+
isWritePending = false;
|
|
221
|
+
} catch (error) {
|
|
222
|
+
if (retryCount >= maxChunkRetries || !isProtocolV2ResponseTimeout(error)) throw error;
|
|
223
|
+
retryCount += 1;
|
|
224
|
+
options.throwIfAborted?.();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (!response) {
|
|
228
|
+
throw ERRORS.TypedError(
|
|
229
|
+
HardwareErrorCode.RuntimeError,
|
|
230
|
+
'FilesystemFileWrite completed without a response'
|
|
147
231
|
);
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
232
|
+
}
|
|
233
|
+
const responseType = (response as { type?: string }).type;
|
|
234
|
+
if (responseType && responseType !== 'FilesystemFile') {
|
|
235
|
+
const responseError = (response as { message?: { error?: unknown } }).message?.error;
|
|
236
|
+
if (typeof responseError === 'string' && responseError.includes(SESSION_ERROR)) {
|
|
237
|
+
throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, SESSION_ERROR);
|
|
238
|
+
}
|
|
239
|
+
throw ERRORS.TypedError(
|
|
240
|
+
HardwareErrorCode.RuntimeError,
|
|
241
|
+
`FilesystemFileWrite received unexpected response ${responseType}`
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
options.throwIfAborted?.();
|
|
245
|
+
lastMessage = response.message;
|
|
246
|
+
const rawProcessedByte = response.message?.processed_byte;
|
|
247
|
+
const processedByte = Number(rawProcessedByte);
|
|
248
|
+
if (
|
|
249
|
+
rawProcessedByte !== undefined &&
|
|
250
|
+
(!Number.isFinite(processedByte) ||
|
|
251
|
+
processedByte <= offset ||
|
|
252
|
+
processedByte > offset + chunk.byteLength)
|
|
253
|
+
) {
|
|
254
|
+
throw ERRORS.TypedError(
|
|
255
|
+
HardwareErrorCode.RuntimeError,
|
|
256
|
+
`FilesystemFileWrite invalid processed_byte ${processedByte}`
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
written =
|
|
260
|
+
rawProcessedByte === undefined ? written + chunk.byteLength : processedByte - startOffset;
|
|
261
|
+
chunks += 1;
|
|
262
|
+
const now = Date.now();
|
|
263
|
+
lastConfirmedAt = now;
|
|
264
|
+
const elapsedMs = now - startTime;
|
|
265
|
+
const transferredBytes = Math.min(written, dataLength);
|
|
266
|
+
const rateWindowElapsedMs = now - rateWindowStartedAt;
|
|
267
|
+
if (rateWindowElapsedMs >= FILE_TRANSFER_RATE_WINDOW_MS) {
|
|
268
|
+
const rateWindowBytes = Math.max(transferredBytes - rateWindowStartedBytes, 0);
|
|
269
|
+
rateBytesPerSecond = Math.round((rateWindowBytes / rateWindowElapsedMs) * 1000);
|
|
270
|
+
rateWindowStartedAt = now;
|
|
271
|
+
rateWindowStartedBytes = transferredBytes;
|
|
272
|
+
} else if (rateBytesPerSecond === undefined && elapsedMs > 0) {
|
|
273
|
+
rateBytesPerSecond = Math.round((transferredBytes / elapsedMs) * 1000);
|
|
274
|
+
}
|
|
275
|
+
options.onProgress?.({
|
|
276
|
+
progress: getConfirmedProgress(startOffset + written, totalSize, written, dataLength),
|
|
277
|
+
transferredBytes,
|
|
278
|
+
totalBytes: dataLength,
|
|
279
|
+
rateBytesPerSecond,
|
|
280
|
+
elapsedMs,
|
|
281
|
+
});
|
|
282
|
+
const logWindowElapsedMs = now - logWindowStartedAt;
|
|
283
|
+
if (logWindowElapsedMs >= FILE_TRANSFER_LOG_INTERVAL_MS && transferredBytes < dataLength) {
|
|
284
|
+
const logWindowBytes = Math.max(transferredBytes - logWindowStartedBytes, 0);
|
|
285
|
+
logFileTransferMetrics({
|
|
286
|
+
transport,
|
|
287
|
+
status: 'progress',
|
|
288
|
+
transferredBytes,
|
|
289
|
+
totalBytes: dataLength,
|
|
290
|
+
elapsedMs,
|
|
291
|
+
rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
|
|
292
|
+
});
|
|
293
|
+
logWindowStartedAt = now;
|
|
294
|
+
logWindowStartedBytes = transferredBytes;
|
|
295
|
+
}
|
|
296
|
+
if (options.paceMs && options.paceMs > 0) {
|
|
297
|
+
await new Promise(resolve => {
|
|
298
|
+
setTimeout(resolve, options.paceMs);
|
|
299
|
+
});
|
|
153
300
|
}
|
|
154
301
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const processedByte = Number(rawProcessedByte);
|
|
165
|
-
if (
|
|
166
|
-
rawProcessedByte !== undefined &&
|
|
167
|
-
(!Number.isFinite(processedByte) ||
|
|
168
|
-
processedByte <= offset ||
|
|
169
|
-
processedByte > offset + chunk.byteLength)
|
|
170
|
-
) {
|
|
171
|
-
throw ERRORS.TypedError(
|
|
172
|
-
HardwareErrorCode.RuntimeError,
|
|
173
|
-
`FilesystemFileWrite invalid processed_byte ${processedByte}`
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
written =
|
|
177
|
-
rawProcessedByte === undefined ? written + chunk.byteLength : processedByte - startOffset;
|
|
178
|
-
chunks += 1;
|
|
179
|
-
const elapsedMs = Date.now() - startTime;
|
|
180
|
-
const transferredBytes = Math.min(written, dataLength);
|
|
181
|
-
options.onProgress?.({
|
|
182
|
-
progress: getConfirmedProgress(startOffset + written, totalSize, written, dataLength),
|
|
183
|
-
transferredBytes,
|
|
302
|
+
} catch (error) {
|
|
303
|
+
const now = Date.now();
|
|
304
|
+
const elapsedMs = Math.max(now - startTime, 0);
|
|
305
|
+
const logWindowElapsedMs = Math.max(now - logWindowStartedAt, 0);
|
|
306
|
+
const logWindowBytes = Math.max(written - logWindowStartedBytes, 0);
|
|
307
|
+
logFileTransferMetrics({
|
|
308
|
+
transport,
|
|
309
|
+
status: 'failed',
|
|
310
|
+
transferredBytes: written,
|
|
184
311
|
totalBytes: dataLength,
|
|
185
|
-
rateBytesPerSecond:
|
|
186
|
-
elapsedMs > 0 ? Math.round((transferredBytes / elapsedMs) * 1000) : undefined,
|
|
187
312
|
elapsedMs,
|
|
313
|
+
rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
|
|
188
314
|
});
|
|
315
|
+
throw error;
|
|
189
316
|
}
|
|
190
317
|
|
|
318
|
+
const elapsedMs = Math.max(lastConfirmedAt - startTime, 0);
|
|
319
|
+
const logWindowElapsedMs = Math.max(lastConfirmedAt - logWindowStartedAt, 0);
|
|
320
|
+
const logWindowBytes = Math.max(written - logWindowStartedBytes, 0);
|
|
321
|
+
logFileTransferMetrics({
|
|
322
|
+
transport,
|
|
323
|
+
status: 'completed',
|
|
324
|
+
transferredBytes: written,
|
|
325
|
+
totalBytes: dataLength,
|
|
326
|
+
elapsedMs,
|
|
327
|
+
rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
|
|
328
|
+
});
|
|
329
|
+
|
|
191
330
|
return {
|
|
192
331
|
...lastMessage,
|
|
193
332
|
path: options.path,
|
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';
|
|
@@ -190,7 +190,7 @@ export default class KaspaSignTransaction extends BaseMethod<KaspaSignTransactio
|
|
|
190
190
|
model_classic1s: {
|
|
191
191
|
min: '3.12.0',
|
|
192
192
|
},
|
|
193
|
-
|
|
193
|
+
model_pro2: {
|
|
194
194
|
min: '0.0.0',
|
|
195
195
|
},
|
|
196
196
|
};
|
|
@@ -506,18 +506,7 @@ 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
|
-
|
|
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
|
-
}
|
|
509
|
+
return this.signTxStream(typedCall, response);
|
|
521
510
|
}
|
|
522
511
|
|
|
523
512
|
// Legacy answer to a streaming-only packet: no prehash material exists.
|
|
@@ -23,7 +23,7 @@ const baseVersionRange = {
|
|
|
23
23
|
model_touch: {
|
|
24
24
|
min: '4.3.0',
|
|
25
25
|
},
|
|
26
|
-
|
|
26
|
+
model_pro2: {
|
|
27
27
|
min: '0.0.0',
|
|
28
28
|
},
|
|
29
29
|
};
|
|
@@ -36,7 +36,7 @@ const specialVersionRange: Record<string, DeviceFirmwareRange> = {
|
|
|
36
36
|
model_touch: {
|
|
37
37
|
min: '4.7.0',
|
|
38
38
|
},
|
|
39
|
-
|
|
39
|
+
model_pro2: {
|
|
40
40
|
min: '0.0.0',
|
|
41
41
|
},
|
|
42
42
|
},
|
|
@@ -47,7 +47,7 @@ const specialVersionRange: Record<string, DeviceFirmwareRange> = {
|
|
|
47
47
|
model_touch: {
|
|
48
48
|
min: '4.9.0',
|
|
49
49
|
},
|
|
50
|
-
|
|
50
|
+
model_pro2: {
|
|
51
51
|
min: '0.0.0',
|
|
52
52
|
},
|
|
53
53
|
},
|
|
@@ -0,0 +1,197 @@
|
|
|
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 { 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_PATH_INFO_QUERY_MESSAGE_TYPE = 60802;
|
|
44
|
+
const FILESYSTEM_FILE_WRITE_MESSAGE_TYPE = 60805;
|
|
45
|
+
const FILESYSTEM_DIR_LIST_MESSAGE_TYPE = 60808;
|
|
46
|
+
const NFT_UPDATE_MESSAGE_TYPE = 61500;
|
|
47
|
+
|
|
48
|
+
export default class DeviceUploadNft extends BaseMethod<DeviceUploadNftParams> {
|
|
49
|
+
private bundle?: Pro2NftBundle;
|
|
50
|
+
|
|
51
|
+
getSupportedProtocols() {
|
|
52
|
+
return ['V2'] as const;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
init() {
|
|
56
|
+
const {
|
|
57
|
+
image,
|
|
58
|
+
thumbnail,
|
|
59
|
+
title,
|
|
60
|
+
subtitle,
|
|
61
|
+
timestampMs = Date.now(),
|
|
62
|
+
chunkSize = PRO2_NFT_DEFAULT_CHUNK_SIZE,
|
|
63
|
+
paceMs = PRO2_NFT_DEFAULT_PACE_MS,
|
|
64
|
+
timeoutMs = PRO2_NFT_DEFAULT_TIMEOUT_MS,
|
|
65
|
+
} = this.payload;
|
|
66
|
+
if (
|
|
67
|
+
!Number.isInteger(chunkSize) ||
|
|
68
|
+
chunkSize < PRO2_NFT_MIN_CHUNK_SIZE ||
|
|
69
|
+
chunkSize > PRO2_NFT_MAX_CHUNK_SIZE
|
|
70
|
+
) {
|
|
71
|
+
throw invalidParameter(
|
|
72
|
+
`Parameter [chunkSize] must be an integer between ${PRO2_NFT_MIN_CHUNK_SIZE} and ${PRO2_NFT_MAX_CHUNK_SIZE}.`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
if (!Number.isInteger(paceMs) || paceMs < 0) {
|
|
76
|
+
throw invalidParameter('Parameter [paceMs] must be a non-negative integer.');
|
|
77
|
+
}
|
|
78
|
+
if (!Number.isInteger(timeoutMs) || timeoutMs <= 0) {
|
|
79
|
+
throw invalidParameter('Parameter [timeoutMs] must be a positive integer.');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.bundle = buildPro2NftBundle({ image, thumbnail, title, subtitle, timestampMs });
|
|
83
|
+
this.params = { image, thumbnail, title, subtitle, timestampMs, chunkSize, paceMs, timeoutMs };
|
|
84
|
+
this.unlockPolicy = 'none';
|
|
85
|
+
this.skipForceUpdateCheck = true;
|
|
86
|
+
this.useDevicePassphraseState = false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private async assertCapabilities() {
|
|
90
|
+
const protocolInfo = await this.device.ensureProtocolV2RuntimeContext();
|
|
91
|
+
const hasFileWrite = supportsProtocolV2Message(
|
|
92
|
+
protocolInfo,
|
|
93
|
+
FILESYSTEM_FILE_WRITE_MESSAGE_TYPE
|
|
94
|
+
);
|
|
95
|
+
const hasPathInfo = supportsProtocolV2Message(
|
|
96
|
+
protocolInfo,
|
|
97
|
+
FILESYSTEM_PATH_INFO_QUERY_MESSAGE_TYPE
|
|
98
|
+
);
|
|
99
|
+
const hasDirList = supportsProtocolV2Message(protocolInfo, FILESYSTEM_DIR_LIST_MESSAGE_TYPE);
|
|
100
|
+
const hasNftUpdate = supportsProtocolV2Message(protocolInfo, NFT_UPDATE_MESSAGE_TYPE);
|
|
101
|
+
if (!hasFileWrite || !hasPathInfo || !hasDirList || !hasNftUpdate) {
|
|
102
|
+
throw createDeviceNotSupportMethodError(this.name, this.device.getCurrentFirmwareType());
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private async assertStorageCapacity(basename: string) {
|
|
107
|
+
const { message: pathInfo } = await this.device.commands.typedCall(
|
|
108
|
+
'FilesystemPathInfoQuery',
|
|
109
|
+
'FilesystemPathInfo',
|
|
110
|
+
{ path: PRO2_NFT_DIRECTORY },
|
|
111
|
+
{ timeoutMs: this.params.timeoutMs }
|
|
112
|
+
);
|
|
113
|
+
if (!pathInfo.exist) return;
|
|
114
|
+
|
|
115
|
+
const { message } = await this.device.commands.typedCall(
|
|
116
|
+
'FilesystemDirList',
|
|
117
|
+
'FilesystemDir',
|
|
118
|
+
{ path: PRO2_NFT_DIRECTORY, depth: 1 },
|
|
119
|
+
{ timeoutMs: this.params.timeoutMs }
|
|
120
|
+
);
|
|
121
|
+
const existingBasenames = getCompletePro2NftBasenames(message.child_files);
|
|
122
|
+
if (existingBasenames.size >= PRO2_NFT_MAX_ITEMS && !existingBasenames.has(basename)) {
|
|
123
|
+
throw ERRORS.TypedError(HardwareErrorCode.NftStorageLimitReached, undefined, {
|
|
124
|
+
count: existingBasenames.size,
|
|
125
|
+
limit: PRO2_NFT_MAX_ITEMS,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private async updateNft(basename: string) {
|
|
131
|
+
return this.device.commands.typedCall(
|
|
132
|
+
'NftUpdate',
|
|
133
|
+
'Success',
|
|
134
|
+
{ file_name_no_ext: basename },
|
|
135
|
+
{ timeoutMs: this.params.timeoutMs }
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async run(): Promise<DeviceUploadNftResponse> {
|
|
140
|
+
const { bundle } = this;
|
|
141
|
+
if (!bundle) throw invalidParameter('NFT data has not been initialized.');
|
|
142
|
+
|
|
143
|
+
await this.assertCapabilities();
|
|
144
|
+
this.throwIfAborted();
|
|
145
|
+
await this.assertStorageCapacity(bundle.basename);
|
|
146
|
+
this.throwIfAborted();
|
|
147
|
+
|
|
148
|
+
const files = [
|
|
149
|
+
{ path: `${PRO2_NFT_DIRECTORY}/${bundle.basename}.bin`, data: bundle.image },
|
|
150
|
+
{ path: `${PRO2_NFT_DIRECTORY}/${bundle.basename}_m.bin`, data: bundle.thumbnail },
|
|
151
|
+
{ path: `${PRO2_NFT_DIRECTORY}/${bundle.basename}.json`, data: bundle.metadata },
|
|
152
|
+
];
|
|
153
|
+
const totalSize = files.reduce((sum, file) => sum + file.data.byteLength, 0);
|
|
154
|
+
let transferredBeforeFile = 0;
|
|
155
|
+
|
|
156
|
+
for (const file of files) {
|
|
157
|
+
const transferredAtFileStart = transferredBeforeFile;
|
|
158
|
+
await writeProtocolV2File({
|
|
159
|
+
commands: this.device.commands,
|
|
160
|
+
path: file.path,
|
|
161
|
+
data: file.data,
|
|
162
|
+
totalSize: file.data.byteLength,
|
|
163
|
+
chunkSize: this.params.chunkSize,
|
|
164
|
+
timeoutMs: this.params.timeoutMs,
|
|
165
|
+
paceMs: this.params.paceMs,
|
|
166
|
+
overwrite: true,
|
|
167
|
+
append: false,
|
|
168
|
+
throwIfAborted: () => this.throwIfAborted(),
|
|
169
|
+
onProgress: progress => {
|
|
170
|
+
if (typeof this.postMessage !== 'function') return;
|
|
171
|
+
const transferredBytes = transferredAtFileStart + progress.transferredBytes;
|
|
172
|
+
this.postMessage(
|
|
173
|
+
createUiMessage(UI_REQUEST.DEVICE_PROGRESS, {
|
|
174
|
+
...progress,
|
|
175
|
+
progress: Math.floor((transferredBytes / totalSize) * 100),
|
|
176
|
+
transferredBytes,
|
|
177
|
+
totalBytes: totalSize,
|
|
178
|
+
})
|
|
179
|
+
);
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
transferredBeforeFile += file.data.byteLength;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
this.throwIfAborted();
|
|
186
|
+
const response = await this.updateNft(bundle.basename);
|
|
187
|
+
return {
|
|
188
|
+
basename: bundle.basename,
|
|
189
|
+
imagePath: files[0].path,
|
|
190
|
+
thumbnailPath: files[1].path,
|
|
191
|
+
metadataPath: files[2].path,
|
|
192
|
+
totalSize,
|
|
193
|
+
nftUpdated: true,
|
|
194
|
+
message: response.message?.message,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -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') ||
|
|
@@ -137,7 +138,6 @@ export function normalizeRebootType(value: RebootTypeInput | undefined): DeviceR
|
|
|
137
138
|
|
|
138
139
|
// 与 firmware-pro2 的 proto_target_to_firmware_target 安装白名单保持一致。
|
|
139
140
|
const INSTALLABLE_FIRMWARE_TARGET_IDS = new Set<number>([
|
|
140
|
-
ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_CRATE,
|
|
141
141
|
ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER,
|
|
142
142
|
ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1,
|
|
143
143
|
ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P2,
|
|
@@ -47,7 +47,7 @@ export default class SolSignTransaction extends BaseMethod<HardwareSolanaSignTx[
|
|
|
47
47
|
getVersionRange() {
|
|
48
48
|
if (this.existsVersionedTx()) {
|
|
49
49
|
return {
|
|
50
|
-
|
|
50
|
+
model_pro2: {
|
|
51
51
|
min: '0.0.0',
|
|
52
52
|
},
|
|
53
53
|
model_mini: {
|
|
@@ -60,7 +60,7 @@ export default class SolSignTransaction extends BaseMethod<HardwareSolanaSignTx[
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
return {
|
|
63
|
-
|
|
63
|
+
model_pro2: {
|
|
64
64
|
min: '0.0.0',
|
|
65
65
|
},
|
|
66
66
|
classic: {
|