@sidhujag/sysweb3-keyring 1.0.545 → 1.0.547

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 (212) hide show
  1. package/coverage/clover.xml +2875 -0
  2. package/coverage/coverage-final.json +29468 -0
  3. package/coverage/lcov-report/base.css +354 -0
  4. package/coverage/lcov-report/block-navigation.js +85 -0
  5. package/coverage/lcov-report/favicon.png +0 -0
  6. package/coverage/lcov-report/index.html +320 -0
  7. package/coverage/lcov-report/prettify.css +101 -0
  8. package/coverage/lcov-report/prettify.js +1008 -0
  9. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  10. package/coverage/lcov-report/sorter.js +191 -0
  11. package/coverage/lcov-report/src/index.html +276 -0
  12. package/coverage/lcov-report/src/index.ts.html +114 -0
  13. package/coverage/lcov-report/src/initial-state.ts.html +558 -0
  14. package/coverage/lcov-report/src/keyring-manager.ts.html +6279 -0
  15. package/coverage/lcov-report/src/ledger/bitcoin_client/index.html +178 -0
  16. package/coverage/lcov-report/src/ledger/bitcoin_client/index.ts.html +144 -0
  17. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/appClient.ts.html +1560 -0
  18. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/bip32.ts.html +276 -0
  19. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/buffertools.ts.html +495 -0
  20. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/clientCommands.ts.html +1138 -0
  21. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/index.html +363 -0
  22. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkelizedPsbt.ts.html +289 -0
  23. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkle.ts.html +486 -0
  24. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkleMap.ts.html +240 -0
  25. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/policy.ts.html +342 -0
  26. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/psbtv2.ts.html +2388 -0
  27. package/coverage/lcov-report/src/ledger/bitcoin_client/lib/varint.ts.html +453 -0
  28. package/coverage/lcov-report/src/ledger/consts.ts.html +177 -0
  29. package/coverage/lcov-report/src/ledger/index.html +216 -0
  30. package/coverage/lcov-report/src/ledger/index.ts.html +1371 -0
  31. package/coverage/lcov-report/src/ledger/utils.ts.html +102 -0
  32. package/coverage/lcov-report/src/signers.ts.html +591 -0
  33. package/coverage/lcov-report/src/storage.ts.html +198 -0
  34. package/coverage/lcov-report/src/transactions/ethereum.ts.html +5826 -0
  35. package/coverage/lcov-report/src/transactions/index.html +216 -0
  36. package/coverage/lcov-report/src/transactions/index.ts.html +93 -0
  37. package/coverage/lcov-report/src/transactions/syscoin.ts.html +1521 -0
  38. package/coverage/lcov-report/src/trezor/index.html +176 -0
  39. package/coverage/lcov-report/src/trezor/index.ts.html +2655 -0
  40. package/coverage/lcov-report/src/types.ts.html +1443 -0
  41. package/coverage/lcov-report/src/utils/derivation-paths.ts.html +486 -0
  42. package/coverage/lcov-report/src/utils/index.html +196 -0
  43. package/coverage/lcov-report/src/utils/psbt.ts.html +159 -0
  44. package/coverage/lcov-report/test/helpers/constants.ts.html +627 -0
  45. package/coverage/lcov-report/test/helpers/index.html +176 -0
  46. package/coverage/lcov.info +4832 -0
  47. package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/appClient.js +1 -124
  48. package/dist/cjs/ledger/bitcoin_client/lib/appClient.js.map +1 -0
  49. package/{cjs → dist/cjs}/transactions/ethereum.js +6 -2
  50. package/dist/cjs/transactions/ethereum.js.map +1 -0
  51. package/dist/package.json +50 -0
  52. package/{types → dist/types}/ledger/bitcoin_client/lib/appClient.d.ts +0 -6
  53. package/examples/basic-usage.js +140 -0
  54. package/jest.config.js +32 -0
  55. package/package.json +31 -13
  56. package/readme.md +201 -0
  57. package/src/declare.d.ts +7 -0
  58. package/src/errorUtils.ts +83 -0
  59. package/src/hardware-wallet-manager.ts +655 -0
  60. package/src/index.ts +12 -0
  61. package/src/initial-state.ts +108 -0
  62. package/src/keyring-manager.ts +2698 -0
  63. package/src/ledger/bitcoin_client/index.ts +19 -0
  64. package/src/ledger/bitcoin_client/lib/appClient.ts +405 -0
  65. package/src/ledger/bitcoin_client/lib/bip32.ts +61 -0
  66. package/src/ledger/bitcoin_client/lib/buffertools.ts +134 -0
  67. package/src/ledger/bitcoin_client/lib/clientCommands.ts +356 -0
  68. package/src/ledger/bitcoin_client/lib/constants.ts +12 -0
  69. package/src/ledger/bitcoin_client/lib/merkelizedPsbt.ts +65 -0
  70. package/src/ledger/bitcoin_client/lib/merkle.ts +136 -0
  71. package/src/ledger/bitcoin_client/lib/merkleMap.ts +49 -0
  72. package/src/ledger/bitcoin_client/lib/policy.ts +91 -0
  73. package/src/ledger/bitcoin_client/lib/psbtv2.ts +768 -0
  74. package/src/ledger/bitcoin_client/lib/varint.ts +120 -0
  75. package/src/ledger/consts.ts +3 -0
  76. package/src/ledger/index.ts +685 -0
  77. package/src/ledger/types.ts +74 -0
  78. package/src/network-utils.ts +99 -0
  79. package/src/providers.ts +345 -0
  80. package/src/signers.ts +158 -0
  81. package/src/storage.ts +63 -0
  82. package/src/transactions/__tests__/integration.test.ts +303 -0
  83. package/src/transactions/__tests__/syscoin.test.ts +409 -0
  84. package/src/transactions/ethereum.ts +2503 -0
  85. package/src/transactions/index.ts +2 -0
  86. package/src/transactions/syscoin.ts +542 -0
  87. package/src/trezor/index.ts +1050 -0
  88. package/src/types.ts +366 -0
  89. package/src/utils/derivation-paths.ts +133 -0
  90. package/src/utils/psbt.ts +24 -0
  91. package/src/utils.ts +191 -0
  92. package/test/README.md +158 -0
  93. package/test/__mocks__/ledger-mock.js +20 -0
  94. package/test/__mocks__/trezor-mock.js +75 -0
  95. package/test/cleanup-summary.md +167 -0
  96. package/test/helpers/README.md +78 -0
  97. package/test/helpers/constants.ts +79 -0
  98. package/test/helpers/setup.ts +714 -0
  99. package/test/integration/import-validation.spec.ts +588 -0
  100. package/test/unit/hardware/ledger.spec.ts +869 -0
  101. package/test/unit/hardware/trezor.spec.ts +828 -0
  102. package/test/unit/keyring-manager/account-management.spec.ts +970 -0
  103. package/test/unit/keyring-manager/import-watchonly.spec.ts +181 -0
  104. package/test/unit/keyring-manager/import-wif.spec.ts +126 -0
  105. package/test/unit/keyring-manager/initialization.spec.ts +782 -0
  106. package/test/unit/keyring-manager/key-derivation.spec.ts +996 -0
  107. package/test/unit/keyring-manager/security.spec.ts +505 -0
  108. package/test/unit/keyring-manager/state-management.spec.ts +375 -0
  109. package/test/unit/network/network-management.spec.ts +372 -0
  110. package/test/unit/transactions/ethereum-transactions.spec.ts +382 -0
  111. package/test/unit/transactions/syscoin-transactions.spec.ts +615 -0
  112. package/tsconfig.json +14 -0
  113. package/cjs/ledger/bitcoin_client/lib/appClient.js.map +0 -1
  114. package/cjs/transactions/ethereum.js.map +0 -1
  115. /package/{README.md → dist/README.md} +0 -0
  116. /package/{cjs → dist/cjs}/errorUtils.js +0 -0
  117. /package/{cjs → dist/cjs}/errorUtils.js.map +0 -0
  118. /package/{cjs → dist/cjs}/hardware-wallet-manager.js +0 -0
  119. /package/{cjs → dist/cjs}/hardware-wallet-manager.js.map +0 -0
  120. /package/{cjs → dist/cjs}/index.js +0 -0
  121. /package/{cjs → dist/cjs}/index.js.map +0 -0
  122. /package/{cjs → dist/cjs}/initial-state.js +0 -0
  123. /package/{cjs → dist/cjs}/initial-state.js.map +0 -0
  124. /package/{cjs → dist/cjs}/keyring-manager.js +0 -0
  125. /package/{cjs → dist/cjs}/keyring-manager.js.map +0 -0
  126. /package/{cjs → dist/cjs}/ledger/bitcoin_client/index.js +0 -0
  127. /package/{cjs → dist/cjs}/ledger/bitcoin_client/index.js.map +0 -0
  128. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/bip32.js +0 -0
  129. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/bip32.js.map +0 -0
  130. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/buffertools.js +0 -0
  131. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/buffertools.js.map +0 -0
  132. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/clientCommands.js +0 -0
  133. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/clientCommands.js.map +0 -0
  134. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/constants.js +0 -0
  135. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/constants.js.map +0 -0
  136. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkelizedPsbt.js +0 -0
  137. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkelizedPsbt.js.map +0 -0
  138. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkle.js +0 -0
  139. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkle.js.map +0 -0
  140. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkleMap.js +0 -0
  141. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkleMap.js.map +0 -0
  142. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/policy.js +0 -0
  143. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/policy.js.map +0 -0
  144. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/psbtv2.js +0 -0
  145. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/psbtv2.js.map +0 -0
  146. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/varint.js +0 -0
  147. /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/varint.js.map +0 -0
  148. /package/{cjs → dist/cjs}/ledger/consts.js +0 -0
  149. /package/{cjs → dist/cjs}/ledger/consts.js.map +0 -0
  150. /package/{cjs → dist/cjs}/ledger/index.js +0 -0
  151. /package/{cjs → dist/cjs}/ledger/index.js.map +0 -0
  152. /package/{cjs → dist/cjs}/ledger/types.js +0 -0
  153. /package/{cjs → dist/cjs}/ledger/types.js.map +0 -0
  154. /package/{cjs → dist/cjs}/network-utils.js +0 -0
  155. /package/{cjs → dist/cjs}/network-utils.js.map +0 -0
  156. /package/{cjs → dist/cjs}/providers.js +0 -0
  157. /package/{cjs → dist/cjs}/providers.js.map +0 -0
  158. /package/{cjs → dist/cjs}/signers.js +0 -0
  159. /package/{cjs → dist/cjs}/signers.js.map +0 -0
  160. /package/{cjs → dist/cjs}/storage.js +0 -0
  161. /package/{cjs → dist/cjs}/storage.js.map +0 -0
  162. /package/{cjs → dist/cjs}/transactions/__tests__/integration.test.js +0 -0
  163. /package/{cjs → dist/cjs}/transactions/__tests__/integration.test.js.map +0 -0
  164. /package/{cjs → dist/cjs}/transactions/__tests__/syscoin.test.js +0 -0
  165. /package/{cjs → dist/cjs}/transactions/__tests__/syscoin.test.js.map +0 -0
  166. /package/{cjs → dist/cjs}/transactions/index.js +0 -0
  167. /package/{cjs → dist/cjs}/transactions/index.js.map +0 -0
  168. /package/{cjs → dist/cjs}/transactions/syscoin.js +0 -0
  169. /package/{cjs → dist/cjs}/transactions/syscoin.js.map +0 -0
  170. /package/{cjs → dist/cjs}/trezor/index.js +0 -0
  171. /package/{cjs → dist/cjs}/trezor/index.js.map +0 -0
  172. /package/{cjs → dist/cjs}/types.js +0 -0
  173. /package/{cjs → dist/cjs}/types.js.map +0 -0
  174. /package/{cjs → dist/cjs}/utils/derivation-paths.js +0 -0
  175. /package/{cjs → dist/cjs}/utils/derivation-paths.js.map +0 -0
  176. /package/{cjs → dist/cjs}/utils/psbt.js +0 -0
  177. /package/{cjs → dist/cjs}/utils/psbt.js.map +0 -0
  178. /package/{cjs → dist/cjs}/utils.js +0 -0
  179. /package/{cjs → dist/cjs}/utils.js.map +0 -0
  180. /package/{types → dist/types}/errorUtils.d.ts +0 -0
  181. /package/{types → dist/types}/hardware-wallet-manager.d.ts +0 -0
  182. /package/{types → dist/types}/index.d.ts +0 -0
  183. /package/{types → dist/types}/initial-state.d.ts +0 -0
  184. /package/{types → dist/types}/keyring-manager.d.ts +0 -0
  185. /package/{types → dist/types}/ledger/bitcoin_client/index.d.ts +0 -0
  186. /package/{types → dist/types}/ledger/bitcoin_client/lib/bip32.d.ts +0 -0
  187. /package/{types → dist/types}/ledger/bitcoin_client/lib/buffertools.d.ts +0 -0
  188. /package/{types → dist/types}/ledger/bitcoin_client/lib/clientCommands.d.ts +0 -0
  189. /package/{types → dist/types}/ledger/bitcoin_client/lib/constants.d.ts +0 -0
  190. /package/{types → dist/types}/ledger/bitcoin_client/lib/merkelizedPsbt.d.ts +0 -0
  191. /package/{types → dist/types}/ledger/bitcoin_client/lib/merkle.d.ts +0 -0
  192. /package/{types → dist/types}/ledger/bitcoin_client/lib/merkleMap.d.ts +0 -0
  193. /package/{types → dist/types}/ledger/bitcoin_client/lib/policy.d.ts +0 -0
  194. /package/{types → dist/types}/ledger/bitcoin_client/lib/psbtv2.d.ts +0 -0
  195. /package/{types → dist/types}/ledger/bitcoin_client/lib/varint.d.ts +0 -0
  196. /package/{types → dist/types}/ledger/consts.d.ts +0 -0
  197. /package/{types → dist/types}/ledger/index.d.ts +0 -0
  198. /package/{types → dist/types}/ledger/types.d.ts +0 -0
  199. /package/{types → dist/types}/network-utils.d.ts +0 -0
  200. /package/{types → dist/types}/providers.d.ts +0 -0
  201. /package/{types → dist/types}/signers.d.ts +0 -0
  202. /package/{types → dist/types}/storage.d.ts +0 -0
  203. /package/{types → dist/types}/transactions/__tests__/integration.test.d.ts +0 -0
  204. /package/{types → dist/types}/transactions/__tests__/syscoin.test.d.ts +0 -0
  205. /package/{types → dist/types}/transactions/ethereum.d.ts +0 -0
  206. /package/{types → dist/types}/transactions/index.d.ts +0 -0
  207. /package/{types → dist/types}/transactions/syscoin.d.ts +0 -0
  208. /package/{types → dist/types}/trezor/index.d.ts +0 -0
  209. /package/{types → dist/types}/types.d.ts +0 -0
  210. /package/{types → dist/types}/utils/derivation-paths.d.ts +0 -0
  211. /package/{types → dist/types}/utils/psbt.d.ts +0 -0
  212. /package/{types → dist/types}/utils.d.ts +0 -0
@@ -0,0 +1,782 @@
1
+ import { INetworkType } from '@sidhujag/sysweb3-network';
2
+
3
+ import { KeyringManager, KeyringAccountType } from '../../../src';
4
+ import {
5
+ FAKE_PASSWORD,
6
+ PEACE_SEED_PHRASE,
7
+ SECOND_FAKE_SEED_PHRASE,
8
+ } from '../../helpers/constants';
9
+ import { setupMocks } from '../../helpers/setup';
10
+
11
+ describe('KeyringManager Initialization', () => {
12
+ let keyringManager: KeyringManager;
13
+ let mockVaultStateGetter: jest.Mock;
14
+ let currentVaultState: any;
15
+
16
+ beforeEach(async () => {
17
+ setupMocks();
18
+ // Set up vault-keys
19
+ await setupTestVault(FAKE_PASSWORD);
20
+ });
21
+
22
+ afterEach(async () => {
23
+ // Clean up resources
24
+ if (keyringManager) {
25
+ await keyringManager.destroy();
26
+ }
27
+ });
28
+
29
+ describe('Seed Management', () => {
30
+ it('should create a new valid seed phrase', () => {
31
+ keyringManager = new KeyringManager();
32
+ const seed = keyringManager.createNewSeed();
33
+
34
+ expect(seed).toBeDefined();
35
+ expect(seed.split(' ')).toHaveLength(12);
36
+ expect(keyringManager.isSeedValid(seed)).toBe(true);
37
+ });
38
+
39
+ it('should validate seed phrases correctly', () => {
40
+ keyringManager = new KeyringManager();
41
+
42
+ expect(keyringManager.isSeedValid(PEACE_SEED_PHRASE)).toBe(true);
43
+ expect(keyringManager.isSeedValid('invalid seed phrase')).toBe(false);
44
+ expect(keyringManager.isSeedValid('')).toBe(false);
45
+ });
46
+
47
+ it('should retrieve the seed after initialization', async () => {
48
+ keyringManager = new KeyringManager();
49
+
50
+ // Set up mock vault state getter for initializeWalletSecurely
51
+ currentVaultState = createMockVaultState({
52
+ activeAccountId: 0,
53
+ activeAccountType: KeyringAccountType.HDAccount,
54
+ networkType: INetworkType.Ethereum,
55
+ chainId: 1,
56
+ });
57
+ mockVaultStateGetter = jest.fn(() => currentVaultState);
58
+ keyringManager.setVaultStateGetter(mockVaultStateGetter);
59
+
60
+ await keyringManager.initializeWalletSecurely(
61
+ PEACE_SEED_PHRASE,
62
+ FAKE_PASSWORD
63
+ );
64
+
65
+ const retrievedSeed = await keyringManager.getSeed(FAKE_PASSWORD);
66
+ expect(retrievedSeed).toBe(PEACE_SEED_PHRASE);
67
+ });
68
+
69
+ it('should reject seed retrieval with wrong password', async () => {
70
+ keyringManager = new KeyringManager();
71
+
72
+ // Set up mock vault state getter for initializeWalletSecurely
73
+ currentVaultState = createMockVaultState({
74
+ activeAccountId: 0,
75
+ activeAccountType: KeyringAccountType.HDAccount,
76
+ networkType: INetworkType.Ethereum,
77
+ chainId: 1,
78
+ });
79
+ mockVaultStateGetter = jest.fn(() => currentVaultState);
80
+ keyringManager.setVaultStateGetter(mockVaultStateGetter);
81
+
82
+ await keyringManager.initializeWalletSecurely(
83
+ PEACE_SEED_PHRASE,
84
+ FAKE_PASSWORD
85
+ );
86
+
87
+ await expect(keyringManager.getSeed('wrong_password')).rejects.toThrow(
88
+ 'Invalid password'
89
+ );
90
+ });
91
+ });
92
+
93
+ describe('Wallet Initialization', () => {
94
+ it('should initialize wallet for EVM chain', async () => {
95
+ // Set up EVM vault state
96
+ currentVaultState = createMockVaultState({
97
+ activeAccountId: 0,
98
+ activeAccountType: KeyringAccountType.HDAccount,
99
+ networkType: INetworkType.Ethereum,
100
+ chainId: 1,
101
+ });
102
+ mockVaultStateGetter = jest.fn(() => currentVaultState);
103
+
104
+ keyringManager = await KeyringManager.createInitialized(
105
+ PEACE_SEED_PHRASE,
106
+ FAKE_PASSWORD,
107
+ mockVaultStateGetter
108
+ );
109
+
110
+ expect(keyringManager.isUnlocked()).toBe(true);
111
+
112
+ const { activeAccount } = keyringManager.getActiveAccount();
113
+ expect(activeAccount.address).toBeDefined();
114
+ expect(activeAccount.address.startsWith('0x')).toBe(true);
115
+ });
116
+
117
+ it('should initialize wallet for UTXO chain', async () => {
118
+ // Set up UTXO vault state
119
+ currentVaultState = createMockVaultState({
120
+ activeAccountId: 0,
121
+ activeAccountType: KeyringAccountType.HDAccount,
122
+ networkType: INetworkType.Syscoin,
123
+ chainId: 57,
124
+ });
125
+ mockVaultStateGetter = jest.fn(() => currentVaultState);
126
+
127
+ keyringManager = await KeyringManager.createInitialized(
128
+ PEACE_SEED_PHRASE,
129
+ FAKE_PASSWORD,
130
+ mockVaultStateGetter
131
+ );
132
+
133
+ expect(keyringManager.isUnlocked()).toBe(true);
134
+
135
+ const { activeAccount } = keyringManager.getActiveAccount();
136
+ expect(activeAccount.address).toBeDefined();
137
+ expect(activeAccount.address.match(/^(sys1|tsys1)/)).toBeTruthy();
138
+ });
139
+
140
+ it('should create deterministic addresses from the same seed', async () => {
141
+ // Set up EVM vault state for both keyrings
142
+ currentVaultState = createMockVaultState({
143
+ activeAccountId: 0,
144
+ activeAccountType: KeyringAccountType.HDAccount,
145
+ networkType: INetworkType.Ethereum,
146
+ chainId: 1,
147
+ });
148
+
149
+ // First EVM keyring
150
+ const mockVaultStateGetter1 = jest.fn(() => currentVaultState);
151
+ const keyring1 = await KeyringManager.createInitialized(
152
+ PEACE_SEED_PHRASE,
153
+ FAKE_PASSWORD,
154
+ mockVaultStateGetter1
155
+ );
156
+
157
+ // Second EVM keyring with same seed
158
+ const mockVaultStateGetter2 = jest.fn(() => currentVaultState);
159
+ const keyring2 = await KeyringManager.createInitialized(
160
+ PEACE_SEED_PHRASE,
161
+ FAKE_PASSWORD,
162
+ mockVaultStateGetter2
163
+ );
164
+
165
+ const account1 = keyring1.getActiveAccount().activeAccount;
166
+ const account2 = keyring2.getActiveAccount().activeAccount;
167
+
168
+ expect(account1.address).toBe(account2.address);
169
+ expect(account1.xpub).toBe(account2.xpub);
170
+ });
171
+
172
+ it('should handle initialization with invalid seed', async () => {
173
+ currentVaultState = createMockVaultState({
174
+ activeAccountId: 0,
175
+ activeAccountType: KeyringAccountType.HDAccount,
176
+ networkType: INetworkType.Ethereum,
177
+ chainId: 1,
178
+ });
179
+ mockVaultStateGetter = jest.fn(() => currentVaultState);
180
+
181
+ await expect(
182
+ KeyringManager.createInitialized(
183
+ 'invalid seed phrase',
184
+ FAKE_PASSWORD,
185
+ mockVaultStateGetter
186
+ )
187
+ ).rejects.toThrow('Invalid Seed');
188
+ });
189
+
190
+ it('should be idempotent for multiple initializations with same parameters', async () => {
191
+ keyringManager = new KeyringManager();
192
+
193
+ // Set up mock vault state getter for initializeWalletSecurely
194
+ currentVaultState = createMockVaultState({
195
+ activeAccountId: 0,
196
+ activeAccountType: KeyringAccountType.HDAccount,
197
+ networkType: INetworkType.Ethereum,
198
+ chainId: 1,
199
+ });
200
+ mockVaultStateGetter = jest.fn(() => currentVaultState);
201
+ keyringManager.setVaultStateGetter(mockVaultStateGetter);
202
+
203
+ // First initialization
204
+ const account1 = await keyringManager.initializeWalletSecurely(
205
+ PEACE_SEED_PHRASE,
206
+ FAKE_PASSWORD
207
+ );
208
+
209
+ // Second initialization with same parameters should return same account
210
+ const account2 = await keyringManager.initializeWalletSecurely(
211
+ PEACE_SEED_PHRASE,
212
+ FAKE_PASSWORD
213
+ );
214
+
215
+ expect(account1.address).toBe(account2.address);
216
+ expect(account1.id).toBe(account2.id);
217
+ });
218
+
219
+ it('should reject re-initialization with different parameters', async () => {
220
+ keyringManager = new KeyringManager();
221
+
222
+ // Set up mock vault state getter for initializeWalletSecurely
223
+ currentVaultState = createMockVaultState({
224
+ activeAccountId: 0,
225
+ activeAccountType: KeyringAccountType.HDAccount,
226
+ networkType: INetworkType.Ethereum,
227
+ chainId: 1,
228
+ });
229
+ mockVaultStateGetter = jest.fn(() => currentVaultState);
230
+ keyringManager.setVaultStateGetter(mockVaultStateGetter);
231
+
232
+ // First initialization
233
+ await keyringManager.initializeWalletSecurely(
234
+ PEACE_SEED_PHRASE,
235
+ FAKE_PASSWORD
236
+ );
237
+
238
+ // Try to initialize with different seed
239
+ await expect(
240
+ keyringManager.initializeWalletSecurely(
241
+ SECOND_FAKE_SEED_PHRASE,
242
+ FAKE_PASSWORD
243
+ )
244
+ ).rejects.toThrow('Wallet already initialized with different parameters');
245
+ });
246
+ });
247
+
248
+ describe('Lock/Unlock', () => {
249
+ beforeEach(async () => {
250
+ // Set up UTXO vault state
251
+ currentVaultState = createMockVaultState({
252
+ activeAccountId: 0,
253
+ activeAccountType: KeyringAccountType.HDAccount,
254
+ networkType: INetworkType.Syscoin,
255
+ chainId: 57,
256
+ });
257
+ mockVaultStateGetter = jest.fn(() => currentVaultState);
258
+
259
+ keyringManager = await KeyringManager.createInitialized(
260
+ PEACE_SEED_PHRASE,
261
+ FAKE_PASSWORD,
262
+ mockVaultStateGetter
263
+ );
264
+ });
265
+
266
+ it('should lock and unlock wallet with correct password', async () => {
267
+ expect(keyringManager.isUnlocked()).toBe(true);
268
+
269
+ keyringManager.lockWallet();
270
+ expect(keyringManager.isUnlocked()).toBe(false);
271
+
272
+ const unlockResult = await keyringManager.unlock(FAKE_PASSWORD);
273
+ expect(unlockResult.canLogin).toBe(true);
274
+ expect(keyringManager.isUnlocked()).toBe(true);
275
+ });
276
+
277
+ it('should reject unlock with wrong password', async () => {
278
+ keyringManager.lockWallet();
279
+
280
+ const unlockResult = await keyringManager.unlock('wrong_password');
281
+ expect(unlockResult.canLogin).toBe(false);
282
+ expect(keyringManager.isUnlocked()).toBe(false);
283
+ });
284
+
285
+ it('should clear session data on lock', () => {
286
+ expect(keyringManager.isUnlocked()).toBe(true);
287
+
288
+ keyringManager.lockWallet();
289
+
290
+ // After locking, keyring should not be unlocked
291
+ expect(keyringManager.isUnlocked()).toBe(false);
292
+ });
293
+
294
+ it('should restore functionality after unlock', async () => {
295
+ const initialAccount = keyringManager.getActiveAccount().activeAccount;
296
+
297
+ keyringManager.lockWallet();
298
+ await keyringManager.unlock(FAKE_PASSWORD);
299
+
300
+ const accountAfterUnlock =
301
+ keyringManager.getActiveAccount().activeAccount;
302
+ expect(accountAfterUnlock.address).toBe(initialAccount.address);
303
+ });
304
+
305
+ it('should handle multiple lock/unlock cycles', async () => {
306
+ for (let i = 0; i < 3; i++) {
307
+ keyringManager.lockWallet();
308
+ expect(keyringManager.isUnlocked()).toBe(false);
309
+
310
+ const result = await keyringManager.unlock(FAKE_PASSWORD);
311
+ expect(result.canLogin).toBe(true);
312
+ expect(keyringManager.isUnlocked()).toBe(true);
313
+ }
314
+ });
315
+ });
316
+
317
+ describe('Session Management', () => {
318
+ it('should transfer session data between keyrings', async () => {
319
+ // Set up EVM vault state
320
+ currentVaultState = createMockVaultState({
321
+ activeAccountId: 0,
322
+ activeAccountType: KeyringAccountType.HDAccount,
323
+ networkType: INetworkType.Ethereum,
324
+ chainId: 1,
325
+ });
326
+
327
+ // Create first keyring
328
+ const mockVaultStateGetter1 = jest.fn(() => currentVaultState);
329
+ const keyring1 = await KeyringManager.createInitialized(
330
+ PEACE_SEED_PHRASE,
331
+ FAKE_PASSWORD,
332
+ mockVaultStateGetter1
333
+ );
334
+
335
+ // Create second keyring
336
+ const keyring2 = new KeyringManager();
337
+
338
+ // Transfer session from first to second keyring
339
+ keyring1.transferSessionTo(keyring2);
340
+
341
+ // Both should be unlocked (first should be locked after transfer, second should be unlocked)
342
+ expect(keyring1.isUnlocked()).toBe(false); // Source keyring is locked after transfer
343
+ expect(keyring2.isUnlocked()).toBe(true); // Target keyring is unlocked
344
+
345
+ // Second keyring should be able to perform operations with transferred session
346
+ const seed2 = await keyring2.getSeed(FAKE_PASSWORD);
347
+ expect(seed2).toBe(PEACE_SEED_PHRASE);
348
+ });
349
+
350
+ it('should throw when transferring from locked keyring', () => {
351
+ const keyring1 = new KeyringManager();
352
+ const keyring2 = new KeyringManager();
353
+
354
+ expect(() => keyring1.transferSessionTo(keyring2)).toThrow(
355
+ 'Source keyring must be unlocked to transfer session'
356
+ );
357
+ });
358
+ });
359
+
360
+ describe('Wallet Reset', () => {
361
+ beforeEach(async () => {
362
+ // Set up EVM vault state
363
+ currentVaultState = createMockVaultState({
364
+ activeAccountId: 0,
365
+ activeAccountType: KeyringAccountType.HDAccount,
366
+ networkType: INetworkType.Ethereum,
367
+ chainId: 1,
368
+ });
369
+ mockVaultStateGetter = jest.fn(() => currentVaultState);
370
+
371
+ keyringManager = await KeyringManager.createInitialized(
372
+ PEACE_SEED_PHRASE,
373
+ FAKE_PASSWORD,
374
+ mockVaultStateGetter
375
+ );
376
+ });
377
+
378
+ it('should forget wallet with correct password', async () => {
379
+ await keyringManager.forgetMainWallet(FAKE_PASSWORD);
380
+
381
+ // After forgetting, wallet should be locked and empty
382
+ expect(keyringManager.isUnlocked()).toBe(false);
383
+ const unlockResult = await keyringManager.unlock(FAKE_PASSWORD);
384
+ expect(unlockResult.canLogin).toBe(false); // No vault to unlock
385
+ });
386
+
387
+ it('should reject forget wallet with wrong password', async () => {
388
+ await expect(
389
+ keyringManager.forgetMainWallet('wrong_password')
390
+ ).rejects.toThrow('Invalid password');
391
+ });
392
+
393
+ it('should require unlock before forget wallet', async () => {
394
+ keyringManager.lockWallet();
395
+
396
+ await expect(
397
+ keyringManager.forgetMainWallet(FAKE_PASSWORD)
398
+ ).rejects.toThrow('Unlock wallet first');
399
+ });
400
+ });
401
+
402
+ describe('Edge Cases', () => {
403
+ it('should handle vault recreation from corrupted session', async () => {
404
+ // Set up EVM vault state
405
+ currentVaultState = createMockVaultState({
406
+ activeAccountId: 0,
407
+ activeAccountType: KeyringAccountType.HDAccount,
408
+ networkType: INetworkType.Ethereum,
409
+ chainId: 1,
410
+ });
411
+ mockVaultStateGetter = jest.fn(() => currentVaultState);
412
+
413
+ keyringManager = await KeyringManager.createInitialized(
414
+ PEACE_SEED_PHRASE,
415
+ FAKE_PASSWORD,
416
+ mockVaultStateGetter
417
+ );
418
+
419
+ // Simulate corrupted session by clearing internal state
420
+ keyringManager.lockWallet();
421
+
422
+ // Should recreate session from vault on unlock
423
+ const result = await keyringManager.unlock(FAKE_PASSWORD);
424
+ expect(result.canLogin).toBe(true);
425
+
426
+ // Verify functionality is restored
427
+ const seed = await keyringManager.getSeed(FAKE_PASSWORD);
428
+ expect(seed).toBe(PEACE_SEED_PHRASE);
429
+ });
430
+
431
+ it("should create vault keys when they don't exist", async () => {
432
+ // Use a keyring with proper UTXO setup
433
+ keyringManager = new KeyringManager();
434
+
435
+ // Set up mock vault state getter for initializeWalletSecurely
436
+ currentVaultState = createMockVaultState({
437
+ activeAccountId: 0,
438
+ activeAccountType: KeyringAccountType.HDAccount,
439
+ networkType: INetworkType.Syscoin,
440
+ chainId: 57,
441
+ });
442
+ mockVaultStateGetter = jest.fn(() => currentVaultState);
443
+ keyringManager.setVaultStateGetter(mockVaultStateGetter);
444
+
445
+ // Get the actual storage instance
446
+ const keyringStorage = (keyringManager as any).storage;
447
+
448
+ // Ensure no vault-keys exist initially (clean state)
449
+ await keyringStorage.set('vault-keys', null);
450
+
451
+ // Should create vault-keys and initialize successfully
452
+ const result = await keyringManager.initializeWalletSecurely(
453
+ PEACE_SEED_PHRASE,
454
+ FAKE_PASSWORD
455
+ );
456
+
457
+ expect(result).toBeDefined();
458
+ expect(result.address).toBeDefined();
459
+
460
+ // Verify vault-keys were actually created by checking storage
461
+ const vaultKeys = await keyringStorage.get('vault-keys');
462
+ expect(vaultKeys).toBeDefined();
463
+ expect(vaultKeys.hash).toBeDefined();
464
+ expect(vaultKeys.salt).toBeDefined();
465
+ expect(typeof vaultKeys.hash).toBe('string');
466
+ expect(typeof vaultKeys.salt).toBe('string');
467
+ expect(vaultKeys.hash.length).toBeGreaterThan(0);
468
+ expect(vaultKeys.salt.length).toBeGreaterThan(0);
469
+
470
+ // Verify keyring is now unlocked and functional
471
+ expect(keyringManager.isUnlocked()).toBe(true);
472
+ const seed = await keyringManager.getSeed(FAKE_PASSWORD);
473
+ expect(seed).toBe(PEACE_SEED_PHRASE);
474
+ });
475
+
476
+ it('should re-initialize from vault when Trezor account was active', async () => {
477
+ // Set up UTXO vault state
478
+ currentVaultState = createMockVaultState({
479
+ activeAccountId: 0,
480
+ activeAccountType: KeyringAccountType.HDAccount,
481
+ networkType: INetworkType.Syscoin,
482
+ chainId: 57,
483
+ });
484
+ mockVaultStateGetter = jest.fn(() => currentVaultState);
485
+
486
+ keyringManager = await KeyringManager.createInitialized(
487
+ PEACE_SEED_PHRASE,
488
+ FAKE_PASSWORD,
489
+ mockVaultStateGetter
490
+ );
491
+
492
+ // Mock Trezor import
493
+ keyringManager.trezorSigner.getAccountInfo = jest.fn().mockResolvedValue({
494
+ descriptor: 'xpub_trezor_test',
495
+ balance: 100000000,
496
+ });
497
+ keyringManager.trezorSigner.getPublicKey = jest.fn().mockResolvedValue({
498
+ publicKey: '0x04...',
499
+ });
500
+ keyringManager.getAddress = jest
501
+ .fn()
502
+ .mockResolvedValue('sys1q_trezor_test');
503
+
504
+ // Import and activate Trezor account
505
+ const trezorAccount = await keyringManager.importTrezorAccount(
506
+ 'Test Trezor'
507
+ );
508
+
509
+ // Update vault state with Trezor account
510
+ currentVaultState.accounts[KeyringAccountType.Trezor][trezorAccount.id] =
511
+ {
512
+ id: trezorAccount.id,
513
+ label: 'Test Trezor',
514
+ address: trezorAccount.address,
515
+ xpub: trezorAccount.xpub,
516
+ xprv: '',
517
+ isImported: false,
518
+ isTrezorWallet: true,
519
+ isLedgerWallet: false,
520
+ balances: { syscoin: 0, ethereum: 0 },
521
+ assets: { syscoin: [], ethereum: [] },
522
+ };
523
+ currentVaultState.activeAccount = {
524
+ id: trezorAccount.id,
525
+ type: KeyringAccountType.Trezor,
526
+ };
527
+
528
+ // Account switch is handled by vault state update
529
+
530
+ // Verify Trezor is active
531
+ const activeBefore = keyringManager.getActiveAccount();
532
+ expect(activeBefore.activeAccountType).toBe(KeyringAccountType.Trezor);
533
+ expect(activeBefore.activeAccount.isTrezorWallet).toBe(true);
534
+
535
+ // Lock keyring and create new instance (simulates app restart)
536
+ keyringManager.lockWallet();
537
+ const newKeyringManager = new KeyringManager();
538
+ const newMockVaultStateGetter = jest.fn(() => currentVaultState);
539
+ newKeyringManager.setVaultStateGetter(newMockVaultStateGetter);
540
+
541
+ // Mock Trezor for new keyring
542
+ newKeyringManager.trezorSigner.getAccountInfo = jest
543
+ .fn()
544
+ .mockResolvedValue({
545
+ descriptor: 'xpub_trezor_test',
546
+ balance: 100000000,
547
+ });
548
+
549
+ // Unlock and verify Trezor account is restored as active
550
+ const unlockResult = await newKeyringManager.unlock(FAKE_PASSWORD);
551
+ expect(unlockResult.canLogin).toBe(true);
552
+
553
+ const activeAfter = newKeyringManager.getActiveAccount();
554
+ expect(activeAfter.activeAccountType).toBe(KeyringAccountType.Trezor);
555
+ expect(activeAfter.activeAccount.isTrezorWallet).toBe(true);
556
+ expect(activeAfter.activeAccount.id).toBe(trezorAccount.id);
557
+ });
558
+
559
+ it('should re-initialize from vault when Ledger account was active', async () => {
560
+ // Set up UTXO vault state
561
+ currentVaultState = createMockVaultState({
562
+ activeAccountId: 0,
563
+ activeAccountType: KeyringAccountType.HDAccount,
564
+ networkType: INetworkType.Syscoin,
565
+ chainId: 57,
566
+ });
567
+ mockVaultStateGetter = jest.fn(() => currentVaultState);
568
+
569
+ keyringManager = await KeyringManager.createInitialized(
570
+ PEACE_SEED_PHRASE,
571
+ FAKE_PASSWORD,
572
+ mockVaultStateGetter
573
+ );
574
+
575
+ // Mock Ledger ensureConnection
576
+ keyringManager.ledgerSigner.ensureConnection = jest
577
+ .fn()
578
+ .mockResolvedValue(undefined);
579
+
580
+ // Mock Ledger import
581
+ keyringManager.ledgerSigner.utxo = {
582
+ getXpub: jest
583
+ .fn()
584
+ .mockResolvedValue(
585
+ 'zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs'
586
+ ),
587
+ getUtxoAddress: jest.fn().mockResolvedValue('sys1q_ledger_test'),
588
+ verifyUtxoAddress: jest.fn().mockResolvedValue('sys1q_ledger_test'),
589
+ };
590
+
591
+ const ledgerAccount = await keyringManager.importLedgerAccount(
592
+ 'Test Ledger'
593
+ );
594
+ expect(ledgerAccount).toBeDefined();
595
+ if (!ledgerAccount) {
596
+ throw new Error('Ledger account creation failed');
597
+ }
598
+
599
+ // Update vault state with Ledger account
600
+ currentVaultState.accounts[KeyringAccountType.Ledger][ledgerAccount.id] =
601
+ {
602
+ id: ledgerAccount.id,
603
+ label: 'Test Ledger',
604
+ address: ledgerAccount.address,
605
+ xpub: ledgerAccount.xpub,
606
+ xprv: '',
607
+ isImported: false,
608
+ isTrezorWallet: false,
609
+ isLedgerWallet: true,
610
+ balances: { syscoin: 0, ethereum: 0 },
611
+ assets: { syscoin: [], ethereum: [] },
612
+ };
613
+ currentVaultState.activeAccount = {
614
+ id: ledgerAccount.id,
615
+ type: KeyringAccountType.Ledger,
616
+ };
617
+
618
+ // Account switch is handled by vault state update
619
+
620
+ // Lock and recreate keyring
621
+ keyringManager.lockWallet();
622
+ const newKeyringManager = new KeyringManager();
623
+ const newMockVaultStateGetter = jest.fn(() => currentVaultState);
624
+ newKeyringManager.setVaultStateGetter(newMockVaultStateGetter);
625
+
626
+ // Mock Ledger ensureConnection for new keyring
627
+ newKeyringManager.ledgerSigner.ensureConnection = jest
628
+ .fn()
629
+ .mockResolvedValue(undefined);
630
+
631
+ // Mock Ledger for new keyring
632
+ newKeyringManager.ledgerSigner.utxo = {
633
+ getXpub: jest
634
+ .fn()
635
+ .mockResolvedValue(
636
+ 'zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs'
637
+ ),
638
+ getUtxoAddress: jest.fn().mockResolvedValue('sys1q_ledger_test'),
639
+ verifyUtxoAddress: jest.fn().mockResolvedValue('sys1q_ledger_test'),
640
+ };
641
+
642
+ const unlockResult = await newKeyringManager.unlock(FAKE_PASSWORD);
643
+ expect(unlockResult.canLogin).toBe(true);
644
+
645
+ const activeAfter = newKeyringManager.getActiveAccount();
646
+ expect(activeAfter.activeAccountType).toBe(KeyringAccountType.Ledger);
647
+ expect(activeAfter.activeAccount.isLedgerWallet).toBe(true);
648
+ });
649
+
650
+ it('should re-initialize from vault when imported account was active', async () => {
651
+ // Set up UTXO vault state
652
+ currentVaultState = createMockVaultState({
653
+ activeAccountId: 0,
654
+ activeAccountType: KeyringAccountType.HDAccount,
655
+ networkType: INetworkType.Syscoin,
656
+ chainId: 57,
657
+ });
658
+ mockVaultStateGetter = jest.fn(() => currentVaultState);
659
+
660
+ keyringManager = await KeyringManager.createInitialized(
661
+ PEACE_SEED_PHRASE,
662
+ FAKE_PASSWORD,
663
+ mockVaultStateGetter
664
+ );
665
+
666
+ // Import zprv account
667
+ const mainnetZprv =
668
+ 'zprvAdGDwa3WySqQoVwVSbYRMKxDhSXpK2wW6wDjekCMdm7TaQ3igf52xRRjYghTvnFurtMm6CMgQivEDJs5ixGSnTtv8usFmkAoTe6XCF5hnpR';
669
+ const importedAccount = await keyringManager.importAccount(
670
+ mainnetZprv,
671
+ 'Test Imported'
672
+ );
673
+
674
+ // Update vault state with imported account
675
+ currentVaultState.accounts[KeyringAccountType.Imported][
676
+ importedAccount.id
677
+ ] = {
678
+ id: importedAccount.id,
679
+ label: 'Test Imported',
680
+ address: importedAccount.address,
681
+ xpub: importedAccount.xpub,
682
+ xprv: importedAccount.xprv,
683
+ isImported: true,
684
+ isTrezorWallet: false,
685
+ isLedgerWallet: false,
686
+ balances: { syscoin: 0, ethereum: 0 },
687
+ assets: { syscoin: [], ethereum: [] },
688
+ };
689
+ currentVaultState.activeAccount = {
690
+ id: importedAccount.id,
691
+ type: KeyringAccountType.Imported,
692
+ };
693
+
694
+ // Account switch is handled by vault state update
695
+
696
+ // Lock and recreate keyring
697
+ keyringManager.lockWallet();
698
+ const newKeyringManager = new KeyringManager();
699
+ const newMockVaultStateGetter = jest.fn(() => currentVaultState);
700
+ newKeyringManager.setVaultStateGetter(newMockVaultStateGetter);
701
+
702
+ const unlockResult = await newKeyringManager.unlock(FAKE_PASSWORD);
703
+ expect(unlockResult.canLogin).toBe(true);
704
+
705
+ const activeAfter = newKeyringManager.getActiveAccount();
706
+ expect(activeAfter.activeAccountType).toBe(KeyringAccountType.Imported);
707
+ expect(activeAfter.activeAccount.isImported).toBe(true);
708
+ expect(activeAfter.activeAccount.id).toBe(importedAccount.id);
709
+ });
710
+
711
+ it('should handle missing hardware wallet during re-init gracefully', async () => {
712
+ // Set up UTXO vault state
713
+ currentVaultState = createMockVaultState({
714
+ activeAccountId: 0,
715
+ activeAccountType: KeyringAccountType.HDAccount,
716
+ networkType: INetworkType.Syscoin,
717
+ chainId: 57,
718
+ });
719
+ mockVaultStateGetter = jest.fn(() => currentVaultState);
720
+
721
+ keyringManager = await KeyringManager.createInitialized(
722
+ PEACE_SEED_PHRASE,
723
+ FAKE_PASSWORD,
724
+ mockVaultStateGetter
725
+ );
726
+
727
+ // Import Trezor
728
+ keyringManager.trezorSigner.getAccountInfo = jest.fn().mockResolvedValue({
729
+ descriptor: 'xpub_trezor_missing',
730
+ balance: 100000000,
731
+ });
732
+ keyringManager.trezorSigner.getPublicKey = jest.fn().mockResolvedValue({
733
+ publicKey: '0x04...',
734
+ });
735
+ keyringManager.getAddress = jest
736
+ .fn()
737
+ .mockResolvedValue('sys1q_trezor_missing');
738
+
739
+ const trezorAccount = await keyringManager.importTrezorAccount(
740
+ 'Missing Trezor'
741
+ );
742
+
743
+ // Update vault state with Trezor account
744
+ currentVaultState.accounts[KeyringAccountType.Trezor][trezorAccount.id] =
745
+ {
746
+ id: trezorAccount.id,
747
+ label: 'Missing Trezor',
748
+ address: trezorAccount.address,
749
+ xpub: trezorAccount.xpub,
750
+ xprv: '',
751
+ isImported: false,
752
+ isTrezorWallet: true,
753
+ isLedgerWallet: false,
754
+ balances: { syscoin: 0, ethereum: 0 },
755
+ assets: { syscoin: [], ethereum: [] },
756
+ };
757
+ currentVaultState.activeAccount = {
758
+ id: trezorAccount.id,
759
+ type: KeyringAccountType.Trezor,
760
+ };
761
+
762
+ // Recreate keyring with Trezor as active but hardware not available
763
+ keyringManager.lockWallet();
764
+ const newKeyringManager = new KeyringManager();
765
+ const newMockVaultStateGetter = jest.fn(() => currentVaultState);
766
+ newKeyringManager.setVaultStateGetter(newMockVaultStateGetter);
767
+
768
+ // Mock hardware wallet communication error
769
+ newKeyringManager.trezorSigner.getAccountInfo = jest
770
+ .fn()
771
+ .mockRejectedValue(new Error('Trezor device not found'));
772
+
773
+ // Should still unlock successfully
774
+ const unlockResult = await newKeyringManager.unlock(FAKE_PASSWORD);
775
+ expect(unlockResult.canLogin).toBe(true);
776
+
777
+ // Account info should still be accessible from vault
778
+ const activeAfter = newKeyringManager.getActiveAccount();
779
+ expect(activeAfter.activeAccount.label).toBe('Missing Trezor');
780
+ });
781
+ });
782
+ });