Skip to content
This repository was archived by the owner on Oct 7, 2024. It is now read-only.

Commit aa68888

Browse files
authored
feat!: create new vault with any keyring (#329)
This change updates the logic inside the eth-keyring-controller to allow the creation of a vault with any keyring. This removes the hardcoded HD Keyring from the code and allow the client to pass the parameters to instantiate any keyring that is accepted by the controller. BREAKING: Unify createNewVaultAndKeychain and createNewVaultAndRestore into new method createNewVaultWithKeyring. createNewVaultWithKeyring accepts a password and a keyring object provided by the client and returns the KeyringControllerState
1 parent cac52da commit aa68888

File tree

3 files changed

+159
-117
lines changed

3 files changed

+159
-117
lines changed

jest.config.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ module.exports = {
4141
// An object that configures minimum threshold enforcement for coverage results
4242
coverageThreshold: {
4343
global: {
44-
branches: 80.35,
45-
functions: 93.65,
46-
lines: 91.9,
47-
statements: 92.07,
44+
branches: 80.18,
45+
functions: 93.54,
46+
lines: 91.69,
47+
statements: 91.87,
4848
},
4949
},
5050
preset: 'ts-jest',

src/KeyringController.test.ts

Lines changed: 136 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,17 @@ async function initializeKeyringController({
6767
if (seedPhrase && !password) {
6868
throw new Error('Password required to restore vault');
6969
} else if (seedPhrase && password) {
70-
await keyringController.createNewVaultAndRestore(
71-
PASSWORD,
72-
walletOneSeedWords,
73-
);
70+
await keyringController.createNewVaultWithKeyring(PASSWORD, {
71+
type: KeyringType.HD,
72+
opts: {
73+
mnemonic: walletOneSeedWords,
74+
numberOfAccounts: 1,
75+
},
76+
});
7477
} else if (password) {
75-
await keyringController.createNewVaultAndKeychain(PASSWORD);
78+
await keyringController.createNewVaultWithKeyring(PASSWORD, {
79+
type: KeyringType.HD,
80+
});
7681
}
7782

7883
return keyringController;
@@ -162,7 +167,9 @@ describe('KeyringController', () => {
162167
const keyringController = await initializeKeyringController({
163168
password: PASSWORD,
164169
});
165-
await keyringController.createNewVaultAndKeychain(PASSWORD);
170+
await keyringController.createNewVaultWithKeyring(PASSWORD, {
171+
type: KeyringType.HD,
172+
});
166173
await keyringController.persistAllKeyrings();
167174
expect(keyringController.keyrings).toHaveLength(1);
168175

@@ -257,7 +264,9 @@ describe('KeyringController', () => {
257264
cacheEncryptionKey: true,
258265
},
259266
});
260-
await keyringController.createNewVaultAndKeychain(PASSWORD);
267+
await keyringController.createNewVaultWithKeyring(PASSWORD, {
268+
type: KeyringType.HD,
269+
});
261270
deleteEncryptionKeyAndSalt(keyringController);
262271

263272
const response = await keyringController.persistAllKeyrings();
@@ -293,32 +302,81 @@ describe('KeyringController', () => {
293302
});
294303
});
295304
});
305+
306+
it('should add an `encryptionSalt` to the `memStore` when a vault is restored', async () => {
307+
const keyringController = await initializeKeyringController({
308+
password: PASSWORD,
309+
constructorOptions: {
310+
cacheEncryptionKey: true,
311+
},
312+
});
313+
314+
await keyringController.createNewVaultWithKeyring(PASSWORD, {
315+
type: KeyringType.HD,
316+
opts: {
317+
mnemonic: walletOneSeedWords,
318+
numberOfAccounts: 1,
319+
},
320+
});
321+
322+
const finalMemStore = keyringController.memStore.getState();
323+
expect(finalMemStore.encryptionKey).toBe(MOCK_HARDCODED_KEY);
324+
expect(finalMemStore.encryptionSalt).toBe(MOCK_ENCRYPTION_SALT);
325+
});
296326
});
297327

298-
describe('createNewVaultAndKeychain', () => {
299-
it('should create a new vault', async () => {
328+
describe('createNewVaultWithKeyring', () => {
329+
it('should create a new vault with a HD keyring', async () => {
300330
const keyringController = await initializeKeyringController({
301331
password: PASSWORD,
302332
});
303333
keyringController.store.putState({});
304334
assert(!keyringController.store.getState().vault, 'no previous vault');
305335

306-
const newVault = await keyringController.createNewVaultAndKeychain(
336+
const newVault = await keyringController.createNewVaultWithKeyring(
307337
PASSWORD,
338+
{
339+
type: KeyringType.HD,
340+
},
308341
);
309342
const { vault } = keyringController.store.getState();
310343
expect(vault).toStrictEqual(expect.stringMatching('.+'));
311344
expect(typeof newVault).toBe('object');
312345
});
313346

347+
it('should create a new vault with a simple keyring', async () => {
348+
const keyringController = await initializeKeyringController({
349+
password: PASSWORD,
350+
});
351+
keyringController.store.putState({});
352+
assert(!keyringController.store.getState().vault, 'no previous vault');
353+
354+
const newVault = await keyringController.createNewVaultWithKeyring(
355+
PASSWORD,
356+
{
357+
type: KeyringType.Simple,
358+
opts: walletOnePrivateKey,
359+
},
360+
);
361+
const { vault } = keyringController.store.getState();
362+
expect(vault).toStrictEqual(expect.stringMatching('.+'));
363+
expect(typeof newVault).toBe('object');
364+
365+
const accounts = await keyringController.getAccounts();
366+
expect(accounts).toHaveLength(1);
367+
expect(accounts[0]).toBe(walletOneAddresses[0]);
368+
});
369+
314370
it('should unlock the vault', async () => {
315371
const keyringController = await initializeKeyringController({
316372
password: PASSWORD,
317373
});
318374
keyringController.store.putState({});
319375
assert(!keyringController.store.getState().vault, 'no previous vault');
320376

321-
await keyringController.createNewVaultAndKeychain(PASSWORD);
377+
await keyringController.createNewVaultWithKeyring(PASSWORD, {
378+
type: KeyringType.HD,
379+
});
322380
const { isUnlocked } = keyringController.memStore.getState();
323381
expect(isUnlocked).toBe(true);
324382
});
@@ -335,7 +393,9 @@ describe('KeyringController', () => {
335393
keyringController.store.putState({});
336394
assert(!keyringController.store.getState().vault, 'no previous vault');
337395

338-
await keyringController.createNewVaultAndKeychain(PASSWORD);
396+
await keyringController.createNewVaultWithKeyring(PASSWORD, {
397+
type: KeyringType.HD,
398+
});
339399
const { vault } = keyringController.store.getState();
340400
// eslint-disable-next-line jest/no-restricted-matchers
341401
expect(vault).toBeTruthy();
@@ -353,8 +413,10 @@ describe('KeyringController', () => {
353413
.mockImplementation(async () => Promise.resolve([]));
354414

355415
await expect(async () =>
356-
keyringController.createNewVaultAndKeychain(PASSWORD),
357-
).rejects.toThrow(KeyringControllerError.NoAccountOnKeychain);
416+
keyringController.createNewVaultWithKeyring(PASSWORD, {
417+
type: KeyringType.HD,
418+
}),
419+
).rejects.toThrow(KeyringControllerError.NoFirstAccount);
358420
});
359421

360422
describe('when `cacheEncryptionKey` is enabled', () => {
@@ -366,16 +428,16 @@ describe('KeyringController', () => {
366428
},
367429
});
368430

369-
await keyringController.createNewVaultAndKeychain(PASSWORD);
431+
await keyringController.createNewVaultWithKeyring(PASSWORD, {
432+
type: KeyringType.HD,
433+
});
370434

371435
const finalMemStore = keyringController.memStore.getState();
372436
expect(finalMemStore.encryptionKey).toBe(MOCK_HARDCODED_KEY);
373437
expect(finalMemStore.encryptionSalt).toBe(MOCK_ENCRYPTION_SALT);
374438
});
375439
});
376-
});
377440

378-
describe('createNewVaultAndRestore', () => {
379441
it('clears old keyrings and creates a one', async () => {
380442
const keyringController = await initializeKeyringController({
381443
password: PASSWORD,
@@ -387,10 +449,13 @@ describe('KeyringController', () => {
387449
const allAccounts = await keyringController.getAccounts();
388450
expect(allAccounts).toHaveLength(2);
389451

390-
await keyringController.createNewVaultAndRestore(
391-
PASSWORD,
392-
walletOneSeedWords,
393-
);
452+
await keyringController.createNewVaultWithKeyring(PASSWORD, {
453+
type: KeyringType.HD,
454+
opts: {
455+
mnemonic: walletOneSeedWords,
456+
numberOfAccounts: 1,
457+
},
458+
});
394459

395460
const allAccountsAfter = await keyringController.getAccounts();
396461
expect(allAccountsAfter).toHaveLength(1);
@@ -403,7 +468,13 @@ describe('KeyringController', () => {
403468
});
404469
await expect(async () =>
405470
// @ts-expect-error Missing other required permission types.
406-
keyringController.createNewVaultAndRestore(12, walletTwoSeedWords),
471+
keyringController.createNewVaultWithKeyring(12, {
472+
type: KeyringType.HD,
473+
opts: {
474+
mnemonic: walletTwoSeedWords,
475+
numberOfAccounts: 1,
476+
},
477+
}),
407478
).rejects.toThrow('KeyringController - Password must be of type string.');
408479
});
409480

@@ -412,16 +483,26 @@ describe('KeyringController', () => {
412483
password: PASSWORD,
413484
});
414485
await expect(async () =>
415-
keyringController.createNewVaultAndRestore(
416-
PASSWORD,
417-
'test test test palace city barely security section midnight wealth south deer',
418-
),
486+
keyringController.createNewVaultWithKeyring(PASSWORD, {
487+
type: KeyringType.HD,
488+
opts: {
489+
mnemonic:
490+
'test test test palace city barely security section midnight wealth south deer',
491+
numberOfAccounts: 1,
492+
},
493+
}),
419494
).rejects.toThrow(
420495
'Eth-Hd-Keyring: Invalid secret recovery phrase provided',
421496
);
422497

423498
await expect(async () =>
424-
keyringController.createNewVaultAndRestore(PASSWORD, '1234'),
499+
keyringController.createNewVaultWithKeyring(PASSWORD, {
500+
type: KeyringType.HD,
501+
opts: {
502+
mnemonic: '1234',
503+
numberOfAccounts: 1,
504+
},
505+
}),
425506
).rejects.toThrow(
426507
'Eth-Hd-Keyring: Invalid secret recovery phrase provided',
427508
);
@@ -437,10 +518,13 @@ describe('KeyringController', () => {
437518
Buffer.from(walletTwoSeedWords).values(),
438519
);
439520

440-
await keyringController.createNewVaultAndRestore(
441-
PASSWORD,
442-
mnemonicAsArrayOfNumbers,
443-
);
521+
await keyringController.createNewVaultWithKeyring(PASSWORD, {
522+
type: KeyringType.HD,
523+
opts: {
524+
mnemonic: mnemonicAsArrayOfNumbers,
525+
numberOfAccounts: 1,
526+
},
527+
});
444528

445529
const allAccountsAfter = await keyringController.getAccounts();
446530
expect(allAccountsAfter).toHaveLength(1);
@@ -456,31 +540,14 @@ describe('KeyringController', () => {
456540
.mockImplementation(async () => Promise.resolve([]));
457541

458542
await expect(async () =>
459-
keyringController.createNewVaultAndRestore(
460-
PASSWORD,
461-
walletTwoSeedWords,
462-
),
463-
).rejects.toThrow('KeyringController - First Account not found.');
464-
});
465-
466-
describe('when `cacheEncryptionKey` is enabled', () => {
467-
it('should add an `encryptionSalt` to the `memStore` when a vault is restored', async () => {
468-
const keyringController = await initializeKeyringController({
469-
password: PASSWORD,
470-
constructorOptions: {
471-
cacheEncryptionKey: true,
543+
keyringController.createNewVaultWithKeyring(PASSWORD, {
544+
type: KeyringType.HD,
545+
opts: {
546+
mnemonic: walletTwoSeedWords,
547+
numberOfAccounts: 1,
472548
},
473-
});
474-
475-
await keyringController.createNewVaultAndRestore(
476-
PASSWORD,
477-
walletOneSeedWords,
478-
);
479-
480-
const finalMemStore = keyringController.memStore.getState();
481-
expect(finalMemStore.encryptionKey).toBe(MOCK_HARDCODED_KEY);
482-
expect(finalMemStore.encryptionSalt).toBe(MOCK_ENCRYPTION_SALT);
483-
});
549+
}),
550+
).rejects.toThrow('KeyringController - First Account not found.');
484551
});
485552
});
486553

@@ -943,10 +1010,13 @@ describe('KeyringController', () => {
9431010
it('does not throw if a vault exists in state', async () => {
9441011
const keyringController = await initializeKeyringController();
9451012

946-
await keyringController.createNewVaultAndRestore(
947-
PASSWORD,
948-
walletOneSeedWords,
949-
);
1013+
await keyringController.createNewVaultWithKeyring(PASSWORD, {
1014+
type: KeyringType.HD,
1015+
opts: {
1016+
mnemonic: walletOneSeedWords,
1017+
numberOfAccounts: 1,
1018+
},
1019+
});
9501020

9511021
expect(async () =>
9521022
keyringController.verifyPassword(PASSWORD),
@@ -1273,10 +1343,13 @@ describe('KeyringController', () => {
12731343
const keyringController = await initializeKeyringController({
12741344
password: PASSWORD,
12751345
});
1276-
await keyringController.createNewVaultAndRestore(
1277-
PASSWORD,
1278-
walletOneSeedWords,
1279-
);
1346+
await keyringController.createNewVaultWithKeyring(PASSWORD, {
1347+
type: KeyringType.HD,
1348+
opts: {
1349+
mnemonic: walletOneSeedWords,
1350+
numberOfAccounts: 1,
1351+
},
1352+
});
12801353
const privateKey = await keyringController.exportAccount(
12811354
// @ts-expect-error this value should never be undefined in this specific context.
12821355
walletOneAddresses[0],

0 commit comments

Comments
 (0)