@sidhujag/sysweb3-keyring 1.0.547 → 1.0.549
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/{dist/cjs → cjs}/providers.js +1 -64
- package/cjs/providers.js.map +1 -0
- package/{dist/cjs → cjs}/transactions/ethereum.js +1 -16
- package/cjs/transactions/ethereum.js.map +1 -0
- package/package.json +2 -30
- package/{dist/types → types}/providers.d.ts +0 -8
- package/{dist/types → types}/transactions/ethereum.d.ts +2 -2
- package/{dist/types → types}/types.d.ts +2 -2
- package/coverage/clover.xml +0 -2875
- package/coverage/coverage-final.json +0 -29468
- package/coverage/lcov-report/base.css +0 -354
- package/coverage/lcov-report/block-navigation.js +0 -85
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -320
- package/coverage/lcov-report/prettify.css +0 -101
- package/coverage/lcov-report/prettify.js +0 -1008
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -191
- package/coverage/lcov-report/src/index.html +0 -276
- package/coverage/lcov-report/src/index.ts.html +0 -114
- package/coverage/lcov-report/src/initial-state.ts.html +0 -558
- package/coverage/lcov-report/src/keyring-manager.ts.html +0 -6279
- package/coverage/lcov-report/src/ledger/bitcoin_client/index.html +0 -178
- package/coverage/lcov-report/src/ledger/bitcoin_client/index.ts.html +0 -144
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/appClient.ts.html +0 -1560
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/bip32.ts.html +0 -276
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/buffertools.ts.html +0 -495
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/clientCommands.ts.html +0 -1138
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/index.html +0 -363
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkelizedPsbt.ts.html +0 -289
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkle.ts.html +0 -486
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkleMap.ts.html +0 -240
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/policy.ts.html +0 -342
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/psbtv2.ts.html +0 -2388
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/varint.ts.html +0 -453
- package/coverage/lcov-report/src/ledger/consts.ts.html +0 -177
- package/coverage/lcov-report/src/ledger/index.html +0 -216
- package/coverage/lcov-report/src/ledger/index.ts.html +0 -1371
- package/coverage/lcov-report/src/ledger/utils.ts.html +0 -102
- package/coverage/lcov-report/src/signers.ts.html +0 -591
- package/coverage/lcov-report/src/storage.ts.html +0 -198
- package/coverage/lcov-report/src/transactions/ethereum.ts.html +0 -5826
- package/coverage/lcov-report/src/transactions/index.html +0 -216
- package/coverage/lcov-report/src/transactions/index.ts.html +0 -93
- package/coverage/lcov-report/src/transactions/syscoin.ts.html +0 -1521
- package/coverage/lcov-report/src/trezor/index.html +0 -176
- package/coverage/lcov-report/src/trezor/index.ts.html +0 -2655
- package/coverage/lcov-report/src/types.ts.html +0 -1443
- package/coverage/lcov-report/src/utils/derivation-paths.ts.html +0 -486
- package/coverage/lcov-report/src/utils/index.html +0 -196
- package/coverage/lcov-report/src/utils/psbt.ts.html +0 -159
- package/coverage/lcov-report/test/helpers/constants.ts.html +0 -627
- package/coverage/lcov-report/test/helpers/index.html +0 -176
- package/coverage/lcov.info +0 -4832
- package/dist/cjs/providers.js.map +0 -1
- package/dist/cjs/transactions/ethereum.js.map +0 -1
- package/dist/package.json +0 -50
- package/examples/basic-usage.js +0 -140
- package/jest.config.js +0 -32
- package/readme.md +0 -201
- package/src/declare.d.ts +0 -7
- package/src/errorUtils.ts +0 -83
- package/src/hardware-wallet-manager.ts +0 -655
- package/src/index.ts +0 -12
- package/src/initial-state.ts +0 -108
- package/src/keyring-manager.ts +0 -2698
- package/src/ledger/bitcoin_client/index.ts +0 -19
- package/src/ledger/bitcoin_client/lib/appClient.ts +0 -405
- package/src/ledger/bitcoin_client/lib/bip32.ts +0 -61
- package/src/ledger/bitcoin_client/lib/buffertools.ts +0 -134
- package/src/ledger/bitcoin_client/lib/clientCommands.ts +0 -356
- package/src/ledger/bitcoin_client/lib/constants.ts +0 -12
- package/src/ledger/bitcoin_client/lib/merkelizedPsbt.ts +0 -65
- package/src/ledger/bitcoin_client/lib/merkle.ts +0 -136
- package/src/ledger/bitcoin_client/lib/merkleMap.ts +0 -49
- package/src/ledger/bitcoin_client/lib/policy.ts +0 -91
- package/src/ledger/bitcoin_client/lib/psbtv2.ts +0 -768
- package/src/ledger/bitcoin_client/lib/varint.ts +0 -120
- package/src/ledger/consts.ts +0 -3
- package/src/ledger/index.ts +0 -685
- package/src/ledger/types.ts +0 -74
- package/src/network-utils.ts +0 -99
- package/src/providers.ts +0 -345
- package/src/signers.ts +0 -158
- package/src/storage.ts +0 -63
- package/src/transactions/__tests__/integration.test.ts +0 -303
- package/src/transactions/__tests__/syscoin.test.ts +0 -409
- package/src/transactions/ethereum.ts +0 -2503
- package/src/transactions/index.ts +0 -2
- package/src/transactions/syscoin.ts +0 -542
- package/src/trezor/index.ts +0 -1050
- package/src/types.ts +0 -366
- package/src/utils/derivation-paths.ts +0 -133
- package/src/utils/psbt.ts +0 -24
- package/src/utils.ts +0 -191
- package/test/README.md +0 -158
- package/test/__mocks__/ledger-mock.js +0 -20
- package/test/__mocks__/trezor-mock.js +0 -75
- package/test/cleanup-summary.md +0 -167
- package/test/helpers/README.md +0 -78
- package/test/helpers/constants.ts +0 -79
- package/test/helpers/setup.ts +0 -714
- package/test/integration/import-validation.spec.ts +0 -588
- package/test/unit/hardware/ledger.spec.ts +0 -869
- package/test/unit/hardware/trezor.spec.ts +0 -828
- package/test/unit/keyring-manager/account-management.spec.ts +0 -970
- package/test/unit/keyring-manager/import-watchonly.spec.ts +0 -181
- package/test/unit/keyring-manager/import-wif.spec.ts +0 -126
- package/test/unit/keyring-manager/initialization.spec.ts +0 -782
- package/test/unit/keyring-manager/key-derivation.spec.ts +0 -996
- package/test/unit/keyring-manager/security.spec.ts +0 -505
- package/test/unit/keyring-manager/state-management.spec.ts +0 -375
- package/test/unit/network/network-management.spec.ts +0 -372
- package/test/unit/transactions/ethereum-transactions.spec.ts +0 -382
- package/test/unit/transactions/syscoin-transactions.spec.ts +0 -615
- package/tsconfig.json +0 -14
- /package/{dist/README.md → README.md} +0 -0
- /package/{dist/cjs → cjs}/errorUtils.js +0 -0
- /package/{dist/cjs → cjs}/errorUtils.js.map +0 -0
- /package/{dist/cjs → cjs}/hardware-wallet-manager.js +0 -0
- /package/{dist/cjs → cjs}/hardware-wallet-manager.js.map +0 -0
- /package/{dist/cjs → cjs}/index.js +0 -0
- /package/{dist/cjs → cjs}/index.js.map +0 -0
- /package/{dist/cjs → cjs}/initial-state.js +0 -0
- /package/{dist/cjs → cjs}/initial-state.js.map +0 -0
- /package/{dist/cjs → cjs}/keyring-manager.js +0 -0
- /package/{dist/cjs → cjs}/keyring-manager.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/index.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/index.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/appClient.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/appClient.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/bip32.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/bip32.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/buffertools.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/buffertools.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/clientCommands.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/clientCommands.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/constants.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/constants.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/merkelizedPsbt.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/merkelizedPsbt.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/merkle.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/merkle.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/merkleMap.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/merkleMap.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/policy.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/policy.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/psbtv2.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/psbtv2.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/varint.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/varint.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/consts.js +0 -0
- /package/{dist/cjs → cjs}/ledger/consts.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/index.js +0 -0
- /package/{dist/cjs → cjs}/ledger/index.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/types.js +0 -0
- /package/{dist/cjs → cjs}/ledger/types.js.map +0 -0
- /package/{dist/cjs → cjs}/network-utils.js +0 -0
- /package/{dist/cjs → cjs}/network-utils.js.map +0 -0
- /package/{dist/cjs → cjs}/signers.js +0 -0
- /package/{dist/cjs → cjs}/signers.js.map +0 -0
- /package/{dist/cjs → cjs}/storage.js +0 -0
- /package/{dist/cjs → cjs}/storage.js.map +0 -0
- /package/{dist/cjs → cjs}/transactions/__tests__/integration.test.js +0 -0
- /package/{dist/cjs → cjs}/transactions/__tests__/integration.test.js.map +0 -0
- /package/{dist/cjs → cjs}/transactions/__tests__/syscoin.test.js +0 -0
- /package/{dist/cjs → cjs}/transactions/__tests__/syscoin.test.js.map +0 -0
- /package/{dist/cjs → cjs}/transactions/index.js +0 -0
- /package/{dist/cjs → cjs}/transactions/index.js.map +0 -0
- /package/{dist/cjs → cjs}/transactions/syscoin.js +0 -0
- /package/{dist/cjs → cjs}/transactions/syscoin.js.map +0 -0
- /package/{dist/cjs → cjs}/trezor/index.js +0 -0
- /package/{dist/cjs → cjs}/trezor/index.js.map +0 -0
- /package/{dist/cjs → cjs}/types.js +0 -0
- /package/{dist/cjs → cjs}/types.js.map +0 -0
- /package/{dist/cjs → cjs}/utils/derivation-paths.js +0 -0
- /package/{dist/cjs → cjs}/utils/derivation-paths.js.map +0 -0
- /package/{dist/cjs → cjs}/utils/psbt.js +0 -0
- /package/{dist/cjs → cjs}/utils/psbt.js.map +0 -0
- /package/{dist/cjs → cjs}/utils.js +0 -0
- /package/{dist/cjs → cjs}/utils.js.map +0 -0
- /package/{dist/types → types}/errorUtils.d.ts +0 -0
- /package/{dist/types → types}/hardware-wallet-manager.d.ts +0 -0
- /package/{dist/types → types}/index.d.ts +0 -0
- /package/{dist/types → types}/initial-state.d.ts +0 -0
- /package/{dist/types → types}/keyring-manager.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/index.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/appClient.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/bip32.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/buffertools.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/clientCommands.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/constants.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/merkelizedPsbt.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/merkle.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/merkleMap.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/policy.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/psbtv2.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/varint.d.ts +0 -0
- /package/{dist/types → types}/ledger/consts.d.ts +0 -0
- /package/{dist/types → types}/ledger/index.d.ts +0 -0
- /package/{dist/types → types}/ledger/types.d.ts +0 -0
- /package/{dist/types → types}/network-utils.d.ts +0 -0
- /package/{dist/types → types}/signers.d.ts +0 -0
- /package/{dist/types → types}/storage.d.ts +0 -0
- /package/{dist/types → types}/transactions/__tests__/integration.test.d.ts +0 -0
- /package/{dist/types → types}/transactions/__tests__/syscoin.test.d.ts +0 -0
- /package/{dist/types → types}/transactions/index.d.ts +0 -0
- /package/{dist/types → types}/transactions/syscoin.d.ts +0 -0
- /package/{dist/types → types}/trezor/index.d.ts +0 -0
- /package/{dist/types → types}/utils/derivation-paths.d.ts +0 -0
- /package/{dist/types → types}/utils/psbt.d.ts +0 -0
- /package/{dist/types → types}/utils.d.ts +0 -0
|
@@ -1,869 +0,0 @@
|
|
|
1
|
-
import { INetworkType } from '@sidhujag/sysweb3-network';
|
|
2
|
-
|
|
3
|
-
import { KeyringManager, KeyringAccountType } from '../../../src';
|
|
4
|
-
import { FAKE_PASSWORD, PEACE_SEED_PHRASE } from '../../helpers/constants';
|
|
5
|
-
import { setupMocks } from '../../helpers/setup';
|
|
6
|
-
|
|
7
|
-
// Use global createMockVaultState
|
|
8
|
-
const createMockVaultState = (global as any).createMockVaultState;
|
|
9
|
-
|
|
10
|
-
describe('Ledger Hardware Wallet', () => {
|
|
11
|
-
let keyringManager: KeyringManager;
|
|
12
|
-
let mockVaultStateGetter: jest.Mock;
|
|
13
|
-
let currentVaultState: any;
|
|
14
|
-
|
|
15
|
-
beforeEach(async () => {
|
|
16
|
-
setupMocks();
|
|
17
|
-
await global.setupTestVault(FAKE_PASSWORD);
|
|
18
|
-
|
|
19
|
-
// Set up UTXO vault state
|
|
20
|
-
currentVaultState = createMockVaultState({
|
|
21
|
-
activeAccountId: 0,
|
|
22
|
-
activeAccountType: KeyringAccountType.HDAccount,
|
|
23
|
-
networkType: INetworkType.Syscoin,
|
|
24
|
-
chainId: 57,
|
|
25
|
-
});
|
|
26
|
-
mockVaultStateGetter = jest.fn(() => currentVaultState);
|
|
27
|
-
|
|
28
|
-
keyringManager = await KeyringManager.createInitialized(
|
|
29
|
-
PEACE_SEED_PHRASE,
|
|
30
|
-
FAKE_PASSWORD,
|
|
31
|
-
mockVaultStateGetter
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
// Mock HardwareWalletManager ensureConnection
|
|
35
|
-
keyringManager.ledgerSigner.ensureConnection = jest
|
|
36
|
-
.fn()
|
|
37
|
-
.mockResolvedValue(undefined);
|
|
38
|
-
|
|
39
|
-
// Mock transport property
|
|
40
|
-
keyringManager.ledgerSigner.transport = {} as any;
|
|
41
|
-
|
|
42
|
-
// Mock ledgerUtxoClient for getMasterFingerprint calls
|
|
43
|
-
keyringManager.ledgerSigner.ledgerUtxoClient = {
|
|
44
|
-
getMasterFingerprint: jest.fn().mockResolvedValue('12345678'),
|
|
45
|
-
signPsbt: jest.fn(),
|
|
46
|
-
} as any;
|
|
47
|
-
|
|
48
|
-
// Mock getAddress to return our mocked addresses
|
|
49
|
-
keyringManager.getAddress = jest
|
|
50
|
-
.fn()
|
|
51
|
-
.mockResolvedValue('sys1qmock_ledger_address');
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
afterEach(async () => {
|
|
55
|
-
// Clean up hardware wallet connections
|
|
56
|
-
if (keyringManager) {
|
|
57
|
-
await keyringManager.destroy();
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
describe('Account Import', () => {
|
|
62
|
-
it('should import Ledger account when connected', async () => {
|
|
63
|
-
// Mock complete UTXO interface
|
|
64
|
-
keyringManager.ledgerSigner.utxo = {
|
|
65
|
-
getXpub: jest
|
|
66
|
-
.fn()
|
|
67
|
-
.mockResolvedValue(
|
|
68
|
-
'zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs'
|
|
69
|
-
),
|
|
70
|
-
getUtxoAddress: jest.fn().mockResolvedValue('sys1qmock_ledger_address'),
|
|
71
|
-
verifyUtxoAddress: jest
|
|
72
|
-
.fn()
|
|
73
|
-
.mockResolvedValue('sys1qmock_ledger_address'),
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const account = await keyringManager.importLedgerAccount('My Ledger');
|
|
77
|
-
|
|
78
|
-
expect(account).toBeDefined();
|
|
79
|
-
if (account) {
|
|
80
|
-
expect(account.id).toBe(0); // First imported Ledger account gets ID 0
|
|
81
|
-
expect(account.label).toBe('My Ledger');
|
|
82
|
-
expect(account.isLedgerWallet).toBe(true);
|
|
83
|
-
expect(account.isTrezorWallet).toBe(false);
|
|
84
|
-
expect(account.isImported).toBe(false);
|
|
85
|
-
expect(account.xprv).toBe(''); // Hardware wallets don't expose private keys
|
|
86
|
-
expect(account.address).toBe('sys1qmock_ledger_address');
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('should fail if Ledger connection fails', async () => {
|
|
91
|
-
// Mock connection failure in ensureConnection
|
|
92
|
-
keyringManager.ledgerSigner.ensureConnection = jest
|
|
93
|
-
.fn()
|
|
94
|
-
.mockRejectedValue(new Error('Failed to connect to device'));
|
|
95
|
-
|
|
96
|
-
await expect(keyringManager.importLedgerAccount()).rejects.toThrow(
|
|
97
|
-
'Failed to connect to device'
|
|
98
|
-
);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('should handle Ledger import for EVM networks', async () => {
|
|
102
|
-
// Set up EVM vault state
|
|
103
|
-
const evmVaultState = createMockVaultState({
|
|
104
|
-
activeAccountId: 0,
|
|
105
|
-
activeAccountType: KeyringAccountType.HDAccount,
|
|
106
|
-
networkType: INetworkType.Ethereum,
|
|
107
|
-
chainId: 1,
|
|
108
|
-
});
|
|
109
|
-
const evmVaultStateGetter = jest.fn(() => evmVaultState);
|
|
110
|
-
|
|
111
|
-
// Create EVM keyring
|
|
112
|
-
const evmKeyring = await KeyringManager.createInitialized(
|
|
113
|
-
PEACE_SEED_PHRASE,
|
|
114
|
-
FAKE_PASSWORD,
|
|
115
|
-
evmVaultStateGetter
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
// Mock ensureConnection for EVM keyring
|
|
119
|
-
evmKeyring.ledgerSigner.ensureConnection = jest
|
|
120
|
-
.fn()
|
|
121
|
-
.mockResolvedValue(undefined);
|
|
122
|
-
|
|
123
|
-
// Mock complete EVM interface
|
|
124
|
-
evmKeyring.ledgerSigner.evm = {
|
|
125
|
-
getEvmAddressAndPubKey: jest.fn().mockResolvedValue({
|
|
126
|
-
address: '0x742d35Cc6634C0532925a3b844Bc9e7595f2bd9F',
|
|
127
|
-
publicKey: '0x04...',
|
|
128
|
-
}),
|
|
129
|
-
signEVMTransaction: jest.fn().mockResolvedValue({
|
|
130
|
-
r: '123456789abcdef123456789abcdef123456789abcdef123456789abcdef12345678',
|
|
131
|
-
s: '987654321fedcba987654321fedcba987654321fedcba987654321fedcba987654',
|
|
132
|
-
v: '1c',
|
|
133
|
-
}),
|
|
134
|
-
signPersonalMessage: jest.fn().mockResolvedValue('0xmocked_signature'),
|
|
135
|
-
signTypedData: jest.fn().mockResolvedValue('0xmocked_typed_signature'),
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
const account = await evmKeyring.importLedgerAccount('Ledger ETH');
|
|
139
|
-
|
|
140
|
-
expect(account).toBeDefined();
|
|
141
|
-
if (account) {
|
|
142
|
-
expect(account.address.startsWith('0x')).toBe(true);
|
|
143
|
-
expect(account.isLedgerWallet).toBe(true);
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it('should reject duplicate Ledger addresses', async () => {
|
|
148
|
-
// Mock getAddress to return the expected addresses
|
|
149
|
-
keyringManager.getAddress = jest
|
|
150
|
-
.fn()
|
|
151
|
-
.mockResolvedValue('sys1q_first_address');
|
|
152
|
-
|
|
153
|
-
// First import with unique address
|
|
154
|
-
keyringManager.ledgerSigner.utxo = {
|
|
155
|
-
getXpub: jest
|
|
156
|
-
.fn()
|
|
157
|
-
.mockResolvedValue(
|
|
158
|
-
'zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs'
|
|
159
|
-
),
|
|
160
|
-
getUtxoAddress: jest.fn().mockResolvedValue('sys1q_first_address'),
|
|
161
|
-
verifyUtxoAddress: jest.fn().mockResolvedValue('sys1q_first_address'),
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
const firstAccount = await keyringManager.importLedgerAccount();
|
|
165
|
-
|
|
166
|
-
// Update vault state with first account
|
|
167
|
-
if (firstAccount) {
|
|
168
|
-
currentVaultState.accounts[KeyringAccountType.Ledger][firstAccount.id] =
|
|
169
|
-
{
|
|
170
|
-
id: firstAccount.id,
|
|
171
|
-
label: firstAccount.label,
|
|
172
|
-
address: firstAccount.address,
|
|
173
|
-
xpub: firstAccount.xpub,
|
|
174
|
-
xprv: '',
|
|
175
|
-
isImported: false,
|
|
176
|
-
isTrezorWallet: false,
|
|
177
|
-
isLedgerWallet: true,
|
|
178
|
-
balances: { syscoin: 0, ethereum: 0 },
|
|
179
|
-
assets: { syscoin: [], ethereum: [] },
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Mock Ledger returning same address for next account (simulate duplicate)
|
|
184
|
-
keyringManager.ledgerSigner.utxo = {
|
|
185
|
-
getXpub: jest
|
|
186
|
-
.fn()
|
|
187
|
-
.mockResolvedValue(
|
|
188
|
-
'zpub6s8HtEQtcu3AmBn9sniSqCAVhx2nJAhb2sd5NDYeYZ1ZJaZx7MAVZZnG1PdCUNJcVJXGbVpGfSYZLgkPSUjLYnJg8UdYvdkfaygcXZKPLy6'
|
|
189
|
-
),
|
|
190
|
-
getUtxoAddress: jest.fn().mockResolvedValue('sys1q_first_address'), // Same as first!
|
|
191
|
-
verifyUtxoAddress: jest.fn().mockResolvedValue('sys1q_first_address'),
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
// Should reject duplicate - this tests the actual business logic
|
|
195
|
-
await expect(keyringManager.importLedgerAccount()).rejects.toThrow(
|
|
196
|
-
'Account already exists'
|
|
197
|
-
);
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
describe('Account Management', () => {
|
|
202
|
-
beforeEach(async () => {
|
|
203
|
-
// Mock complete Ledger methods
|
|
204
|
-
keyringManager.ledgerSigner.utxo = {
|
|
205
|
-
getXpub: jest
|
|
206
|
-
.fn()
|
|
207
|
-
.mockResolvedValue(
|
|
208
|
-
'zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs'
|
|
209
|
-
),
|
|
210
|
-
getUtxoAddress: jest.fn().mockResolvedValue('sys1qmock_ledger_address'),
|
|
211
|
-
verifyUtxoAddress: jest
|
|
212
|
-
.fn()
|
|
213
|
-
.mockResolvedValue('sys1qmock_ledger_address'),
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
// Import a Ledger account
|
|
217
|
-
const account = await keyringManager.importLedgerAccount('Test Ledger');
|
|
218
|
-
|
|
219
|
-
// Update vault state with imported account
|
|
220
|
-
if (account) {
|
|
221
|
-
currentVaultState.accounts[KeyringAccountType.Ledger][account.id] = {
|
|
222
|
-
id: account.id,
|
|
223
|
-
label: account.label,
|
|
224
|
-
address: account.address,
|
|
225
|
-
xpub: account.xpub,
|
|
226
|
-
xprv: '',
|
|
227
|
-
isImported: false,
|
|
228
|
-
isTrezorWallet: false,
|
|
229
|
-
isLedgerWallet: true,
|
|
230
|
-
balances: { syscoin: 0, ethereum: 0 },
|
|
231
|
-
assets: { syscoin: [], ethereum: [] },
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
it('should switch to Ledger account', async () => {
|
|
237
|
-
// Update vault state to set Ledger as active
|
|
238
|
-
currentVaultState.activeAccount = {
|
|
239
|
-
id: 0,
|
|
240
|
-
type: KeyringAccountType.Ledger,
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
// Account switch is handled by vault state update
|
|
244
|
-
|
|
245
|
-
const { activeAccount, activeAccountType } =
|
|
246
|
-
keyringManager.getActiveAccount();
|
|
247
|
-
expect(activeAccountType).toBe(KeyringAccountType.Ledger);
|
|
248
|
-
expect(activeAccount.isLedgerWallet).toBe(true);
|
|
249
|
-
expect(activeAccount.label).toBe('Test Ledger');
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
it('should get Ledger account xpub', async () => {
|
|
253
|
-
// Update vault state to set Ledger as active
|
|
254
|
-
currentVaultState.activeAccount = {
|
|
255
|
-
id: 0,
|
|
256
|
-
type: KeyringAccountType.Ledger,
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
// Account switch is handled by vault state update
|
|
260
|
-
|
|
261
|
-
const xpub = keyringManager.getAccountXpub();
|
|
262
|
-
expect(xpub).toBeDefined();
|
|
263
|
-
expect(xpub).toBe(
|
|
264
|
-
'zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs'
|
|
265
|
-
);
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
it('should handle mixed account types with Ledger', async () => {
|
|
269
|
-
// Add HD account
|
|
270
|
-
const hdAccount = await keyringManager.addNewAccount('HD Account 2');
|
|
271
|
-
|
|
272
|
-
// Update vault state with HD account
|
|
273
|
-
currentVaultState.accounts[KeyringAccountType.HDAccount][hdAccount.id] = {
|
|
274
|
-
id: hdAccount.id,
|
|
275
|
-
label: hdAccount.label,
|
|
276
|
-
address: hdAccount.address,
|
|
277
|
-
xpub: hdAccount.xpub,
|
|
278
|
-
xprv: '',
|
|
279
|
-
isImported: false,
|
|
280
|
-
isTrezorWallet: false,
|
|
281
|
-
isLedgerWallet: false,
|
|
282
|
-
balances: { syscoin: 0, ethereum: 0 },
|
|
283
|
-
assets: { syscoin: [], ethereum: [] },
|
|
284
|
-
};
|
|
285
|
-
|
|
286
|
-
// Switch between them using actual account IDs
|
|
287
|
-
currentVaultState.activeAccount = {
|
|
288
|
-
id: 0,
|
|
289
|
-
type: KeyringAccountType.HDAccount,
|
|
290
|
-
};
|
|
291
|
-
// Account switch is handled by vault state update
|
|
292
|
-
expect(keyringManager.getActiveAccount().activeAccountType).toBe(
|
|
293
|
-
KeyringAccountType.HDAccount
|
|
294
|
-
);
|
|
295
|
-
|
|
296
|
-
// Switch to Ledger account
|
|
297
|
-
currentVaultState.activeAccount = {
|
|
298
|
-
id: 0,
|
|
299
|
-
type: KeyringAccountType.Ledger,
|
|
300
|
-
};
|
|
301
|
-
// Account switch is handled by vault state update
|
|
302
|
-
expect(keyringManager.getActiveAccount().activeAccountType).toBe(
|
|
303
|
-
KeyringAccountType.Ledger
|
|
304
|
-
);
|
|
305
|
-
});
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
describe('Transaction Signing', () => {
|
|
309
|
-
beforeEach(async () => {
|
|
310
|
-
// Complete mock setup for transaction signing tests
|
|
311
|
-
keyringManager.ledgerSigner.utxo = {
|
|
312
|
-
getXpub: jest
|
|
313
|
-
.fn()
|
|
314
|
-
.mockResolvedValue(
|
|
315
|
-
'zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs'
|
|
316
|
-
),
|
|
317
|
-
getUtxoAddress: jest.fn().mockResolvedValue('sys1qmock_ledger_address'),
|
|
318
|
-
verifyUtxoAddress: jest
|
|
319
|
-
.fn()
|
|
320
|
-
.mockResolvedValue('sys1qmock_ledger_address'),
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
const account = await keyringManager.importLedgerAccount('Signing Test');
|
|
324
|
-
if (account) {
|
|
325
|
-
// Update vault state to set Ledger as active
|
|
326
|
-
currentVaultState.accounts[KeyringAccountType.Ledger][account.id] = {
|
|
327
|
-
id: account.id,
|
|
328
|
-
label: account.label,
|
|
329
|
-
address: account.address,
|
|
330
|
-
xpub: account.xpub,
|
|
331
|
-
xprv: '',
|
|
332
|
-
isImported: false,
|
|
333
|
-
isTrezorWallet: false,
|
|
334
|
-
isLedgerWallet: true,
|
|
335
|
-
balances: { syscoin: 0, ethereum: 0 },
|
|
336
|
-
assets: { syscoin: [], ethereum: [] },
|
|
337
|
-
};
|
|
338
|
-
currentVaultState.activeAccount = {
|
|
339
|
-
id: account.id,
|
|
340
|
-
type: KeyringAccountType.Ledger,
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
// Account switch is handled by vault state update
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// Mock getAddress to return our mocked addresses
|
|
347
|
-
keyringManager.getAddress = jest
|
|
348
|
-
.fn()
|
|
349
|
-
.mockResolvedValue('sys1qmock_ledger_address');
|
|
350
|
-
|
|
351
|
-
// Mock Ledger UTXO client for transaction signing
|
|
352
|
-
keyringManager.ledgerSigner.ledgerUtxoClient = {
|
|
353
|
-
getMasterFingerprint: jest.fn().mockResolvedValue('12345678'),
|
|
354
|
-
signPsbt: jest.fn().mockResolvedValue([
|
|
355
|
-
[
|
|
356
|
-
0,
|
|
357
|
-
{
|
|
358
|
-
pubkey: Buffer.from('mock_pubkey'),
|
|
359
|
-
signature: Buffer.from('mock_signature'),
|
|
360
|
-
},
|
|
361
|
-
],
|
|
362
|
-
]),
|
|
363
|
-
// Add minimal required properties to satisfy interface
|
|
364
|
-
transport: {} as any,
|
|
365
|
-
makeRequest: jest.fn(),
|
|
366
|
-
getAppAndVersion: jest.fn(),
|
|
367
|
-
getExtendedPubkey: jest.fn(),
|
|
368
|
-
registerWallet: jest.fn(),
|
|
369
|
-
getWalletAddress: jest.fn(),
|
|
370
|
-
signMessage: jest.fn(),
|
|
371
|
-
} as any;
|
|
372
|
-
|
|
373
|
-
// Mock convertToLedgerFormat to return a proper PSBT mock with toBase64 method
|
|
374
|
-
keyringManager.ledgerSigner.convertToLedgerFormat = jest
|
|
375
|
-
.fn()
|
|
376
|
-
.mockResolvedValue({
|
|
377
|
-
toBase64: jest
|
|
378
|
-
.fn()
|
|
379
|
-
.mockReturnValue(
|
|
380
|
-
'cHNidP8BAHECAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=='
|
|
381
|
-
),
|
|
382
|
-
extractTransaction: jest.fn().mockReturnValue({
|
|
383
|
-
getId: jest.fn().mockReturnValue('mock_transaction_id'),
|
|
384
|
-
}),
|
|
385
|
-
updateInput: jest.fn(),
|
|
386
|
-
finalizeAllInputs: jest.fn(),
|
|
387
|
-
});
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
it('should prepare PSBT for Ledger signing', async () => {
|
|
391
|
-
// Mock the PSBT parsing to avoid base64 validation issues
|
|
392
|
-
const mockSyscoinjs = require('syscoinjs-lib');
|
|
393
|
-
const originalImportPsbtFromJson = mockSyscoinjs.utils.importPsbtFromJson;
|
|
394
|
-
mockSyscoinjs.utils.importPsbtFromJson = jest.fn().mockReturnValue({
|
|
395
|
-
psbt: {
|
|
396
|
-
toBase64: jest
|
|
397
|
-
.fn()
|
|
398
|
-
.mockReturnValue(
|
|
399
|
-
'cHNidP8BAHECAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=='
|
|
400
|
-
),
|
|
401
|
-
extractTransaction: jest.fn().mockReturnValue({
|
|
402
|
-
getId: jest.fn().mockReturnValue('mock_transaction_id'),
|
|
403
|
-
}),
|
|
404
|
-
updateInput: jest.fn(),
|
|
405
|
-
finalizeAllInputs: jest.fn(),
|
|
406
|
-
},
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
const psbtData = {
|
|
410
|
-
psbt: 'valid_psbt_data',
|
|
411
|
-
assets: [],
|
|
412
|
-
};
|
|
413
|
-
|
|
414
|
-
const result = await keyringManager.syscoinTransaction.signPSBT({
|
|
415
|
-
psbt: psbtData,
|
|
416
|
-
isTrezor: false,
|
|
417
|
-
isLedger: true,
|
|
418
|
-
});
|
|
419
|
-
|
|
420
|
-
expect(result).toBeDefined();
|
|
421
|
-
// Verify Ledger-specific handling was applied
|
|
422
|
-
// Restore original function
|
|
423
|
-
mockSyscoinjs.utils.importPsbtFromJson = originalImportPsbtFromJson;
|
|
424
|
-
});
|
|
425
|
-
|
|
426
|
-
it('should reconnect to Ledger when connection is lost during EVM transaction signing', async () => {
|
|
427
|
-
// Set up EVM vault state
|
|
428
|
-
const evmVaultState = createMockVaultState({
|
|
429
|
-
activeAccountId: 0,
|
|
430
|
-
activeAccountType: KeyringAccountType.Ledger,
|
|
431
|
-
networkType: INetworkType.Ethereum,
|
|
432
|
-
chainId: 1,
|
|
433
|
-
});
|
|
434
|
-
const evmVaultStateGetter = jest.fn(() => evmVaultState);
|
|
435
|
-
|
|
436
|
-
// Create EVM keyring with Ledger
|
|
437
|
-
const evmKeyring = await KeyringManager.createInitialized(
|
|
438
|
-
PEACE_SEED_PHRASE,
|
|
439
|
-
FAKE_PASSWORD,
|
|
440
|
-
evmVaultStateGetter
|
|
441
|
-
);
|
|
442
|
-
|
|
443
|
-
// Mock Ledger as disconnected
|
|
444
|
-
evmKeyring.ledgerSigner.transport = null;
|
|
445
|
-
evmKeyring.ledgerSigner.ledgerUtxoClient = null as any;
|
|
446
|
-
evmKeyring.ledgerSigner.ledgerEVMClient = null as any;
|
|
447
|
-
|
|
448
|
-
// Mock transport for reconnection
|
|
449
|
-
const mockTransport = { close: jest.fn() } as any;
|
|
450
|
-
|
|
451
|
-
// Mock ensureConnection to simulate successful reconnection
|
|
452
|
-
evmKeyring.ledgerSigner.ensureConnection = jest
|
|
453
|
-
.fn()
|
|
454
|
-
.mockImplementation(async () => {
|
|
455
|
-
// Simulate successful reconnection
|
|
456
|
-
evmKeyring.ledgerSigner.transport = mockTransport;
|
|
457
|
-
evmKeyring.ledgerSigner.ledgerUtxoClient = {
|
|
458
|
-
getMasterFingerprint: jest.fn().mockResolvedValue('12345678'),
|
|
459
|
-
} as any;
|
|
460
|
-
evmKeyring.ledgerSigner.ledgerEVMClient = {
|
|
461
|
-
signTransaction: jest.fn().mockResolvedValue({
|
|
462
|
-
r: '123456789abcdef',
|
|
463
|
-
s: '987654321fedcba',
|
|
464
|
-
v: '00',
|
|
465
|
-
}),
|
|
466
|
-
getAddress: jest.fn().mockResolvedValue({
|
|
467
|
-
address: '0x742D35Cc6634C0532925a3b844bc9e7595f2bd9f',
|
|
468
|
-
publicKey: '0x04...',
|
|
469
|
-
}),
|
|
470
|
-
signPersonalMessage: jest
|
|
471
|
-
.fn()
|
|
472
|
-
.mockResolvedValue('0xmocked_signature'),
|
|
473
|
-
signEIP712HashedMessage: jest
|
|
474
|
-
.fn()
|
|
475
|
-
.mockResolvedValue('0xmocked_typed_signature'),
|
|
476
|
-
} as any;
|
|
477
|
-
});
|
|
478
|
-
|
|
479
|
-
// Import Ledger account
|
|
480
|
-
const evmAccount = {
|
|
481
|
-
id: 0,
|
|
482
|
-
label: 'Ledger 1',
|
|
483
|
-
address: '0x742D35Cc6634C0532925a3b844bc9e7595f2bd9f',
|
|
484
|
-
xpub: 'xpub...',
|
|
485
|
-
};
|
|
486
|
-
|
|
487
|
-
evmVaultState.accounts[KeyringAccountType.Ledger][0] = {
|
|
488
|
-
id: evmAccount.id,
|
|
489
|
-
label: evmAccount.label,
|
|
490
|
-
address: evmAccount.address,
|
|
491
|
-
xpub: evmAccount.xpub,
|
|
492
|
-
xprv: '',
|
|
493
|
-
isImported: false,
|
|
494
|
-
isTrezorWallet: false,
|
|
495
|
-
isLedgerWallet: true,
|
|
496
|
-
balances: { syscoin: 0, ethereum: 0 },
|
|
497
|
-
assets: { syscoin: [], ethereum: [] },
|
|
498
|
-
};
|
|
499
|
-
|
|
500
|
-
// Test that Ledger reconnects and signs successfully
|
|
501
|
-
const result = await evmKeyring.ledgerSigner.evm.signEVMTransaction({
|
|
502
|
-
rawTx: '0x1234567890',
|
|
503
|
-
accountIndex: 0,
|
|
504
|
-
});
|
|
505
|
-
|
|
506
|
-
// Verify reconnection happened
|
|
507
|
-
expect(evmKeyring.ledgerSigner.ensureConnection).toHaveBeenCalledTimes(1);
|
|
508
|
-
|
|
509
|
-
// Verify the signature was returned
|
|
510
|
-
expect(result).toEqual({
|
|
511
|
-
r: '123456789abcdef',
|
|
512
|
-
s: '987654321fedcba',
|
|
513
|
-
v: '00',
|
|
514
|
-
});
|
|
515
|
-
|
|
516
|
-
// Verify Ledger is now connected
|
|
517
|
-
expect(evmKeyring.ledgerSigner.transport).toBeTruthy();
|
|
518
|
-
});
|
|
519
|
-
|
|
520
|
-
it('should handle EVM transaction signing for Ledger', async () => {
|
|
521
|
-
// Set up EVM vault state
|
|
522
|
-
const evmVaultState = createMockVaultState({
|
|
523
|
-
activeAccountId: 0,
|
|
524
|
-
activeAccountType: KeyringAccountType.HDAccount,
|
|
525
|
-
networkType: INetworkType.Ethereum,
|
|
526
|
-
chainId: 1,
|
|
527
|
-
});
|
|
528
|
-
const evmVaultStateGetter = jest.fn(() => evmVaultState);
|
|
529
|
-
|
|
530
|
-
// Create EVM keyring with Ledger
|
|
531
|
-
const evmKeyring = await KeyringManager.createInitialized(
|
|
532
|
-
PEACE_SEED_PHRASE,
|
|
533
|
-
FAKE_PASSWORD,
|
|
534
|
-
evmVaultStateGetter
|
|
535
|
-
);
|
|
536
|
-
|
|
537
|
-
// Mock ensureConnection
|
|
538
|
-
evmKeyring.ledgerSigner.ensureConnection = jest
|
|
539
|
-
.fn()
|
|
540
|
-
.mockResolvedValue(undefined);
|
|
541
|
-
|
|
542
|
-
// Mock Ledger EVM signer
|
|
543
|
-
const mockSignEVMTransaction = jest.fn().mockResolvedValue({
|
|
544
|
-
r: '123456789abcdef123456789abcdef123456789abcdef123456789abcdef12345678',
|
|
545
|
-
s: '987654321fedcba987654321fedcba987654321fedcba987654321fedcba987654',
|
|
546
|
-
v: '00',
|
|
547
|
-
});
|
|
548
|
-
|
|
549
|
-
evmKeyring.ledgerSigner.evm = {
|
|
550
|
-
getEvmAddressAndPubKey: jest.fn().mockResolvedValue({
|
|
551
|
-
address: '0x742D35Cc6634C0532925a3b844bc9e7595f2bd9f',
|
|
552
|
-
publicKey: '0x04...',
|
|
553
|
-
}),
|
|
554
|
-
signEVMTransaction: mockSignEVMTransaction,
|
|
555
|
-
signPersonalMessage: jest.fn().mockResolvedValue('0xmocked_signature'),
|
|
556
|
-
signTypedData: jest.fn().mockResolvedValue('0xmocked_typed_signature'),
|
|
557
|
-
};
|
|
558
|
-
|
|
559
|
-
// Import Ledger account
|
|
560
|
-
const evmAccount = await evmKeyring.importLedgerAccount('EVM Ledger');
|
|
561
|
-
if (evmAccount) {
|
|
562
|
-
// Update vault state to set Ledger as active
|
|
563
|
-
evmVaultState.accounts[KeyringAccountType.Ledger][evmAccount.id] = {
|
|
564
|
-
id: evmAccount.id,
|
|
565
|
-
label: evmAccount.label,
|
|
566
|
-
address: evmAccount.address,
|
|
567
|
-
xpub: evmAccount.xpub,
|
|
568
|
-
xprv: '',
|
|
569
|
-
isImported: false,
|
|
570
|
-
isTrezorWallet: false,
|
|
571
|
-
isLedgerWallet: true,
|
|
572
|
-
balances: { syscoin: 0, ethereum: 0 },
|
|
573
|
-
assets: { syscoin: [], ethereum: [] },
|
|
574
|
-
};
|
|
575
|
-
evmVaultState.activeAccount = {
|
|
576
|
-
id: evmAccount.id,
|
|
577
|
-
type: KeyringAccountType.Ledger,
|
|
578
|
-
};
|
|
579
|
-
|
|
580
|
-
// Account switch is handled by vault state update
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
// Test that Ledger signing is called - expect it to fail at serialization but verify Ledger was called
|
|
584
|
-
try {
|
|
585
|
-
await evmKeyring.ethereumTransaction.sendFormattedTransaction({
|
|
586
|
-
to: '0x742D35Cc6634C0532925a3b844bc9e7595f2bd9f',
|
|
587
|
-
value: '0x0',
|
|
588
|
-
data: '0x',
|
|
589
|
-
gasLimit: '0x5208',
|
|
590
|
-
maxFeePerGas: '0x3b9aca00',
|
|
591
|
-
maxPriorityFeePerGas: '0x1dcd6500',
|
|
592
|
-
chainId: 1,
|
|
593
|
-
from: '0x742D35Cc6634C0532925a3b844bc9e7595f2bd9f',
|
|
594
|
-
});
|
|
595
|
-
// If it doesn't throw, that's fine too
|
|
596
|
-
} catch (error) {
|
|
597
|
-
// Expected to fail at signature serialization, but we should have called the Ledger signer
|
|
598
|
-
expect(error.message).toContain('value out of range');
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
// The important part: verify that Ledger signing was attempted with correct parameters
|
|
602
|
-
expect(mockSignEVMTransaction).toHaveBeenCalled();
|
|
603
|
-
expect(mockSignEVMTransaction).toHaveBeenCalledWith({
|
|
604
|
-
rawTx: expect.any(String), // Should be a hex string of the unsigned transaction
|
|
605
|
-
accountIndex: expect.any(Number), // Should be the account index
|
|
606
|
-
});
|
|
607
|
-
});
|
|
608
|
-
});
|
|
609
|
-
|
|
610
|
-
describe('Network Support', () => {
|
|
611
|
-
it('should support Ledger on different UTXO networks', async () => {
|
|
612
|
-
// Set up testnet vault state
|
|
613
|
-
const testnetVaultState = createMockVaultState({
|
|
614
|
-
activeAccountId: 0,
|
|
615
|
-
activeAccountType: KeyringAccountType.HDAccount,
|
|
616
|
-
networkType: INetworkType.Syscoin,
|
|
617
|
-
chainId: 5700,
|
|
618
|
-
});
|
|
619
|
-
const testnetVaultStateGetter = jest.fn(() => testnetVaultState);
|
|
620
|
-
|
|
621
|
-
// Test on testnet
|
|
622
|
-
const testnetKeyring = await KeyringManager.createInitialized(
|
|
623
|
-
PEACE_SEED_PHRASE,
|
|
624
|
-
FAKE_PASSWORD,
|
|
625
|
-
testnetVaultStateGetter
|
|
626
|
-
);
|
|
627
|
-
|
|
628
|
-
// Mock getAddress to return testnet address
|
|
629
|
-
testnetKeyring.getAddress = jest
|
|
630
|
-
.fn()
|
|
631
|
-
.mockResolvedValue('tsys1q_testnet_ledger');
|
|
632
|
-
|
|
633
|
-
// Mock ensureConnection for testnet
|
|
634
|
-
testnetKeyring.ledgerSigner.ensureConnection = jest
|
|
635
|
-
.fn()
|
|
636
|
-
.mockResolvedValue(undefined);
|
|
637
|
-
|
|
638
|
-
// Mock testnet Ledger
|
|
639
|
-
testnetKeyring.ledgerSigner.utxo = {
|
|
640
|
-
getXpub: jest
|
|
641
|
-
.fn()
|
|
642
|
-
.mockResolvedValue(
|
|
643
|
-
'vpub5YMNvjHGu8MhNvgxNrGV8qZGkb3SVTiCAzqyCV8TbCZrEXrJqsCTMJjEJXBLfmjfFCDPRpGPW59THQMvPDuQejY5cSpfNYVZYcgJaMVZJCG'
|
|
644
|
-
),
|
|
645
|
-
getUtxoAddress: jest.fn().mockResolvedValue('tsys1q_testnet_ledger'),
|
|
646
|
-
verifyUtxoAddress: jest.fn().mockResolvedValue('tsys1q_testnet_ledger'),
|
|
647
|
-
};
|
|
648
|
-
|
|
649
|
-
const account = await testnetKeyring.importLedgerAccount(
|
|
650
|
-
'Testnet Ledger'
|
|
651
|
-
);
|
|
652
|
-
if (account) {
|
|
653
|
-
expect(account.address.match(/^(sys1|tsys1)/)).toBeTruthy();
|
|
654
|
-
}
|
|
655
|
-
});
|
|
656
|
-
|
|
657
|
-
it('should maintain separate Ledger accounts per network', async () => {
|
|
658
|
-
// Mock getAddress for mainnet
|
|
659
|
-
keyringManager.getAddress = jest
|
|
660
|
-
.fn()
|
|
661
|
-
.mockResolvedValue('sys1q_mainnet_ledger');
|
|
662
|
-
|
|
663
|
-
// Mock mainnet Ledger
|
|
664
|
-
keyringManager.ledgerSigner.utxo = {
|
|
665
|
-
getXpub: jest
|
|
666
|
-
.fn()
|
|
667
|
-
.mockResolvedValue(
|
|
668
|
-
'zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs'
|
|
669
|
-
),
|
|
670
|
-
getUtxoAddress: jest.fn().mockResolvedValue('sys1q_mainnet_ledger'),
|
|
671
|
-
verifyUtxoAddress: jest.fn().mockResolvedValue('sys1q_mainnet_ledger'),
|
|
672
|
-
};
|
|
673
|
-
|
|
674
|
-
// Import on mainnet
|
|
675
|
-
const mainnetAccount = await keyringManager.importLedgerAccount(
|
|
676
|
-
'Mainnet Ledger'
|
|
677
|
-
);
|
|
678
|
-
|
|
679
|
-
// Set up testnet vault state
|
|
680
|
-
const testnetVaultState = createMockVaultState({
|
|
681
|
-
activeAccountId: 0,
|
|
682
|
-
activeAccountType: KeyringAccountType.HDAccount,
|
|
683
|
-
networkType: INetworkType.Syscoin,
|
|
684
|
-
chainId: 5700,
|
|
685
|
-
});
|
|
686
|
-
const testnetVaultStateGetter = jest.fn(() => testnetVaultState);
|
|
687
|
-
|
|
688
|
-
// Create testnet keyring
|
|
689
|
-
const testnetKeyring = await KeyringManager.createInitialized(
|
|
690
|
-
PEACE_SEED_PHRASE,
|
|
691
|
-
FAKE_PASSWORD,
|
|
692
|
-
testnetVaultStateGetter
|
|
693
|
-
);
|
|
694
|
-
|
|
695
|
-
// Mock getAddress for testnet
|
|
696
|
-
testnetKeyring.getAddress = jest
|
|
697
|
-
.fn()
|
|
698
|
-
.mockResolvedValue('tsys1q_testnet_ledger');
|
|
699
|
-
|
|
700
|
-
// Mock ensureConnection for testnet
|
|
701
|
-
testnetKeyring.ledgerSigner.ensureConnection = jest
|
|
702
|
-
.fn()
|
|
703
|
-
.mockResolvedValue(undefined);
|
|
704
|
-
|
|
705
|
-
// Mock testnet Ledger
|
|
706
|
-
testnetKeyring.ledgerSigner.utxo = {
|
|
707
|
-
getXpub: jest
|
|
708
|
-
.fn()
|
|
709
|
-
.mockResolvedValue(
|
|
710
|
-
'vpub5YMNvjHGu8MhNvgxNrGV8qZGkb3SVTiCAzqyCV8TbCZrEXrJqsCTMJjEJXBLfmjfFCDPRpGPW59THQMvPDuQejY5cSpfNYVZYcgJaMVZJCG'
|
|
711
|
-
),
|
|
712
|
-
getUtxoAddress: jest.fn().mockResolvedValue('tsys1q_testnet_ledger'),
|
|
713
|
-
verifyUtxoAddress: jest.fn().mockResolvedValue('tsys1q_testnet_ledger'),
|
|
714
|
-
};
|
|
715
|
-
|
|
716
|
-
// Import on testnet
|
|
717
|
-
const testnetAccount = await testnetKeyring.importLedgerAccount(
|
|
718
|
-
'Testnet Ledger'
|
|
719
|
-
);
|
|
720
|
-
|
|
721
|
-
// Accounts should be independent
|
|
722
|
-
if (mainnetAccount && testnetAccount) {
|
|
723
|
-
expect(mainnetAccount.address).not.toBe(testnetAccount.address);
|
|
724
|
-
expect(mainnetAccount.address.match(/^(sys1|tsys1)/)).toBeTruthy();
|
|
725
|
-
expect(testnetAccount.address.match(/^(sys1|tsys1)/)).toBeTruthy();
|
|
726
|
-
}
|
|
727
|
-
});
|
|
728
|
-
});
|
|
729
|
-
|
|
730
|
-
describe('Error Handling', () => {
|
|
731
|
-
it('should handle Ledger communication errors', async () => {
|
|
732
|
-
// Mock communication error
|
|
733
|
-
keyringManager.ledgerSigner.utxo = {
|
|
734
|
-
getXpub: jest
|
|
735
|
-
.fn()
|
|
736
|
-
.mockRejectedValue(new Error('Ledger device communication error')),
|
|
737
|
-
getUtxoAddress: jest.fn(),
|
|
738
|
-
verifyUtxoAddress: jest.fn(),
|
|
739
|
-
};
|
|
740
|
-
|
|
741
|
-
await expect(keyringManager.importLedgerAccount()).rejects.toThrow(
|
|
742
|
-
'Ledger device communication error'
|
|
743
|
-
);
|
|
744
|
-
});
|
|
745
|
-
|
|
746
|
-
it('should handle invalid Ledger responses', async () => {
|
|
747
|
-
// Mock invalid response
|
|
748
|
-
keyringManager.ledgerSigner.utxo = {
|
|
749
|
-
getXpub: jest.fn().mockResolvedValue(null),
|
|
750
|
-
getUtxoAddress: jest.fn().mockResolvedValue(null),
|
|
751
|
-
verifyUtxoAddress: jest.fn(),
|
|
752
|
-
};
|
|
753
|
-
|
|
754
|
-
await expect(keyringManager.importLedgerAccount()).rejects.toThrow(
|
|
755
|
-
'Something wrong happened'
|
|
756
|
-
);
|
|
757
|
-
});
|
|
758
|
-
|
|
759
|
-
it('should handle Ledger app not open', async () => {
|
|
760
|
-
keyringManager.ledgerSigner.utxo = {
|
|
761
|
-
getXpub: jest
|
|
762
|
-
.fn()
|
|
763
|
-
.mockRejectedValue(new Error('Please open Syscoin app on Ledger')),
|
|
764
|
-
getUtxoAddress: jest.fn(),
|
|
765
|
-
verifyUtxoAddress: jest.fn(),
|
|
766
|
-
};
|
|
767
|
-
|
|
768
|
-
await expect(keyringManager.importLedgerAccount()).rejects.toThrow(
|
|
769
|
-
'Please open Syscoin app on Ledger'
|
|
770
|
-
);
|
|
771
|
-
});
|
|
772
|
-
});
|
|
773
|
-
|
|
774
|
-
describe('Security', () => {
|
|
775
|
-
it('should not expose private keys for hardware wallets', async () => {
|
|
776
|
-
// Mock getAddress
|
|
777
|
-
keyringManager.getAddress = jest
|
|
778
|
-
.fn()
|
|
779
|
-
.mockResolvedValue('sys1q_test_address');
|
|
780
|
-
|
|
781
|
-
keyringManager.ledgerSigner.utxo = {
|
|
782
|
-
getXpub: jest
|
|
783
|
-
.fn()
|
|
784
|
-
.mockResolvedValue(
|
|
785
|
-
'zpub6s8HtEQtcu3AmBn9sniSqCAVhx2nJAhb2sd5NDYeYZ1ZJaZx7MAVZZnG1PdCUNJcVJXGbVpGfSYZLgkPSUjLYnJg8UdYvdkfaygcXZKPLy6'
|
|
786
|
-
),
|
|
787
|
-
getUtxoAddress: jest.fn().mockResolvedValue('sys1q_test_address'),
|
|
788
|
-
verifyUtxoAddress: jest.fn().mockResolvedValue('sys1q_test_address'),
|
|
789
|
-
};
|
|
790
|
-
|
|
791
|
-
const account = await keyringManager.importLedgerAccount('Security Test');
|
|
792
|
-
|
|
793
|
-
expect(account).toBeDefined();
|
|
794
|
-
if (account) {
|
|
795
|
-
expect(account.xprv).toBe(''); // Should be empty for hardware wallets
|
|
796
|
-
expect(account.isLedgerWallet).toBe(true);
|
|
797
|
-
|
|
798
|
-
// Should not be able to get private key for hardware wallet
|
|
799
|
-
await expect(
|
|
800
|
-
keyringManager.getPrivateKeyByAccountId(
|
|
801
|
-
account.id,
|
|
802
|
-
KeyringAccountType.Ledger,
|
|
803
|
-
FAKE_PASSWORD
|
|
804
|
-
)
|
|
805
|
-
).rejects.toThrow();
|
|
806
|
-
}
|
|
807
|
-
});
|
|
808
|
-
|
|
809
|
-
it('should maintain hardware wallet isolation', async () => {
|
|
810
|
-
// Mock getAddress
|
|
811
|
-
keyringManager.getAddress = jest
|
|
812
|
-
.fn()
|
|
813
|
-
.mockResolvedValue('sys1q_isolation_address');
|
|
814
|
-
|
|
815
|
-
// Mock and import Ledger account
|
|
816
|
-
keyringManager.ledgerSigner.utxo = {
|
|
817
|
-
getXpub: jest
|
|
818
|
-
.fn()
|
|
819
|
-
.mockResolvedValue(
|
|
820
|
-
'zpub6s8HtEQtcu3AmBn9sniSqCAVhx2nJAhb2sd5NDYeYZ1ZJaZx7MAVZZnG1PdCUNJcVJXGbVpGfSYZLgkPSUjLYnJg8UdYvdkfaygcXZKPLy6'
|
|
821
|
-
),
|
|
822
|
-
getUtxoAddress: jest.fn().mockResolvedValue('sys1q_isolation_address'),
|
|
823
|
-
verifyUtxoAddress: jest
|
|
824
|
-
.fn()
|
|
825
|
-
.mockResolvedValue('sys1q_isolation_address'),
|
|
826
|
-
};
|
|
827
|
-
|
|
828
|
-
const ledgerAccount = await keyringManager.importLedgerAccount(
|
|
829
|
-
'Isolation Test'
|
|
830
|
-
);
|
|
831
|
-
|
|
832
|
-
if (ledgerAccount) {
|
|
833
|
-
// Update vault state
|
|
834
|
-
currentVaultState.accounts[KeyringAccountType.Ledger][
|
|
835
|
-
ledgerAccount.id
|
|
836
|
-
] = {
|
|
837
|
-
id: ledgerAccount.id,
|
|
838
|
-
label: ledgerAccount.label,
|
|
839
|
-
address: ledgerAccount.address,
|
|
840
|
-
xpub: ledgerAccount.xpub,
|
|
841
|
-
xprv: '',
|
|
842
|
-
isImported: false,
|
|
843
|
-
isTrezorWallet: false,
|
|
844
|
-
isLedgerWallet: true,
|
|
845
|
-
balances: { syscoin: 0, ethereum: 0 },
|
|
846
|
-
assets: { syscoin: [], ethereum: [] },
|
|
847
|
-
};
|
|
848
|
-
|
|
849
|
-
// Verify Ledger accounts are completely separate from HD accounts
|
|
850
|
-
const hdAccounts =
|
|
851
|
-
currentVaultState.accounts[KeyringAccountType.HDAccount];
|
|
852
|
-
const ledgerAccounts =
|
|
853
|
-
currentVaultState.accounts[KeyringAccountType.Ledger];
|
|
854
|
-
|
|
855
|
-
expect(Object.keys(hdAccounts)).toHaveLength(1); // Initial HD account
|
|
856
|
-
expect(Object.keys(ledgerAccounts)).toHaveLength(1); // One imported Ledger account
|
|
857
|
-
|
|
858
|
-
// Verify no cross-contamination of account types
|
|
859
|
-
Object.values(hdAccounts).forEach((account: any) => {
|
|
860
|
-
expect(account.isLedgerWallet).toBe(false);
|
|
861
|
-
});
|
|
862
|
-
|
|
863
|
-
Object.values(ledgerAccounts).forEach((account: any) => {
|
|
864
|
-
expect(account.isLedgerWallet).toBe(true);
|
|
865
|
-
});
|
|
866
|
-
}
|
|
867
|
-
});
|
|
868
|
-
});
|
|
869
|
-
});
|