Skip to content

Commit 91d9a85

Browse files
committed
Merge remote-tracking branch 'origin/main' into normal-account-options
# Conflicts: # packages/accounts-controller/CHANGELOG.md
2 parents 9716380 + 6e8000b commit 91d9a85

File tree

170 files changed

+10996
-8088
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

170 files changed

+10996
-8088
lines changed

.github/workflows/main.yml

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ on:
55
branches: [main]
66
pull_request:
77

8+
concurrency:
9+
group: ${{ github.workflow }}-${{ github.ref }}
10+
cancel-in-progress: ${{ !contains(github.ref, 'refs/heads/main') }}
11+
812
jobs:
913
check-workflows:
1014
name: Check workflows

eslint-warning-thresholds.json

+4-8
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,8 @@
104104
"import-x/order": 3
105105
},
106106
"packages/assets-controllers/src/TokenRatesController.ts": {
107-
"@typescript-eslint/prefer-readonly": 2,
108-
"jsdoc/check-tag-names": 11,
109-
"no-unused-private-class-members": 1
107+
"@typescript-eslint/prefer-readonly": 1,
108+
"jsdoc/check-tag-names": 11
110109
},
111110
"packages/assets-controllers/src/TokensController.test.ts": {
112111
"import-x/namespace": 1,
@@ -230,7 +229,7 @@
230229
"jest/no-conditional-in-test": 8
231230
},
232231
"packages/keyring-controller/src/KeyringController.ts": {
233-
"@typescript-eslint/no-unsafe-enum-comparison": 5,
232+
"@typescript-eslint/no-unsafe-enum-comparison": 4,
234233
"@typescript-eslint/no-unused-vars": 1
235234
},
236235
"packages/keyring-controller/tests/mocks/mockKeyring.ts": {
@@ -416,11 +415,8 @@
416415
"packages/permission-log-controller/tests/PermissionLogController.test.ts": {
417416
"import-x/order": 1
418417
},
419-
"packages/phishing-controller/src/PhishingController.test.ts": {
420-
"import-x/no-named-as-default-member": 1
421-
},
422418
"packages/phishing-controller/src/PhishingController.ts": {
423-
"jsdoc/check-tag-names": 42,
419+
"jsdoc/check-tag-names": 38,
424420
"jsdoc/tag-lines": 1
425421
},
426422
"packages/phishing-controller/src/PhishingDetector.ts": {

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@metamask/core-monorepo",
3-
"version": "367.0.0",
3+
"version": "381.0.0",
44
"private": true,
55
"description": "Monorepo for packages shared between MetaMask clients",
66
"repository": {
@@ -54,7 +54,7 @@
5454
"@babel/preset-typescript": "^7.23.3",
5555
"@lavamoat/allow-scripts": "^3.0.4",
5656
"@lavamoat/preinstall-always-fail": "^2.1.0",
57-
"@metamask/create-release-branch": "^4.1.1",
57+
"@metamask/create-release-branch": "^4.1.2",
5858
"@metamask/eslint-config": "^14.0.0",
5959
"@metamask/eslint-config-jest": "^14.0.0",
6060
"@metamask/eslint-config-nodejs": "^14.0.0",

packages/accounts-controller/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
- Add new `setAccountNameAndSelectAccount` action ([#5714](https://github.com/MetaMask/core/pull/5714))
1213
- Add `entropySource` and `derivationPath` to EVM HD account options via `listNormalAccounts` ([#5618](https://github.com/MetaMask/core/pull/5618))
1314

1415
### Changed
1516

17+
- Bump `@metamask/base-controller` from ^8.0.0 to ^8.0.1 ([#5722](https://github.com/MetaMask/core/pull/5722))
1618
- **BREAKING:** Bump `@metamask/snaps-controllers` peer dependency from ^9.19.0 to ^11.0.0 ([#5639](https://github.com/MetaMask/core/pull/5639))
1719
- **BREAKING:** Bump `@metamask/providers` peer dependency from ^18.1.0 to ^21.0.0 ([#5639](https://github.com/MetaMask/core/pull/5639))
1820
- Bump `@metamask/snaps-sdk` from ^6.17.1 to ^6.22.0 ([#5639](https://github.com/MetaMask/core/pull/5639))

packages/accounts-controller/package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
},
4949
"dependencies": {
5050
"@ethereumjs/util": "^9.1.0",
51-
"@metamask/base-controller": "^8.0.0",
51+
"@metamask/base-controller": "^8.0.1",
5252
"@metamask/eth-snap-keyring": "^12.1.1",
5353
"@metamask/keyring-api": "^17.4.0",
5454
"@metamask/keyring-internal-api": "^6.0.1",
@@ -63,8 +63,8 @@
6363
},
6464
"devDependencies": {
6565
"@metamask/auto-changelog": "^3.4.4",
66-
"@metamask/keyring-controller": "^21.0.3",
67-
"@metamask/network-controller": "^23.2.0",
66+
"@metamask/keyring-controller": "^21.0.4",
67+
"@metamask/network-controller": "^23.3.0",
6868
"@metamask/providers": "^21.0.0",
6969
"@metamask/snaps-controllers": "^11.2.1",
7070
"@types/jest": "^27.4.1",

packages/accounts-controller/src/AccountsController.test.ts

+145
Original file line numberDiff line numberDiff line change
@@ -2783,6 +2783,116 @@ describe('AccountsController', () => {
27832783
});
27842784
});
27852785

2786+
describe('setAccountNameAndSelect', () => {
2787+
const newAccountName = 'New Account Name';
2788+
const mockState = {
2789+
initialState: {
2790+
internalAccounts: {
2791+
accounts: { [mockAccount.id]: mockAccount },
2792+
selectedAccount: mockAccount.id,
2793+
},
2794+
},
2795+
};
2796+
2797+
it('sets the name of an existing account', () => {
2798+
const { accountsController } = setupAccountsController(mockState);
2799+
2800+
accountsController.setAccountNameAndSelectAccount(
2801+
mockAccount.id,
2802+
newAccountName,
2803+
);
2804+
2805+
expect(
2806+
accountsController.getAccountExpect(mockAccount.id).metadata.name,
2807+
).toBe(newAccountName);
2808+
expect(accountsController.state.internalAccounts.selectedAccount).toBe(
2809+
mockAccount.id,
2810+
);
2811+
});
2812+
2813+
it('sets the name of an existing account and select the account', () => {
2814+
const { accountsController } = setupAccountsController({
2815+
initialState: {
2816+
internalAccounts: {
2817+
accounts: {
2818+
[mockAccount.id]: mockAccount,
2819+
[mockAccount2.id]: mockAccount2,
2820+
},
2821+
selectedAccount: mockAccount.id,
2822+
},
2823+
},
2824+
});
2825+
2826+
accountsController.setAccountNameAndSelectAccount(
2827+
mockAccount2.id,
2828+
newAccountName,
2829+
);
2830+
2831+
expect(
2832+
accountsController.getAccountExpect(mockAccount2.id).metadata.name,
2833+
).toBe(newAccountName);
2834+
expect(accountsController.state.internalAccounts.selectedAccount).toBe(
2835+
mockAccount2.id,
2836+
);
2837+
});
2838+
2839+
it('sets the nameLastUpdatedAt timestamp when setting the name of an existing account', () => {
2840+
const expectedTimestamp = Number(new Date('2024-01-02'));
2841+
2842+
jest.spyOn(Date, 'now').mockImplementation(() => expectedTimestamp);
2843+
2844+
const { accountsController } = setupAccountsController(mockState);
2845+
2846+
accountsController.setAccountNameAndSelectAccount(
2847+
mockAccount.id,
2848+
newAccountName,
2849+
);
2850+
2851+
expect(
2852+
accountsController.getAccountExpect(mockAccount.id).metadata
2853+
.nameLastUpdatedAt,
2854+
).toBe(expectedTimestamp);
2855+
});
2856+
2857+
it('publishes the accountRenamed event', () => {
2858+
const { accountsController, messenger } =
2859+
setupAccountsController(mockState);
2860+
2861+
const messengerSpy = jest.spyOn(messenger, 'publish');
2862+
2863+
accountsController.setAccountNameAndSelectAccount(
2864+
mockAccount.id,
2865+
newAccountName,
2866+
);
2867+
2868+
expect(messengerSpy).toHaveBeenCalledWith(
2869+
'AccountsController:accountRenamed',
2870+
accountsController.getAccountExpect(mockAccount.id),
2871+
);
2872+
});
2873+
2874+
it('throw an error if the account name already exists', () => {
2875+
const { accountsController } = setupAccountsController({
2876+
initialState: {
2877+
internalAccounts: {
2878+
accounts: {
2879+
[mockAccount.id]: mockAccount,
2880+
[mockAccount2.id]: mockAccount2,
2881+
},
2882+
selectedAccount: mockAccount.id,
2883+
},
2884+
},
2885+
});
2886+
2887+
expect(() =>
2888+
accountsController.setAccountNameAndSelectAccount(
2889+
mockAccount.id,
2890+
mockAccount2.metadata.name,
2891+
),
2892+
).toThrow('Account name already exists');
2893+
});
2894+
});
2895+
27862896
describe('setAccountName', () => {
27872897
it('sets the name of an existing account', () => {
27882898
const { accountsController } = setupAccountsController({
@@ -3097,6 +3207,10 @@ describe('AccountsController', () => {
30973207
jest.spyOn(AccountsController.prototype, 'getAccountByAddress');
30983208
jest.spyOn(AccountsController.prototype, 'getSelectedAccount');
30993209
jest.spyOn(AccountsController.prototype, 'getAccount');
3210+
jest.spyOn(
3211+
AccountsController.prototype,
3212+
'setAccountNameAndSelectAccount',
3213+
);
31003214
});
31013215

31023216
describe('setSelectedAccount', () => {
@@ -3206,6 +3320,37 @@ describe('AccountsController', () => {
32063320
});
32073321
});
32083322

3323+
describe('setAccountNameAndSelectAccount', () => {
3324+
it('set the account name and select the account', async () => {
3325+
const messenger = buildMessenger();
3326+
const { accountsController } = setupAccountsController({
3327+
initialState: {
3328+
internalAccounts: {
3329+
accounts: {
3330+
[mockAccount.id]: mockAccount,
3331+
[mockAccount2.id]: mockAccount2,
3332+
},
3333+
selectedAccount: mockAccount.id,
3334+
},
3335+
},
3336+
messenger,
3337+
});
3338+
3339+
const newAccountName = 'New Account Name';
3340+
messenger.call(
3341+
'AccountsController:setAccountNameAndSelectAccount',
3342+
mockAccount2.id,
3343+
newAccountName,
3344+
);
3345+
expect(
3346+
accountsController.setAccountNameAndSelectAccount,
3347+
).toHaveBeenCalledWith(mockAccount2.id, newAccountName);
3348+
expect(accountsController.state.internalAccounts.selectedAccount).toBe(
3349+
mockAccount2.id,
3350+
);
3351+
});
3352+
});
3353+
32093354
describe('updateAccounts', () => {
32103355
it('update accounts', async () => {
32113356
const messenger = buildMessenger();

packages/accounts-controller/src/AccountsController.ts

+64-9
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ export type AccountsControllerSetAccountNameAction = {
7171
handler: AccountsController['setAccountName'];
7272
};
7373

74+
export type AccountsControllerSetAccountNameAndSelectAccountAction = {
75+
type: `${typeof controllerName}:setAccountNameAndSelectAccount`;
76+
handler: AccountsController['setAccountNameAndSelectAccount'];
77+
};
78+
7479
export type AccountsControllerListAccountsAction = {
7580
type: `${typeof controllerName}:listAccounts`;
7681
handler: AccountsController['listAccounts'];
@@ -126,6 +131,7 @@ export type AccountsControllerActions =
126131
| AccountsControllerListAccountsAction
127132
| AccountsControllerListMultichainAccountsAction
128133
| AccountsControllerSetAccountNameAction
134+
| AccountsControllerSetAccountNameAndSelectAccountAction
129135
| AccountsControllerUpdateAccountsAction
130136
| AccountsControllerGetAccountByAddressAction
131137
| AccountsControllerGetSelectedAccountAction
@@ -439,6 +445,57 @@ export class AccountsController extends BaseController<
439445
});
440446
}
441447

448+
/**
449+
* Sets the name of the account with the given ID and select it.
450+
*
451+
* @param accountId - The ID of the account to set the name for and select.
452+
* @param accountName - The new name for the account.
453+
* @throws An error if an account with the same name already exists.
454+
*/
455+
setAccountNameAndSelectAccount(accountId: string, accountName: string): void {
456+
const account = this.getAccountExpect(accountId);
457+
458+
this.#assertAccountCanBeRenamed(account, accountName);
459+
460+
const internalAccount = {
461+
...account,
462+
metadata: {
463+
...account.metadata,
464+
name: accountName,
465+
nameLastUpdatedAt: Date.now(),
466+
lastSelected: this.#getLastSelectedIndex(),
467+
},
468+
};
469+
470+
this.#update((state) => {
471+
// FIXME: Using the state as-is cause the following error: "Type instantiation is excessively
472+
// deep and possibly infinite.ts(2589)" (https://github.com/MetaMask/utils/issues/168)
473+
// Using a type-cast workaround this error and is slightly better than using a @ts-expect-error
474+
// which sometimes fail when compiling locally.
475+
(state as AccountsControllerState).internalAccounts.accounts[account.id] =
476+
internalAccount;
477+
(state as AccountsControllerState).internalAccounts.selectedAccount =
478+
account.id;
479+
});
480+
481+
this.messagingSystem.publish(
482+
'AccountsController:accountRenamed',
483+
internalAccount,
484+
);
485+
}
486+
487+
#assertAccountCanBeRenamed(account: InternalAccount, accountName: string) {
488+
if (
489+
this.listMultichainAccounts().find(
490+
(internalAccount) =>
491+
internalAccount.metadata.name === accountName &&
492+
internalAccount.id !== account.id,
493+
)
494+
) {
495+
throw new Error('Account name already exists');
496+
}
497+
}
498+
442499
/**
443500
* Updates the metadata of the account with the given ID.
444501
*
@@ -451,15 +508,8 @@ export class AccountsController extends BaseController<
451508
): void {
452509
const account = this.getAccountExpect(accountId);
453510

454-
if (
455-
metadata.name &&
456-
this.listMultichainAccounts().find(
457-
(internalAccount) =>
458-
internalAccount.metadata.name === metadata.name &&
459-
internalAccount.id !== accountId,
460-
)
461-
) {
462-
throw new Error('Account name already exists');
511+
if (metadata.name) {
512+
this.#assertAccountCanBeRenamed(account, metadata.name);
463513
}
464514

465515
const internalAccount = {
@@ -1215,6 +1265,11 @@ export class AccountsController extends BaseController<
12151265
this.setAccountName.bind(this),
12161266
);
12171267

1268+
this.messagingSystem.registerActionHandler(
1269+
`${controllerName}:setAccountNameAndSelectAccount`,
1270+
this.setAccountNameAndSelectAccount.bind(this),
1271+
);
1272+
12181273
this.messagingSystem.registerActionHandler(
12191274
`${controllerName}:updateAccounts`,
12201275
this.updateAccounts.bind(this),

packages/accounts-controller/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export type {
44
AccountsControllerGetStateAction,
55
AccountsControllerSetSelectedAccountAction,
66
AccountsControllerSetAccountNameAction,
7+
AccountsControllerSetAccountNameAndSelectAccountAction,
78
AccountsControllerListAccountsAction,
89
AccountsControllerListMultichainAccountsAction,
910
AccountsControllerUpdateAccountsAction,

packages/address-book-controller/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Changed
1111

12+
- Bump `@metamask/base-controller` from ^8.0.0 to ^8.0.1 ([#5722](https://github.com/MetaMask/core/pull/5722))
1213
- Bump `@metamask/controller-utils` to `^11.7.0` ([#5583](https://github.com/MetaMask/core/pull/5583))
1314

1415
## [6.0.3]

packages/address-book-controller/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch"
4848
},
4949
"dependencies": {
50-
"@metamask/base-controller": "^8.0.0",
50+
"@metamask/base-controller": "^8.0.1",
5151
"@metamask/controller-utils": "^11.7.0",
5252
"@metamask/utils": "^11.2.0"
5353
},

0 commit comments

Comments
 (0)