@onekeyfe/hd-core 1.2.0-alpha.36 → 1.2.0-alpha.39

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 (79) hide show
  1. package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +5 -1
  2. package/__tests__/deviceUploadNft.test.ts +187 -0
  3. package/__tests__/homescreen.test.ts +41 -1
  4. package/__tests__/logBlockEvent.test.ts +1 -1
  5. package/__tests__/open-wallet-session.test.ts +161 -44
  6. package/__tests__/pro2Nft.test.ts +108 -0
  7. package/__tests__/protocol-v2-unlock-policy.test.ts +86 -35
  8. package/__tests__/protocol-v2.test.ts +168 -444
  9. package/__tests__/public-pro2-api-boundary.test.ts +1 -0
  10. package/__tests__/uiProgressThrottle.test.ts +74 -0
  11. package/dist/api/BaseMethod.d.ts +3 -1
  12. package/dist/api/BaseMethod.d.ts.map +1 -1
  13. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  14. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  15. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +0 -1
  16. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  17. package/dist/api/helpers/protocolV2FileWrite.d.ts +2 -0
  18. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
  19. package/dist/api/index.d.ts +1 -0
  20. package/dist/api/index.d.ts.map +1 -1
  21. package/dist/api/protocol-v2/DeviceUploadNft.d.ts +30 -0
  22. package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -0
  23. package/dist/core/index.d.ts.map +1 -1
  24. package/dist/events/logBlockEvent.d.ts.map +1 -1
  25. package/dist/index.d.ts +34 -2
  26. package/dist/index.js +544 -496
  27. package/dist/inject.d.ts.map +1 -1
  28. package/dist/protocols/protocol-v2/unlockPolicy.d.ts +1 -3
  29. package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -1
  30. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +22 -0
  31. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -0
  32. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  33. package/dist/types/api/index.d.ts +2 -1
  34. package/dist/types/api/index.d.ts.map +1 -1
  35. package/dist/types/api/protocolV2.d.ts +3 -0
  36. package/dist/types/api/protocolV2.d.ts.map +1 -1
  37. package/dist/utils/homescreen.d.ts +4 -0
  38. package/dist/utils/homescreen.d.ts.map +1 -1
  39. package/dist/utils/index.d.ts +1 -1
  40. package/dist/utils/index.d.ts.map +1 -1
  41. package/dist/utils/patch.d.ts +1 -1
  42. package/dist/utils/patch.d.ts.map +1 -1
  43. package/dist/utils/pro2Nft.d.ts +29 -0
  44. package/dist/utils/pro2Nft.d.ts.map +1 -0
  45. package/dist/utils/pro2Wallpaper.d.ts +10 -0
  46. package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
  47. package/dist/utils/uiProgressThrottle.d.ts +3 -0
  48. package/dist/utils/uiProgressThrottle.d.ts.map +1 -0
  49. package/package.json +4 -4
  50. package/src/api/BaseMethod.ts +7 -9
  51. package/src/api/OpenWalletSession.ts +37 -15
  52. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +29 -30
  53. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +0 -7
  54. package/src/api/helpers/protocolV2FileWrite.ts +11 -4
  55. package/src/api/index.ts +1 -0
  56. package/src/api/protocol-v2/DeviceUploadNft.ts +166 -0
  57. package/src/core/index.ts +83 -82
  58. package/src/data/messages/messages-protocol-v2.json +10 -15
  59. package/src/events/logBlockEvent.ts +1 -0
  60. package/src/inject.ts +1 -0
  61. package/src/protocols/protocol-v2/unlockPolicy.ts +1 -105
  62. package/src/protocols/protocol-v2/unlockPolicyRunner.ts +117 -0
  63. package/src/protocols/protocol-v2/walletSession.ts +18 -51
  64. package/src/types/api/index.ts +2 -0
  65. package/src/types/api/protocolV2.ts +13 -0
  66. package/src/utils/homescreen.ts +32 -6
  67. package/src/utils/index.ts +6 -1
  68. package/src/utils/pro2Nft.ts +91 -0
  69. package/src/utils/pro2Wallpaper.ts +35 -8
  70. package/src/utils/uiProgressThrottle.ts +63 -0
  71. package/dist/api/firmware/progressThrottle.d.ts +0 -3
  72. package/dist/api/firmware/progressThrottle.d.ts.map +0 -1
  73. package/dist/protocols/protocol-v2/lockedError.d.ts +0 -2
  74. package/dist/protocols/protocol-v2/lockedError.d.ts.map +0 -1
  75. package/dist/protocols/protocol-v2/unlockRetry.d.ts +0 -10
  76. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +0 -1
  77. package/src/api/firmware/progressThrottle.ts +0 -44
  78. package/src/protocols/protocol-v2/lockedError.ts +0 -10
  79. package/src/protocols/protocol-v2/unlockRetry.ts +0 -131
package/src/core/index.ts CHANGED
@@ -55,12 +55,12 @@ import DeviceConnector from '../device/DeviceConnector';
55
55
  import RequestQueue from './RequestQueue';
56
56
  import { registerHardwareUiEventListeners } from './deviceEventRegistration';
57
57
  import { getSynchronize } from '../utils/getSynchronize';
58
- import { runMethodWithUnlockRetry } from '../protocols/protocol-v2/unlockRetry';
59
- import { ensureProtocolV2WalletSessionUnlocked } from '../protocols/protocol-v2/walletSession';
58
+ import { runMethodWithUnlockPolicy } from '../protocols/protocol-v2/unlockPolicyRunner';
60
59
  import {
61
60
  ProtocolV2UiInteractionCoordinator,
62
61
  isProtocolV2UiEnabled,
63
62
  } from '../protocols/protocol-v2/uiInteraction';
63
+ import { createUiProgressMessageFilter } from '../utils/uiProgressThrottle';
64
64
 
65
65
  import type { ConnectSettings, Features, KnownDevice } from '../types';
66
66
  import type { CoreMessage, IFrameCallMessage, UiPromise, UiPromiseResponse } from '../events';
@@ -155,7 +155,12 @@ export const callAPI = async (context: CoreContext, message: CoreMessage) => {
155
155
  try {
156
156
  method = findMethod(message as IFrameCallMessage);
157
157
  method.connector = _connector;
158
- method.postMessage = postMessage;
158
+ const shouldPostMessage = createUiProgressMessageFilter();
159
+ method.postMessage = event => {
160
+ if (shouldPostMessage(event)) {
161
+ postMessage(event);
162
+ }
163
+ };
159
164
  method.setContext?.(context);
160
165
 
161
166
  method.requestContext = createRequestContext(method.responseID, method.name, {
@@ -551,96 +556,92 @@ const onCallDevice = async (
551
556
  );
552
557
  }
553
558
 
554
- if (method.deviceId && method.checkDeviceId) {
555
- const isSameDeviceID = await checkLiveDeviceId(device, method.deviceId);
556
- if (!isSameDeviceID) {
557
- return Promise.reject(ERRORS.TypedError(HardwareErrorCode.DeviceCheckDeviceIdError));
558
- }
559
- }
560
-
561
- /**
562
- * check firmware release info
563
- */
564
- method.checkFirmwareRelease();
559
+ try {
560
+ let deviceIdCheckedDuringUnlockPreflight = false;
561
+ const response = await runMethodWithUnlockPolicy<object>(method, device, {
562
+ uiCoordinator: protocolV2UiCoordinator,
563
+ afterStatusBeforeUnlock: () => {
564
+ if (method.deviceId && method.checkDeviceId) {
565
+ if (!device.checkDeviceId(method.deviceId)) {
566
+ throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckDeviceIdError);
567
+ }
568
+ deviceIdCheckedDuringUnlockPreflight = true;
569
+ }
570
+ },
571
+ prepare: async () => {
572
+ if (method.deviceId && method.checkDeviceId && !deviceIdCheckedDuringUnlockPreflight) {
573
+ const isSameDeviceID = await checkLiveDeviceId(device, method.deviceId);
574
+ if (!isSameDeviceID) {
575
+ throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckDeviceIdError);
576
+ }
577
+ }
565
578
 
566
- /**
567
- * check additional supported feature
568
- */
569
- method.checkDeviceSupportFeature();
579
+ /**
580
+ * check firmware release info
581
+ */
582
+ method.checkFirmwareRelease();
570
583
 
571
- // reconfigure messages
572
- if (_deviceList && device.features && !device.isProtocolV2()) {
573
- await TransportManager.reconfigure(device.features);
574
- }
584
+ /**
585
+ * check additional supported feature
586
+ */
587
+ method.checkDeviceSupportFeature();
575
588
 
576
- // Check to see if it is safe to use Passphrase
577
- checkPassphraseEnableState(method, device.features);
589
+ // reconfigure messages
590
+ if (_deviceList && device.features && !device.isProtocolV2()) {
591
+ await TransportManager.reconfigure(device.features);
592
+ }
578
593
 
579
- if (shouldCheckPassphraseState(method, device)) {
580
- // check version
581
- const support = device.supportNewPassphrase();
582
- if (!support.support) {
583
- return Promise.reject(
584
- ERRORS.TypedError(
585
- HardwareErrorCode.DeviceNotSupportPassphrase,
586
- `Device not support passphrase, please update to ${support.require}`,
587
- {
588
- require: support.require,
594
+ // Check to see if it is safe to use Passphrase
595
+ checkPassphraseEnableState(method, device.features);
596
+
597
+ if (shouldCheckPassphraseState(method, device)) {
598
+ // check version
599
+ const support = device.supportNewPassphrase();
600
+ if (!support.support) {
601
+ throw ERRORS.TypedError(
602
+ HardwareErrorCode.DeviceNotSupportPassphrase,
603
+ `Device not support passphrase, please update to ${support.require}`,
604
+ {
605
+ require: support.require,
606
+ }
607
+ );
589
608
  }
590
- )
591
- );
592
- }
593
609
 
594
- // Wallet-session recovery is part of the protected business call, not onboarding.
595
- await ensureProtocolV2WalletSessionUnlocked(device);
610
+ // Check Device passphrase State after the Protocol V2 pre-unlock gate.
611
+ const passphraseStateSafety = await device.checkPassphraseStateSafety(
612
+ method.payload?.passphraseState,
613
+ method.payload?.useEmptyPassphrase,
614
+ method.payload?.skipPassphraseCheck,
615
+ hasDeriveCardano(method)
616
+ );
596
617
 
597
- // Check Device passphrase State
598
- const passphraseStateSafety = await device.checkPassphraseStateSafety(
599
- method.payload?.passphraseState,
600
- method.payload?.useEmptyPassphrase,
601
- method.payload?.skipPassphraseCheck,
602
- hasDeriveCardano(method)
603
- );
618
+ // Double check, handles the special case of Touch/Pro
619
+ checkPassphraseEnableState(method, device.features);
604
620
 
605
- // Double check, handles the special case of Touch/Pro
606
- checkPassphraseEnableState(method, device.features);
607
-
608
- if (!passphraseStateSafety) {
609
- DevicePool.clearDeviceCache(method.payload.connectId);
610
- return Promise.reject(
611
- ERRORS.TypedError(HardwareErrorCode.DeviceCheckPassphraseStateError)
612
- );
613
- }
614
-
615
- // Protocol V2 emits the PIN phase completion from DeviceSessionAskPin.
616
- // Keep the legacy compatibility close for Protocol V1 only.
617
- if (!device.isProtocolV2()) {
618
- postMessage(createUiMessage(UI_REQUEST.CLOSE_UI_PIN_WINDOW));
619
- }
620
- }
621
+ if (!passphraseStateSafety) {
622
+ DevicePool.clearDeviceCache(method.payload.connectId);
623
+ throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckPassphraseStateError);
624
+ }
621
625
 
622
- // Automatic check safety_check level for Kovan, Ropsten, Rinkeby, Goerli test networks.
623
- try {
624
- await method.checkSafetyLevelOnTestNet();
625
- } catch (e) {
626
- const error =
627
- e instanceof HardwareError
628
- ? e
629
- : ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'open safety check failed.');
630
- // messageResponse = createResponseMessage(method.responseID, false, { error });
631
- // requestQueue.resolveRequest(method.responseID, messageResponse);
632
- // return;
633
- throw error;
634
- }
626
+ // Protocol V2 emits the PIN phase completion from DeviceSessionAskPin.
627
+ // Keep the legacy compatibility close for Protocol V1 only.
628
+ if (!device.isProtocolV2()) {
629
+ postMessage(createUiMessage(UI_REQUEST.CLOSE_UI_PIN_WINDOW));
630
+ }
631
+ }
635
632
 
636
- method.device?.commands?.checkDisposed();
633
+ // Automatic check safety_check level for Kovan, Ropsten, Rinkeby, Goerli test networks.
634
+ try {
635
+ await method.checkSafetyLevelOnTestNet();
636
+ } catch (e) {
637
+ throw e instanceof HardwareError
638
+ ? e
639
+ : ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'open safety check failed.');
640
+ }
637
641
 
638
- try {
639
- const response: object = await runMethodWithUnlockRetry(
640
- method,
641
- device,
642
- protocolV2UiCoordinator
643
- );
642
+ method.device?.commands?.checkDisposed();
643
+ },
644
+ });
644
645
  messageResponse = createResponseMessage(method.responseID, true, response);
645
646
  requestQueue.resolveRequest(method.responseID, messageResponse);
646
647
  completeMethodRequestContext(method);
@@ -470,6 +470,7 @@
470
470
  "MessageType_DeviceSessionAskPin": 61202,
471
471
  "MessageType_DeviceSessionAskPassphrase": 61203,
472
472
  "MessageType_PortfolioUpdate": 61400,
473
+ "MessageType_NftUpdate": 61500,
473
474
  "MessageType_OnboardingStatusGet": 61600,
474
475
  "MessageType_OnboardingStatus": 61601
475
476
  },
@@ -12200,26 +12201,11 @@
12200
12201
  "DeviceSessionError_Busy": 5
12201
12202
  }
12202
12203
  },
12203
- "DeviceSessionSeedDomain": {
12204
- "values": {
12205
- "SeedDomain_Standard": 1,
12206
- "SeedDomain_Cardano": 2
12207
- }
12208
- },
12209
12204
  "DeviceSessionGet": {
12210
12205
  "fields": {
12211
12206
  "session_id": {
12212
12207
  "type": "bytes",
12213
12208
  "id": 1
12214
- },
12215
- "btc_test_address": {
12216
- "type": "string",
12217
- "id": 2
12218
- },
12219
- "seed_domains": {
12220
- "rule": "repeated",
12221
- "type": "DeviceSessionSeedDomain",
12222
- "id": 3
12223
12209
  }
12224
12210
  }
12225
12211
  },
@@ -12553,6 +12539,15 @@
12553
12539
  }
12554
12540
  }
12555
12541
  },
12542
+ "NftUpdate": {
12543
+ "fields": {
12544
+ "file_name_no_ext": {
12545
+ "rule": "required",
12546
+ "type": "string",
12547
+ "id": 1
12548
+ }
12549
+ }
12550
+ },
12556
12551
  "OnboardingStep": {
12557
12552
  "values": {
12558
12553
  "ONBOARDING_STEP_UNKNOWN": 0,
@@ -10,6 +10,7 @@ export const LogBlockEvent: Set<string> = new Set([
10
10
 
11
11
  const LogLabelMethod: Set<string> = new Set([
12
12
  'openWalletSession',
13
+ 'deviceUploadNft',
13
14
  'deviceUploadWallpaper',
14
15
  'uploadPortfolio',
15
16
  'fileWrite',
package/src/inject.ts CHANGED
@@ -162,6 +162,7 @@ export const createCoreApi = (
162
162
  call({ ...params, connectId, method: 'deviceGetOnboardingStatus' }),
163
163
  deviceUploadWallpaper: (connectId, params) =>
164
164
  call({ ...params, connectId, method: 'deviceUploadWallpaper' }),
165
+ deviceUploadNft: (connectId, params) => call({ ...params, connectId, method: 'deviceUploadNft' }),
165
166
  uploadPortfolio: (connectId, params) => call({ ...params, connectId, method: 'uploadPortfolio' }),
166
167
  deviceRecovery: (connectId, params) => call({ ...params, connectId, method: 'deviceRecovery' }),
167
168
  deviceReset: (connectId, params) => call({ ...params, connectId, method: 'deviceReset' }),
@@ -1,105 +1 @@
1
- export type UnlockPolicy = 'none' | 'unlock-before-run' | 'retry-on-locked';
2
-
3
- /**
4
- * Protocol V2 methods that are safe to replay after a locked response.
5
- *
6
- * Keep this as an exact allowlist. Name-pattern matching can silently make a new
7
- * state-changing method replayable when it happens to share a suffix.
8
- */
9
- export const PROTOCOL_V2_RETRY_ON_LOCKED_METHODS = [
10
- 'cipherKeyValue',
11
- 'allNetworkGetAddress',
12
- 'allNetworkGetAddressByLoop',
13
- 'btcGetAddress',
14
- 'btcGetPublicKey',
15
- 'btcSignMessage',
16
- 'btcSignPsbt',
17
- 'btcSignTransaction',
18
- 'btcVerifyMessage',
19
- 'confluxGetAddress',
20
- 'confluxSignMessage',
21
- 'confluxSignTransaction',
22
- 'evmGetAddress',
23
- 'evmGetPublicKey',
24
- 'evmSignMessage',
25
- 'evmSignTransaction',
26
- 'evmSignTypedData',
27
- 'evmVerifyMessage',
28
- 'starcoinGetAddress',
29
- 'starcoinGetPublicKey',
30
- 'starcoinSignMessage',
31
- 'starcoinSignTransaction',
32
- 'starcoinVerifyMessage',
33
- 'nemGetAddress',
34
- 'nemSignTransaction',
35
- 'solGetAddress',
36
- 'solSignTransaction',
37
- 'solSignOffchainMessage',
38
- 'solSignMessage',
39
- 'stellarGetAddress',
40
- 'stellarSignTransaction',
41
- 'tronGetAddress',
42
- 'tronSignMessage',
43
- 'tronSignTransaction',
44
- 'nearGetAddress',
45
- 'nearSignTransaction',
46
- 'aptosGetAddress',
47
- 'aptosGetPublicKey',
48
- 'aptosSignTransaction',
49
- 'aptosSignMessage',
50
- 'aptosSignInMessage',
51
- 'algoGetAddress',
52
- 'algoSignTransaction',
53
- 'cosmosGetAddress',
54
- 'cosmosGetPublicKey',
55
- 'cosmosSignTransaction',
56
- 'xrpGetAddress',
57
- 'xrpSignTransaction',
58
- 'suiGetAddress',
59
- 'suiGetPublicKey',
60
- 'suiSignMessage',
61
- 'suiSignTransaction',
62
- 'cardanoGetAddress',
63
- 'cardanoGetPublicKey',
64
- 'cardanoSignTransaction',
65
- 'cardanoSignMessage',
66
- 'filecoinGetAddress',
67
- 'filecoinSignTransaction',
68
- 'polkadotGetAddress',
69
- 'polkadotSignTransaction',
70
- 'kaspaGetAddress',
71
- 'kaspaSignTransaction',
72
- 'nexaGetAddress',
73
- 'nexaSignTransaction',
74
- 'nostrGetPublicKey',
75
- 'nostrSignEvent',
76
- 'nostrEncryptMessage',
77
- 'nostrDecryptMessage',
78
- 'nostrSignSchnorr',
79
- 'lnurlAuth',
80
- 'nervosGetAddress',
81
- 'nervosSignTransaction',
82
- 'dnxGetAddress',
83
- 'dnxSignTransaction',
84
- 'tonGetAddress',
85
- 'tonSignMessage',
86
- 'tonSignProof',
87
- 'tonSignData',
88
- 'scdoGetAddress',
89
- 'scdoSignTransaction',
90
- 'scdoSignMessage',
91
- 'alephiumGetAddress',
92
- 'alephiumSignTransaction',
93
- 'alephiumSignMessage',
94
- 'benfenGetAddress',
95
- 'benfenGetPublicKey',
96
- 'benfenSignMessage',
97
- 'benfenSignTransaction',
98
- 'neoGetAddress',
99
- 'neoSignTransaction',
100
- ] as const;
101
-
102
- const retryOnLockedMethods = new Set<string>(PROTOCOL_V2_RETRY_ON_LOCKED_METHODS);
103
-
104
- export const getProtocolV2UnlockPolicy = (methodName: string): UnlockPolicy =>
105
- retryOnLockedMethods.has(methodName) ? 'retry-on-locked' : 'none';
1
+ export type UnlockPolicy = 'none' | 'unlock-before-run';
@@ -0,0 +1,117 @@
1
+ import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
+
3
+ import { LoggerNames, getLogger } from '../../utils';
4
+ import { isProtocolV2UiEnabled, resolveProtocolV2UiInteraction } from './uiInteraction';
5
+ import { refreshProtocolV2DeviceStatus } from './walletSession';
6
+
7
+ import type { BaseMethod } from '../../api/BaseMethod';
8
+ import type { Device } from '../../device/Device';
9
+ import type { HardwareUiInteractionMeta } from '../../events';
10
+ import type { ProtocolV2UiInteractionCoordinator } from './uiInteraction';
11
+
12
+ const Log = getLogger(LoggerNames.Core);
13
+
14
+ export type ProtocolV2UnlockContext = {
15
+ preflightCompleted: boolean;
16
+ };
17
+
18
+ export const createProtocolV2UnlockContext = (): ProtocolV2UnlockContext => ({
19
+ preflightCompleted: false,
20
+ });
21
+
22
+ type RunnableMethod = Pick<
23
+ BaseMethod,
24
+ | 'run'
25
+ | 'unlockPolicy'
26
+ | 'useDevicePassphraseState'
27
+ | 'protocolV2UiInteraction'
28
+ | 'protocolV2UiMode'
29
+ | 'params'
30
+ | 'payload'
31
+ > & {
32
+ name?: string;
33
+ protocolV2UnlockContext?: ProtocolV2UnlockContext;
34
+ };
35
+
36
+ type UiInteractionCoordinator = Pick<
37
+ ProtocolV2UiInteractionCoordinator,
38
+ 'enterMethodInteraction' | 'enterUnlockInteraction'
39
+ >;
40
+
41
+ type RunMethodWithUnlockPolicyOptions<T> = {
42
+ context?: ProtocolV2UnlockContext;
43
+ uiCoordinator?: UiInteractionCoordinator;
44
+ afterStatusBeforeUnlock?: () => void | Promise<void>;
45
+ prepare?: () => Promise<void>;
46
+ run?: () => Promise<T>;
47
+ };
48
+
49
+ export async function runMethodWithUnlockPolicy<T = unknown>(
50
+ method: RunnableMethod,
51
+ device: Device,
52
+ options: RunMethodWithUnlockPolicyOptions<T> = {}
53
+ ): Promise<T> {
54
+ const {
55
+ context = createProtocolV2UnlockContext(),
56
+ uiCoordinator,
57
+ afterStatusBeforeUnlock,
58
+ prepare,
59
+ run: configuredRun,
60
+ } = options;
61
+ const run = configuredRun ?? (() => method.run() as Promise<T>);
62
+ method.protocolV2UnlockContext = context;
63
+
64
+ const shouldEmitUi = isProtocolV2UiEnabled(method);
65
+ const shouldCoordinateUi = shouldEmitUi && uiCoordinator !== undefined;
66
+ const requiresPreUnlock =
67
+ device.isProtocolV2() &&
68
+ (method.useDevicePassphraseState || method.unlockPolicy === 'unlock-before-run') &&
69
+ !device.isBootloader?.() &&
70
+ !device.isRomloader?.();
71
+
72
+ if (requiresPreUnlock && !context.preflightCompleted) {
73
+ const status = await refreshProtocolV2DeviceStatus(device);
74
+ if (typeof status?.unlocked !== 'boolean') {
75
+ throw ERRORS.TypedError(
76
+ HardwareErrorCode.RuntimeError,
77
+ 'Protocol V2 DeviceStatus did not report an explicit unlock state.'
78
+ );
79
+ }
80
+
81
+ await afterStatusBeforeUnlock?.();
82
+
83
+ if (!status.unlocked) {
84
+ const unlockInteraction: HardwareUiInteractionMeta | undefined = shouldCoordinateUi
85
+ ? uiCoordinator.enterUnlockInteraction(method.name)
86
+ : undefined;
87
+ const unlockedStatus = await device.unlockDevice(
88
+ undefined,
89
+ shouldCoordinateUi
90
+ ? { emitUiEvent: false, interaction: unlockInteraction }
91
+ : {
92
+ source: 'unlock-coordinator',
93
+ reason: 'device-locked',
94
+ deviceOnly: true,
95
+ method: method.name,
96
+ }
97
+ );
98
+ if (unlockedStatus?.unlocked !== true) {
99
+ throw ERRORS.TypedError(
100
+ HardwareErrorCode.RuntimeError,
101
+ 'Protocol V2 device remained locked after the unlock flow.'
102
+ );
103
+ }
104
+ Log.debug('Protocol V2 pre-unlock completed', { method: method.name });
105
+ }
106
+
107
+ context.preflightCompleted = true;
108
+ }
109
+
110
+ await prepare?.();
111
+
112
+ if (shouldCoordinateUi) {
113
+ uiCoordinator.enterMethodInteraction(resolveProtocolV2UiInteraction(method));
114
+ }
115
+
116
+ return run();
117
+ }
@@ -1,5 +1,5 @@
1
1
  import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
- import { DeviceSessionPinType, DeviceSessionSeedDomain } from '@onekeyfe/hd-transport';
2
+ import { DeviceSessionPinType } from '@onekeyfe/hd-transport';
3
3
 
4
4
  import { DEVICE } from '../../events';
5
5
  import { assertCompleteDeviceSession } from './deviceSession';
@@ -60,34 +60,15 @@ const negotiateEventlessWalletSession = async (device: Device) => {
60
60
  await device.ensureProtocolV2RuntimeContext();
61
61
  };
62
62
 
63
- const getDeviceSession = async (
64
- device: Device,
65
- request: DeviceSessionGet,
66
- deriveCardano?: boolean
67
- ) => {
68
- const payload =
69
- deriveCardano === undefined
70
- ? request
71
- : {
72
- ...request,
73
- seed_domains: [
74
- DeviceSessionSeedDomain.SeedDomain_Standard,
75
- ...(deriveCardano ? [DeviceSessionSeedDomain.SeedDomain_Cardano] : []),
76
- ],
77
- };
78
- return device.commands.typedCall('DeviceSessionGet', 'DeviceSession', payload);
79
- };
63
+ const getDeviceSession = async (device: Device, request: DeviceSessionGet) =>
64
+ device.commands.typedCall('DeviceSessionGet', 'DeviceSession', request);
80
65
 
81
66
  const askDevicePassphrase = async (device: Device, requestPayload: DeviceSessionAskPassphrase) => {
82
67
  await device.commands.typedCall('DeviceSessionAskPassphrase', 'Success', requestPayload);
83
68
  await refreshProtocolV2DeviceStatus(device);
84
69
  };
85
70
 
86
- const selectDeviceSession = async (
87
- device: Device,
88
- expectedPassphraseState?: string,
89
- deriveCardano?: boolean
90
- ) => {
71
+ const selectDeviceSession = async (device: Device, expectedPassphraseState?: string) => {
91
72
  const existsAttachPinUser = device.features?.attachToPinEnabled === true;
92
73
  const metadata = {
93
74
  source: 'wallet-session-coordinator' as const,
@@ -148,7 +129,7 @@ const selectDeviceSession = async (
148
129
  emitUiEvent: false,
149
130
  interaction: attachPinInteraction,
150
131
  });
151
- return getDeviceSession(device, {}, deriveCardano);
132
+ return getDeviceSession(device, {});
152
133
  }
153
134
 
154
135
  if (hasHostPassphrase) {
@@ -156,7 +137,7 @@ const selectDeviceSession = async (
156
137
  passphrase: hostPassphrase,
157
138
  on_device: false,
158
139
  });
159
- return getDeviceSession(device, {}, deriveCardano);
140
+ return getDeviceSession(device, {});
160
141
  }
161
142
 
162
143
  device.emit(DEVICE.PASSPHRASE_ON_DEVICE, device, {
@@ -164,7 +145,7 @@ const selectDeviceSession = async (
164
145
  ...(passphraseInteraction ? { interaction: passphraseInteraction } : {}),
165
146
  });
166
147
  await askDevicePassphrase(device, { on_device: true });
167
- return getDeviceSession(device, {}, deriveCardano);
148
+ return getDeviceSession(device, {});
168
149
  };
169
150
 
170
151
  export async function getProtocolV2WalletSession(
@@ -253,14 +234,9 @@ export async function getProtocolV2WalletSession(
253
234
  if (options?.selectMainWalletBeforeRestore) {
254
235
  await selectMainWallet();
255
236
  }
256
- response = await getDeviceSession(
257
- device,
258
- {
259
- session_id: cachedStandardSession.sessionId,
260
- btc_test_address: cachedStandardSession.passphraseState,
261
- },
262
- options?.deriveCardano
263
- );
237
+ response = await getDeviceSession(device, {
238
+ session_id: cachedStandardSession.sessionId,
239
+ });
264
240
  resumed = true;
265
241
  } catch (error) {
266
242
  device.clearStandardInternalState?.();
@@ -273,18 +249,13 @@ export async function getProtocolV2WalletSession(
273
249
 
274
250
  if (!response) {
275
251
  await selectMainWallet();
276
- response = await getDeviceSession(device, {}, options?.deriveCardano);
252
+ response = await getDeviceSession(device, {});
277
253
  }
278
254
  } else if (cachedSessionId && expectedPassphraseState) {
279
255
  try {
280
- response = await getDeviceSession(
281
- device,
282
- {
283
- session_id: cachedSessionId,
284
- btc_test_address: expectedPassphraseState,
285
- },
286
- options?.deriveCardano
287
- );
256
+ response = await getDeviceSession(device, {
257
+ session_id: cachedSessionId,
258
+ });
288
259
  resumed = true;
289
260
  } catch (error) {
290
261
  device.clearInternalState();
@@ -295,11 +266,7 @@ export async function getProtocolV2WalletSession(
295
266
  }
296
267
  } else if (expectedPassphraseState) {
297
268
  try {
298
- response = await getDeviceSession(
299
- device,
300
- { btc_test_address: expectedPassphraseState },
301
- options?.deriveCardano
302
- );
269
+ response = await getDeviceSession(device, {});
303
270
  } catch (error) {
304
271
  if (options?.resumeOnly || !isWalletSessionInvalidError(error)) {
305
272
  throw error;
@@ -312,7 +279,7 @@ export async function getProtocolV2WalletSession(
312
279
  device.clearInternalState();
313
280
  throw ERRORS.TypedError(HardwareErrorCode.WalletSessionInvalid);
314
281
  }
315
- response = await selectDeviceSession(device, expectedPassphraseState, options?.deriveCardano);
282
+ response = await selectDeviceSession(device, expectedPassphraseState);
316
283
  }
317
284
 
318
285
  let { message } = response;
@@ -336,10 +303,10 @@ export async function getProtocolV2WalletSession(
336
303
  if (options?.onlyMainPin) {
337
304
  device.clearStandardInternalState?.();
338
305
  await selectMainWallet(true);
339
- response = await getDeviceSession(device, {}, options?.deriveCardano);
306
+ response = await getDeviceSession(device, {});
340
307
  } else {
341
308
  device.clearInternalState();
342
- response = await selectDeviceSession(device, expectedPassphraseState, options?.deriveCardano);
309
+ response = await selectDeviceSession(device, expectedPassphraseState);
343
310
  }
344
311
  message = response.message;
345
312
  try {
@@ -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,
@@ -234,6 +235,7 @@ export type CoreApi = {
234
235
  */
235
236
  deviceReboot: typeof deviceReboot;
236
237
  deviceGetOnboardingStatus: typeof deviceGetOnboardingStatus;
238
+ deviceUploadNft: typeof deviceUploadNft;
237
239
  deviceUploadWallpaper: typeof deviceUploadWallpaper;
238
240
  uploadPortfolio: typeof uploadPortfolio;
239
241