@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.
- package/coverage/clover.xml +2875 -0
- package/coverage/coverage-final.json +29468 -0
- package/coverage/lcov-report/base.css +354 -0
- package/coverage/lcov-report/block-navigation.js +85 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +320 -0
- package/coverage/lcov-report/prettify.css +101 -0
- package/coverage/lcov-report/prettify.js +1008 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +191 -0
- package/coverage/lcov-report/src/index.html +276 -0
- package/coverage/lcov-report/src/index.ts.html +114 -0
- package/coverage/lcov-report/src/initial-state.ts.html +558 -0
- package/coverage/lcov-report/src/keyring-manager.ts.html +6279 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/index.html +178 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/index.ts.html +144 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/appClient.ts.html +1560 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/bip32.ts.html +276 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/buffertools.ts.html +495 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/clientCommands.ts.html +1138 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/index.html +363 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkelizedPsbt.ts.html +289 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkle.ts.html +486 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkleMap.ts.html +240 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/policy.ts.html +342 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/psbtv2.ts.html +2388 -0
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/varint.ts.html +453 -0
- package/coverage/lcov-report/src/ledger/consts.ts.html +177 -0
- package/coverage/lcov-report/src/ledger/index.html +216 -0
- package/coverage/lcov-report/src/ledger/index.ts.html +1371 -0
- package/coverage/lcov-report/src/ledger/utils.ts.html +102 -0
- package/coverage/lcov-report/src/signers.ts.html +591 -0
- package/coverage/lcov-report/src/storage.ts.html +198 -0
- package/coverage/lcov-report/src/transactions/ethereum.ts.html +5826 -0
- package/coverage/lcov-report/src/transactions/index.html +216 -0
- package/coverage/lcov-report/src/transactions/index.ts.html +93 -0
- package/coverage/lcov-report/src/transactions/syscoin.ts.html +1521 -0
- package/coverage/lcov-report/src/trezor/index.html +176 -0
- package/coverage/lcov-report/src/trezor/index.ts.html +2655 -0
- package/coverage/lcov-report/src/types.ts.html +1443 -0
- package/coverage/lcov-report/src/utils/derivation-paths.ts.html +486 -0
- package/coverage/lcov-report/src/utils/index.html +196 -0
- package/coverage/lcov-report/src/utils/psbt.ts.html +159 -0
- package/coverage/lcov-report/test/helpers/constants.ts.html +627 -0
- package/coverage/lcov-report/test/helpers/index.html +176 -0
- package/coverage/lcov.info +4832 -0
- package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/appClient.js +1 -124
- package/dist/cjs/ledger/bitcoin_client/lib/appClient.js.map +1 -0
- package/{cjs → dist/cjs}/transactions/ethereum.js +6 -2
- package/dist/cjs/transactions/ethereum.js.map +1 -0
- package/dist/package.json +50 -0
- package/{types → dist/types}/ledger/bitcoin_client/lib/appClient.d.ts +0 -6
- package/examples/basic-usage.js +140 -0
- package/jest.config.js +32 -0
- package/package.json +31 -13
- package/readme.md +201 -0
- package/src/declare.d.ts +7 -0
- package/src/errorUtils.ts +83 -0
- package/src/hardware-wallet-manager.ts +655 -0
- package/src/index.ts +12 -0
- package/src/initial-state.ts +108 -0
- package/src/keyring-manager.ts +2698 -0
- package/src/ledger/bitcoin_client/index.ts +19 -0
- package/src/ledger/bitcoin_client/lib/appClient.ts +405 -0
- package/src/ledger/bitcoin_client/lib/bip32.ts +61 -0
- package/src/ledger/bitcoin_client/lib/buffertools.ts +134 -0
- package/src/ledger/bitcoin_client/lib/clientCommands.ts +356 -0
- package/src/ledger/bitcoin_client/lib/constants.ts +12 -0
- package/src/ledger/bitcoin_client/lib/merkelizedPsbt.ts +65 -0
- package/src/ledger/bitcoin_client/lib/merkle.ts +136 -0
- package/src/ledger/bitcoin_client/lib/merkleMap.ts +49 -0
- package/src/ledger/bitcoin_client/lib/policy.ts +91 -0
- package/src/ledger/bitcoin_client/lib/psbtv2.ts +768 -0
- package/src/ledger/bitcoin_client/lib/varint.ts +120 -0
- package/src/ledger/consts.ts +3 -0
- package/src/ledger/index.ts +685 -0
- package/src/ledger/types.ts +74 -0
- package/src/network-utils.ts +99 -0
- package/src/providers.ts +345 -0
- package/src/signers.ts +158 -0
- package/src/storage.ts +63 -0
- package/src/transactions/__tests__/integration.test.ts +303 -0
- package/src/transactions/__tests__/syscoin.test.ts +409 -0
- package/src/transactions/ethereum.ts +2503 -0
- package/src/transactions/index.ts +2 -0
- package/src/transactions/syscoin.ts +542 -0
- package/src/trezor/index.ts +1050 -0
- package/src/types.ts +366 -0
- package/src/utils/derivation-paths.ts +133 -0
- package/src/utils/psbt.ts +24 -0
- package/src/utils.ts +191 -0
- package/test/README.md +158 -0
- package/test/__mocks__/ledger-mock.js +20 -0
- package/test/__mocks__/trezor-mock.js +75 -0
- package/test/cleanup-summary.md +167 -0
- package/test/helpers/README.md +78 -0
- package/test/helpers/constants.ts +79 -0
- package/test/helpers/setup.ts +714 -0
- package/test/integration/import-validation.spec.ts +588 -0
- package/test/unit/hardware/ledger.spec.ts +869 -0
- package/test/unit/hardware/trezor.spec.ts +828 -0
- package/test/unit/keyring-manager/account-management.spec.ts +970 -0
- package/test/unit/keyring-manager/import-watchonly.spec.ts +181 -0
- package/test/unit/keyring-manager/import-wif.spec.ts +126 -0
- package/test/unit/keyring-manager/initialization.spec.ts +782 -0
- package/test/unit/keyring-manager/key-derivation.spec.ts +996 -0
- package/test/unit/keyring-manager/security.spec.ts +505 -0
- package/test/unit/keyring-manager/state-management.spec.ts +375 -0
- package/test/unit/network/network-management.spec.ts +372 -0
- package/test/unit/transactions/ethereum-transactions.spec.ts +382 -0
- package/test/unit/transactions/syscoin-transactions.spec.ts +615 -0
- package/tsconfig.json +14 -0
- package/cjs/ledger/bitcoin_client/lib/appClient.js.map +0 -1
- package/cjs/transactions/ethereum.js.map +0 -1
- /package/{README.md → dist/README.md} +0 -0
- /package/{cjs → dist/cjs}/errorUtils.js +0 -0
- /package/{cjs → dist/cjs}/errorUtils.js.map +0 -0
- /package/{cjs → dist/cjs}/hardware-wallet-manager.js +0 -0
- /package/{cjs → dist/cjs}/hardware-wallet-manager.js.map +0 -0
- /package/{cjs → dist/cjs}/index.js +0 -0
- /package/{cjs → dist/cjs}/index.js.map +0 -0
- /package/{cjs → dist/cjs}/initial-state.js +0 -0
- /package/{cjs → dist/cjs}/initial-state.js.map +0 -0
- /package/{cjs → dist/cjs}/keyring-manager.js +0 -0
- /package/{cjs → dist/cjs}/keyring-manager.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/index.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/index.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/bip32.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/bip32.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/buffertools.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/buffertools.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/clientCommands.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/clientCommands.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/constants.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/constants.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkelizedPsbt.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkelizedPsbt.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkle.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkle.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkleMap.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/merkleMap.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/policy.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/policy.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/psbtv2.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/psbtv2.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/varint.js +0 -0
- /package/{cjs → dist/cjs}/ledger/bitcoin_client/lib/varint.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/consts.js +0 -0
- /package/{cjs → dist/cjs}/ledger/consts.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/index.js +0 -0
- /package/{cjs → dist/cjs}/ledger/index.js.map +0 -0
- /package/{cjs → dist/cjs}/ledger/types.js +0 -0
- /package/{cjs → dist/cjs}/ledger/types.js.map +0 -0
- /package/{cjs → dist/cjs}/network-utils.js +0 -0
- /package/{cjs → dist/cjs}/network-utils.js.map +0 -0
- /package/{cjs → dist/cjs}/providers.js +0 -0
- /package/{cjs → dist/cjs}/providers.js.map +0 -0
- /package/{cjs → dist/cjs}/signers.js +0 -0
- /package/{cjs → dist/cjs}/signers.js.map +0 -0
- /package/{cjs → dist/cjs}/storage.js +0 -0
- /package/{cjs → dist/cjs}/storage.js.map +0 -0
- /package/{cjs → dist/cjs}/transactions/__tests__/integration.test.js +0 -0
- /package/{cjs → dist/cjs}/transactions/__tests__/integration.test.js.map +0 -0
- /package/{cjs → dist/cjs}/transactions/__tests__/syscoin.test.js +0 -0
- /package/{cjs → dist/cjs}/transactions/__tests__/syscoin.test.js.map +0 -0
- /package/{cjs → dist/cjs}/transactions/index.js +0 -0
- /package/{cjs → dist/cjs}/transactions/index.js.map +0 -0
- /package/{cjs → dist/cjs}/transactions/syscoin.js +0 -0
- /package/{cjs → dist/cjs}/transactions/syscoin.js.map +0 -0
- /package/{cjs → dist/cjs}/trezor/index.js +0 -0
- /package/{cjs → dist/cjs}/trezor/index.js.map +0 -0
- /package/{cjs → dist/cjs}/types.js +0 -0
- /package/{cjs → dist/cjs}/types.js.map +0 -0
- /package/{cjs → dist/cjs}/utils/derivation-paths.js +0 -0
- /package/{cjs → dist/cjs}/utils/derivation-paths.js.map +0 -0
- /package/{cjs → dist/cjs}/utils/psbt.js +0 -0
- /package/{cjs → dist/cjs}/utils/psbt.js.map +0 -0
- /package/{cjs → dist/cjs}/utils.js +0 -0
- /package/{cjs → dist/cjs}/utils.js.map +0 -0
- /package/{types → dist/types}/errorUtils.d.ts +0 -0
- /package/{types → dist/types}/hardware-wallet-manager.d.ts +0 -0
- /package/{types → dist/types}/index.d.ts +0 -0
- /package/{types → dist/types}/initial-state.d.ts +0 -0
- /package/{types → dist/types}/keyring-manager.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/index.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/bip32.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/buffertools.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/clientCommands.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/constants.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/merkelizedPsbt.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/merkle.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/merkleMap.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/policy.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/psbtv2.d.ts +0 -0
- /package/{types → dist/types}/ledger/bitcoin_client/lib/varint.d.ts +0 -0
- /package/{types → dist/types}/ledger/consts.d.ts +0 -0
- /package/{types → dist/types}/ledger/index.d.ts +0 -0
- /package/{types → dist/types}/ledger/types.d.ts +0 -0
- /package/{types → dist/types}/network-utils.d.ts +0 -0
- /package/{types → dist/types}/providers.d.ts +0 -0
- /package/{types → dist/types}/signers.d.ts +0 -0
- /package/{types → dist/types}/storage.d.ts +0 -0
- /package/{types → dist/types}/transactions/__tests__/integration.test.d.ts +0 -0
- /package/{types → dist/types}/transactions/__tests__/syscoin.test.d.ts +0 -0
- /package/{types → dist/types}/transactions/ethereum.d.ts +0 -0
- /package/{types → dist/types}/transactions/index.d.ts +0 -0
- /package/{types → dist/types}/transactions/syscoin.d.ts +0 -0
- /package/{types → dist/types}/trezor/index.d.ts +0 -0
- /package/{types → dist/types}/types.d.ts +0 -0
- /package/{types → dist/types}/utils/derivation-paths.d.ts +0 -0
- /package/{types → dist/types}/utils/psbt.d.ts +0 -0
- /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
|
+
});
|