@onekeyfe/hd-core 1.2.0-alpha.67 → 1.2.0-alpha.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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__/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-v3-reconnect.test.ts +5 -0
- 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 +1449 -867
- 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.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +11 -4
- 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/firmware/FirmwareUpdateBaseMethod.d.ts +4 -3
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- 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/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 -3
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/data-manager/TransportManager.d.ts.map +1 -1
- package/dist/device/Device.d.ts +29 -5
- 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 -69
- package/dist/index.js +2563 -1217
- 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 -1
- 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/export.d.ts +1 -0
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +4 -2
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +6 -1
- 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 -8
- package/dist/types/settings.d.ts.map +1 -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 +61 -11
- package/src/api/DetectDeviceConnectProtocol.ts +18 -0
- package/src/api/FirmwareUpdate.ts +6 -2
- package/src/api/FirmwareUpdateV2.ts +5 -2
- package/src/api/FirmwareUpdateV3.ts +6 -2
- package/src/api/FirmwareUpdateV4.ts +463 -258
- 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/firmware/FirmwareUpdateBaseMethod.ts +27 -12
- package/src/api/firmware/uploadFirmware.ts +17 -4
- 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 +88 -11
- package/src/data-manager/TransportManager.ts +6 -0
- package/src/device/Device.ts +273 -43
- 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/inject.ts +58 -2
- package/src/lowLevelInject.ts +6 -3
- 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 +6 -3
- package/src/types/api/checkAllFirmwareRelease.ts +3 -1
- package/src/types/api/detectDeviceConnectProtocol.ts +6 -0
- package/src/types/api/deviceUnlock.ts +12 -1
- package/src/types/api/export.ts +1 -0
- package/src/types/api/firmwareUpdate.ts +6 -3
- package/src/types/api/index.ts +13 -0
- 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 -9
- package/src/utils/deviceFeaturesCompat.ts +5 -0
- 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/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/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/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
deviceGetOnboardingStatus,
|
|
3
3
|
deviceReboot,
|
|
4
|
+
deviceUploadNft,
|
|
4
5
|
deviceUploadWallpaper,
|
|
5
6
|
testProtocolV2Ping,
|
|
6
7
|
uploadPortfolio,
|
|
@@ -18,6 +19,7 @@ import type { checkBootloaderRelease } from './checkBootloaderRelease';
|
|
|
18
19
|
import type { checkAllFirmwareRelease } from './checkAllFirmwareRelease';
|
|
19
20
|
import type { checkFirmwareTypeAvailable } from './checkFirmwareTypeAvailable';
|
|
20
21
|
import type { searchDevices } from './searchDevices';
|
|
22
|
+
import type { detectDeviceConnectProtocol } from './detectDeviceConnectProtocol';
|
|
21
23
|
import type { getFeatures } from './getFeatures';
|
|
22
24
|
import type { getDeviceState } from './getDeviceState';
|
|
23
25
|
import type { getOnekeyFeatures } from './getOnekeyFeatures';
|
|
@@ -152,6 +154,7 @@ import type { benfenSignMessage } from './benfenSignMessage';
|
|
|
152
154
|
import type { neoGetAddress } from './neoGetAddress';
|
|
153
155
|
import type { neoSignTransaction } from './neoSignTransaction';
|
|
154
156
|
import type { ConnectSettings } from '../settings';
|
|
157
|
+
import type { HardwareConnectProtocol } from '@onekeyfe/hd-shared';
|
|
155
158
|
|
|
156
159
|
export * from './export';
|
|
157
160
|
export type { DeviceStateScope, GetDeviceStateParams } from './getDeviceState';
|
|
@@ -176,6 +179,14 @@ export type CoreApi = {
|
|
|
176
179
|
removeAllListeners: typeof removeAllListeners;
|
|
177
180
|
dispose: () => void | Promise<void>;
|
|
178
181
|
call: (params: any) => Promise<any>;
|
|
182
|
+
/**
|
|
183
|
+
* Bind a protocol that has already been verified for one transport endpoint.
|
|
184
|
+
* Every later SDK call for the same connectId uses it as a strict expectation.
|
|
185
|
+
*/
|
|
186
|
+
setDeviceConnectProtocol: (
|
|
187
|
+
connectId: string,
|
|
188
|
+
connectProtocol: HardwareConnectProtocol | undefined
|
|
189
|
+
) => void;
|
|
179
190
|
uiResponse: typeof uiResponse;
|
|
180
191
|
cancel: (connectId?: string) => void;
|
|
181
192
|
updateSettings: typeof updateSettings;
|
|
@@ -203,6 +214,7 @@ export type CoreApi = {
|
|
|
203
214
|
* Device function
|
|
204
215
|
*/
|
|
205
216
|
searchDevices: typeof searchDevices;
|
|
217
|
+
detectDeviceConnectProtocol: typeof detectDeviceConnectProtocol;
|
|
206
218
|
promptWebDeviceAccess: typeof promptWebDeviceAccess;
|
|
207
219
|
getFeatures: typeof getFeatures;
|
|
208
220
|
getDeviceState: typeof getDeviceState;
|
|
@@ -248,6 +260,7 @@ export type CoreApi = {
|
|
|
248
260
|
*/
|
|
249
261
|
deviceReboot: typeof deviceReboot;
|
|
250
262
|
deviceGetOnboardingStatus: typeof deviceGetOnboardingStatus;
|
|
263
|
+
deviceUploadNft: typeof deviceUploadNft;
|
|
251
264
|
deviceUploadWallpaper: typeof deviceUploadWallpaper;
|
|
252
265
|
uploadPortfolio: typeof uploadPortfolio;
|
|
253
266
|
|
|
@@ -5,6 +5,10 @@ import type {
|
|
|
5
5
|
DeviceUploadWallpaperParams,
|
|
6
6
|
DeviceUploadWallpaperResponse,
|
|
7
7
|
} from '../../api/protocol-v2/DeviceUploadWallpaper';
|
|
8
|
+
import type {
|
|
9
|
+
DeviceUploadNftParams,
|
|
10
|
+
DeviceUploadNftResponse,
|
|
11
|
+
} from '../../api/protocol-v2/DeviceUploadNft';
|
|
8
12
|
|
|
9
13
|
// Re-export implementation parameter types as the single source of truth.
|
|
10
14
|
export type { DeviceRebootParams, RebootTypeInput } from '../../api/protocol-v2/helpers';
|
|
@@ -12,6 +16,10 @@ export type {
|
|
|
12
16
|
DeviceUploadWallpaperParams,
|
|
13
17
|
DeviceUploadWallpaperResponse,
|
|
14
18
|
} from '../../api/protocol-v2/DeviceUploadWallpaper';
|
|
19
|
+
export type {
|
|
20
|
+
DeviceUploadNftParams,
|
|
21
|
+
DeviceUploadNftResponse,
|
|
22
|
+
} from '../../api/protocol-v2/DeviceUploadNft';
|
|
15
23
|
|
|
16
24
|
// ── Shared response shapes (Protocol V2 file system) ────────────────────
|
|
17
25
|
|
|
@@ -52,6 +60,11 @@ export declare function deviceUploadWallpaper(
|
|
|
52
60
|
params: CommonParams & DeviceUploadWallpaperParams
|
|
53
61
|
): Response<DeviceUploadWallpaperResponse>;
|
|
54
62
|
|
|
63
|
+
export declare function deviceUploadNft(
|
|
64
|
+
connectId: string,
|
|
65
|
+
params: CommonParams & DeviceUploadNftParams
|
|
66
|
+
): Response<DeviceUploadNftResponse>;
|
|
67
|
+
|
|
55
68
|
export declare function uploadPortfolio(
|
|
56
69
|
connectId: string,
|
|
57
70
|
params: {
|
package/src/types/device.ts
CHANGED
|
@@ -210,7 +210,9 @@ export type DeviceStateStatus = {
|
|
|
210
210
|
recoveryMode: boolean | null;
|
|
211
211
|
passphraseProtection: boolean | null;
|
|
212
212
|
pinProtection: boolean | null;
|
|
213
|
+
/** `attach_to_pin_enabled`:是否至少存在一个 Attach PIN 绑定。 */
|
|
213
214
|
attachToPinEnabled: boolean | null;
|
|
215
|
+
/** `unlocked_by_attach_to_pin`:本次解锁是否由 Attach PIN 完成。 */
|
|
214
216
|
unlockedAttachPin: boolean | null;
|
|
215
217
|
};
|
|
216
218
|
|
|
@@ -321,6 +323,7 @@ export type NormalizedFeatures = {
|
|
|
321
323
|
sdProtection: boolean | null;
|
|
322
324
|
wipeCodeProtection: boolean | null;
|
|
323
325
|
passphraseAlwaysOnDevice: boolean | null;
|
|
326
|
+
/** `attach_to_pin_enabled`:是否至少存在一个 Attach PIN 绑定。 */
|
|
324
327
|
attachToPinEnabled?: boolean | null;
|
|
325
328
|
safetyChecks: Enum_SafetyCheckLevel | null;
|
|
326
329
|
autoLockDelayMs: number | null;
|
|
@@ -371,14 +374,21 @@ export type IDeviceType =
|
|
|
371
374
|
| EDeviceType.Mini
|
|
372
375
|
| EDeviceType.Touch
|
|
373
376
|
| EDeviceType.Pro
|
|
374
|
-
| EDeviceType.Pro2
|
|
377
|
+
| EDeviceType.Pro2
|
|
378
|
+
| EDeviceType.Neo;
|
|
375
379
|
|
|
376
380
|
/**
|
|
377
381
|
* model_classic: 'classic' | 'classic1s' | 'classicpure'
|
|
378
382
|
* model_mini: 'classic' | 'classic1s' | 'classicpure' | 'mini'
|
|
379
383
|
* model_touch: 'touch' | 'pro'
|
|
384
|
+
* model_pro2: 'pro2' | 'neo'
|
|
380
385
|
*/
|
|
381
|
-
export type IDeviceModel =
|
|
386
|
+
export type IDeviceModel =
|
|
387
|
+
| 'model_classic'
|
|
388
|
+
| 'model_mini'
|
|
389
|
+
| 'model_touch'
|
|
390
|
+
| 'model_classic1s'
|
|
391
|
+
| 'model_pro2';
|
|
382
392
|
|
|
383
393
|
export const DeviceModelToTypes: { [deviceModel in IDeviceModel]: IDeviceType[] } = {
|
|
384
394
|
model_mini: [
|
|
@@ -388,6 +398,7 @@ export const DeviceModelToTypes: { [deviceModel in IDeviceModel]: IDeviceType[]
|
|
|
388
398
|
EDeviceType.Mini,
|
|
389
399
|
],
|
|
390
400
|
model_touch: [EDeviceType.Touch, EDeviceType.Pro],
|
|
401
|
+
model_pro2: [EDeviceType.Pro2, EDeviceType.Neo],
|
|
391
402
|
model_classic: [EDeviceType.Classic, EDeviceType.Classic1s, EDeviceType.ClassicPure],
|
|
392
403
|
model_classic1s: [EDeviceType.Classic1s, EDeviceType.ClassicPure],
|
|
393
404
|
};
|
|
@@ -399,7 +410,8 @@ export const DeviceTypeToModels: { [deviceType in IDeviceType]: IDeviceModel[] }
|
|
|
399
410
|
[EDeviceType.Mini]: ['model_mini'],
|
|
400
411
|
[EDeviceType.Touch]: ['model_touch'],
|
|
401
412
|
[EDeviceType.Pro]: ['model_touch'],
|
|
402
|
-
[EDeviceType.Pro2]: [],
|
|
413
|
+
[EDeviceType.Pro2]: ['model_pro2'],
|
|
414
|
+
[EDeviceType.Neo]: ['model_pro2'],
|
|
403
415
|
[EDeviceType.Unknown]: [],
|
|
404
416
|
};
|
|
405
417
|
|
package/src/types/params.ts
CHANGED
|
@@ -61,9 +61,15 @@ export interface CommonParams {
|
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
63
|
* Strictly expected transport protocol. The SDK actively verifies this value and
|
|
64
|
-
* rejects a mismatch.
|
|
64
|
+
* rejects a mismatch. After a successful probe, the cached protocol is also strict.
|
|
65
65
|
*/
|
|
66
66
|
connectProtocol?: HardwareConnectProtocol;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Ignore a previously bound protocol for this call and actively detect the
|
|
70
|
+
* protocol again. Intended for the first verified connection or explicit recovery.
|
|
71
|
+
*/
|
|
72
|
+
forceProtocolDetection?: boolean;
|
|
67
73
|
}
|
|
68
74
|
|
|
69
75
|
export type Params<T> = CommonParams & T & { bundle?: undefined };
|
package/src/types/settings.ts
CHANGED
|
@@ -64,6 +64,49 @@ export type IProtocolV2FirmwareComponent = {
|
|
|
64
64
|
version?: IVersionArray;
|
|
65
65
|
};
|
|
66
66
|
|
|
67
|
+
export type IProtocolV2ResourceType =
|
|
68
|
+
| 'images'
|
|
69
|
+
| 'animation'
|
|
70
|
+
| 'wallpaper'
|
|
71
|
+
| 'translations'
|
|
72
|
+
| 'roobert'
|
|
73
|
+
| 'noto';
|
|
74
|
+
|
|
75
|
+
/** Pro2 RES package descriptor. Hashes identify content without a human-managed version. */
|
|
76
|
+
export type IProtocolV2Resource = {
|
|
77
|
+
type: IProtocolV2ResourceType;
|
|
78
|
+
url: string;
|
|
79
|
+
/** Complete okpkg file size in bytes. */
|
|
80
|
+
size: number;
|
|
81
|
+
/** SHA-256 of the complete okpkg file. */
|
|
82
|
+
fileHash: string;
|
|
83
|
+
/** SHA3-512 header_hash from the signed okpkg header. */
|
|
84
|
+
headerHash: string;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/** A file from the Protocol V2 resource manifest, written directly with FileWrite. */
|
|
88
|
+
export type IProtocolV2ResourceFile = {
|
|
89
|
+
name?: string;
|
|
90
|
+
url: string;
|
|
91
|
+
devicePath: string;
|
|
92
|
+
size: number;
|
|
93
|
+
/** SHA-256 of the complete file. */
|
|
94
|
+
fileHash: string;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/** Optional Protocol V2 boot resources restored as individual files. */
|
|
98
|
+
export type IProtocolV2BootResources = {
|
|
99
|
+
required: false;
|
|
100
|
+
target: 'RES';
|
|
101
|
+
manifestUrl?: string;
|
|
102
|
+
files: IProtocolV2ResourceFile[];
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export type IProtocolV2Resources = {
|
|
106
|
+
stable: IProtocolV2Resource[];
|
|
107
|
+
boot?: IProtocolV2BootResources;
|
|
108
|
+
};
|
|
109
|
+
|
|
67
110
|
/** Pro2 RESC bundle okpkg descriptor for incremental FileWrite synchronization. */
|
|
68
111
|
export type IProtocolV2ResourceBundle = {
|
|
69
112
|
/** Bundle name, such as images, animation, translations, or fonts_roobert. */
|
|
@@ -139,17 +182,25 @@ export type IBLEFirmwareReleaseInfo = {
|
|
|
139
182
|
};
|
|
140
183
|
|
|
141
184
|
type IKnownDevice = Exclude<IDeviceType, 'unknown'>;
|
|
185
|
+
type ILegacyKnownDevice = Exclude<IKnownDevice, 'neo'>;
|
|
186
|
+
|
|
187
|
+
type IDeviceReleaseInfo = {
|
|
188
|
+
firmware: IFirmwareReleaseInfo[];
|
|
189
|
+
/** Protocol V2 payload package set */
|
|
190
|
+
'firmware-v1'?: IFirmwareReleaseInfo[];
|
|
191
|
+
'firmware-v2'?: IFirmwareReleaseInfo[];
|
|
192
|
+
'firmware-v8'?: IFirmwareReleaseInfo[];
|
|
193
|
+
'firmware-btc-v8'?: IFirmwareReleaseInfo[];
|
|
194
|
+
ble: IBLEFirmwareReleaseInfo[];
|
|
195
|
+
/** Independent Protocol V2 resource release configuration. */
|
|
196
|
+
resources?: IProtocolV2Resources;
|
|
197
|
+
};
|
|
142
198
|
|
|
143
199
|
export type DeviceTypeMap = {
|
|
144
|
-
[k in
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
'firmware-v2'?: IFirmwareReleaseInfo[];
|
|
149
|
-
'firmware-v8'?: IFirmwareReleaseInfo[];
|
|
150
|
-
'firmware-btc-v8'?: IFirmwareReleaseInfo[];
|
|
151
|
-
ble: IBLEFirmwareReleaseInfo[];
|
|
152
|
-
};
|
|
200
|
+
[k in ILegacyKnownDevice]: IDeviceReleaseInfo;
|
|
201
|
+
} & {
|
|
202
|
+
/** Optional until every remote-config producer publishes a Neo entry. */
|
|
203
|
+
neo?: IDeviceReleaseInfo;
|
|
153
204
|
};
|
|
154
205
|
|
|
155
206
|
export type AssetsMap = {
|
|
@@ -66,6 +66,8 @@ export const resolveDeviceType = (features?: DeviceFeaturesInput): IDeviceType =
|
|
|
66
66
|
return EDeviceType.Pro;
|
|
67
67
|
case 'PRO2':
|
|
68
68
|
return EDeviceType.Pro2;
|
|
69
|
+
case 'NEO':
|
|
70
|
+
return EDeviceType.Neo;
|
|
69
71
|
case 'PURE':
|
|
70
72
|
return EDeviceType.ClassicPure;
|
|
71
73
|
default:
|
|
@@ -75,6 +77,9 @@ export const resolveDeviceType = (features?: DeviceFeaturesInput): IDeviceType =
|
|
|
75
77
|
if (compatible.model?.toString().toLowerCase() === EDeviceType.Pro2) {
|
|
76
78
|
return EDeviceType.Pro2;
|
|
77
79
|
}
|
|
80
|
+
if (compatible.model?.toString().toLowerCase() === EDeviceType.Neo) {
|
|
81
|
+
return EDeviceType.Neo;
|
|
82
|
+
}
|
|
78
83
|
|
|
79
84
|
const serialNo = resolveDeviceSerialNo(features);
|
|
80
85
|
const prefix = serialNo.slice(0, 2).toLowerCase();
|
|
@@ -74,7 +74,8 @@ export const supportInputPinOnSoftware = (features?: Features): SupportFeatureTy
|
|
|
74
74
|
if (
|
|
75
75
|
deviceType === EDeviceType.Touch ||
|
|
76
76
|
deviceType === EDeviceType.Pro ||
|
|
77
|
-
deviceType === EDeviceType.Pro2
|
|
77
|
+
deviceType === EDeviceType.Pro2 ||
|
|
78
|
+
deviceType === EDeviceType.Neo
|
|
78
79
|
) {
|
|
79
80
|
return { support: false };
|
|
80
81
|
}
|
|
@@ -90,7 +91,8 @@ export const supportNewPassphrase = (features?: Features): SupportFeatureType =>
|
|
|
90
91
|
if (
|
|
91
92
|
deviceType === EDeviceType.Touch ||
|
|
92
93
|
deviceType === EDeviceType.Pro ||
|
|
93
|
-
deviceType === EDeviceType.Pro2
|
|
94
|
+
deviceType === EDeviceType.Pro2 ||
|
|
95
|
+
deviceType === EDeviceType.Neo
|
|
94
96
|
) {
|
|
95
97
|
return { support: true };
|
|
96
98
|
}
|
|
@@ -106,6 +108,8 @@ export const getPassphraseStateWithRefreshDeviceInfo = async (
|
|
|
106
108
|
expectPassphraseState?: string;
|
|
107
109
|
onlyMainPin?: boolean;
|
|
108
110
|
initSession?: boolean;
|
|
111
|
+
deriveCardano?: boolean;
|
|
112
|
+
rejectAttachPinForMainWallet?: boolean;
|
|
109
113
|
}
|
|
110
114
|
) => {
|
|
111
115
|
if (device.isProtocolV2()) {
|
|
@@ -121,6 +125,8 @@ export const getPassphraseStateWithRefreshDeviceInfo = async (
|
|
|
121
125
|
initSession: options?.initSession,
|
|
122
126
|
expectedPassphraseState: options?.expectPassphraseState,
|
|
123
127
|
onlyMainPin: options?.onlyMainPin,
|
|
128
|
+
deriveCardano: options?.deriveCardano,
|
|
129
|
+
rejectAttachPinForMainWallet: options?.rejectAttachPinForMainWallet,
|
|
124
130
|
});
|
|
125
131
|
}
|
|
126
132
|
|
|
@@ -139,7 +145,8 @@ export const getPassphraseStateWithRefreshDeviceInfo = async (
|
|
|
139
145
|
const isModeT =
|
|
140
146
|
deviceType === EDeviceType.Touch ||
|
|
141
147
|
deviceType === EDeviceType.Pro ||
|
|
142
|
-
deviceType === EDeviceType.Pro2
|
|
148
|
+
deviceType === EDeviceType.Pro2 ||
|
|
149
|
+
deviceType === EDeviceType.Neo;
|
|
143
150
|
|
|
144
151
|
// 如果可以获取到 passphraseState,但是设备 features 显示设备未开启 passphrase,需要刷新设备状态
|
|
145
152
|
// if passphraseState can be obtained, but the device features show that the device has not enabled passphrase, the device status needs to be refreshed
|
|
@@ -185,6 +192,8 @@ export const getPassphraseState = async (
|
|
|
185
192
|
expectPassphraseState?: string;
|
|
186
193
|
onlyMainPin?: boolean;
|
|
187
194
|
initSession?: boolean;
|
|
195
|
+
deriveCardano?: boolean;
|
|
196
|
+
rejectAttachPinForMainWallet?: boolean;
|
|
188
197
|
}
|
|
189
198
|
): Promise<{
|
|
190
199
|
passphraseState: string | undefined;
|
|
@@ -205,6 +214,8 @@ export const getPassphraseState = async (
|
|
|
205
214
|
initSession: options?.initSession,
|
|
206
215
|
expectedPassphraseState: options?.expectPassphraseState,
|
|
207
216
|
onlyMainPin: options?.onlyMainPin,
|
|
217
|
+
deriveCardano: options?.deriveCardano,
|
|
218
|
+
rejectAttachPinForMainWallet: options?.rejectAttachPinForMainWallet,
|
|
208
219
|
});
|
|
209
220
|
}
|
|
210
221
|
|
|
@@ -31,6 +31,7 @@ export const getDeviceTypeByBleName = (name?: string): IDeviceType => {
|
|
|
31
31
|
if (/^Touch/i.test(name)) return EDeviceType.Touch;
|
|
32
32
|
|
|
33
33
|
if (/\bPro\s*2\b/i.test(name) || /^Pro2/i.test(name)) return EDeviceType.Pro2;
|
|
34
|
+
if (/\bNeo\b/i.test(name) || /^Neo/i.test(name)) return EDeviceType.Neo;
|
|
34
35
|
if (/\bPro\b/i.test(name) || /^Pro/i.test(name)) return EDeviceType.Pro;
|
|
35
36
|
|
|
36
37
|
return EDeviceType.Unknown;
|
|
@@ -93,6 +94,7 @@ export const getMethodVersionRange = (
|
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
const modelFallbacks: IDeviceModel[] = [
|
|
97
|
+
'model_pro2',
|
|
96
98
|
'model_classic1s',
|
|
97
99
|
'model_classic',
|
|
98
100
|
'model_mini',
|
|
@@ -127,6 +127,7 @@ export const getLanguageConfig = (deviceType: IDeviceType): Record<string, strin
|
|
|
127
127
|
keys = Object.keys(LANGUAGE_LABELS) as LanguageKey[];
|
|
128
128
|
break;
|
|
129
129
|
case EDeviceType.Pro2:
|
|
130
|
+
case EDeviceType.Neo:
|
|
130
131
|
return PRO2_LANGUAGE_OPTIONS.map(option => ({ ...option }));
|
|
131
132
|
default:
|
|
132
133
|
keys = [];
|
|
@@ -176,6 +177,7 @@ export const getAutoLockOptions = (
|
|
|
176
177
|
case EDeviceType.Touch:
|
|
177
178
|
case EDeviceType.Pro:
|
|
178
179
|
case EDeviceType.Pro2:
|
|
180
|
+
case EDeviceType.Neo:
|
|
179
181
|
return withNever([30_000, 60_000, 120_000, 300_000, 600_000, 1_800_000], protocol);
|
|
180
182
|
default:
|
|
181
183
|
return [];
|
|
@@ -197,6 +199,7 @@ export const getAutoShutDownOptions = (
|
|
|
197
199
|
case EDeviceType.Pro:
|
|
198
200
|
return withNever([60_000, 120_000, 300_000, 600_000], protocol);
|
|
199
201
|
case EDeviceType.Pro2:
|
|
202
|
+
case EDeviceType.Neo:
|
|
200
203
|
return withNever([60_000, 120_000, 300_000, 600_000, 1_800_000], protocol);
|
|
201
204
|
default:
|
|
202
205
|
return [];
|
package/src/utils/homescreen.ts
CHANGED
|
@@ -4,6 +4,12 @@ import { EDeviceType } from '@onekeyfe/hd-shared';
|
|
|
4
4
|
import { getDeviceType } from './deviceInfoUtils';
|
|
5
5
|
import { getDeviceFirmwareVersion } from './deviceVersionUtils';
|
|
6
6
|
import { PRO2_WALLPAPER_HEIGHT, PRO2_WALLPAPER_WIDTH } from './pro2Wallpaper';
|
|
7
|
+
import {
|
|
8
|
+
PRO2_NFT_IMAGE_HEIGHT,
|
|
9
|
+
PRO2_NFT_IMAGE_WIDTH,
|
|
10
|
+
PRO2_NFT_THUMBNAIL_HEIGHT,
|
|
11
|
+
PRO2_NFT_THUMBNAIL_WIDTH,
|
|
12
|
+
} from './pro2Nft';
|
|
7
13
|
|
|
8
14
|
import type { Features, IDeviceType } from '../types';
|
|
9
15
|
|
|
@@ -302,6 +308,31 @@ type SizeConfig = {
|
|
|
302
308
|
radius?: number;
|
|
303
309
|
};
|
|
304
310
|
|
|
311
|
+
export const getNftSize = ({
|
|
312
|
+
deviceType,
|
|
313
|
+
thumbnail,
|
|
314
|
+
}: {
|
|
315
|
+
deviceType: IDeviceType;
|
|
316
|
+
thumbnail?: boolean;
|
|
317
|
+
}): SizeConfig | undefined => {
|
|
318
|
+
const sizes: Partial<Record<IDeviceType, { full: SizeConfig; thumbnail: SizeConfig }>> = {
|
|
319
|
+
touch: {
|
|
320
|
+
full: { width: 480, height: 800 },
|
|
321
|
+
thumbnail: { width: 238, height: 238 },
|
|
322
|
+
},
|
|
323
|
+
pro: {
|
|
324
|
+
full: { width: 480, height: 800 },
|
|
325
|
+
thumbnail: { width: 226, height: 226, radius: 40 },
|
|
326
|
+
},
|
|
327
|
+
pro2: {
|
|
328
|
+
full: { width: PRO2_NFT_IMAGE_WIDTH, height: PRO2_NFT_IMAGE_HEIGHT },
|
|
329
|
+
thumbnail: { width: PRO2_NFT_THUMBNAIL_WIDTH, height: PRO2_NFT_THUMBNAIL_HEIGHT },
|
|
330
|
+
},
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
return sizes[deviceType]?.[thumbnail ? 'thumbnail' : 'full'];
|
|
334
|
+
};
|
|
335
|
+
|
|
305
336
|
export const getHomeScreenSize = ({
|
|
306
337
|
deviceType,
|
|
307
338
|
homeScreenType,
|
|
@@ -312,12 +343,7 @@ export const getHomeScreenSize = ({
|
|
|
312
343
|
thumbnail?: boolean;
|
|
313
344
|
}) => {
|
|
314
345
|
if (deviceType === EDeviceType.Pro2) {
|
|
315
|
-
return thumbnail
|
|
316
|
-
? undefined
|
|
317
|
-
: {
|
|
318
|
-
width: PRO2_WALLPAPER_WIDTH,
|
|
319
|
-
height: PRO2_WALLPAPER_HEIGHT,
|
|
320
|
-
};
|
|
346
|
+
return thumbnail ? undefined : { width: PRO2_WALLPAPER_WIDTH, height: PRO2_WALLPAPER_HEIGHT };
|
|
321
347
|
}
|
|
322
348
|
|
|
323
349
|
const sizes: Partial<
|
package/src/utils/index.ts
CHANGED
|
@@ -54,7 +54,12 @@ export { getHDPath, getScriptType, getOutputScriptType } from '../api/helpers/pa
|
|
|
54
54
|
|
|
55
55
|
export const isBleConnect = (env: string) => env === 'react-native' || env === 'lowlevel';
|
|
56
56
|
|
|
57
|
-
export {
|
|
57
|
+
export {
|
|
58
|
+
getHomeScreenHex,
|
|
59
|
+
getHomeScreenDefaultList,
|
|
60
|
+
getHomeScreenSize,
|
|
61
|
+
getNftSize,
|
|
62
|
+
} from './homescreen';
|
|
58
63
|
export { encodePro2Wallpaper, PRO2_WALLPAPER_HEIGHT, PRO2_WALLPAPER_WIDTH } from './pro2Wallpaper';
|
|
59
64
|
export type { Pro2WallpaperColorFormat } from './pro2Wallpaper';
|
|
60
65
|
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { blake2s } from '@noble/hashes/blake2s';
|
|
2
|
+
import { bytesToHex } from '@noble/hashes/utils';
|
|
3
|
+
|
|
4
|
+
import { invalidParameter } from '../api/helpers/filesystemValidation';
|
|
5
|
+
import { encodePro2Image } from './pro2Wallpaper';
|
|
6
|
+
|
|
7
|
+
export const PRO2_NFT_IMAGE_WIDTH = 540;
|
|
8
|
+
export const PRO2_NFT_IMAGE_HEIGHT = 540;
|
|
9
|
+
export const PRO2_NFT_THUMBNAIL_WIDTH = 263;
|
|
10
|
+
export const PRO2_NFT_THUMBNAIL_HEIGHT = 263;
|
|
11
|
+
export const PRO2_NFT_DIRECTORY = 'vol1:/nft';
|
|
12
|
+
export const PRO2_NFT_DEFAULT_CHUNK_SIZE = 2048;
|
|
13
|
+
export const PRO2_NFT_DEFAULT_PACE_MS = 0;
|
|
14
|
+
export const PRO2_NFT_DEFAULT_TIMEOUT_MS = 15_000;
|
|
15
|
+
export const PRO2_NFT_MIN_CHUNK_SIZE = 64;
|
|
16
|
+
export const PRO2_NFT_MAX_CHUNK_SIZE = 2048;
|
|
17
|
+
export const PRO2_NFT_MAX_ITEMS = 10;
|
|
18
|
+
|
|
19
|
+
export type Pro2NftImage = {
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
rgba: Uint8Array | ArrayBuffer;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type Pro2NftBundle = {
|
|
26
|
+
basename: string;
|
|
27
|
+
image: Uint8Array;
|
|
28
|
+
thumbnail: Uint8Array;
|
|
29
|
+
metadata: Uint8Array;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const PRO2_NFT_BASENAME_PATTERN = /^nft-[0-9a-f]{8}-[1-9][0-9]*$/;
|
|
33
|
+
|
|
34
|
+
type Pro2NftFileType = 'image' | 'thumbnail' | 'metadata';
|
|
35
|
+
|
|
36
|
+
function parsePro2NftFile(listedPath: string):
|
|
37
|
+
| {
|
|
38
|
+
basename: string;
|
|
39
|
+
fileType: Pro2NftFileType;
|
|
40
|
+
}
|
|
41
|
+
| undefined {
|
|
42
|
+
const filename = listedPath.trim().split('/').at(-1);
|
|
43
|
+
if (!filename) return undefined;
|
|
44
|
+
|
|
45
|
+
let basename: string | undefined;
|
|
46
|
+
let fileType: Pro2NftFileType | undefined;
|
|
47
|
+
if (filename.endsWith('_m.bin')) {
|
|
48
|
+
basename = filename.slice(0, -'_m.bin'.length);
|
|
49
|
+
fileType = 'thumbnail';
|
|
50
|
+
} else if (filename.endsWith('.json')) {
|
|
51
|
+
basename = filename.slice(0, -'.json'.length);
|
|
52
|
+
fileType = 'metadata';
|
|
53
|
+
} else if (filename.endsWith('.bin')) {
|
|
54
|
+
basename = filename.slice(0, -'.bin'.length);
|
|
55
|
+
fileType = 'image';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return basename && fileType && PRO2_NFT_BASENAME_PATTERN.test(basename)
|
|
59
|
+
? { basename, fileType }
|
|
60
|
+
: undefined;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function getCompletePro2NftBasenames(childFiles?: string): Set<string> {
|
|
64
|
+
const filesByBasename = new Map<string, Set<Pro2NftFileType>>();
|
|
65
|
+
|
|
66
|
+
for (const listedPath of childFiles?.split('\n') ?? []) {
|
|
67
|
+
const file = parsePro2NftFile(listedPath);
|
|
68
|
+
if (file) {
|
|
69
|
+
const fileTypes = filesByBasename.get(file.basename) ?? new Set<Pro2NftFileType>();
|
|
70
|
+
fileTypes.add(file.fileType);
|
|
71
|
+
filesByBasename.set(file.basename, fileTypes);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return new Set(
|
|
76
|
+
[...filesByBasename.entries()]
|
|
77
|
+
.filter(([, fileTypes]) => fileTypes.size === 3)
|
|
78
|
+
.map(([basename]) => basename)
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function utf8Length(value: string): number {
|
|
83
|
+
return new TextEncoder().encode(value).byteLength;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function assertImage(
|
|
87
|
+
name: string,
|
|
88
|
+
image: Pro2NftImage,
|
|
89
|
+
expectedWidth: number,
|
|
90
|
+
expectedHeight: number
|
|
91
|
+
) {
|
|
92
|
+
if (image.width !== expectedWidth || image.height !== expectedHeight) {
|
|
93
|
+
throw invalidParameter(
|
|
94
|
+
`Pro2 NFT ${name} dimensions must be ${expectedWidth}x${expectedHeight}.`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
if (!(image.rgba instanceof ArrayBuffer) && !ArrayBuffer.isView(image.rgba)) {
|
|
98
|
+
throw invalidParameter(`Parameter [${name}.rgba] must be an ArrayBuffer or Uint8Array.`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function buildPro2NftBundle(options: {
|
|
103
|
+
image: Pro2NftImage;
|
|
104
|
+
thumbnail: Pro2NftImage;
|
|
105
|
+
title: string;
|
|
106
|
+
subtitle: string;
|
|
107
|
+
timestampMs: number;
|
|
108
|
+
}): Pro2NftBundle {
|
|
109
|
+
const { image, thumbnail, title, subtitle, timestampMs } = options;
|
|
110
|
+
assertImage('image', image, PRO2_NFT_IMAGE_WIDTH, PRO2_NFT_IMAGE_HEIGHT);
|
|
111
|
+
assertImage('thumbnail', thumbnail, PRO2_NFT_THUMBNAIL_WIDTH, PRO2_NFT_THUMBNAIL_HEIGHT);
|
|
112
|
+
const titleLength = typeof title === 'string' ? utf8Length(title) : 0;
|
|
113
|
+
const subtitleLength =
|
|
114
|
+
typeof subtitle === 'string' ? utf8Length(subtitle) : Number.POSITIVE_INFINITY;
|
|
115
|
+
if (titleLength < 1 || titleLength > 63) {
|
|
116
|
+
throw invalidParameter('Pro2 NFT title must contain 1 to 63 UTF-8 bytes.');
|
|
117
|
+
}
|
|
118
|
+
if (subtitleLength > 95) {
|
|
119
|
+
throw invalidParameter('Pro2 NFT subtitle must contain at most 95 UTF-8 bytes.');
|
|
120
|
+
}
|
|
121
|
+
if (!Number.isSafeInteger(timestampMs) || timestampMs <= 0) {
|
|
122
|
+
throw invalidParameter('Parameter [timestampMs] must be a positive safe integer.');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const encodedImage = encodePro2Image({ ...image, alphaMode: 'black-background' }).data;
|
|
126
|
+
const encodedThumbnail = encodePro2Image({
|
|
127
|
+
...thumbnail,
|
|
128
|
+
alphaMode: 'black-background',
|
|
129
|
+
}).data;
|
|
130
|
+
const metadata = new TextEncoder().encode(JSON.stringify({ title, subtitle }));
|
|
131
|
+
if (metadata.byteLength === 0 || metadata.byteLength > 512) {
|
|
132
|
+
throw invalidParameter('Pro2 NFT metadata must contain 1 to 512 UTF-8 bytes.');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const hash8 = bytesToHex(blake2s(encodedImage)).slice(0, 8);
|
|
136
|
+
return {
|
|
137
|
+
basename: `nft-${hash8}-${timestampMs}`,
|
|
138
|
+
image: encodedImage,
|
|
139
|
+
thumbnail: encodedThumbnail,
|
|
140
|
+
metadata,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
@@ -8,6 +8,8 @@ export const PRO2_WALLPAPER_HEIGHT = 1024;
|
|
|
8
8
|
|
|
9
9
|
export type Pro2WallpaperColorFormat = 'RGB565' | 'RGB565A8';
|
|
10
10
|
|
|
11
|
+
export type Pro2ImageAlphaMode = 'preserve' | 'black-background';
|
|
12
|
+
|
|
11
13
|
const COLOR_FORMAT_RGB565 = 0x12;
|
|
12
14
|
const COLOR_FORMAT_RGB565A8 = 0x14;
|
|
13
15
|
|
|
@@ -36,10 +38,11 @@ function align(value: number, boundary: number): number {
|
|
|
36
38
|
return Math.ceil(value / boundary) * boundary;
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
export function
|
|
41
|
+
export function encodePro2Image(options: {
|
|
40
42
|
width: number;
|
|
41
43
|
height: number;
|
|
42
44
|
rgba: Uint8Array | ArrayBuffer;
|
|
45
|
+
alphaMode?: Pro2ImageAlphaMode;
|
|
43
46
|
}): { data: Uint8Array; colorFormat: Pro2WallpaperColorFormat } {
|
|
44
47
|
const { width, height } = options;
|
|
45
48
|
if (!Number.isInteger(width) || width <= 0 || width > 0xffff) {
|
|
@@ -57,11 +60,14 @@ export function encodePro2Wallpaper(options: {
|
|
|
57
60
|
);
|
|
58
61
|
}
|
|
59
62
|
|
|
63
|
+
const alphaMode = options.alphaMode ?? 'preserve';
|
|
60
64
|
let hasTransparency = false;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
if (alphaMode === 'preserve') {
|
|
66
|
+
for (let index = 3; index < rgba.length; index += 4) {
|
|
67
|
+
if (rgba[index] !== 0xff) {
|
|
68
|
+
hasTransparency = true;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
65
71
|
}
|
|
66
72
|
}
|
|
67
73
|
|
|
@@ -85,9 +91,22 @@ export function encodePro2Wallpaper(options: {
|
|
|
85
91
|
for (let x = 0; x < width; x += 1) {
|
|
86
92
|
const sourceOffset = (y * width + x) * 4;
|
|
87
93
|
const thresholdIndex = ((y & 7) << 3) + (x & 7);
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
|
|
94
|
+
const alpha = rgba[sourceOffset + 3];
|
|
95
|
+
const redChannel =
|
|
96
|
+
alphaMode === 'black-background'
|
|
97
|
+
? Math.round((rgba[sourceOffset] * alpha) / 0xff)
|
|
98
|
+
: rgba[sourceOffset];
|
|
99
|
+
const greenChannel =
|
|
100
|
+
alphaMode === 'black-background'
|
|
101
|
+
? Math.round((rgba[sourceOffset + 1] * alpha) / 0xff)
|
|
102
|
+
: rgba[sourceOffset + 1];
|
|
103
|
+
const blueChannel =
|
|
104
|
+
alphaMode === 'black-background'
|
|
105
|
+
? Math.round((rgba[sourceOffset + 2] * alpha) / 0xff)
|
|
106
|
+
: rgba[sourceOffset + 2];
|
|
107
|
+
const red = Math.min(redChannel + RED_THRESHOLD[thresholdIndex], 0xff) & 0xf8;
|
|
108
|
+
const green = Math.min(greenChannel + GREEN_THRESHOLD[thresholdIndex], 0xff) & 0xfc;
|
|
109
|
+
const blue = Math.min(blueChannel + BLUE_THRESHOLD[thresholdIndex], 0xff) & 0xf8;
|
|
91
110
|
const rgb565 = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
|
|
92
111
|
const rgbOffset = 12 + y * stride + x * 2;
|
|
93
112
|
data[rgbOffset] = rgb565 & 0xff;
|
|
@@ -101,3 +120,11 @@ export function encodePro2Wallpaper(options: {
|
|
|
101
120
|
|
|
102
121
|
return { data, colorFormat };
|
|
103
122
|
}
|
|
123
|
+
|
|
124
|
+
export function encodePro2Wallpaper(options: {
|
|
125
|
+
width: number;
|
|
126
|
+
height: number;
|
|
127
|
+
rgba: Uint8Array | ArrayBuffer;
|
|
128
|
+
}): { data: Uint8Array; colorFormat: Pro2WallpaperColorFormat } {
|
|
129
|
+
return encodePro2Image(options);
|
|
130
|
+
}
|