@onekeyfe/hd-core 1.2.3-alpha.3 → 1.2.3-alpha.4

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 (57) hide show
  1. package/README.md +1 -1
  2. package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +503 -10
  3. package/__tests__/core-error-output.test.ts +169 -1
  4. package/__tests__/device-lifecycle-events.test.ts +350 -2
  5. package/__tests__/open-wallet-session-error-response.test.ts +2 -2
  6. package/__tests__/open-wallet-session.test.ts +8 -411
  7. package/__tests__/protocol-v2.test.ts +51 -0
  8. package/__tests__/public-device-state-api.test.ts +2 -7
  9. package/__tests__/search-devices.test.ts +196 -8
  10. package/dist/api/GetFeatures.d.ts.map +1 -1
  11. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  12. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  13. package/dist/api/SearchDevices.d.ts +2 -15
  14. package/dist/api/SearchDevices.d.ts.map +1 -1
  15. package/dist/api/allnetwork/AllNetworkGetAddress.d.ts +2 -0
  16. package/dist/api/allnetwork/AllNetworkGetAddress.d.ts.map +1 -1
  17. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts +7 -1
  18. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  19. package/dist/api/allnetwork/AllNetworkGetAddressByLoop.d.ts.map +1 -1
  20. package/dist/api/device/DeviceVerify.d.ts.map +1 -1
  21. package/dist/core/RequestQueue.d.ts +1 -0
  22. package/dist/core/RequestQueue.d.ts.map +1 -1
  23. package/dist/core/index.d.ts +1 -0
  24. package/dist/core/index.d.ts.map +1 -1
  25. package/dist/data-manager/TransportManager.d.ts +2 -0
  26. package/dist/data-manager/TransportManager.d.ts.map +1 -1
  27. package/dist/device/Device.d.ts +2 -0
  28. package/dist/device/Device.d.ts.map +1 -1
  29. package/dist/index.d.ts +17 -19
  30. package/dist/index.js +449 -184
  31. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  32. package/dist/types/api/getFeatures.d.ts.map +1 -1
  33. package/dist/types/api/getPassphraseState.d.ts.map +1 -1
  34. package/dist/types/api/openWalletSession.d.ts +1 -10
  35. package/dist/types/api/openWalletSession.d.ts.map +1 -1
  36. package/dist/types/params.d.ts.map +1 -1
  37. package/dist/utils/patch.d.ts +1 -1
  38. package/dist/utils/patch.d.ts.map +1 -1
  39. package/package.json +4 -4
  40. package/src/api/GetFeatures.ts +1 -0
  41. package/src/api/GetPassphraseState.ts +1 -0
  42. package/src/api/OpenWalletSession.ts +7 -77
  43. package/src/api/SearchDevices.ts +121 -27
  44. package/src/api/allnetwork/AllNetworkGetAddress.ts +79 -45
  45. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +95 -24
  46. package/src/api/allnetwork/AllNetworkGetAddressByLoop.ts +3 -0
  47. package/src/api/device/DeviceVerify.ts +8 -0
  48. package/src/core/RequestQueue.ts +20 -0
  49. package/src/core/index.ts +135 -43
  50. package/src/data/messages/messages-protocol-v2.json +21 -0
  51. package/src/data-manager/TransportManager.ts +14 -3
  52. package/src/device/Device.ts +58 -27
  53. package/src/protocols/protocol-v2/walletSession.ts +7 -0
  54. package/src/types/api/getFeatures.ts +2 -1
  55. package/src/types/api/getPassphraseState.ts +2 -5
  56. package/src/types/api/openWalletSession.ts +7 -19
  57. package/src/types/params.ts +7 -0
@@ -982,45 +982,6 @@ describe('openWalletSession', () => {
982
982
  );
983
983
  });
984
984
 
985
- test('uses an explicit wallet binding to resume on Protocol V2', async () => {
986
- const typedCall = jest
987
- .fn()
988
- .mockResolvedValueOnce({ message: { version: 2 } })
989
- .mockResolvedValueOnce({
990
- message: {
991
- btc_test_address: 'hidden-state',
992
- session_id: 'renewed-session',
993
- },
994
- });
995
- const promptPassphrase = jest.fn();
996
- const method = new OpenWalletSession({
997
- payload: {
998
- method: 'openWalletSession',
999
- connectId: 'connect-id',
1000
- mode: 'resume-hidden',
1001
- deviceId: 'device-1',
1002
- passphraseState: 'hidden-state',
1003
- },
1004
- });
1005
- method.init();
1006
- deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
1007
- method.device = createDevice({ typedCall, promptPassphrase }) as any;
1008
-
1009
- await expect(method.run()).resolves.toEqual({
1010
- protocol: 'V2',
1011
- walletType: 'hidden',
1012
- deviceId: 'device-1',
1013
- passphraseState: 'hidden-state',
1014
- resumed: true,
1015
- });
1016
- expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
1017
- session_id: 'known-session',
1018
- btc_test_address: 'hidden-state',
1019
- ...standardSessionGet,
1020
- });
1021
- expect(promptPassphrase).not.toHaveBeenCalled();
1022
- });
1023
-
1024
985
  test.each([
1025
986
  {
1026
987
  mode: 'standard',
@@ -1035,12 +996,6 @@ describe('openWalletSession', () => {
1035
996
  deviceId: 'device-1',
1036
997
  passphraseState: 'hidden-state',
1037
998
  },
1038
- {
1039
- mode: 'resume-hidden',
1040
- deviceId: 'device-1',
1041
- passphraseState: 'hidden-state',
1042
- initSession: false,
1043
- },
1044
999
  ])('rejects legacy parameters combined with explicit mode: %o', params => {
1045
1000
  const method = new OpenWalletSession({
1046
1001
  payload: {
@@ -1076,15 +1031,7 @@ describe('openWalletSession', () => {
1076
1031
  }
1077
1032
  );
1078
1033
 
1079
- test('reuses the SDK-managed Protocol V1 hidden-wallet session before validation', async () => {
1080
- const typedCall = jest.fn().mockResolvedValue({
1081
- type: 'PassphraseState',
1082
- message: {
1083
- passphrase_state: 'hidden-state',
1084
- session_id: 'known-session',
1085
- unlocked_attach_pin: false,
1086
- },
1087
- });
1034
+ test('rejects the removed resume-hidden mode', () => {
1088
1035
  const method = new OpenWalletSession({
1089
1036
  payload: {
1090
1037
  method: 'openWalletSession',
@@ -1092,76 +1039,15 @@ describe('openWalletSession', () => {
1092
1039
  mode: 'resume-hidden',
1093
1040
  deviceId: 'device-1',
1094
1041
  passphraseState: 'hidden-state',
1095
- },
1096
- });
1097
- method.init();
1098
- deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
1099
- const device = createDevice({ typedCall });
1100
- device.isProtocolV2 = () => false;
1101
- device.features = {
1102
- ...device.features,
1103
- deviceId: 'device-1',
1104
- unlocked: true,
1105
- sessionId: null,
1106
- };
1107
- device.getCurrentFirmwareVersionString = () => '4.15.0';
1108
- device.getCurrentDeviceType = () => EDeviceType.Pro;
1109
- device.getFeatures = jest.fn();
1110
- method.device = device as any;
1111
-
1112
- await expect(method.run()).resolves.toMatchObject({
1113
- protocol: 'V1',
1114
- walletType: 'hidden',
1115
- passphraseState: 'hidden-state',
1116
- resumed: true,
1117
- });
1118
- expect(device.initialize).toHaveBeenCalledWith({
1119
- deviceId: 'device-1',
1120
- passphraseState: 'hidden-state',
1121
- });
1122
- expect(typedCall).toHaveBeenCalledWith('GetPassphraseState', 'PassphraseState', {
1123
- passphrase_state: 'hidden-state',
1042
+ } as any,
1124
1043
  });
1125
- });
1126
1044
 
1127
- test('rejects a Protocol V1 resume when the device returns another hidden wallet', async () => {
1128
- const typedCall = jest.fn().mockResolvedValue({
1129
- type: 'PassphraseState',
1130
- message: {
1131
- passphrase_state: 'other-hidden-state',
1132
- session_id: 'other-session',
1133
- unlocked_attach_pin: false,
1134
- },
1135
- });
1136
- const method = new OpenWalletSession({
1137
- payload: {
1138
- method: 'openWalletSession',
1139
- connectId: 'connect-id',
1140
- mode: 'resume-hidden',
1141
- deviceId: 'device-1',
1142
- passphraseState: 'hidden-state',
1143
- },
1144
- });
1145
- method.init();
1146
- deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
1147
- const device = createDevice({ typedCall });
1148
- device.isProtocolV2 = () => false;
1149
- device.features = {
1150
- ...device.features,
1151
- deviceId: 'device-1',
1152
- unlocked: true,
1153
- sessionId: null,
1154
- };
1155
- device.getCurrentFirmwareVersionString = () => '4.15.0';
1156
- device.getCurrentDeviceType = () => EDeviceType.Pro;
1157
- device.getFeatures = jest.fn();
1158
- method.device = device as any;
1159
-
1160
- await expect(method.run()).rejects.toMatchObject({
1161
- errorCode: HardwareErrorCode.DeviceCheckPassphraseStateError,
1162
- });
1163
- expect(device.clearInternalState).toHaveBeenCalledTimes(1);
1164
- expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBeUndefined();
1045
+ expect(() => method.init()).toThrow(
1046
+ expect.objectContaining({
1047
+ errorCode: HardwareErrorCode.CallMethodInvalidParameter,
1048
+ message: 'Parameter [mode] must be one of standard or select-hidden.',
1049
+ })
1050
+ );
1165
1051
  });
1166
1052
 
1167
1053
  test('opens the standard wallet without selecting a hidden wallet', async () => {
@@ -1882,295 +1768,6 @@ describe('openWalletSession', () => {
1882
1768
  }
1883
1769
  );
1884
1770
 
1885
- test('resumes a known hidden wallet without prompting or device selection', async () => {
1886
- const typedCall = jest
1887
- .fn()
1888
- .mockResolvedValueOnce({ message: { version: 2 } })
1889
- .mockResolvedValueOnce({
1890
- message: {
1891
- btc_test_address: 'hidden-state',
1892
- session_id: 'renewed-session',
1893
- },
1894
- });
1895
- const promptPassphrase = jest.fn();
1896
- const method = new OpenWalletSession({
1897
- payload: {
1898
- method: 'openWalletSession',
1899
- connectId: 'connect-id',
1900
- mode: 'resume-hidden',
1901
- deviceId: 'device-1',
1902
- passphraseState: 'hidden-state',
1903
- },
1904
- });
1905
- method.init();
1906
- deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
1907
- method.device = createDevice({ typedCall, promptPassphrase }) as any;
1908
-
1909
- await expect(method.run()).resolves.toEqual({
1910
- protocol: 'V2',
1911
- walletType: 'hidden',
1912
- deviceId: 'device-1',
1913
- passphraseState: 'hidden-state',
1914
- resumed: true,
1915
- });
1916
- expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
1917
- session_id: 'known-session',
1918
- btc_test_address: 'hidden-state',
1919
- ...standardSessionGet,
1920
- });
1921
- expect(promptPassphrase).not.toHaveBeenCalled();
1922
- });
1923
-
1924
- test('validates a locked Protocol V2 resume binding after deviceId refresh', async () => {
1925
- const typedCall = jest
1926
- .fn()
1927
- .mockResolvedValueOnce({ message: { version: 2 } })
1928
- .mockResolvedValueOnce({
1929
- message: {
1930
- btc_test_address: 'hidden-state',
1931
- session_id: 'renewed-session',
1932
- },
1933
- });
1934
- const method = new OpenWalletSession({
1935
- payload: {
1936
- method: 'openWalletSession',
1937
- connectId: 'connect-id',
1938
- mode: 'resume-hidden',
1939
- deviceId: 'device-1',
1940
- passphraseState: 'hidden-state',
1941
- },
1942
- });
1943
- method.init();
1944
- deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
1945
- const device = createDevice({ typedCall });
1946
- device.features.unlocked = false;
1947
- device.getDeviceState = jest
1948
- .fn()
1949
- .mockResolvedValueOnce({
1950
- identity: { deviceId: undefined },
1951
- status: { unlocked: false, passphraseProtection: true },
1952
- })
1953
- .mockResolvedValueOnce({
1954
- identity: { deviceId: 'device-1' },
1955
- status: {
1956
- unlocked: true,
1957
- passphraseProtection: true,
1958
- unlockedAttachPin: false,
1959
- },
1960
- });
1961
- device.unlockDevice = jest.fn().mockImplementation(() => {
1962
- device.features.unlocked = true;
1963
- return Promise.resolve(device.features);
1964
- });
1965
- method.device = device as any;
1966
-
1967
- await expect(method.run()).resolves.toMatchObject({
1968
- protocol: 'V2',
1969
- walletType: 'hidden',
1970
- deviceId: 'device-1',
1971
- passphraseState: 'hidden-state',
1972
- resumed: true,
1973
- });
1974
- expect(device.unlockDevice).toHaveBeenCalledTimes(1);
1975
- expect(device.getDeviceState).toHaveBeenCalledTimes(2);
1976
- expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
1977
- session_id: 'known-session',
1978
- btc_test_address: 'hidden-state',
1979
- ...standardSessionGet,
1980
- });
1981
- const sessionGetCall = typedCall.mock.calls.findIndex(
1982
- ([requestName]) => requestName === 'DeviceSessionGet'
1983
- );
1984
- expect(device.getDeviceState.mock.invocationCallOrder[1]).toBeLessThan(
1985
- typedCall.mock.invocationCallOrder[sessionGetCall]
1986
- );
1987
- });
1988
-
1989
- test('rejects a Protocol V2 resume when the refreshed deviceId does not match', async () => {
1990
- const typedCall = jest.fn().mockResolvedValue({
1991
- message: {
1992
- btc_test_address: 'hidden-state',
1993
- session_id: 'renewed-session',
1994
- },
1995
- });
1996
- const method = new OpenWalletSession({
1997
- payload: {
1998
- method: 'openWalletSession',
1999
- connectId: 'connect-id',
2000
- mode: 'resume-hidden',
2001
- deviceId: 'device-1',
2002
- passphraseState: 'hidden-state',
2003
- },
2004
- });
2005
- method.init();
2006
- deviceWalletSessionStore.set('device-1', 'hidden-state', 'known-session');
2007
- const device = createDevice({ typedCall });
2008
- device.features.unlocked = false;
2009
- device.getDeviceState = jest
2010
- .fn()
2011
- .mockResolvedValueOnce({
2012
- identity: { deviceId: undefined },
2013
- status: { passphraseProtection: true },
2014
- })
2015
- .mockResolvedValueOnce({
2016
- identity: { deviceId: 'other-device' },
2017
- status: {
2018
- unlocked: true,
2019
- passphraseProtection: true,
2020
- unlockedAttachPin: false,
2021
- },
2022
- });
2023
- device.unlockDevice = jest.fn().mockImplementation(() => {
2024
- device.features.unlocked = true;
2025
- return Promise.resolve(device.features);
2026
- });
2027
- method.device = device as any;
2028
-
2029
- await expect(method.run()).rejects.toMatchObject({
2030
- errorCode: HardwareErrorCode.DeviceCheckDeviceIdError,
2031
- });
2032
- expect(typedCall).not.toHaveBeenCalled();
2033
- expect(device.clearInternalState).not.toHaveBeenCalled();
2034
- expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBeUndefined();
2035
- });
2036
-
2037
- test('reselects the expected hidden wallet when a cached Protocol V2 session is invalid', async () => {
2038
- const typedCall = jest
2039
- .fn()
2040
- .mockResolvedValueOnce({ message: { version: 2 } })
2041
- .mockRejectedValueOnce(
2042
- Object.assign(new Error('Invalid session'), {
2043
- errorCode: HardwareErrorCode.WalletSessionInvalid,
2044
- })
2045
- )
2046
- .mockResolvedValueOnce({ message: {} })
2047
- .mockResolvedValueOnce({
2048
- message: {
2049
- btc_test_address: 'hidden-state',
2050
- session_id: 'renewed-session',
2051
- },
2052
- });
2053
- const promptPassphrase = jest.fn().mockResolvedValue({ passphrase: 'host hidden wallet' });
2054
- const method = new OpenWalletSession({
2055
- payload: {
2056
- method: 'openWalletSession',
2057
- connectId: 'connect-id',
2058
- mode: 'resume-hidden',
2059
- deviceId: 'device-1',
2060
- passphraseState: 'hidden-state',
2061
- },
2062
- });
2063
- method.init();
2064
- deviceWalletSessionStore.set('device-1', 'hidden-state', 'expired-session');
2065
- method.device = createDevice({ typedCall, promptPassphrase }) as any;
2066
-
2067
- await expect(method.run()).resolves.toEqual({
2068
- protocol: 'V2',
2069
- walletType: 'hidden',
2070
- deviceId: 'device-1',
2071
- passphraseState: 'hidden-state',
2072
- resumed: false,
2073
- });
2074
- expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
2075
- session_id: 'expired-session',
2076
- btc_test_address: 'hidden-state',
2077
- ...standardSessionGet,
2078
- });
2079
- expect(promptPassphrase).toHaveBeenCalledTimes(1);
2080
- expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBe('renewed-session');
2081
- });
2082
-
2083
- test('recovers the current Attach PIN wallet when the cached session is invalid', async () => {
2084
- const typedCall = jest
2085
- .fn()
2086
- .mockResolvedValueOnce({ message: { version: 2 } })
2087
- .mockRejectedValueOnce(
2088
- Object.assign(new Error('Invalid session'), {
2089
- errorCode: HardwareErrorCode.WalletSessionInvalid,
2090
- })
2091
- )
2092
- .mockResolvedValueOnce({
2093
- message: {
2094
- btc_test_address: 'hidden-state',
2095
- session_id: 'renewed-session',
2096
- },
2097
- });
2098
- const promptPassphrase = jest.fn();
2099
- const method = new OpenWalletSession({
2100
- payload: {
2101
- method: 'openWalletSession',
2102
- connectId: 'connect-id',
2103
- mode: 'resume-hidden',
2104
- deviceId: 'device-1',
2105
- passphraseState: 'hidden-state',
2106
- },
2107
- });
2108
- method.init();
2109
- deviceWalletSessionStore.set('device-1', 'hidden-state', 'expired-session');
2110
- const device = createDevice({ unlockedAttachPin: true, typedCall, promptPassphrase });
2111
- method.device = device as any;
2112
-
2113
- await expect(method.run()).resolves.toEqual({
2114
- protocol: 'V2',
2115
- walletType: 'hidden',
2116
- deviceId: 'device-1',
2117
- passphraseState: 'hidden-state',
2118
- resumed: false,
2119
- });
2120
- expect(typedCall.mock.calls.filter(call => call[0] === 'DeviceSessionGet')).toEqual([
2121
- [
2122
- 'DeviceSessionGet',
2123
- 'DeviceSession',
2124
- {
2125
- session_id: 'expired-session',
2126
- btc_test_address: 'hidden-state',
2127
- },
2128
- ],
2129
- ['DeviceSessionGet', 'DeviceSession', {}],
2130
- ]);
2131
- expect(promptPassphrase).not.toHaveBeenCalled();
2132
- expect(device.lockDevice).not.toHaveBeenCalled();
2133
- expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBe('renewed-session');
2134
- });
2135
-
2136
- test('selects the expected hidden wallet when Protocol V2 has no cached session', async () => {
2137
- const typedCall = jest
2138
- .fn()
2139
- .mockResolvedValueOnce({ message: { version: 2 } })
2140
- .mockResolvedValueOnce({
2141
- message: {
2142
- btc_test_address: 'hidden-state',
2143
- session_id: 'new-session',
2144
- },
2145
- });
2146
- const promptPassphrase = jest.fn().mockResolvedValue({ passphrase: 'host hidden wallet' });
2147
- const method = new OpenWalletSession({
2148
- payload: {
2149
- method: 'openWalletSession',
2150
- connectId: 'connect-id',
2151
- mode: 'resume-hidden',
2152
- deviceId: 'device-1',
2153
- passphraseState: 'hidden-state',
2154
- },
2155
- });
2156
- method.init();
2157
- method.device = createDevice({ typedCall, promptPassphrase }) as any;
2158
-
2159
- await expect(method.run()).resolves.toEqual({
2160
- protocol: 'V2',
2161
- walletType: 'hidden',
2162
- deviceId: 'device-1',
2163
- passphraseState: 'hidden-state',
2164
- resumed: false,
2165
- });
2166
- expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
2167
- btc_test_address: 'hidden-state',
2168
- ...standardSessionGet,
2169
- });
2170
- expect(promptPassphrase).not.toHaveBeenCalled();
2171
- expect(deviceWalletSessionStore.get('device-1', 'hidden-state')).toBe('new-session');
2172
- });
2173
-
2174
1771
  test.each([false, true])(
2175
1772
  'openWalletSession does not thread CommonParams.deriveCardano: %s',
2176
1773
  async deriveCardano => {
@@ -1,4 +1,5 @@
1
1
  import { Buffer } from 'buffer';
2
+ import { randomBytes } from 'crypto';
2
3
  import { EDeviceType, EFirmwareType, ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
3
4
  import { sha256 } from '@noble/hashes/sha256';
4
5
  import { bytesToHex } from '@noble/hashes/utils';
@@ -1824,6 +1825,56 @@ describe('Protocol V2 feature adapter', () => {
1824
1825
  ]);
1825
1826
  });
1826
1827
 
1828
+ test.each([false, true])(
1829
+ 'rejects the first incorrect passphrase after a missing or expired session (cached: %s)',
1830
+ async cached => {
1831
+ const deviceId = `first-passphrase-error-${String(cached)}`;
1832
+ const device = Device.fromDescriptor({
1833
+ id: deviceId,
1834
+ path: deviceId,
1835
+ protocolType: 'V2',
1836
+ } as never);
1837
+ device.features = normalizeProtocolV2Features(
1838
+ { ...descriptor, protocolType: 'V2' } as never,
1839
+ {
1840
+ status: { device_id: deviceId, unlocked: true, passphrase_enabled: true },
1841
+ }
1842
+ );
1843
+ device.passphraseState = 'expected-public-address';
1844
+ if (cached) {
1845
+ preloadSessionCache(deviceId, device.passphraseState, randomBytes(32).toString('hex'));
1846
+ }
1847
+ let reads = 0;
1848
+ const typedCall = createWalletSessionTypedCall(
1849
+ jest.fn((request: string) => {
1850
+ if (request === 'DeviceSessionAskPassphrase') return { message: {} };
1851
+ if (request === 'DeviceSessionGet') {
1852
+ reads += 1;
1853
+ if (reads === 1) {
1854
+ throw ERRORS.TypedError(HardwareErrorCode.WalletSessionInvalid);
1855
+ }
1856
+ return {
1857
+ message: {
1858
+ session_id: randomBytes(32).toString('hex'),
1859
+ btc_test_address: 'different-public-address',
1860
+ },
1861
+ };
1862
+ }
1863
+ throw new Error(`Unexpected request: ${request}`);
1864
+ })
1865
+ );
1866
+ const promptPassphrase = jest.fn().mockResolvedValue({ passphraseOnDevice: true });
1867
+ device.commands = { typedCall, promptPassphrase } as never;
1868
+
1869
+ await expect(getProtocolV2WalletSession(device)).rejects.toMatchObject({
1870
+ errorCode: HardwareErrorCode.DeviceCheckPassphraseStateError,
1871
+ });
1872
+ expect(promptPassphrase).toHaveBeenCalledTimes(1);
1873
+ expect(reads).toBe(2);
1874
+ expect(device.getInternalState()).toBeUndefined();
1875
+ }
1876
+ );
1877
+
1827
1878
  test('reselects a hidden wallet when the cached Pro2 session resolves to another wallet', async () => {
1828
1879
  const device = Device.fromDescriptor({
1829
1880
  id: 'cache-device-mismatch',
@@ -22,7 +22,6 @@ describe('public device state API boundary', () => {
22
22
  expect((publicTypes as Record<string, unknown>).OpenWalletSessionMode).toEqual({
23
23
  Standard: 'standard',
24
24
  SelectHidden: 'select-hidden',
25
- ResumeHidden: 'resume-hidden',
26
25
  });
27
26
  });
28
27
 
@@ -83,9 +82,7 @@ describe('public device state API boundary', () => {
83
82
  useEmptyPassphrase: false,
84
83
  });
85
84
  await api.openWalletSession('device-2', {
86
- mode: publicTypes.OpenWalletSessionMode.ResumeHidden,
87
- deviceId: 'wallet-device-1',
88
- passphraseState: 'wallet-state-1',
85
+ mode: publicTypes.OpenWalletSessionMode.SelectHidden,
89
86
  });
90
87
  await api.clearSessionCache({
91
88
  deviceId: 'wallet-device-1',
@@ -100,9 +97,7 @@ describe('public device state API boundary', () => {
100
97
  });
101
98
  expect(call).toHaveBeenNthCalledWith(2, {
102
99
  connectId: 'device-2',
103
- mode: 'resume-hidden',
104
- deviceId: 'wallet-device-1',
105
- passphraseState: 'wallet-state-1',
100
+ mode: 'select-hidden',
106
101
  method: 'openWalletSession',
107
102
  });
108
103
  expect(call).toHaveBeenNthCalledWith(3, {