Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix!: bug 4157, use getAccounts on HD Keyring when calling addNewAccount #4158

Merged
merged 4 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions packages/keyring-controller/src/KeyringController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,32 @@ describe('KeyringController', () => {
},
);
});

// Testing fix for bug #4157 {@link https://github.com/MetaMask/core/issues/4157}
it('should return an existing HD account if the accountCount is lower than oldAccounts', async () => {
const mockAddress = '0x123';
stubKeyringClassWithAccount(MockKeyring, mockAddress);
await withController(
{ keyringBuilders: [keyringBuilderFactory(MockKeyring)] },
async ({ controller, initialState }) => {
await controller.addNewKeyring(MockKeyring.type);

// expect there to be two accounts, 1 from HD and 1 from MockKeyring
expect(await controller.getAccounts()).toHaveLength(2);

const accountCount = initialState.keyrings[0].accounts.length;
const { addedAccountAddress: firstAccountAdded } =
montelaidev marked this conversation as resolved.
Show resolved Hide resolved
await controller.addNewAccount(accountCount);
const { addedAccountAddress: secondAccountAdded } =
montelaidev marked this conversation as resolved.
Show resolved Hide resolved
await controller.addNewAccount(accountCount);
expect(firstAccountAdded).toBe(secondAccountAdded);
expect(controller.state.keyrings[0].accounts).toHaveLength(
accountCount + 1,
);
expect(await controller.getAccounts()).toHaveLength(3);
},
);
});
});

describe('addNewAccountForKeyring', () => {
Expand Down
13 changes: 9 additions & 4 deletions packages/keyring-controller/src/KeyringController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -573,17 +573,22 @@ export class KeyringController extends BaseController<
if (!primaryKeyring) {
throw new Error('No HD keyring found');
}
const oldAccounts = await this.getAccounts();
const oldAccounts = await primaryKeyring.getAccounts();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we change this here, then we probably have to change what's being used by the extension as accountCount, as we currently count all accounts there: https://github.com/MetaMask/metamask-extension/blob/6e0483da7d5269cbb3afdba2ea579902e9d2987b/app/scripts/metamask-controller.js#L3602

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for this reason we should mark this PR as breaking

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, we should mark this as breaking and also make the change in the clients as well.


if (accountCount && oldAccounts.length !== accountCount) {
if (accountCount > oldAccounts.length) {
throw new Error('Account out of sequence');
}
// we return the account already existing at index `accountCount`
const primaryKeyringAccounts = await primaryKeyring.getAccounts();
const existingAccount = oldAccounts[accountCount];

if (!existingAccount) {
throw new Error(`Can't find account at index ${accountCount}`);
}

return {
keyringState: this.#getMemState(),
addedAccountAddress: primaryKeyringAccounts[accountCount],
addedAccountAddress: existingAccount,
};
}

Expand Down Expand Up @@ -797,7 +802,7 @@ export class KeyringController extends BaseController<
}

/**
* Returns the public addresses of all accounts for the current keyring.
* Returns the public addresses of all accounts from every keyring.
*
* @returns A promise resolving to an array of addresses.
*/
Expand Down
Loading