From 030f7680f9aa40ae02eaa8ebac71638a27ec29e7 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Tue, 25 Jul 2023 16:14:40 +0800 Subject: [PATCH 001/235] feat: accounts controller --- .../controllers/accounts-controller.ts | 199 ++++++++++++++++++ app/scripts/metamask-controller.js | 26 +++ 2 files changed, 225 insertions(+) create mode 100644 app/scripts/controllers/accounts-controller.ts diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts new file mode 100644 index 000000000000..e3ed1d59d661 --- /dev/null +++ b/app/scripts/controllers/accounts-controller.ts @@ -0,0 +1,199 @@ +import { + BaseControllerV2, + RestrictedControllerMessenger, +} from '@metamask/base-controller'; +import { Patch } from 'immer'; +import { v4 as uuid } from 'uuid'; +import { InternalAccount, SnapKeyring } from '@metamask/eth-snap-keyring'; +import { KeyringController } from '@metamask/eth-keyring-controller'; +import { SnapControllerEvents } from '@metamask/snaps-controllers'; +import PreferencesController from './preferences'; + +const controllerName = 'AccountsController'; + +export type AccountsControllerState = { + internalAccounts: Record; + selectedAccount: InternalAccount; +}; + +export type AccountsControllerGetStateAction = { + type: `${typeof controllerName}:getState`; + handler: () => AccountsControllerState; +}; + +export type AccountsControllerActions = AccountsControllerGetStateAction; + +export type AccountsControllerChangeEvent = { + type: `${typeof controllerName}:stateChange`; + payload: [AccountsControllerState, Patch[]]; +}; + +export type AccountsControllerEvents = + | AccountsControllerChangeEvent + | SnapControllerEvents; + +export type AccountsControllerMessenger = RestrictedControllerMessenger< + typeof controllerName, + AccountsControllerActions, + AccountsControllerEvents, + string, + string +>; + +const accountsControllerMetadata = { + internalAccounts: { + persist: true, + anonymous: false, + }, + selectedAccount: { + persist: true, + anonymous: false, + }, +}; + +export default class AccountsController extends BaseControllerV2< + typeof controllerName, + AccountsControllerState, + AccountsControllerMessenger +> { + #preferenceController: PreferencesController; + + #keyringController: any; + + constructor({ + messenger, + state, + preferenceController, + keyringController, + onPreferencesStateChange, + }: { + messenger: AccountsControllerMessenger; + state: AccountsControllerState; + preferenceController: PreferencesController; + keyringController: KeyringController; + onPreferencesStateChange: ( + listener: (preferencesState: any) => void, + ) => void; + }) { + super({ + messenger, + name: controllerName, + metadata: accountsControllerMetadata, + state, + }); + + this.#preferenceController = preferenceController; + this.#keyringController = keyringController; + + this.messagingSystem.subscribe( + 'SnapController:stateChange', + async (snapState) => { + console.log('snap state changed', snapState); + }, + ); + + onPreferencesStateChange((preferenceState) => { + console.log('preference state changed', preferenceState); + const { selectedAddress } = preferenceState; + console.log('selected address', selectedAddress); + }); + } + + getAccount(address: string): InternalAccount | undefined { + return Object.values(this.state.internalAccounts).find( + (internalAccount) => + internalAccount.address.toLowerCase() === address.toLowerCase(), + ); + } + + getAccountExpect(address: string): InternalAccount { + const account = this.getAccount(address); + if (account === undefined) { + throw new Error(`Account ${address} not found`); + } + return account; + } + + getAccountId(accountId: string): InternalAccount | undefined { + return this.state.internalAccounts[accountId]; + } + + getAccountByIdExpect(accountId: string): InternalAccount { + const account = this.getAccount(accountId); + if (account === undefined) { + throw new Error(`Account Id ${accountId} not found`); + } + return account; + } + + getAccountsByKeyring(keyring: string): InternalAccount[] { + return Object.values(this.state.internalAccounts).filter( + (internalAccount) => internalAccount.type === keyring, + ); + } + + getAccountsBySnapId(snapId: string): InternalAccount[] { + return Object.values(this.state.internalAccounts).filter( + (internalAccount) => internalAccount.metadata.snap?.id === snapId, + ); + } + + async updateAccounts(): Promise { + const legacyAccounts = await this.#listLegacyAccounts(); + const snapAccounts = await this.#listSnapAccounts(); + + const internalAccounts: Record = [ + ...legacyAccounts, + ...snapAccounts, + ].reduce((internalAccountMap, internalAccount) => { + internalAccountMap[internalAccount.id] = internalAccount; + return internalAccountMap; + }, {} as Record); + + this.update((accountsControllerState: AccountsControllerState) => { + accountsControllerState.internalAccounts = internalAccounts; + }); + } + + async #listSnapAccounts(): Promise { + const [snapKeyring]: [SnapKeyring] = + this.#keyringController.getKeyringsByType(SnapKeyring.type); + + return snapKeyring?.listAccounts(true) ?? []; + } + + async #listLegacyAccounts(): Promise { + const addresses = await this.#keyringController.getAccounts(); + return addresses.map((address: string) => { + return { + id: uuid(), + address, + name: '', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + metadata: {}, + }; + }); + } + + setSelectedAccount(accountId: string): InternalAccount { + const account = this.getAccountByIdExpect(accountId); + + this.update((state) => { + state.selectedAccount = account; + }); + + return account; + } +} diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index f0e87fd6c2ea..a3edc92825ae 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -62,6 +62,8 @@ import { ///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) import { SnapKeyring } from '@metamask/eth-snap-keyring'; +// eslint-disable-next-line import/order +import AccountsController from './controllers/accounts-controller'; ///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) @@ -1009,6 +1011,19 @@ export default class MetamaskController extends EventEmitter { }, }); + const accountsControllerMessenger = this.controllerMessenger.getRestricted({ + name: 'AccountsController', + allowedEvents: ['SnapController:stateChange'], + }); + + this.accountsController = new AccountsController({ + messenger: accountsControllerMessenger, + state: initState.accountsController, + onPreferencesStateChange: (listener) => { + this.preferencesController.store.subscribe(listener); + }, + }); + this.notificationController = new NotificationController({ messenger: this.controllerMessenger.getRestricted({ name: 'NotificationController', @@ -1671,6 +1686,9 @@ export default class MetamaskController extends EventEmitter { this.memStore = new ComposableObservableStore({ config: { AppStateController: this.appStateController.store, + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) + AccountsController: this.accountsController, + ///: END:ONLY_INCLUDE_IN NetworkController: this.networkController, CachedBalancesController: this.cachedBalancesController.store, KeyringController: this.keyringController.memStore, @@ -2964,6 +2982,10 @@ export default class MetamaskController extends EventEmitter { this.preferencesController.getLedgerTransportPreference(); this.setLedgerTransportPreference(transportPreference); + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) + await this.accountsController.updateAccounts(); + ///: END:ONLY_INCLUDE_IN + // set new identities this.preferencesController.setAddresses(accounts); this.selectFirstIdentity(); @@ -3029,6 +3051,10 @@ export default class MetamaskController extends EventEmitter { this.setLedgerTransportPreference(transportPreference); + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) + await this.accountsController.updateAccounts(); + ///: END:ONLY_INCLUDE_IN + return this.keyringController.fullUpdate(); } From 9808d94c3fa6edcc1bd9eb6a5c8b2d1afafc113f Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Tue, 25 Jul 2023 17:55:43 +0800 Subject: [PATCH 002/235] feat: add setLabel and update setSelectedAccount to be id instead of internal account --- .../controllers/accounts-controller.ts | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index e3ed1d59d661..15f05b61d11d 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -13,7 +13,7 @@ const controllerName = 'AccountsController'; export type AccountsControllerState = { internalAccounts: Record; - selectedAccount: InternalAccount; + selectedAccount: string; // id of the selected account }; export type AccountsControllerGetStateAction = { @@ -142,16 +142,16 @@ export default class AccountsController extends BaseControllerV2< const legacyAccounts = await this.#listLegacyAccounts(); const snapAccounts = await this.#listSnapAccounts(); - const internalAccounts: Record = [ - ...legacyAccounts, - ...snapAccounts, - ].reduce((internalAccountMap, internalAccount) => { - internalAccountMap[internalAccount.id] = internalAccount; - return internalAccountMap; - }, {} as Record); + const internalAccounts = [...legacyAccounts, ...snapAccounts].reduce( + (internalAccountMap, internalAccount) => { + internalAccountMap[internalAccount.id] = internalAccount; + return internalAccountMap; + }, + {} as Record, + ); - this.update((accountsControllerState: AccountsControllerState) => { - accountsControllerState.internalAccounts = internalAccounts; + this.update((currentState: AccountsControllerState) => { + currentState.internalAccounts = internalAccounts; }); } @@ -190,10 +190,21 @@ export default class AccountsController extends BaseControllerV2< setSelectedAccount(accountId: string): InternalAccount { const account = this.getAccountByIdExpect(accountId); - this.update((state) => { - state.selectedAccount = account; + this.update((currentState: AccountsControllerState) => { + currentState.selectedAccount = account.id; }); return account; } + + setLabel(accountId: string, label: string): void { + const account = this.getAccountByIdExpect(accountId); + + this.update((currentState: AccountsControllerState) => { + currentState.internalAccounts[accountId] = { + ...account, + name: label, + }; + }); + } } From e9f635f3b80f491f42a9463e11af2a3b8583bedd Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Wed, 26 Jul 2023 13:06:35 +0800 Subject: [PATCH 003/235] feat: use dev version of snaps keyring --- package.json | 2 +- yarn.lock | 178 +++++++++++++++++++++++++-------------------------- 2 files changed, 90 insertions(+), 90 deletions(-) diff --git a/package.json b/package.json index 4e9ae618c843..27464cc91ca0 100644 --- a/package.json +++ b/package.json @@ -241,7 +241,7 @@ "@metamask/eth-json-rpc-middleware": "^11.0.0", "@metamask/eth-keyring-controller": "^10.0.1", "@metamask/eth-ledger-bridge-keyring": "^0.15.0", - "@metamask/eth-snap-keyring": "^0.1.3", + "@metamask/eth-snap-keyring": "git+https://github.com/MetaMask/eth-snap-keyring.git#commit=60130ddcfd8f4e9a1e0de299f6798dfd966f9634", "@metamask/eth-token-tracker": "^4.0.0", "@metamask/eth-trezor-keyring": "^1.0.0", "@metamask/etherscan-link": "^2.2.0", diff --git a/yarn.lock b/yarn.lock index a52ac8daae1d..879f05c47fb1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4171,19 +4171,19 @@ __metadata: languageName: node linkType: hard -"@metamask/eth-snap-keyring@npm:^0.1.3": +"@metamask/eth-snap-keyring@git+https://github.com/MetaMask/eth-snap-keyring.git#commit=60130ddcfd8f4e9a1e0de299f6798dfd966f9634": version: 0.1.3 - resolution: "@metamask/eth-snap-keyring@npm:0.1.3" + resolution: "@metamask/eth-snap-keyring@https://github.com/MetaMask/eth-snap-keyring.git#commit=60130ddcfd8f4e9a1e0de299f6798dfd966f9634" dependencies: - "@ethereumjs/tx": "npm:^4.1.2" - "@metamask/eth-sig-util": "npm:^5.1.0" - "@metamask/keyring-api": "npm:^0.1.3" - "@metamask/snaps-controllers": "npm:^0.35.2-flask.1" - "@metamask/utils": "npm:^6.1.0" - "@types/uuid": "npm:^9.0.1" - superstruct: "npm:^1.0.3" - uuid: "npm:^9.0.0" - checksum: df426fca165d3b22347324a4b17cefa8fc86dd3ef669ab054233c168437f567f77992b69633ec13a1d8c5b77701ba2df25b68fba246cd46ee14f97072f0ac1a6 + "@ethereumjs/tx": ^4.1.2 + "@metamask/eth-sig-util": ^5.1.0 + "@metamask/keyring-api": ^0.1.3 + "@metamask/snaps-controllers": ^0.35.2-flask.1 + "@metamask/utils": ^6.1.0 + "@types/uuid": ^9.0.1 + superstruct: ^1.0.3 + uuid: ^9.0.0 + checksum: f77cb75fcbd05024693488c42d244f78e7ee87f3f295ac95971182a78f1399428acc5f10aaf6d6ba08fa28cc3519d4e644226ac7cdf22e77a8659f945d9686ce languageName: node linkType: hard @@ -24192,84 +24192,84 @@ __metadata: version: 0.0.0-use.local resolution: "metamask-crx@workspace:." dependencies: - "@actions/core": "npm:^1.10.0" - "@actions/github": "npm:^5.1.1" - "@babel/code-frame": "npm:^7.12.13" - "@babel/core": "npm:^7.21.5" - "@babel/eslint-parser": "npm:^7.13.14" - "@babel/eslint-plugin": "npm:^7.12.1" - "@babel/preset-env": "npm:^7.5.5" - "@babel/preset-react": "npm:^7.0.0" - "@babel/preset-typescript": "npm:^7.16.7" - "@babel/register": "npm:^7.5.5" - "@babel/runtime": "npm:^7.18.9" - "@blockaid/ppom": "npm:^0.1.2" - "@download/blockies": "npm:^1.0.3" - "@ensdomains/content-hash": "npm:^2.5.6" - "@ethereumjs/common": "npm:^3.1.1" - "@ethereumjs/tx": "npm:^4.1.1" - "@ethersproject/abi": "npm:^5.6.4" - "@ethersproject/bignumber": "npm:^5.7.0" - "@ethersproject/contracts": "npm:^5.7.0" - "@ethersproject/hdnode": "npm:^5.6.2" - "@ethersproject/providers": "npm:^5.7.2" - "@fortawesome/fontawesome-free": "npm:^5.13.0" - "@keystonehq/bc-ur-registry-eth": "npm:^0.19.1" - "@keystonehq/metamask-airgapped-keyring": "npm:^0.13.1" - "@lavamoat/allow-scripts": "npm:^2.3.1" - "@lavamoat/lavapack": "npm:^5.2.0" - "@lavamoat/snow": "npm:^1.5.0" - "@material-ui/core": "npm:^4.11.0" - "@metamask-institutional/custody-controller": "npm:0.2.6" - "@metamask-institutional/custody-keyring": "npm:^0.0.25" - "@metamask-institutional/extension": "npm:^0.2.1" - "@metamask-institutional/institutional-features": "npm:^1.1.8" - "@metamask-institutional/portfolio-dashboard": "npm:^1.1.3" - "@metamask-institutional/rpc-allowlist": "npm:^1.0.0" - "@metamask-institutional/sdk": "npm:^0.1.17" - "@metamask-institutional/transaction-update": "npm:^0.1.21" - "@metamask/address-book-controller": "npm:^3.0.0" - "@metamask/announcement-controller": "npm:^4.0.0" - "@metamask/approval-controller": "npm:^3.4.0" - "@metamask/assets-controllers": "npm:^9.2.0" - "@metamask/auto-changelog": "npm:^2.1.0" - "@metamask/base-controller": "npm:^3.2.0" - "@metamask/browser-passworder": "npm:^4.1.0" - "@metamask/contract-metadata": "npm:^2.3.1" - "@metamask/controller-utils": "npm:^4.2.0" - "@metamask/design-tokens": "npm:^1.12.0" - "@metamask/desktop": "npm:^0.3.0" - "@metamask/eslint-config": "npm:^9.0.0" - "@metamask/eslint-config-jest": "npm:^9.0.0" - "@metamask/eslint-config-mocha": "npm:^9.0.0" - "@metamask/eslint-config-nodejs": "npm:^9.0.0" - "@metamask/eslint-config-typescript": "npm:^9.0.1" - "@metamask/eth-json-rpc-middleware": "npm:^11.0.0" - "@metamask/eth-keyring-controller": "npm:^10.0.1" - "@metamask/eth-ledger-bridge-keyring": "npm:^0.15.0" - "@metamask/eth-snap-keyring": "npm:^0.1.3" - "@metamask/eth-token-tracker": "npm:^4.0.0" - "@metamask/eth-trezor-keyring": "npm:^1.0.0" - "@metamask/etherscan-link": "npm:^2.2.0" - "@metamask/forwarder": "npm:^1.1.0" - "@metamask/gas-fee-controller": "npm:^6.0.1" - "@metamask/jazzicon": "npm:^2.0.0" - "@metamask/key-tree": "npm:^9.0.0" - "@metamask/keyring-controller": "npm:^7.0.0" - "@metamask/logo": "npm:^3.1.1" - "@metamask/message-manager": "npm:^7.0.2" - "@metamask/metamask-eth-abis": "npm:^3.0.0" - "@metamask/network-controller": "npm:^11.0.0" - "@metamask/notification-controller": "npm:^3.0.0" - "@metamask/obs-store": "npm:^8.1.0" - "@metamask/permission-controller": "npm:^4.0.0" - "@metamask/phishing-controller": "npm:^6.0.0" - "@metamask/phishing-warning": "npm:^2.1.0" - "@metamask/post-message-stream": "npm:^6.0.0" - "@metamask/ppom-validator": "npm:^0.1.2" - "@metamask/providers": "npm:^11.1.0" - "@metamask/rate-limit-controller": "npm:^3.0.0" - "@metamask/rpc-methods": "npm:^1.0.0-prerelease.1" + "@actions/core": ^1.10.0 + "@actions/github": ^5.1.1 + "@babel/code-frame": ^7.12.13 + "@babel/core": ^7.21.5 + "@babel/eslint-parser": ^7.13.14 + "@babel/eslint-plugin": ^7.12.1 + "@babel/preset-env": ^7.5.5 + "@babel/preset-react": ^7.0.0 + "@babel/preset-typescript": ^7.16.7 + "@babel/register": ^7.5.5 + "@babel/runtime": ^7.18.9 + "@blockaid/ppom": ^0.1.2 + "@download/blockies": ^1.0.3 + "@ensdomains/content-hash": ^2.5.6 + "@ethereumjs/common": ^3.1.1 + "@ethereumjs/tx": ^4.1.1 + "@ethersproject/abi": ^5.6.4 + "@ethersproject/bignumber": ^5.7.0 + "@ethersproject/contracts": ^5.7.0 + "@ethersproject/hdnode": ^5.6.2 + "@ethersproject/providers": ^5.7.2 + "@fortawesome/fontawesome-free": ^5.13.0 + "@keystonehq/bc-ur-registry-eth": ^0.19.1 + "@keystonehq/metamask-airgapped-keyring": ^0.13.1 + "@lavamoat/allow-scripts": ^2.3.1 + "@lavamoat/lavapack": ^5.2.0 + "@lavamoat/snow": ^1.5.0 + "@material-ui/core": ^4.11.0 + "@metamask-institutional/custody-controller": 0.2.6 + "@metamask-institutional/custody-keyring": ^0.0.25 + "@metamask-institutional/extension": ^0.2.1 + "@metamask-institutional/institutional-features": ^1.1.8 + "@metamask-institutional/portfolio-dashboard": ^1.1.3 + "@metamask-institutional/rpc-allowlist": ^1.0.0 + "@metamask-institutional/sdk": ^0.1.17 + "@metamask-institutional/transaction-update": ^0.1.21 + "@metamask/address-book-controller": ^3.0.0 + "@metamask/announcement-controller": ^4.0.0 + "@metamask/approval-controller": ^3.4.0 + "@metamask/assets-controllers": ^9.2.0 + "@metamask/auto-changelog": ^2.1.0 + "@metamask/base-controller": ^3.2.0 + "@metamask/browser-passworder": ^4.1.0 + "@metamask/contract-metadata": ^2.3.1 + "@metamask/controller-utils": ^4.2.0 + "@metamask/design-tokens": ^1.12.0 + "@metamask/desktop": ^0.3.0 + "@metamask/eslint-config": ^9.0.0 + "@metamask/eslint-config-jest": ^9.0.0 + "@metamask/eslint-config-mocha": ^9.0.0 + "@metamask/eslint-config-nodejs": ^9.0.0 + "@metamask/eslint-config-typescript": ^9.0.1 + "@metamask/eth-json-rpc-middleware": ^11.0.0 + "@metamask/eth-keyring-controller": ^10.0.1 + "@metamask/eth-ledger-bridge-keyring": ^0.15.0 + "@metamask/eth-snap-keyring": ^0.1.3 + "@metamask/eth-token-tracker": ^4.0.0 + "@metamask/eth-trezor-keyring": ^1.0.0 + "@metamask/etherscan-link": ^2.2.0 + "@metamask/forwarder": ^1.1.0 + "@metamask/gas-fee-controller": ^6.0.1 + "@metamask/jazzicon": ^2.0.0 + "@metamask/key-tree": ^9.0.0 + "@metamask/keyring-controller": ^7.0.0 + "@metamask/logo": ^3.1.1 + "@metamask/message-manager": ^7.0.2 + "@metamask/metamask-eth-abis": ^3.0.0 + "@metamask/network-controller": ^10.3.1 + "@metamask/notification-controller": ^3.0.0 + "@metamask/obs-store": ^8.1.0 + "@metamask/permission-controller": ^4.0.0 + "@metamask/phishing-controller": ^6.0.0 + "@metamask/phishing-warning": ^2.1.0 + "@metamask/post-message-stream": ^6.0.0 + "@metamask/ppom-validator": ^0.1.2 + "@metamask/providers": ^11.1.0 + "@metamask/rate-limit-controller": ^3.0.0 + "@metamask/rpc-methods": ^1.0.0-prerelease.1 "@metamask/rpc-methods-flask": "npm:@metamask/rpc-methods@0.37.2-flask.1" "@metamask/safe-event-emitter": "npm:^2.0.0" "@metamask/scure-bip39": "npm:^2.0.3" From 4a2390b13d16d87285eb5c99ef08d7c892345abe Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Wed, 26 Jul 2023 13:07:13 +0800 Subject: [PATCH 004/235] feat: update listeners and initialize selectedAccount from selectedAddress in the preference controller --- .../controllers/accounts-controller.ts | 184 ++++++++++++++---- app/scripts/metamask-controller.js | 41 +++- 2 files changed, 182 insertions(+), 43 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index 15f05b61d11d..1f6efce6881e 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -4,10 +4,18 @@ import { } from '@metamask/base-controller'; import { Patch } from 'immer'; import { v4 as uuid } from 'uuid'; +import { sha256FromString } from 'ethereumjs-util'; import { InternalAccount, SnapKeyring } from '@metamask/eth-snap-keyring'; -import { KeyringController } from '@metamask/eth-keyring-controller'; -import { SnapControllerEvents } from '@metamask/snaps-controllers'; -import PreferencesController from './preferences'; +import { + SnapController, + SnapControllerEvents, +} from '@metamask/snaps-controllers'; +import { + KeyringControllerState, + KeyringController, +} from '@metamask/keyring-controller'; +import { SnapControllerState } from '@metamask/snaps-controllers-flask'; +import { add0x } from '@metamask/utils'; const controllerName = 'AccountsController'; @@ -51,51 +59,75 @@ const accountsControllerMetadata = { }, }; +const defaultState: AccountsControllerState = { + internalAccounts: {}, + selectedAccount: '', +}; + export default class AccountsController extends BaseControllerV2< typeof controllerName, AccountsControllerState, AccountsControllerMessenger > { - #preferenceController: PreferencesController; + #keyringController: KeyringController; - #keyringController: any; + #snapController: SnapController; constructor({ messenger, state, - preferenceController, keyringController, - onPreferencesStateChange, + snapController, + onKeyringStateChange, + onKeyringAccountRemoved, + onSnapStateChange, }: { messenger: AccountsControllerMessenger; state: AccountsControllerState; - preferenceController: PreferencesController; keyringController: KeyringController; - onPreferencesStateChange: ( - listener: (preferencesState: any) => void, + snapController: SnapController; + onKeyringStateChange: ( + listener: (keyringState: KeyringControllerState) => void, + ) => void; + onKeyringAccountRemoved: (listener: (address: string) => void) => void; + onSnapStateChange: ( + listener: (snapState: SnapControllerState) => void, ) => void; }) { super({ messenger, name: controllerName, metadata: accountsControllerMetadata, - state, + state: { + ...defaultState, + ...state, + }, }); - this.#preferenceController = preferenceController; this.#keyringController = keyringController; + this.#snapController = snapController; - this.messagingSystem.subscribe( - 'SnapController:stateChange', - async (snapState) => { - console.log('snap state changed', snapState); - }, - ); + onSnapStateChange(async (snapState: SnapControllerState) => { + console.log('snap state changed', snapState); + const { snaps } = snapState; + + Object.values(snaps) + .filter((snap) => !snap.enabled || snap.blocked) + .forEach((disabledSnap) => { + this.#disableSnap(disabledSnap.id); + }); + + await this.updateAccounts(); + }); - onPreferencesStateChange((preferenceState) => { - console.log('preference state changed', preferenceState); - const { selectedAddress } = preferenceState; - console.log('selected address', selectedAddress); + onKeyringStateChange(async (keyringState: KeyringControllerState) => { + console.log('keyring state changed', keyringState); + await this.updateAccounts(); + }); + + onKeyringAccountRemoved(async (address: string) => { + console.log('keyring account removed', address); + await this.updateAccounts(); }); } @@ -119,7 +151,7 @@ export default class AccountsController extends BaseControllerV2< } getAccountByIdExpect(accountId: string): InternalAccount { - const account = this.getAccount(accountId); + const account = this.getAccountId(accountId); if (account === undefined) { throw new Error(`Account Id ${accountId} not found`); } @@ -142,9 +174,14 @@ export default class AccountsController extends BaseControllerV2< const legacyAccounts = await this.#listLegacyAccounts(); const snapAccounts = await this.#listSnapAccounts(); + console.log('legacy accounts', legacyAccounts); + console.log('snap accounts', snapAccounts); + const internalAccounts = [...legacyAccounts, ...snapAccounts].reduce( (internalAccountMap, internalAccount) => { - internalAccountMap[internalAccount.id] = internalAccount; + internalAccountMap[internalAccount.id] = { + ...internalAccount, + }; return internalAccountMap; }, {} as Record, @@ -153,22 +190,64 @@ export default class AccountsController extends BaseControllerV2< this.update((currentState: AccountsControllerState) => { currentState.internalAccounts = internalAccounts; }); + + console.log('updated state', this.state); + } + + removeAccountByAddress(address: string): void { + const account = this.getAccount(address); + if (account) { + this.update((currentState: AccountsControllerState) => { + delete currentState.internalAccounts[account.id]; + }); + } + + // this.update((currentState: AccountsControllerState) => { + // currentState.internalAccounts + // } } async #listSnapAccounts(): Promise { - const [snapKeyring]: [SnapKeyring] = - this.#keyringController.getKeyringsByType(SnapKeyring.type); + const [snapKeyring] = this.#keyringController.getKeyringsByType( + SnapKeyring.type, + ); + + const snapAccounts = + (await (snapKeyring as SnapKeyring)?.listAccounts(true)) ?? []; - return snapKeyring?.listAccounts(true) ?? []; + for (const account of snapAccounts) { + account.metadata = { + snap: { + id: account?.metadata?.snap?.id, + enabled: await this.#getSnapStatus( + account?.metadata?.snap?.id as string, + ), + name: account.name, + }, + keyring: { + type: (snapKeyring as SnapKeyring).type, + }, + }; + } + + return snapAccounts; } async #listLegacyAccounts(): Promise { const addresses = await this.#keyringController.getAccounts(); - return addresses.map((address: string) => { - return { - id: uuid(), + const internalAccounts = []; + for (const address of addresses) { + const keyring = await this.#keyringController.getKeyringForAccount( + address, + ); + // TODO: this is done until the keyrings all implement the InternalAccount interface + const v4options = { + random: sha256FromString(address).slice(0, 16), + }; + + internalAccounts.push({ + id: uuid(v4options), address, - name: '', options: {}, supportedMethods: [ 'personal_sign', @@ -182,29 +261,56 @@ export default class AccountsController extends BaseControllerV2< 'eth_signTypedData_v4', ], type: 'eip155:eoa', - metadata: {}, - }; - }); + metadata: { + keyring: keyring.type as string, + }, + }); + } + + return internalAccounts.filter( + (account) => account.metadata.keyring !== 'Snap Keyring', + ); } - setSelectedAccount(accountId: string): InternalAccount { + setSelectedAccount(accountId: string): void { const account = this.getAccountByIdExpect(accountId); this.update((currentState: AccountsControllerState) => { currentState.selectedAccount = account.id; }); - - return account; } - setLabel(accountId: string, label: string): void { + setAccountName(accountId: string, accountName: string): void { const account = this.getAccountByIdExpect(accountId); this.update((currentState: AccountsControllerState) => { currentState.internalAccounts[accountId] = { ...account, - name: label, + name: accountName, }; }); } + + #disableSnap(snapId: string) { + const accounts = this.getAccountsBySnapId(snapId); + + this.update((currentState: AccountsControllerState) => { + accounts.forEach((account) => { + account.metadata.snap = { + ...account.metadata.snap, + enabled: false, + }; + currentState.internalAccounts[account.id] = account; + }); + }); + } + + async #getSnapStatus(snapId: string): Promise { + const snap = await this.#snapController.getSnapState(snapId); + if (!snap) { + return false; + } + + return snap?.enabled && !snap?.blocked; + } } diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index a3edc92825ae..0ab77d65778f 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -19,6 +19,7 @@ import LatticeKeyring from 'eth-lattice-keyring'; import { MetaMaskKeyring as QRHardwareKeyring } from '@keystonehq/metamask-airgapped-keyring'; import EthQuery from 'eth-query'; import nanoid from 'nanoid'; +import { v4 as uuid } from 'uuid'; import { captureException } from '@sentry/browser'; import { AddressBookController } from '@metamask/address-book-controller'; import { @@ -221,6 +222,7 @@ import { securityProviderCheck } from './lib/security-provider-helpers'; import { IndexedDBPPOMStorage } from './lib/ppom/indexed-db-backend'; ///: END:ONLY_INCLUDE_IN import { updateCurrentLocale } from './translate'; +import { sha256FromString } from 'ethereumjs-util'; export const METAMASK_CONTROLLER_EVENTS = { // Fired after state changes that impact the extension badge (unapproved msg count) @@ -1013,15 +1015,30 @@ export default class MetamaskController extends EventEmitter { const accountsControllerMessenger = this.controllerMessenger.getRestricted({ name: 'AccountsController', - allowedEvents: ['SnapController:stateChange'], + allowedEvents: [ + 'SnapController:stateChange', + 'KeyringController:accountRemoved', + 'KeyringController:stateChange', + ], }); this.accountsController = new AccountsController({ messenger: accountsControllerMessenger, state: initState.accountsController, - onPreferencesStateChange: (listener) => { - this.preferencesController.store.subscribe(listener); - }, + keyringController: this.keyringController, + snapController: this.snapController, + onKeyringAccountRemoved: keyringControllerMessenger.subscribe.bind( + keyringControllerMessenger, + 'KeyringController:accountRemoved', + ), + onKeyringStateChange: keyringControllerMessenger.subscribe.bind( + keyringControllerMessenger, + 'KeyringController:stateChange', + ), + onSnapStateChange: this.controllerMessenger.subscribe.bind( + this.controllerMessenger, + 'SnapController:stateChange', + ), }); this.notificationController = new NotificationController({ @@ -2984,6 +3001,15 @@ export default class MetamaskController extends EventEmitter { ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) await this.accountsController.updateAccounts(); + console.log(this.accountsController.state); + const selectedAccount = uuid({ + random: sha256FromString( + this.preferencesController.getSelectedAddress(), + ).slice(0, 16), + }); + + console.log('setting account'); + this.accountsController.setSelectedAccount(selectedAccount); ///: END:ONLY_INCLUDE_IN // set new identities @@ -3053,6 +3079,13 @@ export default class MetamaskController extends EventEmitter { ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) await this.accountsController.updateAccounts(); + const selectedAccount = uuid({ + random: sha256FromString( + this.preferencesController.getSelectedAddress(), + ).slice(0, 16), + }); + + this.accountsController.setSelectedAccount(selectedAccount); ///: END:ONLY_INCLUDE_IN return this.keyringController.fullUpdate(); From 1f789b83616f00f19893837c65820037f0d6c234 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 27 Jul 2023 00:09:19 +0800 Subject: [PATCH 005/235] feat: update app-header to use accounts controller --- .../controllers/accounts-controller.ts | 116 ++++++++++++------ app/scripts/metamask-controller.js | 10 +- test/data/mock-state.json | 97 +++++++++++++++ .../multichain/app-header/app-header.js | 10 +- ui/selectors/selectors.js | 15 +++ ui/store/actions.ts | 56 +++++++++ ui/store/store.ts | 7 ++ 7 files changed, 263 insertions(+), 48 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index 1f6efce6881e..87a462bd9ab5 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -15,13 +15,14 @@ import { KeyringController, } from '@metamask/keyring-controller'; import { SnapControllerState } from '@metamask/snaps-controllers-flask'; -import { add0x } from '@metamask/utils'; const controllerName = 'AccountsController'; export type AccountsControllerState = { - internalAccounts: Record; - selectedAccount: string; // id of the selected account + internalAccounts: { + accounts: Record; + selectedAccount: string; // id of the selected account + }; }; export type AccountsControllerGetStateAction = { @@ -60,8 +61,10 @@ const accountsControllerMetadata = { }; const defaultState: AccountsControllerState = { - internalAccounts: {}, - selectedAccount: '', + internalAccounts: { + accounts: {}, + selectedAccount: '', + }, }; export default class AccountsController extends BaseControllerV2< @@ -109,20 +112,14 @@ export default class AccountsController extends BaseControllerV2< onSnapStateChange(async (snapState: SnapControllerState) => { console.log('snap state changed', snapState); - const { snaps } = snapState; - - Object.values(snaps) - .filter((snap) => !snap.enabled || snap.blocked) - .forEach((disabledSnap) => { - this.#disableSnap(disabledSnap.id); - }); - await this.updateAccounts(); }); onKeyringStateChange(async (keyringState: KeyringControllerState) => { console.log('keyring state changed', keyringState); - await this.updateAccounts(); + if (keyringState.isUnlocked) { + await this.updateAccounts(); + } }); onKeyringAccountRemoved(async (address: string) => { @@ -132,9 +129,8 @@ export default class AccountsController extends BaseControllerV2< } getAccount(address: string): InternalAccount | undefined { - return Object.values(this.state.internalAccounts).find( - (internalAccount) => - internalAccount.address.toLowerCase() === address.toLowerCase(), + return Object.values(this.state.internalAccounts.accounts).find( + (account) => account.address.toLowerCase() === address.toLowerCase(), ); } @@ -147,7 +143,7 @@ export default class AccountsController extends BaseControllerV2< } getAccountId(accountId: string): InternalAccount | undefined { - return this.state.internalAccounts[accountId]; + return this.state.internalAccounts.accounts[accountId]; } getAccountByIdExpect(accountId: string): InternalAccount { @@ -159,13 +155,13 @@ export default class AccountsController extends BaseControllerV2< } getAccountsByKeyring(keyring: string): InternalAccount[] { - return Object.values(this.state.internalAccounts).filter( + return Object.values(this.state.internalAccounts.accounts).filter( (internalAccount) => internalAccount.type === keyring, ); } getAccountsBySnapId(snapId: string): InternalAccount[] { - return Object.values(this.state.internalAccounts).filter( + return Object.values(this.state.internalAccounts.accounts).filter( (internalAccount) => internalAccount.metadata.snap?.id === snapId, ); } @@ -173,22 +169,45 @@ export default class AccountsController extends BaseControllerV2< async updateAccounts(): Promise { const legacyAccounts = await this.#listLegacyAccounts(); const snapAccounts = await this.#listSnapAccounts(); + const accountNames = identitesToAccountNames(this.identities); console.log('legacy accounts', legacyAccounts); console.log('snap accounts', snapAccounts); - const internalAccounts = [...legacyAccounts, ...snapAccounts].reduce( - (internalAccountMap, internalAccount) => { - internalAccountMap[internalAccount.id] = { - ...internalAccount, - }; - return internalAccountMap; - }, - {} as Record, - ); + // keyring type map. + const keyringTypes = new Map(); + + const accounts: Record = [ + ...legacyAccounts, + ...snapAccounts, + ].reduce((internalAccountMap, internalAccount) => { + const keyringAccountIndex = + keyringTypes.get(internalAccount.metadata.keyring.type) ?? 0; + if (keyringAccountIndex) { + keyringTypes.set( + internalAccount.metadata.keyring.type, + keyringAccountIndex + 1, + ); + } else { + keyringTypes.set(internalAccount.metadata.keyring.type, 1); + } + + internalAccountMap[internalAccount.id] = { + ...internalAccount, + }; + + // use the account name from the identities if it exists + internalAccountMap[internalAccount.id].name = accountNames[ + internalAccount.id + ] + ? accountNames[internalAccount.id] + : `${internalAccount.metadata.keyring.type} ${keyringAccountIndex + 1}`; + + return internalAccountMap; + }, {} as Record); this.update((currentState: AccountsControllerState) => { - currentState.internalAccounts = internalAccounts; + currentState.internalAccounts.accounts = accounts; }); console.log('updated state', this.state); @@ -198,7 +217,7 @@ export default class AccountsController extends BaseControllerV2< const account = this.getAccount(address); if (account) { this.update((currentState: AccountsControllerState) => { - delete currentState.internalAccounts[account.id]; + delete currentState.internalAccounts.accounts[account.id]; }); } @@ -213,7 +232,9 @@ export default class AccountsController extends BaseControllerV2< ); const snapAccounts = - (await (snapKeyring as SnapKeyring)?.listAccounts(true)) ?? []; + (await (snapKeyring as SnapKeyring)?.listAccounts(false)) ?? []; + + console.log('snap accounts', snapAccounts); for (const account of snapAccounts) { account.metadata = { @@ -262,21 +283,25 @@ export default class AccountsController extends BaseControllerV2< ], type: 'eip155:eoa', metadata: { - keyring: keyring.type as string, + keyring: { + type: (keyring as any).type as string, + }, }, }); } return internalAccounts.filter( - (account) => account.metadata.keyring !== 'Snap Keyring', + (account) => account.metadata.keyring.type !== 'Snap Keyring', ); } setSelectedAccount(accountId: string): void { const account = this.getAccountByIdExpect(accountId); + console.log('set selected account', account); + this.update((currentState: AccountsControllerState) => { - currentState.selectedAccount = account.id; + currentState.internalAccounts.selectedAccount = account.id; }); } @@ -284,14 +309,14 @@ export default class AccountsController extends BaseControllerV2< const account = this.getAccountByIdExpect(accountId); this.update((currentState: AccountsControllerState) => { - currentState.internalAccounts[accountId] = { + currentState.internalAccounts.accounts[accountId] = { ...account, name: accountName, }; }); } - #disableSnap(snapId: string) { + #disableSnap(snapId: string): void { const accounts = this.getAccountsBySnapId(snapId); this.update((currentState: AccountsControllerState) => { @@ -300,7 +325,7 @@ export default class AccountsController extends BaseControllerV2< ...account.metadata.snap, enabled: false, }; - currentState.internalAccounts[account.id] = account; + currentState.internalAccounts.accounts[account.id] = account; }); }); } @@ -314,3 +339,18 @@ export default class AccountsController extends BaseControllerV2< return snap?.enabled && !snap?.blocked; } } + +export function identitesToAccountNames( + identities: Record, +): Record { + if (!identities) { + return {}; + } + return Object.values(identities).reduce((accounts, identity) => { + const accountId = uuid({ + random: sha256FromString(identity.address).slice(0, 16), + }); + accounts[accountId] = identity.name; + return accounts; + }, {} as Record); +} diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 0ab77d65778f..3c6458948d07 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -2209,6 +2209,7 @@ export default class MetamaskController extends EventEmitter { */ getApi() { const { + accountsController, addressBookController, alertController, appStateController, @@ -2395,6 +2396,10 @@ export default class MetamaskController extends EventEmitter { ), ///: END:ONLY_INCLUDE_IN + // AccountsController + setSelectedInternalAccount: + accountsController.setSelectedAccount.bind(accountsController), + // AssetsContractController getTokenStandardAndDetails: this.getTokenStandardAndDetails.bind(this), @@ -2999,9 +3004,7 @@ export default class MetamaskController extends EventEmitter { this.preferencesController.getLedgerTransportPreference(); this.setLedgerTransportPreference(transportPreference); - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) await this.accountsController.updateAccounts(); - console.log(this.accountsController.state); const selectedAccount = uuid({ random: sha256FromString( this.preferencesController.getSelectedAddress(), @@ -3010,7 +3013,6 @@ export default class MetamaskController extends EventEmitter { console.log('setting account'); this.accountsController.setSelectedAccount(selectedAccount); - ///: END:ONLY_INCLUDE_IN // set new identities this.preferencesController.setAddresses(accounts); @@ -3077,7 +3079,6 @@ export default class MetamaskController extends EventEmitter { this.setLedgerTransportPreference(transportPreference); - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) await this.accountsController.updateAccounts(); const selectedAccount = uuid({ random: sha256FromString( @@ -3086,7 +3087,6 @@ export default class MetamaskController extends EventEmitter { }); this.accountsController.setSelectedAccount(selectedAccount); - ///: END:ONLY_INCLUDE_IN return this.keyringController.fullUpdate(); } diff --git a/test/data/mock-state.json b/test/data/mock-state.json index 77d17841f66b..2261d196d1de 100644 --- a/test/data/mock-state.json +++ b/test/data/mock-state.json @@ -133,6 +133,103 @@ "id": "chain5" } }, + "internalAccounts": { + "accounts": { + "cf8dace4-9439-4bd4-b3a8-88c821c8fcb3": { + "address": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", + "id": "cf8dace4-9439-4bd4-b3a8-88c821c8fcb3", + "metadata": { + "keyring": { + "type": "HD Key Tree" + } + }, + "name": "Test Account", + "options": {}, + "supportedMethods": [ + "personal_sign", + "eth_sendTransaction", + "eth_sign", + "eth_signTransaction", + "eth_signTypedData", + "eth_signTypedData_v1", + "eth_signTypedData_v2", + "eth_signTypedData_v3", + "eth_signTypedData_v4" + ], + "type": "eip155:eoa" + }, + "07c2cfec-36c9-46c4-8115-3836d3ac9047": { + "address": "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b", + "id": "07c2cfec-36c9-46c4-8115-3836d3ac9047", + "metadata": { + "keyring": { + "type": "HD Key Tree" + } + }, + "name": "Test Account 2", + "options": {}, + "supportedMethods": [ + "personal_sign", + "eth_sendTransaction", + "eth_sign", + "eth_signTransaction", + "eth_signTypedData", + "eth_signTypedData_v1", + "eth_signTypedData_v2", + "eth_signTypedData_v3", + "eth_signTypedData_v4" + ], + "type": "eip155:eoa" + }, + "15e69915-2a1a-4019-93b3-916e11fd432f": { + "address": "0xc42edfcc21ed14dda456aa0756c153f7985d8813", + "id": "15e69915-2a1a-4019-93b3-916e11fd432f", + "metadata": { + "keyring": { + "type": "Ledger Hardware" + } + }, + "name": "Ledger Hardware 2", + "options": {}, + "supportedMethods": [ + "personal_sign", + "eth_sendTransaction", + "eth_sign", + "eth_signTransaction", + "eth_signTypedData", + "eth_signTypedData_v1", + "eth_signTypedData_v2", + "eth_signTypedData_v3", + "eth_signTypedData_v4" + ], + "type": "eip155:eoa" + }, + "784225f4-d30b-4e77-a900-c8bbce735b88": { + "address": "0xeb9e64b93097bc15f01f13eae97015c57ab64823", + "id": "784225f4-d30b-4e77-a900-c8bbce735b88", + "metadata": { + "keyring": { + "type": "HD Key Tree" + } + }, + "name": "Test Account 3", + "options": {}, + "supportedMethods": [ + "personal_sign", + "eth_sendTransaction", + "eth_sign", + "eth_signTransaction", + "eth_signTypedData", + "eth_signTypedData_v1", + "eth_signTypedData_v2", + "eth_signTypedData_v3", + "eth_signTypedData_v4" + ], + "type": "eip155:eoa" + } + }, + "selectedAccount": "cf8dace4-9439-4bd4-b3a8-88c821c8fcb3" + }, "keyrings": [ { "type": "HD Key Tree", diff --git a/ui/components/multichain/app-header/app-header.js b/ui/components/multichain/app-header/app-header.js index c5c9e469b3a1..e4e05fc90302 100644 --- a/ui/components/multichain/app-header/app-header.js +++ b/ui/components/multichain/app-header/app-header.js @@ -39,9 +39,9 @@ import { getCurrentNetwork, getOnboardedInThisUISession, getOriginOfCurrentTab, - getSelectedIdentity, getShowProductTour, getTestNetworkBackgroundColor, + getSelectedInternalAccount, ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) getSelectedAddress, getTheme, @@ -84,7 +84,7 @@ export const AppHeader = ({ location }) => { ///: END:ONLY_INCLUDE_IN // Used for account picker - const identity = useSelector(getSelectedIdentity); + const internalAccount = useSelector(getSelectedInternalAccount); const dispatch = useDispatch(); const completedOnboarding = useSelector(getCompletedOnboarding); const onboardedInThisUISession = useSelector(getOnboardedInThisUISession); @@ -269,10 +269,10 @@ export const AppHeader = ({ location }) => { /> ) : null} - {identity ? ( + {internalAccount ? ( { dispatch(toggleAccountMenu()); diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index e1d2a0663915..0ac69c160c6e 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -316,6 +316,21 @@ export function getSelectedIdentity(state) { return identities[selectedAddress]; } +///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) +export function getSelectedInternalAccount(state) { + const accountId = state.metamask.internalAccounts.selectedAccount; + return state.metamask.internalAccounts.accounts[accountId]; +} + +export function getInternalAccounts(state) { + return Object.values(state.metamask.internalAccounts.accounts); +} + +export function getInternalAccount(state, accountId) { + return state.metamask.internalAccounts.accounts[accountId]; +} +///: END:ONLY_INCLUDE_IN + export function getNumberOfTokens(state) { const { tokens } = state.metamask; return tokens ? tokens.length : 0; diff --git a/ui/store/actions.ts b/ui/store/actions.ts index 28ef4943c3c6..d2ed58e9850e 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -41,6 +41,8 @@ import { ///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) getPermissionSubjects, + getSelectedAccount, + getInternalAccount, ///: END:ONLY_INCLUDE_IN } from '../selectors'; import { @@ -1668,6 +1670,12 @@ async function _setSelectedAddress(address: string): Promise { await submitRequestToBackground('setSelectedAddress', [address]); } +async function _setSelectedInternalAccount(accountId: string): Promise { + log.debug(`background.setSelectedInternalAccount`); + console.log('sending to background', accountId); + await submitRequestToBackground('setSelectedInternalAccount', [accountId]); +} + export function setSelectedAddress( address: string, ): ThunkAction { @@ -1685,6 +1693,54 @@ export function setSelectedAddress( }; } +export function setSelectedInternalAccount( + accountId: string, +): ThunkAction { + return async (dispatch, getState) => { + dispatch(showLoadingIndication()); + log.debug(`background.setSelectedAddress`); + + const state = getState(); + const unconnectedAccountAccountAlertIsEnabled = + getUnconnectedAccountAlertEnabledness(state); + const activeTabOrigin = state.activeTab.origin; + const selectedAccount = getSelectedAccount(state); + const accountToBeSet = getInternalAccount(state, accountId); + const permittedAccountsForCurrentTab = + getPermittedAccountsForCurrentTab(state); + + // TODO: ACCOUNTS_CONTROLLER change to account id + const currentTabIsConnectedToPreviousAddress = + Boolean(activeTabOrigin) && + permittedAccountsForCurrentTab.includes(selectedAccount.address); + // TODO: ACCOUNTS_CONTROLLER change to account id + const currentTabIsConnectedToNextAddress = + Boolean(activeTabOrigin) && + permittedAccountsForCurrentTab.includes(accountToBeSet.address); + const switchingToUnconnectedAddress = + currentTabIsConnectedToPreviousAddress && + !currentTabIsConnectedToNextAddress; + + try { + await _setSelectedInternalAccount(accountId); + await forceUpdateMetamaskState(dispatch); + } catch (error) { + dispatch(displayWarning(error)); + return; + } finally { + dispatch(hideLoadingIndication()); + } + + if ( + unconnectedAccountAccountAlertIsEnabled && + switchingToUnconnectedAddress + ) { + dispatch(switchedToUnconnectedAccount()); + await setUnconnectedAccountAlertShown(activeTabOrigin); + } + }; +} + export function setSelectedAccount( address: string, ): ThunkAction { diff --git a/ui/store/store.ts b/ui/store/store.ts index 8f8e46847302..502dafa924bf 100644 --- a/ui/store/store.ts +++ b/ui/store/store.ts @@ -3,6 +3,7 @@ import { configureStore as baseConfigureStore } from '@reduxjs/toolkit'; import devtoolsEnhancer from 'remote-redux-devtools'; import { ApprovalControllerState } from '@metamask/approval-controller'; import { GasEstimateType, GasFeeEstimates } from '@metamask/gas-fee-controller'; +import { InternalAccount } from '@metamask/eth-snap-keyring'; import rootReducer from '../ducks'; import { LedgerTransportTypes } from '../../shared/constants/hardware-wallets'; import { TransactionMeta } from '../../shared/constants/transaction'; @@ -80,6 +81,12 @@ interface TemporaryBackgroundState { ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) custodyAccountDetails?: { [key: string]: any }; ///: END:ONLY_INCLUDE_IN + internalAccounts?: { + accounts: { + [key: string]: InternalAccount; + }; + selectedAccounts: string; + }; } type RootReducerReturnType = ReturnType; From bf27036535f1abbe695e49b86fec75a976c0bc39 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 27 Jul 2023 00:44:37 +0800 Subject: [PATCH 006/235] feat: update account-list-menu to use accounts controller --- .../account-list-menu/account-list-menu.js | 23 ++++++++------ .../account-list-menu.test.js | 31 ++++++++++++++++--- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/ui/components/multichain/account-list-menu/account-list-menu.js b/ui/components/multichain/account-list-menu/account-list-menu.js index 6f3935e4dfe8..67a9bc61b0fe 100644 --- a/ui/components/multichain/account-list-menu/account-list-menu.js +++ b/ui/components/multichain/account-list-menu/account-list-menu.js @@ -23,12 +23,15 @@ import { import { useI18nContext } from '../../../hooks/useI18nContext'; import { MetaMetricsContext } from '../../../contexts/metametrics'; import { - getSelectedAccount, - getMetaMaskAccountsOrdered, getConnectedSubjectsForAllAddresses, getOriginOfCurrentTab, + getInternalAccounts, + getSelectedInternalAccount, } from '../../../selectors'; -import { toggleAccountMenu, setSelectedAccount } from '../../../store/actions'; +import { + toggleAccountMenu, + setSelectedInternalAccount, +} from '../../../store/actions'; import { MetaMetricsEventAccountType, MetaMetricsEventCategory, @@ -49,8 +52,10 @@ import { ENVIRONMENT_TYPE_POPUP } from '../../../../shared/constants/app'; export const AccountListMenu = ({ onClose }) => { const t = useI18nContext(); const trackEvent = useContext(MetaMetricsContext); - const accounts = useSelector(getMetaMaskAccountsOrdered); - const selectedAccount = useSelector(getSelectedAccount); + + const accounts = useSelector(getInternalAccounts); + const selectedAccount = useSelector(getSelectedInternalAccount); + const connectedSites = useSelector(getConnectedSubjectsForAllAddresses); const currentTabOrigin = useSelector(getOriginOfCurrentTab); const history = useHistory(); @@ -67,7 +72,7 @@ export const AccountListMenu = ({ onClose }) => { distance: 100, maxPatternLength: 32, minMatchCharLength: 1, - keys: ['name', 'address'], + keys: ['name', 'address', 'id'], }); fuse.setCollection(accounts); searchResults = fuse.search(searchQuery); @@ -184,11 +189,11 @@ export const AccountListMenu = ({ onClose }) => { location: 'Main Menu', }, }); - dispatch(setSelectedAccount(account.address)); + dispatch(setSelectedInternalAccount(account.id)); }} - identity={account} + account={account} key={account.address} - selected={selectedAccount.address === account.address} + selected={selectedAccount.id === account.id} closeMenu={onClose} connectedAvatar={connectedSite?.iconUrl} connectedAvatarName={connectedSite?.name} diff --git a/ui/components/multichain/account-list-menu/account-list-menu.test.js b/ui/components/multichain/account-list-menu/account-list-menu.test.js index 60b9ef243328..e0ac76c43749 100644 --- a/ui/components/multichain/account-list-menu/account-list-menu.test.js +++ b/ui/components/multichain/account-list-menu/account-list-menu.test.js @@ -136,14 +136,37 @@ describe('AccountListMenu', () => { }, metamask: { ...mockState.metamask, - accounts: { - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { - balance: '0x346ba7725f412cbfdb', - address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + internalAccounts: { + ...mockState.metamask.internalAccounts, + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }, }, }, }); + const props = { onClose: () => jest.fn() }; const { container } = renderWithProvider( , From 1c5f1ba667c481ce3af365d21bd9165ec3cf933c Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 27 Jul 2023 01:05:31 +0800 Subject: [PATCH 007/235] feat: update account-list-item to use accounts controller --- .../account-list-item/account-list-item.js | 41 +++++++++++-------- .../account-list-item.test.js | 41 +++++++++++++------ 2 files changed, 53 insertions(+), 29 deletions(-) diff --git a/ui/components/multichain/account-list-item/account-list-item.js b/ui/components/multichain/account-list-item/account-list-item.js index 10e8d463fb3a..0593c2f50a5f 100644 --- a/ui/components/multichain/account-list-item/account-list-item.js +++ b/ui/components/multichain/account-list-item/account-list-item.js @@ -37,7 +37,6 @@ import { HardwareKeyringNames } from '../../../../shared/constants/hardware-wall import { KeyringType } from '../../../../shared/constants/keyring'; import UserPreferencedCurrencyDisplay from '../../app/user-preferenced-currency-display/user-preferenced-currency-display.component'; import { SECONDARY, PRIMARY } from '../../../helpers/constants/common'; -import { findKeyringForAddress } from '../../../ducks/metamask/metamask'; import Tooltip from '../../ui/tooltip/tooltip'; import { MetaMetricsEventCategory, @@ -71,7 +70,7 @@ function getLabel(keyring = {}, t) { } export const AccountListItem = ({ - identity, + account, selected = false, onClick, closeMenu, @@ -97,9 +96,7 @@ export const AccountListItem = ({ } }, [itemRef, selected]); - const keyring = useSelector((state) => - findKeyringForAddress(state, identity.address), - ); + const { keyring } = account.metadata; const label = getLabel(keyring, t); const trackEvent = useContext(MetaMetricsContext); @@ -132,7 +129,7 @@ export const AccountListItem = ({ - {identity.name.length > MAXIMUM_CHARACTERS_WITHOUT_TOOLTIP ? ( + {account.name.length > MAXIMUM_CHARACTERS_WITHOUT_TOOLTIP ? ( - {identity.name} + {account.name} ) : ( - identity.name + account.name )} @@ -193,7 +190,7 @@ export const AccountListItem = ({ > @@ -213,7 +210,7 @@ export const AccountListItem = ({ /> ) : null} - {shortenAddress(toChecksumHexAddress(identity.address))} + {shortenAddress(toChecksumHexAddress(account.address))} @@ -240,7 +237,7 @@ export const AccountListItem = ({ ) : null} setAccountOptionsMenuOpen(false)} isOpen={accountOptionsMenuOpen} - isRemovable={keyring?.type !== KeyringType.hdKeyTree} + isRemovable={keyring !== KeyringType.hdKeyTree} closeMenu={closeMenu} /> @@ -275,10 +272,20 @@ AccountListItem.propTypes = { /** * Identity of the account */ - identity: PropTypes.shape({ + account: PropTypes.shape({ name: PropTypes.string.isRequired, address: PropTypes.string.isRequired, balance: PropTypes.string.isRequired, + metadata: PropTypes.shape({ + snap: PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string, + enabled: PropTypes.bool, + }), + keyring: PropTypes.shape({ + type: PropTypes.string.isRequired, + }).isRequired, + }).isRequired, }).isRequired, /** * Represents if this account is currently selected diff --git a/ui/components/multichain/account-list-item/account-list-item.test.js b/ui/components/multichain/account-list-item/account-list-item.test.js index 354fdac0c2c1..0aa80dca6752 100644 --- a/ui/components/multichain/account-list-item/account-list-item.test.js +++ b/ui/components/multichain/account-list-item/account-list-item.test.js @@ -8,15 +8,15 @@ import mockState from '../../../../test/data/mock-state.json'; import { shortenAddress } from '../../../helpers/utils/util'; import { AccountListItem } from '.'; -const identity = { - ...mockState.metamask.identities[ - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc' +const account = { + ...mockState.metamask.internalAccounts.accounts[ + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3' ], balance: '0x152387ad22c3f0', }; const DEFAULT_PROPS = { - identity, + account, onClick: jest.fn(), }; @@ -33,9 +33,9 @@ const render = (props = {}) => { describe('AccountListItem', () => { it('renders AccountListItem component and shows account name, address, and balance', () => { const { container } = render(); - expect(screen.getByText(identity.name)).toBeInTheDocument(); + expect(screen.getByText(account.name)).toBeInTheDocument(); expect( - screen.getByText(shortenAddress(toChecksumHexAddress(identity.address))), + screen.getByText(shortenAddress(toChecksumHexAddress(account.address))), ).toBeInTheDocument(); expect(document.querySelector('[title="0.006 ETH"]')).toBeInTheDocument(); @@ -52,8 +52,8 @@ describe('AccountListItem', () => { it('renders the account name tooltip for long names', () => { render({ selected: true, - identity: { - ...identity, + account: { + ...account, name: 'This is a super long name that requires tooltip', }, }); @@ -104,16 +104,33 @@ describe('AccountListItem', () => { expect(getByAltText(`${connectedAvatarName} logo`)).toBeInTheDocument(); }); - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) it('renders the snap label for snap accounts', () => { const { getByText } = render({ - identity: { - address: '0xb552685e3d2790eFd64a175B00D51F02cdaFEe5D', + account: { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'Snap Keyring', + }, + }, name: 'Snap Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, }); expect(getByText('Snaps')).toBeInTheDocument(); }); - ///: END:ONLY_INCLUDE_IN }); From 552cfbcb346b3e79160b1daf9b572a0735e45846 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 27 Jul 2023 08:07:57 +0800 Subject: [PATCH 008/235] feat: update account-list-item, account-list-item-menu, confirm-remove-account to use internal account --- .storybook/test-data.js | 101 +++++++++++++++++- .../confirm-remove-account.component.js | 28 +++-- .../account-list-item-menu.js | 32 +++--- .../account-list-item-menu.stories.js | 10 +- .../account-list-item-menu.test.js | 8 +- .../account-list-item/account-list-item.js | 5 +- .../account-list-item.stories.js | 28 ++--- ui/ducks/metamask/metamask.js | 23 ++-- ui/selectors/selectors.js | 8 +- 9 files changed, 177 insertions(+), 66 deletions(-) diff --git a/.storybook/test-data.js b/.storybook/test-data.js index f538ee2558e4..356c47bef05c 100644 --- a/.storybook/test-data.js +++ b/.storybook/test-data.js @@ -279,6 +279,103 @@ const state = { isUnlocked: true, isAccountMenuOpen: false, rpcUrl: 'https://rawtestrpc.metamask.io/', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x64a845a5b02460acf8a3d84503b0d68d028b4bb4', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'This is a Really Long Account Name', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '07c2cfec-36c9-46c4-8115-3836d3ac9047': { + address: '0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e', + id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '15e69915-2a1a-4019-93b3-916e11fd432f': { + address: '0x9d0ba4ddac06032527b140912ec808ab9451b788', + id: '15e69915-2a1a-4019-93b3-916e11fd432f', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 3', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '784225f4-d30b-4e77-a900-c8bbce735b88': { + address: '0xeb9e64b93097bc15f01f13eae97015c57ab64823', + id: '784225f4-d30b-4e77-a900-c8bbce735b88', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 4', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, identities: { '0x64a845a5b02460acf8a3d84503b0d68d028b4bb4': { name: 'This is a Really Long Account Name', @@ -1599,7 +1696,7 @@ const state = { }, }; -export const networkList = [ +export const networkList = [ { blockExplorerUrl: 'https://etherscan.io', chainId: '0x1', @@ -1673,6 +1770,6 @@ export const networkList = [ rpcUrl: 'https://polygon-rpc.com', ticker: 'MATIC', }, -] +]; export default state; diff --git a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.component.js b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.component.js index e8d8c25cda26..2775eb985053 100644 --- a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.component.js +++ b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.component.js @@ -11,7 +11,21 @@ export default class ConfirmRemoveAccount extends Component { static propTypes = { hideModal: PropTypes.func.isRequired, removeAccount: PropTypes.func.isRequired, - identity: PropTypes.object.isRequired, + account: PropTypes.shape({ + name: PropTypes.string.isRequired, + address: PropTypes.string.isRequired, + balance: PropTypes.string.isRequired, + metadata: PropTypes.shape({ + snap: PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string, + enabled: PropTypes.bool, + }), + keyring: PropTypes.shape({ + type: PropTypes.string.isRequired, + }).isRequired, + }).isRequired, + }).isRequired, chainId: PropTypes.string.isRequired, rpcPrefs: PropTypes.object.isRequired, }; @@ -23,7 +37,7 @@ export default class ConfirmRemoveAccount extends Component { handleRemove = () => { this.props - .removeAccount(this.props.identity.address) + .removeAccount(this.props.account.address) .then(() => this.props.hideModal()); }; @@ -33,31 +47,31 @@ export default class ConfirmRemoveAccount extends Component { renderSelectedAccount() { const { t } = this.context; - const { identity, rpcPrefs, chainId } = this.props; + const { account, rpcPrefs, chainId } = this.props; return (
- +
{t('name')} - {identity.name} + {account.name}
{t('publicAddress')} - {addressSummary(identity.address, 4, 4)} + {addressSummary(account.address, 4, 4)}
{ const accountLink = getAccountLink( - identity.address, + account.address, chainId, rpcPrefs, ); diff --git a/ui/components/multichain/account-list-item-menu/account-list-item-menu.js b/ui/components/multichain/account-list-item-menu/account-list-item-menu.js index 90f070c45e80..b4a4866fabad 100644 --- a/ui/components/multichain/account-list-item-menu/account-list-item-menu.js +++ b/ui/components/multichain/account-list-item-menu/account-list-item-menu.js @@ -43,7 +43,7 @@ export const AccountListItemMenu = ({ onClose, closeMenu, isRemovable, - identity, + account, isOpen, }) => { const t = useI18nContext(); @@ -55,7 +55,7 @@ export const AccountListItemMenu = ({ const deviceName = useSelector(getHardwareWalletType); const keyring = useSelector((state) => - findKeyringForAddress(state, identity.address), + findKeyringForAddress(state, account.id), ); const accountType = formatAccountType(getAccountTypeForKeyring(keyring)); @@ -131,14 +131,14 @@ export const AccountListItemMenu = ({ {isRemovable ? ( { const token = await dispatch( - mmiActions.getCustodianToken(identity.address), + mmiActions.getCustodianToken(account.address), ); const custodyAccountDetails = await dispatch( mmiActions.getAllCustodianAccountsWithToken( @@ -190,7 +190,7 @@ export const AccountListItemMenu = ({ token, custodyAccountDetails, accounts, - selectedAddress: toChecksumHexAddress(identity.address), + selectedAddress: toChecksumHexAddress(account.address), }), ); onClose(); @@ -233,14 +233,22 @@ AccountListItemMenu.propTypes = { */ isRemovable: PropTypes.bool.isRequired, /** - * Identity of the account + * Account object */ - /** - * Identity of the account - */ - identity: PropTypes.shape({ + account: PropTypes.shape({ + id: PropTypes.string.isRequired, name: PropTypes.string.isRequired, address: PropTypes.string.isRequired, balance: PropTypes.string.isRequired, + metadata: PropTypes.shape({ + snap: PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string, + enabled: PropTypes.bool, + }), + keyring: PropTypes.shape({ + type: PropTypes.string.isRequired, + }).isRequired, + }).isRequired, }).isRequired, }; diff --git a/ui/components/multichain/account-list-item-menu/account-list-item-menu.stories.js b/ui/components/multichain/account-list-item-menu/account-list-item-menu.stories.js index 8fd3dc14e4ff..28d34526d13c 100644 --- a/ui/components/multichain/account-list-item-menu/account-list-item-menu.stories.js +++ b/ui/components/multichain/account-list-item-menu/account-list-item-menu.stories.js @@ -1,4 +1,5 @@ import React from 'react'; +import testData from '../../../../.storybook/test-data'; import { AccountListItemMenu } from '.'; export default { @@ -17,7 +18,7 @@ export default { isRemovable: { control: 'boolean', }, - identity: { + account: { control: 'object', }, isOpen: { @@ -26,9 +27,10 @@ export default { }, args: { anchorElement: null, - identity: { - address: '0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e', - name: 'Account 1', + account: { + ...testData.metamask.internalAccounts.accounts[ + Object.keys(testData.metamask.internalAccounts.accounts)[0] + ], balance: '0x152387ad22c3f0', tokenBalance: '32.09 ETH', }, diff --git a/ui/components/multichain/account-list-item-menu/account-list-item-menu.test.js b/ui/components/multichain/account-list-item-menu/account-list-item-menu.test.js index b601e2f8657d..7a390c0ca74a 100644 --- a/ui/components/multichain/account-list-item-menu/account-list-item-menu.test.js +++ b/ui/components/multichain/account-list-item-menu/account-list-item-menu.test.js @@ -5,15 +5,15 @@ import configureStore from '../../../store/store'; import mockState from '../../../../test/data/mock-state.json'; import { AccountListItemMenu } from '.'; -const identity = { - ...mockState.metamask.identities[ - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc' +const account = { + ...mockState.metamask.internalAccounts.accounts[ + Object.keys(mockState.metamask.internalAccounts.accounts)[0] ], balance: '0x152387ad22c3f0', }; const DEFAULT_PROPS = { - identity, + account, onClose: jest.fn(), onHide: jest.fn(), isRemovable: false, diff --git a/ui/components/multichain/account-list-item/account-list-item.js b/ui/components/multichain/account-list-item/account-list-item.js index 0593c2f50a5f..f1a27a843570 100644 --- a/ui/components/multichain/account-list-item/account-list-item.js +++ b/ui/components/multichain/account-list-item/account-list-item.js @@ -258,7 +258,7 @@ export const AccountListItem = ({ /> setAccountOptionsMenuOpen(false)} isOpen={accountOptionsMenuOpen} isRemovable={keyring !== KeyringType.hdKeyTree} @@ -270,9 +270,10 @@ export const AccountListItem = ({ AccountListItem.propTypes = { /** - * Identity of the account + * Account object */ account: PropTypes.shape({ + id: PropTypes.string.isRequired, name: PropTypes.string.isRequired, address: PropTypes.string.isRequired, balance: PropTypes.string.isRequired, diff --git a/ui/components/multichain/account-list-item/account-list-item.stories.js b/ui/components/multichain/account-list-item/account-list-item.stories.js index 627f80bc9127..855455bcca28 100644 --- a/ui/components/multichain/account-list-item/account-list-item.stories.js +++ b/ui/components/multichain/account-list-item/account-list-item.stories.js @@ -8,22 +8,22 @@ import { AccountListItem } from '.'; const store = configureStore(testData); -const [chaosAddress, simpleAddress, hardwareAddress] = Object.keys( - testData.metamask.identities, +const [chaosAccountId, simpleAccountId, hardwareAccountId] = Object.keys( + testData.metamask.internalAccounts.accounts, ); -const SIMPLE_IDENTITY = { - ...testData.metamask.identities[simpleAddress], +const SIMPLE_ACCOUNT = { + ...testData.metamask.internalAccounts.accounts[simpleAccountId], balance: '0x152387ad22c3f0', }; -const HARDWARE_IDENTITY = { - ...testData.metamask.identities[hardwareAddress], +const HARDWARE_ACCOUNT = { + ...testData.metamask.internalAccounts.accounts[hardwareAccountId], balance: '0x152387ad22c3f0', }; -const CHAOS_IDENTITY = { - ...testData.metamask.identities[chaosAddress], +const CHAOS_ACCOUNT = { + ...testData.metamask.internalAccounts.accounts[chaosAccountId], balance: '0x152387ad22c3f0', }; @@ -40,7 +40,7 @@ export default { title: 'Components/Multichain/AccountListItem', component: AccountListItem, argTypes: { - identity: { + account: { control: 'object', }, selected: { @@ -60,7 +60,7 @@ export default { }, }, args: { - identity: SIMPLE_IDENTITY, + account: SIMPLE_ACCOUNT, onClick, }, }; @@ -83,7 +83,7 @@ export const HardwareItem = (args) => (
); -HardwareItem.args = { identity: HARDWARE_IDENTITY }; +HardwareItem.args = { account: HARDWARE_ACCOUNT }; HardwareItem.decorators = [ (story) => {story()}, ]; @@ -93,7 +93,7 @@ export const SelectedHardwareItem = (args) => (
); -SelectedHardwareItem.args = { identity: HARDWARE_IDENTITY, selected: true }; +SelectedHardwareItem.args = { account: HARDWARE_ACCOUNT, selected: true }; SelectedHardwareItem.decorators = [ (story) => {story()}, ]; @@ -103,7 +103,7 @@ export const ChaosDataItem = (args) => ( ); -ChaosDataItem.args = { identity: CHAOS_IDENTITY }; +ChaosDataItem.args = { account: CHAOS_ACCOUNT }; export const ConnectedSiteItem = (args) => (
@@ -121,7 +121,7 @@ export const ConnectedSiteChaosItem = (args) => (
); ConnectedSiteChaosItem.args = { - identity: CHAOS_IDENTITY, + account: CHAOS_ACCOUNT, connectedAvatar: 'https://uniswap.org/favicon.ico', connectedAvatarName: 'Uniswap', }; diff --git a/ui/ducks/metamask/metamask.js b/ui/ducks/metamask/metamask.js index 832c08d4c0d0..38c4225a04b4 100644 --- a/ui/ducks/metamask/metamask.js +++ b/ui/ducks/metamask/metamask.js @@ -16,8 +16,6 @@ import { setCustomGasLimit, setCustomGasPrice } from '../gas/gas.duck'; import { KeyringType } from '../../../shared/constants/keyring'; import { DEFAULT_AUTO_LOCK_TIME_LIMIT } from '../../../shared/constants/preferences'; -import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils'; -import { stripHexPrefix } from '../../../shared/modules/hexstring-utils'; import { decGWEIToHexWEI } from '../../../shared/modules/conversion.utils'; const initialState = { @@ -376,20 +374,13 @@ export function getSeedPhraseBackedUp(state) { * Given the redux state object and an address, finds a keyring that contains that address, if one exists * * @param {object} state - the redux state object - * @param {string} address - the address to search for among the keyring addresses + * @param {string} accountId - the account id to search for among the internal accounts * @returns {object | undefined} The keyring which contains the passed address, or undefined */ -export function findKeyringForAddress(state, address) { - const keyring = state.metamask.keyrings.find((kr) => { - return kr.accounts.some((account) => { - return ( - isEqualCaseInsensitive(account, addHexPrefix(address)) || - isEqualCaseInsensitive(account, stripHexPrefix(address)) - ); - }); - }); +export function findKeyringForAddress(state, accountId) { + const account = state.metamask.internalAccounts.accounts[accountId]; - return keyring; + return account.metadata.keyring; } /** @@ -406,11 +397,11 @@ export function getLedgerTransportType(state) { * Given the redux state object and an address, returns a boolean indicating whether the passed address is part of a Ledger keyring * * @param {object} state - the redux state object - * @param {string} address - the address to search for among all keyring addresses + * @param {string} accountId - the account id to search for among all internal accounts * @returns {boolean} true if the passed address is part of a ledger keyring, and false otherwise */ -export function isAddressLedger(state, address) { - const keyring = findKeyringForAddress(state, address); +export function isAddressLedger(state, accountId) { + const keyring = findKeyringForAddress(state, accountId); return keyring?.type === KeyringType.ledger; } diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 0ac69c160c6e..48b69503746d 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -181,13 +181,13 @@ export function hasUnsignedQRHardwareMessage(state) { } export function getCurrentKeyring(state) { - const identity = getSelectedIdentity(state); + const account = getSelectedInternalAccount(state); - if (!identity) { + if (!account) { return null; } - const keyring = findKeyringForAddress(state, identity.address); + const keyring = findKeyringForAddress(state, account.id); return keyring; } @@ -316,7 +316,6 @@ export function getSelectedIdentity(state) { return identities[selectedAddress]; } -///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) export function getSelectedInternalAccount(state) { const accountId = state.metamask.internalAccounts.selectedAccount; return state.metamask.internalAccounts.accounts[accountId]; @@ -329,7 +328,6 @@ export function getInternalAccounts(state) { export function getInternalAccount(state, accountId) { return state.metamask.internalAccounts.accounts[accountId]; } -///: END:ONLY_INCLUDE_IN export function getNumberOfTokens(state) { const { tokens } = state.metamask; From 82b7751b5d1491ed7f9cba68290c03e2c5f1b6a1 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 27 Jul 2023 09:31:02 +0800 Subject: [PATCH 009/235] feat: update account-details to use internal account --- .../account-details/account-details-display.js | 17 ++++++++++------- .../account-details/account-details.js | 17 ++++++++--------- .../account-details/account-details.stories.js | 6 +++--- .../account-list-item-menu.js | 2 +- .../menu-items/account-details-menu-item.js | 8 ++++---- ui/ducks/app/app.ts | 8 ++++---- ui/pages/routes/routes.component.js | 8 ++++---- ui/pages/routes/routes.container.js | 2 +- ui/store/actionConstants.ts | 2 +- ui/store/actions.ts | 12 +++--------- 10 files changed, 39 insertions(+), 43 deletions(-) diff --git a/ui/components/multichain/account-details/account-details-display.js b/ui/components/multichain/account-details/account-details-display.js index 7e70bfaae228..e0b955e8c2a7 100644 --- a/ui/components/multichain/account-details/account-details-display.js +++ b/ui/components/multichain/account-details/account-details-display.js @@ -9,7 +9,8 @@ import { setAccountLabel } from '../../../store/actions'; import { getCurrentChainId, getHardwareWalletType, - getMetaMaskKeyrings, + getInternalAccount, + getInternalAccounts, } from '../../../selectors'; import { isAbleToExportAccount } from '../../../helpers/utils/util'; import { @@ -32,17 +33,20 @@ import { import { useI18nContext } from '../../../hooks/useI18nContext'; export const AccountDetailsDisplay = ({ - accounts, accountName, - address, + accountId, onExportClick, }) => { const dispatch = useDispatch(); const trackEvent = useContext(MetaMetricsContext); const t = useI18nContext(); - const keyrings = useSelector(getMetaMaskKeyrings); - const keyring = keyrings.find((kr) => kr.accounts.includes(address)); + const displayedAccount = useSelector((state) => + getInternalAccount(state, accountId), + ); + const { keyring } = displayedAccount.metadata; + const { address } = displayedAccount; + const accounts = useSelector(getInternalAccounts); const exportPrivateKeyFeatureEnabled = isAbleToExportAccount(keyring?.type); const chainId = useSelector(getCurrentChainId); @@ -96,8 +100,7 @@ export const AccountDetailsDisplay = ({ }; AccountDetailsDisplay.propTypes = { - accounts: PropTypes.array.isRequired, accountName: PropTypes.string.isRequired, - address: PropTypes.string.isRequired, + accountId: PropTypes.string.isRequired, onExportClick: PropTypes.func.isRequired, }; diff --git a/ui/components/multichain/account-details/account-details.js b/ui/components/multichain/account-details/account-details.js index 249e272edd61..1fa7dfe0ab80 100644 --- a/ui/components/multichain/account-details/account-details.js +++ b/ui/components/multichain/account-details/account-details.js @@ -2,7 +2,7 @@ import React, { useCallback, useState } from 'react'; import PropTypes from 'prop-types'; import { useDispatch, useSelector } from 'react-redux'; import { - setAccountDetailsAddress, + setAccountDetailsAccountId, clearAccountDetails, hideWarning, } from '../../../store/actions'; @@ -17,7 +17,7 @@ import { Box, Text, } from '../../component-library'; -import { getMetaMaskAccountsOrdered } from '../../../selectors'; +import { getInternalAccount } from '../../../selectors'; import { useI18nContext } from '../../../hooks/useI18nContext'; import { AlignItems, @@ -30,12 +30,12 @@ import { AccountDetailsDisplay } from './account-details-display'; import { AccountDetailsAuthenticate } from './account-details-authenticate'; import { AccountDetailsKey } from './account-details-key'; -export const AccountDetails = ({ address }) => { +export const AccountDetails = ({ accountId }) => { const dispatch = useDispatch(); const t = useI18nContext(); const useBlockie = useSelector((state) => state.metamask.useBlockie); - const accounts = useSelector(getMetaMaskAccountsOrdered); - const { name } = accounts.find((account) => account.address === address); + const account = useSelector((state) => getInternalAccount(state, accountId)); + const { name, address } = account; const [attemptingExport, setAttemptingExport] = useState(false); @@ -45,7 +45,7 @@ export const AccountDetails = ({ address }) => { ); const onClose = useCallback(() => { - dispatch(setAccountDetailsAddress('')); + dispatch(setAccountDetailsAccountId('')); dispatch(clearAccountDetails()); dispatch(hideWarning()); }, [dispatch]); @@ -113,9 +113,8 @@ export const AccountDetails = ({ address }) => { ) : ( setAttemptingExport(true)} /> )} @@ -125,5 +124,5 @@ export const AccountDetails = ({ address }) => { }; AccountDetails.propTypes = { - address: PropTypes.string, + accountId: PropTypes.string, }; diff --git a/ui/components/multichain/account-details/account-details.stories.js b/ui/components/multichain/account-details/account-details.stories.js index fd78b220d621..ebf30aae93b1 100644 --- a/ui/components/multichain/account-details/account-details.stories.js +++ b/ui/components/multichain/account-details/account-details.stories.js @@ -2,18 +2,18 @@ import React from 'react'; import testData from '../../../../.storybook/test-data'; import { AccountDetails } from '.'; -const [, address] = Object.keys(testData.metamask.identities); +const [, accountId] = Object.keys(testData.metamask.internalAccounts.accounts); export default { title: 'Components/Multichain/AccountDetails', component: AccountDetails, argTypes: { - address: { + accountId: { control: 'text', }, }, args: { - address, + accountId, }, }; diff --git a/ui/components/multichain/account-list-item-menu/account-list-item-menu.js b/ui/components/multichain/account-list-item-menu/account-list-item-menu.js index b4a4866fabad..fcd595510529 100644 --- a/ui/components/multichain/account-list-item-menu/account-list-item-menu.js +++ b/ui/components/multichain/account-list-item-menu/account-list-item-menu.js @@ -131,7 +131,7 @@ export const AccountListItemMenu = ({ { const t = useI18nContext(); @@ -28,7 +28,7 @@ export const AccountDetailsMenuItem = ({ return ( { - dispatch(setAccountDetailsAddress(address)); + dispatch(setAccountDetailsAccountId(accountId)); trackEvent({ event: MetaMetricsEventName.NavAccountDetailsOpened, category: MetaMetricsEventCategory.Navigation, @@ -49,6 +49,6 @@ export const AccountDetailsMenuItem = ({ AccountDetailsMenuItem.propTypes = { metricsLocation: PropTypes.string.isRequired, closeMenu: PropTypes.func, - address: PropTypes.string.isRequired, + accountId: PropTypes.string.isRequired, textProps: PropTypes.object, }; diff --git a/ui/ducks/app/app.ts b/ui/ducks/app/app.ts index e34edcf2d997..663905552869 100644 --- a/ui/ducks/app/app.ts +++ b/ui/ducks/app/app.ts @@ -68,7 +68,7 @@ interface AppState { onboardedInThisUISession: boolean; customTokenAmount: string; txId: number | null; - accountDetailsAddress: string; + accountDetailsAccountId: string; ///: BEGIN:ONLY_INCLUDE_IN(snaps) snapsInstallPrivacyWarningShown: boolean; ///: END:ONLY_INCLUDE_IN @@ -138,7 +138,7 @@ const initialState: AppState = { customTokenAmount: '', scrollToBottom: true, txId: null, - accountDetailsAddress: '', + accountDetailsAccountId: '', ///: BEGIN:ONLY_INCLUDE_IN(snaps) snapsInstallPrivacyWarningShown: false, ///: END:ONLY_INCLUDE_IN @@ -206,10 +206,10 @@ export default function reduceApp( alertMessage: null, }; - case actionConstants.SET_ACCOUNT_DETAILS_ADDRESS: { + case actionConstants.SET_ACCOUNT_DETAILS_ACCOUNT_ID: { return { ...appState, - accountDetailsAddress: action.payload, + accountDetailsAccountId: action.payload, }; } diff --git a/ui/pages/routes/routes.component.js b/ui/pages/routes/routes.component.js index d6280a79c696..497041c92c17 100644 --- a/ui/pages/routes/routes.component.js +++ b/ui/pages/routes/routes.component.js @@ -157,7 +157,7 @@ export default class Routes extends Component { toggleAccountMenu: PropTypes.func, isNetworkMenuOpen: PropTypes.bool, toggleNetworkMenu: PropTypes.func, - accountDetailsAddress: PropTypes.string, + accountDetailsAccountId: PropTypes.string, isImportNftsModalOpen: PropTypes.bool.isRequired, hideImportNftsModal: PropTypes.func.isRequired, isIpfsModalOpen: PropTypes.bool.isRequired, @@ -514,7 +514,7 @@ export default class Routes extends Component { toggleAccountMenu, isNetworkMenuOpen, toggleNetworkMenu, - accountDetailsAddress, + accountDetailsAccountId, location, isImportNftsModalOpen, hideImportNftsModal, @@ -575,8 +575,8 @@ export default class Routes extends Component { {isNetworkMenuOpen ? ( toggleNetworkMenu()} /> ) : null} - {accountDetailsAddress ? ( - + {accountDetailsAccountId ? ( + ) : null} {isImportNftsModalOpen ? ( hideImportNftsModal()} /> diff --git a/ui/pages/routes/routes.container.js b/ui/pages/routes/routes.container.js index 03c0e7f464ea..21f4f6c09492 100644 --- a/ui/pages/routes/routes.container.js +++ b/ui/pages/routes/routes.container.js @@ -64,7 +64,7 @@ function mapStateToProps(state) { completedOnboarding, isAccountMenuOpen: state.metamask.isAccountMenuOpen, isNetworkMenuOpen: state.metamask.isNetworkMenuOpen, - accountDetailsAddress: state.appState.accountDetailsAddress, + accountDetailsAccountId: state.appState.accountDetailsAccountId, isImportNftsModalOpen: state.appState.importNftsModalOpen, isIpfsModalOpen: state.appState.showIpfsModalOpen, }; diff --git a/ui/store/actionConstants.ts b/ui/store/actionConstants.ts index 3cbc2449733c..2c48bb2ec40c 100644 --- a/ui/store/actionConstants.ts +++ b/ui/store/actionConstants.ts @@ -39,7 +39,7 @@ export const SHOW_SEND_TOKEN_PAGE = 'SHOW_SEND_TOKEN_PAGE'; export const SHOW_PRIVATE_KEY = 'SHOW_PRIVATE_KEY'; export const SET_ACCOUNT_LABEL = 'SET_ACCOUNT_LABEL'; export const CLEAR_ACCOUNT_DETAILS = 'CLEAR_ACCOUNT_DETAILS'; -export const SET_ACCOUNT_DETAILS_ADDRESS = 'SET_ACCOUNT_DETAILS_ADDRESS'; +export const SET_ACCOUNT_DETAILS_ACCOUNT_ID = 'SET_ACCOUNT_DETAILS_ACCOUNT_ID'; // tx conf screen export const COMPLETED_TX = 'COMPLETED_TX'; export const TRANSACTION_ERROR = 'TRANSACTION_ERROR'; diff --git a/ui/store/actions.ts b/ui/store/actions.ts index d2ed58e9850e..bccea4f5c015 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -2923,10 +2923,10 @@ export function toggleNetworkMenu() { }; } -export function setAccountDetailsAddress(address: string) { +export function setAccountDetailsAccountId(accountId: string) { return { - type: actionConstants.SET_ACCOUNT_DETAILS_ADDRESS, - payload: address, + type: actionConstants.SET_ACCOUNT_DETAILS_ACCOUNT_ID, + payload: accountId, }; } @@ -2951,12 +2951,6 @@ export function setParticipateInMetaMetrics( reject(err); return; } - /** - * We need to inform sentry that the user's optin preference may have - * changed. The logic to determine which way to toggle is in the - * toggleSession handler in setupSentry.js. - */ - window.sentry?.toggleSession(); dispatch({ type: actionConstants.SET_PARTICIPATE_IN_METAMETRICS, From 0a6ba4884070d5c72549903e7c806d0f8be1b5dc Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 27 Jul 2023 09:35:32 +0800 Subject: [PATCH 010/235] fix: account-details test to use internal accounts --- .../account-details/account-details.test.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/ui/components/multichain/account-details/account-details.test.js b/ui/components/multichain/account-details/account-details.test.js index 78ae274544de..81a44c70ee4b 100644 --- a/ui/components/multichain/account-details/account-details.test.js +++ b/ui/components/multichain/account-details/account-details.test.js @@ -7,7 +7,7 @@ import configureStore from '../../../store/store'; import mockState from '../../../../test/data/mock-state.json'; import { showPrivateKey } from '../../../../app/_locales/en/messages.json'; import { - setAccountDetailsAddress, + setAccountDetailsAccountId, exportAccount, hideWarning, } from '../../../store/actions'; @@ -17,13 +17,16 @@ import { AccountDetails } from '.'; jest.mock('../../../store/actions.ts'); describe('AccountDetails', () => { - const address = '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'; - const mockSetAccountDetailsAddress = jest.fn(); + const account = Object.values( + mockState.metamask.internalAccounts.accounts, + )[0]; + const { id: accountId, address } = account; + const mockSetAccountDetailsAccountId = jest.fn(); const mockExportAccount = jest.fn().mockResolvedValue(true); const mockHideWarning = jest.fn(); beforeEach(() => { - setAccountDetailsAddress.mockReturnValue(mockSetAccountDetailsAddress); + setAccountDetailsAccountId.mockReturnValue(mockSetAccountDetailsAccountId); exportAccount.mockReturnValue(mockExportAccount); hideWarning.mockReturnValue(mockHideWarning); }); @@ -37,7 +40,7 @@ describe('AccountDetails', () => { }, ...storeModifications, }); - const allProps = { address, ...props }; + const allProps = { accountId, ...props }; return renderWithProvider(, store); } From 084173575c0db97acfbf3333f3de285d44c3606e Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 27 Jul 2023 09:51:05 +0800 Subject: [PATCH 011/235] fix: update getDetectedTokensInCurrentNetwork to use internalAccount --- .storybook/test-data.js | 51 +++++++++++++++++++++++++++++++++++++++ ui/selectors/selectors.js | 6 +++-- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/.storybook/test-data.js b/.storybook/test-data.js index 356c47bef05c..9b4f5d328870 100644 --- a/.storybook/test-data.js +++ b/.storybook/test-data.js @@ -531,6 +531,57 @@ const state = { ], }, ], + '0x64a845a5b02460acf8a3d84503b0d68d028b4bb4': [ + { + address: '0x514910771AF9Ca656af840dff83E8264EcF986CA', + decimals: 18, + symbol: 'LINK', + image: + 'https://crypto.com/price/coin-data/icon/LINK/color_icon.png', + aggregators: [ + 'coinGecko', + 'oneInch', + 'paraswap', + 'zapper', + 'zerion', + ], + }, + { + address: '0xc00e94Cb662C3520282E6f5717214004A7f26888', + decimals: 18, + symbol: 'COMP', + image: + 'https://crypto.com/price/coin-data/icon/COMP/color_icon.png', + aggregators: [ + 'bancor', + 'cmc', + 'cryptocom', + 'coinGecko', + 'oneInch', + 'paraswap', + 'pmm', + 'zapper', + 'zerion', + 'zeroEx', + ], + }, + { + address: '0xfffffffFf15AbF397dA76f1dcc1A1604F45126DB', + decimals: 18, + symbol: 'FSW', + image: + 'https://assets.coingecko.com/coins/images/12256/thumb/falconswap.png?1598534184', + aggregators: [ + 'aave', + 'cmc', + 'coinGecko', + 'oneInch', + 'paraswap', + 'zapper', + 'zerion', + ], + }, + ], }, }, detectedTokens: [ diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 48b69503746d..184df4c4dc4f 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -1386,8 +1386,10 @@ export function getIsDynamicTokenListAvailable(state) { */ export function getDetectedTokensInCurrentNetwork(state) { const currentChainId = getCurrentChainId(state); - const selectedAddress = getSelectedAddress(state); - return state.metamask.allDetectedTokens?.[currentChainId]?.[selectedAddress]; + const selectedAccount = getSelectedInternalAccount(state); + return state.metamask.allDetectedTokens?.[currentChainId]?.[ + selectedAccount.address + ]; } /** From cb6bc827881f569c94dfa74c3c490fda880dde90 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 27 Jul 2023 14:21:27 +0800 Subject: [PATCH 012/235] feat: update global-menu to use internal account --- ui/components/multichain/global-menu/global-menu.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ui/components/multichain/global-menu/global-menu.js b/ui/components/multichain/global-menu/global-menu.js index 1ab9013b112b..e00affb8ff5c 100644 --- a/ui/components/multichain/global-menu/global-menu.js +++ b/ui/components/multichain/global-menu/global-menu.js @@ -42,8 +42,7 @@ import { import { ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) getMetaMetricsId, - ///: END:ONLY_INCLUDE_IN(build-mmi) - getSelectedAddress, + getSelectedInternalAccount, ///: BEGIN:ONLY_INCLUDE_IN(snaps) getUnreadNotificationsCount, ///: END:ONLY_INCLUDE_IN @@ -68,7 +67,7 @@ export const GlobalMenu = ({ closeMenu, anchorElement }) => { const dispatch = useDispatch(); const trackEvent = useContext(MetaMetricsContext); const history = useHistory(); - const address = useSelector(getSelectedAddress); + const { address } = useSelector(getSelectedInternalAccount); const hasUnapprovedTransactions = useSelector( (state) => Object.keys(state.metamask.unapprovedTxs).length > 0, From fa1962939804507948af863f650f9d279fcbc133 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 27 Jul 2023 14:22:55 +0800 Subject: [PATCH 013/235] feat: update import-account to use internal account --- .../controllers/accounts-controller.ts | 38 +++++++++++++++++-- app/scripts/metamask-controller.js | 14 ++----- .../import-account/import-account.js | 5 ++- 3 files changed, 42 insertions(+), 15 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index 87a462bd9ab5..afb8d1bcb933 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -76,9 +76,12 @@ export default class AccountsController extends BaseControllerV2< #snapController: SnapController; + identities: any; + constructor({ messenger, state, + identities, keyringController, snapController, onKeyringStateChange, @@ -89,6 +92,7 @@ export default class AccountsController extends BaseControllerV2< state: AccountsControllerState; keyringController: KeyringController; snapController: SnapController; + identities: any; onKeyringStateChange: ( listener: (keyringState: KeyringControllerState) => void, ) => void; @@ -109,6 +113,7 @@ export default class AccountsController extends BaseControllerV2< this.#keyringController = keyringController; this.#snapController = snapController; + this.identities = identities; onSnapStateChange(async (snapState: SnapControllerState) => { console.log('snap state changed', snapState); @@ -117,8 +122,29 @@ export default class AccountsController extends BaseControllerV2< onKeyringStateChange(async (keyringState: KeyringControllerState) => { console.log('keyring state changed', keyringState); + + // check if there are any new accounts added if (keyringState.isUnlocked) { + // TODO: ACCOUNTS_CONTROLLER keyring will return accounts instead of addresses, remove this flatMap after and just get the latest id + const newAccounts = keyringState.keyrings.flatMap( + (keyring) => keyring.accounts, + ); + + const accounts = this.getAllAccounts(); + const [newAddress] = newAccounts.filter((address) => { + return ( + accounts.findIndex( + (account) => account.address.toLowerCase() === address, + ) === -1 + ); + }); + await this.updateAccounts(); + + if (newAddress) { + console.log('setting new account', newAddress); + this.setSelectedAccount(this.getAccountExpect(newAddress).id); + } } }); @@ -142,12 +168,16 @@ export default class AccountsController extends BaseControllerV2< return account; } - getAccountId(accountId: string): InternalAccount | undefined { + getAccountById(accountId: string): InternalAccount | undefined { return this.state.internalAccounts.accounts[accountId]; } + getAllAccounts(): InternalAccount[] { + return Object.values(this.state.internalAccounts.accounts); + } + getAccountByIdExpect(accountId: string): InternalAccount { - const account = this.getAccountId(accountId); + const account = this.getAccountById(accountId); if (account === undefined) { throw new Error(`Account Id ${accountId} not found`); } @@ -171,8 +201,8 @@ export default class AccountsController extends BaseControllerV2< const snapAccounts = await this.#listSnapAccounts(); const accountNames = identitesToAccountNames(this.identities); - console.log('legacy accounts', legacyAccounts); - console.log('snap accounts', snapAccounts); + // console.log('legacy accounts', legacyAccounts); + // console.log('snap accounts', snapAccounts); // keyring type map. const keyringTypes = new Map(); diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 3c6458948d07..d0527843949a 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1027,6 +1027,7 @@ export default class MetamaskController extends EventEmitter { state: initState.accountsController, keyringController: this.keyringController, snapController: this.snapController, + identities: initState.PreferencesController.identities, onKeyringAccountRemoved: keyringControllerMessenger.subscribe.bind( keyringControllerMessenger, 'KeyringController:accountRemoved', @@ -3623,16 +3624,9 @@ export default class MetamaskController extends EventEmitter { */ async importAccountWithStrategy(strategy, args) { const privateKey = await accountImporter.importAccount(strategy, args); - const keyring = await this.keyringController.addNewKeyring( - KeyringType.imported, - [privateKey], - ); - const [firstAccount] = await keyring.getAccounts(); - // update accounts in preferences controller - const allAccounts = await this.keyringController.getAccounts(); - this.preferencesController.setAddresses(allAccounts); - // set new account as selected - this.preferencesController.setSelectedAddress(firstAccount); + await this.keyringController.addNewKeyring(KeyringType.imported, [ + privateKey, + ]); } // --------------------------------------------------------------------------- diff --git a/ui/components/multichain/import-account/import-account.js b/ui/components/multichain/import-account/import-account.js index 478a2e3acba1..38ca571d566f 100644 --- a/ui/components/multichain/import-account/import-account.js +++ b/ui/components/multichain/import-account/import-account.js @@ -38,9 +38,12 @@ export const ImportAccount = ({ onActionComplete }) => { const loadingMessage = getLoadingMessage(strategy); try { - const { selectedAddress } = await dispatch( + const updatedState = await dispatch( actions.importNewAccount(strategy, importArgs, loadingMessage), ); + const { internalAccounts } = updatedState; + const { address: selectedAddress } = + internalAccounts.accounts[internalAccounts.selectedAccount]; if (selectedAddress) { trackImportEvent(strategy, true); dispatch(actions.hideWarning()); From e169619d7ef65144fee858110cc2f7057609505f Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 27 Jul 2023 14:49:20 +0800 Subject: [PATCH 014/235] fix: account-details-menu test --- .../menu-items/account-details-menu-item.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/components/multichain/menu-items/account-details-menu-item.test.js b/ui/components/multichain/menu-items/account-details-menu-item.test.js index f13c27d63a9f..32923f487399 100644 --- a/ui/components/multichain/menu-items/account-details-menu-item.test.js +++ b/ui/components/multichain/menu-items/account-details-menu-item.test.js @@ -10,7 +10,7 @@ const render = () => { return renderWithProvider( , store, @@ -19,7 +19,7 @@ const render = () => { jest.mock('../../../store/actions', () => ({ ...jest.requireActual('../../../store/actions.ts'), - setAccountDetailsAddress: jest.fn().mockReturnValue({ type: 'TYPE' }), + setAccountDetailsAccountId: jest.fn().mockReturnValue({ type: 'TYPE' }), })); describe('AccountDetailsMenuItem', () => { @@ -31,8 +31,8 @@ describe('AccountDetailsMenuItem', () => { fireEvent.click(getByTestId('account-list-menu-details')); - expect(actions.setAccountDetailsAddress).toHaveBeenCalledWith( - mockState.metamask.selectedAddress, + expect(actions.setAccountDetailsAccountId).toHaveBeenCalledWith( + mockState.metamask.internalAccounts.selectedAccount, ); }); }); From 0cd626a4cde6c6973b5cfe988f617eadac06efc6 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 27 Jul 2023 15:08:14 +0800 Subject: [PATCH 015/235] feat: update import-nfts-modal to use internal account and fix console.error warnings in test --- .../import-nfts-modal/import-nfts-modal.js | 15 ++++++++------- .../import-nfts-modal/import-nfts-modal.test.js | 6 +++--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/ui/components/multichain/import-nfts-modal/import-nfts-modal.js b/ui/components/multichain/import-nfts-modal/import-nfts-modal.js index b399c0fb9560..8850d63b82d8 100644 --- a/ui/components/multichain/import-nfts-modal/import-nfts-modal.js +++ b/ui/components/multichain/import-nfts-modal/import-nfts-modal.js @@ -25,7 +25,7 @@ import { import { getCurrentChainId, getIsMainnet, - getSelectedAddress, + getSelectedInternalAccount, getUseNftDetection, } from '../../../selectors'; import { getNftsDropdownState } from '../../../ducks/metamask/metamask'; @@ -60,7 +60,7 @@ export const ImportNftsModal = ({ onClose }) => { const useNftDetection = useSelector(getUseNftDetection); const isMainnet = useSelector(getIsMainnet); const nftsDropdownState = useSelector(getNftsDropdownState); - const selectedAddress = useSelector(getSelectedAddress); + const selectedAccount = useSelector(getSelectedInternalAccount); const chainId = useSelector(getCurrentChainId); const addressEnteredOnImportTokensPage = history?.location?.state?.addressEnteredOnImportTokensPage; @@ -82,10 +82,10 @@ export const ImportNftsModal = ({ onClose }) => { await dispatch(addNftVerifyOwnership(nftAddress, tokenId)); const newNftDropdownState = { ...nftsDropdownState, - [selectedAddress]: { - ...nftsDropdownState?.[selectedAddress], + [selectedAccount.address]: { + ...nftsDropdownState?.[selectedAccount.address], [chainId]: { - ...nftsDropdownState?.[selectedAddress]?.[chainId], + ...nftsDropdownState?.[selectedAccount.address]?.[chainId], [nftAddress]: true, }, }, @@ -205,7 +205,7 @@ export const ImportNftsModal = ({ onClose }) => { { { it('should enable the "Import" button when valid entries are input into both Address and TokenId fields', () => { const { getByText, getByPlaceholderText } = renderWithProvider( - , + , store, ); expect(getByText('Import')).not.toBeEnabled(); @@ -73,7 +73,7 @@ describe('ImportNftsModal', () => { it('should not enable the "Import" button when an invalid entry is input into one or both Address and TokenId fields', () => { const { getByText, getByPlaceholderText } = renderWithProvider( - , + , store, ); expect(getByText('Import')).not.toBeEnabled(); @@ -144,7 +144,7 @@ describe('ImportNftsModal', () => { ); const { getByTestId, getByText, getByPlaceholderText } = renderWithProvider( - , + , store, ); const addressInput = getByPlaceholderText('0x...'); From 71877f22e55878f4eb7ac2d6070e6b9baf1394fd Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 27 Jul 2023 17:46:49 +0800 Subject: [PATCH 016/235] fix: hardware selector test --- ui/selectors/selectors.test.js | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/ui/selectors/selectors.test.js b/ui/selectors/selectors.test.js index 307cbde925f0..66a98425139d 100644 --- a/ui/selectors/selectors.test.js +++ b/ui/selectors/selectors.test.js @@ -410,36 +410,48 @@ describe('Selectors', () => { describe('#isHardwareWallet', () => { it('returns false if it is not a HW wallet', () => { - mockState.metamask.keyrings[0].type = KeyringType.imported; + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].metadata.keyring.type = KeyringType.imported; expect(selectors.isHardwareWallet(mockState)).toBe(false); }); it('returns true if it is a Ledger HW wallet', () => { - mockState.metamask.keyrings[0].type = KeyringType.ledger; + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].metadata.keyring.type = KeyringType.ledger; expect(selectors.isHardwareWallet(mockState)).toBe(true); }); it('returns true if it is a Trezor HW wallet', () => { - mockState.metamask.keyrings[0].type = KeyringType.trezor; + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].metadata.keyring.type = KeyringType.trezor; expect(selectors.isHardwareWallet(mockState)).toBe(true); }); }); describe('#getHardwareWalletType', () => { it('returns undefined if it is not a HW wallet', () => { - mockState.metamask.keyrings[0].type = KeyringType.imported; + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].metadata.keyring.type = KeyringType.imported; expect(selectors.getHardwareWalletType(mockState)).toBeUndefined(); }); it('returns "Ledger Hardware" if it is a Ledger HW wallet', () => { - mockState.metamask.keyrings[0].type = KeyringType.ledger; + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].metadata.keyring.type = KeyringType.ledger; expect(selectors.getHardwareWalletType(mockState)).toBe( KeyringType.ledger, ); }); it('returns "Trezor Hardware" if it is a Trezor HW wallet', () => { - mockState.metamask.keyrings[0].type = KeyringType.trezor; + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].metadata.keyring.type = KeyringType.trezor; expect(selectors.getHardwareWalletType(mockState)).toBe( KeyringType.trezor, ); From dfd0f137293502aa8d5f4c93860a5f04a0b3798b Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 27 Jul 2023 17:47:22 +0800 Subject: [PATCH 017/235] feat: add snap keyring to switch case --- ui/selectors/selectors.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 184df4c4dc4f..95b9f10c4c8f 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -262,6 +262,10 @@ export function getAccountTypeForKeyring(keyring) { return 'hardware'; case KeyringType.imported: return 'imported'; + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) + case KeyringType.snap: + return 'snap'; + ///: END:ONLY_INCLUDE_IN default: return 'default'; } From 2a19e3911cfa9d614c7c08720a63a1caaa29a812 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Sat, 29 Jul 2023 01:28:27 +0800 Subject: [PATCH 018/235] fix: tests for ui/pages ui/hooks ui/components --- .../controllers/accounts-controller.ts | 6 + app/scripts/metamask-controller.js | 80 ++++++------ test/data/mock-send-state.json | 97 ++++++++++++++ test/data/mock-state.json | 18 --- test/jest/mock-store.js | 98 +++++++++++++- .../unconnected-account-alert.js | 9 +- .../unconnected-account-alert.test.js | 62 +++++++-- ...m-page-container-content.component.test.js | 97 ++++++++++++++ .../confirm-page-container.component.js | 6 +- .../confirm-page-container.container.js | 6 +- .../connected-status-indicator.js | 4 +- .../edit-gas-fee-popover.test.js | 29 ++++- .../edit-gas-item/edit-gas-item.test.js | 29 ++++- .../edit-gas-tooltip/edit-gas-tooltip.test.js | 29 ++++- .../gas-details-item-title.test.js | 29 ++++- .../account-details-modal.component.js | 18 ++- .../account-details-modal.container.js | 5 +- .../account-details-modal.test.js | 43 +++--- .../account-modal-container.component.js | 6 +- .../account-modal-container.container.js | 5 +- .../confirm-remove-account.test.js.snap | 16 +-- .../confirm-remove-account.component.js | 3 +- .../confirm-remove-account.container.js | 2 +- .../confirm-remove-account.stories.js | 4 +- .../confirm-remove-account.test.js | 53 +++++++- .../edit-approval-permission.component.js | 6 +- .../edit-approval-permission.container.js | 4 +- .../export-private-key-modal.component.js | 10 +- ...export-private-key-modal.component.test.js | 30 ++++- .../export-private-key-modal.container.js | 8 +- .../export-private-key-modal.stories.js | 6 +- ui/components/app/nft-details/nft-details.js | 6 +- ui/components/app/nfts-items/nfts-items.js | 4 +- ui/components/app/nfts-tab/nfts-tab.test.js | 29 ++++- .../selected-account.component.js | 12 +- .../selected-account.container.js | 4 +- .../signature-request-original.test.js | 20 +++ .../signature-request-siwe.test.js | 4 + .../signature-request-data.js | 9 +- .../signature-request-data.test.js | 57 ++++++-- .../signature-request.test.js | 67 +++++++++- ...transaction-list-item-details.component.js | 6 +- ...transaction-list-item-details.container.js | 10 +- .../transaction-status-label.test.js | 123 +++++++++++++++--- .../app/wallet-overview/eth-overview.test.js | 57 +++++++- .../wallet-overview/token-overview.test.js | 30 ++++- .../app/wallet-overview/wallet-overview.js | 6 +- .../interactive-replacement-token-modal.js | 4 +- ...eractive-replacement-token-notification.js | 7 +- ...ive-replacement-token-notification.test.js | 39 ++++-- .../wrong-network-notification.test.js | 30 ++++- .../account-list-menu/account-list-menu.js | 4 +- .../multichain/app-header/app-header.js | 17 ++- .../connected-site-menu.js | 4 +- .../connected-site-menu.test.js | 62 +++++++-- .../create-account/create-account.js | 12 +- ui/ducks/alerts/unconnected-account.js | 7 +- ui/ducks/metamask/metamask.js | 32 +++-- ui/ducks/send/send.js | 6 +- ui/ducks/send/send.test.js | 90 ++++++++++++- ui/hooks/useAddressDetails.js | 12 +- ui/hooks/useAddressDetails.test.js | 60 ++++++++- ui/hooks/useAssetDetails.test.js | 28 ++++ ui/hooks/useNftsCollections.js | 4 +- ui/hooks/useTokenTracker.js | 7 +- ui/index.js | 5 +- ui/pages/asset/components/native-asset.js | 9 +- ui/pages/asset/components/token-asset.js | 8 +- .../confirm-add-suggested-token.test.js | 28 ++++ .../confirm-import-token.test.js | 28 ++++ .../confirm-send-ether.test.js.snap | 2 +- .../confirm-signature-request/index.test.js | 36 +++-- .../confirm-token-transaction-base.js | 4 +- .../confirm-transaction-base.test.js.snap | 4 +- .../confirm-transaction-base.container.js | 16 +-- .../confirm-transaction-base.test.js | 31 ++++- .../connected-accounts.container.js | 4 +- .../connected-sites.container.js | 4 +- .../create-password/create-password.test.js | 6 +- .../import-srp/import-srp.test.js | 6 +- .../onboarding-flow/onboarding-flow.test.js | 5 +- .../onboarding-flow/welcome/welcome.test.js | 6 +- .../permissions-connect.container.js | 4 +- .../add-recipient.component.test.js.snap | 108 +++++++-------- ui/pages/send/send.test.js | 30 ++++- ...swaps-quotes-stories-metadata.test.js.snap | 14 +- .../token-allowance/token-allowance.test.js | 57 ++++++-- .../token-details/token-details-page.test.js | 98 +++++++++++++- ui/selectors/institutional/selectors.js | 6 +- ui/selectors/institutional/selectors.test.js | 40 ++++-- ...nonce-sorted-transactions-selector.test.js | 28 ++++ ui/selectors/permissions.js | 6 +- ui/selectors/selectors.js | 93 ++++++++----- ui/selectors/selectors.test.js | 75 +++++++---- ui/selectors/transactions.js | 12 +- ui/selectors/transactions.test.js | 115 +++++++++++++++- ui/store/actions.test.js | 61 ++++++++- ui/store/actions.ts | 38 ++---- ui/store/store.ts | 4 +- 99 files changed, 2126 insertions(+), 552 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index afb8d1bcb933..1b9a22d0bc3d 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -196,6 +196,12 @@ export default class AccountsController extends BaseControllerV2< ); } + getSelectedAccount(): InternalAccount { + return this.getAccountByIdExpect( + this.state.internalAccounts.selectedAccount, + ); + } + async updateAccounts(): Promise { const legacyAccounts = await this.#listLegacyAccounts(); const snapAccounts = await this.#listSnapAccounts(); diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index d0527843949a..ef99c4375e33 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1657,6 +1657,7 @@ export default class MetamaskController extends EventEmitter { this.store.updateStructure({ AppStateController: this.appStateController.store, + AccountsController: this.accountsController, TransactionController: this.txController.store, KeyringController: this.keyringController.store, PreferencesController: this.preferencesController.store, @@ -2357,9 +2358,8 @@ export default class MetamaskController extends EventEmitter { ), addToken: tokensController.addToken.bind(tokensController), updateTokenType: tokensController.updateTokenType.bind(tokensController), - setAccountLabel: preferencesController.setAccountLabel.bind( - preferencesController, - ), + setAccountLabel: + accountsController.setAccountName.bind(accountsController), setFeatureFlag: preferencesController.setFeatureFlag.bind( preferencesController, ), @@ -3006,14 +3006,16 @@ export default class MetamaskController extends EventEmitter { this.setLedgerTransportPreference(transportPreference); await this.accountsController.updateAccounts(); - const selectedAccount = uuid({ - random: sha256FromString( - this.preferencesController.getSelectedAddress(), - ).slice(0, 16), - }); - - console.log('setting account'); - this.accountsController.setSelectedAccount(selectedAccount); + // const selectedAccount = uuid({ + // random: sha256FromString( + // this.preferencesController.getSelectedAddress(), + // ).slice(0, 16), + // }); + + // console.log('setting account'); + this.accountsController.setSelectedAccount( + 'd92ecbfc-a77e-4d60-ac22-dd0ac927f398', + ); // set new identities this.preferencesController.setAddresses(accounts); @@ -3081,13 +3083,16 @@ export default class MetamaskController extends EventEmitter { this.setLedgerTransportPreference(transportPreference); await this.accountsController.updateAccounts(); - const selectedAccount = uuid({ - random: sha256FromString( - this.preferencesController.getSelectedAddress(), - ).slice(0, 16), - }); - - this.accountsController.setSelectedAccount(selectedAccount); + // const selectedAccount = uuid({ + // random: sha256FromString( + // this.preferencesController.getSelectedAddress(), + // ).slice(0, 16), + // }); + + // console.log('setting account'); + this.accountsController.setSelectedAccount( + 'd92ecbfc-a77e-4d60-ac22-dd0ac927f398', + ); return this.keyringController.fullUpdate(); } @@ -3440,10 +3445,10 @@ export default class MetamaskController extends EventEmitter { /** * Adds a new account to the default (first) HD seed phrase Keyring. * - * @param accountCount + * @param accountName * @returns {} keyState */ - async addNewAccount(accountCount) { + async addNewAccount(accountName) { const isActionMetricsQueueE2ETest = this.appStateController.store.getState()[ACTION_QUEUE_METRICS_E2E_TEST]; @@ -3458,30 +3463,18 @@ export default class MetamaskController extends EventEmitter { throw new Error('MetamaskController - No HD Key Tree found'); } const { keyringController } = this; - const { identities: oldIdentities } = - this.preferencesController.store.getState(); - - if (Object.keys(oldIdentities).length === accountCount) { - const oldAccounts = await keyringController.getAccounts(); - const keyState = await keyringController.addNewAccount(primaryKeyring); - const newAccounts = await keyringController.getAccounts(); - - await this.verifySeedPhrase(); - - this.preferencesController.setAddresses(newAccounts); - newAccounts.forEach((address) => { - if (!oldAccounts.includes(address)) { - this.preferencesController.setSelectedAddress(address); - } - }); + await keyringController.addNewAccount(primaryKeyring); + await this.accountsController.updateAccounts(); + let newAccount = this.accountsController.getSelectedAccount(); - const { identities } = this.preferencesController.store.getState(); - return { ...keyState, identities }; + if (accountName) { + this.accountsController.setAccountName(newAccount.id, accountName); + newAccount = this.accountsController.getSelectedAccount(); } return { ...keyringController.memStore.getState(), - identities: oldIdentities, + account: newAccount, }; } @@ -3587,13 +3580,14 @@ export default class MetamaskController extends EventEmitter { /** * Removes an account from state / storage. * - * @param {string[]} address - A hex address + * @param {string[]} accountId - A uuid of the account to remove. */ - async removeAccount(address) { + async removeAccount(accountId) { + const { address } = this.accountsController.getAccountByIdExpect(accountId); + // Remove all associated permissions this.removeAllAccountPermissions(address); - // Remove account from the preferences controller - this.preferencesController.removeAddress(address); + // Remove account from the account tracker controller this.accountTracker.removeAccount([address]); diff --git a/test/data/mock-send-state.json b/test/data/mock-send-state.json index 0193c3ce53d1..7472dde80354 100644 --- a/test/data/mock-send-state.json +++ b/test/data/mock-send-state.json @@ -119,6 +119,103 @@ "type": "rpc", "chainId": "0x5" }, + "internalAccounts": { + "accounts": { + "cf8dace4-9439-4bd4-b3a8-88c821c8fcb3": { + "address": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", + "id": "cf8dace4-9439-4bd4-b3a8-88c821c8fcb3", + "metadata": { + "keyring": { + "type": "HD Key Tree" + } + }, + "name": "Test Account", + "options": {}, + "supportedMethods": [ + "personal_sign", + "eth_sendTransaction", + "eth_sign", + "eth_signTransaction", + "eth_signTypedData", + "eth_signTypedData_v1", + "eth_signTypedData_v2", + "eth_signTypedData_v3", + "eth_signTypedData_v4" + ], + "type": "eip155:eoa" + }, + "07c2cfec-36c9-46c4-8115-3836d3ac9047": { + "address": "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b", + "id": "07c2cfec-36c9-46c4-8115-3836d3ac9047", + "metadata": { + "keyring": { + "type": "HD Key Tree" + } + }, + "name": "Test Account 2", + "options": {}, + "supportedMethods": [ + "personal_sign", + "eth_sendTransaction", + "eth_sign", + "eth_signTransaction", + "eth_signTypedData", + "eth_signTypedData_v1", + "eth_signTypedData_v2", + "eth_signTypedData_v3", + "eth_signTypedData_v4" + ], + "type": "eip155:eoa" + }, + "15e69915-2a1a-4019-93b3-916e11fd432f": { + "address": "0xc42edfcc21ed14dda456aa0756c153f7985d8813", + "id": "15e69915-2a1a-4019-93b3-916e11fd432f", + "metadata": { + "keyring": { + "type": "Ledger Hardware" + } + }, + "name": "Ledger Hardware 2", + "options": {}, + "supportedMethods": [ + "personal_sign", + "eth_sendTransaction", + "eth_sign", + "eth_signTransaction", + "eth_signTypedData", + "eth_signTypedData_v1", + "eth_signTypedData_v2", + "eth_signTypedData_v3", + "eth_signTypedData_v4" + ], + "type": "eip155:eoa" + }, + "784225f4-d30b-4e77-a900-c8bbce735b88": { + "address": "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b", + "id": "784225f4-d30b-4e77-a900-c8bbce735b88", + "metadata": { + "keyring": { + "type": "HD Key Tree" + } + }, + "name": "Test Account 3", + "options": {}, + "supportedMethods": [ + "personal_sign", + "eth_sendTransaction", + "eth_sign", + "eth_signTransaction", + "eth_signTypedData", + "eth_signTypedData_v1", + "eth_signTypedData_v2", + "eth_signTypedData_v3", + "eth_signTypedData_v4" + ], + "type": "eip155:eoa" + } + }, + "selectedAccount": "cf8dace4-9439-4bd4-b3a8-88c821c8fcb3" + }, "keyrings": [ { "type": "HD Key Tree", diff --git a/test/data/mock-state.json b/test/data/mock-state.json index 2261d196d1de..c4fedf33797c 100644 --- a/test/data/mock-state.json +++ b/test/data/mock-state.json @@ -251,24 +251,6 @@ "accounts": ["0xb552685e3d2790efd64a175b00d51f02cdafee5d"] } ], - "identities": { - "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": { - "address": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", - "name": "Test Account" - }, - "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b": { - "address": "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b", - "name": "Test Account 2" - }, - "0xc42edfcc21ed14dda456aa0756c153f7985d8813": { - "address": "0xc42edfcc21ed14dda456aa0756c153f7985d8813", - "name": "Test Ledger 1" - }, - "0xeb9e64b93097bc15f01f13eae97015c57ab64823": { - "name": "Test Account 3", - "address": "0xeb9e64b93097bc15f01f13eae97015c57ab64823" - } - }, "networkDetails": { "EIPS": { "1559": true diff --git a/test/jest/mock-store.js b/test/jest/mock-store.js index ef05b7ba37b5..abafa21b48d7 100644 --- a/test/jest/mock-store.js +++ b/test/jest/mock-store.js @@ -223,6 +223,103 @@ export const createSwapsMockStore = () => { '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48': 2, '0x1111111111111111111111111111111111111111': 0.1, }, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '07c2cfec-36c9-46c4-8115-3836d3ac9047': { + address: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb', + id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '15e69915-2a1a-4019-93b3-916e11fd432f': { + address: '0x2f8d4a878cfa04a6e60d46362f5644deab66572d', + id: '15e69915-2a1a-4019-93b3-916e11fd432f', + metadata: { + keyring: { + type: 'Ledger Hardware', + }, + }, + name: 'Ledger Hardware 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '784225f4-d30b-4e77-a900-c8bbce735b88': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: '784225f4-d30b-4e77-a900-c8bbce735b88', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account 3', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, identities: { '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825': { address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825', @@ -251,7 +348,6 @@ export const createSwapsMockStore = () => { balance: '0x0', }, }, - selectedAddress: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', currentLocale: 'en', keyringTypes: [KeyringType.imported, KeyringType.hdKeyTree], keyrings: [ diff --git a/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js b/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js index 1a64b0aa0bbb..dca99e075de8 100644 --- a/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js +++ b/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js @@ -12,8 +12,7 @@ import { import { getOriginOfCurrentTab, getOrderedConnectedAccountsForActiveTab, - getSelectedAddress, - getSelectedIdentity, + getSelectedInternalAccount, } from '../../../../selectors'; import { isExtensionUrl, getURLHost } from '../../../../helpers/utils/util'; import Popover from '../../../ui/popover'; @@ -34,8 +33,8 @@ const UnconnectedAccountAlert = () => { getOrderedConnectedAccountsForActiveTab, ); const origin = useSelector(getOriginOfCurrentTab); - const selectedIdentity = useSelector(getSelectedIdentity); - const selectedAddress = useSelector(getSelectedAddress); + const account = useSelector(getSelectedInternalAccount); + const { address: selectedAddress } = account; const [dontShowThisAgain, setDontShowThisAgain] = useState(false); const onClose = async () => { @@ -98,7 +97,7 @@ const UnconnectedAccountAlert = () => { footer={footer} > dispatch(connectAccount(selectedAddress))} connectedAccounts={connectedAccounts} selectedAddress={selectedAddress} diff --git a/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.test.js b/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.test.js index 10c514743429..89d8c8872486 100644 --- a/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.test.js +++ b/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.test.js @@ -16,17 +16,56 @@ import { KeyringType } from '../../../../../shared/constants/keyring'; import UnconnectedAccountAlert from '.'; describe('Unconnected Account Alert', () => { - const selectedAddress = '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b'; - - const identities = { - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { - address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - name: 'Account 1', - }, - '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b': { - address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', - name: 'Account 2', + const internalAccounts = { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '07c2cfec-36c9-46c4-8115-3836d3ac9047': { + address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', + id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', }; const accounts = { @@ -59,8 +98,7 @@ describe('Unconnected Account Alert', () => { const mockState = { metamask: { - selectedAddress, - identities, + internalAccounts, accounts, cachedBalances, keyrings, diff --git a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.test.js b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.test.js index aeef6f51b324..3862b36a5db8 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.test.js +++ b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.test.js @@ -26,6 +26,103 @@ describe('Confirm Page Container Content', () => { }, }, }, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '07c2cfec-36c9-46c4-8115-3836d3ac9047': { + address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', + id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '15e69915-2a1a-4019-93b3-916e11fd432f': { + address: '0xc42edfcc21ed14dda456aa0756c153f7985d8813', + id: '15e69915-2a1a-4019-93b3-916e11fd432f', + metadata: { + keyring: { + type: 'Ledger Hardware', + }, + }, + name: 'Ledger Hardware 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '784225f4-d30b-4e77-a900-c8bbce735b88': { + address: '0xeb9e64b93097bc15f01f13eae97015c57ab64823', + id: '784225f4-d30b-4e77-a900-c8bbce735b88', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account 3', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, }, }; diff --git a/ui/components/app/confirm-page-container/confirm-page-container.component.js b/ui/components/app/confirm-page-container/confirm-page-container.component.js index e40dc23a2887..be0040021163 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container.component.js +++ b/ui/components/app/confirm-page-container/confirm-page-container.component.js @@ -45,9 +45,9 @@ import useTransactionInsights from '../../../hooks/useTransactionInsights'; import { getAccountName, getAddressBookEntry, + getInternalAccounts, getIsBuyableChain, getMetadataContractName, - getMetaMaskIdentities, getNetworkIdentifier, getSwapsDefaultToken, } from '../../../selectors'; @@ -124,8 +124,8 @@ const ConfirmPageContainer = (props) => { const networkIdentifier = useSelector(getNetworkIdentifier); const defaultToken = useSelector(getSwapsDefaultToken); const accountBalance = defaultToken.string; - const identities = useSelector(getMetaMaskIdentities); - const ownedAccountName = getAccountName(identities, toAddress); + const accounts = useSelector(getInternalAccounts); + const ownedAccountName = getAccountName(accounts, toAddress); const toName = ownedAccountName || contact?.name; const recipientIsOwnedAccount = Boolean(ownedAccountName); const toMetadataName = useSelector((state) => diff --git a/ui/components/app/confirm-page-container/confirm-page-container.container.js b/ui/components/app/confirm-page-container/confirm-page-container.container.js index fb628fbb2ee5..2815b600f5b5 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container.container.js +++ b/ui/components/app/confirm-page-container/confirm-page-container.container.js @@ -6,7 +6,7 @@ import { getSwapsDefaultToken, getMetadataContractName, getAccountName, - getMetaMaskIdentities, + getInternalAccounts, } from '../../../selectors'; import ConfirmPageContainer from './confirm-page-container.component'; @@ -17,8 +17,8 @@ function mapStateToProps(state, ownProps) { const networkIdentifier = getNetworkIdentifier(state); const defaultToken = getSwapsDefaultToken(state); const accountBalance = defaultToken.string; - const identities = getMetaMaskIdentities(state); - const ownedAccountName = getAccountName(identities, to); + const accounts = getInternalAccounts(state); + const ownedAccountName = getAccountName(accounts, to); const toName = ownedAccountName || contact?.name; const toMetadataName = getMetadataContractName(state, to); diff --git a/ui/components/app/connected-status-indicator/connected-status-indicator.js b/ui/components/app/connected-status-indicator/connected-status-indicator.js index c1a4eae402f0..4099bd17ceb8 100644 --- a/ui/components/app/connected-status-indicator/connected-status-indicator.js +++ b/ui/components/app/connected-status-indicator/connected-status-indicator.js @@ -15,14 +15,14 @@ import { useI18nContext } from '../../../hooks/useI18nContext'; import { getAddressConnectedSubjectMap, getOriginOfCurrentTab, - getSelectedAddress, + getSelectedInternalAccount, } from '../../../selectors'; import { ConnectedSiteMenu } from '../../multichain'; export default function ConnectedStatusIndicator({ onClick }) { const t = useI18nContext(); - const selectedAddress = useSelector(getSelectedAddress); + const { address: selectedAddress } = useSelector(getSelectedInternalAccount); const addressConnectedSubjectMap = useSelector(getAddressConnectedSubjectMap); const originOfCurrentTab = useSelector(getOriginOfCurrentTab); diff --git a/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.test.js b/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.test.js index 3e371a05d782..8205f79472ac 100644 --- a/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.test.js +++ b/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.test.js @@ -61,7 +61,34 @@ const render = ({ txProps, contextProps } = {}) => { balance: '0x1F4', }, }, - selectedAddress: '0xAddress', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xAddress', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, featureFlags: { advancedInlineGas: true }, gasFeeEstimates: MOCK_FEE_ESTIMATE, }, diff --git a/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.test.js b/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.test.js index 44ac34b879a6..b82507283a2f 100644 --- a/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.test.js +++ b/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.test.js @@ -67,7 +67,34 @@ const renderComponent = ({ balance: '0x176e5b6f173ebe66', }, }, - selectedAddress: '0xAddress', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xAddress', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, featureFlags: { advancedInlineGas: true }, gasEstimateType: 'fee-market', gasFeeEstimates: MOCK_FEE_ESTIMATE, diff --git a/ui/components/app/edit-gas-fee-popover/edit-gas-tooltip/edit-gas-tooltip.test.js b/ui/components/app/edit-gas-fee-popover/edit-gas-tooltip/edit-gas-tooltip.test.js index dbeda43ac7ae..b2cbed5df009 100644 --- a/ui/components/app/edit-gas-fee-popover/edit-gas-tooltip/edit-gas-tooltip.test.js +++ b/ui/components/app/edit-gas-fee-popover/edit-gas-tooltip/edit-gas-tooltip.test.js @@ -41,7 +41,34 @@ const renderComponent = (componentProps) => { balance: '0x176e5b6f173ebe66', }, }, - selectedAddress: '0xAddress', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xAddress', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, featureFlags: { advancedInlineGas: true }, }, }; diff --git a/ui/components/app/gas-details-item/gas-details-item-title/gas-details-item-title.test.js b/ui/components/app/gas-details-item/gas-details-item-title/gas-details-item-title.test.js index 9d8f36c4eeaf..f1e9837e7819 100644 --- a/ui/components/app/gas-details-item/gas-details-item-title/gas-details-item-title.test.js +++ b/ui/components/app/gas-details-item/gas-details-item-title/gas-details-item-title.test.js @@ -28,7 +28,34 @@ const render = () => { balance: '0x176e5b6f173ebe66', }, }, - selectedAddress: '0xAddress', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xAddress', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, }, }); diff --git a/ui/components/app/modals/account-details-modal/account-details-modal.component.js b/ui/components/app/modals/account-details-modal/account-details-modal.component.js index 1a759713b711..d4f805e6cff6 100644 --- a/ui/components/app/modals/account-details-modal/account-details-modal.component.js +++ b/ui/components/app/modals/account-details-modal/account-details-modal.component.js @@ -24,11 +24,10 @@ import { NETWORKS_ROUTE } from '../../../../helpers/constants/routes'; export default class AccountDetailsModal extends Component { static propTypes = { - selectedIdentity: PropTypes.object, + selectedAccount: PropTypes.object, chainId: PropTypes.string, showExportPrivateKeyModal: PropTypes.func, setAccountLabel: PropTypes.func, - keyrings: PropTypes.array, rpcPrefs: PropTypes.object, accounts: PropTypes.array, history: PropTypes.object, @@ -47,11 +46,10 @@ export default class AccountDetailsModal extends Component { render() { const { - selectedIdentity, + selectedAccount, chainId, showExportPrivateKeyModal, setAccountLabel, - keyrings, rpcPrefs, history, hideModal, @@ -61,11 +59,11 @@ export default class AccountDetailsModal extends Component { custodyAccountDetails, ///: END:ONLY_INCLUDE_IN } = this.props; - const { name, address } = selectedIdentity; - - const keyring = keyrings.find((kr) => { - return kr.accounts.includes(address); - }); + const { + name, + address, + metadata: { keyring }, + } = selectedAccount; let exportPrivateKeyFeatureEnabled = isAbleToExportAccount(keyring?.type); @@ -75,7 +73,7 @@ export default class AccountDetailsModal extends Component { } const showCustodyLabels = accountType === 'custody'; const custodyLabels = custodyAccountDetails - ? custodyAccountDetails[toChecksumHexAddress(selectedIdentity.address)] + ? custodyAccountDetails[toChecksumHexAddress(selectedAccount.address)] ?.labels : {}; ///: END:ONLY_INCLUDE_IN diff --git a/ui/components/app/modals/account-details-modal/account-details-modal.container.js b/ui/components/app/modals/account-details-modal/account-details-modal.container.js index 0e10c08608f2..ede3245af5b4 100644 --- a/ui/components/app/modals/account-details-modal/account-details-modal.container.js +++ b/ui/components/app/modals/account-details-modal/account-details-modal.container.js @@ -7,13 +7,13 @@ import { hideModal, } from '../../../../store/actions'; import { - getSelectedIdentity, getRpcPrefsForCurrentProvider, getCurrentChainId, getMetaMaskAccountsOrdered, getBlockExplorerLinkText, ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) getAccountType, + getSelectedInternalAccount, ///: END:ONLY_INCLUDE_IN } from '../../../../selectors'; ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) @@ -24,8 +24,7 @@ import AccountDetailsModal from './account-details-modal.component'; const mapStateToProps = (state) => { return { chainId: getCurrentChainId(state), - selectedIdentity: getSelectedIdentity(state), - keyrings: state.metamask.keyrings, + selectedAccount: getSelectedInternalAccount(state), rpcPrefs: getRpcPrefsForCurrentProvider(state), accounts: getMetaMaskAccountsOrdered(state), blockExplorerLinkText: getBlockExplorerLinkText(state, true), diff --git a/ui/components/app/modals/account-details-modal/account-details-modal.test.js b/ui/components/app/modals/account-details-modal/account-details-modal.test.js index 259da80cace6..ac759893f4bd 100644 --- a/ui/components/app/modals/account-details-modal/account-details-modal.test.js +++ b/ui/components/app/modals/account-details-modal/account-details-modal.test.js @@ -150,23 +150,33 @@ describe('Account Details Modal', () => { accounts: ['0xeb9e64b93097bc15f01f13eae97015c57ab64823'], }, ], - identities: { - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { - address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - name: 'Test Account', - }, - '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b': { - address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', - name: 'Test Account 2', - }, - '0xc42edfcc21ed14dda456aa0756c153f7985d8813': { - address: '0xc42edfcc21ed14dda456aa0756c153f7985d8813', - name: 'Test Ledger 1', - }, - '0xeb9e64b93097bc15f01f13eae97015c57ab64823': { - name: 'Test Account 3', - address: '0xeb9e64b93097bc15f01f13eae97015c57ab64823', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'Snap Keyring', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', }, networkDetails: { EIPS: { @@ -199,7 +209,6 @@ describe('Account Details Modal', () => { }, cachedBalances: {}, incomingTransactions: {}, - selectedAddress: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', accounts: { '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { balance: '0x346ba7725f412cbfdb', diff --git a/ui/components/app/modals/account-modal-container/account-modal-container.component.js b/ui/components/app/modals/account-modal-container/account-modal-container.component.js index db93a2dc56f2..364191637206 100644 --- a/ui/components/app/modals/account-modal-container/account-modal-container.component.js +++ b/ui/components/app/modals/account-modal-container/account-modal-container.component.js @@ -6,7 +6,7 @@ import Identicon from '../../../ui/identicon'; export default function AccountModalContainer(props, context) { const { className, - selectedIdentity, + selectedAccount, showBackButton, backButtonAction, hideModal, @@ -20,7 +20,7 @@ export default function AccountModalContainer(props, context) { >
- +
{showBackButton && (
@@ -49,7 +49,7 @@ AccountModalContainer.defaultProps = { AccountModalContainer.propTypes = { className: PropTypes.string, - selectedIdentity: PropTypes.object.isRequired, + selectedAccount: PropTypes.object.isRequired, showBackButton: PropTypes.bool, backButtonAction: PropTypes.func, hideModal: PropTypes.func.isRequired, diff --git a/ui/components/app/modals/account-modal-container/account-modal-container.container.js b/ui/components/app/modals/account-modal-container/account-modal-container.container.js index 0fb64bf1f0e3..83efa13f90c4 100644 --- a/ui/components/app/modals/account-modal-container/account-modal-container.container.js +++ b/ui/components/app/modals/account-modal-container/account-modal-container.container.js @@ -1,11 +1,12 @@ import { connect } from 'react-redux'; import { hideModal } from '../../../../store/actions'; -import { getSelectedIdentity } from '../../../../selectors'; +import { getSelectedInternalAccount } from '../../../../selectors'; import AccountModalContainer from './account-modal-container.component'; function mapStateToProps(state, ownProps) { return { - selectedIdentity: ownProps.selectedIdentity || getSelectedIdentity(state), + selectedAccount: + ownProps.selectedAccount || getSelectedInternalAccount(state), }; } diff --git a/ui/components/app/modals/confirm-remove-account/__snapshots__/confirm-remove-account.test.js.snap b/ui/components/app/modals/confirm-remove-account/__snapshots__/confirm-remove-account.test.js.snap index 0585d2b1d6b3..501ce9397d4a 100644 --- a/ui/components/app/modals/confirm-remove-account/__snapshots__/confirm-remove-account.test.js.snap +++ b/ui/components/app/modals/confirm-remove-account/__snapshots__/confirm-remove-account.test.js.snap @@ -36,7 +36,7 @@ exports[`Confirm Remove Account should match snapshot 1`] = ` style="height: 32px; width: 32px; border-radius: 16px;" >
{ this.props - .removeAccount(this.props.account.address) + .removeAccount(this.props.account.id) .then(() => this.props.hideModal()); }; diff --git a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.container.js b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.container.js index c7c07d0dfd8b..1c74a92e5215 100644 --- a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.container.js +++ b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.container.js @@ -17,7 +17,7 @@ const mapStateToProps = (state) => { const mapDispatchToProps = (dispatch) => { return { - removeAccount: (address) => dispatch(removeAccount(address)), + removeAccount: (accountId) => dispatch(removeAccount(accountId)), }; }; diff --git a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.stories.js b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.stories.js index b7f9bcea2bb8..6d2610b0103a 100644 --- a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.stories.js +++ b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.stories.js @@ -6,12 +6,12 @@ export default { component: ConfirmRemoveAccount, argTypes: { - identity: { + account: { control: 'object', }, }, args: { - identity: { + account: { control: 'object', }, }, diff --git a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.test.js b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.test.js index 39e353565ea9..70ef3e919f03 100644 --- a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.test.js +++ b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.test.js @@ -10,15 +10,62 @@ describe('Confirm Remove Account', () => { providerConfig: { chainId: '0x99', }, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, }, }; const props = { hideModal: jest.fn(), removeAccount: jest.fn().mockResolvedValue(), - identity: { - address: '0x0', + account: { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, chainId: '0x99', rpcPrefs: {}, @@ -55,7 +102,7 @@ describe('Confirm Remove Account', () => { fireEvent.click(queryByText('Remove')); - expect(props.removeAccount).toHaveBeenCalledWith(props.identity.address); + expect(props.removeAccount).toHaveBeenCalledWith(props.account.id); expect(props.hideModal).toHaveBeenCalled(); }); diff --git a/ui/components/app/modals/edit-approval-permission/edit-approval-permission.component.js b/ui/components/app/modals/edit-approval-permission/edit-approval-permission.component.js index caccc2ad6874..14e488246dfe 100644 --- a/ui/components/app/modals/edit-approval-permission/edit-approval-permission.component.js +++ b/ui/components/app/modals/edit-approval-permission/edit-approval-permission.component.js @@ -22,7 +22,7 @@ export default class EditApprovalPermission extends PureComponent { static propTypes = { decimals: PropTypes.number, hideModal: PropTypes.func.isRequired, - selectedIdentity: PropTypes.object, + selectedAccount: PropTypes.object, tokenAmount: PropTypes.string, customTokenAmount: PropTypes.string, tokenSymbol: PropTypes.string, @@ -46,14 +46,14 @@ export default class EditApprovalPermission extends PureComponent { const { t } = this.context; const { hideModal, - selectedIdentity, + selectedAccount, tokenAmount, tokenSymbol, tokenBalance, customTokenAmount, origin, } = this.props; - const { name, address } = selectedIdentity || {}; + const { name, address } = selectedAccount || {}; const { selectedOptionIsUnlimited } = this.state; return ( diff --git a/ui/components/app/modals/edit-approval-permission/edit-approval-permission.container.js b/ui/components/app/modals/edit-approval-permission/edit-approval-permission.container.js index 4a3777c72400..73cdd08eb5c5 100644 --- a/ui/components/app/modals/edit-approval-permission/edit-approval-permission.container.js +++ b/ui/components/app/modals/edit-approval-permission/edit-approval-permission.container.js @@ -1,13 +1,13 @@ import { connect } from 'react-redux'; import { compose } from 'redux'; import withModalProps from '../../../../helpers/higher-order-components/with-modal-props'; -import { getSelectedIdentity } from '../../../../selectors'; +import { getSelectedInternalAccount } from '../../../../selectors'; import EditApprovalPermission from './edit-approval-permission.component'; const mapStateToProps = (state) => { const modalStateProps = state.appState.modal.modalState.props || {}; return { - selectedIdentity: getSelectedIdentity(state), + selectedAccount: getSelectedInternalAccount(state), ...modalStateProps, }; }; diff --git a/ui/components/app/modals/export-private-key-modal/export-private-key-modal.component.js b/ui/components/app/modals/export-private-key-modal/export-private-key-modal.component.js index 3fd86ef99f88..f1fb26753e3d 100644 --- a/ui/components/app/modals/export-private-key-modal/export-private-key-modal.component.js +++ b/ui/components/app/modals/export-private-key-modal/export-private-key-modal.component.js @@ -39,7 +39,7 @@ const ExportPrivateKeyModal = ({ clearAccountDetails, hideWarning, exportAccount, - selectedIdentity, + selectedAccount, showAccountDetailModal, hideModal, warning = null, @@ -93,13 +93,13 @@ const ExportPrivateKeyModal = ({ } }; - const { name, address } = selectedIdentity; + const { name, address } = selectedAccount; if (showHoldToReveal) { return ( showAccountDetailModal()} > @@ -115,7 +115,7 @@ const ExportPrivateKeyModal = ({ return ( showAccountDetailModal()} > @@ -235,7 +235,7 @@ const ExportPrivateKeyModal = ({ ExportPrivateKeyModal.propTypes = { exportAccount: PropTypes.func.isRequired, - selectedIdentity: PropTypes.object.isRequired, + selectedAccount: PropTypes.object.isRequired, warning: PropTypes.node, showAccountDetailModal: PropTypes.func.isRequired, hideModal: PropTypes.func.isRequired, diff --git a/ui/components/app/modals/export-private-key-modal/export-private-key-modal.component.test.js b/ui/components/app/modals/export-private-key-modal/export-private-key-modal.component.test.js index c435d85ce720..7b10ccf9f6dd 100644 --- a/ui/components/app/modals/export-private-key-modal/export-private-key-modal.component.test.js +++ b/ui/components/app/modals/export-private-key-modal/export-private-key-modal.component.test.js @@ -21,11 +21,33 @@ describe('Export Private Key Modal', () => { const state = { metamask: { selectedAddress: mockAddress, - identities: { - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { - address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - name: 'Test Account', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', }, providerConfig: { type: 'rpc', diff --git a/ui/components/app/modals/export-private-key-modal/export-private-key-modal.container.js b/ui/components/app/modals/export-private-key-modal/export-private-key-modal.container.js index 6dd8acd9287e..ab981c1c97de 100644 --- a/ui/components/app/modals/export-private-key-modal/export-private-key-modal.container.js +++ b/ui/components/app/modals/export-private-key-modal/export-private-key-modal.container.js @@ -6,21 +6,21 @@ import { hideModal, clearAccountDetails, } from '../../../../store/actions'; -import { getSelectedIdentity } from '../../../../selectors'; +import { getSelectedInternalAccount } from '../../../../selectors'; import ExportPrivateKeyModal from './export-private-key-modal.component'; function mapStateToPropsFactory() { - let selectedIdentity = null; + let selectedAccount = null; return function mapStateToProps(state) { // We should **not** change the identity displayed here even if it changes from underneath us. // If we do, we will be showing the user one private key and a **different** address and name. // Note that the selected identity **will** change from underneath us when we unlock the keyring // which is the expected behavior that we are side-stepping. - selectedIdentity = selectedIdentity || getSelectedIdentity(state); + selectedAccount = selectedAccount || getSelectedInternalAccount(state); return { warning: state.appState.warning, privateKey: state.appState.accountDetail.privateKey, - selectedIdentity, + selectedAccount, previousModalState: state.appState.modal.previousModalState.name, }; }; diff --git a/ui/components/app/modals/export-private-key-modal/export-private-key-modal.stories.js b/ui/components/app/modals/export-private-key-modal/export-private-key-modal.stories.js index 36ba01b89c4c..893b03535c22 100644 --- a/ui/components/app/modals/export-private-key-modal/export-private-key-modal.stories.js +++ b/ui/components/app/modals/export-private-key-modal/export-private-key-modal.stories.js @@ -22,8 +22,10 @@ export const DefaultStory = () => { exportAccount={() => { return 'mockPrivateKey'; }} - selectedIdentity={ - testData.metamask.identities[testData.metamask.selectedAddress] + selectedAccount={ + testData.metamask.internalAccounts.accounts[ + testData.metamask.internalAccounts.selectedAccount + ] } /> ); diff --git a/ui/components/app/nft-details/nft-details.js b/ui/components/app/nft-details/nft-details.js index e6f8f9db226b..9d1f2f1c305a 100644 --- a/ui/components/app/nft-details/nft-details.js +++ b/ui/components/app/nft-details/nft-details.js @@ -26,7 +26,7 @@ import { getCurrentChainId, getCurrentNetwork, getIpfsGateway, - getSelectedIdentity, + getSelectedInternalAccount, } from '../../../selectors'; import AssetNavigation from '../../../pages/asset/components/asset-navigation'; import { getNftContracts } from '../../../ducks/metamask/metamask'; @@ -82,9 +82,7 @@ export default function NftDetails({ nft }) { const nftContractName = nftContracts.find(({ address: contractAddress }) => isEqualCaseInsensitive(contractAddress, address), )?.name; - const selectedAccountName = useSelector( - (state) => getSelectedIdentity(state).name, - ); + const { name: selectedAccountName } = useSelector(getSelectedInternalAccount); const nftImageAlt = getNftImageAlt(nft); const nftImageURL = getAssetImageURL(imageOriginal ?? image, ipfsGateway); const isDataURI = nftImageURL.startsWith('data:'); diff --git a/ui/components/app/nfts-items/nfts-items.js b/ui/components/app/nfts-items/nfts-items.js index ff044f4c2d7f..a3c09cfa22bb 100644 --- a/ui/components/app/nfts-items/nfts-items.js +++ b/ui/components/app/nfts-items/nfts-items.js @@ -20,7 +20,7 @@ import { getEnvironmentType } from '../../../../app/scripts/lib/util'; import { getCurrentChainId, getIpfsGateway, - getSelectedAddress, + getSelectedInternalAccount, getCurrentNetwork, } from '../../../selectors'; import { ASSET_ROUTE } from '../../../helpers/constants/routes'; @@ -48,7 +48,7 @@ export default function NftsItems({ const collectionsKeys = Object.keys(collections); const nftsDropdownState = useSelector(getNftsDropdownState); const previousCollectionKeys = usePrevious(collectionsKeys); - const selectedAddress = useSelector(getSelectedAddress); + const { address: selectedAddress } = useSelector(getSelectedInternalAccount); const chainId = useSelector(getCurrentChainId); const currentChain = useSelector(getCurrentNetwork); const t = useI18nContext(); diff --git a/ui/components/app/nfts-tab/nfts-tab.test.js b/ui/components/app/nfts-tab/nfts-tab.test.js index 218a7d74507f..43e142fb8733 100644 --- a/ui/components/app/nfts-tab/nfts-tab.test.js +++ b/ui/components/app/nfts-tab/nfts-tab.test.js @@ -164,7 +164,34 @@ const render = ({ }, }, providerConfig: { chainId }, - selectedAddress, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: selectedAddress, + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, useNftDetection, nftsDropdownState, }, diff --git a/ui/components/app/selected-account/selected-account.component.js b/ui/components/app/selected-account/selected-account.component.js index ad16dd6da9d6..a914665986ac 100644 --- a/ui/components/app/selected-account/selected-account.component.js +++ b/ui/components/app/selected-account/selected-account.component.js @@ -24,7 +24,7 @@ class SelectedAccount extends Component { }; static propTypes = { - selectedIdentity: PropTypes.object.isRequired, + selectedAccount: PropTypes.object.isRequired, ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) accountType: PropTypes.string, accountDetails: PropTypes.object, @@ -47,7 +47,7 @@ class SelectedAccount extends Component { render() { const { t } = this.context; const { - selectedIdentity, + selectedAccount, ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) accountType, accountDetails, @@ -56,7 +56,7 @@ class SelectedAccount extends Component { ///: END:ONLY_INCLUDE_IN } = this.props; - const checksummedAddress = toChecksumHexAddress(selectedIdentity.address); + const checksummedAddress = toChecksumHexAddress(selectedAccount.address); let title = this.state.copied ? t('copiedExclamation') @@ -66,7 +66,7 @@ class SelectedAccount extends Component { ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) const custodyLabels = accountDetails - ? accountDetails[toChecksumHexAddress(selectedIdentity.address)]?.labels + ? accountDetails[toChecksumHexAddress(selectedAccount.address)]?.labels : {}; const showCustodyLabels = getEnvironmentType() !== ENVIRONMENT_TYPE_POPUP && @@ -106,9 +106,7 @@ class SelectedAccount extends Component { copyToClipboard(checksummedAddress); }} > -
- {selectedIdentity.name} -
+
{selectedAccount.name}
{ ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) diff --git a/ui/components/app/selected-account/selected-account.container.js b/ui/components/app/selected-account/selected-account.container.js index 40bb2bbf219f..d7f92ed33270 100644 --- a/ui/components/app/selected-account/selected-account.container.js +++ b/ui/components/app/selected-account/selected-account.container.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import { - getSelectedIdentity, + getSelectedInternalAccount, ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) getAccountType, ///: END:ONLY_INCLUDE_IN @@ -16,7 +16,7 @@ import SelectedAccount from './selected-account.component'; const mapStateToProps = (state) => { return { - selectedIdentity: getSelectedIdentity(state), + selectedAccount: getSelectedInternalAccount(state), ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) accountType: getAccountType(state), accountDetails: getCustodyAccountDetails(state), diff --git a/ui/components/app/signature-request-original/signature-request-original.test.js b/ui/components/app/signature-request-original/signature-request-original.test.js index 030451514629..452eb580e613 100644 --- a/ui/components/app/signature-request-original/signature-request-original.test.js +++ b/ui/components/app/signature-request-original/signature-request-original.test.js @@ -65,6 +65,26 @@ const props = { }, selectedAccount: { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, }; diff --git a/ui/components/app/signature-request-siwe/signature-request-siwe.test.js b/ui/components/app/signature-request-siwe/signature-request-siwe.test.js index d09419dd12d1..f3da62f54264 100644 --- a/ui/components/app/signature-request-siwe/signature-request-siwe.test.js +++ b/ui/components/app/signature-request-siwe/signature-request-siwe.test.js @@ -22,6 +22,10 @@ const mockStoreInitialState = { }, }; +mockStoreInitialState.metamask.internalAccounts.accounts[ + mockStoreInitialState.metamask.internalAccounts.selectedAccount +].address = MOCK_ADDRESS; + const mockShowModal = jest.fn(); jest.mock('../../../store/actions.ts', () => { diff --git a/ui/components/app/signature-request/signature-request-data/signature-request-data.js b/ui/components/app/signature-request/signature-request-data/signature-request-data.js index 260945abafb7..7231a71dc355 100644 --- a/ui/components/app/signature-request/signature-request-data/signature-request-data.js +++ b/ui/components/app/signature-request/signature-request-data/signature-request-data.js @@ -2,10 +2,7 @@ import React, { memo } from 'react'; import { useSelector } from 'react-redux'; import { isEqual } from 'lodash'; import PropTypes from 'prop-types'; -import { - getMemoizedMetaMaskIdentities, - getAccountName, -} from '../../../../selectors'; +import { getAccountName, getInternalAccounts } from '../../../../selectors'; import Address from '../../transaction-decoding/components/decoding/address'; import { isValidHexAddress, @@ -21,7 +18,7 @@ import { sanitizeString } from '../../../../helpers/utils/util'; import { Box, Text } from '../../../component-library'; function SignatureRequestData({ data }) { - const identities = useSelector(getMemoizedMetaMaskIdentities); + const accounts = useSelector(getInternalAccounts); return ( @@ -68,7 +65,7 @@ function SignatureRequestData({ data }) {
) : ( diff --git a/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js b/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js index fd90d85db492..28c12e692e36 100644 --- a/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js +++ b/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js @@ -38,15 +38,56 @@ describe('Signature Request Data', () => { type: 'test', chainId: '0x5', }, - identities: { - '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826': { - name: 'Account 1', - address: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', - }, - '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF': { - name: 'Account 2', - address: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '07c2cfec-36c9-46c4-8115-3836d3ac9047': { + address: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF', + id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', }, addressBook: { '0x5': { diff --git a/ui/components/app/signature-request/signature-request.test.js b/ui/components/app/signature-request/signature-request.test.js index 4c500d3fdb3e..641f01e77c11 100644 --- a/ui/components/app/signature-request/signature-request.test.js +++ b/ui/components/app/signature-request/signature-request.test.js @@ -17,6 +17,7 @@ import { getMemoizedMetaMaskIdentities, getPreferences, getSelectedAccount, + getInternalAccounts, getTotalUnapprovedMessagesCount, unconfirmedTransactionsHashSelector, } from '../../../selectors'; @@ -49,7 +50,34 @@ const mockStore = { name: 'John Doe', }, }, - selectedAddress: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, nativeCurrency: 'ETH', currentCurrency: 'usd', conversionRate: null, @@ -81,7 +109,13 @@ const generateUseSelectorRouter = (opts) => (selector) => { case conversionRateSelector: return opts.metamask.conversionRate; case getSelectedAccount: - return opts.metamask.accounts[opts.metamask.selectedAddress]; + return opts.metamask.accounts[ + opts.metamask.internalAccounts.accounts[ + opts.metamask.internalAccounts.selectedAccount + ].address + ]; + case getInternalAccounts: + return Object.values(opts.metamask.internalAccounts.accounts); case getMemoizedAddressBook: return []; case accountsWithSendEtherInfoSelector: @@ -417,7 +451,6 @@ describe('Signature Request Component', () => { ...mockStore, metamask: { ...mockStore.metamask, - selectedAddress: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', accounts: { ...mockStore.metamask.accounts, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { @@ -426,6 +459,34 @@ describe('Signature Request Component', () => { name: 'Account 1', }, }, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, }, }), ); diff --git a/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.js b/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.js index 502f62d94c2b..30ab412ec586 100644 --- a/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.js +++ b/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.js @@ -59,7 +59,7 @@ export default class TransactionListItemDetails extends PureComponent { blockExplorerLinkText: PropTypes.object, ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) getCustodianTransactionDeepLink: PropTypes.func, - selectedIdentity: PropTypes.object, + selectedAccount: PropTypes.object, transactionNote: PropTypes.string, ///: END:ONLY_INCLUDE_IN }; @@ -141,14 +141,14 @@ export default class TransactionListItemDetails extends PureComponent { recipientAddress, tryReverseResolveAddress, ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - selectedIdentity, + selectedAccount, transactionGroup, ///: END:ONLY_INCLUDE_IN } = this.props; ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) this._mounted = true; - const address = selectedIdentity?.address; + const address = selectedAccount?.address; const custodyId = transactionGroup?.primaryTransaction?.custodyId; if (this._mounted && address && custodyId) { diff --git a/ui/components/app/transaction-list-item-details/transaction-list-item-details.container.js b/ui/components/app/transaction-list-item-details/transaction-list-item-details.container.js index 0f4d5d254d0a..9582b8359a84 100644 --- a/ui/components/app/transaction-list-item-details/transaction-list-item-details.container.js +++ b/ui/components/app/transaction-list-item-details/transaction-list-item-details.container.js @@ -13,10 +13,10 @@ import { getEnsResolutionByAddress, getAccountName, getMetadataContractName, - getMetaMaskIdentities, + getInternalAccounts, ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - getSelectedIdentity, getKnownMethodData, + getSelectedInternalAccount, ///: END:ONLY_INCLUDE_IN } from '../../../selectors'; import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils'; @@ -30,8 +30,8 @@ const mapStateToProps = (state, ownProps) => { recipientEns = getEnsResolutionByAddress(state, address); } const addressBook = getAddressBook(state); - const identities = getMetaMaskIdentities(state); - const recipientName = getAccountName(identities, recipientAddress); + const accounts = getInternalAccounts(state); + const recipientName = getAccountName(accounts, recipientAddress); const recipientMetadataName = getMetadataContractName( state, recipientAddress, @@ -66,7 +66,7 @@ const mapStateToProps = (state, ownProps) => { ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) methodData, transactionNote, - selectedIdentity: getSelectedIdentity(state), + selectedAccount: getSelectedInternalAccount(state), ///: END:ONLY_INCLUDE_IN }; }; diff --git a/ui/components/app/transaction-status-label/transaction-status-label.test.js b/ui/components/app/transaction-status-label/transaction-status-label.test.js index 493968aeba5d..a9de09bab52e 100644 --- a/ui/components/app/transaction-status-label/transaction-status-label.test.js +++ b/ui/components/app/transaction-status-label/transaction-status-label.test.js @@ -9,8 +9,34 @@ describe('TransactionStatusLabel Component', () => { const mockState = { metamask: { custodyStatusMaps: {}, - identities: {}, - selectedAddress: 'fakeAddress', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, }, }; @@ -115,12 +141,33 @@ describe('TransactionStatusLabel Component', () => { }, }, }, - selectedAddress: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - identities: { - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { - address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - name: 'Account 1', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'Custody - Jupiter', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', }, keyrings: [ { @@ -158,12 +205,33 @@ describe('TransactionStatusLabel Component', () => { }, }, }, - selectedAddress: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - identities: { - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { - address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - name: 'Account 1', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'Custody - Jupiter', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', }, keyrings: [ { @@ -203,12 +271,33 @@ describe('TransactionStatusLabel Component', () => { }, }, }, - selectedAddress: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - identities: { - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { - address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - name: 'Account 1', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'Custody - Jupiter', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', }, keyrings: [ { diff --git a/ui/components/app/wallet-overview/eth-overview.test.js b/ui/components/app/wallet-overview/eth-overview.test.js index 32e73fbee9a9..5a1c8c2aa113 100644 --- a/ui/components/app/wallet-overview/eth-overview.test.js +++ b/ui/components/app/wallet-overview/eth-overview.test.js @@ -42,18 +42,63 @@ describe('EthOverview', () => { }, useCurrencyRateCheck: true, conversionRate: 2, - identities: { - '0x1': { - address: '0x1', - }, - }, accounts: { '0x1': { address: '0x1', balance: '0x1F4', }, }, - selectedAddress: '0x1', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x1', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: KeyringType.imported, + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + 'e9b992f9-e151-4317-b8b7-c771bb73dd02': { + address: '0x2', + id: 'e9b992f9-e151-4317-b8b7-c771bb73dd02', + metadata: { + keyring: { + type: KeyringType.imported, + }, + }, + name: 'Account 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, keyrings: [ { type: KeyringType.imported, diff --git a/ui/components/app/wallet-overview/token-overview.test.js b/ui/components/app/wallet-overview/token-overview.test.js index 21a4faa571aa..67961994aa41 100644 --- a/ui/components/app/wallet-overview/token-overview.test.js +++ b/ui/components/app/wallet-overview/token-overview.test.js @@ -35,12 +35,34 @@ describe('TokenOverview', () => { preferences: { useNativeCurrencyAsPrimaryCurrency: true, }, - identities: { - '0x1': { - address: '0x1', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x1', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', }, - selectedAddress: '0x1', keyrings: [ { type: KeyringType.hdKeyTree, diff --git a/ui/components/app/wallet-overview/wallet-overview.js b/ui/components/app/wallet-overview/wallet-overview.js index f249579544e4..0415839ca529 100644 --- a/ui/components/app/wallet-overview/wallet-overview.js +++ b/ui/components/app/wallet-overview/wallet-overview.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import classnames from 'classnames'; import { useSelector } from 'react-redux'; import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils'; -import { getSelectedIdentity } from '../../../selectors'; +import { getSelectedInternalAccount } from '../../../selectors'; import { AddressCopyButton } from '../../multichain'; import Box from '../../ui/box/box'; @@ -13,8 +13,8 @@ const WalletOverview = ({ className, showAddress = false, }) => { - const selectedIdentity = useSelector(getSelectedIdentity); - const checksummedAddress = toChecksumHexAddress(selectedIdentity?.address); + const selectedAccount = useSelector(getSelectedInternalAccount); + const checksummedAddress = toChecksumHexAddress(selectedAccount.address); return (
diff --git a/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.js b/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.js index 31359540d340..a6975ac4dcd9 100644 --- a/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.js +++ b/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.js @@ -3,7 +3,7 @@ import { useDispatch, useSelector } from 'react-redux'; import { useI18nContext } from '../../../hooks/useI18nContext'; import { MetaMetricsContext } from '../../../contexts/metametrics'; import { hideModal } from '../../../store/actions'; -import { getSelectedAddress } from '../../../selectors/selectors'; +import { getSelectedInternalAccount } from '../../../selectors/selectors'; import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils'; import { Box, @@ -43,7 +43,7 @@ const InteractiveReplacementTokenModal = () => { const { custodians } = useSelector( (state) => state.metamask.mmiConfiguration, ); - const address = useSelector(getSelectedAddress); + const { address } = useSelector(getSelectedInternalAccount); const custodyAccountDetails = useSelector( (state) => state.metamask.custodyAccountDetails[toChecksumHexAddress(address)], diff --git a/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.js b/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.js index 55da0f9a723e..d8edd4fa9392 100644 --- a/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.js +++ b/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.js @@ -1,7 +1,10 @@ import React, { useState, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import PropTypes from 'prop-types'; -import { getCurrentKeyring, getSelectedAddress } from '../../../selectors'; +import { + getCurrentKeyring, + getSelectedInternalAccount, +} from '../../../selectors'; import { getInteractiveReplacementToken } from '../../../selectors/institutional/selectors'; import { getIsUnlocked } from '../../../ducks/metamask/metamask'; import { useI18nContext } from '../../../hooks/useI18nContext'; @@ -34,7 +37,7 @@ const InteractiveReplacementTokenNotification = ({ isVisible }) => { const mmiActions = mmiActionsFactory(); const keyring = useSelector(getCurrentKeyring); - const address = useSelector(getSelectedAddress); + const { address } = useSelector(getSelectedInternalAccount); const isUnlocked = useSelector(getIsUnlocked); const interactiveReplacementToken = useSelector( getInteractiveReplacementToken, diff --git a/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.js b/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.js index 2d9a06f3dfc0..54f45d6ce700 100644 --- a/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.js +++ b/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.js @@ -38,22 +38,41 @@ jest.mock('../../../store/institutional/institution-actions', () => ({ })); describe('Interactive Replacement Token Notification', () => { - const selectedAddress = '0xca8f1F0245530118D0cf14a06b01Daf8f76Cf281'; - - const identities = { - '0xca8f1F0245530118D0cf14a06b01Daf8f76Cf281': { - address: '0xca8f1F0245530118D0cf14a06b01Daf8f76Cf281', - name: 'Custodian A', - }, - }; + const selectedAccount = 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3'; const mockStore = { metamask: { providerConfig: { type: 'test', }, - selectedAddress, - identities, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xca8f1F0245530118D0cf14a06b01Daf8f76Cf281', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'Custody', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount, + }, isUnlocked: false, interactiveReplacementToken: { oldRefreshToken: 'abc' }, preferences: { diff --git a/ui/components/institutional/wrong-network-notification/wrong-network-notification.test.js b/ui/components/institutional/wrong-network-notification/wrong-network-notification.test.js index 447593db4214..c0e2dbfd5930 100644 --- a/ui/components/institutional/wrong-network-notification/wrong-network-notification.test.js +++ b/ui/components/institutional/wrong-network-notification/wrong-network-notification.test.js @@ -27,11 +27,33 @@ describe('Wrong Network Notification', function () { custodianName: 'saturn', }, }, - identities: { - '0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275': { - name: 'Custody Account A', - address: '0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'Custody', + }, + }, + name: 'Custody Account A', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', }, keyrings: [ { diff --git a/ui/components/multichain/account-list-menu/account-list-menu.js b/ui/components/multichain/account-list-menu/account-list-menu.js index 67a9bc61b0fe..ac27d5de561b 100644 --- a/ui/components/multichain/account-list-menu/account-list-menu.js +++ b/ui/components/multichain/account-list-menu/account-list-menu.js @@ -25,7 +25,7 @@ import { MetaMetricsContext } from '../../../contexts/metametrics'; import { getConnectedSubjectsForAllAddresses, getOriginOfCurrentTab, - getInternalAccounts, + getMetaMaskAccountsOrdered, getSelectedInternalAccount, } from '../../../selectors'; import { @@ -53,7 +53,7 @@ export const AccountListMenu = ({ onClose }) => { const t = useI18nContext(); const trackEvent = useContext(MetaMetricsContext); - const accounts = useSelector(getInternalAccounts); + const accounts = useSelector(getMetaMaskAccountsOrdered); const selectedAccount = useSelector(getSelectedInternalAccount); const connectedSites = useSelector(getConnectedSubjectsForAllAddresses); diff --git a/ui/components/multichain/app-header/app-header.js b/ui/components/multichain/app-header/app-header.js index e4e05fc90302..a87426277047 100644 --- a/ui/components/multichain/app-header/app-header.js +++ b/ui/components/multichain/app-header/app-header.js @@ -43,7 +43,6 @@ import { getTestNetworkBackgroundColor, getSelectedInternalAccount, ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - getSelectedAddress, getTheme, ///: END:ONLY_INCLUDE_IN } from '../../../selectors'; @@ -75,14 +74,6 @@ export const AppHeader = ({ location }) => { const t = useI18nContext(); const chainId = useSelector(getCurrentChainId); - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) - const selectedAddress = useSelector(getSelectedAddress); - const custodianIcon = useSelector((state) => - getCustodianIconForAddress(state, selectedAddress), - ); - const theme = useSelector((state) => getTheme(state)); - ///: END:ONLY_INCLUDE_IN - // Used for account picker const internalAccount = useSelector(getSelectedInternalAccount); const dispatch = useDispatch(); @@ -90,6 +81,14 @@ export const AppHeader = ({ location }) => { const onboardedInThisUISession = useSelector(getOnboardedInThisUISession); const showProductTourPopup = useSelector(getShowProductTour); + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + const { address: selectedAddress } = internalAccount; + const custodianIcon = useSelector((state) => + getCustodianIconForAddress(state, selectedAddress), + ); + const theme = useSelector((state) => getTheme(state)); + ///: END:ONLY_INCLUDE_IN + // Used for network icon / dropdown const currentNetwork = useSelector(getCurrentNetwork); const testNetworkBackgroundColor = useSelector(getTestNetworkBackgroundColor); diff --git a/ui/components/multichain/connected-site-menu/connected-site-menu.js b/ui/components/multichain/connected-site-menu/connected-site-menu.js index 16d7a345d9ee..c299ac8127e6 100644 --- a/ui/components/multichain/connected-site-menu/connected-site-menu.js +++ b/ui/components/multichain/connected-site-menu/connected-site-menu.js @@ -22,7 +22,7 @@ import { IconSize, Box, } from '../../component-library'; -import { getSelectedIdentity } from '../../../selectors'; +import { getSelectedInternalAccount } from '../../../selectors'; import Tooltip from '../../ui/tooltip'; import { useI18nContext } from '../../../hooks/useI18nContext'; @@ -34,7 +34,7 @@ export const ConnectedSiteMenu = ({ onClick, }) => { const t = useI18nContext(); - const selectedAccount = useSelector(getSelectedIdentity); + const selectedAccount = useSelector(getSelectedInternalAccount); return ( { - const selectedAddress = '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b'; - - const identities = { - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { - address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - name: 'Account 1', - }, - '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b': { - address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', - name: 'Account 2', + const internalAccounts = { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '07c2cfec-36c9-46c4-8115-3836d3ac9047': { + address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', + id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }, + selectedAccount: '07c2cfec-36c9-46c4-8115-3836d3ac9047', }; const accounts = { @@ -38,8 +77,7 @@ describe('Connected Site Menu', () => { }; const mockStore = { metamask: { - selectedAddress, - identities, + internalAccounts, accounts, }, }; diff --git a/ui/components/multichain/create-account/create-account.js b/ui/components/multichain/create-account/create-account.js index 838609ab7a9a..dffd8df37b35 100644 --- a/ui/components/multichain/create-account/create-account.js +++ b/ui/components/multichain/create-account/create-account.js @@ -10,10 +10,7 @@ import { } from '../../component-library'; import { useI18nContext } from '../../../hooks/useI18nContext'; import { getAccountNameErrorMessage } from '../../../helpers/utils/accounts'; -import { - getMetaMaskAccountsOrdered, - getMetaMaskIdentities, -} from '../../../selectors'; +import { getMetaMaskAccountsOrdered } from '../../../selectors'; import { addNewAccount, setAccountLabel } from '../../../store/actions'; import { getMostRecentOverviewPage } from '../../../ducks/history/history'; import { @@ -32,10 +29,9 @@ export const CreateAccount = ({ onActionComplete }) => { const trackEvent = useContext(MetaMetricsContext); const accounts = useSelector(getMetaMaskAccountsOrdered); - const identities = useSelector(getMetaMaskIdentities); const mostRecentOverviewPage = useSelector(getMostRecentOverviewPage); - const newAccountNumber = Object.keys(identities).length + 1; + const newAccountNumber = Object.keys(accounts).length + 1; const defaultAccountName = t('newAccountNumberName', [newAccountNumber]); const [newAccountName, setNewAccountName] = useState(''); @@ -49,9 +45,9 @@ export const CreateAccount = ({ onActionComplete }) => { ); const onCreateAccount = async (name) => { - const newAccountAddress = await dispatch(addNewAccount()); + const newAccount = await dispatch(addNewAccount(name)); if (name) { - dispatch(setAccountLabel(newAccountAddress, name)); + dispatch(setAccountLabel(newAccount, name)); } }; diff --git a/ui/ducks/alerts/unconnected-account.js b/ui/ducks/alerts/unconnected-account.js index a1cc12ba6058..4506b49c5f16 100644 --- a/ui/ducks/alerts/unconnected-account.js +++ b/ui/ducks/alerts/unconnected-account.js @@ -8,7 +8,10 @@ import { setAlertEnabledness, setSelectedAddress, } from '../../store/actions'; -import { getOriginOfCurrentTab, getSelectedAddress } from '../../selectors'; +import { + getOriginOfCurrentTab, + getSelectedInternalAccount, +} from '../../selectors'; import { ALERT_STATE } from './enums'; // Constants @@ -128,7 +131,7 @@ export const switchToAccount = (address) => { export const connectAccount = () => { return async (dispatch, getState) => { const state = getState(); - const selectedAddress = getSelectedAddress(state); + const { address: selectedAddress } = getSelectedInternalAccount(state); const origin = getOriginOfCurrentTab(state); try { await dispatch(connectAccountRequested()); diff --git a/ui/ducks/metamask/metamask.js b/ui/ducks/metamask/metamask.js index 38c4225a04b4..4fbbd625575a 100644 --- a/ui/ducks/metamask/metamask.js +++ b/ui/ducks/metamask/metamask.js @@ -9,6 +9,9 @@ import { accountsWithSendEtherInfoSelector, checkNetworkAndAccountSupports1559, getAddressBook, + getFirstInternalAccountByAddress, + getInternalAccount, + getSelectedInternalAccount, getUseCurrencyRateCheck, } from '../../selectors'; import { updateTransactionGasFees } from '../../store/actions'; @@ -79,12 +82,15 @@ export default function reduceMetamask(state = initialState, action) { }; case actionConstants.SET_ACCOUNT_LABEL: { - const { account } = action.value; - const name = action.value.label; - const id = {}; - id[account] = { ...metamaskState.identities[account], name }; - const identities = { ...metamaskState.identities, ...id }; - return Object.assign(metamaskState, { identities }); + const { account: newAccount } = action.value; + const internalAccounts = { + ...metamaskState.internalAccounts, + accounts: { + ...metamaskState.internalAccounts.accounts, + ...{ [newAccount.id]: newAccount }, + }, + }; + return Object.assign(metamaskState, { internalAccounts }); } case actionConstants.UPDATE_CUSTOM_NONCE: @@ -255,8 +261,9 @@ export function getNftsDropdownState(state) { export const getNfts = (state) => { const { - metamask: { allNfts, selectedAddress }, + metamask: { allNfts }, } = state; + const { address: selectedAddress } = getSelectedInternalAccount(state); const { chainId } = getProviderConfig(state); return allNfts?.[selectedAddress]?.[chainId] ?? []; @@ -264,8 +271,9 @@ export const getNfts = (state) => { export const getNftContracts = (state) => { const { - metamask: { allNftContracts, selectedAddress }, + metamask: { allNftContracts }, } = state; + const { address: selectedAddress } = getSelectedInternalAccount(state); const { chainId } = getProviderConfig(state); return allNftContracts?.[selectedAddress]?.[chainId] ?? []; @@ -374,13 +382,13 @@ export function getSeedPhraseBackedUp(state) { * Given the redux state object and an address, finds a keyring that contains that address, if one exists * * @param {object} state - the redux state object - * @param {string} accountId - the account id to search for among the internal accounts + * @param {string} address - the address to search for among the internal accounts * @returns {object | undefined} The keyring which contains the passed address, or undefined */ -export function findKeyringForAddress(state, accountId) { - const account = state.metamask.internalAccounts.accounts[accountId]; +export function findKeyringForAddress(state, address) { + const account = getFirstInternalAccountByAddress(state, address); - return account.metadata.keyring; + return account?.metadata?.keyring; } /** diff --git a/ui/ducks/send/send.js b/ui/ducks/send/send.js index f63e4a13ad46..a9bca3493aa2 100644 --- a/ui/ducks/send/send.js +++ b/ui/ducks/send/send.js @@ -38,7 +38,7 @@ import { getIsMultiLayerFeeNetwork, getEnsResolutionByAddress, getSelectedAccount, - getSelectedAddress, + getSelectedInternalAccount, } from '../../selectors'; import { disconnectGasFeeEstimatePoller, @@ -1908,7 +1908,7 @@ export function updateRecipientUserInput(userInput) { const sendingAddress = draftTransaction.fromAccount?.address ?? state[name].selectedAccount.address ?? - getSelectedAddress(state); + getSelectedInternalAccount(state).address; const chainId = getCurrentChainId(state); const tokens = getTokens(state); const useTokenDetection = getUseTokenDetection(state); @@ -2030,7 +2030,7 @@ export function updateSendAsset( const sendingAddress = draftTransaction.fromAccount?.address ?? state[name].selectedAccount.address ?? - getSelectedAddress(state); + getSelectedInternalAccount(state).address; const account = getTargetAccount(state, sendingAddress); if (type === AssetType.native) { const unapprovedTxs = getUnapprovedTxs(state); diff --git a/ui/ducks/send/send.test.js b/ui/ducks/send/send.test.js index 340d447db710..09f2743e0fdf 100644 --- a/ui/ducks/send/send.test.js +++ b/ui/ducks/send/send.test.js @@ -1340,7 +1340,7 @@ describe('Send Slice', () => { const action = initializeSendState(); await action(dispatchSpy, getState, undefined); - expect(dispatchSpy).toHaveBeenCalledTimes(3); + expect(dispatchSpy).toHaveBeenCalledTimes(2); expect(dispatchSpy.mock.calls[0][0].type).toStrictEqual( 'send/initializeSendState/pending', @@ -1777,6 +1777,34 @@ describe('Send Slice', () => { occurrences: 12, }, }, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, }, send: INITIAL_SEND_STATE_FOR_EXISTING_DRAFT, }; @@ -2073,6 +2101,34 @@ describe('Send Slice', () => { occurrences: 12, }, }, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, }, send: INITIAL_SEND_STATE_FOR_EXISTING_DRAFT, }; @@ -2426,7 +2482,7 @@ describe('Send Slice', () => { await store.dispatch(editExistingTransaction(AssetType.native, 1)); const actionResult = store.getActions(); - expect(actionResult).toHaveLength(7); + expect(actionResult).toHaveLength(6); expect(actionResult[0]).toMatchObject({ type: 'send/clearPreviousDrafts', }); @@ -2522,6 +2578,34 @@ describe('Send Slice', () => { balance: '0x0', }, }, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: mockAddress1, + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, cachedBalances: { [CHAIN_IDS.GOERLI]: { [mockAddress1]: '0x0', @@ -2762,7 +2846,7 @@ describe('Send Slice', () => { await store.dispatch(editExistingTransaction(AssetType.token, 1)); const actionResult = store.getActions(); - expect(actionResult).toHaveLength(9); + expect(actionResult).toHaveLength(8); expect(actionResult[0].type).toStrictEqual('send/clearPreviousDrafts'); expect(actionResult[1]).toStrictEqual({ type: 'send/addNewDraft', diff --git a/ui/hooks/useAddressDetails.js b/ui/hooks/useAddressDetails.js index 63a1b58ec25e..aa1cd5d26289 100644 --- a/ui/hooks/useAddressDetails.js +++ b/ui/hooks/useAddressDetails.js @@ -3,28 +3,32 @@ import { useSelector } from 'react-redux'; import { toChecksumHexAddress } from '../../shared/modules/hexstring-utils'; import { getAddressBook, - getMetaMaskIdentities, + getInternalAccounts, getTokenList, } from '../selectors'; import { shortenAddress } from '../helpers/utils/util'; const useAddressDetails = (toAddress) => { const addressBook = useSelector(getAddressBook); - const identities = useSelector(getMetaMaskIdentities); + const accounts = useSelector(getInternalAccounts); const tokenList = useSelector(getTokenList); const checksummedAddress = toChecksumHexAddress(toAddress); if (!toAddress) { return {}; } + const toAccount = accounts.find( + (account) => toChecksumHexAddress(account.address) === checksummedAddress, + ); + const addressBookEntryObject = addressBook.find( (entry) => entry.address === checksummedAddress, ); if (addressBookEntryObject?.name) { return { toName: addressBookEntryObject.name, isTrusted: true }; } - if (identities[toAddress]?.name) { - return { toName: identities[toAddress].name, isTrusted: true }; + if (toAccount) { + return { toName: toAccount.name, isTrusted: true }; } if (tokenList[toAddress?.toLowerCase()]?.name) { return { diff --git a/ui/hooks/useAddressDetails.test.js b/ui/hooks/useAddressDetails.test.js index cf09f1b9d4a4..76f3db93b097 100644 --- a/ui/hooks/useAddressDetails.test.js +++ b/ui/hooks/useAddressDetails.test.js @@ -13,6 +13,34 @@ const renderUseAddressDetails = (toAddress, stateVariables = {}) => { chainId: '0x5', }, tokenList: {}, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, ...stateVariables, }, }; @@ -54,15 +82,37 @@ describe('useAddressDetails', () => { expect(isTrusted).toBe(true); }); - it('should return name from identities if address is present in identities', () => { + it('should return name from internal account if address is present in internalAccounts', () => { const { result } = renderUseAddressDetails( '0x06195827297c7A80a443b6894d3BDB8824b43896', { - identities: { - '0x06195827297c7A80a443b6894d3BDB8824b43896': { - address: '0x06195827297c7A80a443b6894d3BDB8824b43896', - name: 'Account 1', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x06195827297c7A80a443b6894d3BDB8824b43896', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', }, }, ); diff --git a/ui/hooks/useAssetDetails.test.js b/ui/hooks/useAssetDetails.test.js index 074a3aec65c8..4a0860f499d5 100644 --- a/ui/hooks/useAssetDetails.test.js +++ b/ui/hooks/useAssetDetails.test.js @@ -20,6 +20,34 @@ const renderUseAssetDetails = ({ }, tokenList: {}, tokens: [], + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: userAddress, + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, }, }; diff --git a/ui/hooks/useNftsCollections.js b/ui/hooks/useNftsCollections.js index 17d639a15287..4df71373882b 100644 --- a/ui/hooks/useNftsCollections.js +++ b/ui/hooks/useNftsCollections.js @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; import { isEqual } from 'lodash'; import { getNfts, getNftContracts } from '../ducks/metamask/metamask'; -import { getCurrentChainId, getSelectedAddress } from '../selectors'; +import { getCurrentChainId, getSelectedInternalAccount } from '../selectors'; import { usePrevious } from './usePrevious'; import { useI18nContext } from './useI18nContext'; @@ -18,7 +18,7 @@ export function useNftsCollections() { }); const nfts = useSelector(getNfts); const [nftsLoading, setNftsLoading] = useState(() => nfts?.length >= 0); - const selectedAddress = useSelector(getSelectedAddress); + const { address: selectedAddress } = useSelector(getSelectedInternalAccount); const chainId = useSelector(getCurrentChainId); const nftContracts = useSelector(getNftContracts); const prevNfts = usePrevious(nfts); diff --git a/ui/hooks/useTokenTracker.js b/ui/hooks/useTokenTracker.js index b58562168806..a0952b4bca91 100644 --- a/ui/hooks/useTokenTracker.js +++ b/ui/hooks/useTokenTracker.js @@ -1,7 +1,7 @@ import { useState, useEffect, useRef, useCallback } from 'react'; import TokenTracker from '@metamask/eth-token-tracker'; import { shallowEqual, useSelector } from 'react-redux'; -import { getCurrentChainId, getSelectedAddress } from '../selectors'; +import { getCurrentChainId, getSelectedInternalAccount } from '../selectors'; import { SECOND } from '../../shared/constants/time'; import { isEqualCaseInsensitive } from '../../shared/modules/string-utils'; import { useEqualityCheck } from './useEqualityCheck'; @@ -12,7 +12,10 @@ export function useTokenTracker( hideZeroBalanceTokens = false, ) { const chainId = useSelector(getCurrentChainId); - const userAddress = useSelector(getSelectedAddress, shallowEqual); + const { address: userAddress } = useSelector( + getSelectedInternalAccount, + shallowEqual, + ); const [loading, setLoading] = useState(() => tokens?.length >= 0); const [tokensWithBalances, setTokensWithBalances] = useState([]); const [error, setError] = useState(null); diff --git a/ui/index.js b/ui/index.js index 21b8831158ad..c9cbeed660a7 100644 --- a/ui/index.js +++ b/ui/index.js @@ -16,7 +16,7 @@ import * as actions from './store/actions'; import configureStore from './store/store'; import { getPermittedAccountsForCurrentTab, - getSelectedAddress, + getSelectedInternalAccount, } from './selectors'; import { ALERT_STATE } from './ducks/alerts'; import { @@ -129,7 +129,8 @@ async function startApp(metamaskState, backgroundConnection, opts) { const { origin } = draftInitialState.activeTab; const permittedAccountsForCurrentTab = getPermittedAccountsForCurrentTab(draftInitialState); - const selectedAddress = getSelectedAddress(draftInitialState); + const { address: selectedAddress } = + getSelectedInternalAccount(draftInitialState); const unconnectedAccountAlertShownOrigins = getUnconnectedAccountAlertShown(draftInitialState); const unconnectedAccountAlertIsEnabled = diff --git a/ui/pages/asset/components/native-asset.js b/ui/pages/asset/components/native-asset.js index b0cdf6b702f2..a951711e5e1f 100644 --- a/ui/pages/asset/components/native-asset.js +++ b/ui/pages/asset/components/native-asset.js @@ -6,11 +6,10 @@ import { getAccountLink } from '@metamask/etherscan-link'; import TransactionList from '../../../components/app/transaction-list'; import { EthOverview } from '../../../components/app/wallet-overview'; import { - getSelectedIdentity, getCurrentChainId, getRpcPrefsForCurrentProvider, - getSelectedAddress, getIsCustomNetwork, + getSelectedInternalAccount, } from '../../../selectors/selectors'; import { DEFAULT_ROUTE } from '../../../helpers/constants/routes'; import { getURLHostName } from '../../../helpers/utils/util'; @@ -20,13 +19,11 @@ import AssetNavigation from './asset-navigation'; import AssetOptions from './asset-options'; export default function NativeAsset({ nativeCurrency }) { - const selectedAccountName = useSelector( - (state) => getSelectedIdentity(state).name, - ); + const { name: selectedAccountName } = useSelector(getSelectedInternalAccount); const chainId = useSelector(getCurrentChainId); const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider); - const address = useSelector(getSelectedAddress); + const { address } = useSelector(getSelectedInternalAccount); const history = useHistory(); const accountLink = getAccountLink(address, chainId, rpcPrefs); const trackEvent = useContext(MetaMetricsContext); diff --git a/ui/pages/asset/components/token-asset.js b/ui/pages/asset/components/token-asset.js index 18b1ee5103e4..15b353392699 100644 --- a/ui/pages/asset/components/token-asset.js +++ b/ui/pages/asset/components/token-asset.js @@ -7,7 +7,7 @@ import TransactionList from '../../../components/app/transaction-list'; import { TokenOverview } from '../../../components/app/wallet-overview'; import { getCurrentChainId, - getSelectedIdentity, + getSelectedInternalAccount, getRpcPrefsForCurrentProvider, getIsCustomNetwork, } from '../../../selectors/selectors'; @@ -26,9 +26,9 @@ export default function TokenAsset({ token }) { const dispatch = useDispatch(); const chainId = useSelector(getCurrentChainId); const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider); - const selectedIdentity = useSelector(getSelectedIdentity); - const selectedAccountName = selectedIdentity.name; - const selectedAddress = selectedIdentity.address; + const selectedAccount = useSelector(getSelectedInternalAccount); + const selectedAccountName = selectedAccount.name; + const selectedAddress = selectedAccount.address; const history = useHistory(); const tokenTrackerLink = getTokenTrackerLink( token.address, diff --git a/ui/pages/confirm-add-suggested-token/confirm-add-suggested-token.test.js b/ui/pages/confirm-add-suggested-token/confirm-add-suggested-token.test.js index 720f0202b019..e62a71d3a5e7 100644 --- a/ui/pages/confirm-add-suggested-token/confirm-add-suggested-token.test.js +++ b/ui/pages/confirm-add-suggested-token/confirm-add-suggested-token.test.js @@ -62,6 +62,34 @@ const renderComponent = (tokens = []) => { pendingApprovals: PENDING_APPROVALS, tokens, providerConfig: { chainId: '0x1' }, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, }, history: { mostRecentOverviewPage: '/', diff --git a/ui/pages/confirm-import-token/confirm-import-token.test.js b/ui/pages/confirm-import-token/confirm-import-token.test.js index a4c9d824af9a..285883c7112c 100644 --- a/ui/pages/confirm-import-token/confirm-import-token.test.js +++ b/ui/pages/confirm-import-token/confirm-import-token.test.js @@ -37,6 +37,34 @@ const renderComponent = (mockPendingTokens = MOCK_PENDING_TOKENS) => { metamask: { pendingTokens: { ...mockPendingTokens }, providerConfig: { chainId: '0x1' }, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, }, history: { mostRecentOverviewPage: '/', diff --git a/ui/pages/confirm-send-ether/__snapshots__/confirm-send-ether.test.js.snap b/ui/pages/confirm-send-ether/__snapshots__/confirm-send-ether.test.js.snap index c889ab29635e..24204d0947dc 100644 --- a/ui/pages/confirm-send-ether/__snapshots__/confirm-send-ether.test.js.snap +++ b/ui/pages/confirm-send-ether/__snapshots__/confirm-send-ether.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`ConfirmSendEther should render correct information for for confirm send ether 1`] = ` -[ +Array [
+ > + Account 1 +
diff --git a/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js b/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js index daf9e10ffd20..1826487ac6ff 100644 --- a/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js +++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js @@ -41,6 +41,7 @@ import { getUnapprovedTransaction, getFullTxData, getUseCurrencyRateCheck, + getFirstInternalAccountByAddress, } from '../../selectors'; import { getMostRecentOverviewPage } from '../../ducks/history/history'; import { @@ -121,14 +122,8 @@ const mapStateToProps = (state, ownProps) => { const gasLoadingAnimationIsShowing = getGasLoadingAnimationIsShowing(state); const isBuyableChain = getIsBuyableChain(state); const { confirmTransaction, metamask } = state; - const { - conversionRate, - identities, - addressBook, - networkId, - unapprovedTxs, - nextNonce, - } = metamask; + const { conversionRate, addressBook, networkId, unapprovedTxs, nextNonce } = + metamask; const { chainId } = getProviderConfig(state); const { tokenData, txData, tokenProps, nonce } = confirmTransaction; const { txParams = {}, id: transactionId, type } = txData; @@ -148,7 +143,8 @@ const mapStateToProps = (state, ownProps) => { const tokenToAddress = getTokenAddressParam(transactionData); const { balance } = accounts[fromAddress]; - const { name: fromName } = identities[fromAddress]; + const fromAccount = getFirstInternalAccountByAddress(state, fromAddress); + const { name: fromName } = fromAccount; const isSendingAmount = type === TransactionType.simpleSend || !isEmptyHexString(amount); @@ -162,7 +158,7 @@ const mapStateToProps = (state, ownProps) => { const tokenList = getTokenList(state); const toName = - identities[toAddress]?.name || + getFirstInternalAccountByAddress(state, toAddress)?.name || tokenList[toAddress?.toLowerCase()]?.name || shortenAddress(toChecksumHexAddress(toAddress)); diff --git a/ui/pages/confirm-transaction-base/confirm-transaction-base.test.js b/ui/pages/confirm-transaction-base/confirm-transaction-base.test.js index 7a079ece4756..5abe7bd26e86 100644 --- a/ui/pages/confirm-transaction-base/confirm-transaction-base.test.js +++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.test.js @@ -77,7 +77,6 @@ const baseStore = { medium: '1', fast: '2', }, - selectedAddress: mockTxParamsFromAddress, keyrings: [ { type: KeyringType.hdKeyTree, @@ -112,11 +111,33 @@ const baseStore = { address: mockTxParamsFromAddress, }, }, - identities: { - [mockTxParamsFromAddress]: { address: mockTxParamsFromAddress }, - [mockTxParamsToAddress]: { - name: 'Test Address 1', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: mockTxParamsFromAddress, + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', }, tokenAddress: '0x32e6c34cd57087abbd59b5a4aecc4cb495924356', tokenList: {}, diff --git a/ui/pages/connected-accounts/connected-accounts.container.js b/ui/pages/connected-accounts/connected-accounts.container.js index 8a8cffb3b530..bc3a1a4c2dfd 100644 --- a/ui/pages/connected-accounts/connected-accounts.container.js +++ b/ui/pages/connected-accounts/connected-accounts.container.js @@ -3,7 +3,7 @@ import { getAccountToConnectToActiveTab, getOrderedConnectedAccountsForActiveTab, getPermissionsForActiveTab, - getSelectedAddress, + getSelectedInternalAccount, } from '../../selectors'; import { isExtensionUrl } from '../../helpers/utils/util'; import { @@ -19,7 +19,7 @@ const mapStateToProps = (state) => { const accountToConnect = getAccountToConnectToActiveTab(state); const connectedAccounts = getOrderedConnectedAccountsForActiveTab(state); const permissions = getPermissionsForActiveTab(state); - const selectedAddress = getSelectedAddress(state); + const { address: selectedAddress } = getSelectedInternalAccount(state); const isActiveTabExtension = isExtensionUrl(activeTab); return { diff --git a/ui/pages/connected-sites/connected-sites.container.js b/ui/pages/connected-sites/connected-sites.container.js index 7e7b2a9c47fd..27779b6bcf33 100644 --- a/ui/pages/connected-sites/connected-sites.container.js +++ b/ui/pages/connected-sites/connected-sites.container.js @@ -11,7 +11,7 @@ import { getOriginOfCurrentTab, getPermissionSubjects, getPermittedAccountsByOrigin, - getSelectedAddress, + getSelectedInternalAccount, } from '../../selectors'; import { CONNECT_ROUTE } from '../../helpers/constants/routes'; import { getMostRecentOverviewPage } from '../../ducks/history/history'; @@ -23,7 +23,7 @@ const mapStateToProps = (state) => { const connectedSubjects = getConnectedSubjectsForSelectedAddress(state); const originOfCurrentTab = getOriginOfCurrentTab(state); const permittedAccountsByOrigin = getPermittedAccountsByOrigin(state); - const selectedAddress = getSelectedAddress(state); + const { address: selectedAddress } = getSelectedInternalAccount(state); const currentTabHasNoAccounts = !permittedAccountsByOrigin[originOfCurrentTab]?.length; diff --git a/ui/pages/onboarding-flow/create-password/create-password.test.js b/ui/pages/onboarding-flow/create-password/create-password.test.js index ef28b4dad23c..4f1316715981 100644 --- a/ui/pages/onboarding-flow/create-password/create-password.test.js +++ b/ui/pages/onboarding-flow/create-password/create-password.test.js @@ -24,8 +24,10 @@ jest.mock('react-router-dom', () => ({ describe('Onboarding Create Password', () => { const mockState = { metamask: { - identities: {}, - selectedAddress: '', + internalAccounts: { + accounts: {}, + selectedAccount: '', + }, }, }; diff --git a/ui/pages/onboarding-flow/import-srp/import-srp.test.js b/ui/pages/onboarding-flow/import-srp/import-srp.test.js index ef88f715eab3..5d4004dc0dec 100644 --- a/ui/pages/onboarding-flow/import-srp/import-srp.test.js +++ b/ui/pages/onboarding-flow/import-srp/import-srp.test.js @@ -21,8 +21,10 @@ const TEST_SEED = describe('Import SRP', () => { const mockState = { metamask: { - identities: {}, - selectedAddress: '', + internalAccounts: { + accounts: {}, + selectedAccount: '', + }, }, }; diff --git a/ui/pages/onboarding-flow/onboarding-flow.test.js b/ui/pages/onboarding-flow/onboarding-flow.test.js index 6e60d7f2c275..520e141b5318 100644 --- a/ui/pages/onboarding-flow/onboarding-flow.test.js +++ b/ui/pages/onboarding-flow/onboarding-flow.test.js @@ -36,7 +36,10 @@ jest.mock('../../store/actions', () => ({ describe('Onboarding Flow', () => { const mockState = { metamask: { - identities: {}, + internalAccounts: { + accounts: {}, + selectedAccount: '', + }, providerConfig: { type: NETWORK_TYPES.GOERLI, chainId: '0x0', diff --git a/ui/pages/onboarding-flow/welcome/welcome.test.js b/ui/pages/onboarding-flow/welcome/welcome.test.js index c7965efd52f4..9aaca063c45e 100644 --- a/ui/pages/onboarding-flow/welcome/welcome.test.js +++ b/ui/pages/onboarding-flow/welcome/welcome.test.js @@ -42,8 +42,10 @@ jest.mock('react-router-dom', () => ({ describe('Onboarding Welcome Component', () => { const mockState = { metamask: { - identities: {}, - selectedAddress: '', + internalAccounts: { + accounts: {}, + selectedAccount: '', + }, }, }; diff --git a/ui/pages/permissions-connect/permissions-connect.container.js b/ui/pages/permissions-connect/permissions-connect.container.js index a5f1ee145092..41576cc2fc0e 100644 --- a/ui/pages/permissions-connect/permissions-connect.container.js +++ b/ui/pages/permissions-connect/permissions-connect.container.js @@ -8,7 +8,7 @@ import { getAccountsWithLabels, getLastConnectedInfo, getPermissionsRequests, - getSelectedAddress, + getSelectedInternalAccount, ///: BEGIN:ONLY_INCLUDE_IN(snaps) getSnapInstallOrUpdateRequests, getRequestState, @@ -57,7 +57,7 @@ const mapStateToProps = (state, ownProps) => { ...getSnapInstallOrUpdateRequests(state), ]; ///: END:ONLY_INCLUDE_IN - const currentAddress = getSelectedAddress(state); + const { address: currentAddress } = getSelectedInternalAccount(state); const permissionsRequest = permissionsRequests.find( (req) => req.metadata.id === permissionsRequestId, diff --git a/ui/pages/send/send-content/add-recipient/__snapshots__/add-recipient.component.test.js.snap b/ui/pages/send/send-content/add-recipient/__snapshots__/add-recipient.component.test.js.snap index b6587dd99582..6397374fc500 100644 --- a/ui/pages/send/send-content/add-recipient/__snapshots__/add-recipient.component.test.js.snap +++ b/ui/pages/send/send-content/add-recipient/__snapshots__/add-recipient.component.test.js.snap @@ -95,7 +95,7 @@ exports[`Add Recipient Component Domain Resolution should match snapshot 1`] = ` style="height: 28px; width: 28px; border-radius: 14px;" >
- Test Account 2 + Test Account 3

- 0xec1a...251b + 0xeb9e...4823

@@ -158,7 +158,7 @@ exports[`Add Recipient Component Domain Resolution should match snapshot 1`] = ` style="height: 28px; width: 28px; border-radius: 14px;" >
- Test Ledger 1 + Test Account 2

- 0xc42e...8813 + 0xec1a...251b

@@ -221,7 +221,7 @@ exports[`Add Recipient Component Domain Resolution should match snapshot 1`] = ` style="height: 28px; width: 28px; border-radius: 14px;" >
- Test Account 3 + Ledger Hardware 2

- 0xeb9e...4823 + 0xc42e...8813

@@ -531,7 +531,7 @@ exports[`Add Recipient Component render should match snapshot 1`] = ` style="height: 28px; width: 28px; border-radius: 14px;" >
- Test Account 2 + Test Account 3

- 0xec1a...251b + 0xeb9e...4823

@@ -594,7 +594,7 @@ exports[`Add Recipient Component render should match snapshot 1`] = ` style="height: 28px; width: 28px; border-radius: 14px;" >
- Test Ledger 1 + Test Account 2

- 0xc42e...8813 + 0xec1a...251b

@@ -657,7 +657,7 @@ exports[`Add Recipient Component render should match snapshot 1`] = ` style="height: 28px; width: 28px; border-radius: 14px;" >
- Test Account 3 + Ledger Hardware 2

- 0xeb9e...4823 + 0xc42e...8813

diff --git a/ui/pages/send/send.test.js b/ui/pages/send/send.test.js index 0713cbe81acf..eeb5ba25496d 100644 --- a/ui/pages/send/send.test.js +++ b/ui/pages/send/send.test.js @@ -78,7 +78,34 @@ const baseStore = { medium: '1', fast: '2', }, - selectedAddress: '0x0', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, keyrings: [ { type: KeyringType.hdKeyTree, @@ -110,7 +137,6 @@ const baseStore = { accounts: { '0x0': { balance: '0x0', address: '0x0' }, }, - identities: { '0x0': { address: '0x0' } }, tokenAddress: '0x32e6c34cd57087abbd59b5a4aecc4cb495924356', tokenList: { '0x32e6c34cd57087abbd59b5a4aecc4cb495924356': { diff --git a/ui/pages/swaps/loading-swaps-quotes/__snapshots__/loading-swaps-quotes-stories-metadata.test.js.snap b/ui/pages/swaps/loading-swaps-quotes/__snapshots__/loading-swaps-quotes-stories-metadata.test.js.snap index 66be56d52a69..cbb28155e807 100644 --- a/ui/pages/swaps/loading-swaps-quotes/__snapshots__/loading-swaps-quotes-stories-metadata.test.js.snap +++ b/ui/pages/swaps/loading-swaps-quotes/__snapshots__/loading-swaps-quotes-stories-metadata.test.js.snap @@ -1,28 +1,28 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`storiesMetadata matches expected values for storiesMetadata 1`] = ` -{ - "airswap": { +Object { + "airswap": Object { "color": "#2B71FF", "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASkAAAB5CAYAAABlYNfBAAAACXBIWXMAACxLAAAsSwGlPZapAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAyZSURBVHgB7d3xddy2HcBxqK//V+4COXeBKgs0TAeo3Q4QKRkgURao2Q5QKx3AcjtA3XQAU11A9gQ+dQHbWSC/8ieS7yjcDyBA8nh3yffzHp/8TBAAeeTvABDkOQcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE4jImQOAQ1QHqGfSOHcAcEh6AUoIVAAOihGgCFQADkMkQBGoAOxXQoAiUAHYj4wARaACsKwRAYpABWAZEwIUgQrAbs0QoAhUAHZjxgBFoAIwrx0EKAIVgHnsMEARqABMs0CAIlABGGfBAEWgApBnDwGKQAUcgRN3ADRA1X9Ktz8XJycn/3B7Vh+Hlf9/db3u3AR1nqf1n1Pvvz/W+X50iXVIEMwvV12+/lnVS1Evv6qXR+2qD/Xyv3q5q8t6m5jH5Hq2efnHcK587oU+48g2o453rA5Dpp6HR03214Ly7bVFVZdfBOpVuAnq7Usjz+tI+ineaN718tRlqNPfB1NpzoUPCeWs23KKQH4ngXxKl6nNa+3l89plavN5adTpRWQbXb41tnkvzZdPbh10+Vym6T7jwv0cyOEEqM7eApXYJ7C6npjvkkGq713K8ZTmwvlUtgPB6HKkCQhXVlqXQcIX9Y+SGSTEDpyaTzGwzTpQ/qXLJPMEqb6kz/hoyeEFqM7iB70ucxWpj57Y2d+avbz3FaSUXkzPImXp8ljGB6i+f0nbVZV4cClc+rELtX6ygkRbnz8a+bwb2OZLCRvTmps7SHXH4pnboV+4PZD9j0HF6Em5dKD6JrJOA1T2t+aB0DFPDZJ/i6zX7s4qsF7Hnl7Wy7/bf8c8bRcdP9E/N/VyZ5RXuDyfGf+n+fzBpdP0T4z/vxnY5ovI+kIOo8s19BnPUsCiDjxA9S02mF4fk7ULX6hKB0ofuXF5l/Uf/5vuZZ3fl4H0Yvz3d1oHF/db1wQAq9Wnef6+LvOmV47++bRebo30Vb181R+slc2grwaic7cdbF7V6f/kpS/d9r6v63S/cQPa7T+vl1CLRRP8OmUAu85LrzNtNa287R8cE6/sx+02MQ/2OaEe+sfaJ92H7xKy0M9Yf/RkZWXvAvtzVORwu3ghO29R1WVcJNalcCPIPN29VUI5Xbe1DOTx2khvDQoPjhvJptuy7rbx6yibrqQvqcsn4a5eX5mQT6iL9W5i2d2+JA8FjKlLII+kz3gui3X35HhaUH1LdP2srp71rbbTfv9U2sVqWz5/cXb9tXuy6m/imm/mPv02/rtLK0tbW4/b8r7yb5G3XT79vxt/c5fe5ftsYP3v3DAtzzqH/mkllk2L0S/7zm0fV8170aGA9riWrjnuvkImjJ+G/NItYIYApc3Ru3bRf+t8GZ0384OXrptX84lrmqR6wKb+Jp8GKreLrp80vxfo10/nAV3W67ruU+f+BJhrPtKu1PXTb9RvXXNh+ids4ZoxprnK0j9lJIle8f9x20Hpi9h2baDQbVYu7j7wJswh+syo18tI+qdG2Tf18r3b/lL7uq7D1R7Oi+/auvifse7r9+6YyLguns7F0FvIFzJucmG/fJ1/oyfTN/XyStLm4Vhmb1GJ3aS/btddGutKl0mmd/e0S7FyGSTcXSkT0szWZZCma/IosE+Fy69/FdunQPlW9+p2oOy1Ud9Vu64y1j1xCWSG7p5XzzdGXS7cMZH0AKWB41qaoDR7c9Golwatl5J/63u2QCXhaQerdv2pbAfU7OkIcrhBKjQmNestbbEv7Ad1CWyz9tLruJcV8F67vOOg+3ceSB8KIq9767/NqUNi/mODVGXs24U7FpIWoCpZKDBF6tkFrFSzBCqxW0qVl+aVkSZrDEL2F6Ssupe9NKGB7c79REGZeG5IeL7RbSS9dSE/l/CFuXLh47DOTB8MarJpGWZNCk3Yt7FBaj2mHgdB0gJUN72+bBftjj2VJmgsHrSkadmktq4mB6pAOf7M6cJIU2WWs2iQkvhdtSde2lAw82mac2nG8LJI/MJeGelDgeJMwi2ZMlBusFWUcdwePAIjIx6vSajTmJn4oc945Q6dNIFmDnpSVdJcZJrnIoFLNsFqyOgBebGnHawDaa0xtMIlkgWDlGwCQhXI5zSQfi3pNO21ZDwfKAktOy/t2kt369VXrPVGPrldPavF98JIZwWawef5ZL4gFTqet+5YSHgexVRVm/fUO3ZD9dfxoFigmnTbV+yL+DqQ1jqWV4lFLRakZHMBvAkcsxeR7VK/GHw5zwcOtmoC6R48AiPhLl/h5RXqDp0G6pjcfZKRD1DLxCDVbl9I+Eto8UfKJpFmzGXsnbQUa2m6lSs3I2m6nR8iZU4KkBIeMD8LpD810iYPoEtGkJLm5Lfot+Z1ZBm6a7o12dIou2thVpIvJf/QA74rL83LgTShFk/ppbGCQSxQW3m+i6S3Ptf3bvgYW/XqblzFFv2M1xKWPa51EKS5IGM7NpdKMl8P4tVTA8E3A3XVD2lyl1PsFsN6YJvK2KZMKG6uIDXFYADx6tCdN6XkBaxoORJ+M0LppfEDmdXassa43nn5WMHuSaRulZE+1jUcM7UiFKSmyvqMD5LsrvvnW0tGk1PS3mGk62aZ1SvhVtS5US8dqNWxuAsZEdh6ee0zSL2WCSevbN4zVUgTYKqh8gbyGrq977+pwAwUEg5CRW/92lsfaxWF7nLqZ3fR7v+ZUYcqtD+Zx2CKSZ/xQZHx4w5jrCX8LaT10FZTlZCPXhizDdhL+Dk9rZOeiM8kr/VQJJS5dJDqug6Fm5lsWllXgbJTJmmaXT5J6Op59bAu9lLyu3qpz+mJbG4mnbd1znodjcwbpG7lp/ouKQkPvO3Cq7Y8DQ7Xkt71rGQH3w6B8tcy/ngMTkeQeYLUm7aO/rI20updppXbIdm0PqyAczmwnXU8Skno6nn5mF0+GWhlGXmFXmyXIjR943mk3qEgtY4s3ed/Lc0X/E5vXB0MWTZYpbqWHU1Gk/S3HeQauu1sXZSxb3VfrDVhBQq1k6fhjbpepe5br87WRVpJYldvoPwf5eHbGTqxrp41YD6VOR1BZpzMuaS9vPRO6Xtn6kXfbaNPsuvDu3duP+5c80T3I33H0g7fh7OrpvFeXojXPtyr42J/NVbrF1BSvdoLZ8yx0Yd0sx6q7b0M78ZbVdTL18Ym3w+U76/XAvTlbyvv/28CeWj6P7v56UP2x/qixMMm45+py6XNV21hFG4BEn89cF835nDfpJbtyY+XgW1OI2XvpCXlbVMZ2w12+9ptn7fpryXvLuDg3brAdqFjknSMjDoMTbO5n60eqEdoTGnlpetuHmi9K0nzPqPM45w+sG/SXKTaRdKg9UbG6y787q0K+3jkZmhgVOtYynDXzXroWD2JbLPrIDWq2yd2sEianNmr69qoazGwXTeeFBOcLmDU4Wogr3eRba3z4lVC/VcyfE5ZE0wJUrsmm7tgemteWxulsVy0iwa5ldszGW5FZd1BFDvoVJnpZwtS7Xa6hN5ocBlIHxujW7fHJdQC0SBjDRqnzpwOtf5y8wld9Cn7H3r2Lee1K48l3utImVGfvL/4iZL4xTjmZ4nOAnkVgfQ7D1K9bStj+61un+T9jFXXEu6W2DalSyDhoNp54RJJ/O5c7KZD8gzzhPJjUzLOvHIJUngocgJfuJHEDgZXRrolg1Ss23cbSL+S+ebOJT/cKuEpBN3+Fpl5lYE6haYwhLqqo26uSDxQPffqSpDChoTfCDH1AeXCyHNrAF0WDFK98kItlDKyjbaqKhnvtYz7sc7KyGvO15acB9Jbv8E3aX6ZxFuyp72yCVLHQppv8V2/TcE6aa7dDMRuBVx6aRYNUr08qkA+Z5Ht+i2rtaQZPetZwsEiuas3sM+x91VVc5Rr7E+oJVv20hxdkFr8d/f2TZpvFX2B/A8nJyfJrzwZWVZh/PfbOV6aL80F77ce7ozfqlu57Xk7d9aPB8jmBwgeyJk7FikzWG4gj+733fTvJ73V+uMbOj/rv3Veb91IsvlVFj9wZn8+gX3+aNUvdIzdDOdF77iZ50Vknz9OOZaYkTSD2GsZ8YMGALATsv2mg9IBwL7J5vUeH/y+OQAsTh6+dyj71aoAMBvZvBTuQtJehlY6ANglaR5EfSP5Dx+XDgB2rW095T5oXDoAWEpmoCodACwtMVCVDgD2ScIPppYOAA6BEahKBwCHpBeoeKczgMMkC72rHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwjP4PBMEnBmOvoCgAAAAASUVORK5CYII=", }, - "dexag": { + "dexag": Object { "color": "#13171F", "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASkAAAB5CAYAAABlYNfBAAAACXBIWXMAACxLAAAsSwGlPZapAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAy3SURBVHgB7d3xndtEFsDxl/vc/ywVoFwDWRo4FAqAhQKIcwWQcAWwzhVw2W2A3VAASa4A1mkAlgbOpgFYGrg5vdUIP49H0kiWVlr4fT8ffWzL0mg0lkZPo5EsAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYn3Nu4YbzJJL+STFkAgB9FZXIlTvcOpLukY4vhgsBgL6KSiR3hzuJpHtqvj8WAOjLHRZNXUXSy1wZRdVOAwDJ3GHRVBZJ7zIyXS4A0JfrF01dRNLJaqYlmgLQn+sXTWWRdC4bps8FwL31QCamFUzx8iRx8ssHDx48DebPipd1wzyrYp7HMiFTsR754aYYNkW+bmQARfpVulnw1U2xjGs5kMm/vt74dDct81TTV3kbNE9/RGOWmUlbZKTt8A+r4VRtiCiqkloJDrE+Gh0+K4bXbrchP+ZXP13n/Lmyu8VZMfyYsIwLl9h3zKe78POsW9L+wZmrrMV78et+5Zfb5KptvU16az+8lI58Grlfng7f95j/QzP/847zP3Dl71TNn0fSPx2qzEyax77sLlzadnibtisPeAgVBbN07bq0RYXWcgcS16M2j65DZeXKyqSr05Y0T103/3Nmp3PlDtlWaYa+cTU7hit3Nlum30hHPo2HQZ6zjvPbPHSt5LRMfjXLPop8v3bDltlj19/adayIx/ZXmYezYngmuyGutSmGF5HxqZ02tTJ7XoS1Z3K3NsWgYfrPUobW1qNi0L5cmf+srxoVHhf5/EpaaIheTHt76lUMK7+c38wk7xXDh8XwkVmG7mw674uaZB8Gn69N/jcm3fd9/h8Vaa2CeX7yy3sTzFfRdf5Utnl66t9/LCMo8qc77cbnI/OjNfpL3Ra0SeQj8zm5/50rT7Fy2W7X1zWnVu/8NGOVWbWN3Pj0rUy222L1+WWR90+K1885FTRccxSyjEx/UjNt3WmWHs1GDWWDdXiTOE8eyW9S5esSIgJXRpuvg/Tzmmkvm8o8YVmSUsZuPzqp+40PjqR8OtUpV6d0/PLfD/Kp0VBSReXn/8rM+7Jmmj5lpvl4XjOdjaRaIz8/T+b2m05+cJz+bbny9CV2Tr6OFZSrD5G1sBc13y1lRMFG1OnWHLe/0w4acrvd07CzmmkOqqQ65iesOH6JTDNUJRXuuL90mO+z4HeJVg418+s6Xpn5cjlAhzLrVEkF84bb4b8FWy4eTcVuIm6thNwE0ZQ7oJLy858Fec1kIG63u8evNdPcZSVVRSm2veY4Ms1QlVS4rDxhvgcufmEmNTqxUVhSxdgxzboy61VJmfm/CpaRy4T+IvOiR/iNbOnl0VeyL9YAvCmGS/P5aWQaraBm1SgYWMp2/YfO67V5fzRkBdiHthWJvwRuRredRr0vhy2rKgMdkSfOXrVHbWTbrqhXzlIOdrl5/04OFFmP27zIgPwydD9cVaOK4WuZ0KwqKd9IZxt1l+E0xcaxkP3+QOrc9t3xDbqryHTP3EzPs/3620p5sK4TPm3bCDqXMvjJv+rOkEW+tw29Hx1QuWor9n/M5783Tlw2etsLGyvZ/jZH0l456Pp8apad1EaZqK3MDqX5/Zf5nE+5z8wtktKd6VLKo1anKKrmyl3sKpYWduf+NnfIrsfRwKH2HCupNrpzV/nWSOr7AyqqS/M+ZcfL/WtVybz1n20F1MReFTw4krorPppaye72spCJzKULQkhP1T4IR7qyn08WmX4ZGXcbTRXzrGQ/tNc2rRdtvaan4LsWbGS7nnrEXrXN53e4THaP8NpTecgjeDIficTypN6kXNr23Qe0/ewfxfCdH63dJNauvFPhPLUntk+ruhSf+9ELqe+KoHvqJ+bzOz9O09D10ig32lXEbbseZH7UKmVbG6LMBraSsruGrvcHMpFZVlKRvjfV5fZFZPK6iKui0VQeGa8N249lnjay238qyldM2r9sUTPdRoY9zWhkdjLdgXXjzmOTSZmvlSTwlcvr4u3nxaBXmjL/1ULKg81KygjpbcJOrMt+5/NVVUJ7lZTb3kKS+1Fv/cFD57n242+j3Ni26tN+YpZZu312KLOV7Pe1G5vtd5fJRGZ3utdAf8QsMn7ZNFND21Q+9VWLBnZjfC82QZF3rZy0J/1SJtyAKn5n086jP0q54+cyEH/6oRWVHlTOZbexPZeyktLo6iLhVNBWGE2nfLl/te1J+v7bKlvSvI6tp3pjltkAqoNJ5T2ZyL2opPyGt4x81RZFVZ7WjG+8TWSu/GmvbtTVDqaVmu68n0m50T/0w51EimZn08vdmflqJWXZ2zz9TXavTiXRisqfMj336T0N0tGyWEhDZeUru43sHrQWscUVwxfms61kbGT6RThj6qleQ5lp+ntlNsemCRiu/ibivEMaZ4emkbCMpUm3cz8pk86VSecs+C4L8n/pEq+8uN2+Y3nk+179pNz+/Wf/dQm9st1+P6SldOC2N9LGtg/NQ1Yzj+0H9H3k+4cN3zd20AzWSb+PXqGtKbNM2te5sczcgf2kguWcHZrOEGYfSfkfLvZDr2raA+osJX5OP8doKjPvN8F3S/tdUQaLKe+vcmVEoG0pWTWqGD6+i8ex+OhKl7OQMuKwV3P183c1s16a93mkcsj9a6w9KTzli13lq071bmKRvi+zheyX2Ubm5ZF5/5NM5D6c7i1rxj+VDvyOfB75alZtU36HycyocGe3G85ShlvuA+knvAH37V3vbOZUcCllA3tFo6xPw2lle8Pt7SjZPeWzp3o63dvIIm23iN8PoJEKu+6ihS7D/o5vZ3o6V0XDumKjH3TqzLqSaoiiLnv+qHrqFIs6ep+ajSA3728i0WJm3v8s82BPNyc74voKSCuGVTVK4pFO2Fnxy9uR+1f19i77m0ru946d5iAXduD8VurNosxi3LYjq83jO5nI3COpuk6XL6SHhmgqc3f4YLwW9vQzdiRuvfI3sanzVHUzqOzdShPprGgrmhOTzrcNy7AdO780FVy1HW06NEfM7XfUdXpmPl9PGenNtpLyG81J5KvLAwusLprSRsKkBuixuLJbQWZGxSrjjXn/oUxP904bCTySaekOlvI7ar7PzTxf+9cv/bjaSsZUctX3uV9mbtJuO5DabXDqMvudiaJsP69zmdCcI6m6U7BeUVQlcn9gZegbeo9dh9s3fCRnr+Sd11TGNkp45vrdIuJkWLa9Ip8qKnXbjpGp98zpzldVFrlsG7NTKhl7L6BGa7rtVDfitnWNsZHY7bJHLLPk7dBtu0XYCw6rxG4+fy6u/lEsg7UduREe5eLij5q5aGqYd+VztF4G86xd/eNhw+durVM3cLdd57ZL52opidzuZfkq/VPXsnO4tMvpeVsZmmn10rt9blbjZX23f5nd5j9LWJ59/IvV+kiZkcss9vjgC1f/sMNquzoN1iepW8TY5nrvXqxbwEYOjKICmlZY6VXR1FKGs5Dy9g09YmvEsTHfHcv+PVo6zWd13Qr87Rl6ZfO1H5VJ+djhs0j6djnVPWFj0EOw3l9XdUzU86GllI8rXon/h5lgnswMdTQdPeVfyH4Z/ubT/EC2p1pHQZ7+2dI0UEU0z4LxrU0K5l7AV8H8YaN807LHKLM6C+m2Ha5lnt0ipufu8KmaLv7npL2jKbcbSa1c2j/Z2OUuOyxLw/i162fQSMrPX3U07bLOoWUkT1euuyuX2K3ExSOa4w7rHEYtyQ/mc+OUWZinH3ukr5H9pO2zVt++MaNx5T+7ZMFoPcd/KANz5YZ8FfnqLOXPECLpLWUbBd7+R6Arw2WNzqqH3dsfvzqqabvJqz6dMl35l1InPv0skv6NWY52WdhI5FYNt+3jU+2gXTvL2nQyqV9nke0D5DY+T9d+2PsPOLe9zWQhZdQUS69KS9vr3nTJt9s2FJ/4UesubTB+/ucmT50v7Jg8LKRjmYWdZn1aj6WM0JRu3/qHDZmU5fhE6rdDLb+zKTsHz56rj6JGa4h19UfqTDpyibfFzOkodV+5xD8w+LNxibfF3Kfym83VPV8pRNuiRr66UNfOdSoj4Uh1ON/LnHLs6T6V35wazusexXLtykcGj2kTWbZGda/6nPIAGM4sKinTbhNTtblMQaOplQCYzFxO95Yyz2du526+D8YD/hQmr6Rc/U3EczFa2xSAdnOIpJYyb0RTwIQmraTuQRRVSY2m9J9NNrLtEQ1MoepPtZG7//MGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAe+P/Y5prDKzUFBMAAAAASUVORK5CYII=", }, - "oneInch": { + "oneInch": Object { "color": "#323232", "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASkAAAB5CAYAAABlYNfBAAAACXBIWXMAACxLAAAsSwGlPZapAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAACQQSURBVHgB7Z0JfFTl1f/PnSwzk3VCAoFAYEjYDRAUSHCBoOBSFwK2wlurgNrW/pVCrcv/Uzdc2tpqy6J2UStY6/ZWIYhWrCgBPwIJCmGRLZAMS1hDMknInsx9z++ZucMkTCBAAmQ4Xz/jzNx7596ZkPnlnN9znvMQCYIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgCIIgnFc0ukSwZWTaaqpMM3WNUk2k23Uip+7Ss2rXZc0jQRAuWgJWpMJGZma6XOSs+TYr25w2aU60OXjWlJRkGpXYmb4/4qSXVm92kKaPtVjIWVlJ9iCdbI0aOevXZeWRIAgXDQEpUkqgNG0xufTpusk0dHBn26w3b0ijhKNOOtizC414/WN88DyOpmxR5hB7tDlUvW5feaVximxq1J+BwJEgCBeUgBQpS9rEwoevHGx/afWWhYlRYdM+HD+Suvzrv2R+YBKlffgVpZtM9KOYKErpEkMsUkRWM1WEWWhbaBB9sKWQPtu1j8pr64l0bXZN7qJnSBCEC0YQdXAs6Zn24B4DbA37tzs9zzNu7JM464pucSw2++3PpqdYrli0ioISOtO/GxvpwdXf0+2HnZSw9wgFb9tDpVsdtKGmjlZZQ6iWNfuyeBv1jI6gfWWVVF5XlxHcbcDKhgPbHca5g7sPXBCcyNs81xMEoX0xUQenZm2Wg1zabIiV2uCiDERIPRpdCBNt4w4cI72kgig2kq74+Bu13SA4JYmO/uR6umpoH5p2tJwmbi6g67Y4aFZkOC2aPI4So8JZxrWnvS9oJDtvy9B1bYP3eoIgtCsBke4hwuHUbAGMcBap2X/u13PqDVYLjdqxhzY6K5VIaZzS6dW13tfgudY9jly7ivyeM2hwEh3+QTpN/28OG+2lDp20PNL1jC+n3mR7ac1mWpa/P7smZ/FYEgShXQkYT8o8cmJpJ1uks7SswvF0eFjGtOIyur9HHP11UyGdLRAx8z030+clTpX+IUJLNwXRWlcjTfrgS7JY9RhndpakfYLQjnT4dM9AM+nz7r1tnM0WGZ6x5Wipip6mHS0jp0k7SUTKTRrNi7TSLV2iT3nO42ym1775KV23bgfdc7yWLv94NTUsy6UrE+PV/qpqbUzz15jTbp8pqaAgtB3BFCDU1NDcDTt2z/z7Ew/SI8/Op63HayjtYAl22YxjtoYE0XPRYUTDU2hbwT4ysVjRkbIWzxlRVUNL0gbQ1ys2UPoWd0RW1DmaDi5bqx4HkT7WMjxTnUDXaKhm0jKjzEEZFbWNvXnTLBIE4ZwJqBIEc1rm3P/+5bmZZRVVdN8jv6d3i8tpUH2j2geBun9wMj3xsym05Ks1NOvOCfSj+5+kvIOlpzxn0MgBdOQHo2jL0RIqr6mnKEsIoa4KNVWreYRw9b7D3voqRFjPjr2crvvnZ06NtCy1UXft4XA1LzSMsiU1FIQzJ6BECgb66GEpKx6/bzJx2sci9AS94jjkTKlrtI3uaqN33nqJFn+1mu6//UZatf57enTumzTiSCm9WFpJUbpO+4Pd2W+PBleT82qdIpWRrlnYfK+p9RjxoRQ8OpVM7FsZwJhHKtn/5Q9beovZbL4vrMnNeosEQWgVAZPugZq1WdmrdC37caKMnl270JiMdLp7Va5tBHtUaTdcQz3i42igvQe5WJB++8YHtPaff6K3P11BP3/1X/RecQWrDBHEbGZ5NU3ndBHCBSBKDSs3nnS9htztSsC0TlFKoIIS4mjZkCTqn9STFr3yO3XM9t176cCRo/Tlmm8pd/O2jAOHizMsaRNnYyRSlU90AAoLC5EyT9V5dJNvdk3TnHzvcLlcb/Xt2zebBKEd6fDFnM0J7jFw9t6DR2xdY21038QbqKyiko7FRNEj035IURFhNGpIf5r54us09orBNGbkEH4+gL4rLaOwLbsoyqXTR11jnZ3HX2l58dBh9dxIF32BMAWnJFNV+kBaWVdP2fuPUmeTiXZelUJPr91CkckpVGLuRAcrasgWHUVDkhPphqtHUOb4a8gSGkobdhbYXA2Ns4K7D6KGom0rfc+NaLBhv7t49GKABcrOYrSGRWkKPx3At658s/MtlcVq2syZM6Pnz5//OQlCOxFQIqXqpUibVXa8im4dk0afrMqlz1Z/R3/41b0qigJ19Q20ZtN2mnXXRPUYN1tUJH3w+SqV5u2+fKDlb0/OoOs58lqq6fTGviJKr2tQgqXSQQ6uzBw1uQ4UU8jhUup/5WDqftvV9FG4mZ5igXLFxNPga2+m0up62uespk0Hy2llwTFyVteRPS6SRl+eQj36DaLV6/Kovq4mw1eo1Kigri1uKNp+UXRm8AjUCnKLUkuMEqES2pOA8qSsaZMW33lzRmavbl1oeU4epXOUNG3CeIoKD2t+KAxs76jf9sJ99OxPf6PSu7QZd9P0zOvV9pCgIFqd9z39ds4C+v3mXapa/eedIlRqCO8JwgUQWWFeYFGQiSZ9sJxCeg+i6M7xZI2MVvchZov3wlfZO9G4Pp3ps+/30x//PJ/Kiw+jfmJazdqP3mKRms0i9fTFUn+1e/dujFDOacWhenl5eadhw4bJwEALFBUVUXV1dSZHpKkmk6kXb7JxJKp+B5E687Zsfriyd+/eDhKaEDAi5YlCCte+/Sea987H9PyMqad9TRiP0lXV1tGCrC9oa+FeSh88gG4fd1WTY6x8THnFcTUS+OqmfLqfBQl+FUQK9wYQKsvDU2g/R10QKp+OChQdF09JqSMoceAQ9TzGGkI/TetFC9bsovf+/ipVVpQ5rVa9d021toF329m2z6zLWbyEzoH8/PwM/hJk8i//UN/tHBltDAoKmtuaL8OuXbs28DlS6fTofN6H2J+aS8JJsAiRw+HozT+jgtMcWsrH3tOnT58sErwETDGnwdC+vWn8qGHe5/wlo9CQYFrLKd68d5ZQeWWVdx8EKNJq4chpPL3IKWFzgQLVLGJd4zrRS0/PoAXhFop0ueiL+Bjaz1FTDjooeIC5Xvfel5QYHU4LJo52z/vzUMbR0obln9Dyt16lqnKnSgVfz9lDY/olUOr4W9QcQ0Og1HsmvTedBTC4+fZ0QUHBChanFfzZZ3rMbu8N2/jLsoGPO62KG3/pWwH+2LX2WKFlYvhn/uaGDRvkZ+lDwIgURsr4D5Zz1fotdFlyL7UNAhVhMdNLCz+iP7z6okr7YiIjmryupKxciVVzgkwnfjSVNbXKS/qWDfAhLILVKf2onM89N9KdxhmlC42bC6j+81xK6RyjJij/7IoBNDkliW7s20Ptryovo9WL36H62holVOuLnNTD3pviuvfEbnuI2ex+39Q0+jkVHmGaCWFi8Snl22yI0WleZuPj5sJzIuFiwxYREdGa6PWSIaAiKY5Alny9/nvqk9hNPY8Ot9Lb/1lBBd9/TDmPB9Guwp0UGXbCHwoNDqKlq3LUcb6iBBCiR3m21ze4R/hs3ePJzFHabWNG0Ld9EqnvpOvdEVVoiDeqql+WyxHVcup+vJqeSb+M5t2YTjcl9/CeF0KFqAoUlFSRld9Dv7Rr1POuSf09R7nsdBqMqInFphCC0wphao6tsbHxdFXxre1SCnMum4Q2gf+42knwEmjpnmPjzkLlNcVGRZCJo51F/1lMtw7V6JF/N1Ifex+a//ZH6kCkgBgFXLpynTrOFnHCXMdzfOsqeRSvE6dtOBaMvvwyTgunU6+u8fTg5FtoaD+7EqcPw0K9URVo3FxIdYu/VingvrLjaFXc5E0eKthJxUV71GNEVHHde6loqv/IaygsEvMJNfupPiSLUypSNkRNdG5p1phT7eTzt3aU0SH1UkJ7EViRlGYa2qube/Lvd9t20WPzFtCwQYOJev6Cel32E6qtrqRrRw1X+yFkX2/YouqogJmFKNziTrdQ7BnFXhXunRVVFOMRsCfum6zubx0zkh6ccgtFR0QogTKPSqUdcTaVAhqE3DhSVaPPXJbTxEQ3OLR7Z5PnI27+IYVFRTcZCfSHpyxgMZ26LKBVnM5zgvDwtU7XmbSU/a9rSRDaiYASKRYV+62citU3NpK9e1caPqgfPXTP3TSCR+3GXT2S7v/xJOrRtbMSKNw27nSQ8/gJAUEqqHmEBqN+ECeca+/hYr/X69WtMx2yd6fXnpxBD3BktSDCJ5rK3UauomKad1O615Py5VDhCZFCrZZuckdrhi/VEpyiZVAbCFRrYaGCxzWdHzqa7+PtMOgvl2FzoT0JGJFCCQLrSyoM7kZP983MselubykiXN0gQPCYDF/qX5+uYCPc7j0H0rwwj4kOcXJ5fKng4GD6R9YXJ10T18LUGtRlzfARKUyR0VnrtoYG0aT3l6NB3kmvhTcFIFCOA8XelPJ08GeYQOcZHhJfmJSU1JsFaRhHVmNx48cxvP1aESihvQmcSKqRMuAZgVr+4m/YvosaXCcmCkN8MNIXFx2hhOr5Nz6gPQePqInGzooT0ZQl9ERZQUVVjXoNtg3u15tefm/pSZfFRGYQzfdDhw/2Guil3+6gAVv3qkiqJSqcpbR73xEljkb1e31tLZ0KFt0yugBA4FmQ8pAC4saPpXBTOC8EzARjzWSa8JOb3d18N+UXUomznGrq6tVziAxG8PBFgyD9/PmXacW3W+i++39BCxe8Sa9+8Ak97vGb4E3hOERgjSxySPtgqidymrho+TeEEgdEUP6Akb71q1xKq61XI37Xf55L6Q9PUS1c0NLFHxCm+NgoKmXfKi4mSpUnsBQ5WvqcqE7WtPNfg+spSFQeVlsKFM6bn5+fGhISMoZTWURrvTCJmZoOCDgxqdlTiFpYX1+/sl+/fu22PqLns9r54QS+JuYo2lAp7u/98Pasth40wL8vRm/5c6IYFxXqQz0/E2O/g5+r6/PT7EAftAiUHueq2nz74r+pFA6dDTZ/+CqVwLDmX7gdjn0c6UQosbnh/z1F9Sw+E6b8hIpcYZT76YdUfaSIDi1/23u+Yh6Rq2toUI8RdcWzeByvqaX9R47R3b95iXL/9We/7wPXXfPYi2pSss7//bCqjoJHD6UvB9tpetbXJx0/buoDlH+wjAYmJaiUr1+vrvTxy+ieoGfX5GT57Z/uMc5R+OnX9OZf3my+28O/yKcvuWefKTk5ucXC0V27dmV6zoMvqL35a/mWzV+gZ8405ePPQA0NDRn8Wpw7k85uhNJxttf3h48Io9h1Gp2Z71foeR9vneLcrak4N3Cc4fUxrQazCAJyNe6ASPd03TQTURRStx5sZqOxHVKoysoqJVBIySY/+gINmHg/Wa1Weu7J/68ECnRL6kdlbJ5vzD/RCz046MSPBdEU0kekfSgEvXbkUFq6Klf5VYiymqNaE0dZvWnfZ+u20f6yKr/vG+eOiQ5XURTEtKz4kNrOfzk2tvRZ8YXkX/pfNf38Or6sszw+0Vh+vpDaAE/0ABGx+9mNbdPwxcMUHGoFECcc6zHcMXF5Gp19CYXduD7qxegsgYAgamERMWrOZtOZD0xAgBbu3r37z9Q22OnMwB+uuXz9gp07dwZcIWiHFyl0PrB36zzrdR5hy997gL/wFfSjcVcrkXp32UrVNyqaTXMjnXvm4Qdo1d4K9RhTVHbkuCOcr7/7XgmP7ukh5UtFtXuOHnytSeOuolfeX6rOX1VT500pAdJMiFPsgCT6KMys+qhHson/2nfb/b53LdSq6rBKyirJYgml8qNH1PZG0lbQKYCRzV/y3r7ChL+iF8gn0jgFe+pUB3iEIMYQp7MoPD3l9SEs/AVddKbTSXwinLaoOQOzPJOyLxS9+d9ifWumPHUkOn4k5aIMjNAhHevbK4HGDh+ifKW9h44qY3wIG95LV+ZyqhdOsZ060X8claqAEgK1etE7VFXh9qERSRnC09hMqFSJAG8Lt5pVy5eCokPK27KwIDmPV6mKdDzHdTJ/PIGW/eU5uosjO0RUz9vC/dZJYdIxRvRKWaBw/gg+t1Hgqbv0Paf72IioLqAwNaGZX9N8nyEE69tYnJozMTo6elFrD/a8L4xWrqe2K+mAffIUXVgg2gsCKaIKiHSvmE3y8spqGpHSX00wBoigMNqHynDUQu05dJhCbHFKoACmphgCBTbnO9Q9UriGhpMb3UEEIWJo35KWMoDPd0Q9RvRVwgIVycY8yhFQkY708sVZ96h79Fb3hzXKvVJNiUfAIsIsdGz/Xjx01K/LyrNlZNo60KozLUYgBw4c0NgQRzpmp3aGhWcsRzKzW3GcIZxfUdtPjLZdBHMieRzJ9CYFCB1fpEyUjSZ22wr2UpwtSm1C2oVYCNXnEKvbxozkFO1T6sr+E0CKd6xob5PTGGUILs+oXnMQYYGQ4CDqztHUXo7SDO8Kx0Nson2m1qAk4Tf33kEtEZuYpMoPgJUjsuqyYo9oatkQJ3RFsFioQw/zQwzq6ursrTTx24pfnirt8whUTDsJlMLJ0AUGLXZYLM97TV17EAjLrGeTpj9z//Ov0Ls8uvbInDfVCN5eVQO1RXlRECikfpgjV7x/D+3IPXmkDfsBBMffED+2GxEWuinA5/IFxZ/lVTVNts2Ycitd00K5QgWFqTQPxERHUEHeOvVYJx7WdqFti+64kI3vYHKfKywGGMWz0/klJioqqkVfCO+JBWomtVNkxyKYd5E0/9P4vcykACAg6qRYqGbvHZmZ99i8BegiaUc7lT/+6l76ZGUOpd/9a6rTgunKSXeqKSd5ng4EvsBn2n+4WI3iAXhFtT6GuAH2w68azB4YaqWaj+6hpQtqssw+1eOvP/mgeg++BaOhETGkmX2irggrbeRUT0f9DWlz4Gzw43NqeteBwSIPb7GQqDqokJCQaE4Xh51JNMbHjva33Ujz+OHZjAZCeLI4jcqrr68v87wvnGsoXy/DuAQb121VBnDSz4EfZ5B7tLVVnMor7EgETDFnXW5WFqVmZnOKlLlxZ+Gc9Lseso0YPJCuvekWaohPVsdsWfVFEx/K4J3fP0p3P/6SEh34TC1R29Cgoqmrhw1SzyFKzYGR3sUW6Y3GMGXmtScepDse+4P3mMheA7yPYcYf3rVVvS/NJ/3gwC2bLi34O6VP8teV0iMu81qborVk0Hsiu6km0xklEOjR9WxLXUeNwk/MqeTHtuTk5LZYrmwOn+eh5hs5up3H7x9TkjBA0JpU1QYDvT0LX88HgdWqJU+lRw50Xrkr8waaM/sRirS7BQGjeQUb1530EnTjRCTVNS5GdeEMs4RidM3v6VFugLTPHByspszU+zHYsf94M/HCohBGCQSwdIr3Pu4aF037tm1Sj91tWhTKPKdLDI5C/H5mCH5wcHAeIgtqJf7Ma45GNE8BaatPgwnUp2qL7Jku5EBZSBu1T4ZYb/K3g6+Dn8OKM2ihg8/cizo4Adc+GAsZJLDo3DXhRvrGUeIdzUO5gT/uuP4aMnOKNiipp6ouR6pnVJu3BETIqJ0ywMif0eoFfaia11vd5ZmyE56QRMFWd3fQUB75qyk5rNoLp4weT/09ze900gOycvhcMJvNumcayFmBfw9O0/xVzrf4Er7ePRfpBOqVrT2QI7wY6uAElEi5l7SijOvSr1C9mSBSAJGKvzQPEdS4tFQK5RQPq8qgqtxfdNQcf6N/Lo8oRXr6UDWPpjDKCCISkr3bErvGYlkrNT2m1+Dh3sJS1rssEtqUAwcO4AtrP4OXLLwY58TZ7XZEUw66hAisSMqlTcPdXZk30vL8o97Nxpe/OePThymTG9FT74R45Q9VNBuhOxPgUSFdhFAhmjLAyCHm9Vli4lWqh+tgnh5qo7rY+1It6+KBHZuNEoSFHWVl445EXV0doqnW9o7XOc27VAcuLjoCqp8UO89TM8ddo6Ko9UXuyKmlKArcdPVwleJBqNDCBca5vygJZnrulh30xZr1p30fpWyco18VFncwRguNKCpx2FWUnNiF+vSMJyuL2XEWREfRUSWSXiHVTtsJsy3R6RIhNDRUO5Pe4U6ns9UpldC+BFIkNQ3/yxw3ukkUZZjS/hjs0/AOKRoiIURBKNiEIYrH+Y599Ni8N5WnceNVw1WJwalapaD2CeKE1jDAiKKw5t7AywYocTpaUkG79x1WxZxxMZHe0T2Joi4eZKHTi4eAKUFgw3wqDPM+fZNpUfYutQldBYqbVZYbwCiPjYpUjxE9IQLqFBnujn7qSJUR/PXfn9KCJcvpnRceo26xMUq8UGLgCyKx5tEXTHVzSISK0NB9AZi7D6BtBQe8BZwgPjaaQlx1FyqKEoQOQUBEUuFXZqpRm+tGXdEkijKquP0R6VmuCgKD/lHocIDniKjQmeDdz1bSvHeX0l+fmEHdO3dSkZE/vwoeVPPIyoimXvlgKW3Md5AteQjVm0KbCBR8KZQfoPpdRVG6/oxEUYJwMgEhUjwgl4H7MVeO8npRwDNh9yRQG4X5d8CY4Gv0Nsc9qs/hI/3yxxOoX88ElfZBzHwjJq8wsauzNHvNSdfYWriPz/G/FGwJp+jkIU32ofSgZ7dYlYru27YZRZx5NblZs0loN1zuf7tWp3CB2JepoxIQIqWRNiEyPIz2u6zebZij11LZAcRnUO+eKi3DnDtEQwaod8KCofCS0gb39y7aoGqogt3ZMQTKWLQBkVddfT3lbD7RMwpLud/xyO/UVJj4EeObXD/IpLF5Hk8N1ceNNM+ha/pEEtqVsLAwnf/dTtsCxwN6ZLV6+onQvgRIZ05KxRSYwpITfhEW4PQHBApCNX7UMCU8WEQUkRJAZ8+fPfcyPTJngYq2knp0bbKyMUYAcTz8KoARPIjVNcNSeORvg/e45197j6OxYyrNMwo3DRI5gtJcDSd6WWn6dEnz2p/y8nIy5sG1kl+eaRM9oX3o8MY5/CgOhmwR8T281eWgvLjpwgeIimbeOYHvB6iIaCiP7MHYRrTz+qJltHRljhIpdDjAcQ/ffbtXvHzBa+A3qd5SbKSjXQv6RuVs3qH2z39nCX20/BtVWd48zYNRjnYu6Kvu9aFyslRrFr2RJmg6baz5NiubhDYHRZAOhyOPhQopX2vEJyYyMvIrFqprZaTvwtLhRYr1ws4ZFFWaowjNU5DmuZcxd/tRzcUJ6duh4hJ6f1m2V5iM41586F6aOHYUJcTFeD0nlB74GuPwpTDCB7GCUKE8HKkhUjyI07x3lygfqlP/4U3eJwQKRjma7bmjPG0hwihL2sQV7GtlcMCWV52zeBgJ7QL+DXft2oVVXrKplZ0E+NhhUVFR6/Pz8+9pqfrcZwEHNScwUBdDuJB0eJHi3z077ht49AxdDjCJ2IiGJl3nnjwM7wji9E3eNjaz328iTE/9/Md05w8y3A3zdHQj1slZWa26HWDdPvwSopgzKMg98odpMxAnw6sCWJgBIM2DQMGHMoWc8LlieLTQEKgTdVv6NJ+1esSXOg+wz6Q3NDTMN5lMZ+I3oZf8ioKCguzGxsaVWFLM2IH2KYWFhZmeligQKh2LOrBQSSlJGxIIdVJ2/A/iBAGYnjle+U4QKkOc4Cu9/elX7De9QoOSEumJn/4P3T7+KnWMscaeUf+E54iSUHQJcTJxmIbSA2NVZLXIqNXs9aqM3uYYETQFh1C3UTc38aGslhD2sKxNBCos0kYsSlRdXgY/zamZ9LFt7EsFxFJlbQ26CLCIQGyyfXpAtQq0f2GxavIa18mzE9Bf/GmOvFYG+lp455OOH0np/BdMc1eWP/mz/1EThZHWoZGc0RsK6RgECnP1/vn8r1XNUwmLElqyIEJS3hKLTrDnvjmdIsNbvP5v/+FeCRkChQjKV6BQamBP6MwjeZWUOHAw9R95NYWYLap1MXwpwH/cp1etaTuB8qxpR4J/2JvSOT17yLMAQ3uByCqbhDYhcCrOGSVQmIcX5RYKRDlYnfjjle507Olf3KkWCEXahs6bCbHnNniDpdpfef8Tr0CFRnZqsr+xUff2MefkgOLCTKQdPcxRlWe5dk0JlHQ8OI8gUj527NgGp9OJpnJttU5ek0tQO/VOv1QJKJGCeW1MdUF0g17nRu9yTIPpl5igHmMicainxS+ExpgAjFE6LI+F9sMPTrlFddX0hzsye1l5W/CgOg8bc5JAAaMAFLVRCV060fEDu0+0L3aXHiykNsYziuXwk4qcEeHh4Zhk29q6onansrJSLS9ObUBsbCwizjkccUZzCnfWC4u2ACZt+xsNbMsRwktqtDEQRMphPFiQ9YUyzOExbdrp8AoUgGeE9fJSknsqjwkpXnMQeUF4cHuFIzAsiYWFFIZ4lsnae+hIkxFBwyRvXgvlC6a/oLq8cP0aNQXG40FNVAtItB/n/EvcFqLgM+xP50pbia+Bx5+ajdS4jYXKGRwc3CQ6RvS2f/9+Z21trYPOcQEInGv37t34921tKUWHp+MXc+onRGrhki9UNIWGcxAYX7B95h//7l1x2GgR3Pw4XyBGiLImP/aCumElGkOg0BuquUnuizt6iqEEm5nWLX3fWKHGwQI1rD0FylMugSb+2XQO4EtstVqzyeePwIV6Lz7ncrTFuQzwGfv06TObRSqJn7ZFu2a0/n3IXzfP+vp6dPpsi/7nEFX9TFoId3Q6vEgFhZz45XqCjXOAkTise9c8XUPB5fz3lpI1NMQ7Dw+rvrS07FRLoJK8eZmBL2i/MjC5O5Xv2U4r3/+HMsp5DHGexaoEykHtDMxhHm6/51y/0N27d0fzt2vpHISqrd6L77mobQRF4elRjl7mWM0YPZ7PyiPE5+PXX4te5/72ezpqzjuTPu0t0Zbn6ggExFC1eeTEUiy+8O4Lj6qizfiYKFUicD17Ul+v39LkWJQdrP7nn8hqMaspLig3wGKiD89ZoI6FsJUdr6SeXbuo9M53KSqkd7EpVzZZSMEXpHbdOXqqLD6oIifPAqQOj/+UTecZT6FhKtrm+i5vhFofpHJY3KA1y7R7RgyxGordt3EczsNfbicLR/bpznOq9+I5R15r+4m35blaOLfNs/pLKp9rKD43uVMrI70yPmuep+96dmtLDnxWl0n1fe/8b1HqWSor+wx/Dn7Pxdv2nMvP4WIiIETKMjJzIf9JnAqRGjVkIHXt5F515Y5HX/AWWvqCOip4VzDPUV6AHwL+on7MftNtY9LUoqJfc1p3DaeCMN8xehfZayBF9RxwUvSEtA6Le3bm6Kn8cJFXnDze0zysCUiCIJw1gdGZ00QLfZ8aK7U88dPJasSuOYZ3hf5OWMYKFeaYjzd25FA6XFpOA5N60frtu1UqiNdj5A4pnq9AIWpK6GyjPj1iyVRxRPlOqxe/Q8X79zqxorI1TO8tAiUI505AiFRNDeUhctm6e5+qgTKWO1crGc+aftLxEKhtBe65fRjpg1gdKz/urixnrwrtW46VVaj9D0y+hWpKD5Or3r1aMebgpfTtQTZTDR3ekkMr3v4rrfvPRyeJ04VcIl0QAonAiKTyslRqNf/dJarUoNJnXTx4TP6McXc7lWJysv/kW6pgUOl5/QwWKYWziCOsBKo/uof++8YcFTVhKk59bU22TvosESdBaB8CZ45XaqbNHKqtSB/SP/XdFx5Tm0qc5fTrP71Orz05Q3lL5VE9OXWLUZFR2e6mCzQYPhXYylHWg7/7C21f/Df1HAb8pr1HKdhs9prhLExzrVZ6S0RJENqXwKk4RzSVnvmrnM07Vqi2KV98Q0tWrKY3nv6liqYQLcV3H6pG5tQtxt0dE3VOVUf3EaKwRV9+Q9NuG88RU6Ia1cMNntTQfnY18meY4RYLzYU41ZIgCO1NwM2WRzkCR1O2Q8Wl9PlfnlUCtXFnIaXf/Wuyj5tMuinE7+saK8uoZNOqJi2HIVDREeFK4NiKd1qtem+JnATh/BJQc/eARvoSjqamIlUzijk35TtU94GEyGCKiI0jXQv2FnOqFWIa66m6VCdb6kjanruKGmrdMVJpeaXTWXHcqeumPM3kmicCJQjnn4ATKVWOoNNUREAGmNrCBrcyu0EIe0shoe6mdfV1NbzvROKGlM6k6W/pGmXV5kgrX0G40ARkczS05J0x5ZaMP866R619h4UVSNPHsgAN5eHM3i7d1EvTdJuua05NY5+JXGW6i/IoiLJlUQRBuLgITJHCwgYubcOYKy6zuScEawtrchZNJ0EQOhwB22bWLVS0GJGSxUoTxU8SBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQLin+Dz5IwjUsPBVBAAAAAElFTkSuQmCC", }, - "paraswap": { + "paraswap": Object { "color": "#0058D4", "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASkAAAB5CAYAAABlYNfBAAAACXBIWXMAACxLAAAsSwGlPZapAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAy3SURBVHgB7d3xndtEFsDxl/vc/ywVoFwDWRo4FAqAhQKIcwWQcAWwzhVw2W2A3VAASa4A1mkAlgbOpgFYGrg5vdUIP49H0kiWVlr4fT8ffWzL0mg0lkZPo5EsAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYn3Nu4YbzJJL+STFkAgB9FZXIlTvcOpLukY4vhgsBgL6KSiR3hzuJpHtqvj8WAOjLHRZNXUXSy1wZRdVOAwDJ3GHRVBZJ7zIyXS4A0JfrF01dRNLJaqYlmgLQn+sXTWWRdC4bps8FwL31QCamFUzx8iRx8ssHDx48DebPipd1wzyrYp7HMiFTsR754aYYNkW+bmQARfpVulnw1U2xjGs5kMm/vt74dDct81TTV3kbNE9/RGOWmUlbZKTt8A+r4VRtiCiqkloJDrE+Gh0+K4bXbrchP+ZXP13n/Lmyu8VZMfyYsIwLl9h3zKe78POsW9L+wZmrrMV78et+5Zfb5KptvU16az+8lI58Grlfng7f95j/QzP/847zP3Dl71TNn0fSPx2qzEyax77sLlzadnibtisPeAgVBbN07bq0RYXWcgcS16M2j65DZeXKyqSr05Y0T103/3Nmp3PlDtlWaYa+cTU7hit3Nlum30hHPo2HQZ6zjvPbPHSt5LRMfjXLPop8v3bDltlj19/adayIx/ZXmYezYngmuyGutSmGF5HxqZ02tTJ7XoS1Z3K3NsWgYfrPUobW1qNi0L5cmf+srxoVHhf5/EpaaIheTHt76lUMK7+c38wk7xXDh8XwkVmG7mw674uaZB8Gn69N/jcm3fd9/h8Vaa2CeX7yy3sTzFfRdf5Utnl66t9/LCMo8qc77cbnI/OjNfpL3Ra0SeQj8zm5/50rT7Fy2W7X1zWnVu/8NGOVWbWN3Pj0rUy222L1+WWR90+K1885FTRccxSyjEx/UjNt3WmWHs1GDWWDdXiTOE8eyW9S5esSIgJXRpuvg/Tzmmkvm8o8YVmSUsZuPzqp+40PjqR8OtUpV6d0/PLfD/Kp0VBSReXn/8rM+7Jmmj5lpvl4XjOdjaRaIz8/T+b2m05+cJz+bbny9CV2Tr6OFZSrD5G1sBc13y1lRMFG1OnWHLe/0w4acrvd07CzmmkOqqQ65iesOH6JTDNUJRXuuL90mO+z4HeJVg418+s6Xpn5cjlAhzLrVEkF84bb4b8FWy4eTcVuIm6thNwE0ZQ7oJLy858Fec1kIG63u8evNdPcZSVVRSm2veY4Ms1QlVS4rDxhvgcufmEmNTqxUVhSxdgxzboy61VJmfm/CpaRy4T+IvOiR/iNbOnl0VeyL9YAvCmGS/P5aWQaraBm1SgYWMp2/YfO67V5fzRkBdiHthWJvwRuRredRr0vhy2rKgMdkSfOXrVHbWTbrqhXzlIOdrl5/04OFFmP27zIgPwydD9cVaOK4WuZ0KwqKd9IZxt1l+E0xcaxkP3+QOrc9t3xDbqryHTP3EzPs/3620p5sK4TPm3bCDqXMvjJv+rOkEW+tw29Hx1QuWor9n/M5783Tlw2etsLGyvZ/jZH0l456Pp8apad1EaZqK3MDqX5/Zf5nE+5z8wtktKd6VLKo1anKKrmyl3sKpYWduf+NnfIrsfRwKH2HCupNrpzV/nWSOr7AyqqS/M+ZcfL/WtVybz1n20F1MReFTw4krorPppaye72spCJzKULQkhP1T4IR7qyn08WmX4ZGXcbTRXzrGQ/tNc2rRdtvaan4LsWbGS7nnrEXrXN53e4THaP8NpTecgjeDIficTypN6kXNr23Qe0/ewfxfCdH63dJNauvFPhPLUntk+ruhSf+9ELqe+KoHvqJ+bzOz9O09D10ig32lXEbbseZH7UKmVbG6LMBraSsruGrvcHMpFZVlKRvjfV5fZFZPK6iKui0VQeGa8N249lnjay238qyldM2r9sUTPdRoY9zWhkdjLdgXXjzmOTSZmvlSTwlcvr4u3nxaBXmjL/1ULKg81KygjpbcJOrMt+5/NVVUJ7lZTb3kKS+1Fv/cFD57n242+j3Ni26tN+YpZZu312KLOV7Pe1G5vtd5fJRGZ3utdAf8QsMn7ZNFND21Q+9VWLBnZjfC82QZF3rZy0J/1SJtyAKn5n086jP0q54+cyEH/6oRWVHlTOZbexPZeyktLo6iLhVNBWGE2nfLl/te1J+v7bKlvSvI6tp3pjltkAqoNJ5T2ZyL2opPyGt4x81RZFVZ7WjG+8TWSu/GmvbtTVDqaVmu68n0m50T/0w51EimZn08vdmflqJWXZ2zz9TXavTiXRisqfMj336T0N0tGyWEhDZeUru43sHrQWscUVwxfms61kbGT6RThj6qleQ5lp+ntlNsemCRiu/ibivEMaZ4emkbCMpUm3cz8pk86VSecs+C4L8n/pEq+8uN2+Y3nk+179pNz+/Wf/dQm9st1+P6SldOC2N9LGtg/NQ1Yzj+0H9H3k+4cN3zd20AzWSb+PXqGtKbNM2te5sczcgf2kguWcHZrOEGYfSfkfLvZDr2raA+osJX5OP8doKjPvN8F3S/tdUQaLKe+vcmVEoG0pWTWqGD6+i8ex+OhKl7OQMuKwV3P183c1s16a93mkcsj9a6w9KTzli13lq071bmKRvi+zheyX2Ubm5ZF5/5NM5D6c7i1rxj+VDvyOfB75alZtU36HycyocGe3G85ShlvuA+knvAH37V3vbOZUcCllA3tFo6xPw2lle8Pt7SjZPeWzp3o63dvIIm23iN8PoJEKu+6ihS7D/o5vZ3o6V0XDumKjH3TqzLqSaoiiLnv+qHrqFIs6ep+ajSA3728i0WJm3v8s82BPNyc74voKSCuGVTVK4pFO2Fnxy9uR+1f19i77m0ru946d5iAXduD8VurNosxi3LYjq83jO5nI3COpuk6XL6SHhmgqc3f4YLwW9vQzdiRuvfI3sanzVHUzqOzdShPprGgrmhOTzrcNy7AdO780FVy1HW06NEfM7XfUdXpmPl9PGenNtpLyG81J5KvLAwusLprSRsKkBuixuLJbQWZGxSrjjXn/oUxP904bCTySaekOlvI7ar7PzTxf+9cv/bjaSsZUctX3uV9mbtJuO5DabXDqMvudiaJsP69zmdCcI6m6U7BeUVQlcn9gZegbeo9dh9s3fCRnr+Sd11TGNkp45vrdIuJkWLa9Ip8qKnXbjpGp98zpzldVFrlsG7NTKhl7L6BGa7rtVDfitnWNsZHY7bJHLLPk7dBtu0XYCw6rxG4+fy6u/lEsg7UduREe5eLij5q5aGqYd+VztF4G86xd/eNhw+durVM3cLdd57ZL52opidzuZfkq/VPXsnO4tMvpeVsZmmn10rt9blbjZX23f5nd5j9LWJ59/IvV+kiZkcss9vjgC1f/sMNquzoN1iepW8TY5nrvXqxbwEYOjKICmlZY6VXR1FKGs5Dy9g09YmvEsTHfHcv+PVo6zWd13Qr87Rl6ZfO1H5VJ+djhs0j6djnVPWFj0EOw3l9XdUzU86GllI8rXon/h5lgnswMdTQdPeVfyH4Z/ubT/EC2p1pHQZ7+2dI0UEU0z4LxrU0K5l7AV8H8YaN807LHKLM6C+m2Ha5lnt0ipufu8KmaLv7npL2jKbcbSa1c2j/Z2OUuOyxLw/i162fQSMrPX3U07bLOoWUkT1euuyuX2K3ExSOa4w7rHEYtyQ/mc+OUWZinH3ukr5H9pO2zVt++MaNx5T+7ZMFoPcd/KANz5YZ8FfnqLOXPECLpLWUbBd7+R6Arw2WNzqqH3dsfvzqqabvJqz6dMl35l1InPv0skv6NWY52WdhI5FYNt+3jU+2gXTvL2nQyqV9nke0D5DY+T9d+2PsPOLe9zWQhZdQUS69KS9vr3nTJt9s2FJ/4UesubTB+/ucmT50v7Jg8LKRjmYWdZn1aj6WM0JRu3/qHDZmU5fhE6rdDLb+zKTsHz56rj6JGa4h19UfqTDpyibfFzOkodV+5xD8w+LNxibfF3Kfym83VPV8pRNuiRr66UNfOdSoj4Uh1ON/LnHLs6T6V35wazusexXLtykcGj2kTWbZGda/6nPIAGM4sKinTbhNTtblMQaOplQCYzFxO95Yyz2du526+D8YD/hQmr6Rc/U3EczFa2xSAdnOIpJYyb0RTwIQmraTuQRRVSY2m9J9NNrLtEQ1MoepPtZG7//MGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAe+P/Y5prDKzUFBMAAAAASUVORK5CYII=", }, - "totle": { + "totle": Object { "color": "#283B4C", "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASkAAAB5CAYAAABlYNfBAAAACXBIWXMAACxLAAAsSwGlPZapAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAZwSURBVHgB7d2Pcds2FMfx514HSBbosVkgjgdonAzQph6glrtA/gzQyhs4HaCVF6ibBWJngdpdoGYmiDOB+p4EpjwJkCgRlAni+7nDSSYlkpbFn0EQBEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoDvT6XQyHY6xANjIVwIAPUZIAeg1QgpArxFSAHrta0nT6d7e3lha0obsiT4c73DZndH1PdCHfenOjX4ud9KSbqc9FO5Heyy13EVediEd0e28kvC67fN/0PQ924j9O8bctq6kGlJYZjvIpXTnWy0bB4nbqWzHtcB+IYEdWV93ow9WzlvuOCMtv0o3brU8Cszb03Ihy+Gx6j3bsPWMJd4/wD3pOUIKnaiF00str8QTTAv2XRnpe23HthrtuSB7tEkhOhdQP8q8FjGW9QG1yGpt1j/uvZZCkLXB1KT0y/zHmpdYu8dr6dmyh8YF1FjiHHI902JBdaSf740gS0M63ButmV9q2TZIRtLdsgcjckBVrFZlQfWcoFqrlAGiTWogXGPzykZQ3dFH+uCrFZ7o+yfSwgYBZY3vV1o+uud2KPhYy+GK9zyUeVAd6HaWoRfpvGobxhLeTnvRe8/67Bd4tGr5PXer2x6zgb43CCm05gLKajyrAupayxvfmbvaafXRimVYUP2p5UCQFRrOEUNVOwk503A6CHUtsBqQq8GMZX66vgwsZ18D7ZUgK0OqSZ3Untup7JfSLdtZPrvnrTsipsrVgkYS7lzYuHOshZXrfmC1JQu9xc6pFoa/WEfZGJ0/kYbBhFS9TUW/xIfSfUi9S7j9IiYLjp8C88427b3vguqTPj3S8rcsd1+wn0e2bEEWONzD1mptSYee2VYjeitbcA3g9v43vtlavhdkg5BCWy880yy9TtvUNF1QTcTfPnXorlVEBlI93Dt27RKl9JBum7Wl/CDDZ0nyXWDeB2nPws4ujfGd8Xuq5Z3giw1759+l0q6XakgVWi71j/Ksb0HlAsou9M3lP33hmXYT8e/iCzsLxydCSNVZF5Dbhq+18P9Z5jXV3kvhcM8aSH2JX8g8qArpiTUBVUoiX4oNFZ5pHyWeUC/zbwRZ6H1IuUsh7BquXgeVboMNnWEdFkMB1btaXyS+3/eTRODapehqkLkkGs4bBlWXA76t5AJqEphdynADCuhcMm1SFlTWBiX+gcXs56qNaqcXoRJQX66/q3soEdTGpPL5LFhUNnydfbBRaru7kFTDeS2orN2nWJhtX+ZLN38nCKiZUpZ7hj+WeHw1ZNvJYrZ7DcFgLzBOrp+U2+ktiErP7FlQSdydJISAmvvHM61wvf7bskap0DC5DNuSiSQ7czYIql1cMjEOTC8ln4CyGk2oi0CrfmK13uxPffNTuIEA4ki2x/maoLovpaQXUFNp5y/xn9A4jnDW1WpRhWc6/aMykvRlMT0LqtkZyJzO4tW6CFx5ZlfjP23M1aKss6avp7nNnAiykfy1ez0JquwCqsZC47fAvCcaOL/LJgv7P6BCAVfq50xNKiODuMD4noOqCqgsOx262tSVhEc8ONHg+bfJoZ8LKBtix8aS8r2+upwDGRnSeFLliu4JXUktoLq6EeRs1AOZN5YXnvmz68rcXZ3P643enpuHHoZXI28TbDB/2OBuQ3VXW95vcNP1zOi6TqTnBjXG+Y6DKqmAcmHQiYWB6qwWFOqAOZL5zT/teVmbXsh614neNqwapK+pauSHrtdT6X1IDW48qR0d+mV9iOfjDvtmN1to+JaiVtaxq/uPBFka5KB3HQcVARXggsoOOWyM8lLisFrxQaYnJSADHpmzo6CyPkEE1Aq1GpV99tsctlTs8PG1Lu85n3feBn3fvYU2qraswXckabPwOPVMj3qJiQuq0t2MdCLz/k6HDd9ugWRnCs86CqeqzedDYN1tlmvb3Xaww3V/C1uP/bMsBcNhp7+1XHimT6bLxr7XCbZmDeXub2CN5hdaLu3WVbVi087sej/GLgdqmoYUgPvD3WIA9BohBaDXCCkAvUZILUtmWFUAA2dnkrRc1xrNJwIAfVILqokAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAODzH2I9OMX8XdCHAAAAAElFTkSuQmCC", }, - "zeroExV1": { + "zeroExV1": Object { "color": "#000", "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASkAAAB5CAYAAABlYNfBAAAACXBIWXMAACxLAAAsSwGlPZapAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAlASURBVHgB7d3/eeO2GcDx1336f3UThNcF4g3KLNA4HaDnywC5Xgeo6Q5Q+zpAz+kCd+0AJyUDxNcFTsoCsbtA3gIVFL0CIRGgKMm2vp/nwWPxF0hT4isABCERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADhCJ4LeVLVyf05d+sylZy7dufSjS7OTk5OPgrXcufN/KpfO16zyfqhzmLGvEjOX7mWA9zgcVx3SwrXL916AvtwHa+TShUtT3cwvfxUCGSLuvJy4dLPh/H2Qgfhg4NIXOrw7l9659EJ6CMfVmPx+5vOCrYSgc6dlpi79SbBC50FquuG8+Qt2JAPQ3QUp65NLdY/jIkh1+LUgi/vwXLk/qWDz/6J/+Ov56p+9uCqXrtz2n7li/GvBoppzJvNzs8m5S9eyG/eyfM9KjGT1/V147tIH979duvf5UoB98gEq8c35dt03p5t/qumqzFvBohT1zpyXqUvnLr3U1ZLqIFU+bZekfInlXHoIefkq/9ma99jnnVVypiSFQei8/UmjC6rO3LZOfIiPuuoXLszn0Tn5h1kWX7RbV/mGDFKJfKtEsPo55zNCkMLWwgcwDlBVwfYXmnYqRypcmC+jC/PULIvbjhrZ0q6ClMnflwyvo+PuLAUSpLA194EZRx+8unD7qaaN5UiFC9qe108dy3+QLe06SIV9xMfdWZoiSOX5lSApfMBqM+vGNYhOJFO4CCoz61vzutbCgPcU6LK/Um1m/zNezaXvzPTpIzlX/rj/aqZ9H8RasDWC1Hrn0XTpHZsL83oi7TuDF3KcavPaX9g3iXXemNf+Yv9SHoe4c+fngq0RpNazF8bElaJmkilRiroMvYgnZp4vIQzSD+gR8QHnGzP9MT6vbtr/ic9Vr86S+2SOe2ZmE6QGQJBKCNULG0BupMxKKcpUE22Vz+d/NA3ooap3Ksv/2c94s251l/5tpkePqHo8EwyKIJV2Fk1/J5lSpSjz+n3HfuK8LnTeH8unRrag897yi7wO0V/LFzVeRfM2ndebaNs/CoC56C7NtHDbqdn2tmP5uCOvM13Vq4+VtrtSNLJn2n4M5kPG+mOz/k99q8e6h7t7sjzmW7OfHzKOi7t7HShJpdlq2EwyabsUlXqkY+XOlWzgqom+5DUxsy56Xqg2GPqn9xvZI10+7V8tZslq1Te5maze+fP/95k8fPY9ZTSDARCk0mwg+I/ks21RPhikLkT7wR1lBJ3X0XEV3RVMBM5G9s9X1+LG75wqtA/S9yaPB1vlC4H4PJr9vQBDS1SNcp/DOo+2e5G5XpWRd9ybuZYM4X+Zmu0O8uygtqt67wq2exdVh4pLkrq/zpzTaB+nGcdFda8DJam2KprOLbLnlKJy9pfSRMeRW5pqZH0j/l5oe8QDP+N97uYu/T2ady4PTPgf/XtSmdkTBj4cBkGq26xrhVCyqcyspiC/30iH0MfKVvtq7RhoLXyL23UuS/p6DSiupt0XBHDPX+i2yvd7eSBCSciPyOpLqPaLw0etrwXYBW2PXFBnbDM2608L8z+X/GOz+7nbVPWJqh5FdyiHohtGPCjII354t7hKpLsbquVa04MgNgV5Ud3rwKB3bVXJytp+xq+R3bk0+1o0or9OHJPvj1SZWYccbK82r+M7djn8Nv+SZR8rX5o6l+3Os8/DjxHW59GkdYPeLVzu++4pjoy2+ybVHeuPS0osukVJKmwfN6KfRssfRGN5OJaNIx4U5nPXNx9l+OBHjTaptrihfG2bUfhA1WZWI+XuCtdvZPUYrxLLq/B6JgdoLPc0PeLBRPqz7ViVPozHZBbPGH7lSk+/LRklA/mo7nV7tmFZY17n3tGLqwr/lQK+Ed1doD7wLILTohHd9zuqZLWx/M2BGssXbOdLH7W+36KkYPurLUZGmEh/76WsD9zCLPz9yN07HIRm9pNKrJf1pL62+0nV0oO2B+SLHaSx3Bxf16/BbOungmPZeT+pPpTqXhaqe21xda9as15jXs8k/yHkKpru+23cVY17KQeiyxEPKtmdxzQyArZAkIqEPkk2ULXapMK3nS05fVtQrfo8sb8+ftex/JUcTmrEg13s4xvBk0ebVNpMlg+K1onlTbTujeSrzOtepagQJBtZPQaf7BhV/i5lfcDGXBtE/WgQf5Dt+cDk+1nVYdq3x434WXIcHW3f5h+ZZXFb1FVBvqNo217dA7TdqbMy+dtb9VPd8+ifa9p/sp5/zMz7dWnetEk9blT30uISji0VNNGydaNLptTR9EQKhYurNrN+edwllChsW1Ul6V9d3qXUiAe5z+rluIn29WAekwH2Zl2JJ1GKKioJaftHJKvC7eOOmtM1642j/ZzKnmi74+Ugv0Ic5T+OSh+jjm0oSeHp0cRzctsEGW0HuLEUyt2/zn/mXXcVKDYcn0/xD39mdc0o3EdRlY8ghSdJ24+vvI2nC/O7iLYvuni13b+q6Vj/uuRCHoKmx3+qZEDhwn4WnYsPGdsQpPD06ObOiFVBPnEpqnTc9FF0LP71KGMbW+3qPUZ45jGmRjzYSQlOC38tmCD1uNFwvtm6DpE3uf2iQmCIq3aNlIlHNWgybrv75X820/7xnr/JbtXmdc445n3Foynwa8E4XtpuB1ItG773Ntr2WgroFo31pSWObWiPBu0t9rWo8q2UFDvWpySFp0nn1aY40ExdeqHrG679NhfaHhDttvTC1XY1ryrYNlUF+6QDBw8dYHC7Hvv0QfEmusBrWX98BCk8XWsC1cJYzY9uhunUaI19AtRFlEfxnbLEheA1MiBN33H7UnZI02NEXWWuS5DC06Ttnui5/HalAcpX82ywu5UedFk1mu7qYtD2iAfZIxQMsN/OmwNKkHrUaDgv4Bqr/W3855LfIDxx6Qu/XY/ny3ypyW8zC+kr6cHt1//xA+t9bfL60aW/yAB0ObidmPx31WDe2r3Mf4B1FtK9rB95wZ5Ln0oHG9wVfxwzkxA5EfQSvrFrmT/Q618vRkvwAcA/VjPhwVcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwJH7H5NlZI/0GQ+cAAAAAElFTkSuQmCC", }, diff --git a/ui/pages/token-allowance/token-allowance.test.js b/ui/pages/token-allowance/token-allowance.test.js index aaa828e22853..8b808ebc642b 100644 --- a/ui/pages/token-allowance/token-allowance.test.js +++ b/ui/pages/token-allowance/token-allowance.test.js @@ -20,15 +20,56 @@ const state = { }, gasEstimateType: 'none', selectedAddress: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - identities: { - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { - address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - name: 'Account 1', - }, - '0xc42edfcc21ed14dda456aa0756c153f7985d8813': { - address: '0xc42edfcc21ed14dda456aa0756c153f7985d8813', - name: 'Account 2', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '07c2cfec-36c9-46c4-8115-3836d3ac9047': { + address: '0xc42edfcc21ed14dda456aa0756c153f7985d8813', + id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', }, cachedBalances: {}, addressBook: [ diff --git a/ui/pages/token-details/token-details-page.test.js b/ui/pages/token-details/token-details-page.test.js index 1e7cf71074df..4be8c6be36c3 100644 --- a/ui/pages/token-details/token-details-page.test.js +++ b/ui/pages/token-details/token-details-page.test.js @@ -9,7 +9,103 @@ import TokenDetailsPage from './token-details-page'; const testTokenAddress = '0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F'; const state = { metamask: { - selectedAddress: '0xAddress', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xAddress', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '07c2cfec-36c9-46c4-8115-3836d3ac9047': { + address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', + id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '15e69915-2a1a-4019-93b3-916e11fd432f': { + address: '0xc42edfcc21ed14dda456aa0756c153f7985d8813', + id: '15e69915-2a1a-4019-93b3-916e11fd432f', + metadata: { + keyring: { + type: 'Ledger Hardware', + }, + }, + name: 'Ledger Hardware 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '784225f4-d30b-4e77-a900-c8bbce735b88': { + address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', + id: '784225f4-d30b-4e77-a900-c8bbce735b88', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account 3', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, contractExchangeRates: { '0xAnotherToken': 0.015, }, diff --git a/ui/selectors/institutional/selectors.js b/ui/selectors/institutional/selectors.js index f7198a8337c7..89e6a5a84d23 100644 --- a/ui/selectors/institutional/selectors.js +++ b/ui/selectors/institutional/selectors.js @@ -1,5 +1,5 @@ import { toChecksumAddress } from 'ethereumjs-util'; -import { getSelectedIdentity, getAccountType } from '../selectors'; +import { getAccountType, getSelectedInternalAccount } from '../selectors'; import { getProviderConfig } from '../../ducks/metamask/metamask'; import { hexToDecimal } from '../../../shared/modules/conversion.utils'; @@ -52,13 +52,13 @@ export function getCustodianIconForAddress(state, address) { } export function getIsCustodianSupportedChain(state) { - const selectedIdentity = getSelectedIdentity(state); + const selectedAccount = getSelectedInternalAccount(state); const accountType = getAccountType(state); const providerConfig = getProviderConfig(state); const supportedChains = accountType === 'custody' - ? getCustodyAccountSupportedChains(state, selectedIdentity.address) + ? getCustodyAccountSupportedChains(state, selectedAccount.address) : null; return supportedChains?.supportedChains diff --git a/ui/selectors/institutional/selectors.test.js b/ui/selectors/institutional/selectors.test.js index e357523c0123..2810effdf226 100644 --- a/ui/selectors/institutional/selectors.test.js +++ b/ui/selectors/institutional/selectors.test.js @@ -188,11 +188,6 @@ describe('Institutional selectors', () => { const accountAddress = '0x1'; const state = buildState({ metamask: { - identities: { - [accountAddress]: { - address: accountAddress, - }, - }, keyrings: [ { type: 'Custody', @@ -204,7 +199,6 @@ describe('Institutional selectors', () => { supportedChains: ['4'], }, }, - selectedAddress: accountAddress, providerConfig: { chainId: toHex(1), }, @@ -220,11 +214,6 @@ describe('Institutional selectors', () => { const accountAddress = '0x1'; const state = buildState({ metamask: { - identities: { - [accountAddress]: { - address: accountAddress, - }, - }, keyrings: [ { type: 'SomethingElse', @@ -236,7 +225,34 @@ describe('Institutional selectors', () => { supportedChains: ['4'], }, }, - selectedAddress: accountAddress, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: accountAddress, + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, providerConfig: { chainId: toHex(1), }, diff --git a/ui/selectors/nonce-sorted-transactions-selector.test.js b/ui/selectors/nonce-sorted-transactions-selector.test.js index 89a2599af4ee..926cd97e0078 100644 --- a/ui/selectors/nonce-sorted-transactions-selector.test.js +++ b/ui/selectors/nonce-sorted-transactions-selector.test.js @@ -83,6 +83,34 @@ const getStateTree = ({ featureFlags: { showIncomingTransactions: true, }, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: SENDERS.ONE, + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, incomingTransactions: [...incomingTxList], currentNetworkTxList: [...txList], }, diff --git a/ui/selectors/permissions.js b/ui/selectors/permissions.js index c14b50bbf4a8..cdb18657cb79 100644 --- a/ui/selectors/permissions.js +++ b/ui/selectors/permissions.js @@ -7,7 +7,7 @@ import { getApprovalRequestsByType } from './approvals'; import { getMetaMaskAccountsOrdered, getOriginOfCurrentTab, - getSelectedAddress, + getSelectedInternalAccount, getSubjectMetadata, getTargetSubjectMetadata, } from '.'; @@ -77,7 +77,7 @@ export function getPermittedAccountsByOrigin(state) { * @returns {Array} An array of connected subject objects. */ export function getConnectedSubjectsForSelectedAddress(state) { - const { selectedAddress } = state.metamask; + const { address: selectedAddress } = getSelectedInternalAccount(state); const subjects = getPermissionSubjects(state); const subjectMetadata = getSubjectMetadata(state); @@ -227,7 +227,7 @@ function subjectSelector(state, origin) { } export function getAccountToConnectToActiveTab(state) { - const selectedAddress = getSelectedAddress(state); + const { address: selectedAddress } = getSelectedInternalAccount(state); const connectedAccounts = getPermittedAccountsForCurrentTab(state); const { diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 95b9f10c4c8f..af2faef994ca 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -187,9 +187,7 @@ export function getCurrentKeyring(state) { return null; } - const keyring = findKeyringForAddress(state, account.id); - - return keyring; + return account.metadata.keyring; } /** @@ -333,6 +331,32 @@ export function getInternalAccount(state, accountId) { return state.metamask.internalAccounts.accounts[accountId]; } +export function getInternalAccountsSortedByKeyring(state) { + const accounts = getInternalAccounts(state); + + return accounts.sort((previousAccount, currentAccount) => { + // sort accounts by keyring type in alphabetical order + const previousKeyringType = previousAccount.metadata.keyring.type; + const currentKeyringType = currentAccount.metadata.keyring.type; + if (previousKeyringType < currentKeyringType) { + return -1; + } + if (previousKeyringType > currentKeyringType) { + return 1; + } + // if keyring types are the same, sort accounts by address in alphabetical order + const previousAddress = previousAccount.address.toLowerCase(); + const currentAddress = currentAccount.address.toLowerCase(); + if (previousAddress < currentAddress) { + return -1; + } + if (previousAddress > currentAddress) { + return 1; + } + return 0; + }); +} + export function getNumberOfTokens(state) { const { tokens } = state.metamask; return tokens ? tokens.length : 0; @@ -364,17 +388,17 @@ export function getMetaMaskCachedBalances(state) { } /** - * Get ordered (by keyrings) accounts with identity and balance + * Get ordered (by keyrings) accounts with internal account and balance */ export const getMetaMaskAccountsOrdered = createSelector( - getMetaMaskKeyrings, - getMetaMaskIdentities, + getInternalAccountsSortedByKeyring, getMetaMaskAccounts, - (keyrings, identities, accounts) => - keyrings - .reduce((list, keyring) => list.concat(keyring.accounts), []) - .filter((address) => Boolean(identities[address])) - .map((address) => ({ ...identities[address], ...accounts[address] })), + (internalAccounts, accounts) => { + return internalAccounts.map((internalAccount) => ({ + ...internalAccount, + ...accounts[internalAccount.address], + })); + }, ); export const getMetaMaskAccountsConnected = createSelector( @@ -385,7 +409,7 @@ export const getMetaMaskAccountsConnected = createSelector( export function isBalanceCached(state) { const selectedAccountBalance = - state.metamask.accounts[getSelectedAddress(state)].balance; + state.metamask.accounts[getSelectedInternalAccount(state).address].balance; const cachedBalance = getSelectedAccountCachedBalance(state); return Boolean(!selectedAccountBalance && cachedBalance); @@ -393,16 +417,19 @@ export function isBalanceCached(state) { export function getSelectedAccountCachedBalance(state) { const cachedBalances = getMetaMaskCachedBalances(state); - const selectedAddress = getSelectedAddress(state); + const { address: selectedAddress } = getSelectedInternalAccount(state); return cachedBalances && cachedBalances[selectedAddress]; } export function getSelectedAccount(state) { const accounts = getMetaMaskAccounts(state); - const selectedAddress = getSelectedAddress(state); + const selectedAccount = getSelectedInternalAccount(state); - return accounts[selectedAddress]; + return { + ...selectedAccount, + ...accounts[selectedAccount.address], + }; } export function getTargetAccount(state, targetAddress) { @@ -428,9 +455,7 @@ export function getEnsResolutionByAddress(state, address) { const entry = getAddressBookEntry(state, address) || - Object.values(state.metamask.identities).find((identity) => - isEqualCaseInsensitive(identity.address, address), - ); + getFirstInternalAccountByAddress(state, address); return entry?.name || ''; } @@ -446,17 +471,24 @@ export function getAddressBookEntry(state, address) { export function getAddressBookEntryOrAccountName(state, address) { const entry = getAddressBookEntry(state, address) || - Object.values(state.metamask.identities).find((identity) => - isEqualCaseInsensitive(identity.address, address), + Object.values(getInternalAccounts(state)).find((internalAccount) => + isEqualCaseInsensitive(internalAccount.address, address), ); return entry && entry.name !== '' ? entry.name : address; } -export function getAccountName(identities, address) { - const entry = Object.values(identities).find((identity) => - isEqualCaseInsensitive(identity.address, address), +export function getAccountName(accounts, accountAddress) { + const account = accounts.find((internalAccount) => + isEqualCaseInsensitive(internalAccount.address, accountAddress), ); - return entry && entry.name !== '' ? entry.name : ''; + return account && account.name !== '' ? account.name : ''; +} + +export function getFirstInternalAccountByAddress(state, address) { + const account = getInternalAccounts(state).find((internalAccount) => + isEqualCaseInsensitive(internalAccount.address, address), + ); + return account; } export function getMetadataContractName(state, address) { @@ -469,11 +501,14 @@ export function getMetadataContractName(state, address) { export function accountsWithSendEtherInfoSelector(state) { const accounts = getMetaMaskAccounts(state); - const identities = getMetaMaskIdentities(state); + const internalAccounts = getInternalAccounts(state); - const accountsWithSendEtherInfo = Object.entries(identities).map( - ([key, identity]) => { - return { ...identity, ...accounts[key] }; + const accountsWithSendEtherInfo = Object.values(internalAccounts).map( + (internalAccount) => { + return { + ...internalAccount, + ...accounts[internalAccount.address], + }; }, ); @@ -496,7 +531,7 @@ export function getAccountsWithLabels(state) { } export function getCurrentAccountWithSendEtherInfo(state) { - const currentAddress = getSelectedAddress(state); + const { address: currentAddress } = getSelectedInternalAccount(state); const accounts = accountsWithSendEtherInfoSelector(state); return getAccountByAddress(accounts, currentAddress); diff --git a/ui/selectors/selectors.test.js b/ui/selectors/selectors.test.js index 66a98425139d..c4cd256a7202 100644 --- a/ui/selectors/selectors.test.js +++ b/ui/selectors/selectors.test.js @@ -1,4 +1,5 @@ import { ApprovalType } from '@metamask/controller-utils'; +import { deepClone } from '@metamask/snaps-utils'; import mockState from '../../test/data/mock-state.json'; import { KeyringType } from '../../shared/constants/keyring'; import { @@ -16,6 +17,15 @@ jest.mock('../../shared/modules/network.utils', () => { }; }); +const modifyStateWithHWKeyring = (keyring) => { + const modifiedState = deepClone(mockState); + modifiedState.metamask.internalAccounts.accounts[ + modifiedState.metamask.internalAccounts.selectedAccount + ].metadata.keyring.type = keyring; + + return modifiedState; +}; + describe('Selectors', () => { describe('#getSelectedAddress', () => { it('returns undefined if selectedAddress is undefined', () => { @@ -410,58 +420,71 @@ describe('Selectors', () => { describe('#isHardwareWallet', () => { it('returns false if it is not a HW wallet', () => { - mockState.metamask.internalAccounts.accounts[ - mockState.metamask.internalAccounts.selectedAccount - ].metadata.keyring.type = KeyringType.imported; - expect(selectors.isHardwareWallet(mockState)).toBe(false); + const mockStateWithImported = modifyStateWithHWKeyring( + KeyringType.imported, + ); + expect(selectors.isHardwareWallet(mockStateWithImported)).toBe(false); }); it('returns true if it is a Ledger HW wallet', () => { - mockState.metamask.internalAccounts.accounts[ - mockState.metamask.internalAccounts.selectedAccount - ].metadata.keyring.type = KeyringType.ledger; - expect(selectors.isHardwareWallet(mockState)).toBe(true); + const mockStateWithLedger = modifyStateWithHWKeyring(KeyringType.ledger); + expect(selectors.isHardwareWallet(mockStateWithLedger)).toBe(true); }); it('returns true if it is a Trezor HW wallet', () => { - mockState.metamask.internalAccounts.accounts[ - mockState.metamask.internalAccounts.selectedAccount - ].metadata.keyring.type = KeyringType.trezor; - expect(selectors.isHardwareWallet(mockState)).toBe(true); + const mockStateWithTrezor = modifyStateWithHWKeyring(KeyringType.trezor); + expect(selectors.isHardwareWallet(mockStateWithTrezor)).toBe(true); }); }); describe('#getHardwareWalletType', () => { it('returns undefined if it is not a HW wallet', () => { - mockState.metamask.internalAccounts.accounts[ - mockState.metamask.internalAccounts.selectedAccount - ].metadata.keyring.type = KeyringType.imported; - expect(selectors.getHardwareWalletType(mockState)).toBeUndefined(); + const mockStateWithImported = modifyStateWithHWKeyring( + KeyringType.imported, + ); + expect( + selectors.getHardwareWalletType(mockStateWithImported), + ).toBeUndefined(); }); it('returns "Ledger Hardware" if it is a Ledger HW wallet', () => { - mockState.metamask.internalAccounts.accounts[ - mockState.metamask.internalAccounts.selectedAccount - ].metadata.keyring.type = KeyringType.ledger; - expect(selectors.getHardwareWalletType(mockState)).toBe( + const mockStateWithLedger = modifyStateWithHWKeyring(KeyringType.ledger); + expect(selectors.getHardwareWalletType(mockStateWithLedger)).toBe( KeyringType.ledger, ); }); it('returns "Trezor Hardware" if it is a Trezor HW wallet', () => { - mockState.metamask.internalAccounts.accounts[ - mockState.metamask.internalAccounts.selectedAccount - ].metadata.keyring.type = KeyringType.trezor; - expect(selectors.getHardwareWalletType(mockState)).toBe( + const mockStateWithTrezor = modifyStateWithHWKeyring(KeyringType.trezor); + expect(selectors.getHardwareWalletType(mockStateWithTrezor)).toBe( KeyringType.trezor, ); }); }); - it('returns selected identity', () => { - expect(selectors.getSelectedIdentity(mockState)).toStrictEqual({ + it('returns selected internal account', () => { + expect(selectors.getSelectedInternalAccount(mockState)).toStrictEqual({ address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }); }); diff --git a/ui/selectors/transactions.js b/ui/selectors/transactions.js index 61dc52883a07..09e75e49bb50 100644 --- a/ui/selectors/transactions.js +++ b/ui/selectors/transactions.js @@ -16,7 +16,7 @@ import { getProviderConfig } from '../ducks/metamask/metamask'; import { getCurrentChainId, deprecatedGetCurrentNetworkId, - getSelectedAddress, + getSelectedInternalAccount, } from './selectors'; import { hasPendingApprovals, getApprovalRequestsByType } from './approvals'; @@ -33,7 +33,7 @@ export const incomingTxListSelector = (state) => { const { networkId } = state.metamask; const { chainId } = getProviderConfig(state); - const selectedAddress = getSelectedAddress(state); + const { address: selectedAddress } = getSelectedInternalAccount(state); return Object.values(state.metamask.incomingTransactions).filter( (tx) => tx.txParams.to === selectedAddress && @@ -66,12 +66,14 @@ export const smartTransactionsListSelector = (state) => })); export const selectedAddressTxListSelector = createSelector( - getSelectedAddress, + getSelectedInternalAccount, currentNetworkTxListSelector, smartTransactionsListSelector, - (selectedAddress, transactions = [], smTransactions = []) => { + (selectedInternalAccount, transactions = [], smTransactions = []) => { return transactions - .filter(({ txParams }) => txParams.from === selectedAddress) + .filter( + ({ txParams }) => txParams.from === selectedInternalAccount.address, + ) .concat(smTransactions); }, ); diff --git a/ui/selectors/transactions.test.js b/ui/selectors/transactions.test.js index 30d48efcc68b..ca7c499fa636 100644 --- a/ui/selectors/transactions.test.js +++ b/ui/selectors/transactions.test.js @@ -34,6 +34,34 @@ describe('Transaction Selectors', () => { providerConfig: { chainId: '0x5', }, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xAddress', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, }, }; @@ -116,7 +144,34 @@ describe('Transaction Selectors', () => { featureFlags: { showIncomingTransactions: false, }, - selectedAddress: '0xAddress', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xAddress', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, currentNetworkTxList: [ { id: 0, @@ -177,11 +232,38 @@ describe('Transaction Selectors', () => { nickname: 'mainnet', chainId: CHAIN_IDS.MAINNET, }, - selectedAddress: '0xAddress', featureFlags: { showIncomingTransactions: false, }, currentNetworkTxList: [tx1, tx2], + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xAddress', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, }, }; @@ -261,7 +343,6 @@ describe('Transaction Selectors', () => { nickname: 'mainnet', chainId: CHAIN_IDS.MAINNET, }, - selectedAddress: '0xAddress', featureFlags: { showIncomingTransactions: false, }, @@ -271,6 +352,34 @@ describe('Transaction Selectors', () => { approvedTx, confirmedTx, ], + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xAddress', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, }, }; diff --git a/ui/store/actions.test.js b/ui/store/actions.test.js index 91e2c2ef763d..2b5eef22afda 100644 --- a/ui/store/actions.test.js +++ b/ui/store/actions.test.js @@ -15,15 +15,39 @@ const middleware = [thunk]; const defaultState = { metamask: { currentLocale: 'test', - selectedAddress: '0xFirstAddress', providerConfig: { chainId: '0x1' }, accounts: { '0xFirstAddress': { balance: '0x0', }, }, - identities: { - '0xFirstAddress': {}, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xFirstAddress', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', }, cachedBalances: { '0x1': { @@ -230,7 +254,6 @@ describe('Actions', () => { background.getState.callsFake((cb) => cb(null, { currentLocale: 'test', - selectedAddress: '0xAnotherAddress', providerConfig: { chainId: '0x1', }, @@ -239,6 +262,34 @@ describe('Actions', () => { balance: '0x0', }, }, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xAnotherAddress', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, cachedBalances: { '0x1': { '0xAnotherAddress': '0x0', @@ -262,7 +313,7 @@ describe('Actions', () => { ]; await store.dispatch( - actions.removeAccount('0xe18035bf8712672935fdb4e5e431b1a0183d2dfc'), + actions.removeAccount('cf8dace4-9439-4bd4-b3a8-88c821c8fcb3'), ); expect(removeAccount.callCount).toStrictEqual(1); const actionTypes = store.getActions().map((action) => action.type); diff --git a/ui/store/actions.ts b/ui/store/actions.ts index bccea4f5c015..4215440a8279 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -114,6 +114,7 @@ import { MetaMaskReduxState, TemporaryMessageDataType, } from './store'; +import { InternalAccount } from '@metamask/eth-snap-keyring'; export function goHome() { return { @@ -361,14 +362,14 @@ export function resetAccount(): ThunkAction< } export function removeAccount( - address: string, + accountId: string, ): ThunkAction { return async (dispatch: MetaMaskReduxDispatch) => { dispatch(showLoadingIndication()); try { await new Promise((resolve, reject) => { - callBackgroundMethod('removeAccount', [address], (error, account) => { + callBackgroundMethod('removeAccount', [accountId], (error, account) => { if (error) { reject(error); return; @@ -384,7 +385,7 @@ export function removeAccount( dispatch(hideLoadingIndication()); } - log.info(`Account removed: ${address}`); + log.info(`Account removed: ${accountId}`); dispatch(showAccountsPage()); }; } @@ -423,35 +424,24 @@ export function importNewAccount( }; } -export function addNewAccount(): ThunkAction< - void, - MetaMaskReduxState, - unknown, - AnyAction -> { +export function addNewAccount( + accountName: string, +): ThunkAction { log.debug(`background.addNewAccount`); - return async (dispatch, getState) => { - const oldIdentities = getState().metamask.identities; + return async (dispatch) => { dispatch(showLoadingIndication()); - - let newIdentities; try { - const { identities } = await submitRequestToBackground('addNewAccount', [ - Object.keys(oldIdentities).length, + const { account } = await submitRequestToBackground('addNewAccount', [ + accountName, ]); - newIdentities = identities; + return account; } catch (error) { dispatch(displayWarning(error)); throw error; } finally { dispatch(hideLoadingIndication()); + await forceUpdateMetamaskState(dispatch); } - - const newAccountAddress = Object.keys(newIdentities).find( - (address) => !oldIdentities[address], - ); - await forceUpdateMetamaskState(dispatch); - return newAccountAddress; }; } @@ -2716,7 +2706,7 @@ export function showPrivateKey(key: string): PayloadAction { } export function setAccountLabel( - account: string, + account: InternalAccount, label: string, ): ThunkAction, MetaMaskReduxState, unknown, AnyAction> { return (dispatch: MetaMaskReduxDispatch) => { @@ -2724,7 +2714,7 @@ export function setAccountLabel( log.debug(`background.setAccountLabel`); return new Promise((resolve, reject) => { - callBackgroundMethod('setAccountLabel', [account, label], (err) => { + callBackgroundMethod('setAccountLabel', [account.id, label], (err) => { dispatch(hideLoadingIndication()); if (err) { diff --git a/ui/store/store.ts b/ui/store/store.ts index 502dafa924bf..21d92a83251d 100644 --- a/ui/store/store.ts +++ b/ui/store/store.ts @@ -81,11 +81,11 @@ interface TemporaryBackgroundState { ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) custodyAccountDetails?: { [key: string]: any }; ///: END:ONLY_INCLUDE_IN - internalAccounts?: { + internalAccounts: { accounts: { [key: string]: InternalAccount; }; - selectedAccounts: string; + selectedAccount: string; }; } From 3a015b1f9b7cab1804518f54263d528bf3b63786 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Sat, 29 Jul 2023 09:57:49 +0800 Subject: [PATCH 019/235] fix: lint --- app/scripts/metamask-controller.js | 2 -- ui/ducks/metamask/metamask.js | 1 - ui/selectors/selectors.js | 1 - ui/store/actions.ts | 2 +- 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index ef99c4375e33..f9790bbfcc6a 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -19,7 +19,6 @@ import LatticeKeyring from 'eth-lattice-keyring'; import { MetaMaskKeyring as QRHardwareKeyring } from '@keystonehq/metamask-airgapped-keyring'; import EthQuery from 'eth-query'; import nanoid from 'nanoid'; -import { v4 as uuid } from 'uuid'; import { captureException } from '@sentry/browser'; import { AddressBookController } from '@metamask/address-book-controller'; import { @@ -222,7 +221,6 @@ import { securityProviderCheck } from './lib/security-provider-helpers'; import { IndexedDBPPOMStorage } from './lib/ppom/indexed-db-backend'; ///: END:ONLY_INCLUDE_IN import { updateCurrentLocale } from './translate'; -import { sha256FromString } from 'ethereumjs-util'; export const METAMASK_CONTROLLER_EVENTS = { // Fired after state changes that impact the extension badge (unapproved msg count) diff --git a/ui/ducks/metamask/metamask.js b/ui/ducks/metamask/metamask.js index 4fbbd625575a..0d82e0244ffc 100644 --- a/ui/ducks/metamask/metamask.js +++ b/ui/ducks/metamask/metamask.js @@ -10,7 +10,6 @@ import { checkNetworkAndAccountSupports1559, getAddressBook, getFirstInternalAccountByAddress, - getInternalAccount, getSelectedInternalAccount, getUseCurrencyRateCheck, } from '../../selectors'; diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index af2faef994ca..8de4afad90c7 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -80,7 +80,6 @@ import { isEIP1559Network, getLedgerTransportType, isAddressLedger, - findKeyringForAddress, } from '../ducks/metamask/metamask'; import { getLedgerWebHidConnectedStatus, diff --git a/ui/store/actions.ts b/ui/store/actions.ts index 4215440a8279..d712892a46cc 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -22,6 +22,7 @@ import { NonEmptyArray } from '@metamask/controller-utils'; ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) import { HandlerType } from '@metamask/snaps-utils'; ///: END:ONLY_INCLUDE_IN +import { InternalAccount } from '@metamask/eth-snap-keyring'; import { getMethodDataAsync } from '../helpers/utils/transactions.util'; import switchDirection from '../../shared/lib/switch-direction'; import { @@ -114,7 +115,6 @@ import { MetaMaskReduxState, TemporaryMessageDataType, } from './store'; -import { InternalAccount } from '@metamask/eth-snap-keyring'; export function goHome() { return { From 355c5dd0ed504e576434f1e3470cde3ea177db01 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Sat, 29 Jul 2023 10:06:32 +0800 Subject: [PATCH 020/235] fix: code fence --- ui/components/multichain/global-menu/global-menu.js | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/components/multichain/global-menu/global-menu.js b/ui/components/multichain/global-menu/global-menu.js index e00affb8ff5c..43f934737d39 100644 --- a/ui/components/multichain/global-menu/global-menu.js +++ b/ui/components/multichain/global-menu/global-menu.js @@ -40,7 +40,6 @@ import { } from '../../../selectors/institutional/selectors'; ///: END:ONLY_INCLUDE_IN import { - ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) getMetaMetricsId, getSelectedInternalAccount, ///: BEGIN:ONLY_INCLUDE_IN(snaps) From ba4618cfa8c9b6341d3dedd049ea79cefc8b0e5a Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Sat, 29 Jul 2023 10:06:51 +0800 Subject: [PATCH 021/235] fix: removable keyrings --- .../multichain/account-list-item/account-list-item.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/components/multichain/account-list-item/account-list-item.js b/ui/components/multichain/account-list-item/account-list-item.js index f1a27a843570..85d0be73496a 100644 --- a/ui/components/multichain/account-list-item/account-list-item.js +++ b/ui/components/multichain/account-list-item/account-list-item.js @@ -97,6 +97,8 @@ export const AccountListItem = ({ }, [itemRef, selected]); const { keyring } = account.metadata; + const isRemovable = + keyring.type !== KeyringType.hdKeyTree && keyring.type !== KeyringType.snap; const label = getLabel(keyring, t); const trackEvent = useContext(MetaMetricsContext); @@ -261,7 +263,7 @@ export const AccountListItem = ({ account={account} onClose={() => setAccountOptionsMenuOpen(false)} isOpen={accountOptionsMenuOpen} - isRemovable={keyring !== KeyringType.hdKeyTree} + isRemovable={isRemovable} closeMenu={closeMenu} /> From 061bb767726cdd8b9628b6fac19d4d61e90b1c8d Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Tue, 1 Aug 2023 23:30:04 +0800 Subject: [PATCH 022/235] fix: fix unit tests --- .../controllers/accounts-controller.ts | 73 ++-- app/scripts/metamask-controller.js | 78 ++-- test/data/mock-state.json | 1 - test/jest/mock-store.js | 18 - .../advanced-gas-fee-defaults.test.js | 8 +- .../advanced-gas-fee-gas-limit.test.js | 8 +- .../base-fee-input/base-fee-input.test.js | 8 +- .../priority-fee-input.test.js | 8 +- .../advanced-gas-fee-popover.test.js | 8 +- .../app/cancel-button/cancel-button.js | 4 +- .../cancel-speedup-popover.stories.js | 8 +- .../cancel-speedup-popover.test.js | 8 +- .../confirm-gas-display.test.js | 8 +- .../confirm-legacy-gas-display.test.js | 8 +- .../confirm-subtitle/confirm-subtitle.test.js | 6 +- .../edit-gas-fee-button.test.js | 8 +- .../gas-details-item/gas-details-item.test.js | 8 +- .../account-details-modal.component.js | 3 +- .../account-details-modal.container.js | 6 +- .../export-private-key-modal.test.js | 4 +- .../new-account-modal.container.js | 10 +- .../app/nft-details/nft-details.test.js | 8 +- .../app/nfts-items/nfts-items.test.js | 7 +- .../transaction-detail.component.test.js | 8 +- .../transaction-list-item.component.test.js | 4 +- .../account-details-display.js | 2 +- .../create-account/create-account.js | 3 +- .../create-account/create-account.test.js | 28 +- .../multichain/global-menu/global-menu.js | 2 + ui/ducks/metamask/metamask.js | 12 +- ui/ducks/metamask/metamask.test.js | 275 ++++++++++++- ui/ducks/send/send.js | 6 +- ui/ducks/send/send.test.js | 80 +++- ui/ducks/swaps/swaps.test.js | 4 +- ui/hooks/gasFeeInput/useGasFeeErrors.js | 7 +- ui/hooks/useTransactionInfo.js | 7 +- ui/hooks/useTransactionInfo.test.js | 6 +- ui/index.js | 4 +- .../confirm-transaction-base.container.js | 11 +- .../interactive-replacement-token-page.js | 41 +- ...interactive-replacement-token-page.test.js | 15 +- .../add-recipient.component.test.js.snap | 72 ++-- .../settings-tab/settings-tab.container.js | 4 +- .../swaps/prepare-swap-page/review-quote.js | 7 +- ui/pages/swaps/view-quote/view-quote.js | 7 +- ui/selectors/institutional/selectors.test.js | 108 +++++- ui/selectors/permissions.js | 5 +- ui/selectors/permissions.test.js | 361 ++++++++++++++++-- ui/selectors/selectors.js | 79 ++-- ui/store/actionConstants.test.js | 40 +- ui/store/actions.test.js | 83 +++- ui/store/actions.ts | 28 +- 52 files changed, 1248 insertions(+), 367 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index 1b9a22d0bc3d..e509392db664 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -5,16 +5,25 @@ import { import { Patch } from 'immer'; import { v4 as uuid } from 'uuid'; import { sha256FromString } from 'ethereumjs-util'; -import { InternalAccount, SnapKeyring } from '@metamask/eth-snap-keyring'; +import { + InternalAccount, + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) + SnapKeyring, + ///: END:ONLY_INCLUDE_IN(keyring-snaps) +} from '@metamask/eth-snap-keyring'; +///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) import { SnapController, SnapControllerEvents, } from '@metamask/snaps-controllers'; +///: END:ONLY_INCLUDE_IN(keyring-snaps) import { KeyringControllerState, KeyringController, } from '@metamask/keyring-controller'; +///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) import { SnapControllerState } from '@metamask/snaps-controllers-flask'; +///: END:ONLY_INCLUDE_IN(keyring-snaps) const controllerName = 'AccountsController'; @@ -74,7 +83,9 @@ export default class AccountsController extends BaseControllerV2< > { #keyringController: KeyringController; + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) #snapController: SnapController; + ///: END:ONLY_INCLUDE_IN(keyring-snaps) identities: any; @@ -83,23 +94,27 @@ export default class AccountsController extends BaseControllerV2< state, identities, keyringController, + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) snapController, - onKeyringStateChange, - onKeyringAccountRemoved, onSnapStateChange, + ///: END:ONLY_INCLUDE_IN(keyring-snaps) + onKeyringStateChange, }: { messenger: AccountsControllerMessenger; state: AccountsControllerState; keyringController: KeyringController; + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) snapController: SnapController; + ///: END:ONLY_INCLUDE_IN(keyring-snaps) identities: any; onKeyringStateChange: ( listener: (keyringState: KeyringControllerState) => void, ) => void; - onKeyringAccountRemoved: (listener: (address: string) => void) => void; + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) onSnapStateChange: ( listener: (snapState: SnapControllerState) => void, ) => void; + ///: END:ONLY_INCLUDE_IN(keyring-snaps) }) { super({ messenger, @@ -112,13 +127,17 @@ export default class AccountsController extends BaseControllerV2< }); this.#keyringController = keyringController; + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) this.#snapController = snapController; + ///: END:ONLY_INCLUDE_IN(keyring-snaps) this.identities = identities; + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) onSnapStateChange(async (snapState: SnapControllerState) => { console.log('snap state changed', snapState); await this.updateAccounts(); }); + ///: END:ONLY_INCLUDE_IN(keyring-snaps) onKeyringStateChange(async (keyringState: KeyringControllerState) => { console.log('keyring state changed', keyringState); @@ -147,11 +166,6 @@ export default class AccountsController extends BaseControllerV2< } } }); - - onKeyringAccountRemoved(async (address: string) => { - console.log('keyring account removed', address); - await this.updateAccounts(); - }); } getAccount(address: string): InternalAccount | undefined { @@ -184,18 +198,6 @@ export default class AccountsController extends BaseControllerV2< return account; } - getAccountsByKeyring(keyring: string): InternalAccount[] { - return Object.values(this.state.internalAccounts.accounts).filter( - (internalAccount) => internalAccount.type === keyring, - ); - } - - getAccountsBySnapId(snapId: string): InternalAccount[] { - return Object.values(this.state.internalAccounts.accounts).filter( - (internalAccount) => internalAccount.metadata.snap?.id === snapId, - ); - } - getSelectedAccount(): InternalAccount { return this.getAccountByIdExpect( this.state.internalAccounts.selectedAccount, @@ -204,7 +206,9 @@ export default class AccountsController extends BaseControllerV2< async updateAccounts(): Promise { const legacyAccounts = await this.#listLegacyAccounts(); + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) const snapAccounts = await this.#listSnapAccounts(); + ///: END:ONLY_INCLUDE_IN(keyring-snaps) const accountNames = identitesToAccountNames(this.identities); // console.log('legacy accounts', legacyAccounts); @@ -215,7 +219,9 @@ export default class AccountsController extends BaseControllerV2< const accounts: Record = [ ...legacyAccounts, + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) ...snapAccounts, + ///: END:ONLY_INCLUDE_IN(keyring-snaps) ].reduce((internalAccountMap, internalAccount) => { const keyringAccountIndex = keyringTypes.get(internalAccount.metadata.keyring.type) ?? 0; @@ -262,6 +268,7 @@ export default class AccountsController extends BaseControllerV2< // } } + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) async #listSnapAccounts(): Promise { const [snapKeyring] = this.#keyringController.getKeyringsByType( SnapKeyring.type, @@ -289,6 +296,7 @@ export default class AccountsController extends BaseControllerV2< return snapAccounts; } + ///: END:ONLY_INCLUDE_IN(keyring-snaps) async #listLegacyAccounts(): Promise { const addresses = await this.#keyringController.getAccounts(); @@ -337,6 +345,13 @@ export default class AccountsController extends BaseControllerV2< console.log('set selected account', account); this.update((currentState: AccountsControllerState) => { + currentState.internalAccounts.accounts[account.id] = { + ...currentState.internalAccounts.accounts[account.id], + metadata: { + ...currentState.internalAccounts.accounts[account.id].metadata, + lastSelected: Date.now(), + }, + }; currentState.internalAccounts.selectedAccount = account.id; }); } @@ -350,22 +365,11 @@ export default class AccountsController extends BaseControllerV2< name: accountName, }; }); - } - - #disableSnap(snapId: string): void { - const accounts = this.getAccountsBySnapId(snapId); - this.update((currentState: AccountsControllerState) => { - accounts.forEach((account) => { - account.metadata.snap = { - ...account.metadata.snap, - enabled: false, - }; - currentState.internalAccounts.accounts[account.id] = account; - }); - }); + console.log('state after set account name', this.state); } + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) async #getSnapStatus(snapId: string): Promise { const snap = await this.#snapController.getSnapState(snapId); if (!snap) { @@ -374,6 +378,7 @@ export default class AccountsController extends BaseControllerV2< return snap?.enabled && !snap?.blocked; } + ///: END:ONLY_INCLUDE_IN(keyring-snaps) } export function identitesToAccountNames( diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index f9790bbfcc6a..ecbd8621d50a 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -62,8 +62,6 @@ import { ///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) import { SnapKeyring } from '@metamask/eth-snap-keyring'; -// eslint-disable-next-line import/order -import AccountsController from './controllers/accounts-controller'; ///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) @@ -152,6 +150,7 @@ import { getTokenValueParam } from '../../shared/lib/metamask-controller-utils'; import { isManifestV3 } from '../../shared/modules/mv3.utils'; import { hexToDecimal } from '../../shared/modules/conversion.utils'; import { ACTION_QUEUE_METRICS_E2E_TEST } from '../../shared/constants/test-flags'; +import AccountsController from './controllers/accounts-controller'; ///: BEGIN:ONLY_INCLUDE_IN(blockaid) import { createPPOMMiddleware } from './lib/ppom/ppom-middleware'; @@ -1011,35 +1010,6 @@ export default class MetamaskController extends EventEmitter { }, }); - const accountsControllerMessenger = this.controllerMessenger.getRestricted({ - name: 'AccountsController', - allowedEvents: [ - 'SnapController:stateChange', - 'KeyringController:accountRemoved', - 'KeyringController:stateChange', - ], - }); - - this.accountsController = new AccountsController({ - messenger: accountsControllerMessenger, - state: initState.accountsController, - keyringController: this.keyringController, - snapController: this.snapController, - identities: initState.PreferencesController.identities, - onKeyringAccountRemoved: keyringControllerMessenger.subscribe.bind( - keyringControllerMessenger, - 'KeyringController:accountRemoved', - ), - onKeyringStateChange: keyringControllerMessenger.subscribe.bind( - keyringControllerMessenger, - 'KeyringController:stateChange', - ), - onSnapStateChange: this.controllerMessenger.subscribe.bind( - this.controllerMessenger, - 'SnapController:stateChange', - ), - }); - this.notificationController = new NotificationController({ messenger: this.controllerMessenger.getRestricted({ name: 'NotificationController', @@ -1127,6 +1097,33 @@ export default class MetamaskController extends EventEmitter { ///: END:ONLY_INCLUDE_IN + const accountsControllerMessenger = this.controllerMessenger.getRestricted({ + name: 'AccountsController', + allowedEvents: [ + 'SnapController:stateChange', + 'KeyringController:accountRemoved', + 'KeyringController:stateChange', + ], + }); + + console.log('init accounts controller state', initState.AccountsController); + + this.accountsController = new AccountsController({ + messenger: accountsControllerMessenger, + state: initState.AccountsController, + keyringController: this.keyringController, + snapController: this.snapController, + identities: initState.PreferencesController?.identities, + onKeyringStateChange: keyringControllerMessenger.subscribe.bind( + keyringControllerMessenger, + 'KeyringController:stateChange', + ), + onSnapStateChange: this.controllerMessenger.subscribe.bind( + this.controllerMessenger, + 'SnapController:stateChange', + ), + }); + ///: BEGIN:ONLY_INCLUDE_IN(desktop) this.desktopController = new DesktopController({ initState: initState.DesktopController, @@ -1703,9 +1700,7 @@ export default class MetamaskController extends EventEmitter { this.memStore = new ComposableObservableStore({ config: { AppStateController: this.appStateController.store, - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) AccountsController: this.accountsController, - ///: END:ONLY_INCLUDE_IN NetworkController: this.networkController, CachedBalancesController: this.cachedBalancesController.store, KeyringController: this.keyringController.memStore, @@ -3011,9 +3006,9 @@ export default class MetamaskController extends EventEmitter { // }); // console.log('setting account'); - this.accountsController.setSelectedAccount( - 'd92ecbfc-a77e-4d60-ac22-dd0ac927f398', - ); + // this.accountsController.setSelectedAccount( + // 'd92ecbfc-a77e-4d60-ac22-dd0ac927f398', + // ); // set new identities this.preferencesController.setAddresses(accounts); @@ -3081,16 +3076,6 @@ export default class MetamaskController extends EventEmitter { this.setLedgerTransportPreference(transportPreference); await this.accountsController.updateAccounts(); - // const selectedAccount = uuid({ - // random: sha256FromString( - // this.preferencesController.getSelectedAddress(), - // ).slice(0, 16), - // }); - - // console.log('setting account'); - this.accountsController.setSelectedAccount( - 'd92ecbfc-a77e-4d60-ac22-dd0ac927f398', - ); return this.keyringController.fullUpdate(); } @@ -3466,6 +3451,7 @@ export default class MetamaskController extends EventEmitter { let newAccount = this.accountsController.getSelectedAccount(); if (accountName) { + console.log('setting new name', accountName); this.accountsController.setAccountName(newAccount.id, accountName); newAccount = this.accountsController.getSelectedAccount(); } diff --git a/test/data/mock-state.json b/test/data/mock-state.json index c4fedf33797c..b8f61b7a1580 100644 --- a/test/data/mock-state.json +++ b/test/data/mock-state.json @@ -350,7 +350,6 @@ "origin": "metamask" } }, - "selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", "accounts": { "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": { "balance": "0x346ba7725f412cbfdb", diff --git a/test/jest/mock-store.js b/test/jest/mock-store.js index abafa21b48d7..dfa0fa9e0a7b 100644 --- a/test/jest/mock-store.js +++ b/test/jest/mock-store.js @@ -320,24 +320,6 @@ export const createSwapsMockStore = () => { }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', }, - identities: { - '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825': { - address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825', - name: 'Send Account 1', - }, - '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb': { - address: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb', - name: 'Send Account 2', - }, - '0x2f8d4a878cfa04a6e60d46362f5644deab66572d': { - address: '0x2f8d4a878cfa04a6e60d46362f5644deab66572d', - name: 'Send Account 3', - }, - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { - address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - name: 'Send Account 4', - }, - }, accounts: { '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', diff --git a/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.test.js b/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.test.js index ca62537748bd..8438b00a9097 100644 --- a/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.test.js +++ b/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.test.js @@ -30,13 +30,17 @@ jest.mock('../../../../store/actions', () => ({ })); const render = (defaultGasParams, contextParams) => { + const selectedAddress = + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].address; const store = configureStore({ metamask: { ...mockState.metamask, ...defaultGasParams, accounts: { - [mockState.metamask.selectedAddress]: { - address: mockState.metamask.selectedAddress, + [selectedAddress]: { + address: selectedAddress, balance: '0x1F4', }, }, diff --git a/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.test.js b/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.test.js index 7d1495883fb5..917c7d9e9d54 100644 --- a/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.test.js +++ b/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.test.js @@ -22,12 +22,16 @@ jest.mock('../../../../store/actions', () => ({ })); const render = (contextProps) => { + const selectedAddress = + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].address; const store = configureStore({ metamask: { ...mockState.metamask, accounts: { - [mockState.metamask.selectedAddress]: { - address: mockState.metamask.selectedAddress, + [selectedAddress]: { + address: selectedAddress, balance: '0x1F4', }, }, diff --git a/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.test.js b/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.test.js index c6f088164802..c8928e82504c 100644 --- a/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.test.js +++ b/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/base-fee-input.test.js @@ -25,12 +25,16 @@ jest.mock('../../../../../store/actions', () => ({ })); const render = (txProps, contextProps) => { + const selectedAddress = + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].address; const store = configureStore({ metamask: { ...mockState.metamask, accounts: { - [mockState.metamask.selectedAddress]: { - address: mockState.metamask.selectedAddress, + [selectedAddress]: { + address: selectedAddress, balance: '0x1F4', }, }, diff --git a/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js b/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js index 83540a3cd92d..f14c3badc4d9 100644 --- a/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js +++ b/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-inputs/priority-fee-input/priority-fee-input.test.js @@ -25,12 +25,16 @@ jest.mock('../../../../../store/actions', () => ({ })); const render = (txProps, contextProps) => { + const selectedAddress = + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].address; const store = configureStore({ metamask: { ...mockState.metamask, accounts: { - [mockState.metamask.selectedAddress]: { - address: mockState.metamask.selectedAddress, + [selectedAddress]: { + address: selectedAddress, balance: '0x1F4', }, }, diff --git a/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-popover.test.js b/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-popover.test.js index 3b60b3bab288..166f3bd59c06 100644 --- a/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-popover.test.js +++ b/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-popover.test.js @@ -29,12 +29,16 @@ jest.mock('../../../contexts/transaction-modal', () => ({ })); const render = () => { + const selectedAddress = + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].address; const store = configureStore({ metamask: { ...mockState.metamask, accounts: { - [mockState.metamask.selectedAddress]: { - address: mockState.metamask.selectedAddress, + [selectedAddress]: { + address: selectedAddress, balance: '0x1F4', }, }, diff --git a/ui/components/app/cancel-button/cancel-button.js b/ui/components/app/cancel-button/cancel-button.js index c751fa668847..bedae6c0dff9 100644 --- a/ui/components/app/cancel-button/cancel-button.js +++ b/ui/components/app/cancel-button/cancel-button.js @@ -9,7 +9,7 @@ import { getConversionRate } from '../../../ducks/metamask/metamask'; import { useI18nContext } from '../../../hooks/useI18nContext'; import { useIncrementedGasFees } from '../../../hooks/useIncrementedGasFees'; import { isBalanceSufficient } from '../../../pages/send/send.utils'; -import { getSelectedAccount } from '../../../selectors'; +import { getSelectedInternalAccountWithBalance } from '../../../selectors'; export default function CancelButton({ cancelTransaction, @@ -20,7 +20,7 @@ export default function CancelButton({ const customCancelGasSettings = useIncrementedGasFees(transaction); - const selectedAccount = useSelector(getSelectedAccount); + const selectedAccount = useSelector(getSelectedInternalAccountWithBalance); const conversionRate = useSelector(getConversionRate); const hasEnoughCancelGas = isBalanceSufficient({ diff --git a/ui/components/app/cancel-speedup-popover/cancel-speedup-popover.stories.js b/ui/components/app/cancel-speedup-popover/cancel-speedup-popover.stories.js index 0b2d541d771e..5f8f1967feea 100644 --- a/ui/components/app/cancel-speedup-popover/cancel-speedup-popover.stories.js +++ b/ui/components/app/cancel-speedup-popover/cancel-speedup-popover.stories.js @@ -13,12 +13,16 @@ import { decGWEIToHexWEI } from '../../../../shared/modules/conversion.utils'; import { GasFeeContextProvider } from '../../../contexts/gasFee'; import CancelSpeedupPopover from './cancel-speedup-popover'; +const selectedAddress = + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].address; const store = configureStore({ metamask: { ...mockState.metamask, accounts: { - [mockState.metamask.selectedAddress]: { - address: mockState.metamask.selectedAddress, + [selectedAddress]: { + address: selectedAddress, balance: '0x1F4', }, }, diff --git a/ui/components/app/cancel-speedup-popover/cancel-speedup-popover.test.js b/ui/components/app/cancel-speedup-popover/cancel-speedup-popover.test.js index 1512b8992a09..4dc20d5f515d 100644 --- a/ui/components/app/cancel-speedup-popover/cancel-speedup-popover.test.js +++ b/ui/components/app/cancel-speedup-popover/cancel-speedup-popover.test.js @@ -73,12 +73,16 @@ const render = ( props, maxFeePerGas = MOCK_SUGGESTED_MEDIUM_MAXFEEPERGAS_HEX_WEI, ) => { + const selectedAddress = + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].address; const store = configureStore({ metamask: { ...mockState.metamask, accounts: { - [mockState.metamask.selectedAddress]: { - address: mockState.metamask.selectedAddress, + [selectedAddress]: { + address: selectedAddress, balance: '0x1F4', }, }, diff --git a/ui/components/app/confirm-gas-display/confirm-gas-display.test.js b/ui/components/app/confirm-gas-display/confirm-gas-display.test.js index 6e96fb3f42e7..4576478c41cb 100644 --- a/ui/components/app/confirm-gas-display/confirm-gas-display.test.js +++ b/ui/components/app/confirm-gas-display/confirm-gas-display.test.js @@ -20,14 +20,18 @@ jest.mock('../../../store/actions', () => ({ })); const render = ({ transactionProp = {}, contextProps = {} } = {}) => { + const selectedAddress = + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].address; const store = configureStore({ ...mockState, ...contextProps, metamask: { ...mockState.metamask, accounts: { - [mockState.metamask.selectedAddress]: { - address: mockState.metamask.selectedAddress, + [selectedAddress]: { + address: selectedAddress, balance: '0x1F4', }, }, diff --git a/ui/components/app/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.test.js b/ui/components/app/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.test.js index 1d975e19eff4..65b04758c789 100644 --- a/ui/components/app/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.test.js +++ b/ui/components/app/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.test.js @@ -8,13 +8,17 @@ import configureStore from '../../../../store/store'; import ConfirmLegacyGasDisplay from './confirm-legacy-gas-display'; +const selectedAddress = + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].address; const mmState = { ...mockState, metamask: { ...mockState.metamask, accounts: { - [mockState.metamask.selectedAddress]: { - address: mockState.metamask.selectedAddress, + [selectedAddress]: { + address: selectedAddress, balance: '0x1F4', }, }, diff --git a/ui/components/app/confirm-subtitle/confirm-subtitle.test.js b/ui/components/app/confirm-subtitle/confirm-subtitle.test.js index 6b8d1a156759..3c123afc5a98 100644 --- a/ui/components/app/confirm-subtitle/confirm-subtitle.test.js +++ b/ui/components/app/confirm-subtitle/confirm-subtitle.test.js @@ -43,9 +43,13 @@ describe('ConfirmSubTitle', () => { }); it('should not return null if it is NFT Transfer', async () => { + const selectedAddress = + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].address; mockState.metamask.preferences.showFiatInTestnets = false; mockState.metamask.allNftContracts = { - [mockState.metamask.selectedAddress]: { + [selectedAddress]: { [mockState.metamask.providerConfig.chainId]: [{ address: '0x9' }], }, }; diff --git a/ui/components/app/edit-gas-fee-button/edit-gas-fee-button.test.js b/ui/components/app/edit-gas-fee-button/edit-gas-fee-button.test.js index df20bc8efcbf..d177cfaf961a 100644 --- a/ui/components/app/edit-gas-fee-button/edit-gas-fee-button.test.js +++ b/ui/components/app/edit-gas-fee-button/edit-gas-fee-button.test.js @@ -26,12 +26,16 @@ jest.mock('../../../store/actions', () => ({ })); const render = ({ componentProps, contextProps } = {}) => { + const selectedAddress = + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].address; const store = configureStore({ metamask: { ...mockState.metamask, accounts: { - [mockState.metamask.selectedAddress]: { - address: mockState.metamask.selectedAddress, + [selectedAddress]: { + address: selectedAddress, balance: '0x1F4', }, }, diff --git a/ui/components/app/gas-details-item/gas-details-item.test.js b/ui/components/app/gas-details-item/gas-details-item.test.js index 87511133a1f9..ec2cea335940 100644 --- a/ui/components/app/gas-details-item/gas-details-item.test.js +++ b/ui/components/app/gas-details-item/gas-details-item.test.js @@ -20,12 +20,16 @@ jest.mock('../../../store/actions', () => ({ })); const render = ({ contextProps } = {}) => { + const selectedAddress = + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].address; const store = configureStore({ metamask: { ...mockState.metamask, accounts: { - [mockState.metamask.selectedAddress]: { - address: mockState.metamask.selectedAddress, + [selectedAddress]: { + address: selectedAddress, balance: '0x1F4', }, }, diff --git a/ui/components/app/modals/account-details-modal/account-details-modal.component.js b/ui/components/app/modals/account-details-modal/account-details-modal.component.js index d4f805e6cff6..1cccb281e6b9 100644 --- a/ui/components/app/modals/account-details-modal/account-details-modal.component.js +++ b/ui/components/app/modals/account-details-modal/account-details-modal.component.js @@ -60,6 +60,7 @@ export default class AccountDetailsModal extends Component { ///: END:ONLY_INCLUDE_IN } = this.props; const { + id: accountId, name, address, metadata: { keyring }, @@ -104,7 +105,7 @@ export default class AccountDetailsModal extends Component { setAccountLabel(address, label)} + onSubmit={(label) => setAccountLabel(accountId, label)} accounts={this.props.accounts} /> { diff --git a/ui/components/app/modals/account-details-modal/account-details-modal.container.js b/ui/components/app/modals/account-details-modal/account-details-modal.container.js index ede3245af5b4..057329bcab87 100644 --- a/ui/components/app/modals/account-details-modal/account-details-modal.container.js +++ b/ui/components/app/modals/account-details-modal/account-details-modal.container.js @@ -11,9 +11,9 @@ import { getCurrentChainId, getMetaMaskAccountsOrdered, getBlockExplorerLinkText, + getSelectedInternalAccount, ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) getAccountType, - getSelectedInternalAccount, ///: END:ONLY_INCLUDE_IN } from '../../../../selectors'; ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) @@ -39,8 +39,8 @@ const mapDispatchToProps = (dispatch) => { return { showExportPrivateKeyModal: () => dispatch(showModal({ name: 'EXPORT_PRIVATE_KEY' })), - setAccountLabel: (address, label) => - dispatch(setAccountLabel(address, label)), + setAccountLabel: (accountId, label) => + dispatch(setAccountLabel(accountId, label)), hideModal: () => { dispatch(hideModal()); }, diff --git a/ui/components/app/modals/export-private-key-modal/export-private-key-modal.test.js b/ui/components/app/modals/export-private-key-modal/export-private-key-modal.test.js index 873be62b615f..c18d53da4ce8 100644 --- a/ui/components/app/modals/export-private-key-modal/export-private-key-modal.test.js +++ b/ui/components/app/modals/export-private-key-modal/export-private-key-modal.test.js @@ -76,7 +76,9 @@ describe('Export PrivateKey Modal', () => { expect(actions.exportAccount).toHaveBeenCalledWith( password, - mockState.metamask.selectedAddress, + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].address, ); }); }); diff --git a/ui/components/app/modals/new-account-modal/new-account-modal.container.js b/ui/components/app/modals/new-account-modal/new-account-modal.container.js index 2a1ba3175e80..a97331f0501c 100644 --- a/ui/components/app/modals/new-account-modal/new-account-modal.container.js +++ b/ui/components/app/modals/new-account-modal/new-account-modal.container.js @@ -12,11 +12,11 @@ function mapDispatchToProps(dispatch) { return { hideModal: () => dispatch(actions.hideModal()), createAccount: (newAccountName) => { - return dispatch(actions.addNewAccount()).then((newAccountAddress) => { + return dispatch(actions.addNewAccount()).then((account) => { if (newAccountName) { - dispatch(actions.setAccountLabel(newAccountAddress, newAccountName)); + dispatch(actions.setAccountLabel(account.id, newAccountName)); } - return newAccountAddress; + return account.id; }); }, }; @@ -30,8 +30,8 @@ function mergeProps(stateProps, dispatchProps) { ...stateProps, ...dispatchProps, onSave: (newAccountName) => { - return createAccount(newAccountName).then((newAccountAddress) => - onCreateNewAccount(newAccountAddress), + return createAccount(newAccountName).then((account) => + onCreateNewAccount(account), ); }, }; diff --git a/ui/components/app/nft-details/nft-details.test.js b/ui/components/app/nft-details/nft-details.test.js index 7733e75aed3b..92ea24c859da 100644 --- a/ui/components/app/nft-details/nft-details.test.js +++ b/ui/components/app/nft-details/nft-details.test.js @@ -48,9 +48,11 @@ jest.mock('../../../store/actions.ts', () => ({ describe('NFT Details', () => { const mockStore = configureMockStore([thunk])(mockState); - - const nfts = - mockState.metamask.allNfts[mockState.metamask.selectedAddress][toHex(5)]; + const selectedAddress = + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].address; + const nfts = mockState.metamask.allNfts[selectedAddress][toHex(5)]; const props = { nft: nfts[5], diff --git a/ui/components/app/nfts-items/nfts-items.test.js b/ui/components/app/nfts-items/nfts-items.test.js index cd57d3e52427..da1389bb91ab 100644 --- a/ui/components/app/nfts-items/nfts-items.test.js +++ b/ui/components/app/nfts-items/nfts-items.test.js @@ -24,8 +24,11 @@ jest.mock('../../../store/actions.ts', () => ({ })); describe('NFTs Item Component', () => { - const nfts = - mockState.metamask.allNfts[mockState.metamask.selectedAddress][toHex(5)]; + const selectedAddress = + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].address; + const nfts = mockState.metamask.allNfts[selectedAddress][toHex(5)]; const props = { collections: { '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { diff --git a/ui/components/app/transaction-detail/transaction-detail.component.test.js b/ui/components/app/transaction-detail/transaction-detail.component.test.js index 54f522c13b64..65858abc1773 100644 --- a/ui/components/app/transaction-detail/transaction-detail.component.test.js +++ b/ui/components/app/transaction-detail/transaction-detail.component.test.js @@ -22,12 +22,16 @@ jest.mock('../../../store/actions', () => ({ })); const render = ({ componentProps, contextProps } = {}) => { + const selectedAddress = + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].address; const store = configureStore({ metamask: { ...mockState.metamask, accounts: { - [mockState.metamask.selectedAddress]: { - address: mockState.metamask.selectedAddress, + [selectedAddress]: { + address: selectedAddress, balance: '0x1F4', }, }, diff --git a/ui/components/app/transaction-list-item/transaction-list-item.component.test.js b/ui/components/app/transaction-list-item/transaction-list-item.component.test.js index 5a830e3d74a3..776e83b43067 100644 --- a/ui/components/app/transaction-list-item/transaction-list-item.component.test.js +++ b/ui/components/app/transaction-list-item/transaction-list-item.component.test.js @@ -6,7 +6,7 @@ import mockState from '../../../../test/data/mock-state.json'; import transactionGroup from '../../../../test/data/mock-pending-transaction-data.json'; import { getConversionRate, - getSelectedAccount, + getSelectedInternalAccountWithBalance, getTokenExchangeRates, getPreferences, getShouldShowFiat, @@ -98,7 +98,7 @@ const mockStore = configureStore(); const generateUseSelectorRouter = (opts) => (selector) => { if (selector === getConversionRate) { return 1; - } else if (selector === getSelectedAccount) { + } else if (selector === getSelectedInternalAccountWithBalance) { return { balance: opts.balance ?? '2AA1EFB94E0000', }; diff --git a/ui/components/multichain/account-details/account-details-display.js b/ui/components/multichain/account-details/account-details-display.js index e0b955e8c2a7..5c86d2228153 100644 --- a/ui/components/multichain/account-details/account-details-display.js +++ b/ui/components/multichain/account-details/account-details-display.js @@ -61,7 +61,7 @@ export const AccountDetailsDisplay = ({ { - dispatch(setAccountLabel(address, label)); + dispatch(setAccountLabel(accountId, label)); trackEvent({ category: MetaMetricsEventCategory.Accounts, event: MetaMetricsEventName.AccountRenamed, diff --git a/ui/components/multichain/create-account/create-account.js b/ui/components/multichain/create-account/create-account.js index dffd8df37b35..424a29d362fa 100644 --- a/ui/components/multichain/create-account/create-account.js +++ b/ui/components/multichain/create-account/create-account.js @@ -46,8 +46,9 @@ export const CreateAccount = ({ onActionComplete }) => { const onCreateAccount = async (name) => { const newAccount = await dispatch(addNewAccount(name)); + console.log(newAccount); if (name) { - dispatch(setAccountLabel(newAccount, name)); + dispatch(setAccountLabel(newAccount.id, name)); } }; diff --git a/ui/components/multichain/create-account/create-account.test.js b/ui/components/multichain/create-account/create-account.test.js index f93f013afc08..bbe6974509a4 100644 --- a/ui/components/multichain/create-account/create-account.test.js +++ b/ui/components/multichain/create-account/create-account.test.js @@ -10,7 +10,31 @@ const render = (props = { onActionComplete: () => jest.fn() }) => { return renderWithProvider(, store); }; -const mockAddNewAccount = jest.fn().mockReturnValue({ type: 'TYPE' }); +const mockInternalAccount = { + id: '0179ecc1-19c2-4c78-8df9-e08b604665e9', + name: 'test', + address: '0x1', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', +}; + +const mockAddNewAccount = jest.fn().mockReturnValue(mockInternalAccount); const mockSetAccountLabel = jest.fn().mockReturnValue({ type: 'TYPE' }); jest.mock('../../../store/actions', () => ({ @@ -44,7 +68,7 @@ describe('CreateAccount', () => { await waitFor(() => expect(mockAddNewAccount).toHaveBeenCalled()); await waitFor(() => expect(mockSetAccountLabel).toHaveBeenCalledWith( - { type: 'TYPE' }, + mockInternalAccount.id, newAccountName, ), ); diff --git a/ui/components/multichain/global-menu/global-menu.js b/ui/components/multichain/global-menu/global-menu.js index 43f934737d39..180cf587f773 100644 --- a/ui/components/multichain/global-menu/global-menu.js +++ b/ui/components/multichain/global-menu/global-menu.js @@ -40,7 +40,9 @@ import { } from '../../../selectors/institutional/selectors'; ///: END:ONLY_INCLUDE_IN import { + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) getMetaMetricsId, + ///: END:ONLY_INCLUDE_IN getSelectedInternalAccount, ///: BEGIN:ONLY_INCLUDE_IN(snaps) getUnreadNotificationsCount, diff --git a/ui/ducks/metamask/metamask.js b/ui/ducks/metamask/metamask.js index 0d82e0244ffc..88d88ba41597 100644 --- a/ui/ducks/metamask/metamask.js +++ b/ui/ducks/metamask/metamask.js @@ -25,7 +25,10 @@ const initialState = { isUnlocked: false, isAccountMenuOpen: false, isNetworkMenuOpen: false, - identities: {}, + internalAccounts: { + accounts: {}, + selectedAccount: '', + }, unapprovedTxs: {}, networkConfigurations: {}, addressBook: [], @@ -81,12 +84,15 @@ export default function reduceMetamask(state = initialState, action) { }; case actionConstants.SET_ACCOUNT_LABEL: { - const { account: newAccount } = action.value; + const { accountId, label } = action.value; const internalAccounts = { ...metamaskState.internalAccounts, accounts: { ...metamaskState.internalAccounts.accounts, - ...{ [newAccount.id]: newAccount }, + [accountId]: { + ...metamaskState.internalAccounts.accounts[accountId], + name: label, + }, }, }; return Object.assign(metamaskState, { internalAccounts }); diff --git a/ui/ducks/metamask/metamask.test.js b/ui/ducks/metamask/metamask.test.js index 1370bf9a6eb9..c8025d216a7d 100644 --- a/ui/ducks/metamask/metamask.test.js +++ b/ui/ducks/metamask/metamask.test.js @@ -18,23 +18,102 @@ describe('MetaMask Reducers', () => { isInitialized: true, isUnlocked: true, featureFlags: { sendHexData: true }, - identities: { - '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825': { - address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825', - name: 'Send Account 1', - }, - '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb': { - address: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb', - name: 'Send Account 2', - }, - '0x2f8d4a878cfa04a6e60d46362f5644deab66572d': { - address: '0x2f8d4a878cfa04a6e60d46362f5644deab66572d', - name: 'Send Account 3', - }, - '0xd85a4b6a394794842887b8284293d69163007bbb': { - address: '0xd85a4b6a394794842887b8284293d69163007bbb', - name: 'Send Account 4', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Send Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '07c2cfec-36c9-46c4-8115-3836d3ac9047': { + address: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb', + id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Send Account 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '15e69915-2a1a-4019-93b3-916e11fd432f': { + address: '0x2f8d4a878cfa04a6e60d46362f5644deab66572d', + id: '15e69915-2a1a-4019-93b3-916e11fd432f', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Send Account 3', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '784225f4-d30b-4e77-a900-c8bbce735b88': { + address: '0xd85a4b6a394794842887b8284293d69163007bbb', + id: '784225f4-d30b-4e77-a900-c8bbce735b88', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Send Account 4', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', }, cachedBalances: {}, currentBlockGasLimit: '0x4c1878', @@ -120,7 +199,34 @@ describe('MetaMask Reducers', () => { it('locks MetaMask', () => { const unlockMetaMaskState = { isUnlocked: true, - selectedAddress: 'test address', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Send Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, }; const lockMetaMask = reduceMetamask(unlockMetaMaskState, { type: actionConstants.LOCK_METAMASK, @@ -131,18 +237,69 @@ describe('MetaMask Reducers', () => { it('sets account label', () => { const state = reduceMetamask( - {}, + { + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Send Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, + }, { type: actionConstants.SET_ACCOUNT_LABEL, value: { - account: 'test account', + accountId: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', label: 'test label', }, }, ); - expect(state.identities).toStrictEqual({ - 'test account': { name: 'test label' }, + expect(state.internalAccounts.accounts).toStrictEqual({ + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'test label', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }); }); @@ -286,6 +443,25 @@ describe('MetaMask Reducers', () => { it('should return an array including all the users accounts and the address book', () => { expect(getSendToAccounts(mockState)).toStrictEqual([ { + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', code: '0x', balance: '0x47c9d71831c76efe', nonce: '0x1b', @@ -293,6 +469,25 @@ describe('MetaMask Reducers', () => { name: 'Send Account 1', }, { + id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', code: '0x', balance: '0x37452b1315889f80', nonce: '0xa', @@ -300,6 +495,25 @@ describe('MetaMask Reducers', () => { name: 'Send Account 2', }, { + id: '15e69915-2a1a-4019-93b3-916e11fd432f', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', code: '0x', balance: '0x30c9d71831c76efe', nonce: '0x1c', @@ -307,6 +521,25 @@ describe('MetaMask Reducers', () => { name: 'Send Account 3', }, { + id: '784225f4-d30b-4e77-a900-c8bbce735b88', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', code: '0x', balance: '0x0', nonce: '0x0', diff --git a/ui/ducks/send/send.js b/ui/ducks/send/send.js index a9bca3493aa2..17b617150224 100644 --- a/ui/ducks/send/send.js +++ b/ui/ducks/send/send.js @@ -39,6 +39,7 @@ import { getEnsResolutionByAddress, getSelectedAccount, getSelectedInternalAccount, + getInternalAccountWithBalanceByAddress, } from '../../selectors'; import { disconnectGasFeeEstimatePoller, @@ -1733,7 +1734,10 @@ export function editExistingTransaction(assetType, transactionId) { const state = getState(); const unapprovedTransactions = getUnapprovedTxs(state); const transaction = unapprovedTransactions[transactionId]; - const account = getTargetAccount(state, transaction.txParams.from); + const account = getInternalAccountWithBalanceByAddress( + state, + transaction.txParams.from, + ); if (assetType === AssetType.native) { await dispatch( diff --git a/ui/ducks/send/send.test.js b/ui/ducks/send/send.test.js index 09f2743e0fdf..0df11a962b5b 100644 --- a/ui/ducks/send/send.test.js +++ b/ui/ducks/send/send.test.js @@ -1912,7 +1912,10 @@ describe('Send Slice', () => { const updateRecipientState = { metamask: { addressBook: {}, - identities: {}, + internalAccounts: { + accounts: {}, + selectedAccount: '', + }, providerConfig: { chainId: '0x1', }, @@ -2020,7 +2023,10 @@ describe('Send Slice', () => { const tokenState = { metamask: { addressBook: {}, - identities: {}, + internalAccounts: { + accounts: {}, + selectedAccount: '', + }, blockGasLimit: '', selectedAddress: '', providerConfig: { @@ -2436,7 +2442,10 @@ describe('Send Slice', () => { addressBook: { [CHAIN_IDS.GOERLI]: {}, }, - identities: {}, + internalAccounts: { + accounts: {}, + selectedAccount: '', + }, accounts: { [mockAddress1]: { address: mockAddress1, @@ -2763,7 +2772,33 @@ describe('Send Slice', () => { const editTransactionState = { metamask: { blockGasLimit: '0x3a98', - selectedAddress: '', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: mockAddress1, + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, providerConfig: { chainId: CHAIN_IDS.GOERLI, }, @@ -2782,7 +2817,6 @@ describe('Send Slice', () => { addressBook: { [CHAIN_IDS.GOERLI]: {}, }, - identities: {}, accounts: { [mockAddress1]: { address: mockAddress1, @@ -2846,7 +2880,7 @@ describe('Send Slice', () => { await store.dispatch(editExistingTransaction(AssetType.token, 1)); const actionResult = store.getActions(); - expect(actionResult).toHaveLength(8); + expect(actionResult).toHaveLength(9); expect(actionResult[0].type).toStrictEqual('send/clearPreviousDrafts'); expect(actionResult[1]).toStrictEqual({ type: 'send/addNewDraft', @@ -2864,6 +2898,25 @@ describe('Send Slice', () => { fromAccount: { address: mockAddress1, balance: '0x0', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, }, gas: { error: null, @@ -3199,7 +3252,10 @@ describe('Send Slice', () => { send: INITIAL_SEND_STATE_FOR_EXISTING_DRAFT, metamask: { ensResolutionsByAddress: {}, - identities: {}, + internalAccounts: { + accounts: {}, + selectedAccount: '', + }, addressBook: {}, providerConfig: { chainId: '0x5', @@ -3215,7 +3271,10 @@ describe('Send Slice', () => { metamask: { ensResolutionsByAddress: {}, addressBook: {}, - identities: {}, + internalAccounts: { + accounts: {}, + selectedAccount: '', + }, providerConfig: { chainId: '0x5', }, @@ -3262,7 +3321,10 @@ describe('Send Slice', () => { send: INITIAL_SEND_STATE_FOR_EXISTING_DRAFT, metamask: { ensResolutionsByAddress: {}, - identities: {}, + internalAccounts: { + accounts: {}, + selectedAccount: '', + }, addressBook: {}, providerConfig: { chainId: '0x5', diff --git a/ui/ducks/swaps/swaps.test.js b/ui/ducks/swaps/swaps.test.js index 6ba7c7677019..f2700a78bfd6 100644 --- a/ui/ducks/swaps/swaps.test.js +++ b/ui/ducks/swaps/swaps.test.js @@ -421,7 +421,9 @@ describe('Ducks - Swaps', () => { it('returns false if feature flag is enabled, is a HW and is Ethereum network', () => { const state = createSwapsMockStore(); - state.metamask.keyrings[0].type = 'Trezor Hardware'; + state.metamask.internalAccounts.accounts[ + state.metamask.internalAccounts.selectedAccount + ].metadata.keyring.type = 'Trezor Hardware'; expect(swaps.getSmartTransactionsEnabled(state)).toBe(false); }); diff --git a/ui/hooks/gasFeeInput/useGasFeeErrors.js b/ui/hooks/gasFeeInput/useGasFeeErrors.js index b48f5cef0fcf..70ef8c3772e1 100644 --- a/ui/hooks/gasFeeInput/useGasFeeErrors.js +++ b/ui/hooks/gasFeeInput/useGasFeeErrors.js @@ -3,7 +3,7 @@ import { shallowEqual, useSelector } from 'react-redux'; import { GasEstimateTypes, GAS_LIMITS } from '../../../shared/constants/gas'; import { checkNetworkAndAccountSupports1559, - getSelectedAccount, + getSelectedInternalAccountWithBalance, } from '../../selectors'; import { isLegacyTransaction } from '../../helpers/utils/transactions.util'; import { bnGreaterThan, bnLessThan } from '../../helpers/utils/util'; @@ -267,7 +267,10 @@ export function useGasFeeErrors({ [gasErrors, gasWarnings], ); - const { balance: ethBalance } = useSelector(getSelectedAccount, shallowEqual); + const { balance: ethBalance } = useSelector( + getSelectedInternalAccountWithBalance, + shallowEqual, + ); const balanceError = hasBalanceError( minimumCostInHexWei, transaction, diff --git a/ui/hooks/useTransactionInfo.js b/ui/hooks/useTransactionInfo.js index eec5f9a6f572..316f1bb44bc6 100644 --- a/ui/hooks/useTransactionInfo.js +++ b/ui/hooks/useTransactionInfo.js @@ -2,11 +2,12 @@ import { useSelector } from 'react-redux'; import { getProviderConfig } from '../ducks/metamask/metamask'; import { isEqualCaseInsensitive } from '../../shared/modules/string-utils'; +import { getSelectedInternalAccount } from '../selectors'; export const useTransactionInfo = (txData = {}) => { - const { allNftContracts, selectedAddress } = useSelector( - (state) => state.metamask, - ); + const { allNftContracts } = useSelector((state) => state.metamask); + const { address: selectedAddress } = useSelector(getSelectedInternalAccount); + const { chainId } = useSelector(getProviderConfig); const isNftTransfer = Boolean( diff --git a/ui/hooks/useTransactionInfo.test.js b/ui/hooks/useTransactionInfo.test.js index 8d962e3e03ac..a3233b4f3872 100644 --- a/ui/hooks/useTransactionInfo.test.js +++ b/ui/hooks/useTransactionInfo.test.js @@ -15,8 +15,12 @@ describe('useTransactionInfo', () => { expect(result.current.isNftTransfer).toStrictEqual(false); }); it('should return true if transaction is NFT transfer', () => { + const selectedAddress = + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].address; mockState.metamask.allNftContracts = { - [mockState.metamask.selectedAddress]: { + [selectedAddress]: { [mockState.metamask.providerConfig.chainId]: [{ address: '0x9' }], }, }; diff --git a/ui/index.js b/ui/index.js index c9cbeed660a7..b05729806787 100644 --- a/ui/index.js +++ b/ui/index.js @@ -129,8 +129,8 @@ async function startApp(metamaskState, backgroundConnection, opts) { const { origin } = draftInitialState.activeTab; const permittedAccountsForCurrentTab = getPermittedAccountsForCurrentTab(draftInitialState); - const { address: selectedAddress } = - getSelectedInternalAccount(draftInitialState); + const selectedAddress = + getSelectedInternalAccount(draftInitialState)?.address ?? ''; const unconnectedAccountAlertShownOrigins = getUnconnectedAccountAlertShown(draftInitialState); const unconnectedAccountAlertIsEnabled = diff --git a/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js b/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js index 1826487ac6ff..34283b76abf9 100644 --- a/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js +++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js @@ -25,7 +25,6 @@ import { getCustomNonceValue, getIsMainnet, getKnownMethodData, - getMetaMaskAccounts, getUseNonceField, transactionFeeSelector, getNoGasPriceFetched, @@ -42,6 +41,7 @@ import { getFullTxData, getUseCurrencyRateCheck, getFirstInternalAccountByAddress, + getInternalAccountWithBalanceByAddress, } from '../../selectors'; import { getMostRecentOverviewPage } from '../../ducks/history/history'; import { @@ -137,14 +137,15 @@ const mapStateToProps = (state, ownProps) => { value: amount, data, } = (transaction && transaction.txParams) || txParams; - const accounts = getMetaMaskAccounts(state); const transactionData = parseStandardTokenTransactionData(data); const tokenToAddress = getTokenAddressParam(transactionData); - const { balance } = accounts[fromAddress]; - const fromAccount = getFirstInternalAccountByAddress(state, fromAddress); - const { name: fromName } = fromAccount; + const fromAccount = getInternalAccountWithBalanceByAddress( + state, + fromAddress, + ); + const { name: fromName, balance } = fromAccount; const isSendingAmount = type === TransactionType.simpleSend || !isEmptyHexString(amount); diff --git a/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.js b/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.js index db0c2d5af4b6..3da0bb616dce 100644 --- a/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.js +++ b/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.js @@ -3,7 +3,10 @@ import { useSelector, useDispatch } from 'react-redux'; import PropTypes from 'prop-types'; import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils'; import { getMostRecentOverviewPage } from '../../../ducks/history/history'; -import { getMetaMaskAccounts } from '../../../selectors'; +import { + getMetaMaskAccounts, + getSelectedInternalAccount, +} from '../../../selectors'; import CustodyLabels from '../../../components/institutional/custody-labels/custody-labels'; import PulseLoader from '../../../components/ui/pulse-loader'; import { INSTITUTIONAL_FEATURES_DONE_ROUTE } from '../../../helpers/constants/routes'; @@ -52,14 +55,15 @@ export default function InteractiveReplacementTokenPage({ history }) { (state) => state.appState.modal.modalState.props?.address, ); const { - selectedAddress, custodyAccountDetails, interactiveReplacementToken, mmiConfiguration, } = useSelector((state) => state.metamask); + const selectedAccount = useSelector(getSelectedInternalAccount); const { custodianName } = - custodyAccountDetails[toChecksumHexAddress(address || selectedAddress)] || - {}; + custodyAccountDetails[ + toChecksumHexAddress(address || selectedAccount.address) + ] || {}; const { url } = interactiveReplacementToken || {}; const { custodians } = mmiConfiguration; const custodian = @@ -106,20 +110,21 @@ export default function InteractiveReplacementTokenPage({ history }) { ), ); - const filteredAccounts = custodianAccounts.filter( - (account) => metaMaskAccounts[account.address.toLowerCase()], - ); - - const mappedAccounts = filteredAccounts.map((account) => ({ - address: account.address, - name: account.name, - labels: account.labels, - balance: - metaMaskAccounts[account.address.toLowerCase()]?.balance || 0, - })); + const custodianAccountsWithBalances = custodianAccounts + .map((custodianAccount) => { + return { + ...custodianAccount, + balance: Object.values(metaMaskAccounts).find( + (account) => + account.address.toLowerCase() === + custodianAccount.address.toLowerCase(), + )?.balance, + }; + }) + .filter((custodianAccount) => custodianAccount.balance !== undefined); if (isMounted) { - setTokenAccounts(mappedAccounts); + setTokenAccounts(custodianAccountsWithBalances); setIsLoading(false); } } catch (e) { @@ -210,10 +215,14 @@ export default function InteractiveReplacementTokenPage({ history }) { setIsLoading(false); } } catch (e) { + console.log('in error', e); console.error(e); } }; + console.log('custodian', custodian); + console.log('tokenAccounts', tokenAccounts); + return ( diff --git a/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.test.js b/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.test.js index a888b0a89032..219bfaa41f6f 100644 --- a/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.test.js +++ b/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.test.js @@ -85,7 +85,6 @@ const render = ({ newState } = {}) => { metamask: { ...mockState.metamask, modal: { props: address }, - selectedAddress: address, interactiveReplacementToken: { url: 'https://saturn-custody-ui.codefi.network/', }, @@ -106,9 +105,23 @@ const render = ({ newState } = {}) => { institutionalFeatures: { connectRequests, }, + internalAccounts: { + ...mockState.metamask.internalAccounts, + accounts: { + ...mockState.metamask.internalAccounts.accounts, + [mockState.metamask.internalAccounts.selectedAccount]: { + ...mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ], + address, + name: accountName, + }, + }, + }, ...newState, }, }; + const middlewares = [thunk]; const mockStore = configureMockStore(middlewares); const store = mockStore(state); diff --git a/ui/pages/send/send-content/add-recipient/__snapshots__/add-recipient.component.test.js.snap b/ui/pages/send/send-content/add-recipient/__snapshots__/add-recipient.component.test.js.snap index 6397374fc500..0adf9aa4a196 100644 --- a/ui/pages/send/send-content/add-recipient/__snapshots__/add-recipient.component.test.js.snap +++ b/ui/pages/send/send-content/add-recipient/__snapshots__/add-recipient.component.test.js.snap @@ -95,7 +95,7 @@ exports[`Add Recipient Component Domain Resolution should match snapshot 1`] = ` style="height: 28px; width: 28px; border-radius: 14px;" >
- Test Account 3 + Test Account 2

- 0xeb9e...4823 + 0xec1a...251b

@@ -158,7 +158,7 @@ exports[`Add Recipient Component Domain Resolution should match snapshot 1`] = ` style="height: 28px; width: 28px; border-radius: 14px;" >
- Test Account 2 + Test Account 3

- 0xec1a...251b + 0xeb9e...4823

@@ -531,7 +531,7 @@ exports[`Add Recipient Component render should match snapshot 1`] = ` style="height: 28px; width: 28px; border-radius: 14px;" >
- Test Account 3 + Test Account 2

- 0xeb9e...4823 + 0xec1a...251b

@@ -594,7 +594,7 @@ exports[`Add Recipient Component render should match snapshot 1`] = ` style="height: 28px; width: 28px; border-radius: 14px;" >
- Test Account 2 + Test Account 3

- 0xec1a...251b + 0xeb9e...4823

diff --git a/ui/pages/settings/settings-tab/settings-tab.container.js b/ui/pages/settings/settings-tab/settings-tab.container.js index 0888670daa7e..75a21d16f126 100644 --- a/ui/pages/settings/settings-tab/settings-tab.container.js +++ b/ui/pages/settings/settings-tab/settings-tab.container.js @@ -21,8 +21,10 @@ const mapStateToProps = (state, ownProps) => { nativeCurrency, useBlockie, currentLocale, - selectedAddress, + internalAccounts: { accounts, selectedAccount }, } = metamask; + + const { address: selectedAddress } = accounts[selectedAccount]; const { useNativeCurrencyAsPrimaryCurrency, hideZeroBalanceTokens } = getPreferences(state); diff --git a/ui/pages/swaps/prepare-swap-page/review-quote.js b/ui/pages/swaps/prepare-swap-page/review-quote.js index 5c815f2a51d6..81cb230f556f 100644 --- a/ui/pages/swaps/prepare-swap-page/review-quote.js +++ b/ui/pages/swaps/prepare-swap-page/review-quote.js @@ -55,7 +55,7 @@ import { } from '../../../ducks/swaps/swaps'; import { conversionRateSelector, - getSelectedAccount, + getSelectedInternalAccountWithBalance, getCurrentCurrency, getTokenExchangeRates, getSwapsDefaultToken, @@ -191,7 +191,10 @@ export default function ReviewQuote({ setReceiveToAmount }) { const swapsUserFeeLevel = useSelector(getSwapsUserFeeLevel); const tokenConversionRates = useSelector(getTokenExchangeRates, isEqual); const memoizedTokenConversionRates = useEqualityCheck(tokenConversionRates); - const { balance: ethBalance } = useSelector(getSelectedAccount, shallowEqual); + const { balance: ethBalance } = useSelector( + getSelectedInternalAccountWithBalance, + shallowEqual, + ); const conversionRate = useSelector(conversionRateSelector); const USDConversionRate = useSelector(getUSDConversionRate); const isMultiLayerFeeNetwork = useSelector(getIsMultiLayerFeeNetwork); diff --git a/ui/pages/swaps/view-quote/view-quote.js b/ui/pages/swaps/view-quote/view-quote.js index 4be72b2c6425..5c8ca9decfb0 100644 --- a/ui/pages/swaps/view-quote/view-quote.js +++ b/ui/pages/swaps/view-quote/view-quote.js @@ -55,7 +55,7 @@ import { } from '../../../ducks/swaps/swaps'; import { conversionRateSelector, - getSelectedAccount, + getSelectedInternalAccountWithBalance, getCurrentCurrency, getTokenExchangeRates, getSwapsDefaultToken, @@ -165,7 +165,10 @@ export default function ViewQuote() { const swapsUserFeeLevel = useSelector(getSwapsUserFeeLevel); const tokenConversionRates = useSelector(getTokenExchangeRates, isEqual); const memoizedTokenConversionRates = useEqualityCheck(tokenConversionRates); - const { balance: ethBalance } = useSelector(getSelectedAccount, shallowEqual); + const { balance: ethBalance } = useSelector( + getSelectedInternalAccountWithBalance, + shallowEqual, + ); const conversionRate = useSelector(conversionRateSelector); const USDConversionRate = useSelector(getUSDConversionRate); const isMultiLayerFeeNetwork = useSelector(getIsMultiLayerFeeNetwork); diff --git a/ui/selectors/institutional/selectors.test.js b/ui/selectors/institutional/selectors.test.js index 2810effdf226..05d950127fa7 100644 --- a/ui/selectors/institutional/selectors.test.js +++ b/ui/selectors/institutional/selectors.test.js @@ -19,13 +19,37 @@ function buildState(overrides = {}) { type: 'test', chainId: toHex(1), }, - identities: { - '0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275': { - name: 'Custody Account A', - address: '0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275', + internalAccounts: { + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'Custody', + }, + }, + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + code: '0x', + balance: '0x47c9d71831c76efe', + nonce: '0x1b', + address: '0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275', + name: 'Custody Account A', + }, }, }, - selectedAddress: '0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275', waitForConfirmDeepLinkDialog: '123', keyrings: [ { @@ -156,23 +180,42 @@ describe('Institutional selectors', () => { const accountAddress = '0x1'; const state = buildState({ metamask: { - identities: { - [accountAddress]: { - address: accountAddress, + internalAccounts: { + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'Custody', + }, + }, + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + code: '0x', + balance: '0x47c9d71831c76efe', + nonce: '0x1b', + address: accountAddress, + name: 'Custody Account A', + }, }, }, - keyrings: [ - { - type: 'Custody', - accounts: [accountAddress], - }, - ], custodianSupportedChains: { [accountAddress]: { supportedChains: ['1', '2', '3'], }, }, - selectedAddress: accountAddress, providerConfig: { chainId: toHex(1), }, @@ -188,12 +231,37 @@ describe('Institutional selectors', () => { const accountAddress = '0x1'; const state = buildState({ metamask: { - keyrings: [ - { - type: 'Custody', - accounts: [accountAddress], + internalAccounts: { + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'Custody', + }, + }, + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + code: '0x', + balance: '0x47c9d71831c76efe', + nonce: '0x1b', + address: accountAddress, + name: 'Custody Account A', + }, }, - ], + }, custodianSupportedChains: { [accountAddress]: { supportedChains: ['4'], diff --git a/ui/selectors/permissions.js b/ui/selectors/permissions.js index cdb18657cb79..4773db30ebe5 100644 --- a/ui/selectors/permissions.js +++ b/ui/selectors/permissions.js @@ -266,7 +266,10 @@ export function getOrderedConnectedAccountsForActiveTab(state) { .filter((account) => connectedAccounts.includes(account.address)) .map((account) => ({ ...account, - lastActive: permissionHistoryByAccount?.[account.address], + metadata: { + ...account.metadata, + lastActive: permissionHistoryByAccount?.[account.address], + }, })) .sort( ({ lastSelected: lastSelectedA }, { lastSelected: lastSelectedB }) => { diff --git a/ui/selectors/permissions.test.js b/ui/selectors/permissions.test.js index d531bce2f5e4..68ea1f91ddc7 100644 --- a/ui/selectors/permissions.test.js +++ b/ui/selectors/permissions.test.js @@ -11,7 +11,34 @@ describe('selectors', () => { it('should return the list of connected subjects when there is 1 connected account', () => { const mockState = { metamask: { - selectedAddress: '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Really Long Name That Should Be Truncated', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, subjectMetadata: { 'peepeth.com': { iconUrl: 'https://peepeth.com/favicon-32x32.png', @@ -78,7 +105,34 @@ describe('selectors', () => { it('should return the list of connected subjects when there are 2 connected accounts', () => { const mockState = { metamask: { - selectedAddress: '0x7250739de134d33ec7ab1ee592711e15098c9d2d', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x7250739de134d33ec7ab1ee592711e15098c9d2d', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Really Long Name That Should Be Truncated', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, subjectMetadata: { 'peepeth.com': { iconUrl: 'https://peepeth.com/favicon-32x32.png', @@ -210,30 +264,129 @@ describe('selectors', () => { }, }, }, - identities: { - '0x7250739de134d33ec7ab1ee592711e15098c9d2d': { - address: '0x7250739de134d33ec7ab1ee592711e15098c9d2d', - name: 'Really Long Name That Should Be Truncated', - }, - '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5': { - address: '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5', - lastSelected: 1586359844192, - name: 'Account 1', - }, - '0xb3958fb96c8201486ae20be1d5c9f58083df343a': { - lastSelected: 1586359844193, - address: '0xb3958fb96c8201486ae20be1d5c9f58083df343a', - name: 'Account 2', - }, - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { - address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - lastSelected: 1586359844192, - name: 'Account 3', - }, - '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4': { - address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', - name: 'Account 4', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x7250739de134d33ec7ab1ee592711e15098c9d2d', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Really Long Name That Should Be Truncated', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '07c2cfec-36c9-46c4-8115-3836d3ac9047': { + address: '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5', + id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', + metadata: { + lastSelected: 1586359844192, + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '15e69915-2a1a-4019-93b3-916e11fd432f': { + address: '0xb3958fb96c8201486ae20be1d5c9f58083df343a', + id: '15e69915-2a1a-4019-93b3-916e11fd432f', + metadata: { + lastActive: 1586359844192, + lastSelected: 1586359844193, + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '784225f4-d30b-4e77-a900-c8bbce735b88': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: '784225f4-d30b-4e77-a900-c8bbce735b88', + metadata: { + lastSelected: 1586359844192, + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 3', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + 'f9305241-c50f-4725-ad0f-cbd3f24ac7ab': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'f9305241-c50f-4725-ad0f-cbd3f24ac7ab', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 4', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', }, keyrings: [ { @@ -266,38 +419,166 @@ describe('selectors', () => { it('should return connected accounts sorted by last selected, then by keyring controller order', () => { expect(getOrderedConnectedAccountsForActiveTab(mockState)).toStrictEqual([ { - address: '0xb3958fb96c8201486ae20be1d5c9f58083df343a', + address: '0x7250739de134d33ec7ab1ee592711e15098c9d2d', balance: undefined, - name: 'Account 2', - lastActive: 1586359844192, - lastSelected: 1586359844193, + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + lastActive: 1586359844192, + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Really Long Name That Should Be Truncated', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, { address: '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5', balance: undefined, + id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', + metadata: { + lastActive: 1586359844192, + lastSelected: 1586359844192, + keyring: { + type: 'HD Key Tree', + }, + }, name: 'Account 1', - lastActive: 1586359844192, - lastSelected: 1586359844192, + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, { - address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + address: '0xb3958fb96c8201486ae20be1d5c9f58083df343a', balance: undefined, - name: 'Account 3', - lastActive: 1586359844192, - lastSelected: 1586359844192, + id: '15e69915-2a1a-4019-93b3-916e11fd432f', + metadata: { + lastActive: 1586359844192, + lastSelected: 1586359844193, + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, { - address: '0x7250739de134d33ec7ab1ee592711e15098c9d2d', + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', balance: undefined, - name: 'Really Long Name That Should Be Truncated', - lastActive: 1586359844192, + id: '784225f4-d30b-4e77-a900-c8bbce735b88', + metadata: { + lastActive: 1586359844192, + lastSelected: 1586359844192, + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 3', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, { - address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', balance: undefined, + id: 'f9305241-c50f-4725-ad0f-cbd3f24ac7ab', + metadata: { + lastActive: 1586359844192, + keyring: { + type: 'HD Key Tree', + }, + }, name: 'Account 4', - lastActive: 1586359844192, + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, + // { + // address: '0xb3958fb96c8201486ae20be1d5c9f58083df343a', + // balance: undefined, + // name: 'Account 2', + // lastActive: 1586359844192, + // lastSelected: 1586359844193, + // }, + // { + // address: '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5', + // balance: undefined, + // name: 'Account 1', + // lastActive: 1586359844192, + // lastSelected: 1586359844192, + // }, + // { + // address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + // balance: undefined, + // name: 'Account 3', + // lastActive: 1586359844192, + // lastSelected: 1586359844192, + // }, + // { + // address: '0x7250739de134d33ec7ab1ee592711e15098c9d2d', + // balance: undefined, + // name: 'Really Long Name That Should Be Truncated', + // lastActive: 1586359844192, + // }, + // { + // address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', + // balance: undefined, + // name: 'Account 4', + // lastActive: 1586359844192, + // }, ]); }); }); diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 8de4afad90c7..eddd995bd9c8 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -283,27 +283,34 @@ export function deprecatedGetCurrentNetworkId(state) { } export const getMetaMaskAccounts = createSelector( + getInternalAccounts, getMetaMaskAccountsRaw, getMetaMaskCachedBalances, - (currentAccounts, cachedBalances) => - Object.entries(currentAccounts).reduce( - (selectedAccounts, [accountID, account]) => { - if (account.balance === null || account.balance === undefined) { - return { - ...selectedAccounts, - [accountID]: { - ...account, - balance: cachedBalances && cachedBalances[accountID], - }, - }; - } + (internalAccounts, currentAccounts, cachedBalances) => { + return internalAccounts.reduce((selectedAccounts, account) => { + if ( + currentAccounts[account.address]?.balance === null || + currentAccounts[account.address]?.balance === undefined + ) { return { ...selectedAccounts, - [accountID]: account, + [account.id]: { + ...account, + ...currentAccounts[account.address], + balance: cachedBalances && cachedBalances[account.address], + }, }; - }, - {}, - ), + } + return { + ...selectedAccounts, + [account.id]: { + ...account, + ...currentAccounts[account.address], + balance: currentAccounts[account.address].balance, + }, + }; + }, {}); + }, ); export function getSelectedAddress(state) { @@ -322,6 +329,25 @@ export function getSelectedInternalAccount(state) { return state.metamask.internalAccounts.accounts[accountId]; } +export function getSelectedInternalAccountWithBalance(state) { + const selectedAccount = getSelectedInternalAccount(state); + const { balance } = getMetaMaskAccountsRaw(state)[selectedAccount.address]; + + const selectedAccountWithBalance = { + ...selectedAccount, + balance, + }; + + return selectedAccountWithBalance; +} + +export function getInternalAccountWithBalanceByAddress(state, address) { + const accountsWithBalance = getMetaMaskAccounts(state); + return Object.values(accountsWithBalance).find((account) => + isEqualCaseInsensitive(account.address, address), + ); +} + export function getInternalAccounts(state) { return Object.values(state.metamask.internalAccounts.accounts); } @@ -343,15 +369,6 @@ export function getInternalAccountsSortedByKeyring(state) { if (previousKeyringType > currentKeyringType) { return 1; } - // if keyring types are the same, sort accounts by address in alphabetical order - const previousAddress = previousAccount.address.toLowerCase(); - const currentAddress = currentAccount.address.toLowerCase(); - if (previousAddress < currentAddress) { - return -1; - } - if (previousAddress > currentAddress) { - return 1; - } return 0; }); } @@ -395,7 +412,7 @@ export const getMetaMaskAccountsOrdered = createSelector( (internalAccounts, accounts) => { return internalAccounts.map((internalAccount) => ({ ...internalAccount, - ...accounts[internalAccount.address], + ...accounts[internalAccount.id], })); }, ); @@ -427,7 +444,7 @@ export function getSelectedAccount(state) { return { ...selectedAccount, - ...accounts[selectedAccount.address], + ...accounts[selectedAccount.id], }; } @@ -506,7 +523,7 @@ export function accountsWithSendEtherInfoSelector(state) { (internalAccount) => { return { ...internalAccount, - ...accounts[internalAccount.address], + ...accounts[internalAccount.id], }; }, ); @@ -1566,7 +1583,11 @@ export function getAllAccountsOnNetworkAreEmpty(state) { export function getShouldShowSeedPhraseReminder(state) { const { tokens, seedPhraseBackedUp, dismissSeedBackUpReminder } = state.metamask; - const accountBalance = getCurrentEthBalance(state) ?? 0; + + // if there is no account, we don't need to show the seed phrase reminder + const accountBalance = getSelectedInternalAccount(state) + ? getCurrentEthBalance(state) + : 0; return ( seedPhraseBackedUp === false && (parseInt(accountBalance, 16) > 0 || tokens.length > 0) && diff --git a/ui/store/actionConstants.test.js b/ui/store/actionConstants.test.js index c03b857eb942..9aa9ccc47207 100644 --- a/ui/store/actionConstants.test.js +++ b/ui/store/actionConstants.test.js @@ -5,12 +5,38 @@ import * as actionConstants from './actionConstants'; describe('Redux actionConstants', () => { describe('SET_ACCOUNT_LABEL', () => { it('updates the state.metamask.identities[:i].name property of the state to the action.value.label', () => { + const accountId = 'foo'; const initialState = { metamask: { - identities: { - foo: { - name: 'bar', + internalAccounts: { + accounts: { + [accountId]: { + foo: { + address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825', + id: accountId, + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'bar', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, }, + selectedAccount: accountId, }, }, }; @@ -19,16 +45,16 @@ describe('Redux actionConstants', () => { const action = { type: actionConstants.SET_ACCOUNT_LABEL, value: { - account: 'foo', + accountId: 'foo', label: 'baz', }, }; freeze(action); const resultingState = reducers(initialState, action); - expect(resultingState.metamask.identities.foo.name).toStrictEqual( - action.value.label, - ); + expect( + resultingState.metamask.internalAccounts.accounts[accountId].name, + ).toStrictEqual(action.value.label); }); }); }); diff --git a/ui/store/actions.test.js b/ui/store/actions.test.js index 2b5eef22afda..4744b0ca1e0a 100644 --- a/ui/store/actions.test.js +++ b/ui/store/actions.test.js @@ -264,15 +264,15 @@ describe('Actions', () => { }, internalAccounts: { accounts: { - 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + '22497cc9-e791-42b8-adef-2f13ef216b86': { address: '0xAnotherAddress', - id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + id: '22497cc9-e791-42b8-adef-2f13ef216b86', metadata: { keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', + name: 'Test Account 2', options: {}, supportedMethods: [ 'personal_sign', @@ -288,7 +288,7 @@ describe('Actions', () => { type: 'eip155:eoa', }, }, - selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + selectedAccount: '22497cc9-e791-42b8-adef-2f13ef216b86', }, cachedBalances: { '0x1': { @@ -472,6 +472,53 @@ describe('Actions', () => { { type: 'SHOW_LOADING_INDICATION', payload: undefined }, { type: 'DISPLAY_WARNING', payload: 'error' }, { type: 'HIDE_LOADING_INDICATION' }, + { + type: 'UPDATE_METAMASK_STATE', + value: { + accounts: { + '0xFirstAddress': { + balance: '0x0', + }, + }, + cachedBalances: { + '0x1': { + '0xFirstAddress': '0x0', + }, + }, + currentLocale: 'test', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xFirstAddress', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, + providerConfig: { + chainId: '0x1', + }, + }, + }, ]; await expect(store.dispatch(actions.addNewAccount(1))).rejects.toThrow( @@ -1953,6 +2000,34 @@ describe('Actions', () => { balance: '0x0', }, }, + internalAccounts: { + accounts: { + '8e110453-2231-4e62-82de-29b913dfef4b': { + address: '0xFirstAddress', + id: '8e110453-2231-4e62-82de-29b913dfef4b', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: '8e110453-2231-4e62-82de-29b913dfef4b', + }, cachedBalances: { '0x1': { '0xFirstAddress': '0x0', diff --git a/ui/store/actions.ts b/ui/store/actions.ts index d712892a46cc..9a9eff9c393c 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -22,7 +22,6 @@ import { NonEmptyArray } from '@metamask/controller-utils'; ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) import { HandlerType } from '@metamask/snaps-utils'; ///: END:ONLY_INCLUDE_IN -import { InternalAccount } from '@metamask/eth-snap-keyring'; import { getMethodDataAsync } from '../helpers/utils/transactions.util'; import switchDirection from '../../shared/lib/switch-direction'; import { @@ -37,13 +36,13 @@ import { getSelectedAddress, hasTransactionPendingApprovals, getApprovalFlows, + getInternalAccount, + getSelectedInternalAccount, ///: BEGIN:ONLY_INCLUDE_IN(snaps) getNotifications, ///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) getPermissionSubjects, - getSelectedAccount, - getInternalAccount, ///: END:ONLY_INCLUDE_IN } from '../selectors'; import { @@ -1527,18 +1526,21 @@ export function updateMetamaskState( const providerConfig = getProviderConfig(state); const { metamask: currentState } = state; - const { currentLocale, selectedAddress } = currentState; + const { + currentLocale, + internalAccounts: { selectedAccount: selectedAccountId }, + } = currentState; const { currentLocale: newLocale, - selectedAddress: newSelectedAddress, providerConfig: newProviderConfig, + internalAccounts: { selectedAccount: newSelectedAccountId }, } = newState; if (currentLocale && newLocale && currentLocale !== newLocale) { dispatch(updateCurrentLocale(newLocale)); } - if (selectedAddress !== newSelectedAddress) { + if (selectedAccountId !== newSelectedAccountId) { dispatch({ type: actionConstants.SELECTED_ADDRESS_CHANGED }); } @@ -1550,8 +1552,8 @@ export function updateMetamaskState( getMetaMaskAccounts({ metamask: newState }); const oldAccounts: { [address: string]: Record } = getMetaMaskAccounts({ metamask: currentState }); - const newSelectedAccount = newAccounts[newSelectedAddress]; - const oldSelectedAccount = newAccounts[selectedAddress]; + const newSelectedAccount = newAccounts[newSelectedAccountId]; + const oldSelectedAccount = newAccounts[selectedAccountId]; // dispatch an ACCOUNT_CHANGED for any account whose balance or other // properties changed in this update Object.entries(oldAccounts).forEach(([address, oldAccount]) => { @@ -1694,7 +1696,7 @@ export function setSelectedInternalAccount( const unconnectedAccountAccountAlertIsEnabled = getUnconnectedAccountAlertEnabledness(state); const activeTabOrigin = state.activeTab.origin; - const selectedAccount = getSelectedAccount(state); + const selectedAccount = getSelectedInternalAccount(state); const accountToBeSet = getInternalAccount(state, accountId); const permittedAccountsForCurrentTab = getPermittedAccountsForCurrentTab(state); @@ -2706,7 +2708,7 @@ export function showPrivateKey(key: string): PayloadAction { } export function setAccountLabel( - account: InternalAccount, + accountId: string, label: string, ): ThunkAction, MetaMaskReduxState, unknown, AnyAction> { return (dispatch: MetaMaskReduxDispatch) => { @@ -2714,7 +2716,7 @@ export function setAccountLabel( log.debug(`background.setAccountLabel`); return new Promise((resolve, reject) => { - callBackgroundMethod('setAccountLabel', [account.id, label], (err) => { + callBackgroundMethod('setAccountLabel', [accountId, label], (err) => { dispatch(hideLoadingIndication()); if (err) { @@ -2725,9 +2727,9 @@ export function setAccountLabel( dispatch({ type: actionConstants.SET_ACCOUNT_LABEL, - value: { account, label }, + value: { accountId, label }, }); - resolve(account); + resolve(accountId); }); }); }; From 3eb0a18ec03989417cbf868a53374462ee3c6a4a Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 3 Aug 2023 11:50:11 +0800 Subject: [PATCH 023/235] fix: send test --- .../controllers/accounts-controller.ts | 159 ++++++++++++------ .../multichain/global-menu/global-menu.js | 6 +- ui/ducks/send/send.js | 5 +- ui/ducks/send/send.test.js | 130 +++++++++++++- ui/hooks/gasFeeInput/test-utils.js | 7 + ui/selectors/selectors.js | 4 +- 6 files changed, 252 insertions(+), 59 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index e509392db664..d409a61d68a6 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -30,6 +30,7 @@ const controllerName = 'AccountsController'; export type AccountsControllerState = { internalAccounts: { accounts: Record; + lostAccounts: Record; selectedAccount: string; // id of the selected account }; }; @@ -72,6 +73,7 @@ const accountsControllerMetadata = { const defaultState: AccountsControllerState = { internalAccounts: { accounts: {}, + lostAccounts: {}, selectedAccount: '', }, }; @@ -145,53 +147,59 @@ export default class AccountsController extends BaseControllerV2< // check if there are any new accounts added if (keyringState.isUnlocked) { // TODO: ACCOUNTS_CONTROLLER keyring will return accounts instead of addresses, remove this flatMap after and just get the latest id - const newAccounts = keyringState.keyrings.flatMap( + const updatedKeyringAccounts = keyringState.keyrings.flatMap( (keyring) => keyring.accounts, ); - const accounts = this.getAllAccounts(); - const [newAddress] = newAccounts.filter((address) => { - return ( - accounts.findIndex( - (account) => account.address.toLowerCase() === address, - ) === -1 - ); - }); + const accounts = this.listAccounts(); await this.updateAccounts(); if (newAddress) { console.log('setting new account', newAddress); - this.setSelectedAccount(this.getAccountExpect(newAddress).id); + const updatedAccountsList = this.listAccounts(); + const { id: newAccountId } = updatedAccountsList.find( + (account) => + account.address.toLowerCase() === newAddress.toLowerCase(), + ); + this.setSelectedAccount(newAccountId); } } }); - } - - getAccount(address: string): InternalAccount | undefined { - return Object.values(this.state.internalAccounts.accounts).find( - (account) => account.address.toLowerCase() === address.toLowerCase(), - ); - } - getAccountExpect(address: string): InternalAccount { - const account = this.getAccount(address); - if (account === undefined) { - throw new Error(`Account ${address} not found`); + // if somehow the selected account becomes lost then select the first account + if ( + this.state.internalAccounts.selectedAccount !== '' && + !this.getAccount(this.state.internalAccounts.selectedAccount) + ) { + this.setSelectedAccount(this.listAccounts()[0]?.id); } - return account; } - getAccountById(accountId: string): InternalAccount | undefined { + // getAccount(address: string): InternalAccount | undefined { + // return Object.values(this.state.internalAccounts.accounts).find( + // (account) => account.address.toLowerCase() === address.toLowerCase(), + // ); + // } + + // getAccountExpect(address: string): InternalAccount { + // const account = this.getAccount(address); + // if (account === undefined) { + // throw new Error(`Account ${address} not found`); + // } + // return account; + // } + + getAccount(accountId: string): InternalAccount | undefined { return this.state.internalAccounts.accounts[accountId]; } - getAllAccounts(): InternalAccount[] { + listAccounts(): InternalAccount[] { return Object.values(this.state.internalAccounts.accounts); } - getAccountByIdExpect(accountId: string): InternalAccount { - const account = this.getAccountById(accountId); + getAccountExpect(accountId: string): InternalAccount { + const account = this.getAccount(accountId); if (account === undefined) { throw new Error(`Account Id ${accountId} not found`); } @@ -199,21 +207,23 @@ export default class AccountsController extends BaseControllerV2< } getSelectedAccount(): InternalAccount { - return this.getAccountByIdExpect( - this.state.internalAccounts.selectedAccount, - ); + return this.getAccountExpect(this.state.internalAccounts.selectedAccount); } async updateAccounts(): Promise { - const legacyAccounts = await this.#listLegacyAccounts(); + let legacyAccounts = await this.#listLegacyAccounts(); ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) const snapAccounts = await this.#listSnapAccounts(); + // remove duplicate accounts that are retrieved from the snap keyring. + legacyAccounts = legacyAccounts.filter( + (account) => + !snapAccounts.find( + (snapAccount) => snapAccount.address !== account.address, + ), + ); ///: END:ONLY_INCLUDE_IN(keyring-snaps) const accountNames = identitesToAccountNames(this.identities); - // console.log('legacy accounts', legacyAccounts); - // console.log('snap accounts', snapAccounts); - // keyring type map. const keyringTypes = new Map(); @@ -243,30 +253,53 @@ export default class AccountsController extends BaseControllerV2< internalAccount.id ] ? accountNames[internalAccount.id] - : `${internalAccount.metadata.keyring.type} ${keyringAccountIndex + 1}`; + : `${keyringTypeToName(internalAccount.metadata.keyring.type)} ${ + keyringAccountIndex + 1 + }`; return internalAccountMap; }, {} as Record); + // find lost accounts + const lostAccounts = this.listAccounts() + .filter((existingAccount) => accounts[existingAccount.id] === undefined) + .reduce((lostAccountsMap, lostAccount) => { + lostAccountsMap[lostAccount.id] = lostAccount; + return lostAccountsMap; + }, {} as Record); + this.update((currentState: AccountsControllerState) => { currentState.internalAccounts.accounts = accounts; + currentState.internalAccounts.lostAccounts = lostAccounts; }); console.log('updated state', this.state); } - removeAccountByAddress(address: string): void { - const account = this.getAccount(address); - if (account) { - this.update((currentState: AccountsControllerState) => { - delete currentState.internalAccounts.accounts[account.id]; - }); - } + // removeAccount(accountId: string): void { + // const accountToDelete = this.getAccount(accountId); + // const accounts = this.getAllAccounts(); - // this.update((currentState: AccountsControllerState) => { - // currentState.internalAccounts - // } - } + // console.log('removing account', accountToDelete); + + // if (accountToDelete) { + // const previousAccount = accounts + // .filter((account) => account.lastSelected && account.id !== accountId) + // .sort((accountA, accountB) => { + // // sort by lastSelected descending + // return ( + // accountB.metadata.lastSelected - accountA.metadata.lastSelected + // ); + // })[0]; + + // console.log('setting new selected', previousAccount); + + // this.update((currentState: AccountsControllerState) => { + // delete currentState.internalAccounts.accounts[accountToDelete.id]; + // currentState.internalAccounts.selectedAccount = previousAccount.id; + // }); + // } + // } ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) async #listSnapAccounts(): Promise { @@ -340,7 +373,7 @@ export default class AccountsController extends BaseControllerV2< } setSelectedAccount(accountId: string): void { - const account = this.getAccountByIdExpect(accountId); + const account = this.getAccountExpect(accountId); console.log('set selected account', account); @@ -357,7 +390,7 @@ export default class AccountsController extends BaseControllerV2< } setAccountName(accountId: string, accountName: string): void { - const account = this.getAccountByIdExpect(accountId); + const account = this.getAccountExpect(accountId); this.update((currentState: AccountsControllerState) => { currentState.internalAccounts.accounts[accountId] = { @@ -395,3 +428,35 @@ export function identitesToAccountNames( return accounts; }, {} as Record); } + +function keyringTypeToName(keyringType: string): string { + switch (keyringType) { + case 'Simple Key Pair': { + return 'Account'; + } + case 'HD Key Tree': { + return 'Account'; + } + case 'Trezor Hardware': { + return 'Trezor'; + } + case 'Ledger Hardware': { + return 'Ledger'; + } + case 'Lattice Hardware': { + return 'Lattice'; + } + case 'QR Hardware Wallet Device': { + return 'QR'; + } + case 'Snap Keyring': { + return 'Snap Account'; + } + case 'Custody': { + return 'Custody'; + } + default: { + return 'Account'; + } + } +} diff --git a/ui/components/multichain/global-menu/global-menu.js b/ui/components/multichain/global-menu/global-menu.js index 180cf587f773..72e8e3f8ad9d 100644 --- a/ui/components/multichain/global-menu/global-menu.js +++ b/ui/components/multichain/global-menu/global-menu.js @@ -68,7 +68,7 @@ export const GlobalMenu = ({ closeMenu, anchorElement }) => { const dispatch = useDispatch(); const trackEvent = useContext(MetaMetricsContext); const history = useHistory(); - const { address } = useSelector(getSelectedInternalAccount); + const account = useSelector(getSelectedInternalAccount); const hasUnapprovedTransactions = useSelector( (state) => Object.keys(state.metamask.unapprovedTxs).length > 0, @@ -95,12 +95,12 @@ export const GlobalMenu = ({ closeMenu, anchorElement }) => { { 1559: true, }, }, - selectedAddress: mockAddress1, - identities: { [mockAddress1]: { address: mockAddress1 } }, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: mockAddress1, + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, keyrings: [ { type: KeyringType.hdKeyTree, @@ -1340,7 +1366,7 @@ describe('Send Slice', () => { const action = initializeSendState(); await action(dispatchSpy, getState, undefined); - expect(dispatchSpy).toHaveBeenCalledTimes(2); + expect(dispatchSpy).toHaveBeenCalledTimes(3); expect(dispatchSpy.mock.calls[0][0].type).toStrictEqual( 'send/initializeSendState/pending', @@ -1578,6 +1604,34 @@ describe('Send Slice', () => { metamask: { blockGasLimit: '', selectedAddress: '', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: mockAddress1, + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, providerConfig: { chainId: CHAIN_IDS.GOERLI, }, @@ -2443,8 +2497,32 @@ describe('Send Slice', () => { [CHAIN_IDS.GOERLI]: {}, }, internalAccounts: { - accounts: {}, - selectedAccount: '', + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: mockAddress1, + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', }, accounts: { [mockAddress1]: { @@ -2491,7 +2569,7 @@ describe('Send Slice', () => { await store.dispatch(editExistingTransaction(AssetType.native, 1)); const actionResult = store.getActions(); - expect(actionResult).toHaveLength(6); + expect(actionResult).toHaveLength(7); expect(actionResult[0]).toMatchObject({ type: 'send/clearPreviousDrafts', }); @@ -2511,6 +2589,26 @@ describe('Send Slice', () => { fromAccount: { address: mockAddress1, balance: '0x0', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, gas: { error: null, @@ -2682,6 +2780,26 @@ describe('Send Slice', () => { fromAccount: { address: mockAddress1, balance: '0x0', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, gas: { error: null, diff --git a/ui/hooks/gasFeeInput/test-utils.js b/ui/hooks/gasFeeInput/test-utils.js index 86e00a822447..2a0cd7cd046c 100644 --- a/ui/hooks/gasFeeInput/test-utils.js +++ b/ui/hooks/gasFeeInput/test-utils.js @@ -14,6 +14,7 @@ import { txDataSelector, getCurrentKeyring, getTokenExchangeRates, + getSelectedInternalAccountWithBalance, } from '../../selectors'; import { useGasFeeEstimates } from '../useGasFeeEstimates'; @@ -142,6 +143,12 @@ export const generateUseSelectorRouter = if (selector === getTokenExchangeRates) { return { '0x1': '1' }; } + if (selector === getSelectedInternalAccountWithBalance) { + return { + balance: '0x440aa47cc2556', + }; + } + return undefined; }; diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index eddd995bd9c8..500cf9a33c75 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -424,8 +424,8 @@ export const getMetaMaskAccountsConnected = createSelector( ); export function isBalanceCached(state) { - const selectedAccountBalance = - state.metamask.accounts[getSelectedInternalAccount(state).address].balance; + const { balance: selectedAccountBalance } = + getSelectedInternalAccountWithBalance(state); const cachedBalance = getSelectedAccountCachedBalance(state); return Boolean(!selectedAccountBalance && cachedBalance); From fbeda3c5b0d9a73c1044789b95ffe810443fb510 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 3 Aug 2023 11:51:06 +0800 Subject: [PATCH 024/235] fix: use getAccountExpect --- app/scripts/metamask-controller.js | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index ecbd8621d50a..f46df898471f 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -2999,20 +2999,6 @@ export default class MetamaskController extends EventEmitter { this.setLedgerTransportPreference(transportPreference); await this.accountsController.updateAccounts(); - // const selectedAccount = uuid({ - // random: sha256FromString( - // this.preferencesController.getSelectedAddress(), - // ).slice(0, 16), - // }); - - // console.log('setting account'); - // this.accountsController.setSelectedAccount( - // 'd92ecbfc-a77e-4d60-ac22-dd0ac927f398', - // ); - - // set new identities - this.preferencesController.setAddresses(accounts); - this.selectFirstIdentity(); return vault; } finally { @@ -3567,7 +3553,7 @@ export default class MetamaskController extends EventEmitter { * @param {string[]} accountId - A uuid of the account to remove. */ async removeAccount(accountId) { - const { address } = this.accountsController.getAccountByIdExpect(accountId); + const { address } = this.accountsController.getAccountExpect(accountId); // Remove all associated permissions this.removeAllAccountPermissions(address); From f3a17c548775a286202ff63c97adaf2f0655f95e Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 3 Aug 2023 12:25:51 +0800 Subject: [PATCH 025/235] fix: eth-overview test --- .../app/wallet-overview/eth-overview.test.js | 23 +++++++++++++++---- ui/ducks/send/send.js | 1 - 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/ui/components/app/wallet-overview/eth-overview.test.js b/ui/components/app/wallet-overview/eth-overview.test.js index 5a1c8c2aa113..8acc1a39a62f 100644 --- a/ui/components/app/wallet-overview/eth-overview.test.js +++ b/ui/components/app/wallet-overview/eth-overview.test.js @@ -241,12 +241,25 @@ describe('EthOverview', () => { const mockedStoreWithCustodyKeyring = { metamask: { ...mockStore.metamask, - keyrings: [ - { - type: 'Custody', - accounts: ['0x1'], + internalAccounts: { + ...mockStore.metamask.internalAccounts, + accounts: { + ...mockStore.metamask.internalAccounts.accounts, + [mockStore.metamask.internalAccounts.selectedAccount]: { + ...mockStore.metamask.internalAccounts.accounts[ + mockStore.metamask.internalAccounts.selectedAccount + ], + metadata: { + ...mockStore.metamask.internalAccounts.accounts[ + mockStore.metamask.internalAccounts.selectedAccount + ].metadata, + keyring: { + type: 'Custody', + }, + }, + }, }, - ], + }, }, }; diff --git a/ui/ducks/send/send.js b/ui/ducks/send/send.js index 76ab5a140361..a685244920f8 100644 --- a/ui/ducks/send/send.js +++ b/ui/ducks/send/send.js @@ -29,7 +29,6 @@ import { getCurrentChainId, getGasPriceInHexWei, getIsMainnet, - getTargetAccount, getIsNonStandardEthChain, checkNetworkAndAccountSupports1559, getUseTokenDetection, From fe9a4217c907e2c42db44419d4113e993e08f4d6 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 3 Aug 2023 12:26:17 +0800 Subject: [PATCH 026/235] fix: add fence to snap code in accountscontroller --- app/scripts/metamask-controller.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index f46df898471f..46044d6b99f8 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1112,16 +1112,20 @@ export default class MetamaskController extends EventEmitter { messenger: accountsControllerMessenger, state: initState.AccountsController, keyringController: this.keyringController, + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) snapController: this.snapController, + ///: END:ONLY_INCLUDE_IN identities: initState.PreferencesController?.identities, onKeyringStateChange: keyringControllerMessenger.subscribe.bind( keyringControllerMessenger, 'KeyringController:stateChange', ), + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) onSnapStateChange: this.controllerMessenger.subscribe.bind( this.controllerMessenger, 'SnapController:stateChange', ), + ///: END:ONLY_INCLUDE_IN }); ///: BEGIN:ONLY_INCLUDE_IN(desktop) From 84d96704b4264194fb37805867788fa6fb46f392 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 3 Aug 2023 12:39:45 +0800 Subject: [PATCH 027/235] chore: update yarn.lock --- yarn.lock | 174 +++++++++++++++++++++++++++--------------------------- 1 file changed, 87 insertions(+), 87 deletions(-) diff --git a/yarn.lock b/yarn.lock index 879f05c47fb1..7ae8da8f9b47 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4175,15 +4175,15 @@ __metadata: version: 0.1.3 resolution: "@metamask/eth-snap-keyring@https://github.com/MetaMask/eth-snap-keyring.git#commit=60130ddcfd8f4e9a1e0de299f6798dfd966f9634" dependencies: - "@ethereumjs/tx": ^4.1.2 - "@metamask/eth-sig-util": ^5.1.0 - "@metamask/keyring-api": ^0.1.3 - "@metamask/snaps-controllers": ^0.35.2-flask.1 - "@metamask/utils": ^6.1.0 - "@types/uuid": ^9.0.1 - superstruct: ^1.0.3 - uuid: ^9.0.0 - checksum: f77cb75fcbd05024693488c42d244f78e7ee87f3f295ac95971182a78f1399428acc5f10aaf6d6ba08fa28cc3519d4e644226ac7cdf22e77a8659f945d9686ce + "@ethereumjs/tx": "npm:^4.1.2" + "@metamask/eth-sig-util": "npm:^5.1.0" + "@metamask/keyring-api": "npm:^0.1.3" + "@metamask/snaps-controllers": "npm:^0.35.2-flask.1" + "@metamask/utils": "npm:^6.1.0" + "@types/uuid": "npm:^9.0.1" + superstruct: "npm:^1.0.3" + uuid: "npm:^9.0.0" + checksum: d8eb396f2efefd511fce6654c27f91e7a3ef0bee74932a01ff41f45d62b335a267d879f72c0a3326b4185bd71e12c2d140d1162f394e588665876259585c8ccd languageName: node linkType: hard @@ -24192,84 +24192,84 @@ __metadata: version: 0.0.0-use.local resolution: "metamask-crx@workspace:." dependencies: - "@actions/core": ^1.10.0 - "@actions/github": ^5.1.1 - "@babel/code-frame": ^7.12.13 - "@babel/core": ^7.21.5 - "@babel/eslint-parser": ^7.13.14 - "@babel/eslint-plugin": ^7.12.1 - "@babel/preset-env": ^7.5.5 - "@babel/preset-react": ^7.0.0 - "@babel/preset-typescript": ^7.16.7 - "@babel/register": ^7.5.5 - "@babel/runtime": ^7.18.9 - "@blockaid/ppom": ^0.1.2 - "@download/blockies": ^1.0.3 - "@ensdomains/content-hash": ^2.5.6 - "@ethereumjs/common": ^3.1.1 - "@ethereumjs/tx": ^4.1.1 - "@ethersproject/abi": ^5.6.4 - "@ethersproject/bignumber": ^5.7.0 - "@ethersproject/contracts": ^5.7.0 - "@ethersproject/hdnode": ^5.6.2 - "@ethersproject/providers": ^5.7.2 - "@fortawesome/fontawesome-free": ^5.13.0 - "@keystonehq/bc-ur-registry-eth": ^0.19.1 - "@keystonehq/metamask-airgapped-keyring": ^0.13.1 - "@lavamoat/allow-scripts": ^2.3.1 - "@lavamoat/lavapack": ^5.2.0 - "@lavamoat/snow": ^1.5.0 - "@material-ui/core": ^4.11.0 - "@metamask-institutional/custody-controller": 0.2.6 - "@metamask-institutional/custody-keyring": ^0.0.25 - "@metamask-institutional/extension": ^0.2.1 - "@metamask-institutional/institutional-features": ^1.1.8 - "@metamask-institutional/portfolio-dashboard": ^1.1.3 - "@metamask-institutional/rpc-allowlist": ^1.0.0 - "@metamask-institutional/sdk": ^0.1.17 - "@metamask-institutional/transaction-update": ^0.1.21 - "@metamask/address-book-controller": ^3.0.0 - "@metamask/announcement-controller": ^4.0.0 - "@metamask/approval-controller": ^3.4.0 - "@metamask/assets-controllers": ^9.2.0 - "@metamask/auto-changelog": ^2.1.0 - "@metamask/base-controller": ^3.2.0 - "@metamask/browser-passworder": ^4.1.0 - "@metamask/contract-metadata": ^2.3.1 - "@metamask/controller-utils": ^4.2.0 - "@metamask/design-tokens": ^1.12.0 - "@metamask/desktop": ^0.3.0 - "@metamask/eslint-config": ^9.0.0 - "@metamask/eslint-config-jest": ^9.0.0 - "@metamask/eslint-config-mocha": ^9.0.0 - "@metamask/eslint-config-nodejs": ^9.0.0 - "@metamask/eslint-config-typescript": ^9.0.1 - "@metamask/eth-json-rpc-middleware": ^11.0.0 - "@metamask/eth-keyring-controller": ^10.0.1 - "@metamask/eth-ledger-bridge-keyring": ^0.15.0 - "@metamask/eth-snap-keyring": ^0.1.3 - "@metamask/eth-token-tracker": ^4.0.0 - "@metamask/eth-trezor-keyring": ^1.0.0 - "@metamask/etherscan-link": ^2.2.0 - "@metamask/forwarder": ^1.1.0 - "@metamask/gas-fee-controller": ^6.0.1 - "@metamask/jazzicon": ^2.0.0 - "@metamask/key-tree": ^9.0.0 - "@metamask/keyring-controller": ^7.0.0 - "@metamask/logo": ^3.1.1 - "@metamask/message-manager": ^7.0.2 - "@metamask/metamask-eth-abis": ^3.0.0 - "@metamask/network-controller": ^10.3.1 - "@metamask/notification-controller": ^3.0.0 - "@metamask/obs-store": ^8.1.0 - "@metamask/permission-controller": ^4.0.0 - "@metamask/phishing-controller": ^6.0.0 - "@metamask/phishing-warning": ^2.1.0 - "@metamask/post-message-stream": ^6.0.0 - "@metamask/ppom-validator": ^0.1.2 - "@metamask/providers": ^11.1.0 - "@metamask/rate-limit-controller": ^3.0.0 - "@metamask/rpc-methods": ^1.0.0-prerelease.1 + "@actions/core": "npm:^1.10.0" + "@actions/github": "npm:^5.1.1" + "@babel/code-frame": "npm:^7.12.13" + "@babel/core": "npm:^7.21.5" + "@babel/eslint-parser": "npm:^7.13.14" + "@babel/eslint-plugin": "npm:^7.12.1" + "@babel/preset-env": "npm:^7.5.5" + "@babel/preset-react": "npm:^7.0.0" + "@babel/preset-typescript": "npm:^7.16.7" + "@babel/register": "npm:^7.5.5" + "@babel/runtime": "npm:^7.18.9" + "@blockaid/ppom": "npm:^0.1.2" + "@download/blockies": "npm:^1.0.3" + "@ensdomains/content-hash": "npm:^2.5.6" + "@ethereumjs/common": "npm:^3.1.1" + "@ethereumjs/tx": "npm:^4.1.1" + "@ethersproject/abi": "npm:^5.6.4" + "@ethersproject/bignumber": "npm:^5.7.0" + "@ethersproject/contracts": "npm:^5.7.0" + "@ethersproject/hdnode": "npm:^5.6.2" + "@ethersproject/providers": "npm:^5.7.2" + "@fortawesome/fontawesome-free": "npm:^5.13.0" + "@keystonehq/bc-ur-registry-eth": "npm:^0.19.1" + "@keystonehq/metamask-airgapped-keyring": "npm:^0.13.1" + "@lavamoat/allow-scripts": "npm:^2.3.1" + "@lavamoat/lavapack": "npm:^5.2.0" + "@lavamoat/snow": "npm:^1.5.0" + "@material-ui/core": "npm:^4.11.0" + "@metamask-institutional/custody-controller": "npm:0.2.6" + "@metamask-institutional/custody-keyring": "npm:^0.0.25" + "@metamask-institutional/extension": "npm:^0.2.1" + "@metamask-institutional/institutional-features": "npm:^1.1.8" + "@metamask-institutional/portfolio-dashboard": "npm:^1.1.3" + "@metamask-institutional/rpc-allowlist": "npm:^1.0.0" + "@metamask-institutional/sdk": "npm:^0.1.17" + "@metamask-institutional/transaction-update": "npm:^0.1.21" + "@metamask/address-book-controller": "npm:^3.0.0" + "@metamask/announcement-controller": "npm:^4.0.0" + "@metamask/approval-controller": "npm:^3.4.0" + "@metamask/assets-controllers": "npm:^9.2.0" + "@metamask/auto-changelog": "npm:^2.1.0" + "@metamask/base-controller": "npm:^3.2.0" + "@metamask/browser-passworder": "npm:^4.1.0" + "@metamask/contract-metadata": "npm:^2.3.1" + "@metamask/controller-utils": "npm:^4.2.0" + "@metamask/design-tokens": "npm:^1.12.0" + "@metamask/desktop": "npm:^0.3.0" + "@metamask/eslint-config": "npm:^9.0.0" + "@metamask/eslint-config-jest": "npm:^9.0.0" + "@metamask/eslint-config-mocha": "npm:^9.0.0" + "@metamask/eslint-config-nodejs": "npm:^9.0.0" + "@metamask/eslint-config-typescript": "npm:^9.0.1" + "@metamask/eth-json-rpc-middleware": "npm:^11.0.0" + "@metamask/eth-keyring-controller": "npm:^10.0.1" + "@metamask/eth-ledger-bridge-keyring": "npm:^0.15.0" + "@metamask/eth-snap-keyring": "git+https://github.com/MetaMask/eth-snap-keyring.git#commit=60130ddcfd8f4e9a1e0de299f6798dfd966f9634" + "@metamask/eth-token-tracker": "npm:^4.0.0" + "@metamask/eth-trezor-keyring": "npm:^1.0.0" + "@metamask/etherscan-link": "npm:^2.2.0" + "@metamask/forwarder": "npm:^1.1.0" + "@metamask/gas-fee-controller": "npm:^6.0.1" + "@metamask/jazzicon": "npm:^2.0.0" + "@metamask/key-tree": "npm:^9.0.0" + "@metamask/keyring-controller": "npm:^7.0.0" + "@metamask/logo": "npm:^3.1.1" + "@metamask/message-manager": "npm:^7.0.2" + "@metamask/metamask-eth-abis": "npm:^3.0.0" + "@metamask/network-controller": "npm:^11.0.0" + "@metamask/notification-controller": "npm:^3.0.0" + "@metamask/obs-store": "npm:^8.1.0" + "@metamask/permission-controller": "npm:^4.0.0" + "@metamask/phishing-controller": "npm:^6.0.0" + "@metamask/phishing-warning": "npm:^2.1.0" + "@metamask/post-message-stream": "npm:^6.0.0" + "@metamask/ppom-validator": "npm:^0.1.2" + "@metamask/providers": "npm:^11.1.0" + "@metamask/rate-limit-controller": "npm:^3.0.0" + "@metamask/rpc-methods": "npm:^1.0.0-prerelease.1" "@metamask/rpc-methods-flask": "npm:@metamask/rpc-methods@0.37.2-flask.1" "@metamask/safe-event-emitter": "npm:^2.0.0" "@metamask/scure-bip39": "npm:^2.0.3" From b524093af2bba4e2adb650ad8ae27c64d83ec018 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 3 Aug 2023 21:32:53 +0800 Subject: [PATCH 028/235] fix: add and remove account logic on keyring state change --- .../controllers/accounts-controller.ts | 183 ++++++++++-------- package.json | 2 +- yarn.lock | 8 +- 3 files changed, 102 insertions(+), 91 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index d409a61d68a6..8070b00a90cb 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -137,7 +137,26 @@ export default class AccountsController extends BaseControllerV2< ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) onSnapStateChange(async (snapState: SnapControllerState) => { console.log('snap state changed', snapState); - await this.updateAccounts(); + + // only check if snaps changed in status + const { snaps } = snapState; + const accounts = this.listAccounts(); + + this.update((currentState: AccountsControllerState) => { + Object.values(snaps).forEach((snap) => { + if (!this.#isSnapEnabled(snap.id)) { + accounts.forEach((account) => { + if (account.metadata.snap?.id === snap.id) { + currentState.internalAccounts.accounts[ + account.id + ].metadata.snap.enabled = false; + } + }); + } + }); + }); + + console.log('updated state after snap changes', this.state); }); ///: END:ONLY_INCLUDE_IN(keyring-snaps) @@ -145,24 +164,61 @@ export default class AccountsController extends BaseControllerV2< console.log('keyring state changed', keyringState); // check if there are any new accounts added + // TODO: change when accountAdded event is added to the keyring controller + if (keyringState.isUnlocked) { // TODO: ACCOUNTS_CONTROLLER keyring will return accounts instead of addresses, remove this flatMap after and just get the latest id - const updatedKeyringAccounts = keyringState.keyrings.flatMap( + const updatedKeyringAddresses = keyringState.keyrings.flatMap( (keyring) => keyring.accounts, ); - - const accounts = this.listAccounts(); + const previousAccounts = this.listAccounts(); await this.updateAccounts(); - if (newAddress) { - console.log('setting new account', newAddress); - const updatedAccountsList = this.listAccounts(); - const { id: newAccountId } = updatedAccountsList.find( + if (updatedKeyringAddresses.length > previousAccounts.length) { + // new address to add + const newAddress = updatedKeyringAddresses.find( + (address) => + !previousAccounts.find( + (account) => + account.address.toLowerCase() === address.toLowerCase(), + ), + ); + + const newAccount = this.listAccounts().find( (account) => account.address.toLowerCase() === newAddress.toLowerCase(), ); - this.setSelectedAccount(newAccountId); + + console.log('new account in onKeyringStateChange', newAccount); + + // set the first new account as the selected account + this.setSelectedAccount(newAccount.id); + } else if ( + updatedKeyringAddresses.length < previousAccounts.length && + !this.getAccount(this.state.internalAccounts.selectedAccount) + ) { + // handle if the removed account is the selected + + const previousAccount = this.listAccounts() + .filter( + (account) => + account.id !== this.state.internalAccounts.selectedAccount, + ) + .sort((accountA, accountB) => { + // sort by lastSelected descending + return ( + accountB.metadata?.lastSelected - + accountA.metadata?.lastSelected + ); + })[0]; + + console.log( + 'removed selected account and now setting previous', + previousAccount, + ); + + this.setSelectedAccount(previousAccount.id); } } }); @@ -176,20 +232,6 @@ export default class AccountsController extends BaseControllerV2< } } - // getAccount(address: string): InternalAccount | undefined { - // return Object.values(this.state.internalAccounts.accounts).find( - // (account) => account.address.toLowerCase() === address.toLowerCase(), - // ); - // } - - // getAccountExpect(address: string): InternalAccount { - // const account = this.getAccount(address); - // if (account === undefined) { - // throw new Error(`Account ${address} not found`); - // } - // return account; - // } - getAccount(accountId: string): InternalAccount | undefined { return this.state.internalAccounts.accounts[accountId]; } @@ -222,7 +264,6 @@ export default class AccountsController extends BaseControllerV2< ), ); ///: END:ONLY_INCLUDE_IN(keyring-snaps) - const accountNames = identitesToAccountNames(this.identities); // keyring type map. const keyringTypes = new Map(); @@ -233,74 +274,41 @@ export default class AccountsController extends BaseControllerV2< ...snapAccounts, ///: END:ONLY_INCLUDE_IN(keyring-snaps) ].reduce((internalAccountMap, internalAccount) => { - const keyringAccountIndex = - keyringTypes.get(internalAccount.metadata.keyring.type) ?? 0; + const keyringTypeName = keyringTypeToName( + internalAccount.metadata.keyring.type, + ); + const keyringAccountIndex = keyringTypes.get(keyringTypeName) ?? 0; if (keyringAccountIndex) { - keyringTypes.set( - internalAccount.metadata.keyring.type, - keyringAccountIndex + 1, - ); + keyringTypes.set(keyringTypeName, keyringAccountIndex + 1); } else { - keyringTypes.set(internalAccount.metadata.keyring.type, 1); + keyringTypes.set(keyringTypeName, 1); } + const existingAccount = this.getAccount(internalAccount.id); + internalAccountMap[internalAccount.id] = { ...internalAccount, + // use the account name from the identities if it exists + name: existingAccount + ? existingAccount.name + : `${keyringTypeName} ${keyringAccountIndex + 1}`, + metadata: { + ...internalAccount.metadata, + lastSelected: this.getAccount(internalAccount.id)?.metadata + ?.lastSelected, + }, }; - // use the account name from the identities if it exists - internalAccountMap[internalAccount.id].name = accountNames[ - internalAccount.id - ] - ? accountNames[internalAccount.id] - : `${keyringTypeToName(internalAccount.metadata.keyring.type)} ${ - keyringAccountIndex + 1 - }`; - return internalAccountMap; }, {} as Record); - // find lost accounts - const lostAccounts = this.listAccounts() - .filter((existingAccount) => accounts[existingAccount.id] === undefined) - .reduce((lostAccountsMap, lostAccount) => { - lostAccountsMap[lostAccount.id] = lostAccount; - return lostAccountsMap; - }, {} as Record); - this.update((currentState: AccountsControllerState) => { currentState.internalAccounts.accounts = accounts; - currentState.internalAccounts.lostAccounts = lostAccounts; }); console.log('updated state', this.state); } - // removeAccount(accountId: string): void { - // const accountToDelete = this.getAccount(accountId); - // const accounts = this.getAllAccounts(); - - // console.log('removing account', accountToDelete); - - // if (accountToDelete) { - // const previousAccount = accounts - // .filter((account) => account.lastSelected && account.id !== accountId) - // .sort((accountA, accountB) => { - // // sort by lastSelected descending - // return ( - // accountB.metadata.lastSelected - accountA.metadata.lastSelected - // ); - // })[0]; - - // console.log('setting new selected', previousAccount); - - // this.update((currentState: AccountsControllerState) => { - // delete currentState.internalAccounts.accounts[accountToDelete.id]; - // currentState.internalAccounts.selectedAccount = previousAccount.id; - // }); - // } - // } - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) async #listSnapAccounts(): Promise { const [snapKeyring] = this.#keyringController.getKeyringsByType( @@ -316,7 +324,7 @@ export default class AccountsController extends BaseControllerV2< account.metadata = { snap: { id: account?.metadata?.snap?.id, - enabled: await this.#getSnapStatus( + enabled: await this.#isSnapEnabled( account?.metadata?.snap?.id as string, ), name: account.name, @@ -331,9 +339,10 @@ export default class AccountsController extends BaseControllerV2< } ///: END:ONLY_INCLUDE_IN(keyring-snaps) + // Note: listLegacyAccounts is a temporary method until the keyrings all implement the InternalAccount interface async #listLegacyAccounts(): Promise { const addresses = await this.#keyringController.getAccounts(); - const internalAccounts = []; + const internalAccounts: InternalAccount[] = []; for (const address of addresses) { const keyring = await this.#keyringController.getKeyringForAccount( address, @@ -378,13 +387,8 @@ export default class AccountsController extends BaseControllerV2< console.log('set selected account', account); this.update((currentState: AccountsControllerState) => { - currentState.internalAccounts.accounts[account.id] = { - ...currentState.internalAccounts.accounts[account.id], - metadata: { - ...currentState.internalAccounts.accounts[account.id].metadata, - lastSelected: Date.now(), - }, - }; + currentState.internalAccounts.accounts[account.id].metadata.lastSelected = + Date.now(); currentState.internalAccounts.selectedAccount = account.id; }); } @@ -392,6 +396,14 @@ export default class AccountsController extends BaseControllerV2< setAccountName(accountId: string, accountName: string): void { const account = this.getAccountExpect(accountId); + if ( + this.listAccounts().find( + (internalAccount) => internalAccount.name === accountName, + ) + ) { + throw new Error('Account name already exists'); + } + this.update((currentState: AccountsControllerState) => { currentState.internalAccounts.accounts[accountId] = { ...account, @@ -403,12 +415,11 @@ export default class AccountsController extends BaseControllerV2< } ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) - async #getSnapStatus(snapId: string): Promise { - const snap = await this.#snapController.getSnapState(snapId); + async #isSnapEnabled(snapId: string): Promise { + const snap = (await this.#snapController.getSnapState(snapId)) as any; if (!snap) { return false; } - return snap?.enabled && !snap?.blocked; } ///: END:ONLY_INCLUDE_IN(keyring-snaps) diff --git a/package.json b/package.json index 27464cc91ca0..b549c674dade 100644 --- a/package.json +++ b/package.json @@ -241,7 +241,7 @@ "@metamask/eth-json-rpc-middleware": "^11.0.0", "@metamask/eth-keyring-controller": "^10.0.1", "@metamask/eth-ledger-bridge-keyring": "^0.15.0", - "@metamask/eth-snap-keyring": "git+https://github.com/MetaMask/eth-snap-keyring.git#commit=60130ddcfd8f4e9a1e0de299f6798dfd966f9634", + "@metamask/eth-snap-keyring": "git+https://github.com/MetaMask/eth-snap-keyring.git#commit=543117c98e80c83378dbd8bb2bc87704ee0f96f0", "@metamask/eth-token-tracker": "^4.0.0", "@metamask/eth-trezor-keyring": "^1.0.0", "@metamask/etherscan-link": "^2.2.0", diff --git a/yarn.lock b/yarn.lock index 7ae8da8f9b47..50fc989f91e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4171,9 +4171,9 @@ __metadata: languageName: node linkType: hard -"@metamask/eth-snap-keyring@git+https://github.com/MetaMask/eth-snap-keyring.git#commit=60130ddcfd8f4e9a1e0de299f6798dfd966f9634": +"@metamask/eth-snap-keyring@git+https://github.com/MetaMask/eth-snap-keyring.git#commit=543117c98e80c83378dbd8bb2bc87704ee0f96f0": version: 0.1.3 - resolution: "@metamask/eth-snap-keyring@https://github.com/MetaMask/eth-snap-keyring.git#commit=60130ddcfd8f4e9a1e0de299f6798dfd966f9634" + resolution: "@metamask/eth-snap-keyring@https://github.com/MetaMask/eth-snap-keyring.git#commit=543117c98e80c83378dbd8bb2bc87704ee0f96f0" dependencies: "@ethereumjs/tx": "npm:^4.1.2" "@metamask/eth-sig-util": "npm:^5.1.0" @@ -4183,7 +4183,7 @@ __metadata: "@types/uuid": "npm:^9.0.1" superstruct: "npm:^1.0.3" uuid: "npm:^9.0.0" - checksum: d8eb396f2efefd511fce6654c27f91e7a3ef0bee74932a01ff41f45d62b335a267d879f72c0a3326b4185bd71e12c2d140d1162f394e588665876259585c8ccd + checksum: 3215227629560912c4d8d097cb7a45116996022ecb60d816751be6e1d01ba7eb2d8de06eea670914003a9ff319107e99f820089e9b4cb7883df733799fcff560 languageName: node linkType: hard @@ -24247,7 +24247,7 @@ __metadata: "@metamask/eth-json-rpc-middleware": "npm:^11.0.0" "@metamask/eth-keyring-controller": "npm:^10.0.1" "@metamask/eth-ledger-bridge-keyring": "npm:^0.15.0" - "@metamask/eth-snap-keyring": "git+https://github.com/MetaMask/eth-snap-keyring.git#commit=60130ddcfd8f4e9a1e0de299f6798dfd966f9634" + "@metamask/eth-snap-keyring": "git+https://github.com/MetaMask/eth-snap-keyring.git#commit=543117c98e80c83378dbd8bb2bc87704ee0f96f0" "@metamask/eth-token-tracker": "npm:^4.0.0" "@metamask/eth-trezor-keyring": "npm:^1.0.0" "@metamask/etherscan-link": "npm:^2.2.0" From d1daf9a008b31fda629a248a3a5aac481322f23d Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Sat, 5 Aug 2023 19:17:38 +0800 Subject: [PATCH 029/235] fix: metamask-controller.actions tests --- .../controllers/accounts-controller.ts | 31 +++----- .../metamask-controller.actions.test.js | 9 +-- app/scripts/metamask-controller.js | 70 ++++++++++++------- test/data/mock-send-state.json | 18 ----- 4 files changed, 57 insertions(+), 71 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index 8070b00a90cb..c7dec9b8f997 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -161,7 +161,7 @@ export default class AccountsController extends BaseControllerV2< ///: END:ONLY_INCLUDE_IN(keyring-snaps) onKeyringStateChange(async (keyringState: KeyringControllerState) => { - console.log('keyring state changed', keyringState); + // console.log('keyring state changed', keyringState); // check if there are any new accounts added // TODO: change when accountAdded event is added to the keyring controller @@ -187,13 +187,15 @@ export default class AccountsController extends BaseControllerV2< const newAccount = this.listAccounts().find( (account) => - account.address.toLowerCase() === newAddress.toLowerCase(), + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + account.address.toLowerCase() === newAddress!.toLowerCase(), ); console.log('new account in onKeyringStateChange', newAccount); // set the first new account as the selected account - this.setSelectedAccount(newAccount.id); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + this.setSelectedAccount(newAccount!.id); } else if ( updatedKeyringAddresses.length < previousAccounts.length && !this.getAccount(this.state.internalAccounts.selectedAccount) @@ -208,8 +210,8 @@ export default class AccountsController extends BaseControllerV2< .sort((accountA, accountB) => { // sort by lastSelected descending return ( - accountB.metadata?.lastSelected - - accountA.metadata?.lastSelected + (accountB.metadata?.lastSelected ?? 0) - + (accountA.metadata?.lastSelected ?? 0) ); })[0]; @@ -318,12 +320,10 @@ export default class AccountsController extends BaseControllerV2< const snapAccounts = (await (snapKeyring as SnapKeyring)?.listAccounts(false)) ?? []; - console.log('snap accounts', snapAccounts); - for (const account of snapAccounts) { account.metadata = { snap: { - id: account?.metadata?.snap?.id, + id: account?.metadata?.snap?.id!, enabled: await this.#isSnapEnabled( account?.metadata?.snap?.id as string, ), @@ -425,21 +425,6 @@ export default class AccountsController extends BaseControllerV2< ///: END:ONLY_INCLUDE_IN(keyring-snaps) } -export function identitesToAccountNames( - identities: Record, -): Record { - if (!identities) { - return {}; - } - return Object.values(identities).reduce((accounts, identity) => { - const accountId = uuid({ - random: sha256FromString(identity.address).slice(0, 16), - }); - accounts[accountId] = identity.name; - return accounts; - }, {} as Record); -} - function keyringTypeToName(keyringType: string): string { switch (keyringType) { case 'Simple Key Pair': { diff --git a/app/scripts/metamask-controller.actions.test.js b/app/scripts/metamask-controller.actions.test.js index 5e7c771a1a6b..6475f03e4d14 100644 --- a/app/scripts/metamask-controller.actions.test.js +++ b/app/scripts/metamask-controller.actions.test.js @@ -146,8 +146,8 @@ describe('MetaMaskController', function () { metamaskController.addNewAccount(1), ]); assert.deepEqual( - Object.keys(addNewAccountResult1.identities), - Object.keys(addNewAccountResult2.identities), + addNewAccountResult1.accounts, + addNewAccountResult2.accounts, ); }); @@ -156,8 +156,8 @@ describe('MetaMaskController', function () { const addNewAccountResult1 = await metamaskController.addNewAccount(1); const addNewAccountResult2 = await metamaskController.addNewAccount(1); assert.deepEqual( - Object.keys(addNewAccountResult1.identities), - Object.keys(addNewAccountResult2.identities), + addNewAccountResult1.accounts, + addNewAccountResult2.accounts, ); }); @@ -165,6 +165,7 @@ describe('MetaMaskController', function () { await metamaskController.createNewVaultAndKeychain('test@123'); const addNewAccountResult1 = await metamaskController.addNewAccount(1); const addNewAccountResult2 = await metamaskController.addNewAccount(2); + console.log(addNewAccountResult1, addNewAccountResult2); assert.notDeepEqual(addNewAccountResult1, addNewAccountResult2); }); }); diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 46044d6b99f8..e4eafd50b580 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1106,8 +1106,6 @@ export default class MetamaskController extends EventEmitter { ], }); - console.log('init accounts controller state', initState.AccountsController); - this.accountsController = new AccountsController({ messenger: accountsControllerMessenger, state: initState.AccountsController, @@ -2398,6 +2396,9 @@ export default class MetamaskController extends EventEmitter { setSelectedInternalAccount: accountsController.setSelectedAccount.bind(accountsController), + setAccountName: + accountsController.setAccountName.bind(accountsController), + // AssetsContractController getTokenStandardAndDetails: this.getTokenStandardAndDetails.bind(this), @@ -2909,9 +2910,7 @@ export default class MetamaskController extends EventEmitter { vault = await this.keyringController.createNewVaultAndKeychain( password, ); - const addresses = await this.keyringController.getAccounts(); - this.preferencesController.setAddresses(addresses); - this.selectFirstIdentity(); + await this.accountsController.updateAccounts(); } return vault; @@ -2936,9 +2935,6 @@ export default class MetamaskController extends EventEmitter { const { keyringController } = this; - // clear known identities - this.preferencesController.setAddresses([]); - // clear permissions this.permissionController.clearState(); @@ -2988,10 +2984,18 @@ export default class MetamaskController extends EventEmitter { ); } + await this.accountsController.updateAccounts(); + const internalAccounts = this.accountsController.listAccounts(); + // remove extra zero balance account potentially created from seeking ahead if (accounts.length > 1 && lastBalance === '0x0') { - await this.removeAccount(accounts[accounts.length - 1]); - accounts = await keyringController.getAccounts(); + await this.removeAccount( + internalAccounts.find( + (account) => + account.address.toLowerCase() === + accounts[accounts.length - 1].toLowerCase(), + ).id, + ); } // This must be set as soon as possible to communicate to the @@ -3151,10 +3155,20 @@ export default class MetamaskController extends EventEmitter { /** * Sets the first address in the state to the selected address */ - selectFirstIdentity() { - const { identities } = this.preferencesController.store.getState(); - const [address] = Object.keys(identities); - this.preferencesController.setSelectedAddress(address); + selectFirstAccount() { + const [account] = this.accountsController.listAccounts(); + this.accountsController.setSelectedAccount(account.id); + } + + setAccountName(accountId, accountName) { + const accounts = this.accountsController.listAccounts(); + if (accounts.some((account) => account.name === accountName)) { + throw new Error( + `An account with the name ${accountName} already exists.`, + ); + } + + this.accountsController.setAccountName(accountId, accountName); } /** @@ -3418,10 +3432,10 @@ export default class MetamaskController extends EventEmitter { /** * Adds a new account to the default (first) HD seed phrase Keyring. * - * @param accountName + * @param accountCount * @returns {} keyState */ - async addNewAccount(accountName) { + async addNewAccount(accountCount) { const isActionMetricsQueueE2ETest = this.appStateController.store.getState()[ACTION_QUEUE_METRICS_E2E_TEST]; @@ -3436,19 +3450,24 @@ export default class MetamaskController extends EventEmitter { throw new Error('MetamaskController - No HD Key Tree found'); } const { keyringController } = this; - await keyringController.addNewAccount(primaryKeyring); - await this.accountsController.updateAccounts(); - let newAccount = this.accountsController.getSelectedAccount(); + const currentAccounts = this.accountsController.listAccounts(); + const numberOfHdKeyringAccounts = currentAccounts.filter( + (account) => account.metadata.keyring.type === KeyringType.hdKeyTree, + ).length; - if (accountName) { - console.log('setting new name', accountName); - this.accountsController.setAccountName(newAccount.id, accountName); - newAccount = this.accountsController.getSelectedAccount(); + if (numberOfHdKeyringAccounts === accountCount) { + const keyState = await keyringController.addNewAccount(primaryKeyring); + await this.accountsController.updateAccounts(); + const updatedAccounts = this.accountsController.listAccounts(); + return { + ...keyState, + accounts: updatedAccounts, + }; } return { ...keyringController.memStore.getState(), - account: newAccount, + accounts: currentAccounts, }; } @@ -4424,8 +4443,7 @@ export default class MetamaskController extends EventEmitter { return; } - // Ensure preferences + identities controller know about all addresses - this.preferencesController.syncAddresses(addresses); + // Ensure account tracker controller know about all addresses this.accountTracker.syncWithAddresses(addresses); } diff --git a/test/data/mock-send-state.json b/test/data/mock-send-state.json index 7472dde80354..d8686ea02feb 100644 --- a/test/data/mock-send-state.json +++ b/test/data/mock-send-state.json @@ -233,24 +233,6 @@ "accounts": ["0xeb9e64b93097bc15f01f13eae97015c57ab64823"] } ], - "identities": { - "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": { - "address": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", - "name": "Test Account" - }, - "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b": { - "address": "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b", - "name": "Test Account 2" - }, - "0xc42edfcc21ed14dda456aa0756c153f7985d8813": { - "address": "0xc42edfcc21ed14dda456aa0756c153f7985d8813", - "name": "Test Ledger 1" - }, - "0xeb9e64b93097bc15f01f13eae97015c57ab64823": { - "name": "Test Account 3", - "address": "0xeb9e64b93097bc15f01f13eae97015c57ab64823" - } - }, "networkDetails": { "EIPS": { "1559": true From 3228730d73f87260c431d9b858242bc0fa4d2059 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Sun, 6 Aug 2023 10:24:36 +0800 Subject: [PATCH 030/235] fix: remove the use of identities --- .../advanced-gas-controls.test.js | 2 +- ...ission-page-container-content.component.js | 37 ++++---- .../permission-page-container.component.js | 29 ++++--- .../permission-page-container.container.js | 14 ++-- .../signature-request-original.stories.js | 10 +-- .../signature-request-siwe-header.stories.js | 5 +- .../signature-request-data.test.js | 10 +-- .../signature-request.test.js | 2 - ui/ducks/app/app.test.js | 31 +++++-- ui/ducks/send/send.test.js | 2 - .../connected-accounts.stories.js | 55 ++++++++++-- .../import-token/import-token.component.js | 14 ++-- .../import-token/import-token.container.js | 13 +-- ui/pages/import-token/import-token.stories.js | 14 ++-- ui/pages/import-token/import-token.test.js | 54 +++++++++++- .../send-asset-row.component.js | 23 ++++- .../send-asset-row.container.js | 3 +- .../send-asset-row/send-asset-row.stories.js | 5 +- .../edit-contact/edit-contact.container.js | 5 +- .../view-contact/view-contact.container.js | 5 +- ui/selectors/confirm-transaction.js | 1 + ui/selectors/permissions.js | 16 ++-- ui/selectors/permissions.test.js | 84 ++++++++++++++++--- ui/selectors/selectors.js | 16 ---- ui/store/actionConstants.test.js | 2 +- ui/store/actions.test.js | 7 +- ui/store/actions.ts | 17 ++-- ui/store/store.ts | 5 -- 28 files changed, 337 insertions(+), 144 deletions(-) diff --git a/ui/components/app/advanced-gas-controls/advanced-gas-controls.test.js b/ui/components/app/advanced-gas-controls/advanced-gas-controls.test.js index 6a15f9c6b4a2..7ce522dd6325 100644 --- a/ui/components/app/advanced-gas-controls/advanced-gas-controls.test.js +++ b/ui/components/app/advanced-gas-controls/advanced-gas-controls.test.js @@ -7,7 +7,7 @@ import AdvancedGasControls from './advanced-gas-controls.component'; const renderComponent = (props) => { const store = configureMockStore([])({ - metamask: { identities: [], providerConfig: {} }, + metamask: { providerConfig: {} }, }); return renderWithProvider(, store); }; diff --git a/ui/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js b/ui/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js index 96a39ec0fe4c..499f472a79ef 100644 --- a/ui/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js +++ b/ui/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js @@ -17,13 +17,20 @@ export default class PermissionPageContainerContent extends PureComponent { iconUrl: PropTypes.string, }), selectedPermissions: PropTypes.object.isRequired, - selectedIdentities: PropTypes.array, - allIdentitiesSelected: PropTypes.bool, + selectedAccounts: PropTypes.arrayOf( + PropTypes.shape({ + address: PropTypes.string.isRequired, + addressLabel: PropTypes.string.isRequired, + balance: PropTypes.string.isRequired, + label: PropTypes.string.isRequired, + }), + ), + allAccountsSelected: PropTypes.bool, }; static defaultProps = { - selectedIdentities: [], - allIdentitiesSelected: false, + selectedAccounts: [], + allAccountsSelected: false, }; static contextTypes = { @@ -44,7 +51,7 @@ export default class PermissionPageContainerContent extends PureComponent { } renderAccountTooltip(textContent) { - const { selectedIdentities } = this.props; + const { selectedAccounts } = this.props; const { t } = this.context; return ( @@ -54,15 +61,15 @@ export default class PermissionPageContainerContent extends PureComponent { wrapperClassName="permission-approval-container__bold-title-elements" html={
- {selectedIdentities.slice(0, 6).map((identity, index) => { + {selectedAccounts.slice(0, 6).map((account, index) => { return (
- {identity.addressLabel} + {account.addressLabel}
); })} - {selectedIdentities.length > 6 - ? t('plusXMore', [selectedIdentities.length - 6]) + {selectedAccounts.length > 6 + ? t('plusXMore', [selectedAccounts.length - 6]) : null}
} @@ -75,8 +82,8 @@ export default class PermissionPageContainerContent extends PureComponent { getTitle() { const { subjectMetadata, - selectedIdentities, - allIdentitiesSelected, + selectedAccounts, + allAccountsSelected, selectedPermissions, } = this.props; const { t } = this.context; @@ -85,18 +92,18 @@ export default class PermissionPageContainerContent extends PureComponent { return t('externalExtension', [subjectMetadata.extensionId]); } else if (!selectedPermissions.eth_accounts) { return t('permissionRequestCapitalized'); - } else if (allIdentitiesSelected) { + } else if (allAccountsSelected) { return t('connectToAll', [ this.renderAccountTooltip(t('connectToAllAccounts')), ]); - } else if (selectedIdentities.length > 1) { + } else if (selectedAccounts.length > 1) { return t('connectToMultiple', [ this.renderAccountTooltip( - t('connectToMultipleNumberOfAccounts', [selectedIdentities.length]), + t('connectToMultipleNumberOfAccounts', [selectedAccounts.length]), ), ]); } - return t('connectTo', [selectedIdentities[0]?.addressLabel]); + return t('connectTo', [selectedAccounts[0]?.addressLabel]); } getHeaderText() { diff --git a/ui/components/app/permission-page-container/permission-page-container.component.js b/ui/components/app/permission-page-container/permission-page-container.component.js index 1f817edf893e..43f61ba056fa 100644 --- a/ui/components/app/permission-page-container/permission-page-container.component.js +++ b/ui/components/app/permission-page-container/permission-page-container.component.js @@ -22,8 +22,15 @@ export default class PermissionPageContainer extends Component { static propTypes = { approvePermissionsRequest: PropTypes.func.isRequired, rejectPermissionsRequest: PropTypes.func.isRequired, - selectedIdentities: PropTypes.array, - allIdentitiesSelected: PropTypes.bool, + selectedAccounts: PropTypes.arrayOf( + PropTypes.shape({ + address: PropTypes.string.isRequired, + addressLabel: PropTypes.string.isRequired, + balance: PropTypes.string.isRequired, + label: PropTypes.string.isRequired, + }), + ), + allAccountsSelected: PropTypes.bool, ///: BEGIN:ONLY_INCLUDE_IN(snaps) currentPermissions: PropTypes.object, snapsInstallPrivacyWarningShown: PropTypes.bool.isRequired, @@ -43,8 +50,8 @@ export default class PermissionPageContainer extends Component { static defaultProps = { request: {}, requestMetadata: {}, - selectedIdentities: [], - allIdentitiesSelected: false, + selectedAccounts: [], + allAccountsSelected: false, ///: BEGIN:ONLY_INCLUDE_IN(snaps) currentPermissions: {}, ///: END:ONLY_INCLUDE_IN @@ -144,14 +151,14 @@ export default class PermissionPageContainer extends Component { request: _request, approvePermissionsRequest, rejectPermissionsRequest, - selectedIdentities, + selectedAccounts, } = this.props; const request = { ..._request, permissions: { ..._request.permissions }, - approvedAccounts: selectedIdentities.map( - (selectedIdentity) => selectedIdentity.address, + approvedAccounts: selectedAccounts.map( + (selectedAccount) => selectedAccount.address, ), }; @@ -172,8 +179,8 @@ export default class PermissionPageContainer extends Component { const { requestMetadata, targetSubjectMetadata, - selectedIdentities, - allIdentitiesSelected, + selectedAccounts, + allAccountsSelected, } = this.props; ///: BEGIN:ONLY_INCLUDE_IN(snaps) @@ -207,8 +214,8 @@ export default class PermissionPageContainer extends Component { requestMetadata={requestMetadata} subjectMetadata={targetSubjectMetadata} selectedPermissions={this.state.selectedPermissions} - selectedIdentities={selectedIdentities} - allIdentitiesSelected={allIdentitiesSelected} + selectedAccounts={selectedAccounts} + allAccountsSelected={allAccountsSelected} />
{targetSubjectMetadata?.subjectType !== SubjectType.Snap && ( diff --git a/ui/components/app/permission-page-container/permission-page-container.container.js b/ui/components/app/permission-page-container/permission-page-container.container.js index f84a7c254877..7fa311789de3 100644 --- a/ui/components/app/permission-page-container/permission-page-container.container.js +++ b/ui/components/app/permission-page-container/permission-page-container.container.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import { - getMetaMaskIdentities, + getMetaMaskAccounts, ///: BEGIN:ONLY_INCLUDE_IN(snaps) getPermissions, ///: END:ONLY_INCLUDE_IN @@ -8,20 +8,20 @@ import { import PermissionPageContainer from './permission-page-container.component'; const mapStateToProps = (state, ownProps) => { - const { selectedIdentities } = ownProps; + const { selectedAccounts } = ownProps; ///: BEGIN:ONLY_INCLUDE_IN(snaps) const currentPermissions = getPermissions( state, ownProps.request.metadata?.origin, ); ///: END:ONLY_INCLUDE_IN - const allIdentities = getMetaMaskIdentities(state); - const allIdentitiesSelected = - Object.keys(selectedIdentities).length === - Object.keys(allIdentities).length && selectedIdentities.length > 1; + const allAccounts = getMetaMaskAccounts(state); + const allAccountsSelected = + Object.keys(selectedAccounts).length === Object.keys(allAccounts).length && + selectedAccounts.length > 1; return { - allIdentitiesSelected, + allAccountsSelected, ///: BEGIN:ONLY_INCLUDE_IN(snaps) currentPermissions, ///: END:ONLY_INCLUDE_IN diff --git a/ui/components/app/signature-request-original/signature-request-original.stories.js b/ui/components/app/signature-request-original/signature-request-original.stories.js index 3e1346d347dd..a36210b56d5c 100644 --- a/ui/components/app/signature-request-original/signature-request-original.stories.js +++ b/ui/components/app/signature-request-original/signature-request-original.stories.js @@ -5,8 +5,8 @@ import testData from '../../../../.storybook/test-data'; import README from './README.mdx'; import SignatureRequestOriginal from './signature-request-original.component'; -const [MOCK_PRIMARY_IDENTITY, MOCK_SECONDARY_IDENTITY] = Object.values( - testData.metamask.identities, +const [MOCK_PRIMARY_ACCOUNT, MOCK_SECONDARY_ACCOUNT] = Object.values( + testData.metamask.internalAccounts.accounts, ); const MOCK_SIGN_DATA = JSON.stringify({ @@ -67,14 +67,14 @@ export default { sign: { action: 'Sign' }, }, args: { - fromAccount: MOCK_PRIMARY_IDENTITY, + fromAccount: MOCK_PRIMARY_ACCOUNT.address, history: { push: action('history.push()'), }, mostRecentOverviewPage: '/', nativeCurrency: 'ETH', providerConfig: { name: 'Goerli ETH' }, - selectedAccount: MOCK_PRIMARY_IDENTITY, + selectedAccount: MOCK_PRIMARY_ACCOUNT, }, }; @@ -151,5 +151,5 @@ AccountMismatchStory.args = { }, type: MESSAGE_TYPE.PERSONAL_SIGN, }, - selectedAccount: MOCK_SECONDARY_IDENTITY, + selectedAccount: MOCK_SECONDARY_ACCOUNT, }; diff --git a/ui/components/app/signature-request-siwe/signature-request-siwe-header/signature-request-siwe-header.stories.js b/ui/components/app/signature-request-siwe/signature-request-siwe-header/signature-request-siwe-header.stories.js index cf6dbb98ac4f..2630af9b1ff6 100644 --- a/ui/components/app/signature-request-siwe/signature-request-siwe-header/signature-request-siwe-header.stories.js +++ b/ui/components/app/signature-request-siwe/signature-request-siwe-header/signature-request-siwe-header.stories.js @@ -2,7 +2,10 @@ import React from 'react'; import testData from '../../../../../.storybook/test-data'; import SignatureRequestSIWEHeader from '.'; -const primaryIdentity = Object.values(testData.metamask.identities)[0]; +const primaryIdentity = + testData.metamask.internalAccounts.accounts[ + testData.metamask.internalAccounts.selectedAccount + ]; const subjectMetadata = { iconUrl: '/images/logo/metamask-fox.svg', name: 'MetaMask', diff --git a/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js b/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js index 28c12e692e36..a0ab0f80189e 100644 --- a/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js +++ b/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js @@ -221,7 +221,7 @@ describe('Signature Request Data', () => { expect(iconImage).toBeDefined(); }); - it('should render first account name from wallets array if address exists in identities object', () => { + it('should render first account name from wallets array if address exists in internal account object', () => { const { getByText } = renderWithProvider( , store, @@ -240,7 +240,7 @@ describe('Signature Request Data', () => { expect(iconImage).toBeDefined(); }); - it('should render second account name from wallets array if address exists in identities object', () => { + it('should render second account name from wallets array if address exists in internal account object', () => { const { getByText } = renderWithProvider( , store, @@ -305,7 +305,7 @@ describe('Signature Request Data', () => { expect(iconImage).toBeDefined(); }); - it('should render first shorten address from wallets array if address does not exists in identities and address book objects', () => { + it('should render first shorten address from wallets array if address does not exists in internal account and address book objects', () => { const { getByText } = renderWithProvider( , store, @@ -324,7 +324,7 @@ describe('Signature Request Data', () => { expect(iconImage).toBeDefined(); }); - it('should render second shorten address from wallets array if address does not exists in identities and address book objects', () => { + it('should render second shorten address from wallets array if address does not exists in internal account and address book objects', () => { const { getByText } = renderWithProvider( , store, @@ -343,7 +343,7 @@ describe('Signature Request Data', () => { expect(iconImage).toBeDefined(); }); - it('should render third shorten address from wallets array if address does not exists in identities and address book objects', () => { + it('should render third shorten address from wallets array if address does not exists in internal account and address book objects', () => { const { getByText } = renderWithProvider( , store, diff --git a/ui/components/app/signature-request/signature-request.test.js b/ui/components/app/signature-request/signature-request.test.js index 641f01e77c11..c8b7fde84038 100644 --- a/ui/components/app/signature-request/signature-request.test.js +++ b/ui/components/app/signature-request/signature-request.test.js @@ -14,7 +14,6 @@ import { conversionRateSelector, getCurrentCurrency, getMemoizedAddressBook, - getMemoizedMetaMaskIdentities, getPreferences, getSelectedAccount, getInternalAccounts, @@ -121,7 +120,6 @@ const generateUseSelectorRouter = (opts) => (selector) => { case accountsWithSendEtherInfoSelector: return Object.values(opts.metamask.accounts); case unconfirmedTransactionsHashSelector: - case getMemoizedMetaMaskIdentities: return {}; default: return undefined; diff --git a/ui/ducks/app/app.test.js b/ui/ducks/app/app.test.js index 4f38785ab8e1..881760860c9d 100644 --- a/ui/ducks/app/app.test.js +++ b/ui/ducks/app/app.test.js @@ -6,12 +6,33 @@ const actions = actionConstants; describe('App State', () => { const metamaskState = { - selectedAddress: '0xAddress', - identities: { - '0xAddress': { - name: 'account 1', - address: '0xAddress', + internalAccounts: { + accounts: { + 'mock-id': { + address: '0xAddress', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Accounts 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }, + selectedAccount: 'mock-id', }, }; diff --git a/ui/ducks/send/send.test.js b/ui/ducks/send/send.test.js index 481c06726f67..33e6c9acd13c 100644 --- a/ui/ducks/send/send.test.js +++ b/ui/ducks/send/send.test.js @@ -2130,7 +2130,6 @@ describe('Send Slice', () => { const updateRecipientState = { metamask: { addressBook: {}, - identities: {}, providerConfig: { chainId: '', }, @@ -2678,7 +2677,6 @@ describe('Send Slice', () => { addressBook: { [CHAIN_IDS.GOERLI]: {}, }, - identities: {}, accounts: { [mockAddress1]: { address: mockAddress1, diff --git a/ui/pages/connected-accounts/connected-accounts.stories.js b/ui/pages/connected-accounts/connected-accounts.stories.js index ea2aa55af55c..8fedd59ef5d5 100644 --- a/ui/pages/connected-accounts/connected-accounts.stories.js +++ b/ui/pages/connected-accounts/connected-accounts.stories.js @@ -6,22 +6,61 @@ export default { title: 'Pages/ConnectedAccounts', }; -const account = [ +const accounts = [ { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, name: 'Account 1', - address: '0x983211ce699ea5ab57cc528086154b6db1ad8e55', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + { + address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', + id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, ]; -const identities = { - name: 'Account 1', - address: '0x64a845a5b02460acf8a3d84503b0d68d028b4bb4', -}; + export const DefaultStory = () => { return ( a.address.toLowerCase() === customAddress.toLowerCase(), + ), + ): this.setState({ customAddressError: this.context.t('personalAddressDetected'), }); diff --git a/ui/pages/import-token/import-token.container.js b/ui/pages/import-token/import-token.container.js index 9d238d646503..0a0421874fa7 100644 --- a/ui/pages/import-token/import-token.container.js +++ b/ui/pages/import-token/import-token.container.js @@ -21,13 +21,7 @@ import ImportToken from './import-token.component'; const mapStateToProps = (state) => { const { - metamask: { - identities, - tokens, - pendingTokens, - useTokenDetection, - selectedAddress, - }, + metamask: { internalAccounts, tokens, pendingTokens, useTokenDetection }, } = state; const { chainId } = getProviderConfig(state); @@ -39,7 +33,7 @@ const mapStateToProps = (state) => { Boolean(process.env.IN_TEST); return { - identities, + accounts: Object.values(internalAccounts.accounts), mostRecentOverviewPage: getMostRecentOverviewPage(state), tokens, pendingTokens, @@ -48,7 +42,8 @@ const mapStateToProps = (state) => { rpcPrefs: getRpcPrefsForCurrentProvider(state), tokenList: getTokenList(state), useTokenDetection, - selectedAddress, + selectedAccount: + internalAccounts.accounts[internalAccounts.selectedAccount], isDynamicTokenListAvailable: getIsDynamicTokenListAvailable(state), networkName: getTokenDetectionSupportNetworkByChainId(state), tokenDetectionInactiveOnNonMainnetSupportedNetwork: diff --git a/ui/pages/import-token/import-token.stories.js b/ui/pages/import-token/import-token.stories.js index b5368a430313..152fa48ff9df 100644 --- a/ui/pages/import-token/import-token.stories.js +++ b/ui/pages/import-token/import-token.stories.js @@ -13,9 +13,8 @@ const { metamask } = store.getState(); const { networkConfigurations, - identities, + internalAccounts, pendingTokens, - selectedAddress, tokenList, tokens, } = metamask; @@ -52,7 +51,7 @@ export default { type: 'object', }, }, - identities: { + accounts: { control: { type: 'object', }, @@ -90,9 +89,9 @@ export default { getTokenStandardAndDetails: { action: 'getTokenStandardAndDetails', }, - selectedAddress: { + selectedAccount: { control: { - type: 'text', + type: 'object', }, }, }, @@ -102,14 +101,15 @@ export default { }, pendingTokens, tokens, - identities, + accounts: Object.values(internalAccounts.accounts), showSearchTab: true, mostRecentOverviewPage: DEFAULT_ROUTE, chainId: networkConfigurations['test-networkConfigurationId-1'].chainId, rpcPrefs: networkConfigurations['test-networkConfigurationId-1'].rpcPrefs, tokenList, useTokenDetection: false, - selectedAddress, + selectedAccount: + internalAccounts.accounts[internalAccounts.selectedAccount], }, }; diff --git a/ui/pages/import-token/import-token.test.js b/ui/pages/import-token/import-token.test.js index b2fb6b5a2494..2294e0431c2f 100644 --- a/ui/pages/import-token/import-token.test.js +++ b/ui/pages/import-token/import-token.test.js @@ -28,6 +28,7 @@ describe('Import Token', () => { push: historyStub, }, showSearchTab: true, + accounts: [], tokenList: {}, }; @@ -37,8 +38,57 @@ describe('Import Token', () => { tokens: [], providerConfig: { chainId: '0x1' }, networkConfigurations: {}, - identities: {}, - selectedAddress: '0x1231231', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '28502799-71ba-41b3-b66d-7e51c8ada822': { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: '28502799-71ba-41b3-b66d-7e51c8ada822', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, useTokenDetection: true, }, history: { diff --git a/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js b/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js index 8b8b6d165e91..440de6889810 100644 --- a/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js +++ b/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js @@ -26,7 +26,22 @@ export default class SendAssetRow extends Component { }), ).isRequired, accounts: PropTypes.object.isRequired, - selectedAddress: PropTypes.string.isRequired, + selectedAccount: PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + address: PropTypes.string.isRequired, + balance: PropTypes.string.isRequired, + metadata: PropTypes.shape({ + snap: PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string, + enabled: PropTypes.bool, + }), + keyring: PropTypes.shape({ + type: PropTypes.string.isRequired, + }).isRequired, + }).isRequired, + }).isRequired, sendAsset: PropTypes.object, updateSendAsset: PropTypes.func.isRequired, nativeCurrency: PropTypes.string, @@ -186,12 +201,12 @@ export default class SendAssetRow extends Component { renderNativeCurrency(insideDropdown = false) { const { t } = this.context; - const { accounts, selectedAddress, nativeCurrency, nativeCurrencyImage } = + const { accounts, selectedAccount, nativeCurrency, nativeCurrencyImage } = this.props; const { sendableTokens, sendableNfts } = this.state; - const balanceValue = accounts[selectedAddress] - ? accounts[selectedAddress].balance + const balanceValue = accounts[selectedAccount.address] + ? accounts[selectedAccount.address].balance : ''; const sendableAssets = [...sendableTokens, ...sendableNfts]; diff --git a/ui/pages/send/send-content/send-asset-row/send-asset-row.container.js b/ui/pages/send/send-content/send-asset-row/send-asset-row.container.js index 63c579c57705..863682012228 100644 --- a/ui/pages/send/send-content/send-asset-row/send-asset-row.container.js +++ b/ui/pages/send/send-content/send-asset-row/send-asset-row.container.js @@ -7,6 +7,7 @@ import { import { getMetaMaskAccounts, getNativeCurrencyImage, + getSelectedAccount, } from '../../../../selectors'; import { updateSendAsset, getSendAsset } from '../../../../ducks/send'; import SendAssetRow from './send-asset-row.component'; @@ -14,7 +15,7 @@ import SendAssetRow from './send-asset-row.component'; function mapStateToProps(state) { return { tokens: state.metamask.tokens, - selectedAddress: state.metamask.selectedAddress, + selectedAccount: getSelectedAccount(state), nfts: getNfts(state), collections: getNftContracts(state), sendAsset: getSendAsset(state), diff --git a/ui/pages/send/send-content/send-asset-row/send-asset-row.stories.js b/ui/pages/send/send-content/send-asset-row/send-asset-row.stories.js index bc18085d02d3..7c1edd022f7a 100644 --- a/ui/pages/send/send-content/send-asset-row/send-asset-row.stories.js +++ b/ui/pages/send/send-content/send-asset-row/send-asset-row.stories.js @@ -18,13 +18,14 @@ export default { export const DefaultStory = () => { const { metamask } = store.getState(); - const { identities, assetImages, tokens } = metamask; + const { internalAccounts, assetImages, tokens } = metamask; + const accounts = Object.values(internalAccounts.accounts); return ( undefined} setUnsendableAssetError={() => undefined} diff --git a/ui/pages/settings/contact-list-tab/edit-contact/edit-contact.container.js b/ui/pages/settings/contact-list-tab/edit-contact/edit-contact.container.js index 72cb084795b3..2ce34dab7f81 100644 --- a/ui/pages/settings/contact-list-tab/edit-contact/edit-contact.container.js +++ b/ui/pages/settings/contact-list-tab/edit-contact/edit-contact.container.js @@ -23,7 +23,10 @@ const mapStateToProps = (state, ownProps) => { : ownProps.match.params.id; const contact = - getAddressBookEntry(state, address) || state.metamask.identities[address]; + getAddressBookEntry(state, address) || + state.metamask.internalAccounts.accounts.find( + (account) => account.address.toLowerCase() === address, + ); const { memo, name } = contact || {}; const { chainId } = getProviderConfig(state); diff --git a/ui/pages/settings/contact-list-tab/view-contact/view-contact.container.js b/ui/pages/settings/contact-list-tab/view-contact/view-contact.container.js index 275273d0af38..2cb9e240f46f 100644 --- a/ui/pages/settings/contact-list-tab/view-contact/view-contact.container.js +++ b/ui/pages/settings/contact-list-tab/view-contact/view-contact.container.js @@ -19,7 +19,10 @@ const mapStateToProps = (state, ownProps) => { : ownProps.match.params.id; const contact = - getAddressBookEntry(state, address) || state.metamask.identities[address]; + getAddressBookEntry(state, address) || + state.metamask.internalAccounts.accounts.find( + (account) => account.address.toLowerCase() === address, + ); const { memo, name } = contact || {}; return { diff --git a/ui/selectors/confirm-transaction.js b/ui/selectors/confirm-transaction.js index 349750192606..3b8eb067788f 100644 --- a/ui/selectors/confirm-transaction.js +++ b/ui/selectors/confirm-transaction.js @@ -93,6 +93,7 @@ export const unconfirmedTransactionsHashSelector = createSelector( network, chainId, ) => { + console.log(111, unapprovedTxs); const filteredUnapprovedTxs = Object.keys(unapprovedTxs).reduce( (acc, address) => { const transactions = { ...acc }; diff --git a/ui/selectors/permissions.js b/ui/selectors/permissions.js index 4773db30ebe5..71b5787692c6 100644 --- a/ui/selectors/permissions.js +++ b/ui/selectors/permissions.js @@ -5,6 +5,7 @@ import { WALLET_SNAP_PERMISSION_KEY } from '@metamask/rpc-methods'; import { CaveatTypes } from '../../shared/constants/permissions'; import { getApprovalRequestsByType } from './approvals'; import { + getInternalAccounts, getMetaMaskAccountsOrdered, getOriginOfCurrentTab, getSelectedInternalAccount, @@ -227,23 +228,20 @@ function subjectSelector(state, origin) { } export function getAccountToConnectToActiveTab(state) { - const { address: selectedAddress } = getSelectedInternalAccount(state); + const selectedAccount = getSelectedInternalAccount(state); + const numberOfAccounts = getInternalAccounts(state).length; const connectedAccounts = getPermittedAccountsForCurrentTab(state); - const { - metamask: { identities }, - } = state; - const numberOfAccounts = Object.keys(identities).length; - if ( connectedAccounts.length && connectedAccounts.length !== numberOfAccounts ) { if ( - connectedAccounts.findIndex((address) => address === selectedAddress) === - -1 + connectedAccounts.findIndex( + (address) => address === selectedAccount.address, + ) === -1 ) { - return identities[selectedAddress]; + return selectedAccount; } } diff --git a/ui/selectors/permissions.test.js b/ui/selectors/permissions.test.js index 68ea1f91ddc7..44ac5bf132c0 100644 --- a/ui/selectors/permissions.test.js +++ b/ui/selectors/permissions.test.js @@ -619,19 +619,79 @@ describe('selectors', () => { url: 'https://remix.ethereum.org/', }, metamask: { - identities: { - '0x7250739de134d33ec7ab1ee592711e15098c9d2d': { - address: '0x7250739de134d33ec7ab1ee592711e15098c9d2d', - name: 'Really Long Name That Should Be Truncated', - }, - '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5': { - address: '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5', - name: 'Account 1', - }, - '0xb3958fb96c8201486ae20be1d5c9f58083df343a': { - address: '0xb3958fb96c8201486ae20be1d5c9f58083df343a', - name: 'Account 2', + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x7250739de134d33ec7ab1ee592711e15098c9d2d', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Really Long Name That Should Be Truncated', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '07c2cfec-36c9-46c4-8115-3836d3ac9047': { + address: '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5', + id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '15e69915-2a1a-4019-93b3-916e11fd432f': { + address: '0xb3958fb96c8201486ae20be1d5c9f58083df343a', + id: '15e69915-2a1a-4019-93b3-916e11fd432f', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 2', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', }, subjects: { 'https://remix.ethereum.org': { diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 500cf9a33c75..78f3f659ddf1 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -317,13 +317,6 @@ export function getSelectedAddress(state) { return state.metamask.selectedAddress; } -export function getSelectedIdentity(state) { - const selectedAddress = getSelectedAddress(state); - const { identities } = state.metamask; - - return identities[selectedAddress]; -} - export function getSelectedInternalAccount(state) { const accountId = state.metamask.internalAccounts.selectedAccount; return state.metamask.internalAccounts.accounts[accountId]; @@ -382,10 +375,6 @@ export function getMetaMaskKeyrings(state) { return state.metamask.keyrings; } -export function getMetaMaskIdentities(state) { - return state.metamask.identities; -} - export function getMetaMaskAccountsRaw(state) { return state.metamask.accounts; } @@ -882,11 +871,6 @@ export function getShowWhatsNewPopup(state) { const createDeepEqualSelector = createSelectorCreator(defaultMemoize, isEqual); -export const getMemoizedMetaMaskIdentities = createDeepEqualSelector( - getMetaMaskIdentities, - (identities) => identities, -); - export const getMemoizedAddressBook = createDeepEqualSelector( getAddressBook, (addressBook) => addressBook, diff --git a/ui/store/actionConstants.test.js b/ui/store/actionConstants.test.js index 9aa9ccc47207..136dd41b9665 100644 --- a/ui/store/actionConstants.test.js +++ b/ui/store/actionConstants.test.js @@ -4,7 +4,7 @@ import * as actionConstants from './actionConstants'; describe('Redux actionConstants', () => { describe('SET_ACCOUNT_LABEL', () => { - it('updates the state.metamask.identities[:i].name property of the state to the action.value.label', () => { + it('updates the state.metamask.internalAccounts.accounts[accountId].name property of the state to the action.value.label', () => { const accountId = 'foo'; const initialState = { metamask: { diff --git a/ui/store/actions.test.js b/ui/store/actions.test.js index 4744b0ca1e0a..d75fb5514632 100644 --- a/ui/store/actions.test.js +++ b/ui/store/actions.test.js @@ -444,12 +444,15 @@ describe('Actions', () => { describe('#addNewAccount', () => { it('adds a new account', async () => { const store = mockStore({ - metamask: { identities: {}, ...defaultState.metamask }, + metamask: { + internalAccounts: { accounts: {}, selectedAccount: '' }, + ...defaultState.metamask, + }, }); const addNewAccount = background.addNewAccount.callsFake((_, cb) => cb(null, { - identities: {}, + accounts: [], }), ); diff --git a/ui/store/actions.ts b/ui/store/actions.ts index 9a9eff9c393c..cccb93de5348 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -424,16 +424,23 @@ export function importNewAccount( } export function addNewAccount( - accountName: string, + accountCount: string, ): ThunkAction { log.debug(`background.addNewAccount`); - return async (dispatch) => { + return async (dispatch, getState) => { + const oldAccounts = getState().metamask.internalAccounts.accounts; + // const oldHdAccounts = Object.values(oldAccounts).filter( + // (account) => account.metadata.keyring.type === 'HD Key Tree', + // ); + dispatch(showLoadingIndication()); + try { - const { account } = await submitRequestToBackground('addNewAccount', [ - accountName, + const { accounts } = await submitRequestToBackground('addNewAccount', [ + accountCount, ]); - return account; + const newAccount = accounts.find((account) => !oldAccounts[account.id]); + return newAccount; } catch (error) { dispatch(displayWarning(error)); throw error; diff --git a/ui/store/store.ts b/ui/store/store.ts index 21d92a83251d..1df2edcf0495 100644 --- a/ui/store/store.ts +++ b/ui/store/store.ts @@ -56,11 +56,6 @@ interface TemporaryBackgroundState { }; currentNetworkTxList: TransactionMeta[]; selectedAddress: string; - identities: { - [address: string]: { - balance: string; - }; - }; ledgerTransportType: LedgerTransportTypes; unapprovedDecryptMsgs: MessagesIndexedById; unapprovedTxs: { From dd18f59e711d6deed772acfc40fbe87f31097bb4 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Sun, 6 Aug 2023 23:07:33 +0800 Subject: [PATCH 031/235] feat: add new tests internal accounts in metamask-controller --- app/scripts/metamask-controller.test.js | 287 ++++++++++++++++-------- 1 file changed, 194 insertions(+), 93 deletions(-) diff --git a/app/scripts/metamask-controller.test.js b/app/scripts/metamask-controller.test.js index 02d7b1f50ff4..f36553a392c2 100644 --- a/app/scripts/metamask-controller.test.js +++ b/app/scripts/metamask-controller.test.js @@ -15,6 +15,8 @@ import { METAMASK_STALELIST_FILE, METAMASK_HOTLIST_DIFF_FILE, } from '@metamask/phishing-controller'; +import { v4 as uuid } from 'uuid'; +import { sha256FromString } from 'ethereumjs-util'; import { TransactionStatus } from '../../shared/constants/transaction'; import createTxMeta from '../../test/lib/createTxMeta'; import { NETWORK_TYPES } from '../../shared/constants/network'; @@ -125,6 +127,12 @@ const MAINNET_CHAIN_ID = '0x1'; const firstTimeState = { config: {}, + AccountsController: { + internalAccounts: { + accounts: {}, + selectedAccount: '', + }, + }, NetworkController: { providerConfig: { type: NETWORK_TYPES.RPC, @@ -353,7 +361,7 @@ describe('MetaMaskController', function () { }); describe('submitPassword', function () { - it('removes any identities that do not correspond to known accounts.', async function () { + it('removes any account that do not correspond to known accounts.', async function () { const password = 'password'; await metamaskController.createNewVaultAndKeychain(password); @@ -361,23 +369,23 @@ describe('MetaMaskController', function () { metamaskController.preferencesController.addAddresses([fakeAddress]); await metamaskController.submitPassword(password); - const identities = Object.keys( - metamaskController.preferencesController.store.getState().identities, - ); const addresses = await metamaskController.keyringController.getAccounts(); - identities.forEach((identity) => { + const internalAccounts = + metamaskController.accountsController.listAccounts(); + + internalAccounts.forEach((account) => { assert.ok( - addresses.includes(identity), - `addresses should include all IDs: ${identity}`, + addresses.includes(account.address), + `addresses should include all IDs: ${account.address}`, ); }); addresses.forEach((address) => { assert.ok( - identities.includes(address), - `identities should include all Addresses: ${address}`, + internalAccounts.find((account) => account.address === address), + `internalAccounts should include all Addresses: ${address}`, ); }); }); @@ -387,7 +395,7 @@ describe('MetaMaskController', function () { it('can only create new vault on keyringController once', async function () { const selectStub = sandbox.stub( metamaskController, - 'selectFirstIdentity', + 'selectFirstAccount', ); const password = 'a-fake-password'; @@ -423,7 +431,7 @@ describe('MetaMaskController', function () { ); }); - it('should clear previous identities after vault restoration', async function () { + it('should clear previous accounts after vault restoration', async function () { sandbox.stub(metamaskController, 'getBalance'); metamaskController.getBalance.callsFake(() => { return Promise.resolve('0x0'); @@ -436,30 +444,78 @@ describe('MetaMaskController', function () { ); let endTime = Date.now(); - const firstVaultIdentities = cloneDeep( - metamaskController.getState().identities, + const originalVaultAccounts = + metamaskController.getState().internalAccounts; + + const testAccount = cloneDeep( + Object.values(originalVaultAccounts.accounts).find( + (account) => account.address === TEST_ADDRESS, + ), ); + assert.ok( - firstVaultIdentities[TEST_ADDRESS].lastSelected >= startTime && - firstVaultIdentities[TEST_ADDRESS].lastSelected <= endTime, - `'${firstVaultIdentities[TEST_ADDRESS].lastSelected}' expected to be between '${startTime}' and '${endTime}'`, - ); - delete firstVaultIdentities[TEST_ADDRESS].lastSelected; - assert.deepEqual(firstVaultIdentities, { - [TEST_ADDRESS]: { address: TEST_ADDRESS, name: DEFAULT_LABEL }, + testAccount.metadata.lastSelected >= startTime && + testAccount.metadata.lastSelected <= endTime, + `'${testAccount.metadata.lastSelected}' expected to be between '${startTime}' and '${endTime}'`, + ); + + delete testAccount.metadata.lastSelected; + + assert.deepEqual(testAccount, { + id: 'e26b5b50-739e-4d6a-a9d1-a9163f480a52', + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + metadata: { + keyring: { type: 'HD Key Tree' }, + }, + name: DEFAULT_LABEL, }); - await metamaskController.preferencesController.setAccountLabel( - TEST_ADDRESS, - 'Account Foo', - ); + metamaskController.setAccountName(testAccount.id, 'Account Foo'); + + const labeledVaultAccounts = + metamaskController.getState().internalAccounts; - const labelledFirstVaultIdentities = cloneDeep( - metamaskController.getState().identities, + const labeledAccount = cloneDeep( + Object.values(labeledVaultAccounts.accounts).find( + (account) => account.address === TEST_ADDRESS, + ), ); - delete labelledFirstVaultIdentities[TEST_ADDRESS].lastSelected; - assert.deepEqual(labelledFirstVaultIdentities, { - [TEST_ADDRESS]: { address: TEST_ADDRESS, name: 'Account Foo' }, + + delete labeledAccount.metadata.lastSelected; + + assert.deepEqual(labeledAccount, { + id: 'e26b5b50-739e-4d6a-a9d1-a9163f480a52', + address: TEST_ADDRESS, + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + metadata: { + keyring: { type: 'HD Key Tree' }, + }, + name: 'Account Foo', }); startTime = Date.now(); @@ -469,20 +525,43 @@ describe('MetaMaskController', function () { ); endTime = Date.now(); - const secondVaultIdentities = cloneDeep( - metamaskController.getState().identities, + const secondVaultAccounts = + metamaskController.getState().internalAccounts; + + const secondTestAccount = cloneDeep( + Object.values(secondVaultAccounts.accounts).find( + (account) => account.address === TEST_ADDRESS_ALT, + ), ); + assert.ok( - secondVaultIdentities[TEST_ADDRESS_ALT].lastSelected >= startTime && - secondVaultIdentities[TEST_ADDRESS_ALT].lastSelected <= endTime, - `'${secondVaultIdentities[TEST_ADDRESS_ALT].lastSelected}' expected to be between '${startTime}' and '${endTime}'`, - ); - delete secondVaultIdentities[TEST_ADDRESS_ALT].lastSelected; - assert.deepEqual(secondVaultIdentities, { - [TEST_ADDRESS_ALT]: { - address: TEST_ADDRESS_ALT, - name: DEFAULT_LABEL, + secondTestAccount.metadata.lastSelected >= startTime && + secondTestAccount.metadata.lastSelected <= endTime, + `'${secondTestAccount.metadata.lastSelected}' expected to be between '${startTime}' and '${endTime}'`, + ); + + delete secondTestAccount.metadata.lastSelected; + + assert.deepEqual(secondTestAccount, { + id: 'f73954ab-4605-459c-b0ff-23978b190709', + address: TEST_ADDRESS_ALT, + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + metadata: { + keyring: { type: 'HD Key Tree' }, }, + name: DEFAULT_LABEL, }); }); @@ -504,14 +583,42 @@ describe('MetaMaskController', function () { TEST_SEED, ); - const identities = cloneDeep(metamaskController.getState().identities); - assert.ok( - identities[TEST_ADDRESS].lastSelected >= startTime && - identities[TEST_ADDRESS].lastSelected <= Date.now(), + const restoredVaultAccounts = + metamaskController.getState().internalAccounts; + + const testAccount = cloneDeep( + Object.values(restoredVaultAccounts.accounts).find( + (account) => account.address === TEST_ADDRESS, + ), ); - delete identities[TEST_ADDRESS].lastSelected; - assert.deepEqual(identities, { - [TEST_ADDRESS]: { address: TEST_ADDRESS, name: DEFAULT_LABEL }, + + assert.ok( + testAccount.metadata.lastSelected >= startTime && + testAccount.metadata.lastSelected <= Date.now(), + ); + + delete testAccount.metadata.lastSelected; + + assert.deepEqual(testAccount, { + id: 'e26b5b50-739e-4d6a-a9d1-a9163f480a52', + address: TEST_ADDRESS, + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + metadata: { + keyring: { type: 'HD Key Tree' }, + }, + name: DEFAULT_LABEL, }); }); }); @@ -556,36 +663,33 @@ describe('MetaMaskController', function () { }); }); - describe('#selectFirstIdentity', function () { - let identities, address; - - beforeEach(function () { - address = '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'; - identities = { - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { - address, - name: 'Account 1', - }, - '0xc42edfcc21ed14dda456aa0756c153f7985d8813': { - address: '0xc42edfcc21ed14dda456aa0756c153f7985d8813', - name: 'Account 2', - }, - }; - metamaskController.preferencesController.store.updateState({ - identities, - }); - metamaskController.selectFirstIdentity(); + describe('#selectFirstAccount', function () { + const expectedId = uuid({ + random: sha256FromString(TEST_ADDRESS).slice(0, 16), }); - it('changes preferences controller select address', function () { - const preferenceControllerState = - metamaskController.preferencesController.store.getState(); - assert.equal(preferenceControllerState.selectedAddress, address); + beforeEach(async function () { + await metamaskController.createNewVaultAndRestore( + 'password', + TEST_SEED, + ); + metamaskController.addNewAccount(1); + metamaskController.addNewAccount(2); + + metamaskController.selectFirstAccount(); + }); + it('changes accounts controller select account', function () { + const selectedAccount = + metamaskController.accountsController.getSelectedAccount(); + assert.equal(selectedAccount.id, expectedId); }); - it('changes metamask controller selected address', function () { + it('changes metamask controller selected account', function () { const metamaskState = metamaskController.getState(); - assert.equal(metamaskState.selectedAddress, address); + assert.equal( + metamaskState.internalAccounts.selectedAccount, + expectedId, + ); }); }); @@ -891,15 +995,22 @@ describe('MetaMaskController', function () { describe('#removeAccount', function () { let ret; - const addressToRemove = '0x1'; let mockKeyring; + const accountIdToBeRemoved = 'mock-id'; + const accountAddressTobeRemoved = '0x1'; beforeEach(async function () { mockKeyring = { getAccounts: sinon.stub().returns(Promise.resolve([])), destroy: sinon.stub(), }; - sinon.stub(metamaskController.preferencesController, 'removeAddress'); + + sinon + .stub(metamaskController.accountsController, 'getAccountExpect') + .returns({ + id: accountIdToBeRemoved, + address: accountAddressTobeRemoved, + }); sinon.stub(metamaskController.accountTracker, 'removeAccount'); sinon.stub(metamaskController.keyringController, 'removeAccount'); sinon.stub(metamaskController, 'removeAllAccountPermissions'); @@ -910,44 +1021,44 @@ describe('MetaMaskController', function () { ) .returns(Promise.resolve(mockKeyring)); - ret = await metamaskController.removeAccount(addressToRemove); + ret = await metamaskController.removeAccount(accountIdToBeRemoved); }); afterEach(function () { metamaskController.keyringController.removeAccount.restore(); metamaskController.accountTracker.removeAccount.restore(); - metamaskController.preferencesController.removeAddress.restore(); metamaskController.removeAllAccountPermissions.restore(); + metamaskController.accountsController.getAccountExpect.restore(); mockKeyring.getAccounts.resetHistory(); mockKeyring.destroy.resetHistory(); }); - it('should call preferencesController.removeAddress', async function () { + it('should call accountsController.getAccountExpect', async function () { assert( - metamaskController.preferencesController.removeAddress.calledWith( - addressToRemove, + metamaskController.accountsController.getAccountExpect.calledWith( + accountIdToBeRemoved, ), ); }); it('should call accountTracker.removeAccount', async function () { assert( metamaskController.accountTracker.removeAccount.calledWith([ - addressToRemove, + accountAddressTobeRemoved, ]), ); }); it('should call keyringController.removeAccount', async function () { assert( metamaskController.keyringController.removeAccount.calledWith( - addressToRemove, + accountAddressTobeRemoved, ), ); }); it('should call metamaskController.removeAllAccountPermissions', async function () { assert( metamaskController.removeAllAccountPermissions.calledWith( - addressToRemove, + accountAddressTobeRemoved, ), ); }); @@ -957,7 +1068,7 @@ describe('MetaMaskController', function () { it('should call coreKeyringController.getKeyringForAccount', async function () { assert( metamaskController.coreKeyringController.getKeyringForAccount.calledWith( - addressToRemove, + accountAddressTobeRemoved, ), ); }); @@ -1145,11 +1256,7 @@ describe('MetaMaskController', function () { }); it('should sync addresses if there are keyrings in state', async function () { - const syncAddresses = sinon.fake(); const syncWithAddresses = sinon.fake(); - sandbox.replace(metamaskController, 'preferencesController', { - syncAddresses, - }); sandbox.replace(metamaskController, 'accountTracker', { syncWithAddresses, }); @@ -1163,17 +1270,12 @@ describe('MetaMaskController', function () { ], }); - assert.deepEqual(syncAddresses.args, [[['0x1', '0x2']]]); assert.deepEqual(syncWithAddresses.args, [[['0x1', '0x2']]]); assert.deepEqual(metamaskController.getState(), oldState); }); it('should NOT update selected address if already unlocked', async function () { - const syncAddresses = sinon.fake(); const syncWithAddresses = sinon.fake(); - sandbox.replace(metamaskController, 'preferencesController', { - syncAddresses, - }); sandbox.replace(metamaskController, 'accountTracker', { syncWithAddresses, }); @@ -1188,7 +1290,6 @@ describe('MetaMaskController', function () { ], }); - assert.deepEqual(syncAddresses.args, [[['0x1', '0x2']]]); assert.deepEqual(syncWithAddresses.args, [[['0x1', '0x2']]]); assert.deepEqual(metamaskController.getState(), oldState); }); From b7b6d9bfe6fc735d53c4c984b926b59ccbd859df Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Tue, 8 Aug 2023 14:30:32 +0800 Subject: [PATCH 032/235] fix: send-asset-row story --- .../send-content/send-asset-row/send-asset-row.stories.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/pages/send/send-content/send-asset-row/send-asset-row.stories.js b/ui/pages/send/send-content/send-asset-row/send-asset-row.stories.js index 7c1edd022f7a..e5962a3ac113 100644 --- a/ui/pages/send/send-content/send-asset-row/send-asset-row.stories.js +++ b/ui/pages/send/send-content/send-asset-row/send-asset-row.stories.js @@ -20,11 +20,13 @@ export const DefaultStory = () => { const { internalAccounts, assetImages, tokens } = metamask; const accounts = Object.values(internalAccounts.accounts); + const selectedAccount = + internalAccounts.accounts[internalAccounts.selectedAccount]; return ( undefined} From a919a0bae570961604a9f1a5a98eb45c22fee8d4 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Tue, 8 Aug 2023 19:24:54 +0800 Subject: [PATCH 033/235] fix: add account --- app/scripts/metamask-controller.js | 9 +++- .../new-account-modal.container.js | 2 +- ui/store/actions.test.js | 46 ++++++++++++++++++- ui/store/actions.ts | 14 ++++-- 4 files changed, 63 insertions(+), 8 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index e4eafd50b580..420687420fcc 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -3433,9 +3433,10 @@ export default class MetamaskController extends EventEmitter { * Adds a new account to the default (first) HD seed phrase Keyring. * * @param accountCount + * @param accountName * @returns {} keyState */ - async addNewAccount(accountCount) { + async addNewAccount(accountCount, accountName) { const isActionMetricsQueueE2ETest = this.appStateController.store.getState()[ACTION_QUEUE_METRICS_E2E_TEST]; @@ -3458,6 +3459,12 @@ export default class MetamaskController extends EventEmitter { if (numberOfHdKeyringAccounts === accountCount) { const keyState = await keyringController.addNewAccount(primaryKeyring); await this.accountsController.updateAccounts(); + if (accountName) { + this.accountsController.setAccountName( + this.accountsController.getSelectedAccount().id, + accountName, + ); + } const updatedAccounts = this.accountsController.listAccounts(); return { ...keyState, diff --git a/ui/components/app/modals/new-account-modal/new-account-modal.container.js b/ui/components/app/modals/new-account-modal/new-account-modal.container.js index a97331f0501c..8756309ec3ac 100644 --- a/ui/components/app/modals/new-account-modal/new-account-modal.container.js +++ b/ui/components/app/modals/new-account-modal/new-account-modal.container.js @@ -12,7 +12,7 @@ function mapDispatchToProps(dispatch) { return { hideModal: () => dispatch(actions.hideModal()), createAccount: (newAccountName) => { - return dispatch(actions.addNewAccount()).then((account) => { + return dispatch(actions.addNewAccount(newAccountName)).then((account) => { if (newAccountName) { dispatch(actions.setAccountLabel(account.id, newAccountName)); } diff --git a/ui/store/actions.test.js b/ui/store/actions.test.js index d75fb5514632..bb67b03f9a48 100644 --- a/ui/store/actions.test.js +++ b/ui/store/actions.test.js @@ -458,7 +458,7 @@ describe('Actions', () => { _setBackgroundConnection(background); - await store.dispatch(actions.addNewAccount(1)); + await store.dispatch(actions.addNewAccount()); expect(addNewAccount.callCount).toStrictEqual(1); }); @@ -530,6 +530,50 @@ describe('Actions', () => { expect(store.getActions()).toStrictEqual(expectedActions); }); + + it('adds a new account and sets the name', async () => { + const store = mockStore({ + metamask: { + internalAccounts: { accounts: {}, selectedAccount: '' }, + ...defaultState.metamask, + }, + }); + + const addNewAccount = background.addNewAccount.callsFake((_, cb) => + cb(null, { + accounts: [ + { + address: '0xNewAddress', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb5', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'new name', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + ], + }), + ); + + _setBackgroundConnection(background); + + await store.dispatch(actions.addNewAccount('new name')); + expect(addNewAccount.callCount).toStrictEqual(1); + }); }); describe('#checkHardwareStatus', () => { diff --git a/ui/store/actions.ts b/ui/store/actions.ts index cccb93de5348..698a027a6709 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -424,22 +424,26 @@ export function importNewAccount( } export function addNewAccount( - accountCount: string, + accountName: string, ): ThunkAction { log.debug(`background.addNewAccount`); return async (dispatch, getState) => { const oldAccounts = getState().metamask.internalAccounts.accounts; - // const oldHdAccounts = Object.values(oldAccounts).filter( - // (account) => account.metadata.keyring.type === 'HD Key Tree', - // ); + const oldHdAccounts = Object.values(oldAccounts).filter( + (account) => account.metadata.keyring.type === 'HD Key Tree', + ); dispatch(showLoadingIndication()); try { const { accounts } = await submitRequestToBackground('addNewAccount', [ - accountCount, + oldHdAccounts.length, ]); const newAccount = accounts.find((account) => !oldAccounts[account.id]); + + if (accountName) { + dispatch(setAccountLabel(newAccount.id, accountName)); + } return newAccount; } catch (error) { dispatch(displayWarning(error)); From a4fc4776d88df0b2f791a61825bb72b25fc5f332 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Tue, 8 Aug 2023 19:25:05 +0800 Subject: [PATCH 034/235] fix: snapshot --- .../__snapshots__/confirm-send-ether.test.js.snap | 2 +- ...ding-swaps-quotes-stories-metadata.test.js.snap | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ui/pages/confirm-send-ether/__snapshots__/confirm-send-ether.test.js.snap b/ui/pages/confirm-send-ether/__snapshots__/confirm-send-ether.test.js.snap index 24204d0947dc..c889ab29635e 100644 --- a/ui/pages/confirm-send-ether/__snapshots__/confirm-send-ether.test.js.snap +++ b/ui/pages/confirm-send-ether/__snapshots__/confirm-send-ether.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`ConfirmSendEther should render correct information for for confirm send ether 1`] = ` -Array [ +[
Date: Tue, 8 Aug 2023 21:05:39 +0800 Subject: [PATCH 035/235] fix: update actions --- ui/store/actions.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ui/store/actions.ts b/ui/store/actions.ts index 777303f86f36..a48ea6e5ae16 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -435,23 +435,23 @@ export function addNewAccount( dispatch(showLoadingIndication()); + let newAccount; try { const { accounts } = await submitRequestToBackground('addNewAccount', [ oldHdAccounts.length, ]); - const newAccount = accounts.find((account) => !oldAccounts[account.id]); - - if (accountName) { - dispatch(setAccountLabel(newAccount.id, accountName)); - } - return newAccount; + newAccount = accounts.find((account) => !oldAccounts[account.id]); } catch (error) { dispatch(displayWarning(error)); throw error; } finally { dispatch(hideLoadingIndication()); - await forceUpdateMetamaskState(dispatch); } + await forceUpdateMetamaskState(dispatch); + if (accountName) { + dispatch(setAccountLabel(newAccount.id, accountName)); + } + return newAccount; }; } From 38c12eb74fed123eb217cc376514690bd5e0c73b Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Tue, 8 Aug 2023 21:26:27 +0800 Subject: [PATCH 036/235] fix: update permission to use accounts --- ui/pages/permissions-connect/permissions-connect.component.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/pages/permissions-connect/permissions-connect.component.js b/ui/pages/permissions-connect/permissions-connect.component.js index 4820bc1ab55a..f70899179e08 100644 --- a/ui/pages/permissions-connect/permissions-connect.component.js +++ b/ui/pages/permissions-connect/permissions-connect.component.js @@ -410,7 +410,7 @@ export default class PermissionConnect extends Component { rejectPermissionsRequest={(requestId) => this.cancelPermissionsRequest(requestId) } - selectedIdentities={accounts.filter((account) => + selectedAccounts={accounts.filter((account) => selectedAccountAddresses.has(account.address), )} targetSubjectMetadata={targetSubjectMetadata} From 2d353bc9586ff7f404f13f886ac96d5bce64acf0 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Tue, 8 Aug 2023 21:50:41 +0800 Subject: [PATCH 037/235] fix: actions tests --- ui/store/actions.test.js | 47 ---------------------------------------- ui/store/actions.ts | 16 ++++++++++---- 2 files changed, 12 insertions(+), 51 deletions(-) diff --git a/ui/store/actions.test.js b/ui/store/actions.test.js index d4ee4e288fbf..e8c5a1045331 100644 --- a/ui/store/actions.test.js +++ b/ui/store/actions.test.js @@ -475,53 +475,6 @@ describe('Actions', () => { { type: 'SHOW_LOADING_INDICATION', payload: undefined }, { type: 'DISPLAY_WARNING', payload: 'error' }, { type: 'HIDE_LOADING_INDICATION' }, - { - type: 'UPDATE_METAMASK_STATE', - value: { - accounts: { - '0xFirstAddress': { - balance: '0x0', - }, - }, - cachedBalances: { - '0x1': { - '0xFirstAddress': '0x0', - }, - }, - currentLocale: 'test', - internalAccounts: { - accounts: { - 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { - address: '0xFirstAddress', - id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', - metadata: { - keyring: { - type: 'HD Key Tree', - }, - }, - name: 'Test Account', - options: {}, - supportedMethods: [ - 'personal_sign', - 'eth_sendTransaction', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v2', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', - }, - }, - selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', - }, - providerConfig: { - chainId: '0x1', - }, - }, - }, ]; await expect(store.dispatch(actions.addNewAccount(1))).rejects.toThrow( diff --git a/ui/store/actions.ts b/ui/store/actions.ts index a48ea6e5ae16..52ab2694fcdc 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -114,6 +114,7 @@ import { MetaMaskReduxState, TemporaryMessageDataType, } from './store'; +import { InternalAccount } from '@metamask/eth-snap-keyring'; export function goHome() { return { @@ -437,9 +438,10 @@ export function addNewAccount( let newAccount; try { - const { accounts } = await submitRequestToBackground('addNewAccount', [ - oldHdAccounts.length, - ]); + const { accounts }: { accounts: InternalAccount[] } = + await submitRequestToBackground('addNewAccount', [ + oldHdAccounts.length, + ]); newAccount = accounts.find((account) => !oldAccounts[account.id]); } catch (error) { dispatch(displayWarning(error)); @@ -448,7 +450,7 @@ export function addNewAccount( dispatch(hideLoadingIndication()); } await forceUpdateMetamaskState(dispatch); - if (accountName) { + if (accountName && newAccount) { dispatch(setAccountLabel(newAccount.id, accountName)); } return newAccount; @@ -2935,6 +2937,12 @@ export function setParticipateInMetaMetrics( reject(err); return; } + /** + * We need to inform sentry that the user's optin preference may have + * changed. The logic to determine which way to toggle is in the + * toggleSession handler in setupSentry.js. + */ + window.sentry?.toggleSession(); dispatch({ type: actionConstants.SET_PARTICIPATE_IN_METAMETRICS, From e8cc01a99f18f68775eb428f5b74f55e8adcff6f Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Mon, 21 Aug 2023 19:55:50 +0800 Subject: [PATCH 038/235] fix: merge usage of identities --- .../import-tokens-modal/import-tokens-modal.js | 14 ++++++++------ ui/selectors/selectors.js | 4 ++-- ui/store/actions.ts | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/ui/components/multichain/import-tokens-modal/import-tokens-modal.js b/ui/components/multichain/import-tokens-modal/import-tokens-modal.js index 2e8ef6b10d87..78590344ed42 100644 --- a/ui/components/multichain/import-tokens-modal/import-tokens-modal.js +++ b/ui/components/multichain/import-tokens-modal/import-tokens-modal.js @@ -13,14 +13,14 @@ import { Tab, Tabs } from '../../ui/tabs'; import { useI18nContext } from '../../../hooks/useI18nContext'; import { getCurrentChainId, + getInternalAccounts, getIsDynamicTokenListAvailable, getIsMainnet, getIsTokenDetectionInactiveOnMainnet, getIsTokenDetectionSupported, getIstokenDetectionInactiveOnNonMainnetSupportedNetwork, - getMetaMaskIdentities, getRpcPrefsForCurrentProvider, - getSelectedAddress, + getSelectedAccount, getTokenDetectionSupportNetworkByChainId, getTokenList, } from '../../../selectors'; @@ -111,9 +111,9 @@ export const ImportTokensModal = ({ onClose }) => { const isDynamicTokenListAvailable = useSelector( getIsDynamicTokenListAvailable, ); - const selectedAddress = useSelector(getSelectedAddress); + const selectedAccount = useSelector(getSelectedAccount); const isMainnet = useSelector(getIsMainnet); - const identities = useSelector(getMetaMaskIdentities); + const accounts = useSelector(getInternalAccounts); const tokens = useSelector((state) => state.metamask.tokens); const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider); @@ -337,7 +337,7 @@ export const ImportTokensModal = ({ onClose }) => { try { ({ standard } = await getTokenStandardAndDetails( standardAddress, - selectedAddress, + selectedAccount.address, null, )); } catch (error) { @@ -383,7 +383,9 @@ export const ImportTokensModal = ({ onClose }) => { setCustomDecimalsError(null); break; - case Boolean(identities[standardAddress]): + case Boolean( + accounts.find((internalAccount) => internalAccount.address === address), + ): setCustomAddressError(t('personalAddressDetected')); break; diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 65761f1f4fa4..0569753dd4e2 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -333,11 +333,11 @@ export function getSelectedInternalAccount(state) { export function getSelectedInternalAccountWithBalance(state) { const selectedAccount = getSelectedInternalAccount(state); - const { balance } = getMetaMaskAccountsRaw(state)[selectedAccount.address]; + const rawAccount = getMetaMaskAccountsRaw(state)[selectedAccount.address]; const selectedAccountWithBalance = { ...selectedAccount, - balance, + balance: rawAccount ? rawAccount.balance : 0, }; return selectedAccountWithBalance; diff --git a/ui/store/actions.ts b/ui/store/actions.ts index c5acec43fd82..d73f312ee4fe 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -22,6 +22,7 @@ import { NonEmptyArray } from '@metamask/controller-utils'; ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) import { HandlerType } from '@metamask/snaps-utils'; ///: END:ONLY_INCLUDE_IN +import { InternalAccount } from '@metamask/eth-snap-keyring'; import { getMethodDataAsync } from '../helpers/utils/transactions.util'; import switchDirection from '../../shared/lib/switch-direction'; import { @@ -114,7 +115,6 @@ import { MetaMaskReduxState, TemporaryMessageDataType, } from './store'; -import { InternalAccount } from '@metamask/eth-snap-keyring'; export function goHome() { return { From 9d087d695366fcad22459760af60706aa0591f2f Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Mon, 21 Aug 2023 19:56:09 +0800 Subject: [PATCH 039/235] fix: import flow e2e --- test/e2e/fixture-builder.js | 95 ++++++++++++++++++++++++------ test/e2e/tests/import-flow.spec.js | 8 +-- 2 files changed, 81 insertions(+), 22 deletions(-) diff --git a/test/e2e/fixture-builder.js b/test/e2e/fixture-builder.js index 12de298bd888..340184535844 100644 --- a/test/e2e/fixture-builder.js +++ b/test/e2e/fixture-builder.js @@ -693,29 +693,88 @@ class FixtureBuilder { return this; } - withPreferencesController(data) { - merge(this.fixture.data.PreferencesController, data); + withAccountsController(data) { + merge(this.fixture.data.AccountsController, data); return this; } - withPreferencesControllerImportedAccountIdentities() { - return this.withPreferencesController({ - identities: { - '0x0cc5261ab8ce458dc977078a3623e2badd27afd3': { - name: 'Account 1', - address: '0x0cc5261ab8ce458dc977078a3623e2badd27afd3', - lastSelected: 1665507600000, - }, - '0x3ed0ee22e0685ebbf07b2360a8331693c413cc59': { - name: 'Account 2', - address: '0x3ed0ee22e0685ebbf07b2360a8331693c413cc59', - }, - '0xd38d853771fb546bd8b18b2f3638491bc0b0e906': { - name: 'Account 3', - address: '0xd38d853771fb546bd8b18b2f3638491bc0b0e906', + withAccountsControllerImportedAccount() { + return this.withAccountsController({ + internalAccounts: { + selectedAccount: '2fdb2de6-80c7-4d2f-9f95-cb6895389843', + accounts: { + '2fdb2de6-80c7-4d2f-9f95-cb6895389843': { + name: 'Account 1', + id: '2fdb2de6-80c7-4d2f-9f95-cb6895389843', + address: '0x0cc5261ab8ce458dc977078a3623e2badd27afd3', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + metadata: { + lastSelected: 1665507600000, + keyring: { + type: 'HD Key Tree', + }, + }, + }, + '58093703-57e9-4ea9-8545-49e8a75cb084': { + name: 'Account 2', + id: '58093703-57e9-4ea9-8545-49e8a75cb084', + address: '0x3ed0ee22e0685ebbf07b2360a8331693c413cc59', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + }, + 'dd658aab-abf2-4f53-b735-c8a57151d447': { + name: 'Account 3', + id: 'dd658aab-abf2-4f53-b735-c8a57151d447', + address: '0xd38d853771fb546bd8b18b2f3638491bc0b0e906', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + }, }, }, - selectedAddress: '0x0cc5261ab8ce458dc977078a3623e2badd27afd3', }); } diff --git a/test/e2e/tests/import-flow.spec.js b/test/e2e/tests/import-flow.spec.js index 3991350a6407..e94946e311a2 100644 --- a/test/e2e/tests/import-flow.spec.js +++ b/test/e2e/tests/import-flow.spec.js @@ -185,7 +185,7 @@ describe('Import flow', function () { { fixtures: new FixtureBuilder() .withKeyringControllerImportedAccountVault() - .withPreferencesControllerImportedAccountIdentities() + .withAccountsControllerImportedAccount() .build(), ganacheOptions, title: this.test.title, @@ -249,7 +249,7 @@ describe('Import flow', function () { await driver.clickElement({ text: 'Remove', tag: 'button' }); await driver.findElement({ css: '[data-testid="account-menu-icon"]', - text: 'Account 1', + text: 'Account 4', }); await driver.clickElement('[data-testid="account-menu-icon"]'); const accountListItemsAfterRemoval = await driver.findElements( @@ -265,7 +265,7 @@ describe('Import flow', function () { { fixtures: new FixtureBuilder() .withKeyringControllerImportedAccountVault() - .withPreferencesControllerImportedAccountIdentities() + .withAccountsControllerImportedAccount() .build(), ganacheOptions, title: this.test.title, @@ -328,7 +328,7 @@ describe('Import flow', function () { { fixtures: new FixtureBuilder() .withKeyringControllerImportedAccountVault() - .withPreferencesControllerImportedAccountIdentities() + .withAccountsControllerImportedAccount() .build(), ganacheOptions, title: this.test.title, From 9d60f902d26c71a341403c257c8052e0b1f09dc3 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Mon, 21 Aug 2023 20:01:56 +0800 Subject: [PATCH 040/235] fix: lavamoat policy --- lavamoat/browserify/desktop/policy.json | 3 +- lavamoat/browserify/flask/policy.json | 3 +- lavamoat/build-system/policy.json | 132 ++++++++++++++++++++++-- 3 files changed, 126 insertions(+), 12 deletions(-) diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index 56edb5e326bd..599a5c34b92c 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -1196,8 +1196,7 @@ }, "@metamask/eth-snap-keyring": { "globals": { - "console.error": true, - "console.warn": true + "console.error": true }, "packages": { "@ethereumjs/tx": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index d56789b6a158..4dd2b27a1870 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -1196,8 +1196,7 @@ }, "@metamask/eth-snap-keyring": { "globals": { - "console.error": true, - "console.warn": true + "console.error": true }, "packages": { "@ethereumjs/tx": true, diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json index 4ab9521cfbeb..96fef5e24515 100644 --- a/lavamoat/build-system/policy.json +++ b/lavamoat/build-system/policy.json @@ -1134,6 +1134,21 @@ "string.prototype.matchall>side-channel": true } }, + "@storybook/addon-mdx-gfm>@storybook/node-logger>npmlog>gauge>has-unicode": { + "builtin": { + "os.type": true + }, + "globals": { + "process.env.LANG": true, + "process.env.LC_ALL": true, + "process.env.LC_CTYPE": true + } + }, + "@storybook/addon-mdx-gfm>@storybook/node-logger>npmlog>gauge>wide-align": { + "packages": { + "yargs>string-width": true + } + }, "@storybook/core>@storybook/core-server>x-default-browser>default-browser-id>untildify>os-homedir": { "builtin": { "os.homedir": true @@ -4999,6 +5014,7 @@ "@lavamoat/allow-scripts>@npmcli/run-script>node-gyp>npmlog": true, "gulp-watch>chokidar>fsevents>node-pre-gyp>detect-libc": true, "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog": true, "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf": true, "gulp-watch>chokidar>fsevents>node-pre-gyp>semver": true } @@ -5056,9 +5072,20 @@ }, "packages": { "@storybook/core>@storybook/core-server>x-default-browser>default-browser-id>untildify>os-homedir": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-homedir": true, "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-tmpdir": true } }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-homedir": { + "builtin": { + "os.homedir": true + }, + "globals": { + "process.env": true, + "process.getuid": true, + "process.platform": true + } + }, "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-tmpdir": { "globals": { "process.env.SystemRoot": true, @@ -5069,6 +5096,70 @@ "process.platform": true } }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog": { + "builtin": { + "events.EventEmitter": true, + "util": true + }, + "globals": { + "process.nextTick": true, + "process.stderr": true + }, + "packages": { + "@storybook/addon-mdx-gfm>@storybook/node-logger>npmlog>console-control-strings": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge": true, + "nyc>yargs>set-blocking": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet": { + "builtin": { + "events.EventEmitter": true, + "util.inherits": true + }, + "packages": { + "koa>delegates": true, + "readable-stream": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge": { + "builtin": { + "util.format": true + }, + "globals": { + "clearInterval": true, + "process": true, + "setImmediate": true, + "setInterval": true + }, + "packages": { + "@storybook/addon-mdx-gfm>@storybook/node-logger>npmlog>console-control-strings": true, + "@storybook/addon-mdx-gfm>@storybook/node-logger>npmlog>gauge>has-unicode": true, + "@storybook/addon-mdx-gfm>@storybook/node-logger>npmlog>gauge>wide-align": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>aproba": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi": true, + "nyc>signal-exit": true, + "react>object-assign": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width": { + "packages": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width>is-fullwidth-code-point": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi": true, + "gulp>gulp-cli>yargs>string-width>code-point-at": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width>is-fullwidth-code-point": { + "packages": { + "gulp>gulp-cli>yargs>string-width>is-fullwidth-code-point>number-is-nan": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi": { + "packages": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi>ansi-regex": true + } + }, "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf": { "builtin": { "assert": true, @@ -5080,9 +5171,34 @@ "setTimeout": true }, "packages": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob": true, "nyc>glob": true } }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob": { + "builtin": { + "assert": true, + "events.EventEmitter": true, + "fs": true, + "path.join": true, + "path.resolve": true, + "util": true + }, + "globals": { + "console.error": true, + "process.cwd": true, + "process.nextTick": true, + "process.platform": true + }, + "packages": { + "eslint>minimatch": true, + "gulp-watch>path-is-absolute": true, + "nyc>glob>fs.realpath": true, + "nyc>glob>inflight": true, + "pump>once": true, + "pumpify>inherits": true + } + }, "gulp-watch>chokidar>fsevents>node-pre-gyp>semver": { "globals": { "console": true, @@ -6530,6 +6646,13 @@ "process.platform": true } }, + "mockttp>portfinder>mkdirp": { + "builtin": { + "fs": true, + "path.dirname": true, + "path.resolve": true + } + }, "nock>debug": { "builtin": { "tty.isatty": true, @@ -8137,14 +8260,7 @@ "path.dirname": true }, "packages": { - "stylelint>file-entry-cache>flat-cache>write>mkdirp": true - } - }, - "stylelint>file-entry-cache>flat-cache>write>mkdirp": { - "builtin": { - "fs": true, - "path.dirname": true, - "path.resolve": true + "mockttp>portfinder>mkdirp": true } }, "stylelint>global-modules": { From 501463ef35a47ac06c9643ae4b5c7c649b79b14b Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Wed, 23 Aug 2023 00:31:42 +0800 Subject: [PATCH 041/235] fix: update snapshot and default state in fixtures --- .../controllers/accounts-controller.ts | 25 ++++--------- test/e2e/fixture-builder.js | 36 +++++++++++++++++++ ...rs-after-init-opt-in-background-state.json | 1 + .../errors-after-init-opt-in-ui-state.json | 3 +- ...s-before-init-opt-in-background-state.json | 1 + .../errors-before-init-opt-in-ui-state.json | 1 + 6 files changed, 47 insertions(+), 20 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index c7dec9b8f997..585fd116d254 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -20,6 +20,7 @@ import { import { KeyringControllerState, KeyringController, + KeyringControllerEvents, } from '@metamask/keyring-controller'; ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) import { SnapControllerState } from '@metamask/snaps-controllers-flask'; @@ -49,7 +50,8 @@ export type AccountsControllerChangeEvent = { export type AccountsControllerEvents = | AccountsControllerChangeEvent - | SnapControllerEvents; + | SnapControllerEvents + | KeyringControllerEvents; export type AccountsControllerMessenger = RestrictedControllerMessenger< typeof controllerName, @@ -136,8 +138,6 @@ export default class AccountsController extends BaseControllerV2< ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) onSnapStateChange(async (snapState: SnapControllerState) => { - console.log('snap state changed', snapState); - // only check if snaps changed in status const { snaps } = snapState; const accounts = this.listAccounts(); @@ -155,14 +155,10 @@ export default class AccountsController extends BaseControllerV2< } }); }); - - console.log('updated state after snap changes', this.state); }); ///: END:ONLY_INCLUDE_IN(keyring-snaps) onKeyringStateChange(async (keyringState: KeyringControllerState) => { - // console.log('keyring state changed', keyringState); - // check if there are any new accounts added // TODO: change when accountAdded event is added to the keyring controller @@ -215,11 +211,6 @@ export default class AccountsController extends BaseControllerV2< ); })[0]; - console.log( - 'removed selected account and now setting previous', - previousAccount, - ); - this.setSelectedAccount(previousAccount.id); } } @@ -307,8 +298,6 @@ export default class AccountsController extends BaseControllerV2< this.update((currentState: AccountsControllerState) => { currentState.internalAccounts.accounts = accounts; }); - - console.log('updated state', this.state); } ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) @@ -384,8 +373,6 @@ export default class AccountsController extends BaseControllerV2< setSelectedAccount(accountId: string): void { const account = this.getAccountExpect(accountId); - console.log('set selected account', account); - this.update((currentState: AccountsControllerState) => { currentState.internalAccounts.accounts[account.id].metadata.lastSelected = Date.now(); @@ -398,7 +385,9 @@ export default class AccountsController extends BaseControllerV2< if ( this.listAccounts().find( - (internalAccount) => internalAccount.name === accountName, + (internalAccount) => + internalAccount.name === accountName && + internalAccount.id !== accountId, ) ) { throw new Error('Account name already exists'); @@ -410,8 +399,6 @@ export default class AccountsController extends BaseControllerV2< name: accountName, }; }); - - console.log('state after set account name', this.state); } ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) diff --git a/test/e2e/fixture-builder.js b/test/e2e/fixture-builder.js index 340184535844..b7e2000b4e90 100644 --- a/test/e2e/fixture-builder.js +++ b/test/e2e/fixture-builder.js @@ -15,6 +15,37 @@ const { DAPP_URL } = require('./helpers'); function defaultFixture() { return { data: { + AccountsController: { + internalAccounts: { + selectedAccount: 'd5e45e4a-3b04-4a09-a5e1-39762e5c6be4', + accounts: { + 'd5e45e4a-3b04-4a09-a5e1-39762e5c6be4': { + id: 'd5e45e4a-3b04-4a09-a5e1-39762e5c6be4', + address: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', + name: 'Account 1', + metadata: { + lastSelected: 1665507600000, + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + }, + }, AlertController: { alertEnabledness: { unconnectedAccount: true, @@ -693,6 +724,11 @@ class FixtureBuilder { return this; } + withPreferencesController(data) { + merge(this.fixture.data.PreferencesController, data); + return this; + } + withAccountsController(data) { merge(this.fixture.data.AccountsController, data); return this; diff --git a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json index 583be202045a..4f15dfa0ff30 100644 --- a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json +++ b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json @@ -1,5 +1,6 @@ { "AccountTracker": { "accounts": "object" }, + "AccountsController": "object", "AddressBookController": "object", "AlertController": { "alertEnabledness": { "unconnectedAccount": true, "web3ShimUsage": true }, diff --git a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json index 24f10128fa91..7e04bb3fcde6 100644 --- a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json +++ b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json @@ -12,7 +12,7 @@ "isUnlocked": false, "isAccountMenuOpen": false, "isNetworkMenuOpen": "boolean", - "identities": "object", + "internalAccounts": "object", "unapprovedTxs": "object", "networkConfigurations": "object", "addressBook": "object", @@ -86,6 +86,7 @@ "useCurrencyRateCheck": "boolean", "openSeaEnabled": "boolean", "advancedGasFee": "object", + "identities": "object", "lostIdentities": "object", "forgottenPassword": false, "ipfsGateway": "dweb.link", diff --git a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json b/test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json index 422bcb0e297f..6e6466f87f5e 100644 --- a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json +++ b/test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json @@ -1,5 +1,6 @@ { "data": { + "AccountsController": "object", "AlertController": { "alertEnabledness": { "unconnectedAccount": true, "web3ShimUsage": true }, "unconnectedAccountAlertShownOrigins": "object", diff --git a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json b/test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json index 0a9fac1d0a9d..e0c3ff3e589b 100644 --- a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json +++ b/test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json @@ -1,5 +1,6 @@ { "data": { + "AccountsController": "object", "AlertController": { "alertEnabledness": { "unconnectedAccount": true, "web3ShimUsage": true }, "unconnectedAccountAlertShownOrigins": "object", From 50ac5fae48667453d785dcd0540e6cc4d73f934a Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 24 Aug 2023 17:02:44 +0800 Subject: [PATCH 042/235] fix:remove log --- ui/selectors/confirm-transaction.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/selectors/confirm-transaction.js b/ui/selectors/confirm-transaction.js index 3e4ffe480442..5646bc27035f 100644 --- a/ui/selectors/confirm-transaction.js +++ b/ui/selectors/confirm-transaction.js @@ -93,7 +93,6 @@ export const unconfirmedTransactionsHashSelector = createSelector( network, chainId, ) => { - console.log(111, unapprovedTxs); const filteredUnapprovedTxs = Object.keys(unapprovedTxs).reduce( (acc, address) => { const transactions = { ...acc }; @@ -108,6 +107,7 @@ export const unconfirmedTransactionsHashSelector = createSelector( }, {}, ); + console.log(111, filteredUnapprovedTxs); return { ...filteredUnapprovedTxs, From ab9d811746783b278bc6a95c187bd588b557cce1 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 24 Aug 2023 17:04:39 +0800 Subject: [PATCH 043/235] fix: update IncomingTransactionHelper to use internal account --- .../controllers/accounts-controller.ts | 8 +++ .../IncomingTransactionHelper.test.ts | 35 ++++++++-- .../transactions/IncomingTransactionHelper.ts | 7 +- app/scripts/controllers/transactions/index.js | 3 +- app/scripts/metamask-controller.js | 20 ++++-- .../unconnected-account-alert.js | 2 +- .../connected-accounts-list.component.js | 12 ++-- .../connected-accounts-list.stories.js | 2 +- ui/ducks/alerts/unconnected-account.js | 6 +- .../confirm-transaction.component.js | 5 ++ .../connected-accounts.component.js | 6 +- .../connected-accounts.container.js | 4 +- .../connected-accounts.stories.js | 2 +- ui/store/actions.test.js | 70 +++---------------- ui/store/actions.ts | 59 ++-------------- 15 files changed, 92 insertions(+), 149 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index 585fd116d254..bebf6117cdc5 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -48,8 +48,14 @@ export type AccountsControllerChangeEvent = { payload: [AccountsControllerState, Patch[]]; }; +export type AccountsControllerSelectedAccountChangeEvent = { + type: `${typeof controllerName}:selectedAccountChange`; + payload: [InternalAccount]; +}; + export type AccountsControllerEvents = | AccountsControllerChangeEvent + | AccountsControllerSelectedAccountChangeEvent | SnapControllerEvents | KeyringControllerEvents; @@ -378,6 +384,8 @@ export default class AccountsController extends BaseControllerV2< Date.now(); currentState.internalAccounts.selectedAccount = account.id; }); + + this.messagingSystem.publish(`${this.name}:selectedAccountChange`, account); } setAccountName(accountId: string, accountName: string): void { diff --git a/app/scripts/controllers/transactions/IncomingTransactionHelper.test.ts b/app/scripts/controllers/transactions/IncomingTransactionHelper.test.ts index f20675215885..104ec7b5519a 100644 --- a/app/scripts/controllers/transactions/IncomingTransactionHelper.test.ts +++ b/app/scripts/controllers/transactions/IncomingTransactionHelper.test.ts @@ -1,6 +1,7 @@ import { NetworkType } from '@metamask/controller-utils'; import type { BlockTracker, NetworkState } from '@metamask/network-controller'; +import { InternalAccount } from '@metamask/eth-snap-keyring'; import { TransactionMeta, TransactionStatus, @@ -22,7 +23,29 @@ const NETWORK_STATE_MOCK: NetworkState = { networkId: '1', } as unknown as NetworkState; -const ADDERSS_MOCK = '0x1'; +const INTERNAL_ACCOUNT_MOCK: InternalAccount = { + address: '0x1', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', +}; const FROM_BLOCK_HEX_MOCK = '0x20'; const FROM_BLOCK_DECIMAL_MOCK = 32; @@ -34,7 +57,7 @@ const BLOCK_TRACKER_MOCK = { const CONTROLLER_ARGS_MOCK = { blockTracker: BLOCK_TRACKER_MOCK, - getCurrentAccount: () => ADDERSS_MOCK, + getCurrentAccount: () => INTERNAL_ACCOUNT_MOCK, getNetworkState: () => NETWORK_STATE_MOCK, remoteTransactionSource: {} as RemoteTransactionSource, transactionLimit: 1, @@ -137,7 +160,7 @@ describe('IncomingTransactionHelper', () => { ); expect(remoteTransactionSource.fetchTransactions).toHaveBeenCalledWith({ - address: ADDERSS_MOCK, + address: INTERNAL_ACCOUNT_MOCK.address, currentChainId: NETWORK_STATE_MOCK.providerConfig.chainId, currentNetworkId: NETWORK_STATE_MOCK.networkId, fromBlock: expect.any(Number), @@ -173,7 +196,7 @@ describe('IncomingTransactionHelper', () => { ...CONTROLLER_ARGS_MOCK, remoteTransactionSource, lastFetchedBlockNumbers: { - [`${NETWORK_STATE_MOCK.providerConfig.chainId}#${ADDERSS_MOCK}`]: + [`${NETWORK_STATE_MOCK.providerConfig.chainId}#${INTERNAL_ACCOUNT_MOCK.address}`]: FROM_BLOCK_DECIMAL_MOCK, }, }); @@ -414,7 +437,7 @@ describe('IncomingTransactionHelper', () => { ); expect(lastFetchedBlockNumbers).toStrictEqual({ - [`${NETWORK_STATE_MOCK.providerConfig.chainId}#${ADDERSS_MOCK}`]: + [`${NETWORK_STATE_MOCK.providerConfig.chainId}#${INTERNAL_ACCOUNT_MOCK.address}`]: parseInt(TRANSACTION_MOCK_2.blockNumber as string, 10), }); }); @@ -472,7 +495,7 @@ describe('IncomingTransactionHelper', () => { TRANSACTION_MOCK_2, ]), lastFetchedBlockNumbers: { - [`${NETWORK_STATE_MOCK.providerConfig.chainId}#${ADDERSS_MOCK}`]: + [`${NETWORK_STATE_MOCK.providerConfig.chainId}#${INTERNAL_ACCOUNT_MOCK.address}`]: parseInt(TRANSACTION_MOCK_2.blockNumber as string, 10), }, }); diff --git a/app/scripts/controllers/transactions/IncomingTransactionHelper.ts b/app/scripts/controllers/transactions/IncomingTransactionHelper.ts index 3acb6372637f..0a087c65430b 100644 --- a/app/scripts/controllers/transactions/IncomingTransactionHelper.ts +++ b/app/scripts/controllers/transactions/IncomingTransactionHelper.ts @@ -3,6 +3,7 @@ import type { BlockTracker, NetworkState } from '@metamask/network-controller'; import type { Hex } from '@metamask/utils'; import log from 'loglevel'; +import { InternalAccount } from '@metamask/eth-snap-keyring'; import { TransactionMeta } from '../../../../shared/constants/transaction'; import { RemoteTransactionSource } from './types'; @@ -15,7 +16,7 @@ export class IncomingTransactionHelper { #blockTracker: BlockTracker; - #getCurrentAccount: () => string; + #getCurrentAccount: () => InternalAccount; #getLocalTransactions: () => TransactionMeta[]; @@ -49,7 +50,7 @@ export class IncomingTransactionHelper { updateTransactions, }: { blockTracker: BlockTracker; - getCurrentAccount: () => string; + getCurrentAccount: () => InternalAccount; getNetworkState: () => NetworkState; getLocalTransactions?: () => TransactionMeta[]; isEnabled?: () => boolean; @@ -115,7 +116,7 @@ export class IncomingTransactionHelper { ); const fromBlock = this.#getFromBlock(latestBlockNumber); - const address = this.#getCurrentAccount(); + const { address } = this.#getCurrentAccount(); const currentChainId = this.#getCurrentChainId(); const currentNetworkId = this.#getCurrentNetworkId(); diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 8e30f4c5dc58..0178abc31c1f 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -154,6 +154,7 @@ export default class TransactionController extends EventEmitter { this._getCurrentAccountEIP1559Compatibility = opts.getCurrentAccountEIP1559Compatibility; this.preferencesStore = opts.preferencesStore || new ObservableStore({}); + this.getCurrentAccount = opts.getCurrentAccount; this.provider = opts.provider; this.getPermittedAccounts = opts.getPermittedAccounts; this.blockTracker = opts.blockTracker; @@ -224,7 +225,7 @@ export default class TransactionController extends EventEmitter { this.incomingTransactionHelper = new IncomingTransactionHelper({ blockTracker: this.blockTracker, - getCurrentAccount: () => this.getSelectedAddress(), + getCurrentAccount: () => this.getCurrentAccount(), getNetworkState: () => this._getNetworkState(), isEnabled: () => Boolean( diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index d0801be023c4..04f9bfb72343 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1217,6 +1217,7 @@ export default class MetamaskController extends EventEmitter { getCurrentChainId: () => this.networkController.state.providerConfig.chainId, preferencesStore: this.preferencesController.store, + getCurrentAccount: () => this.accountsController.getSelectedAccount(), txHistoryLimit: 60, signTransaction: this.keyringController.signTransaction.bind( this.keyringController, @@ -1560,7 +1561,7 @@ export default class MetamaskController extends EventEmitter { ) => { if (innerOrigin === ORIGIN_METAMASK) { const selectedAddress = - this.preferencesController.getSelectedAddress(); + this.accountsController.getSelectedAccount().address; return selectedAddress ? [selectedAddress] : []; } else if (this.isUnlocked()) { return await this.getPermittedAccounts(innerOrigin, { @@ -2008,7 +2009,7 @@ export default class MetamaskController extends EventEmitter { let lastSelectedAddress; this.preferencesController.store.subscribe(async (state) => { - const { selectedAddress, currentLocale } = state; + const { currentLocale } = state; await updateCurrentLocale(currentLocale); @@ -2017,13 +2018,18 @@ export default class MetamaskController extends EventEmitter { } else { this.txController.stopIncomingTransactionPolling(); } - - if (selectedAddress && selectedAddress !== lastSelectedAddress) { - lastSelectedAddress = selectedAddress; - await this._onAccountChange(selectedAddress); - } }); + this.controllerMessenger.subscribe( + `${this.accountsController.name}:selectedAccountChange`, + async (account) => { + if (account.address && account.address !== lastSelectedAddress) { + lastSelectedAddress = account.address; + await this._onAccountChange(account.address); + } + }, + ); + // This handles account changes every time relevant permission state // changes, for any reason. this.controllerMessenger.subscribe( diff --git a/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js b/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js index dca99e075de8..618534ec9b94 100644 --- a/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js +++ b/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js @@ -101,7 +101,7 @@ const UnconnectedAccountAlert = () => { connectAccount={() => dispatch(connectAccount(selectedAddress))} connectedAccounts={connectedAccounts} selectedAddress={selectedAddress} - setSelectedAddress={(address) => dispatch(switchToAccount(address))} + setSelectedAccount={(accountId) => dispatch(switchToAccount(accountId))} shouldRenderListOptions={false} /> diff --git a/ui/components/app/connected-accounts-list/connected-accounts-list.component.js b/ui/components/app/connected-accounts-list/connected-accounts-list.component.js index 11563efc82d5..06c5072bc26d 100644 --- a/ui/components/app/connected-accounts-list/connected-accounts-list.component.js +++ b/ui/components/app/connected-accounts-list/connected-accounts-list.component.js @@ -29,7 +29,7 @@ export default class ConnectedAccountsList extends PureComponent { connectAccount: PropTypes.func.isRequired, selectedAddress: PropTypes.string.isRequired, removePermittedAccount: PropTypes.func, - setSelectedAddress: PropTypes.func.isRequired, + setSelectedAccount: PropTypes.func.isRequired, shouldRenderListOptions: (props, propName, componentName) => { if (typeof props[propName] !== 'boolean') { return new Error( @@ -57,7 +57,7 @@ export default class ConnectedAccountsList extends PureComponent { switchAccount = (address) => { this.hideAccountOptions(); - this.props.setSelectedAddress(address); + this.props.setSelectedAccount(address); }; hideAccountOptions = () => { @@ -112,13 +112,13 @@ export default class ConnectedAccountsList extends PureComponent { ); } - renderListItemAction(address) { + renderListItemAction(accountId) { const { t } = this.context; return ( this.switchAccount(address)} + onClick={() => this.switchAccount(accountId)} > {t('switchToThisAccount')} @@ -134,7 +134,7 @@ export default class ConnectedAccountsList extends PureComponent { <>
{this.renderUnconnectedAccount()} - {connectedAccounts.map(({ address, name }, index) => { + {connectedAccounts.map(({ accountId, address, name }, index) => { return ( ); diff --git a/ui/components/app/connected-accounts-list/connected-accounts-list.stories.js b/ui/components/app/connected-accounts-list/connected-accounts-list.stories.js index 793b0acca9b4..03fa6f6ad9f6 100644 --- a/ui/components/app/connected-accounts-list/connected-accounts-list.stories.js +++ b/ui/components/app/connected-accounts-list/connected-accounts-list.stories.js @@ -8,7 +8,7 @@ export default { connectedAccounts: { control: 'array', }, - selectedAddress: { + setSelectedAccount: { control: 'text', }, shouldRenderListOptions: { diff --git a/ui/ducks/alerts/unconnected-account.js b/ui/ducks/alerts/unconnected-account.js index 4506b49c5f16..049f038d79d0 100644 --- a/ui/ducks/alerts/unconnected-account.js +++ b/ui/ducks/alerts/unconnected-account.js @@ -6,7 +6,7 @@ import * as actionConstants from '../../store/actionConstants'; import { addPermittedAccount, setAlertEnabledness, - setSelectedAddress, + setSelectedInternalAccount, } from '../../store/actions'; import { getOriginOfCurrentTab, @@ -114,11 +114,11 @@ export const dismissAndDisableAlert = () => { }; }; -export const switchToAccount = (address) => { +export const switchToAccount = (accountId) => { return async (dispatch) => { try { await dispatch(switchAccountRequested()); - await dispatch(setSelectedAddress(address)); + await dispatch(setSelectedInternalAccount(accountId)); await dispatch(switchAccountSucceeded()); } catch (error) { console.error(error); diff --git a/ui/pages/confirm-transaction/confirm-transaction.component.js b/ui/pages/confirm-transaction/confirm-transaction.component.js index b570ea059164..8ea69cbbb778 100644 --- a/ui/pages/confirm-transaction/confirm-transaction.component.js +++ b/ui/pages/confirm-transaction/confirm-transaction.component.js @@ -47,6 +47,7 @@ import ConfirmSignatureRequest from '../confirm-signature-request'; import ConfirmTokenTransactionSwitch from './confirm-token-transaction-switch'; const ConfirmTransaction = () => { + console.log('here'); const dispatch = useDispatch(); const history = useHistory(); const { id: paramsTransactionId } = useParams(); @@ -57,6 +58,8 @@ const ConfirmTransaction = () => { const mostRecentOverviewPage = useSelector(getMostRecentOverviewPage); const sendTo = useSelector(getSendTo); + console.log('sendTo', sendTo); + const unconfirmedTxsSorted = useSelector(unconfirmedTransactionsListSelector); const unconfirmedTxs = useSelector(unconfirmedTransactionsHashSelector); @@ -92,6 +95,8 @@ const ConfirmTransaction = () => { const { id, type } = transaction; const transactionId = id && String(id); const isValidTokenMethod = isTokenMethodAction(type); + console.log('transactionId', transactionId); + console.log('transactionId', paramsTransactionId); const isValidTransactionId = transactionId && (!paramsTransactionId || paramsTransactionId === transactionId); diff --git a/ui/pages/connected-accounts/connected-accounts.component.js b/ui/pages/connected-accounts/connected-accounts.component.js index 24fdb79acb93..6f3b132e9ad8 100644 --- a/ui/pages/connected-accounts/connected-accounts.component.js +++ b/ui/pages/connected-accounts/connected-accounts.component.js @@ -25,7 +25,7 @@ export default class ConnectedAccounts extends PureComponent { isActiveTabExtension: PropTypes.bool.isRequired, selectedAddress: PropTypes.string.isRequired, removePermittedAccount: PropTypes.func.isRequired, - setSelectedAddress: PropTypes.func.isRequired, + setSelectedAccount: PropTypes.func.isRequired, history: PropTypes.object.isRequired, }; @@ -41,7 +41,7 @@ export default class ConnectedAccounts extends PureComponent { permissions, selectedAddress, removePermittedAccount, - setSelectedAddress, + setSelectedAccount, } = this.props; const { t } = this.context; @@ -76,7 +76,7 @@ export default class ConnectedAccounts extends PureComponent { connectedAccounts={connectedAccounts} selectedAddress={selectedAddress} removePermittedAccount={removePermittedAccount} - setSelectedAddress={setSelectedAddress} + setSelectedAccount={setSelectedAccount} shouldRenderListOptions /> diff --git a/ui/pages/connected-accounts/connected-accounts.container.js b/ui/pages/connected-accounts/connected-accounts.container.js index bc3a1a4c2dfd..ffe550ca8c7f 100644 --- a/ui/pages/connected-accounts/connected-accounts.container.js +++ b/ui/pages/connected-accounts/connected-accounts.container.js @@ -9,7 +9,7 @@ import { isExtensionUrl } from '../../helpers/utils/util'; import { addPermittedAccount, removePermittedAccount, - setSelectedAddress, + setSelectedAccount, } from '../../store/actions'; import { getMostRecentOverviewPage } from '../../ducks/history/history'; import ConnectedAccounts from './connected-accounts.component'; @@ -39,7 +39,7 @@ const mapDispatchToProps = (dispatch) => { dispatch(addPermittedAccount(origin, address)), removePermittedAccount: (origin, address) => dispatch(removePermittedAccount(origin, address)), - setSelectedAddress: (address) => dispatch(setSelectedAddress(address)), + setSelectedAccount: (accountId) => dispatch(setSelectedAccount(accountId)), }; }; diff --git a/ui/pages/connected-accounts/connected-accounts.stories.js b/ui/pages/connected-accounts/connected-accounts.stories.js index 8fedd59ef5d5..1c63bf6024f2 100644 --- a/ui/pages/connected-accounts/connected-accounts.stories.js +++ b/ui/pages/connected-accounts/connected-accounts.stories.js @@ -63,7 +63,7 @@ export const DefaultStory = () => { accountToConnect={accounts[0]} connectAccount={action('Account Connected')} removePermittedAccount={action('Account Removed')} - setSelectedAddress={action('Selected Address Changed')} + setSelectedAccount={action('Selected Account Changed')} /> ); }; diff --git a/ui/store/actions.test.js b/ui/store/actions.test.js index e8c5a1045331..d500c4bc0830 100644 --- a/ui/store/actions.test.js +++ b/ui/store/actions.test.js @@ -871,89 +871,37 @@ describe('Actions', () => { }); }); - describe('#setSelectedAddress', () => { + describe('#setSelectedAccount', () => { afterEach(() => { sinon.restore(); }); - it('calls setSelectedAddress in background', async () => { + it('calls setSelectedAccount in background', async () => { const store = mockStore(); - const setSelectedAddressSpy = sinon.stub().callsFake((_, cb) => cb()); + const setSelectedAccountSpy = sinon.stub().callsFake((_, cb) => cb()); background.getApi.returns({ - setSelectedAddress: setSelectedAddressSpy, + setSelectedInternalAccount: setSelectedAccountSpy, }); _setBackgroundConnection(background.getApi()); await store.dispatch( - actions.setSelectedAddress( - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - ), + actions.setSelectedAccount('0140ecb0-185b-4067-a25a-43997fecb05d'), ); - expect(setSelectedAddressSpy.callCount).toStrictEqual(1); + expect(setSelectedAccountSpy.callCount).toStrictEqual(1); }); - it('errors when setSelectedAddress throws', async () => { + it('errors when setSelectedAccount throws', async () => { const store = mockStore(); - const setSelectedAddressSpy = sinon - .stub() - .callsFake((_, cb) => cb(new Error('error'))); - - background.getApi.returns({ - setSelectedAddress: setSelectedAddressSpy, - }); - - _setBackgroundConnection(background.getApi()); - - const expectedActions = [ - { type: 'SHOW_LOADING_INDICATION', payload: undefined }, - { type: 'DISPLAY_WARNING', payload: 'error' }, - { type: 'HIDE_LOADING_INDICATION' }, - ]; - - await store.dispatch(actions.setSelectedAddress()); - expect(store.getActions()).toStrictEqual(expectedActions); - }); - }); - - describe('#setSelectedAccount', () => { - afterEach(() => { - sinon.restore(); - }); - - it('#setSelectedAccount', async () => { - const store = mockStore({ - activeTab: {}, - metamask: { alertEnabledness: {}, selectedAddress: '0x123' }, - }); - - const setSelectedAddressSpy = sinon.stub().callsFake((_, cb) => cb()); - - background.getApi.returns({ - setSelectedAddress: setSelectedAddressSpy, - }); - - _setBackgroundConnection(background.getApi()); - - await store.dispatch(actions.setSelectedAccount()); - expect(setSelectedAddressSpy.callCount).toStrictEqual(1); - }); - - it('displays warning if setSelectedAccount throws', async () => { - const store = mockStore({ - activeTab: {}, - metamask: { alertEnabledness: {}, selectedAddress: '0x123' }, - }); - - const setSelectedAddressSpy = sinon + const setSelectedAccountSpy = sinon .stub() .callsFake((_, cb) => cb(new Error('error'))); background.getApi.returns({ - setSelectedAddress: setSelectedAddressSpy, + setSelectedInternalAccount: setSelectedAccountSpy, }); _setBackgroundConnection(background.getApi()); diff --git a/ui/store/actions.ts b/ui/store/actions.ts index 77d4c0ba3ace..5f6b9ff615f7 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -1670,25 +1670,20 @@ export function lockMetamask(): ThunkAction< }; } -async function _setSelectedAddress(address: string): Promise { - log.debug(`background.setSelectedAddress`); - await submitRequestToBackground('setSelectedAddress', [address]); -} - async function _setSelectedInternalAccount(accountId: string): Promise { log.debug(`background.setSelectedInternalAccount`); console.log('sending to background', accountId); await submitRequestToBackground('setSelectedInternalAccount', [accountId]); } -export function setSelectedAddress( - address: string, +export function setSelectedAccount( + accountId: string, ): ThunkAction { return async (dispatch: MetaMaskReduxDispatch) => { dispatch(showLoadingIndication()); - log.debug(`background.setSelectedAddress`); + log.debug(`background.setSelectedInternalAccount`); try { - await _setSelectedAddress(address); + await _setSelectedInternalAccount(accountId); } catch (error) { dispatch(displayWarning(error)); return; @@ -1703,7 +1698,7 @@ export function setSelectedInternalAccount( ): ThunkAction { return async (dispatch, getState) => { dispatch(showLoadingIndication()); - log.debug(`background.setSelectedAddress`); + log.debug(`background.setSelectedInternalAccount`); const state = getState(); const unconnectedAccountAccountAlertIsEnabled = @@ -1746,50 +1741,6 @@ export function setSelectedInternalAccount( }; } -export function setSelectedAccount( - address: string, -): ThunkAction { - return async (dispatch, getState) => { - dispatch(showLoadingIndication()); - log.debug(`background.setSelectedAddress`); - - const state = getState(); - const unconnectedAccountAccountAlertIsEnabled = - getUnconnectedAccountAlertEnabledness(state); - const activeTabOrigin = state.activeTab.origin; - const selectedAddress = getSelectedAddress(state); - const permittedAccountsForCurrentTab = - getPermittedAccountsForCurrentTab(state); - const currentTabIsConnectedToPreviousAddress = - Boolean(activeTabOrigin) && - permittedAccountsForCurrentTab.includes(selectedAddress); - const currentTabIsConnectedToNextAddress = - Boolean(activeTabOrigin) && - permittedAccountsForCurrentTab.includes(address); - const switchingToUnconnectedAddress = - currentTabIsConnectedToPreviousAddress && - !currentTabIsConnectedToNextAddress; - - try { - await _setSelectedAddress(address); - await forceUpdateMetamaskState(dispatch); - } catch (error) { - dispatch(displayWarning(error)); - return; - } finally { - dispatch(hideLoadingIndication()); - } - - if ( - unconnectedAccountAccountAlertIsEnabled && - switchingToUnconnectedAddress - ) { - dispatch(switchedToUnconnectedAccount()); - await setUnconnectedAccountAlertShown(activeTabOrigin); - } - }; -} - export function addPermittedAccount( origin: string, address: string, From 1aa9eb1d06cdc6caa9c838e277f65299ba2ecf1a Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 24 Aug 2023 19:13:55 +0800 Subject: [PATCH 044/235] fix: send tx using internal account --- app/scripts/controllers/transactions/index.js | 11 +++++------ app/scripts/metamask-controller.js | 6 +++++- .../send-asset-row/send-asset-row.component.js | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 0178abc31c1f..42d1e997f376 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -1581,13 +1581,13 @@ export default class TransactionController extends EventEmitter { if (origin === ORIGIN_METAMASK) { // Assert the from address is the selected address - if (normalizedTxParams.from !== this.getSelectedAddress()) { + if (normalizedTxParams.from !== this.getSelectedAccountAddress()) { throw ethErrors.rpc.internal({ message: `Internally initiated transaction is using invalid account.`, data: { origin, fromAddress: normalizedTxParams.from, - selectedAddress: this.getSelectedAddress(), + selectedAddress: this.getSelectedAccountAddress(), }, }); } @@ -1917,8 +1917,7 @@ export default class TransactionController extends EventEmitter { this.getState = () => this.memStore.getState(); /** @returns {string} the user selected address */ - this.getSelectedAddress = () => - this.preferencesStore.getState().selectedAddress; + this.getSelectedAccountAddress = () => this.getCurrentAccount().address; /** @returns {Array} transactions whos status is unapproved */ this.getUnapprovedTxCount = () => @@ -2494,8 +2493,8 @@ export default class TransactionController extends EventEmitter { eip_1559_version: eip1559Version, gas_edit_type: 'none', gas_edit_attempted: 'none', - account_type: await this.getAccountType(this.getSelectedAddress()), - device_model: await this.getDeviceModel(this.getSelectedAddress()), + account_type: await this.getAccountType(this.getSelectedAccountAddress()), + device_model: await this.getDeviceModel(this.getSelectedAccountAddress()), asset_type: assetType, token_standard: tokenStandard, transaction_type: transactionType, diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 04f9bfb72343..3184b028cf17 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -2948,6 +2948,9 @@ export default class MetamaskController extends EventEmitter { password, ); await this.accountsController.updateAccounts(); + this.accountsController.setSelectedAccount( + this.accountsController.getAccounts()[0].id, + ); } return vault; @@ -3562,7 +3565,8 @@ export default class MetamaskController extends EventEmitter { * @returns {Promise} The current selected address. */ async resetAccount() { - const selectedAddress = this.preferencesController.getSelectedAddress(); + const selectedAddress = + this.accountsController.getSelectedAccount().address; this.txController.wipeTransactions(selectedAddress); this.networkController.resetConnection(); diff --git a/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js b/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js index 440de6889810..dfcd421338b7 100644 --- a/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js +++ b/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js @@ -205,8 +205,8 @@ export default class SendAssetRow extends Component { this.props; const { sendableTokens, sendableNfts } = this.state; - const balanceValue = accounts[selectedAccount.address] - ? accounts[selectedAccount.address].balance + const balanceValue = accounts[selectedAccount.id] + ? accounts[selectedAccount.id].balance : ''; const sendableAssets = [...sendableTokens, ...sendableNfts]; From 601dd55628eb9cd9468d7b70798bfda23e557d8f Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 24 Aug 2023 19:31:26 +0800 Subject: [PATCH 045/235] lint: remove unused --- ui/store/actions.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/store/actions.ts b/ui/store/actions.ts index 5f6b9ff615f7..1c82d60f944f 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -34,7 +34,6 @@ import { getEnvironmentType, addHexPrefix } from '../../app/scripts/lib/util'; import { getMetaMaskAccounts, getPermittedAccountsForCurrentTab, - getSelectedAddress, hasTransactionPendingApprovals, getApprovalFlows, getInternalAccount, From 01319ec57c07448d53303bb479524d4b1aa8f592 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Fri, 25 Aug 2023 08:16:50 +0800 Subject: [PATCH 046/235] fix: relocate AccountTracker to after AccountsController, and set to first hd account on vault creation --- .../controllers/accounts-controller.ts | 4 +- .../controllers/transactions/index.test.js | 28 +++++ app/scripts/lib/account-tracker.js | 17 ++- app/scripts/metamask-controller.js | 109 ++++++++++-------- app/scripts/metamask-controller.test.js | 53 +++++++-- 5 files changed, 147 insertions(+), 64 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index bebf6117cdc5..04e52da1f3f2 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -335,9 +335,9 @@ export default class AccountsController extends BaseControllerV2< ///: END:ONLY_INCLUDE_IN(keyring-snaps) // Note: listLegacyAccounts is a temporary method until the keyrings all implement the InternalAccount interface - async #listLegacyAccounts(): Promise { + async #listLegacyAccounts(): Promise[]> { const addresses = await this.#keyringController.getAccounts(); - const internalAccounts: InternalAccount[] = []; + const internalAccounts: Omit[] = []; for (const address of addresses) { const keyring = await this.#keyringController.getKeyringForAccount( address, diff --git a/app/scripts/controllers/transactions/index.test.js b/app/scripts/controllers/transactions/index.test.js index 77150f34a78e..0cfe6a6db95f 100644 --- a/app/scripts/controllers/transactions/index.test.js +++ b/app/scripts/controllers/transactions/index.test.js @@ -62,6 +62,30 @@ const TRANSACTION_META_MOCK = { time: 123456789, }; +const MOCK_INTENRAL_ACCOUNT = { + id: '2d47e693-26c2-47cb-b374-6151199bbe3f', + address: '0x88bb7F89eB5e5b30D3e15a57C68DBe03C6aCCB21', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', +}; + async function flushPromises() { await new Promise((resolve) => setImmediate(resolve)); } @@ -74,6 +98,7 @@ describe('Transaction Controller', function () { fragmentExists, networkStatusStore, getCurrentChainId, + getCurrentAccount, messengerMock, resultCallbacksMock, updateSpy, @@ -105,6 +130,8 @@ describe('Transaction Controller', function () { getCurrentChainId = sinon.stub().callsFake(() => currentChainId); + getCurrentAccount = sinon.stub().callsFake(() => MOCK_INTENRAL_ACCOUNT); + resultCallbacksMock = { success: sinon.spy(), error: sinon.spy(), @@ -144,6 +171,7 @@ describe('Transaction Controller', function () { getProviderConfig: () => providerConfig, getPermittedAccounts: () => undefined, getCurrentChainId, + getCurrentAccount, getParticipateInMetrics: () => false, trackMetaMetricsEvent: () => undefined, createEventFragment: () => undefined, diff --git a/app/scripts/lib/account-tracker.js b/app/scripts/lib/account-tracker.js index cbc87aef749a..d7eb66356739 100644 --- a/app/scripts/lib/account-tracker.js +++ b/app/scripts/lib/account-tracker.js @@ -82,6 +82,7 @@ export default class AccountTracker { this.getNetworkIdentifier = opts.getNetworkIdentifier; this.preferencesController = opts.preferencesController; this.onboardingController = opts.onboardingController; + this.accountsController = opts.accountsController; this.onboardingController.store.subscribe( previousValueComparator(async (prevState, currState) => { @@ -93,6 +94,19 @@ export default class AccountTracker { }, this.onboardingController.store.getState()), ); + this.controllerMessenger = opts.controllerMessenger; + + this.controllerMessenger.subscribe( + 'AccountsController:selectedAccountChange', + () => { + const { useMultiAccountBalanceChecker } = + this.preferencesController.store.getState(); + if (!useMultiAccountBalanceChecker) { + this._updateAccounts(); + } + }, + ); + this.preferencesController.store.subscribe( previousValueComparator(async (prevState, currState) => { const { selectedAddress: prevSelectedAddress } = prevState; @@ -247,7 +261,8 @@ export default class AccountTracker { addresses = Object.keys(accounts); } else { - const selectedAddress = this.preferencesController.getSelectedAddress(); + const selectedAddress = + this.accountsController.getSelectedAccount().address; addresses = [selectedAddress]; } diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 3184b028cf17..e15db75c988c 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -740,54 +740,6 @@ export default class MetamaskController extends EventEmitter { initState: initState.OnboardingController, }); - // account tracker watches balances, nonces, and any code at their address - this.accountTracker = new AccountTracker({ - provider: this.provider, - blockTracker: this.blockTracker, - getCurrentChainId: () => - this.networkController.state.providerConfig.chainId, - getNetworkIdentifier: () => { - const { type, rpcUrl } = this.networkController.state.providerConfig; - return type === NETWORK_TYPES.RPC ? rpcUrl : type; - }, - preferencesController: this.preferencesController, - onboardingController: this.onboardingController, - initState: - isManifestV3 && - isFirstMetaMaskControllerSetup === false && - initState.AccountTracker?.accounts - ? { accounts: initState.AccountTracker.accounts } - : { accounts: {} }, - }); - - // start and stop polling for balances based on activeControllerConnections - this.on('controllerConnectionChanged', (activeControllerConnections) => { - const { completedOnboarding } = - this.onboardingController.store.getState(); - if (activeControllerConnections > 0 && completedOnboarding) { - this.triggerNetworkrequests(); - } else { - this.stopNetworkRequests(); - } - }); - - this.onboardingController.store.subscribe( - previousValueComparator(async (prevState, currState) => { - const { completedOnboarding: prevCompletedOnboarding } = prevState; - const { completedOnboarding: currCompletedOnboarding } = currState; - if (!prevCompletedOnboarding && currCompletedOnboarding) { - this.triggerNetworkrequests(); - } - }, this.onboardingController.store.getState()), - ); - - this.cachedBalancesController = new CachedBalancesController({ - accountTracker: this.accountTracker, - getCurrentChainId: () => - this.networkController.state.providerConfig.chainId, - initState: initState.CachedBalancesController, - }); - let additionalKeyrings = [keyringBuilderFactory(QRHardwareKeyring)]; if (this.canUseHardwareWallets()) { @@ -1129,6 +1081,56 @@ export default class MetamaskController extends EventEmitter { ///: END:ONLY_INCLUDE_IN }); + // account tracker watches balances, nonces, and any code at their address + this.accountTracker = new AccountTracker({ + provider: this.provider, + blockTracker: this.blockTracker, + getCurrentChainId: () => + this.networkController.state.providerConfig.chainId, + getNetworkIdentifier: () => { + const { type, rpcUrl } = this.networkController.state.providerConfig; + return type === NETWORK_TYPES.RPC ? rpcUrl : type; + }, + preferencesController: this.preferencesController, + accountsController: this.accountsController, + controllerMessenger: this.controllerMessenger, + onboardingController: this.onboardingController, + initState: + isManifestV3 && + isFirstMetaMaskControllerSetup === false && + initState.AccountTracker?.accounts + ? { accounts: initState.AccountTracker.accounts } + : { accounts: {} }, + }); + + // start and stop polling for balances based on activeControllerConnections + this.on('controllerConnectionChanged', (activeControllerConnections) => { + const { completedOnboarding } = + this.onboardingController.store.getState(); + if (activeControllerConnections > 0 && completedOnboarding) { + this.triggerNetworkrequests(); + } else { + this.stopNetworkRequests(); + } + }); + + this.onboardingController.store.subscribe( + previousValueComparator(async (prevState, currState) => { + const { completedOnboarding: prevCompletedOnboarding } = prevState; + const { completedOnboarding: currCompletedOnboarding } = currState; + if (!prevCompletedOnboarding && currCompletedOnboarding) { + this.triggerNetworkrequests(); + } + }, this.onboardingController.store.getState()), + ); + + this.cachedBalancesController = new CachedBalancesController({ + accountTracker: this.accountTracker, + getCurrentChainId: () => + this.networkController.state.providerConfig.chainId, + initState: initState.CachedBalancesController, + }); + ///: BEGIN:ONLY_INCLUDE_IN(desktop) this.desktopController = new DesktopController({ initState: initState.DesktopController, @@ -2949,7 +2951,7 @@ export default class MetamaskController extends EventEmitter { ); await this.accountsController.updateAccounts(); this.accountsController.setSelectedAccount( - this.accountsController.getAccounts()[0].id, + this.accountsController.listAccounts()[0].id, ); } @@ -2999,6 +3001,8 @@ export default class MetamaskController extends EventEmitter { const ethQuery = new EthQuery(this.provider); accounts = await this.coreKeyringController.getAccounts(); + const firstAccount = accounts[0]; + lastBalance = await this.getBalance( accounts[accounts.length - 1], ethQuery, @@ -3036,6 +3040,13 @@ export default class MetamaskController extends EventEmitter { await this.accountsController.updateAccounts(); + // set first hd account as the selected account by default + this.accountsController.setSelectedAccount( + this.accountsController + .listAccounts() + .find((account) => account.address === firstAccount).id, + ); + return vault; } finally { releaseLock(); diff --git a/app/scripts/metamask-controller.test.js b/app/scripts/metamask-controller.test.js index b09f900c9017..59d321f3e82c 100644 --- a/app/scripts/metamask-controller.test.js +++ b/app/scripts/metamask-controller.test.js @@ -28,6 +28,7 @@ import { KeyringType } from '../../shared/constants/keyring'; import { deferredPromise } from './lib/util'; import TransactionController from './controllers/transactions'; import PreferencesController from './controllers/preferences'; +import AccountsController from './controllers/accounts-controller'; const Ganache = require('../../test/e2e/ganache'); @@ -121,6 +122,29 @@ const TEST_ADDRESS_3 = '0xeb9e64b93097bc15f01f13eae97015c57ab64823'; const TEST_SEED_ALT = 'setup olympic issue mobile velvet surge alcohol burger horse view reopen gentle'; const TEST_ADDRESS_ALT = '0xc42edfcc21ed14dda456aa0756c153f7985d8813'; +const TEST_INTERNAL_ACCOUNT = { + id: '2d47e693-26c2-47cb-b374-6151199bbe3f', + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', +}; const NOTIFICATION_ID = 'NHL8f2eSSTn9TKBamRLiU'; @@ -965,7 +989,7 @@ describe('MetaMaskController', function () { await addNewAccount; assert.fail('should throw'); } catch (e) { - assert.equal(e.message, 'No HD keyring found'); + assert.equal(e.message, 'MetamaskController - No HD Key Tree found'); } }); }); @@ -992,19 +1016,17 @@ describe('MetaMaskController', function () { }); describe('#resetAccount', function () { - it('wipes transactions from only the correct network id and with the selected address', async function () { - const selectedAddressStub = sinon.stub( - metamaskController.preferencesController, - 'getSelectedAddress', + it('wipes transactions from only the correct network id and with the selected account', async function () { + const selectedAccountStub = sinon.stub( + metamaskController.accountsController, + 'getSelectedAccount', ); const getNetworkIdStub = sinon.stub( metamaskController.txController.txStateManager, 'getNetworkId', ); - selectedAddressStub.returns( - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - ); + selectedAccountStub.returns(TEST_INTERNAL_ACCOUNT); getNetworkIdStub.returns(42); metamaskController.txController.txStateManager._addTransactionsToState([ @@ -1781,10 +1803,15 @@ describe('MetaMaskController', function () { describe('incoming transactions', function () { let txControllerStub, preferencesControllerSpy, controllerMessengerSpy; - beforeEach(function () { + beforeEach(async function () { txControllerStub = TransactionController.prototype; preferencesControllerSpy = metamaskController.preferencesController; controllerMessengerSpy = ControllerMessenger.prototype; + sandbox + .stub(metamaskController.accountsController, 'getSelectedAccount') + .callsFake(() => { + return TEST_INTERNAL_ACCOUNT; + }); }); it('starts incoming transaction polling if show incoming transactions enabled', async function () { @@ -1814,9 +1841,11 @@ describe('MetaMaskController', function () { it('updates incoming transactions when changing account', async function () { assert(txControllerStub.updateIncomingTransactions.notCalled); - await preferencesControllerSpy.store.subscribe.lastCall.args[0]({ - selectedAddress: 'foo', - }); + await controllerMessengerSpy.subscribe.args + .filter( + (args) => args[0] === 'AccountsController:selectedAccountChange', + ) + .slice(-1)[0][1](); assert(txControllerStub.updateIncomingTransactions.calledOnce); }); From 7e816796cec3be27445ca557b40a1a66403ef3cc Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Fri, 25 Aug 2023 17:51:07 +0800 Subject: [PATCH 047/235] feat: add migrations --- .../controllers/accounts-controller.ts | 2 +- .../transactions/IncomingTransactionHelper.ts | 2 +- app/scripts/migrations/097.test.ts | 338 ++++++++++++++++++ app/scripts/migrations/097.ts | 134 +++++++ .../multichain/app-header/app-header.js | 2 +- 5 files changed, 475 insertions(+), 3 deletions(-) create mode 100644 app/scripts/migrations/097.test.ts create mode 100644 app/scripts/migrations/097.ts diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index 04e52da1f3f2..d20235dcb291 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -420,7 +420,7 @@ export default class AccountsController extends BaseControllerV2< ///: END:ONLY_INCLUDE_IN(keyring-snaps) } -function keyringTypeToName(keyringType: string): string { +export function keyringTypeToName(keyringType: string): string { switch (keyringType) { case 'Simple Key Pair': { return 'Account'; diff --git a/app/scripts/controllers/transactions/IncomingTransactionHelper.ts b/app/scripts/controllers/transactions/IncomingTransactionHelper.ts index 0a087c65430b..5fa366dadfaa 100644 --- a/app/scripts/controllers/transactions/IncomingTransactionHelper.ts +++ b/app/scripts/controllers/transactions/IncomingTransactionHelper.ts @@ -257,7 +257,7 @@ export class IncomingTransactionHelper { } #getBlockNumberKey(): string { - return `${this.#getCurrentChainId()}#${this.#getCurrentAccount().toLowerCase()}`; + return `${this.#getCurrentChainId()}#${this.#getCurrentAccount().address.toLowerCase()}`; } #canStart(): boolean { diff --git a/app/scripts/migrations/097.test.ts b/app/scripts/migrations/097.test.ts new file mode 100644 index 000000000000..8c758aa178c8 --- /dev/null +++ b/app/scripts/migrations/097.test.ts @@ -0,0 +1,338 @@ +import { v4 as uuid } from 'uuid'; +import { sha256FromString } from 'ethereumjs-util'; +import { InternalAccount } from '@metamask/eth-snap-keyring'; +import { keyringTypeToName } from '../controllers/accounts-controller'; +import { KeyringType } from '../../../shared/constants/keyring'; +import { migrate } from './097'; + +const MOCK_ADDRESS = '0x0'; + +function addressToUUID(address: string): string { + return uuid({ + random: sha256FromString(address).slice(0, 16), + }); +} + +function createMockKeyring( + keyringType: string, + accounts: string[] = [MOCK_ADDRESS], +): { type: string; accounts: string[] } { + return { + type: keyringType, + accounts, + }; +} + +interface Identity { + name: string; + address: string; + lastSelected?: number; +} + +function createMockPreferenceControllerState( + identities: Identity[] = [{ name: 'Account 1', address: MOCK_ADDRESS }], + selectedAddress: string = MOCK_ADDRESS, +): { + identities: { + [key: string]: { name: string; lastSelected?: number; address: string }; + }; + selectedAddress: string; +} { + const state: { + identities: { + [key: string]: { name: string; lastSelected?: number; address: string }; + }; + selectedAddress: string; + } = { + identities: {}, + selectedAddress, + }; + + identities.forEach(({ address, name, lastSelected }) => { + state.identities[address] = { + address, + name, + lastSelected, + }; + }); + + return state; +} + +function expectedInternalAccount( + address: string, + keyringType: string, + nickname: string, + lastSelected?: number, +): InternalAccount { + return { + address, + id: addressToUUID(address), + metadata: { + keyring: { + type: keyringType, + }, + lastSelected: lastSelected ? expect.any(Number) : null, + }, + name: nickname, + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }; +} + +function createMockState( + keyrings: { + type: string; + accounts: string[]; + }[] = [createMockKeyring('HD Key Tree')], + preferenceState: { + identities: { + [key: string]: { + lastSelected?: number; + name: string; + address: string; + }; + }; + selectedAddress: string; + } = createMockPreferenceControllerState(), +) { + const data = { + KeyringController: { + keyrings, + }, + PreferencesController: { + ...preferenceState, + }, + }; + + return data; +} + +describe('migration #96', () => { + it('updates the version metadata', async () => { + const oldStorage = { + meta: { version: 96 }, + data: createMockState(), + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.meta).toStrictEqual({ version: 97 }); + }); + + describe('createDefaultAccountsController', () => { + it('creates default state for accounts controller', async () => { + const oldData = createMockState(); + + const oldStorage = { + meta: { version: 96 }, + data: oldData, + }; + + const newStorage = await migrate(oldStorage); + + const expectedUUID = addressToUUID(MOCK_ADDRESS); + const resultInternalAccount = expectedInternalAccount( + MOCK_ADDRESS, + 'HD Key Tree', + 'Account 1', + ); + + expect(newStorage.data.AccountsController).toStrictEqual({ + internalAccounts: { + accounts: { + [expectedUUID]: resultInternalAccount, + }, + selectedAccount: expectedUUID, + }, + }); + }); + }); + + describe('moveIdentitiesToAccountsController', () => { + const expectedUUID = addressToUUID(MOCK_ADDRESS); + it('should move the identities into AccountsController as internal accounts', async () => { + const oldData = createMockState(); + + const oldStorage = { + meta: { version: 96 }, + data: oldData, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.data).toStrictEqual({ + AccountsController: { + internalAccounts: { + accounts: { + [expectedUUID]: expectedInternalAccount( + MOCK_ADDRESS, + 'HD Key Tree', + `${keyringTypeToName('HD Key Tree')} 1`, + ), + }, + selectedAccount: expectedUUID, + }, + }, + KeyringController: expect.any(Object), + PreferencesController: expect.any(Object), + }); + }); + + it.each( + Object.values(KeyringType).map((keyring) => [ + keyring, + createMockKeyring(keyring), + ]), + )( + 'should assign the correct keyring type for each identity', + async (keyringType, keyring) => { + const oldData = createMockState( + [keyring], + createMockPreferenceControllerState( + [ + { + name: `${keyringTypeToName(keyringType)} 1`, + address: MOCK_ADDRESS, + }, + ], + MOCK_ADDRESS, + ), + ); + const oldStorage = { + meta: { version: 96 }, + data: oldData, + }; + const newStorage = await migrate(oldStorage); + + expect(newStorage.data).toStrictEqual({ + KeyringController: expect.any(Object), + PreferencesController: expect.any(Object), + AccountsController: { + internalAccounts: expect.objectContaining({ + accounts: { + [expectedUUID]: expectedInternalAccount( + MOCK_ADDRESS, + keyringType, + `${keyringTypeToName(keyringType)} 1`, + ), + }, + selectedAccount: expectedUUID, + }), + }, + }); + }, + ); + + it('should keep the same name from the idententities', async () => { + const oldData = createMockState( + [createMockKeyring('HD Key Tree')], + createMockPreferenceControllerState([ + { name: 'a random name', address: MOCK_ADDRESS }, + ]), + ); + const oldStorage = { + meta: { version: 96 }, + data: oldData, + }; + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual({ + KeyringController: expect.any(Object), + PreferencesController: expect.any(Object), + AccountsController: { + internalAccounts: { + accounts: { + [expectedUUID]: expectedInternalAccount( + MOCK_ADDRESS, + 'HD Key Tree', + `a random name`, + ), + }, + selectedAccount: expectedUUID, + }, + }, + }); + }); + }); + + describe('moveSelectedAddressToAccountsController', () => { + it('should select the same account as the selected address', async () => { + const oldData = createMockState(); + const oldStorage = { + meta: { version: 96 }, + data: oldData, + }; + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual({ + KeyringController: expect.any(Object), + PreferencesController: expect.any(Object), + AccountsController: { + internalAccounts: { + accounts: expect.any(Object), + selectedAccount: addressToUUID(MOCK_ADDRESS), + }, + }, + }); + }); + + it("should leave selectedAccount as empty is there aren't any selectedAddress", async () => { + const oldData = createMockState(); + const oldStorage = { + meta: { version: 96 }, + data: oldData, + }; + const newStorage = await migrate(oldStorage); + expect(newStorage.data).toStrictEqual({ + KeyringController: expect.any(Object), + PreferencesController: expect.any(Object), + AccountsController: { + internalAccounts: { + accounts: expect.any(Object), + selectedAccount: addressToUUID(MOCK_ADDRESS), + }, + }, + }); + }); + + it('should throw an error if there is a selectedAddress and it is not found in the accounts map', async () => { + const oldData = createMockState(); + const oldStorage = { + meta: { version: 96 }, + data: oldData, + }; + expect(await migrate(oldStorage)).toThrowError( + `Account Id ${addressToUUID(MOCK_ADDRESS)} not found`, + ); + }); + }); + + describe('removeIdentitiesAndSelectedAddressFromPreferencesController', () => { + it('removes identities and selectedAddress in PreferenceController state', async () => { + const oldData = createMockState(); + + const oldStorage = { + meta: { version: 96 }, + data: oldData, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.data).toStrictEqual({ + AccountsController: expect.any(Object), + KeyringController: expect.any(Object), + PreferencesController: {}, + }); + }); + }); +}); diff --git a/app/scripts/migrations/097.ts b/app/scripts/migrations/097.ts new file mode 100644 index 000000000000..3a5e3c991bb7 --- /dev/null +++ b/app/scripts/migrations/097.ts @@ -0,0 +1,134 @@ +import { InternalAccount } from '@metamask/eth-snap-keyring'; +import { sha256FromString } from 'ethereumjs-util'; +import { v4 as uuid } from 'uuid'; +import { cloneDeep } from 'lodash'; + +type VersionedData = { + meta: { version: number }; + data: Record; +}; + +export const version = 97; + +/** + * This migration does the following: + * + * - Creates a default state for AccountsController. + * - Moves identites and selectedAddress from the PreferencesController to the AccountsController state. + * - Removes identites and selectedAddress from the PreferencesController + * + * @param originalVersionedData - Versioned MetaMask extension state, exactly what we persist to dist. + * @param originalVersionedData.meta - State metadata. + * @param originalVersionedData.meta.version - The current state version. + * @param originalVersionedData.data - The persisted MetaMask state, keyed by controller. + * @returns Updated versioned MetaMask extension state. + */ +export async function migrate( + originalVersionedData: VersionedData, +): Promise { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + migrateData(versionedData.data); + return versionedData; +} + +function migrateData(state: Record): void { + createDefaultAccountsController(state); + moveIdentitiesToAccountsController(state); + moveSelectedAddressToAccountsController(state); + removeIdentitiesAndSelectedAddressFromPreferencesController(state); +} + +function createDefaultAccountsController(state: Record) { + state.AccountsController = { + internalAccounts: { + accounts: {}, + selectedAccount: '', + }, + }; +} + +function moveIdentitiesToAccountsController(state: Record) { + const identities: { + [key: string]: { + name: string; + lastSelected: number; + }; + } = state.PreferencesController?.identities || {}; + + const { keyrings }: { keyrings: { type: string; accounts: string[] }[] } = + state.KeyringController; + + if (Object.keys(identities).length === 0) { + return; + } + + const accounts: Record = {}; + + keyrings.forEach((keyring) => { + keyring.accounts.forEach((address) => { + const expectedId = uuid({ + random: sha256FromString(address).slice(0, 16), + }); + + const identity = identities[address]; + + if (!identity) { + throw new Error( + `Missing account name for ${address} in PreferencesControllerState`, + ); + } + + accounts[expectedId] = { + address, + id: expectedId, + name: identity.name, + options: {}, + metadata: { + lastSelected: identity.lastSelected ?? null, + keyring: { + type: keyring.type, + }, + }, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }; + }); + }); + + state.AccountsController.internalAccounts.accounts = accounts; +} + +function moveSelectedAddressToAccountsController(state: Record) { + const selectedAddress = state.PreferencesController?.selectedAddress; + + const selectedAccount = Object.values( + state.AccountsController.internalAccounts.accounts, + ).find((account: InternalAccount) => { + return account.address.toLowerCase() === selectedAddress.toLowerCase(); + }) as InternalAccount; + + if (selectedAccount) { + state.AccountsController.internalAccounts = { + ...state.AccountsController.internalAccounts, + selectedAccount: selectedAccount.id, + }; + } +} + +function removeIdentitiesAndSelectedAddressFromPreferencesController( + state: Record, +) { + delete state.PreferencesController.identities; + delete state.PreferencesController.selectedAddress; +} diff --git a/ui/components/multichain/app-header/app-header.js b/ui/components/multichain/app-header/app-header.js index fbc925482664..7dbc4d2ca017 100644 --- a/ui/components/multichain/app-header/app-header.js +++ b/ui/components/multichain/app-header/app-header.js @@ -98,7 +98,7 @@ export const AppHeader = ({ location }) => { const testNetworkBackgroundColor = useSelector(getTestNetworkBackgroundColor); // Used for copy button - const currentAddress = selectedAddress; + const { address: currentAddress } = internalAccount; const checksummedCurrentAddress = toChecksumHexAddress(currentAddress); const [copied, handleCopy] = useCopyToClipboard(MINUTE); From f1d4f9979ff3b6bb06938d19a4311a303f815420 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Fri, 25 Aug 2023 17:51:53 +0800 Subject: [PATCH 048/235] feat: add migration to migrations/index.js --- app/scripts/migrations/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index da4e1029e57f..cd69b19909bb 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -101,6 +101,7 @@ import * as m093 from './093'; import * as m094 from './094'; import * as m095 from './095'; import * as m096 from './096'; +import * as m097 from './097'; const migrations = [ m002, @@ -199,5 +200,6 @@ const migrations = [ m094, m095, m096, + m097, ]; export default migrations; From f9a2d0533f3250740edd4def1b70fafa7b83b6f5 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Fri, 25 Aug 2023 23:54:08 +0800 Subject: [PATCH 049/235] fix: account-detail unit test --- .../multichain/account-details/account-details.test.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/ui/components/multichain/account-details/account-details.test.js b/ui/components/multichain/account-details/account-details.test.js index 061eaf0f3bb3..6843021fde0b 100644 --- a/ui/components/multichain/account-details/account-details.test.js +++ b/ui/components/multichain/account-details/account-details.test.js @@ -11,7 +11,6 @@ import { clearAccountDetails, exportAccount, hideWarning, - setAccountDetailsAddress, } from '../../../store/actions'; import configureStore from '../../../store/store'; import { AccountDetailsKey } from './account-details-key'; @@ -28,14 +27,12 @@ describe('AccountDetails', () => { const mockClearAccountDetails = jest.fn(); const mockExportAccount = jest.fn().mockResolvedValue(true); const mockHideWarning = jest.fn(); - const mockSetAccountDetailsAddress = jest.fn(); beforeEach(() => { setAccountDetailsAccountId.mockReturnValue(mockSetAccountDetailsAccountId); clearAccountDetails.mockReturnValue(mockClearAccountDetails); exportAccount.mockReturnValue(mockExportAccount); hideWarning.mockReturnValue(mockHideWarning); - setAccountDetailsAddress.mockReturnValue(mockSetAccountDetailsAddress); }); afterEach(() => jest.clearAllMocks()); From 3f5fbec63c204817d7e7605997e6924a378430f4 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Sat, 26 Aug 2023 02:03:01 +0800 Subject: [PATCH 050/235] fix: remove identities in accounts controller --- app/scripts/controllers/accounts-controller.ts | 12 +++--------- app/scripts/metamask-controller.js | 1 - 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index d20235dcb291..8e8bd3615862 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -97,12 +97,9 @@ export default class AccountsController extends BaseControllerV2< #snapController: SnapController; ///: END:ONLY_INCLUDE_IN(keyring-snaps) - identities: any; - constructor({ messenger, state, - identities, keyringController, ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) snapController, @@ -116,7 +113,6 @@ export default class AccountsController extends BaseControllerV2< ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) snapController: SnapController; ///: END:ONLY_INCLUDE_IN(keyring-snaps) - identities: any; onKeyringStateChange: ( listener: (keyringState: KeyringControllerState) => void, ) => void; @@ -140,7 +136,6 @@ export default class AccountsController extends BaseControllerV2< ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) this.#snapController = snapController; ///: END:ONLY_INCLUDE_IN(keyring-snaps) - this.identities = identities; ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) onSnapStateChange(async (snapState: SnapControllerState) => { @@ -266,6 +261,7 @@ export default class AccountsController extends BaseControllerV2< // keyring type map. const keyringTypes = new Map(); + const previousAccounts = this.state.internalAccounts.accounts; const accounts: Record = [ ...legacyAccounts, @@ -283,18 +279,16 @@ export default class AccountsController extends BaseControllerV2< keyringTypes.set(keyringTypeName, 1); } - const existingAccount = this.getAccount(internalAccount.id); + const existingAccount = previousAccounts[internalAccount.id]; internalAccountMap[internalAccount.id] = { ...internalAccount, - // use the account name from the identities if it exists name: existingAccount ? existingAccount.name : `${keyringTypeName} ${keyringAccountIndex + 1}`, metadata: { ...internalAccount.metadata, - lastSelected: this.getAccount(internalAccount.id)?.metadata - ?.lastSelected, + lastSelected: existingAccount?.metadata?.lastSelected, }, }; diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 4f5aa5618ed8..8edaf1b2dd09 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1069,7 +1069,6 @@ export default class MetamaskController extends EventEmitter { ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) snapController: this.snapController, ///: END:ONLY_INCLUDE_IN - identities: initState.PreferencesController?.identities, onKeyringStateChange: keyringControllerMessenger.subscribe.bind( keyringControllerMessenger, 'KeyringController:stateChange', From 945997f16ab436c7298defaf7230fa7cb6e8d644 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Sat, 26 Aug 2023 02:03:28 +0800 Subject: [PATCH 051/235] fix: app header initial internalAccount address may not be defined during onboarding --- .../phishing-detection.spec.js | 315 ------------------ .../multichain/app-header/app-header.js | 2 +- 2 files changed, 1 insertion(+), 316 deletions(-) delete mode 100644 test/e2e/tests/phishing-controller/phishing-detection.spec.js diff --git a/test/e2e/tests/phishing-controller/phishing-detection.spec.js b/test/e2e/tests/phishing-controller/phishing-detection.spec.js deleted file mode 100644 index 2e29a2411ac3..000000000000 --- a/test/e2e/tests/phishing-controller/phishing-detection.spec.js +++ /dev/null @@ -1,315 +0,0 @@ -const { strict: assert } = require('assert'); - -const { convertToHexValue, withFixtures, openDapp } = require('../../helpers'); -const FixtureBuilder = require('../../fixture-builder'); -const { - METAMASK_HOTLIST_DIFF_URL, - METAMASK_STALELIST_URL, - BlockProvider, -} = require('./helpers'); - -const { - setupPhishingDetectionMocks, - mockConfigLookupOnWarningPage, -} = require('./mocks'); - -describe('Phishing Detection', function () { - const ganacheOptions = { - accounts: [ - { - secretKey: - '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', - balance: convertToHexValue(25000000000000000000), - }, - ], - }; - - describe('Phishing Detection Mock', function () { - it('should be updated to use v1 of the API', function () { - // Update the fixture in phishing-controller/mocks.js if this test fails - assert.equal( - METAMASK_STALELIST_URL, - 'https://phishing-detection.metafi.codefi.network/v1/stalelist', - ); - assert.equal( - METAMASK_HOTLIST_DIFF_URL, - 'https://phishing-detection.metafi.codefi.network/v1/diffsSince', - ); - }); - }); - - it('should display the MetaMask Phishing Detection page and take the user to the blocked page if they continue', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions, - title: this.test.title, - testSpecificMock: async (mockServer) => { - return setupPhishingDetectionMocks(mockServer, { - blockProvider: BlockProvider.MetaMask, - blocklist: ['127.0.0.1'], - }); - }, - dapp: true, - failOnConsoleError: false, - }, - async ({ driver }) => { - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - await openDapp(driver); - await driver.clickElement({ - text: 'continue to the site.', - }); - const header = await driver.findElement('h1'); - assert.equal(await header.getText(), 'E2E Test Dapp'); - }, - ); - }); - - it('should display the MetaMask Phishing Detection page in an iframe and take the user to the blocked page if they continue', async function () { - const DAPP_WITH_IFRAMED_PAGE_ON_BLOCKLIST = 'http://localhost:8080/'; - const IFRAMED_HOSTNAME = '127.0.0.1'; - - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions, - title: this.test.title, - testSpecificMock: async (mockServer) => { - return setupPhishingDetectionMocks(mockServer, { - blockProvider: BlockProvider.MetaMask, - blocklist: [IFRAMED_HOSTNAME], - }); - }, - dapp: true, - dappPaths: ['mock-page-with-iframe'], - dappOptions: { - numberOfDapps: 2, - }, - failOnConsoleError: false, - }, - async ({ driver }) => { - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - await driver.openNewPage(DAPP_WITH_IFRAMED_PAGE_ON_BLOCKLIST); - - const iframe = await driver.findElement('iframe'); - - await driver.switchToFrame(iframe); - await driver.clickElement({ - text: 'Open this warning in a new tab', - }); - await driver.switchToWindowWithTitle('MetaMask Phishing Detection'); - await driver.clickElement({ - text: 'continue to the site.', - }); - const header = await driver.findElement('h1'); - assert.equal(await header.getText(), 'E2E Test Dapp'); - }, - ); - }); - - it('should display the MetaMask Phishing Detection page in an iframe but should NOT take the user to the blocked page if it is not an accessible resource', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions, - title: this.test.title, - testSpecificMock: async (mockServer) => { - return setupPhishingDetectionMocks(mockServer, { - blockProvider: BlockProvider.MetaMask, - blocklist: ['127.0.0.1'], - }); - }, - dapp: true, - dappPaths: ['mock-page-with-disallowed-iframe'], - dappOptions: { - numberOfDapps: 2, - }, - failOnConsoleError: false, - }, - async ({ driver }) => { - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - await driver.openNewPage( - `http://localhost:8080?extensionUrl=${driver.extensionUrl}`, - ); - - const iframe = await driver.findElement('iframe'); - - await driver.switchToFrame(iframe); - await driver.clickElement({ - text: 'Open this warning in a new tab', - }); - await driver.switchToWindowWithTitle('MetaMask Phishing Detection'); - await driver.clickElement({ - text: 'continue to the site.', - }); - - // Ensure we're not on the wallet home page - await driver.assertElementNotPresent('[data-testid="wallet-balance"]'); - }, - ); - }); - - it('should navigate the user to eth-phishing-detect to dispute a block if the phishing warning page fails to identify the source', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions, - title: this.test.title, - testSpecificMock: (mockServer) => { - setupPhishingDetectionMocks(mockServer, { - blockProvider: BlockProvider.MetaMask, - blocklist: ['127.0.0.1'], - }); - mockConfigLookupOnWarningPage(mockServer, { statusCode: 500 }); - }, - dapp: true, - failOnConsoleError: false, - }, - async ({ driver }) => { - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - await openDapp(driver); - - await driver.clickElement({ text: 'report a detection problem.' }); - - // wait for page to load before checking URL. - await driver.findElement({ - text: `Empty page by ${BlockProvider.MetaMask}`, - }); - assert.equal( - await driver.getCurrentUrl(), - `https://github.com/MetaMask/eth-phishing-detect/issues/new?title=[Legitimate%20Site%20Blocked]%20127.0.0.1&body=http%3A%2F%2F127.0.0.1%3A8080%2F`, - ); - }, - ); - }); - - it('should navigate the user to eth-phishing-detect to dispute a block from MetaMask', async function () { - // Must be site on actual eth-phishing-detect blocklist - const phishingSite = new URL('https://test.metamask-phishing.io'); - - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions, - title: this.test.title, - testSpecificMock: async (mockServer) => { - return setupPhishingDetectionMocks(mockServer, { - blockProvider: BlockProvider.MetaMask, - blocklist: [phishingSite.hostname], - }); - }, - dapp: true, - failOnConsoleError: false, - }, - async ({ driver }) => { - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - await driver.openNewPage(phishingSite.href); - - await driver.clickElement({ text: 'report a detection problem.' }); - - // wait for page to load before checking URL. - await driver.findElement({ - text: `Empty page by ${BlockProvider.MetaMask}`, - }); - assert.equal( - await driver.getCurrentUrl(), - `https://github.com/MetaMask/eth-phishing-detect/issues/new?title=[Legitimate%20Site%20Blocked]%20${encodeURIComponent( - phishingSite.hostname, - )}&body=${encodeURIComponent(phishingSite.href)}`, - ); - }, - ); - }); - - it('should navigate the user to PhishFort to dispute a Phishfort Block', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions, - title: this.test.title, - testSpecificMock: async (mockServer) => { - return setupPhishingDetectionMocks(mockServer, { - blockProvider: BlockProvider.PhishFort, - blocklist: ['127.0.0.1'], - }); - }, - dapp: true, - failOnConsoleError: false, - }, - async ({ driver }) => { - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - await driver.openNewPage('http://127.0.0.1:8080'); - - await driver.clickElement({ text: 'report a detection problem.' }); - - // wait for page to load before checking URL. - await driver.findElement({ - text: `Empty page by ${BlockProvider.PhishFort}`, - }); - assert.equal( - await driver.getCurrentUrl(), - `https://github.com/phishfort/phishfort-lists/issues/new?title=[Legitimate%20Site%20Blocked]%20127.0.0.1&body=http%3A%2F%2F127.0.0.1%3A8080%2F`, - ); - }, - ); - }); - - it('should open a new extension expanded view when clicking back to safety button', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions, - title: this.test.title, - testSpecificMock: async (mockServer) => { - return setupPhishingDetectionMocks(mockServer, { - blockProvider: BlockProvider.MetaMask, - blocklist: ['127.0.0.1'], - }); - }, - dapp: true, - dappPaths: ['mock-page-with-disallowed-iframe'], - dappOptions: { - numberOfDapps: 2, - }, - failOnConsoleError: false, - }, - async ({ driver }) => { - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - await driver.openNewPage( - `http://localhost:8080?extensionUrl=${driver.extensionUrl}`, - ); - - const iframe = await driver.findElement('iframe'); - - await driver.switchToFrame(iframe); - await driver.clickElement({ - text: 'Open this warning in a new tab', - }); - await driver.switchToWindowWithTitle('MetaMask Phishing Detection'); - await driver.clickElement({ - text: 'Back to safety', - }); - - // Ensure we're redirected to wallet home page - const homePage = await driver.findElement('.home__main-view'); - const homePageDisplayed = await homePage.isDisplayed(); - - assert.equal(homePageDisplayed, true); - }, - ); - }); -}); diff --git a/ui/components/multichain/app-header/app-header.js b/ui/components/multichain/app-header/app-header.js index 7dbc4d2ca017..f187448a153f 100644 --- a/ui/components/multichain/app-header/app-header.js +++ b/ui/components/multichain/app-header/app-header.js @@ -98,7 +98,7 @@ export const AppHeader = ({ location }) => { const testNetworkBackgroundColor = useSelector(getTestNetworkBackgroundColor); // Used for copy button - const { address: currentAddress } = internalAccount; + const currentAddress = internalAccount?.address; const checksummedCurrentAddress = toChecksumHexAddress(currentAddress); const [copied, handleCopy] = useCopyToClipboard(MINUTE); From 999c350f14274e9b814f179051c6b6e1e0997ea8 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Sat, 26 Aug 2023 14:21:39 +0800 Subject: [PATCH 052/235] fix: update migrationcd --- app/scripts/migrations/097.test.ts | 91 +---- app/scripts/migrations/097.ts | 70 ++-- test/e2e/nft/erc721-interaction.spec.js | 494 ------------------------ test/e2e/run-all.js | 6 +- test/e2e/tests/edit-gas-fee.spec.js | 270 ------------- test/e2e/tests/gas-estimates.spec.js | 250 ------------ test/e2e/tests/import-flow.spec.js | 3 + 7 files changed, 38 insertions(+), 1146 deletions(-) delete mode 100644 test/e2e/nft/erc721-interaction.spec.js delete mode 100644 test/e2e/tests/edit-gas-fee.spec.js delete mode 100644 test/e2e/tests/gas-estimates.spec.js diff --git a/app/scripts/migrations/097.test.ts b/app/scripts/migrations/097.test.ts index 8c758aa178c8..c8732fba6cb8 100644 --- a/app/scripts/migrations/097.test.ts +++ b/app/scripts/migrations/097.test.ts @@ -1,8 +1,6 @@ import { v4 as uuid } from 'uuid'; import { sha256FromString } from 'ethereumjs-util'; import { InternalAccount } from '@metamask/eth-snap-keyring'; -import { keyringTypeToName } from '../controllers/accounts-controller'; -import { KeyringType } from '../../../shared/constants/keyring'; import { migrate } from './097'; const MOCK_ADDRESS = '0x0'; @@ -13,16 +11,6 @@ function addressToUUID(address: string): string { }); } -function createMockKeyring( - keyringType: string, - accounts: string[] = [MOCK_ADDRESS], -): { type: string; accounts: string[] } { - return { - type: keyringType, - accounts, - }; -} - interface Identity { name: string; address: string; @@ -61,7 +49,6 @@ function createMockPreferenceControllerState( function expectedInternalAccount( address: string, - keyringType: string, nickname: string, lastSelected?: number, ): InternalAccount { @@ -70,7 +57,7 @@ function expectedInternalAccount( id: addressToUUID(address), metadata: { keyring: { - type: keyringType, + type: 'HD Key Tree', }, lastSelected: lastSelected ? expect.any(Number) : null, }, @@ -92,10 +79,6 @@ function expectedInternalAccount( } function createMockState( - keyrings: { - type: string; - accounts: string[]; - }[] = [createMockKeyring('HD Key Tree')], preferenceState: { identities: { [key: string]: { @@ -108,9 +91,6 @@ function createMockState( } = createMockPreferenceControllerState(), ) { const data = { - KeyringController: { - keyrings, - }, PreferencesController: { ...preferenceState, }, @@ -145,7 +125,6 @@ describe('migration #96', () => { const expectedUUID = addressToUUID(MOCK_ADDRESS); const resultInternalAccount = expectedInternalAccount( MOCK_ADDRESS, - 'HD Key Tree', 'Account 1', ); @@ -178,66 +157,18 @@ describe('migration #96', () => { accounts: { [expectedUUID]: expectedInternalAccount( MOCK_ADDRESS, - 'HD Key Tree', - `${keyringTypeToName('HD Key Tree')} 1`, + `Account 1`, ), }, selectedAccount: expectedUUID, }, }, - KeyringController: expect.any(Object), PreferencesController: expect.any(Object), }); }); - it.each( - Object.values(KeyringType).map((keyring) => [ - keyring, - createMockKeyring(keyring), - ]), - )( - 'should assign the correct keyring type for each identity', - async (keyringType, keyring) => { - const oldData = createMockState( - [keyring], - createMockPreferenceControllerState( - [ - { - name: `${keyringTypeToName(keyringType)} 1`, - address: MOCK_ADDRESS, - }, - ], - MOCK_ADDRESS, - ), - ); - const oldStorage = { - meta: { version: 96 }, - data: oldData, - }; - const newStorage = await migrate(oldStorage); - - expect(newStorage.data).toStrictEqual({ - KeyringController: expect.any(Object), - PreferencesController: expect.any(Object), - AccountsController: { - internalAccounts: expect.objectContaining({ - accounts: { - [expectedUUID]: expectedInternalAccount( - MOCK_ADDRESS, - keyringType, - `${keyringTypeToName(keyringType)} 1`, - ), - }, - selectedAccount: expectedUUID, - }), - }, - }); - }, - ); - - it('should keep the same name from the idententities', async () => { + it('should keep the same name from the identities', async () => { const oldData = createMockState( - [createMockKeyring('HD Key Tree')], createMockPreferenceControllerState([ { name: 'a random name', address: MOCK_ADDRESS }, ]), @@ -248,14 +179,12 @@ describe('migration #96', () => { }; const newStorage = await migrate(oldStorage); expect(newStorage.data).toStrictEqual({ - KeyringController: expect.any(Object), PreferencesController: expect.any(Object), AccountsController: { internalAccounts: { accounts: { [expectedUUID]: expectedInternalAccount( MOCK_ADDRESS, - 'HD Key Tree', `a random name`, ), }, @@ -275,7 +204,6 @@ describe('migration #96', () => { }; const newStorage = await migrate(oldStorage); expect(newStorage.data).toStrictEqual({ - KeyringController: expect.any(Object), PreferencesController: expect.any(Object), AccountsController: { internalAccounts: { @@ -294,7 +222,6 @@ describe('migration #96', () => { }; const newStorage = await migrate(oldStorage); expect(newStorage.data).toStrictEqual({ - KeyringController: expect.any(Object), PreferencesController: expect.any(Object), AccountsController: { internalAccounts: { @@ -304,17 +231,6 @@ describe('migration #96', () => { }, }); }); - - it('should throw an error if there is a selectedAddress and it is not found in the accounts map', async () => { - const oldData = createMockState(); - const oldStorage = { - meta: { version: 96 }, - data: oldData, - }; - expect(await migrate(oldStorage)).toThrowError( - `Account Id ${addressToUUID(MOCK_ADDRESS)} not found`, - ); - }); }); describe('removeIdentitiesAndSelectedAddressFromPreferencesController', () => { @@ -330,7 +246,6 @@ describe('migration #96', () => { expect(newStorage.data).toStrictEqual({ AccountsController: expect.any(Object), - KeyringController: expect.any(Object), PreferencesController: {}, }); }); diff --git a/app/scripts/migrations/097.ts b/app/scripts/migrations/097.ts index 3a5e3c991bb7..568dc2206863 100644 --- a/app/scripts/migrations/097.ts +++ b/app/scripts/migrations/097.ts @@ -52,58 +52,46 @@ function moveIdentitiesToAccountsController(state: Record) { const identities: { [key: string]: { name: string; + address: string; lastSelected: number; }; } = state.PreferencesController?.identities || {}; - const { keyrings }: { keyrings: { type: string; accounts: string[] }[] } = - state.KeyringController; - if (Object.keys(identities).length === 0) { return; } const accounts: Record = {}; - keyrings.forEach((keyring) => { - keyring.accounts.forEach((address) => { - const expectedId = uuid({ - random: sha256FromString(address).slice(0, 16), - }); - - const identity = identities[address]; - - if (!identity) { - throw new Error( - `Missing account name for ${address} in PreferencesControllerState`, - ); - } + Object.values(identities).forEach((identity) => { + const expectedId = uuid({ + random: sha256FromString(identity.address).slice(0, 16), + }); - accounts[expectedId] = { - address, - id: expectedId, - name: identity.name, - options: {}, - metadata: { - lastSelected: identity.lastSelected ?? null, - keyring: { - type: keyring.type, - }, + accounts[expectedId] = { + address: identity.address, + id: expectedId, + name: identity.name, + options: {}, + metadata: { + lastSelected: identity.lastSelected ?? null, + keyring: { + type: 'HD Key Tree', }, - supportedMethods: [ - 'personal_sign', - 'eth_sendTransaction', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v2', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', - }; - }); + }, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }; }); state.AccountsController.internalAccounts.accounts = accounts; @@ -121,7 +109,7 @@ function moveSelectedAddressToAccountsController(state: Record) { if (selectedAccount) { state.AccountsController.internalAccounts = { ...state.AccountsController.internalAccounts, - selectedAccount: selectedAccount.id, + selectedAccount: selectedAccount.id ?? '', }; } } diff --git a/test/e2e/nft/erc721-interaction.spec.js b/test/e2e/nft/erc721-interaction.spec.js deleted file mode 100644 index e979a8530600..000000000000 --- a/test/e2e/nft/erc721-interaction.spec.js +++ /dev/null @@ -1,494 +0,0 @@ -const { strict: assert } = require('assert'); -const { convertToHexValue, withFixtures, openDapp } = require('../helpers'); -const { SMART_CONTRACTS } = require('../seeder/smart-contracts'); -const FixtureBuilder = require('../fixture-builder'); - -describe('ERC721 NFTs testdapp interaction', function () { - const smartContract = SMART_CONTRACTS.NFTS; - const ganacheOptions = { - accounts: [ - { - secretKey: - '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', - balance: convertToHexValue(25000000000000000000), - }, - ], - }; - - it('should prompt users to add their NFTs to their wallet (one by one)', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .build(), - ganacheOptions, - smartContract, - title: this.test.title, - failOnConsoleError: false, - }, - async ({ driver, _, contractRegistry }) => { - const contract = contractRegistry.getContractAddress(smartContract); - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - - // Open Dapp and wait for deployed contract - await openDapp(driver, contract); - await driver.findClickableElement('#deployButton'); - - // mint NFT - await driver.fill('#mintAmountInput', '5'); - await driver.clickElement({ text: 'Mint', tag: 'button' }); - - // Notification - await driver.waitUntilXWindowHandles(3); - let windowHandles = await driver.getAllWindowHandles(); - const [extension] = windowHandles; - await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); - await driver.waitForSelector({ - css: '.confirm-page-container-summary__action__name', - text: 'Deposit', - }); - await driver.clickElement({ text: 'Confirm', tag: 'button' }); - await driver.waitUntilXWindowHandles(2); - await driver.switchToWindow(extension); - await driver.clickElement('[data-testid="home__activity-tab"]'); - const transactionItem = await driver.waitForSelector({ - css: '[data-testid="activity-list-item-action"]', - text: 'Deposit', - }); - assert.equal(await transactionItem.isDisplayed(), true); - - // verify the mint transaction has finished - await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); - const nftsMintStatus = await driver.findElement({ - css: '#nftsStatus', - text: 'Mint completed', - }); - assert.equal(await nftsMintStatus.isDisplayed(), true); - - // watch 3 of the nfts - await driver.clickElement({ text: 'Watch NFT 1', tag: 'button' }); - await driver.clickElement({ text: 'Watch NFT 2', tag: 'button' }); - await driver.clickElement({ text: 'Watch NFT 3', tag: 'button' }); - - await driver.waitUntilXWindowHandles(3); - windowHandles = await driver.getAllWindowHandles(); - await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); - - // confirm watchNFT - await driver.waitForSelector({ - css: '.mm-text--heading-lg', - text: 'Add suggested NFTs', - }); - await driver.clickElement({ text: 'Add NFTs', tag: 'button' }); - await driver.switchToWindow(extension); - await driver.clickElement({ text: 'NFTs', tag: 'button' }); - await driver.findElement({ text: 'TestDappNFTs (3)' }); - const nftsListItemsFirstCheck = await driver.findElements( - '.nft-item__container', - ); - assert.equal(nftsListItemsFirstCheck.length, 3); - - await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); - await driver.clickElement({ text: 'Watch NFT 4', tag: 'button' }); - await driver.clickElement({ text: 'Watch NFT 5', tag: 'button' }); - await driver.clickElement({ text: 'Watch NFT 6', tag: 'button' }); - - await driver.waitUntilXWindowHandles(3); - windowHandles = await driver.getAllWindowHandles(); - await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); - - // confirm watchNFT - await driver.waitForSelector({ - css: '.mm-text--heading-lg', - text: 'Add suggested NFTs', - }); - await driver.clickElement({ text: 'Add NFTs', tag: 'button' }); - await driver.switchToWindow(extension); - await driver.clickElement({ text: 'NFTs', tag: 'button' }); - await driver.findElement({ text: 'TestDappNFTs (6)' }); - const nftsListItemsSecondCheck = await driver.findElements( - '.nft-item__container', - ); - assert.equal(nftsListItemsSecondCheck.length, 6); - }, - ); - }); - - it('should prompt users to add their NFTs to their wallet (all at once)', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .build(), - ganacheOptions, - smartContract, - title: this.test.title, - failOnConsoleError: false, - }, - async ({ driver, _, contractRegistry }) => { - const contract = contractRegistry.getContractAddress(smartContract); - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - - // Open Dapp and wait for deployed contract - await openDapp(driver, contract); - await driver.findClickableElement('#deployButton'); - - // mint NFT - await driver.fill('#mintAmountInput', '5'); - await driver.clickElement({ text: 'Mint', tag: 'button' }); - - // Notification - await driver.waitUntilXWindowHandles(3); - let windowHandles = await driver.getAllWindowHandles(); - const [extension] = windowHandles; - await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); - await driver.waitForSelector({ - css: '.confirm-page-container-summary__action__name', - text: 'Deposit', - }); - await driver.clickElement({ text: 'Confirm', tag: 'button' }); - await driver.waitUntilXWindowHandles(2); - await driver.switchToWindow(extension); - await driver.clickElement('[data-testid="home__activity-tab"]'); - const transactionItem = await driver.waitForSelector({ - css: '[data-testid="activity-list-item-action"]', - text: 'Deposit', - }); - assert.equal(await transactionItem.isDisplayed(), true); - // verify the mint transaction has finished - await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); - const nftsMintStatus = await driver.findElement({ - css: '#nftsStatus', - text: 'Mint completed', - }); - assert.equal(await nftsMintStatus.isDisplayed(), true); - - // watch all nfts - await driver.clickElement({ text: 'Watch all NFTs', tag: 'button' }); - - await driver.waitUntilXWindowHandles(3); - windowHandles = await driver.getAllWindowHandles(); - await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); - - // confirm watchNFT - await driver.waitForSelector({ - css: '.mm-text--heading-lg', - text: 'Add suggested NFTs', - }); - - await driver.findElements('.confirm-add-suggested-nft__nft-list-item'); - const suggestedNftListItems = await driver.findElements( - '.confirm-add-suggested-nft__nft-list-item', - ); - // there are 6 nfts to add because one is minted as part of the fixture - assert.equal(suggestedNftListItems.length, 6); - - // remove one nft from the list - const removeButtons = await driver.findElements( - '.confirm-add-suggested-nft__nft-remove', - ); - await removeButtons[0].click(); - - await driver.clickElement({ text: 'Add NFTs', tag: 'button' }); - await driver.switchToWindow(extension); - await driver.clickElement({ text: 'NFTs', tag: 'button' }); - await driver.findElement({ text: 'TestDappNFTs (5)' }); - const nftsListItemsSecondCheck = await driver.findElements( - '.nft-item__container', - ); - - assert.equal(nftsListItemsSecondCheck.length, 5); - }, - ); - }); - - it('should transfer a single ERC721 NFT from one account to another', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .build(), - ganacheOptions, - smartContract, - title: this.test.title, - failOnConsoleError: false, - }, - async ({ driver, _, contractRegistry }) => { - const contract = contractRegistry.getContractAddress(smartContract); - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - - // Open Dapp and wait for deployed contract - await openDapp(driver, contract); - await driver.findClickableElement('#deployButton'); - - // Click Transer - await driver.fill('#transferTokenInput', '1'); - await driver.clickElement('#transferFromButton'); - await driver.waitUntilXWindowHandles(3); - const windowHandles = await driver.getAllWindowHandles(); - const [extension] = windowHandles; - await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); - - // Confirm transfer - await driver.waitForSelector({ - css: '.mm-text--heading-md', - text: 'TestDappNFTs', - }); - await driver.clickElement({ text: 'Confirm', tag: 'button' }); - await driver.waitUntilXWindowHandles(2); - await driver.switchToWindow(extension); - await driver.clickElement('[data-testid="home__activity-tab"]'); - await driver.waitForSelector( - '.transaction-list__completed-transactions .activity-list-item:nth-of-type(1)', - ); - - // Verify transaction - await driver.findElement({ text: 'Send TDN' }); - }, - ); - }); - - it('should approve an address to transfer a single ERC721 NFT', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .build(), - ganacheOptions, - smartContract, - title: this.test.title, - failOnConsoleError: false, - }, - async ({ driver, _, contractRegistry }) => { - const contract = contractRegistry.getContractAddress(smartContract); - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - - // Open Dapp and wait for deployed contract - await openDapp(driver, contract); - await driver.findClickableElement('#deployButton'); - - // Click Approve - const approveInput = await driver.findElement('#approveTokenInput'); - await approveInput.clear(); - await approveInput.sendKeys('1'); - await driver.clickElement('#approveButton'); - - await driver.waitUntilXWindowHandles(3); - const windowHandles = await driver.getAllWindowHandles(); - const [extension] = windowHandles; - await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); - - // Verify dialog - const title = await driver.findElement( - '[data-testid="confirm-approve-title"]', - ); - await driver.clickElement({ - text: 'View full transaction details', - css: '.confirm-approve-content__small-blue-text', - }); - const [func] = await driver.findElements( - '.confirm-approve-content__data .confirm-approve-content__small-text', - ); - assert.equal( - await title.getText(), - 'Allow access to and transfer of your TestDappNFTs (#1)?', - ); - assert.equal(await func.getText(), 'Function: Approve'); - - // Confirm approval - await driver.clickElement({ text: 'Confirm', tag: 'button' }); - await driver.waitUntilXWindowHandles(2); - await driver.switchToWindow(extension); - await driver.clickElement('[data-testid="home__activity-tab"]'); - await driver.waitForSelector( - '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', - ); - - // Verify transaction - const completedTx = await driver.waitForSelector({ - css: '[data-testid="activity-list-item-action"]', - text: 'Approve TDN spending cap', - }); - assert.equal(await completedTx.isDisplayed(), true); - }, - ); - }); - - it('should enable approval for a third party address to manage all ERC721 NFTs', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .build(), - ganacheOptions, - smartContract, - title: this.test.title, - failOnConsoleError: false, - }, - async ({ driver, _, contractRegistry }) => { - const contract = contractRegistry.getContractAddress(smartContract); - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - - // Open Dapp and wait for deployed contract - await openDapp(driver, contract); - await driver.findClickableElement('#deployButton'); - - // Enable Set approval for all - await driver.clickElement('#setApprovalForAllButton'); - await driver.waitUntilXWindowHandles(3); - const windowHandles = await driver.getAllWindowHandles(); - const [extension] = windowHandles; - await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); - - // Verify dialog - const title = await driver.findElement( - '[data-testid="confirm-approve-title"]', - ); - await driver.clickElement({ - text: 'View full transaction details', - css: '.confirm-approve-content__small-blue-text', - }); - const [func, params] = await driver.findElements( - '.confirm-approve-content__data .confirm-approve-content__small-text', - ); - assert.equal( - await title.getText(), - 'Allow access to and transfer of all your TestDappNFTs?', - ); - assert.equal(await func.getText(), 'Function: SetApprovalForAll'); - assert.equal(await params.getText(), 'Parameters: true'); - - // Confirm enabling set approval for all - await driver.clickElement({ text: 'Confirm', tag: 'button' }); - await driver.clickElement({ text: 'Approve', tag: 'button' }); - - await driver.waitUntilXWindowHandles(2); - await driver.switchToWindow(extension); - await driver.clickElement('[data-testid="home__activity-tab"]'); - await driver.waitForSelector( - '.transaction-list__completed-transactions .activity-list-item:nth-of-type(1)', - ); - - // Verify transaction - const completedTx = await driver.waitForSelector({ - css: '[data-testid="activity-list-item-action"]', - text: 'Approve TDN with no spend limit', - }); - assert.equal(await completedTx.isDisplayed(), true); - }, - ); - }); - - it('should disable approval for a third party address to manage all ERC721 NFTs', async function () { - await withFixtures( - { - dapp: true, - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .build(), - ganacheOptions, - smartContract, - title: this.test.title, - failOnConsoleError: false, - }, - async ({ driver, _, contractRegistry }) => { - const contract = contractRegistry.getContractAddress(smartContract); - await driver.navigate(); - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - - // Open Dapp and wait for deployed contract - await openDapp(driver, contract); - await driver.findClickableElement('#deployButton'); - - // Disable Set approval for all - await driver.clickElement('#revokeButton'); - await driver.waitUntilXWindowHandles(3); - const windowHandles = await driver.getAllWindowHandles(); - const [extension] = windowHandles; - await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); - - // Verify dialog - const title = await driver.findElement( - '[data-testid="confirm-approve-title"]', - ); - await driver.clickElement({ - text: 'View full transaction details', - css: '.confirm-approve-content__small-blue-text', - }); - const [func, params] = await driver.findElements( - '.confirm-approve-content__data .confirm-approve-content__small-text', - ); - const proceedWithCautionIsDisplayed = await driver.isElementPresent( - '.dialog--error', - ); - assert.equal( - await title.getText(), - 'Revoke permission to access and transfer all of your TestDappNFTs?', - ); - assert.equal(await func.getText(), 'Function: SetApprovalForAll'); - assert.equal(await params.getText(), 'Parameters: false'); - assert.equal(proceedWithCautionIsDisplayed, false); - - // Confirm disabling set approval for all - await driver.clickElement({ text: 'Confirm', tag: 'button' }); - - await driver.waitUntilXWindowHandles(2); - await driver.switchToWindow(extension); - await driver.clickElement('[data-testid="home__activity-tab"]'); - await driver.waitForSelector( - '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', - ); - - // Verify transaction - const completedTx = await driver.waitForSelector({ - css: '[data-testid="activity-list-item-action"]', - text: 'Approve TDN with no spend limit', - }); - assert.equal(await completedTx.isDisplayed(), true); - }, - ); - }); -}); diff --git a/test/e2e/run-all.js b/test/e2e/run-all.js index 811f6b8fb94c..674e1a007373 100644 --- a/test/e2e/run-all.js +++ b/test/e2e/run-all.js @@ -119,10 +119,10 @@ async function main() { } else { const testDir = path.join(__dirname, 'tests'); testPaths = [ - ...(await getTestPathsForTestDir(testDir)), + // ...(await getTestPathsForTestDir(testDir)), ...(await getTestPathsForTestDir(path.join(__dirname, 'swaps'))), - ...(await getTestPathsForTestDir(path.join(__dirname, 'nft'))), - ...(await getTestPathsForTestDir(path.join(__dirname, 'metrics'))), + // ...(await getTestPathsForTestDir(path.join(__dirname, 'nft'))), + // ...(await getTestPathsForTestDir(path.join(__dirname, 'metrics'))), path.join(__dirname, 'metamask-ui.spec.js'), ]; diff --git a/test/e2e/tests/edit-gas-fee.spec.js b/test/e2e/tests/edit-gas-fee.spec.js deleted file mode 100644 index 965ffaec7054..000000000000 --- a/test/e2e/tests/edit-gas-fee.spec.js +++ /dev/null @@ -1,270 +0,0 @@ -const { strict: assert } = require('assert'); -const { - convertToHexValue, - getWindowHandles, - withFixtures, - openDapp, -} = require('../helpers'); -const FixtureBuilder = require('../fixture-builder'); - -describe('Editing Confirm Transaction', function () { - it('allows selecting high, medium, low gas estimates on edit gas fee popover', async function () { - const ganacheOptions = { - hardfork: 'london', - accounts: [ - { - secretKey: - '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', - balance: convertToHexValue(25000000000000000000), - }, - ], - }; - await withFixtures( - { - fixtures: new FixtureBuilder() - .withTransactionControllerTypeTwoTransaction() - .build(), - ganacheOptions, - title: this.test.title, - }, - async ({ driver }) => { - await driver.navigate(); - - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - - const transactionAmounts = await driver.findElements( - '.currency-display-component__text', - ); - const transactionAmount = transactionAmounts[0]; - assert.equal(await transactionAmount.getText(), '1'); - - // update estimates to high - await driver.clickElement('[data-testid="edit-gas-fee-button"]'); - await driver.waitForSelector({ - text: 'sec', - tag: 'span', - }); - await driver.clickElement( - '[data-testid="edit-gas-fee-item-high"] > span:first-child', - ); - await driver.waitForSelector({ text: '🦍' }); - await driver.waitForSelector({ - text: 'Aggressive', - }); - - // update estimates to medium - await driver.clickElement('[data-testid="edit-gas-fee-button"]'); - await driver.clickElement( - '[data-testid="edit-gas-fee-item-medium"] > span:first-child', - ); - await driver.waitForSelector({ text: '🦊' }); - await driver.waitForSelector({ - text: 'Market', - }); - - // update estimates to low - await driver.clickElement('[data-testid="edit-gas-fee-button"]'); - await driver.clickElement( - '[data-testid="edit-gas-fee-item-low"] > span:first-child', - ); - await driver.waitForSelector({ text: '🐢' }); - await driver.waitForSelector({ - text: 'Low', - }); - await driver.waitForSelector('[data-testid="low-gas-fee-alert"]'); - - // confirms the transaction - await driver.clickElement({ text: 'Confirm', tag: 'button' }); - - await driver.clickElement('[data-testid="home__activity-tab"]'); - await driver.wait(async () => { - const confirmedTxes = await driver.findElements( - '.transaction-list__completed-transactions .activity-list-item', - ); - return confirmedTxes.length === 1; - }, 10000); - - const txValues = await driver.findElements( - '[data-testid="transaction-list-item-primary-currency"]', - ); - assert.equal(txValues.length, 1); - assert.ok(/-1\s*ETH/u.test(await txValues[0].getText())); - }, - ); - }); - - it('allows accessing advance gas fee popover from edit gas fee popover', async function () { - const ganacheOptions = { - hardfork: 'london', - accounts: [ - { - secretKey: - '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', - balance: convertToHexValue(25000000000000000000), - }, - ], - }; - await withFixtures( - { - fixtures: new FixtureBuilder() - .withTransactionControllerTypeTwoTransaction() - .build(), - ganacheOptions, - title: this.test.title, - }, - async ({ driver }) => { - await driver.navigate(); - - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - - const transactionAmounts = await driver.findElements( - '.currency-display-component__text', - ); - const transactionAmount = transactionAmounts[0]; - assert.equal(await transactionAmount.getText(), '1'); - - // update estimates to high - await driver.clickElement('[data-testid="edit-gas-fee-button"]'); - await driver.waitForSelector({ - text: 'sec', - tag: 'span', - }); - await driver.clickElement('[data-testid="edit-gas-fee-item-custom"]'); - - // enter max fee - await driver.fill('[data-testid="base-fee-input"]', '8.5'); - - // enter priority fee - await driver.fill('[data-testid="priority-fee-input"]', '8.5'); - - // save default values - await driver.clickElement('input[type="checkbox"]'); - - // edit gas limit - await driver.clickElement('[data-testid="advanced-gas-fee-edit"]'); - await driver.fill('[data-testid="gas-limit-input"]', '100000'); - - // Submit gas fee changes - await driver.clickElement({ text: 'Save', tag: 'button' }); - - // has correct updated value on the confirm screen the transaction - await driver.waitForSelector({ - css: '.transaction-detail-item:nth-of-type(1) h6:nth-of-type(2)', - text: '0.00085 ETH', - }); - await driver.waitForSelector({ - css: '.transaction-detail-item:nth-of-type(2) h6:nth-of-type(2)', - text: '1.00085 ETH', - }); - - // confirms the transaction - await driver.clickElement({ text: 'Confirm', tag: 'button' }); - - await driver.clickElement('[data-testid="home__activity-tab"]'); - await driver.wait(async () => { - const confirmedTxes = await driver.findElements( - '.transaction-list__completed-transactions .activity-list-item', - ); - return confirmedTxes.length === 1; - }, 10000); - - const txValues = await driver.findElements( - '[data-testid="transaction-list-item-primary-currency"]', - ); - assert.equal(txValues.length, 1); - assert.ok(/-1\s*ETH/u.test(await txValues[0].getText())); - }, - ); - }); - - it('should use dapp suggested estimates for transaction coming from dapp', async function () { - const ganacheOptions = { - hardfork: 'london', - accounts: [ - { - secretKey: - '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', - balance: convertToHexValue(25000000000000000000), - }, - ], - }; - await withFixtures( - { - fixtures: new FixtureBuilder() - .withPermissionControllerConnectedToTestDapp() - .build(), - ganacheOptions, - title: this.test.title, - dapp: true, - }, - async ({ driver }) => { - await driver.navigate(); - - // login to extension - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - - // open dapp and connect - await openDapp(driver); - await driver.clickElement({ - text: 'Send EIP 1559 Transaction', - tag: 'button', - }); - - // check transaction in extension popup - const windowHandles = await getWindowHandles(driver, 3); - await driver.switchToWindow(windowHandles.popup); - await driver.waitForSelector({ text: '🌐' }); - await driver.waitForSelector({ - text: 'Site suggested', - }); - - await driver.clickElement('[data-testid="edit-gas-fee-button"]'); - await driver.waitForSelector({ - text: 'sec', - tag: 'span', - }); - await driver.clickElement( - '[data-testid="edit-gas-fee-item-dappSuggested"]', - ); - - const transactionAmounts = await driver.findElements( - '.currency-display-component__text', - ); - const transactionAmount = transactionAmounts[0]; - assert.equal(await transactionAmount.getText(), '0'); - - // has correct updated value on the confirm screen the transaction - const editedTransactionAmounts = await driver.findElements( - '.transaction-detail-item__row .transaction-detail-item__detail-values .currency-display-component__text:last-of-type', - ); - const editedTransactionAmount = editedTransactionAmounts[0]; - assert.equal(await editedTransactionAmount.getText(), '0.00021'); - - const editedTransactionFee = editedTransactionAmounts[1]; - assert.equal(await editedTransactionFee.getText(), '0.00021'); - - // confirms the transaction - await driver.clickElement({ text: 'Confirm', tag: 'button' }); - - // transaction should correct values in activity tab - await driver.switchToWindow(windowHandles.extension); - await driver.clickElement('[data-testid="home__activity-tab"]'); - await driver.wait(async () => { - const confirmedTxes = await driver.findElements( - '.transaction-list__completed-transactions .activity-list-item', - ); - return confirmedTxes.length === 1; - }, 10000); - - const txValues = await driver.findElements( - '[data-testid="transaction-list-item-primary-currency"]', - ); - assert.equal(txValues.length, 1); - assert.ok(/-0\s*ETH/u.test(await txValues[0].getText())); - }, - ); - }); -}); diff --git a/test/e2e/tests/gas-estimates.spec.js b/test/e2e/tests/gas-estimates.spec.js deleted file mode 100644 index f9f27029a0d6..000000000000 --- a/test/e2e/tests/gas-estimates.spec.js +++ /dev/null @@ -1,250 +0,0 @@ -const { - convertToHexValue, - withFixtures, - logInWithBalanceValidation, -} = require('../helpers'); -const FixtureBuilder = require('../fixture-builder'); -const { CHAIN_IDS } = require('../../../shared/constants/network'); - -describe('Gas estimates generated by MetaMask', function () { - const baseGanacheOptions = { - accounts: [ - { - secretKey: - '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', - balance: convertToHexValue(25000000000000000000), - }, - ], - }; - const preLondonGanacheOptions = { - ...baseGanacheOptions, - hardfork: 'berlin', - }; - const postLondonGanacheOptions = { - ...baseGanacheOptions, - hardfork: 'london', - }; - - describe('Send on a network that is EIP-1559 compatible', function () { - it('show expected gas defaults', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions: postLondonGanacheOptions, - title: this.test.title, - }, - async ({ driver, ganacheServer }) => { - await driver.navigate(); - await logInWithBalanceValidation(driver, ganacheServer); - - await driver.clickElement('[data-testid="eth-overview-send"]'); - - await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', - '0x2f318C334780961FB129D2a6c30D0763d9a5C970', - ); - - await driver.fill('.unit-input__input', '1'); - - // Check that the gas estimation is what we expect - await driver.findElement({ - cass: '[data-testid="confirm-gas-display"]', - text: '0.00043983', - }); - }, - ); - }); - - it('show expected gas defaults when API is down', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions: postLondonGanacheOptions, - testSpecificMock: (mockServer) => { - mockServer - .forGet( - 'https://gas-api.metaswap.codefi.network/networks/1337/suggestedGasFees', - ) - .thenCallback(() => { - return { - json: { - error: 'cannot get gas prices for chain id 1337', - }, - statusCode: 503, - }; - }); - }, - title: this.test.title, - }, - async ({ driver, ganacheServer }) => { - await driver.navigate(); - await logInWithBalanceValidation(driver, ganacheServer); - - await driver.clickElement('[data-testid="eth-overview-send"]'); - - await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', - '0x2f318C334780961FB129D2a6c30D0763d9a5C970', - ); - - await driver.fill('.unit-input__input', '1'); - - // Check that the gas estimation is what we expect - await driver.findElement({ - cass: '[data-testid="confirm-gas-display"]', - text: '0.00043983', - }); - }, - ); - }); - - it('show expected gas defaults when the network is not supported', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions: postLondonGanacheOptions, - testSpecificMock: (mockServer) => { - mockServer - .forGet( - 'https://gas-api.metaswap.codefi.network/networks/1337/suggestedGasFees', - ) - .thenCallback(() => { - return { - statusCode: 422, - }; - }); - }, - title: this.test.title, - }, - async ({ driver, ganacheServer }) => { - await driver.navigate(); - await logInWithBalanceValidation(driver, ganacheServer); - - await driver.clickElement('[data-testid="eth-overview-send"]'); - - await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', - '0x2f318C334780961FB129D2a6c30D0763d9a5C970', - ); - - await driver.fill('.unit-input__input', '1'); - - // Check that the gas estimation is what we expect - await driver.findElement({ - cass: '[data-testid="confirm-gas-display"]', - text: '0.00043983', - }); - }, - ); - }); - }); - - describe('Send on a network that is not EIP-1559 compatible', function () { - it('show expected gas defaults on a network supported by legacy gas API', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions: { - ...preLondonGanacheOptions, - chainId: parseInt(CHAIN_IDS.BSC, 16), - }, - title: this.test.title, - }, - async ({ driver, ganacheServer }) => { - await driver.navigate(); - await logInWithBalanceValidation(driver, ganacheServer); - - await driver.clickElement('[data-testid="eth-overview-send"]'); - - await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', - '0x2f318C334780961FB129D2a6c30D0763d9a5C970', - ); - - await driver.fill('.unit-input__input', '1'); - - // Check that the gas estimation is what we expect - await driver.findElement({ - cass: '[data-testid="confirm-gas-display"]', - text: '0.000042', - }); - }, - ); - }); - - it('show expected gas defaults on a network supported by legacy gas API when that API is down', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions: { - ...preLondonGanacheOptions, - chainId: parseInt(CHAIN_IDS.BSC, 16), - }, - testSpecificMock: (mockServer) => { - mockServer - .forGet( - `https://gas-api.metaswap.codefi.network/networks/${parseInt( - CHAIN_IDS.BSC, - 16, - )}/gasPrices`, - ) - .thenCallback(() => { - return { - statusCode: 422, - }; - }); - }, - title: this.test.title, - }, - async ({ driver, ganacheServer }) => { - await driver.navigate(); - await logInWithBalanceValidation(driver, ganacheServer); - - await driver.clickElement('[data-testid="eth-overview-send"]'); - - await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', - '0x2f318C334780961FB129D2a6c30D0763d9a5C970', - ); - - await driver.fill('.unit-input__input', '1'); - - // Check that the gas estimation is what we expect - await driver.findElement({ - cass: '[data-testid="confirm-gas-display"]', - text: '0.000042', - }); - }, - ); - }); - - it('show expected gas defaults on a network not supported by legacy gas API', async function () { - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions: preLondonGanacheOptions, - title: this.test.title, - }, - async ({ driver, ganacheServer }) => { - await driver.navigate(); - await logInWithBalanceValidation(driver, ganacheServer); - - await driver.clickElement('[data-testid="eth-overview-send"]'); - - await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', - '0x2f318C334780961FB129D2a6c30D0763d9a5C970', - ); - - await driver.fill('.unit-input__input', '1'); - - // Check that the gas estimation is what we expect - await driver.findElement({ - cass: '[data-testid="confirm-gas-display"]', - text: '0.000042', - }); - }, - ); - }); - }); -}); diff --git a/test/e2e/tests/import-flow.spec.js b/test/e2e/tests/import-flow.spec.js index e94946e311a2..3b9d0f63dc22 100644 --- a/test/e2e/tests/import-flow.spec.js +++ b/test/e2e/tests/import-flow.spec.js @@ -22,6 +22,8 @@ const ganacheOptions = { ], }; +const SMALL_DELAY = 2000; + describe('Import flow', function () { it('Import wallet using Secret Recovery Phrase', async function () { const testPassword = 'correct horse battery staple'; @@ -251,6 +253,7 @@ describe('Import flow', function () { css: '[data-testid="account-menu-icon"]', text: 'Account 4', }); + await driver.delay(SMALL_DELAY); await driver.clickElement('[data-testid="account-menu-icon"]'); const accountListItemsAfterRemoval = await driver.findElements( '.multichain-account-list-item', From d446f5973f70c2e42f6153f988da8511e4a89551 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Mon, 28 Aug 2023 00:59:51 +0800 Subject: [PATCH 053/235] feat: update alert, detect token and account tracker to use intenral account --- .../controllers/accounts-controller.ts | 111 ++++++++++++------ app/scripts/controllers/alert.js | 29 +++-- app/scripts/controllers/detect-tokens.js | 35 ++++-- app/scripts/controllers/detect-tokens.test.js | 111 ++++++++++++++++-- .../controllers/transactions/index.test.js | 103 +++++++++++++--- app/scripts/lib/account-tracker.test.js | 32 ++++- app/scripts/metamask-controller.js | 5 +- app/scripts/metamask-controller.test.js | 24 ++-- 8 files changed, 349 insertions(+), 101 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index 8e8bd3615862..a2e1d2db97a3 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -31,7 +31,6 @@ const controllerName = 'AccountsController'; export type AccountsControllerState = { internalAccounts: { accounts: Record; - lostAccounts: Record; selectedAccount: string; // id of the selected account }; }; @@ -80,8 +79,11 @@ const accountsControllerMetadata = { const defaultState: AccountsControllerState = { internalAccounts: { - accounts: {}, - lostAccounts: {}, + accounts: { + '': { + address: '', + } as InternalAccount, + }, selectedAccount: '', }, }; @@ -170,49 +172,34 @@ export default class AccountsController extends BaseControllerV2< ); const previousAccounts = this.listAccounts(); + // if there are no overlaps between the addresses in the keyring and previous accounts, + // it means the keyring is being reinitialized because the vault is being restored with the same SRP + const overlaps = updatedKeyringAddresses.filter((address) => + previousAccounts.find( + (account) => + account.address.toLowerCase() === address.toLowerCase(), + ), + ); + await this.updateAccounts(); if (updatedKeyringAddresses.length > previousAccounts.length) { - // new address to add - const newAddress = updatedKeyringAddresses.find( - (address) => - !previousAccounts.find( - (account) => - account.address.toLowerCase() === address.toLowerCase(), - ), - ); - - const newAccount = this.listAccounts().find( - (account) => - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - account.address.toLowerCase() === newAddress!.toLowerCase(), + this.#handleNewAccountAdded( + updatedKeyringAddresses, + previousAccounts, ); - - console.log('new account in onKeyringStateChange', newAccount); - - // set the first new account as the selected account - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.setSelectedAccount(newAccount!.id); + } else if ( + updatedKeyringAddresses.length > 0 && + overlaps.length === 0 + ) { + // if the keyring is being reinitialized, the selected account will be reset to the first account + this.setSelectedAccount(this.listAccounts()[0].id); } else if ( updatedKeyringAddresses.length < previousAccounts.length && + overlaps.length > 0 && !this.getAccount(this.state.internalAccounts.selectedAccount) ) { - // handle if the removed account is the selected - - const previousAccount = this.listAccounts() - .filter( - (account) => - account.id !== this.state.internalAccounts.selectedAccount, - ) - .sort((accountA, accountB) => { - // sort by lastSelected descending - return ( - (accountB.metadata?.lastSelected ?? 0) - - (accountA.metadata?.lastSelected ?? 0) - ); - })[0]; - - this.setSelectedAccount(previousAccount.id); + this.#handleSelectedAccountRemoved(); } } }); @@ -235,6 +222,14 @@ export default class AccountsController extends BaseControllerV2< } getAccountExpect(accountId: string): InternalAccount { + // Edge case where the extension is setup but the srp is not yet created + // certain ui elements will query the selected address before any accounts are created. + if (!accountId) { + return { + address: '', + } as InternalAccount; + } + const account = this.getAccount(accountId); if (account === undefined) { throw new Error(`Account Id ${accountId} not found`); @@ -412,6 +407,46 @@ export default class AccountsController extends BaseControllerV2< return snap?.enabled && !snap?.blocked; } ///: END:ONLY_INCLUDE_IN(keyring-snaps) + + #handleSelectedAccountRemoved() { + const previousAccount = this.listAccounts() + .filter( + (account) => account.id !== this.state.internalAccounts.selectedAccount, + ) + .sort((accountA, accountB) => { + // sort by lastSelected descending + return ( + (accountB.metadata?.lastSelected ?? 0) - + (accountA.metadata?.lastSelected ?? 0) + ); + })[0]; + + this.setSelectedAccount(previousAccount.id); + } + + #handleNewAccountAdded( + updatedKeyringAddresses: string[], + previousAccounts: InternalAccount[], + ) { + const newAddress = updatedKeyringAddresses.find( + (address) => + !previousAccounts.find( + (account) => account.address.toLowerCase() === address.toLowerCase(), + ), + ); + + const newAccount = this.listAccounts().find( + (account) => + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + account.address.toLowerCase() === newAddress!.toLowerCase(), + ); + + // console.log('new account in onKeyringStateChange', newAccount); + + // set the first new account as the selected account + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + this.setSelectedAccount(newAccount!.id); + } } export function keyringTypeToName(keyringType: string): string { diff --git a/app/scripts/controllers/alert.js b/app/scripts/controllers/alert.js index 0c682dd38183..e27861883804 100644 --- a/app/scripts/controllers/alert.js +++ b/app/scripts/controllers/alert.js @@ -38,7 +38,7 @@ export default class AlertController { * @param {AlertControllerOptions} [opts] - Controller configuration parameters */ constructor(opts = {}) { - const { initState = {}, preferencesStore } = opts; + const { initState = {}, accountsController, controllerMessenger } = opts; const state = { ...defaultState, alertEnabledness: { @@ -49,18 +49,23 @@ export default class AlertController { this.store = new ObservableStore(state); - this.selectedAddress = preferencesStore.getState().selectedAddress; + this.selectedAddress = accountsController.getSelectedAccount().address; - preferencesStore.subscribe(({ selectedAddress }) => { - const currentState = this.store.getState(); - if ( - currentState.unconnectedAccountAlertShownOrigins && - this.selectedAddress !== selectedAddress - ) { - this.selectedAddress = selectedAddress; - this.store.updateState({ unconnectedAccountAlertShownOrigins: {} }); - } - }); + this.controllerMessenger = controllerMessenger; + + this.controllerMessenger.subscribe( + 'AccountsController:selectedAccountChange', + (account) => { + const currentState = this.store.getState(); + if ( + currentState.unconnectedAccountAlertShownOrigins && + this.selectedAddress !== account.address + ) { + this.selectedAddress = account.address; + this.store.updateState({ unconnectedAccountAlertShownOrigins: {} }); + } + }, + ); } setAlertEnabledness(alertId, enabledness) { diff --git a/app/scripts/controllers/detect-tokens.js b/app/scripts/controllers/detect-tokens.js index 46719aebcced..24f68d55e95a 100644 --- a/app/scripts/controllers/detect-tokens.js +++ b/app/scripts/controllers/detect-tokens.js @@ -34,6 +34,8 @@ export default class DetectTokensController { * @param config.assetsContractController * @param config.trackMetaMetricsEvent * @param config.messenger + * @param config.controllerMessenger + * @param config.accountsController */ constructor({ messenger, @@ -45,6 +47,8 @@ export default class DetectTokensController { tokensController, assetsContractController = null, trackMetaMetricsEvent, + controllerMessenger, + accountsController, } = {}) { this.messenger = messenger; this.assetsContractController = assetsContractController; @@ -56,7 +60,8 @@ export default class DetectTokensController { this.tokenList = tokenList; this.useTokenDetection = this.preferences?.store.getState().useTokenDetection; - this.selectedAddress = this.preferences?.store.getState().selectedAddress; + this.accountsController = accountsController; + this.selectedAddress = this.accountsController.getSelectedAccount().address; this.tokenAddresses = this.tokensController?.state.tokens.map((token) => { return token.address; }); @@ -64,17 +69,24 @@ export default class DetectTokensController { this.detectedTokens = this.tokensController?.state.detectedTokens; this.chainId = this.getChainIdFromNetworkStore(); this._trackMetaMetricsEvent = trackMetaMetricsEvent; + this.controllerMessenger = controllerMessenger; + + this.controllerMessenger.subscribe( + 'AccountsController:selectedAccountChange', + (account) => { + const useTokenDetection = + this.preferences?.store.getState().useTokenDetection; + if ( + this.selectedAddress !== account.address || + this.useTokenDetection !== useTokenDetection + ) { + this.selectedAddress = account.address; + this.useTokenDetection = useTokenDetection; + this.restartTokenDetection({ selectedAddress: this.selectedAddress }); + } + }, + ); - preferences?.store.subscribe(({ selectedAddress, useTokenDetection }) => { - if ( - this.selectedAddress !== selectedAddress || - this.useTokenDetection !== useTokenDetection - ) { - this.selectedAddress = selectedAddress; - this.useTokenDetection = useTokenDetection; - this.restartTokenDetection({ selectedAddress }); - } - }); tokensController?.subscribe( ({ tokens = [], ignoredTokens = [], detectedTokens = [] }) => { this.tokenAddresses = tokens.map((token) => { @@ -84,6 +96,7 @@ export default class DetectTokensController { this.detectedTokens = detectedTokens; }, ); + messenger.subscribe('NetworkController:stateChange', () => { if (this.chainId !== this.getChainIdFromNetworkStore()) { const chainId = this.getChainIdFromNetworkStore(); diff --git a/app/scripts/controllers/detect-tokens.test.js b/app/scripts/controllers/detect-tokens.test.js index 8d2a7d4b91a0..5253f890e3dd 100644 --- a/app/scripts/controllers/detect-tokens.test.js +++ b/app/scripts/controllers/detect-tokens.test.js @@ -15,6 +15,7 @@ import { NETWORK_TYPES } from '../../../shared/constants/network'; import { toChecksumHexAddress } from '../../../shared/modules/hexstring-utils'; import DetectTokensController from './detect-tokens'; import PreferencesController from './preferences'; +import AccountsController from './accounts-controller'; function buildMessenger() { return new ControllerMessenger().getRestricted({ @@ -31,7 +32,9 @@ describe('DetectTokensController', function () { preferences, provider, tokensController, - tokenListController; + tokenListController, + controllerMessenger, + accountsController; const noop = () => undefined; @@ -227,10 +230,6 @@ describe('DetectTokensController', function () { onInfuraIsUnblocked: sinon.stub(), networkConfigurations: {}, }); - preferences.setAddresses([ - '0x7e57e2', - '0xbc86727e770de68b1060c91f6bb6945c73e10388', - ]); preferences.setUseTokenDetection(true); tokensController = new TokensController({ @@ -253,6 +252,76 @@ describe('DetectTokensController', function () { 'NetworkController:stateChange', ), }); + + controllerMessenger = new ControllerMessenger(); + + const accountsControllerMessenger = controllerMessenger.getRestricted({ + name: 'AccountsController', + allowedEvents: [ + 'SnapController:stateChange', + 'KeyringController:accountRemoved', + 'KeyringController:stateChange', + ], + }); + + accountsController = new AccountsController({ + messenger: accountsControllerMessenger, + state: { + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x7e57e2', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + '07c2cfec-36c9-46c4-8115-3836d3ac9047': { + address: '0xbc86727e770de68b1060c91f6bb6945c73e10388', + id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, + }, + onSnapStateChange: sinon.spy(), + onKeyringStateChange: sinon.spy(), + }); }); afterEach(function () { @@ -262,7 +331,13 @@ describe('DetectTokensController', function () { it('should poll on correct interval', async function () { const stub = sinon.stub(global, 'setInterval'); - new DetectTokensController({ messenger: buildMessenger(), interval: 1337 }); // eslint-disable-line no-new + // eslint-disable-next-line no-new + new DetectTokensController({ + messenger: buildMessenger(), + interval: 1337, + accountsController, + controllerMessenger, + }); assert.strictEqual(stub.getCall(0).args[1], 1337); stub.restore(); }); @@ -278,6 +353,8 @@ describe('DetectTokensController', function () { tokenList: tokenListController, tokensController, assetsContractController, + accountsController, + controllerMessenger, }); controller.isOpen = true; controller.isUnlocked = true; @@ -315,6 +392,8 @@ describe('DetectTokensController', function () { tokenList: tokenListController, tokensController, assetsContractController, + accountsController, + controllerMessenger, }); controller.isOpen = true; controller.isUnlocked = true; @@ -340,6 +419,8 @@ describe('DetectTokensController', function () { tokensController, assetsContractController, trackMetaMetricsEvent: noop, + accountsController, + controllerMessenger, }); controller.isOpen = true; controller.isUnlocked = true; @@ -392,6 +473,8 @@ describe('DetectTokensController', function () { tokensController, assetsContractController, trackMetaMetricsEvent: noop, + accountsController, + controllerMessenger, }); controller.isOpen = true; controller.isUnlocked = true; @@ -450,12 +533,14 @@ describe('DetectTokensController', function () { tokenList: tokenListController, tokensController, assetsContractController, + accountsController, + controllerMessenger, }); controller.isOpen = true; controller.isUnlocked = true; const stub = sandbox.stub(controller, 'detectNewTokens'); - await preferences.setSelectedAddress( - '0xbc86727e770de68b1060c91f6bb6945c73e10388', + accountsController.setSelectedAccount( + '07c2cfec-36c9-46c4-8115-3836d3ac9047', ); sandbox.assert.called(stub); }); @@ -470,6 +555,8 @@ describe('DetectTokensController', function () { tokenList: tokenListController, tokensController, assetsContractController, + accountsController, + controllerMessenger, }); controller.isOpen = true; controller.selectedAddress = '0x0'; @@ -489,6 +576,8 @@ describe('DetectTokensController', function () { tokenList: tokenListController, tokensController, assetsContractController, + accountsController, + controllerMessenger, }); controller.isOpen = true; controller.isUnlocked = false; @@ -510,10 +599,12 @@ describe('DetectTokensController', function () { keyringMemStore, tokensController, assetsContractController, + accountsController, + controllerMessenger, }); // trigger state update from preferences controller - await preferences.setSelectedAddress( - '0xbc86727e770de68b1060c91f6bb6945c73e10388', + accountsController.setSelectedAccount( + '07c2cfec-36c9-46c4-8115-3836d3ac9047', ); controller.isOpen = false; controller.isUnlocked = true; diff --git a/app/scripts/controllers/transactions/index.test.js b/app/scripts/controllers/transactions/index.test.js index 0cfe6a6db95f..d029733fb6df 100644 --- a/app/scripts/controllers/transactions/index.test.js +++ b/app/scripts/controllers/transactions/index.test.js @@ -62,7 +62,7 @@ const TRANSACTION_META_MOCK = { time: 123456789, }; -const MOCK_INTENRAL_ACCOUNT = { +const MOCK_INTERNAL_ACCOUNT = { id: '2d47e693-26c2-47cb-b374-6151199bbe3f', address: '0x88bb7F89eB5e5b30D3e15a57C68DBe03C6aCCB21', metadata: { @@ -130,7 +130,7 @@ describe('Transaction Controller', function () { getCurrentChainId = sinon.stub().callsFake(() => currentChainId); - getCurrentAccount = sinon.stub().callsFake(() => MOCK_INTENRAL_ACCOUNT); + getCurrentAccount = sinon.stub().callsFake(() => MOCK_INTERNAL_ACCOUNT); resultCallbacksMock = { success: sinon.spy(), @@ -388,13 +388,36 @@ describe('Transaction Controller', function () { describe('#addTransaction', function () { const selectedAddress = '0xc684832530fcbddae4b4230a47e991ddcec2831d'; + const selectedInternalAccount = { + address: selectedAddress, + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }; const recipientAddress = '0xc684832530fcbddae4b4230a47e991ddcec2831d'; let txMeta, txParams, getPermittedAccounts, signStub, - getSelectedAddress, + getSelectedAccountAddress, getDefaultGasFees; beforeEach(function () { @@ -417,9 +440,9 @@ describe('Transaction Controller', function () { .stub(txController, 'getPermittedAccounts') .returns([txParams.from]); - getSelectedAddress = sinon - .stub(txController, 'getSelectedAddress') - .returns(selectedAddress); + getSelectedAccountAddress = sinon + .stub(txController, 'getSelectedAccountAddress') + .returns(selectedInternalAccount.address); getDefaultGasFees = sinon .stub(txController, '_getDefaultGasFees') @@ -430,7 +453,7 @@ describe('Transaction Controller', function () { txController.txStateManager._addTransactionsToState([]); getPermittedAccounts.restore(); signStub?.restore(); - getSelectedAddress.restore(); + getSelectedAccountAddress.restore(); getDefaultGasFees.restore(); }); @@ -1166,9 +1189,32 @@ describe('Transaction Controller', function () { describe('#createCancelTransaction', function () { const selectedAddress = '0x1678a085c290ebd122dc42cba69373b5953b831d'; + const selectedInternalAccount = { + address: selectedAddress, + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }; const recipientAddress = '0xc42edfcc21ed14dda456aa0756c153f7985d8813'; - let getSelectedAddress, + let getSelectedAccountAddress, getPermittedAccounts, getDefaultGasFees, getDefaultGasLimit; @@ -1177,9 +1223,9 @@ describe('Transaction Controller', function () { '0x2a5523c6fa98b47b7d9b6c8320179785150b42a16bcff36b398c5062b65657e8'; providerResultStub.eth_sendRawTransaction = hash; - getSelectedAddress = sinon - .stub(txController, 'getSelectedAddress') - .returns(selectedAddress); + getSelectedAccountAddress = sinon + .stub(txController, 'getSelectedAccountAddress') + .returns(selectedInternalAccount.address); getDefaultGasFees = sinon .stub(txController, '_getDefaultGasFees') .returns({}); @@ -1192,7 +1238,7 @@ describe('Transaction Controller', function () { }); afterEach(function () { - getSelectedAddress.restore(); + getSelectedAccountAddress.restore(); getPermittedAccounts.restore(); getDefaultGasFees.restore(); getDefaultGasLimit.restore(); @@ -1632,9 +1678,32 @@ describe('Transaction Controller', function () { let txParams; let expectedTxParams; const selectedAddress = '0x1678a085c290ebd122dc42cba69373b5953b831d'; + const selectedInternalAccount = { + address: selectedAddress, + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }; const recipientAddress = '0xc42edfcc21ed14dda456aa0756c153f7985d8813'; - let getSelectedAddress, + let getSelectedAccountAddress, getPermittedAccounts, getDefaultGasFees, getDefaultGasLimit; @@ -1647,9 +1716,9 @@ describe('Transaction Controller', function () { '0x2a5523c6fa98b47b7d9b6c8320179785150b42a16bcff36b398c5062b65657e8'; providerResultStub.eth_sendRawTransaction = hash; - getSelectedAddress = sinon - .stub(txController, 'getSelectedAddress') - .returns(selectedAddress); + getSelectedAccountAddress = sinon + .stub(txController, 'getSelectedAccountAddress') + .returns(selectedInternalAccount.address); getDefaultGasFees = sinon .stub(txController, '_getDefaultGasFees') .returns({}); @@ -1685,7 +1754,7 @@ describe('Transaction Controller', function () { afterEach(function () { addTransactionSpy.restore(); approveTransactionSpy.restore(); - getSelectedAddress.restore(); + getSelectedAccountAddress.restore(); getPermittedAccounts.restore(); getDefaultGasFees.restore(); getDefaultGasLimit.restore(); diff --git a/app/scripts/lib/account-tracker.test.js b/app/scripts/lib/account-tracker.test.js index f643fc655d43..7089bfe2ee8a 100644 --- a/app/scripts/lib/account-tracker.test.js +++ b/app/scripts/lib/account-tracker.test.js @@ -1,4 +1,5 @@ import EventEmitter from 'events'; +import { ControllerMessenger } from '@metamask/base-controller'; import { SINGLE_CALL_BALANCES_ADDRESS } from '../constants/contracts'; @@ -31,12 +32,19 @@ const mockAccounts = { }, }; +const mockKeyringController = jest.fn(); +const mockSnapController = jest.fn(); +const mockSnapChange = jest.fn(); +const mockKeyringChange = jest.fn(); + describe('Account Tracker', () => { let provider, blockTrackerStub, providerResultStub, useMultiAccountBalanceChecker, - accountTracker; + accountTracker, + controllerMessenger, + accountsController; beforeEach(() => { providerResultStub = { @@ -53,6 +61,26 @@ describe('Account Tracker', () => { blockTrackerStub.getCurrentBlock = noop; blockTrackerStub.getLatestBlock = noop; + controllerMessenger = new ControllerMessenger(); + + const accountsControllerMessenger = controllerMessenger.getRestricted({ + name: 'AccountsController', + allowedEvents: [ + 'SnapController:stateChange', + 'KeyringController:accountRemoved', + 'KeyringController:stateChange', + ], + }); + + accountsController = new AccountTracker({ + state: {}, + messenger: accountsControllerMessenger, + keyringController: () => mockKeyringController, + snapController: () => mockSnapController, + onSnapChange: () => mockSnapChange, + onKeyringChange: () => mockKeyringChange, + }); + accountTracker = new AccountTracker({ provider, blockTracker: blockTrackerStub, @@ -70,6 +98,8 @@ describe('Account Tracker', () => { getState: noop, }, }, + controllerMessenger, + accountsController, }); }); diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 5abd84cb38e7..4bb0394f894d 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1146,6 +1146,8 @@ export default class MetamaskController extends EventEmitter { messenger: detectTokensControllerMessenger, preferences: this.preferencesController, tokensController: this.tokensController, + accountsController: this.accountsController, + controllerMessenger: this.controllerMessenger, assetsContractController: this.assetsContractController, network: this.networkController, keyringMemStore: this.keyringController.memStore, @@ -1162,7 +1164,8 @@ export default class MetamaskController extends EventEmitter { this.alertController = new AlertController({ initState: initState.AlertController, - preferencesStore: this.preferencesController.store, + controllerMessenger: this.controllerMessenger, + accountsController: this.accountsController, }); ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) diff --git a/app/scripts/metamask-controller.test.js b/app/scripts/metamask-controller.test.js index 7c5dc95aeb75..d06e00ad4722 100644 --- a/app/scripts/metamask-controller.test.js +++ b/app/scripts/metamask-controller.test.js @@ -28,7 +28,6 @@ import { KeyringType } from '../../shared/constants/keyring'; import { deferredPromise } from './lib/util'; import TransactionController from './controllers/transactions'; import PreferencesController from './controllers/preferences'; -import AccountsController from './controllers/accounts-controller'; const Ganache = require('../../test/e2e/ganache'); @@ -166,7 +165,11 @@ const firstTimeState = { config: {}, AccountsController: { internalAccounts: { - accounts: {}, + accounts: { + '': { + address: '', + }, + }, selectedAccount: '', }, }, @@ -1801,17 +1804,22 @@ describe('MetaMaskController', function () { }); describe('incoming transactions', function () { - let txControllerStub, preferencesControllerSpy, controllerMessengerSpy; + let txControllerStub, + preferencesControllerSpy, + controllerMessengerSpy, + accountsControllerSpy; beforeEach(async function () { txControllerStub = TransactionController.prototype; preferencesControllerSpy = metamaskController.preferencesController; controllerMessengerSpy = ControllerMessenger.prototype; + accountsControllerSpy = metamaskController.accountsController; sandbox - .stub(metamaskController.accountsController, 'getSelectedAccount') + .stub(metamaskController.accountsController, 'getAccountExpect') .callsFake(() => { return TEST_INTERNAL_ACCOUNT; }); + sandbox.stub(metamaskController.accountsController, 'update'); }); it('starts incoming transaction polling if incomingTransactionsPreferences is enabled for that chainId', async function () { @@ -1840,13 +1848,7 @@ describe('MetaMaskController', function () { it('updates incoming transactions when changing account', async function () { assert(txControllerStub.updateIncomingTransactions.notCalled); - - await controllerMessengerSpy.subscribe.args - .filter( - (args) => args[0] === 'AccountsController:selectedAccountChange', - ) - .slice(-1)[0][1](); - + accountsControllerSpy.setSelectedAccount('mock-id'); assert(txControllerStub.updateIncomingTransactions.calledOnce); }); From 1be53fb5a5cfab29c33b6a8d02643a1081013127 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Mon, 28 Aug 2023 01:00:17 +0800 Subject: [PATCH 054/235] fix: update custody-confirm-link-modal to use internal account --- .../custody-confirm-link-modal.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/components/institutional/custody-confirm-link-modal/custody-confirm-link-modal.js b/ui/components/institutional/custody-confirm-link-modal/custody-confirm-link-modal.js index 815c4b9bf65e..095922d727d9 100644 --- a/ui/components/institutional/custody-confirm-link-modal/custody-confirm-link-modal.js +++ b/ui/components/institutional/custody-confirm-link-modal/custody-confirm-link-modal.js @@ -10,8 +10,8 @@ import { useI18nContext } from '../../../hooks/useI18nContext'; import withModalProps from '../../../helpers/higher-order-components/with-modal-props'; import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils'; import { mmiActionsFactory } from '../../../store/institutional/institution-background'; -import { setSelectedAddress } from '../../../store/actions'; -import { getMetaMaskIdentities } from '../../../selectors'; +import { setSelectedInternalAccount } from '../../../store/actions'; +import { getInternalAccounts } from '../../../selectors'; import { getMMIAddressFromModalOrAddress, getCustodyAccountDetails, @@ -42,7 +42,7 @@ const CustodyConfirmLink = ({ hideModal }) => { const dispatch = useDispatch(); const mmiActions = mmiActionsFactory(); const trackEvent = useContext(MetaMetricsContext); - const mmiAccounts = useSelector(getMetaMaskIdentities); + const mmiAccounts = useSelector(getInternalAccounts); const address = useSelector(getMMIAddressFromModalOrAddress); const custodyAccountDetails = useSelector(getCustodyAccountDetails); const { custodians } = useSelector(getMMIConfiguration); @@ -64,7 +64,7 @@ const CustodyConfirmLink = ({ hideModal }) => { ethereum.accounts.includes(account.toLowerCase()), ); - ethAccount && dispatch(setSelectedAddress(ethAccount.toLowerCase())); + ethAccount && dispatch(setSelectedInternalAccount(ethAccount.id)); } trackEvent({ From 27f9b718b23a2ab557872d91bd7d7de67fa04f40 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Mon, 28 Aug 2023 01:00:41 +0800 Subject: [PATCH 055/235] fix: update advanced gas fee default story to use intenral account --- .../advanced-gas-fee-defaults.stories.js | 9 +- .../confirm-add-suggested-nft.test.js.snap | 100 ++---------------- 2 files changed, 15 insertions(+), 94 deletions(-) diff --git a/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.stories.js b/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.stories.js index 5769f235b881..c8e62d9969c0 100644 --- a/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.stories.js +++ b/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.stories.js @@ -8,13 +8,18 @@ import { GasFeeContextProvider } from '../../../../contexts/gasFee'; import { GasEstimateTypes } from '../../../../../shared/constants/gas'; import AdvancedGasFeeDefaults from './advanced-gas-fee-defaults'; +const selectedAddress = + mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].address; + const store = configureStore({ ...mockState, metamask: { ...mockState.metamask, accounts: { - [mockState.metamask.selectedAddress]: { - address: mockState.metamask.selectedAddress, + [selectedAddress]: { + address: selectedAddress, balance: '0x1F4', }, }, diff --git a/ui/pages/confirm-add-suggested-nft/__snapshots__/confirm-add-suggested-nft.test.js.snap b/ui/pages/confirm-add-suggested-nft/__snapshots__/confirm-add-suggested-nft.test.js.snap index 02d00db76cf9..acfd8aa362b0 100644 --- a/ui/pages/confirm-add-suggested-nft/__snapshots__/confirm-add-suggested-nft.test.js.snap +++ b/ui/pages/confirm-add-suggested-nft/__snapshots__/confirm-add-suggested-nft.test.js.snap @@ -24,49 +24,9 @@ exports[`ConfirmAddSuggestedNFT Component should match snapshot 1`] = ` class="box box--display-flex box--flex-direction-row box--align-items-center" >
-
-
- - - - - -
-
-
+ class="identicon__image-border" + style="height: 32px; width: 32px; border-radius: 16px;" + />
-
-
- - - - - -
-
-
+ class="identicon__image-border" + style="height: 32px; width: 32px; border-radius: 16px;" + />
Date: Mon, 28 Aug 2023 10:05:35 +0800 Subject: [PATCH 056/235] fix: account-tracker test --- app/scripts/lib/account-tracker.js | 21 ++++++--------------- app/scripts/lib/account-tracker.test.js | 7 ++++--- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/app/scripts/lib/account-tracker.js b/app/scripts/lib/account-tracker.js index d7eb66356739..f2c4a4ab8ea0 100644 --- a/app/scripts/lib/account-tracker.js +++ b/app/scripts/lib/account-tracker.js @@ -94,33 +94,24 @@ export default class AccountTracker { }, this.onboardingController.store.getState()), ); + this.selectedAccount = this.accountsController.getSelectedAccount(); + this.controllerMessenger = opts.controllerMessenger; this.controllerMessenger.subscribe( 'AccountsController:selectedAccountChange', - () => { + (newAccount) => { const { useMultiAccountBalanceChecker } = this.preferencesController.store.getState(); - if (!useMultiAccountBalanceChecker) { - this._updateAccounts(); - } - }, - ); - this.preferencesController.store.subscribe( - previousValueComparator(async (prevState, currState) => { - const { selectedAddress: prevSelectedAddress } = prevState; - const { - selectedAddress: currSelectedAddress, - useMultiAccountBalanceChecker, - } = currState; if ( - prevSelectedAddress !== currSelectedAddress && + this.selectedAccount.id !== newAccount.id && !useMultiAccountBalanceChecker ) { + this.selectedAccount = newAccount; this._updateAccounts(); } - }, this.onboardingController.store.getState()), + }, ); this.ethersProvider = new Web3Provider(this._provider); } diff --git a/app/scripts/lib/account-tracker.test.js b/app/scripts/lib/account-tracker.test.js index 7089bfe2ee8a..8a79bb84cc81 100644 --- a/app/scripts/lib/account-tracker.test.js +++ b/app/scripts/lib/account-tracker.test.js @@ -4,6 +4,7 @@ import { ControllerMessenger } from '@metamask/base-controller'; import { SINGLE_CALL_BALANCES_ADDRESS } from '../constants/contracts'; import { createTestProviderTools } from '../../../test/stub/provider'; +import AccountsController from '../controllers/accounts-controller'; import AccountTracker from './account-tracker'; const noop = () => true; @@ -72,13 +73,13 @@ describe('Account Tracker', () => { ], }); - accountsController = new AccountTracker({ + accountsController = new AccountsController({ state: {}, messenger: accountsControllerMessenger, keyringController: () => mockKeyringController, snapController: () => mockSnapController, - onSnapChange: () => mockSnapChange, - onKeyringChange: () => mockKeyringChange, + onSnapStateChange: () => mockSnapChange, + onKeyringStateChange: () => mockKeyringChange, }); accountTracker = new AccountTracker({ From 8f88fa2d06bd380f07d74683383c6a78cd56903b Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Mon, 28 Aug 2023 10:06:55 +0800 Subject: [PATCH 057/235] fix: remove default account in default state in accounts controller --- app/scripts/controllers/accounts-controller.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index a2e1d2db97a3..c6e4096200a5 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -79,11 +79,7 @@ const accountsControllerMetadata = { const defaultState: AccountsControllerState = { internalAccounts: { - accounts: { - '': { - address: '', - } as InternalAccount, - }, + accounts: {}, selectedAccount: '', }, }; @@ -226,8 +222,18 @@ export default class AccountsController extends BaseControllerV2< // certain ui elements will query the selected address before any accounts are created. if (!accountId) { return { + id: '', + name: '', address: '', - } as InternalAccount; + options: {}, + supportedMethods: [], + type: 'eip155:eoa', + metadata: { + keyring: { + type: '', + }, + }, + }; } const account = this.getAccount(accountId); From 012ce5d4ad4d0719f7874d654bc9d80f3dd26c62 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Mon, 28 Aug 2023 21:10:45 +0800 Subject: [PATCH 058/235] fix: double negative in updateAccounts filter --- .../controllers/accounts-controller.ts | 190 +++++++++--------- 1 file changed, 94 insertions(+), 96 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index c6e4096200a5..b2288cb0cd30 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -1,30 +1,21 @@ -import { - BaseControllerV2, - RestrictedControllerMessenger, -} from '@metamask/base-controller'; -import { Patch } from 'immer'; -import { v4 as uuid } from 'uuid'; -import { sha256FromString } from 'ethereumjs-util'; -import { - InternalAccount, - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) - SnapKeyring, - ///: END:ONLY_INCLUDE_IN(keyring-snaps) -} from '@metamask/eth-snap-keyring'; -///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) -import { - SnapController, - SnapControllerEvents, -} from '@metamask/snaps-controllers'; -///: END:ONLY_INCLUDE_IN(keyring-snaps) -import { +import type { RestrictedControllerMessenger } from '@metamask/base-controller'; +import { BaseControllerV2 } from '@metamask/base-controller'; +import type { InternalAccount } from '@metamask/eth-snap-keyring'; +import { SnapKeyring } from '@metamask/eth-snap-keyring'; +import type { KeyringControllerState, KeyringController, KeyringControllerEvents, } from '@metamask/keyring-controller'; -///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) -import { SnapControllerState } from '@metamask/snaps-controllers-flask'; -///: END:ONLY_INCLUDE_IN(keyring-snaps) +import type { + SnapController, + SnapControllerEvents, +} from '@metamask/snaps-controllers'; +import type { SnapControllerState } from '@metamask/snaps-controllers-flask'; +import type { Snap } from '@metamask/snaps-utils'; +import { sha256FromString } from 'ethereumjs-util'; +import type { Patch } from 'immer'; +import { v4 as uuid } from 'uuid'; const controllerName = 'AccountsController'; @@ -91,34 +82,26 @@ export default class AccountsController extends BaseControllerV2< > { #keyringController: KeyringController; - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) #snapController: SnapController; - ///: END:ONLY_INCLUDE_IN(keyring-snaps) constructor({ messenger, state, keyringController, - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) snapController, onSnapStateChange, - ///: END:ONLY_INCLUDE_IN(keyring-snaps) onKeyringStateChange, }: { messenger: AccountsControllerMessenger; state: AccountsControllerState; keyringController: KeyringController; - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) snapController: SnapController; - ///: END:ONLY_INCLUDE_IN(keyring-snaps) onKeyringStateChange: ( listener: (keyringState: KeyringControllerState) => void, ) => void; - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) onSnapStateChange: ( listener: (snapState: SnapControllerState) => void, ) => void; - ///: END:ONLY_INCLUDE_IN(keyring-snaps) }) { super({ messenger, @@ -131,74 +114,89 @@ export default class AccountsController extends BaseControllerV2< }); this.#keyringController = keyringController; - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) this.#snapController = snapController; - ///: END:ONLY_INCLUDE_IN(keyring-snaps) - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) + // eslint-disable-next-line @typescript-eslint/no-misused-promises onSnapStateChange(async (snapState: SnapControllerState) => { // only check if snaps changed in status const { snaps } = snapState; const accounts = this.listAccounts(); + const disabledSnaps: Snap[] = []; + for (const snap of Object.values(snaps)) { + if (!(await this.#isSnapEnabled(snap.id))) { + disabledSnaps.push(snap); + } + } + + const accountsToUpdate = accounts.filter( + (account) => + account.metadata.snap && + disabledSnaps.find((snap) => snap.id === account.metadata.snap?.id), + ); + this.update((currentState: AccountsControllerState) => { - Object.values(snaps).forEach((snap) => { - if (!this.#isSnapEnabled(snap.id)) { - accounts.forEach((account) => { - if (account.metadata.snap?.id === snap.id) { - currentState.internalAccounts.accounts[ - account.id - ].metadata.snap.enabled = false; - } - }); + accountsToUpdate.forEach((account) => { + if ( + currentState.internalAccounts.accounts[account.id]?.metadata?.snap + ) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore this account is guaranteed to have snap metadata + currentState.internalAccounts.accounts[ + account.id + ].metadata.snap.enabled = false; } }); }); }); - ///: END:ONLY_INCLUDE_IN(keyring-snaps) - - onKeyringStateChange(async (keyringState: KeyringControllerState) => { - // check if there are any new accounts added - // TODO: change when accountAdded event is added to the keyring controller - if (keyringState.isUnlocked) { - // TODO: ACCOUNTS_CONTROLLER keyring will return accounts instead of addresses, remove this flatMap after and just get the latest id - const updatedKeyringAddresses = keyringState.keyrings.flatMap( - (keyring) => keyring.accounts, - ); - const previousAccounts = this.listAccounts(); - - // if there are no overlaps between the addresses in the keyring and previous accounts, - // it means the keyring is being reinitialized because the vault is being restored with the same SRP - const overlaps = updatedKeyringAddresses.filter((address) => - previousAccounts.find( - (account) => - account.address.toLowerCase() === address.toLowerCase(), - ), - ); + onKeyringStateChange( + // eslint-disable-next-line @typescript-eslint/no-misused-promises + async (keyringState: KeyringControllerState): Promise => { + // check if there are any new accounts added + // TODO: change when accountAdded event is added to the keyring controller - await this.updateAccounts(); - - if (updatedKeyringAddresses.length > previousAccounts.length) { - this.#handleNewAccountAdded( - updatedKeyringAddresses, - previousAccounts, + if (keyringState.isUnlocked) { + // TODO: ACCOUNTS_CONTROLLER keyring will return accounts instead of addresses, remove this flatMap after and just get the latest id + const updatedKeyringAddresses = keyringState.keyrings.flatMap( + (keyring) => keyring.accounts, + ); + const previousAccounts = this.listAccounts(); + + // if there are no overlaps between the addresses in the keyring and previous accounts, + // it means the keyring is being reinitialized because the vault is being restored with the same SRP + const overlaps = updatedKeyringAddresses.filter((address) => + previousAccounts.find( + (account) => + account.address.toLowerCase() === address.toLowerCase(), + ), ); - } else if ( - updatedKeyringAddresses.length > 0 && - overlaps.length === 0 - ) { - // if the keyring is being reinitialized, the selected account will be reset to the first account - this.setSelectedAccount(this.listAccounts()[0].id); - } else if ( - updatedKeyringAddresses.length < previousAccounts.length && - overlaps.length > 0 && - !this.getAccount(this.state.internalAccounts.selectedAccount) - ) { - this.#handleSelectedAccountRemoved(); + + await this.updateAccounts(); + + const updatedAccounts = this.listAccounts(); + + if (updatedKeyringAddresses.length > previousAccounts.length) { + this.#handleNewAccountAdded( + updatedKeyringAddresses, + previousAccounts, + ); + } else if ( + updatedKeyringAddresses.length > 0 && + overlaps.length === 0 + ) { + // if the keyring is being reinitialized, the selected account will be reset to the first account + this.setSelectedAccount(this.listAccounts()[0].id); + } else if ( + updatedKeyringAddresses.length < previousAccounts.length && + overlaps.length > 0 && + !this.getAccount(this.state.internalAccounts.selectedAccount) + ) { + this.#handleSelectedAccountRemoved(); + } } - } - }); + }, + ); // if somehow the selected account becomes lost then select the first account if ( @@ -249,16 +247,14 @@ export default class AccountsController extends BaseControllerV2< async updateAccounts(): Promise { let legacyAccounts = await this.#listLegacyAccounts(); - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) const snapAccounts = await this.#listSnapAccounts(); // remove duplicate accounts that are retrieved from the snap keyring. legacyAccounts = legacyAccounts.filter( (account) => !snapAccounts.find( - (snapAccount) => snapAccount.address !== account.address, + (snapAccount) => snapAccount.address === account.address, ), ); - ///: END:ONLY_INCLUDE_IN(keyring-snaps) // keyring type map. const keyringTypes = new Map(); @@ -266,9 +262,7 @@ export default class AccountsController extends BaseControllerV2< const accounts: Record = [ ...legacyAccounts, - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) ...snapAccounts, - ///: END:ONLY_INCLUDE_IN(keyring-snaps) ].reduce((internalAccountMap, internalAccount) => { const keyringTypeName = keyringTypeToName( internalAccount.metadata.keyring.type, @@ -296,12 +290,13 @@ export default class AccountsController extends BaseControllerV2< return internalAccountMap; }, {} as Record); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore Type instantiation is excessively deep and possibly infinite. this.update((currentState: AccountsControllerState) => { currentState.internalAccounts.accounts = accounts; }); } - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) async #listSnapAccounts(): Promise { const [snapKeyring] = this.#keyringController.getKeyringsByType( SnapKeyring.type, @@ -311,12 +306,12 @@ export default class AccountsController extends BaseControllerV2< (await (snapKeyring as SnapKeyring)?.listAccounts(false)) ?? []; for (const account of snapAccounts) { + const snapId = account.metadata.snap?.id as string; + account.metadata = { snap: { - id: account?.metadata?.snap?.id!, - enabled: await this.#isSnapEnabled( - account?.metadata?.snap?.id as string, - ), + id: snapId, + enabled: await this.#isSnapEnabled(snapId), name: account.name, }, keyring: { @@ -327,7 +322,6 @@ export default class AccountsController extends BaseControllerV2< return snapAccounts; } - ///: END:ONLY_INCLUDE_IN(keyring-snaps) // Note: listLegacyAccounts is a temporary method until the keyrings all implement the InternalAccount interface async #listLegacyAccounts(): Promise[]> { @@ -404,7 +398,6 @@ export default class AccountsController extends BaseControllerV2< }); } - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) async #isSnapEnabled(snapId: string): Promise { const snap = (await this.#snapController.getSnapState(snapId)) as any; if (!snap) { @@ -412,7 +405,6 @@ export default class AccountsController extends BaseControllerV2< } return snap?.enabled && !snap?.blocked; } - ///: END:ONLY_INCLUDE_IN(keyring-snaps) #handleSelectedAccountRemoved() { const previousAccount = this.listAccounts() @@ -455,6 +447,12 @@ export default class AccountsController extends BaseControllerV2< } } +/** + * Returns the name of the keyring type. + * + * @param keyringType - The type of the keyring. + * @returns The name of the keyring type. + */ export function keyringTypeToName(keyringType: string): string { switch (keyringType) { case 'Simple Key Pair': { From 08cb11dba7b2a0c73f5ff371a0682ed18738f50b Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Tue, 29 Aug 2023 00:35:49 +0800 Subject: [PATCH 059/235] update accounts controller to not have snapcontroller and keyringcontroller as args in construction --- .../controllers/accounts-controller.ts | 69 +++++++++---------- app/scripts/metamask-controller.js | 63 +++++++++-------- lavamoat/browserify/beta/policy.json | 56 +++++++++++++++ lavamoat/browserify/main/policy.json | 56 +++++++++++++++ lavamoat/browserify/mmi/policy.json | 56 +++++++++++++++ .../confirm-transaction.component.js | 5 -- ui/selectors/confirm-transaction.js | 1 - 7 files changed, 236 insertions(+), 70 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index b2288cb0cd30..586a03f9c2ff 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -7,12 +7,11 @@ import type { KeyringController, KeyringControllerEvents, } from '@metamask/keyring-controller'; -import type { - SnapController, - SnapControllerEvents, -} from '@metamask/snaps-controllers'; +///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) +import type { SnapControllerEvents } from '@metamask/snaps-controllers'; import type { SnapControllerState } from '@metamask/snaps-controllers-flask'; import type { Snap } from '@metamask/snaps-utils'; +///: END:ONLY_INCLUDE_IN(keyring-snaps) import { sha256FromString } from 'ethereumjs-util'; import type { Patch } from 'immer'; import { v4 as uuid } from 'uuid'; @@ -80,28 +79,36 @@ export default class AccountsController extends BaseControllerV2< AccountsControllerState, AccountsControllerMessenger > { - #keyringController: KeyringController; + getKeyringForAccount: KeyringController['getKeyringForAccount']; + + getKeyringByType: KeyringController['getKeyringsByType']; - #snapController: SnapController; + getAccounts: KeyringController['getAccounts']; constructor({ messenger, state, - keyringController, - snapController, + getKeyringForAccount, + getKeyringByType, + getAccounts, + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) onSnapStateChange, + ///: END:ONLY_INCLUDE_IN(keyring-snaps) onKeyringStateChange, }: { messenger: AccountsControllerMessenger; state: AccountsControllerState; - keyringController: KeyringController; - snapController: SnapController; + getKeyringForAccount: KeyringController['getKeyringForAccount']; + getKeyringByType: KeyringController['getKeyringsByType']; + getAccounts: KeyringController['getAccounts']; onKeyringStateChange: ( listener: (keyringState: KeyringControllerState) => void, ) => void; + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) onSnapStateChange: ( listener: (snapState: SnapControllerState) => void, ) => void; + ///: END:ONLY_INCLUDE_IN(keyring-snaps) }) { super({ messenger, @@ -113,21 +120,20 @@ export default class AccountsController extends BaseControllerV2< }, }); - this.#keyringController = keyringController; - this.#snapController = snapController; + this.getKeyringForAccount = getKeyringForAccount; + this.getKeyringByType = getKeyringByType; + this.getAccounts = getAccounts; + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) // eslint-disable-next-line @typescript-eslint/no-misused-promises onSnapStateChange(async (snapState: SnapControllerState) => { // only check if snaps changed in status const { snaps } = snapState; const accounts = this.listAccounts(); - const disabledSnaps: Snap[] = []; - for (const snap of Object.values(snaps)) { - if (!(await this.#isSnapEnabled(snap.id))) { - disabledSnaps.push(snap); - } - } + const disabledSnaps: Snap[] = Object.values(snaps).filter( + (snap) => !snap.enabled || !snap.blocked, + ); const accountsToUpdate = accounts.filter( (account) => @@ -149,6 +155,7 @@ export default class AccountsController extends BaseControllerV2< }); }); }); + ///: END:ONLY_INCLUDE_IN(keyring-snaps) onKeyringStateChange( // eslint-disable-next-line @typescript-eslint/no-misused-promises @@ -174,8 +181,6 @@ export default class AccountsController extends BaseControllerV2< await this.updateAccounts(); - const updatedAccounts = this.listAccounts(); - if (updatedKeyringAddresses.length > previousAccounts.length) { this.#handleNewAccountAdded( updatedKeyringAddresses, @@ -247,6 +252,7 @@ export default class AccountsController extends BaseControllerV2< async updateAccounts(): Promise { let legacyAccounts = await this.#listLegacyAccounts(); + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) const snapAccounts = await this.#listSnapAccounts(); // remove duplicate accounts that are retrieved from the snap keyring. legacyAccounts = legacyAccounts.filter( @@ -255,6 +261,7 @@ export default class AccountsController extends BaseControllerV2< (snapAccount) => snapAccount.address === account.address, ), ); + ///: END:ONLY_INCLUDE_IN(keyring-snaps) // keyring type map. const keyringTypes = new Map(); @@ -262,7 +269,9 @@ export default class AccountsController extends BaseControllerV2< const accounts: Record = [ ...legacyAccounts, + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) ...snapAccounts, + ///: END:ONLY_INCLUDE_IN(keyring-snaps) ].reduce((internalAccountMap, internalAccount) => { const keyringTypeName = keyringTypeToName( internalAccount.metadata.keyring.type, @@ -298,9 +307,7 @@ export default class AccountsController extends BaseControllerV2< } async #listSnapAccounts(): Promise { - const [snapKeyring] = this.#keyringController.getKeyringsByType( - SnapKeyring.type, - ); + const [snapKeyring] = this.getKeyringByType(SnapKeyring.type); const snapAccounts = (await (snapKeyring as SnapKeyring)?.listAccounts(false)) ?? []; @@ -311,7 +318,7 @@ export default class AccountsController extends BaseControllerV2< account.metadata = { snap: { id: snapId, - enabled: await this.#isSnapEnabled(snapId), + enabled: true, name: account.name, }, keyring: { @@ -325,12 +332,10 @@ export default class AccountsController extends BaseControllerV2< // Note: listLegacyAccounts is a temporary method until the keyrings all implement the InternalAccount interface async #listLegacyAccounts(): Promise[]> { - const addresses = await this.#keyringController.getAccounts(); + const addresses = await this.getAccounts(); const internalAccounts: Omit[] = []; for (const address of addresses) { - const keyring = await this.#keyringController.getKeyringForAccount( - address, - ); + const keyring = await this.getKeyringForAccount(address); // TODO: this is done until the keyrings all implement the InternalAccount interface const v4options = { random: sha256FromString(address).slice(0, 16), @@ -398,14 +403,6 @@ export default class AccountsController extends BaseControllerV2< }); } - async #isSnapEnabled(snapId: string): Promise { - const snap = (await this.#snapController.getSnapState(snapId)) as any; - if (!snap) { - return false; - } - return snap?.enabled && !snap?.blocked; - } - #handleSelectedAccountRemoved() { const previousAccount = this.listAccounts() .filter( diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 4bb0394f894d..3016dbe07d90 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -832,6 +832,41 @@ export default class MetamaskController extends EventEmitter { const getIdentities = () => this.preferencesController.store.getState().identities; + const accountsControllerMessenger = this.controllerMessenger.getRestricted({ + name: 'AccountsController', + allowedEvents: [ + 'SnapController:stateChange', + 'KeyringController:accountRemoved', + 'KeyringController:stateChange', + 'AccountsController:selectedAccountChange', + ], + }); + + this.accountsController = new AccountsController({ + messenger: accountsControllerMessenger, + state: initState.AccountsController, + getKeyringForAccount: + this.coreKeyringController.getKeyringForAccount.bind( + this.coreKeyringController, + ), + getKeyringByType: this.coreKeyringController.getKeyringsByType.bind( + this.coreKeyringController, + ), + getAccounts: this.coreKeyringController.getAccounts.bind( + this.coreKeyringController, + ), + onKeyringStateChange: keyringControllerMessenger.subscribe.bind( + keyringControllerMessenger, + 'KeyringController:stateChange', + ), + ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) + onSnapStateChange: this.controllerMessenger.subscribe.bind( + this.controllerMessenger, + 'SnapController:stateChange', + ), + ///: END:ONLY_INCLUDE_IN + }); + this.permissionController = new PermissionController({ messenger: this.controllerMessenger.getRestricted({ name: 'PermissionController', @@ -1053,34 +1088,6 @@ export default class MetamaskController extends EventEmitter { ///: END:ONLY_INCLUDE_IN - const accountsControllerMessenger = this.controllerMessenger.getRestricted({ - name: 'AccountsController', - allowedEvents: [ - 'SnapController:stateChange', - 'KeyringController:accountRemoved', - 'KeyringController:stateChange', - ], - }); - - this.accountsController = new AccountsController({ - messenger: accountsControllerMessenger, - state: initState.AccountsController, - keyringController: this.keyringController, - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) - snapController: this.snapController, - ///: END:ONLY_INCLUDE_IN - onKeyringStateChange: keyringControllerMessenger.subscribe.bind( - keyringControllerMessenger, - 'KeyringController:stateChange', - ), - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) - onSnapStateChange: this.controllerMessenger.subscribe.bind( - this.controllerMessenger, - 'SnapController:stateChange', - ), - ///: END:ONLY_INCLUDE_IN - }); - // account tracker watches balances, nonces, and any code at their address this.accountTracker = new AccountTracker({ provider: this.provider, diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 533907a835a3..7272f1e8ce6d 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -1123,6 +1123,19 @@ "koa>content-disposition>safe-buffer": true } }, + "@metamask/eth-snap-keyring": { + "globals": { + "console.error": true + }, + "packages": { + "@ethereumjs/tx": true, + "@metamask/eth-snap-keyring>@metamask/keyring-api": true, + "@metamask/eth-snap-keyring>@metamask/utils": true, + "@metamask/eth-snap-keyring>uuid": true, + "browserify>events": true, + "superstruct": true + } + }, "@metamask/eth-snap-keyring>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, @@ -1149,6 +1162,49 @@ "crypto": true } }, + "@metamask/eth-snap-keyring>@metamask/keyring-api": { + "packages": { + "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": true, + "@metamask/eth-snap-keyring>@metamask/keyring-api>uuid": true, + "superstruct": true + } + }, + "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/eth-snap-keyring>@metamask/keyring-api>uuid": { + "globals": { + "crypto": true + } + }, + "@metamask/eth-snap-keyring>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/eth-snap-keyring>uuid": { + "globals": { + "crypto": true + } + }, "@metamask/eth-token-tracker": { "globals": { "console.warn": true diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 0eaa5467fb28..db96c9850956 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -1123,6 +1123,19 @@ "koa>content-disposition>safe-buffer": true } }, + "@metamask/eth-snap-keyring": { + "globals": { + "console.error": true + }, + "packages": { + "@ethereumjs/tx": true, + "@metamask/eth-snap-keyring>@metamask/keyring-api": true, + "@metamask/eth-snap-keyring>@metamask/utils": true, + "@metamask/eth-snap-keyring>uuid": true, + "browserify>events": true, + "superstruct": true + } + }, "@metamask/eth-snap-keyring>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, @@ -1149,6 +1162,49 @@ "crypto": true } }, + "@metamask/eth-snap-keyring>@metamask/keyring-api": { + "packages": { + "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": true, + "@metamask/eth-snap-keyring>@metamask/keyring-api>uuid": true, + "superstruct": true + } + }, + "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/eth-snap-keyring>@metamask/keyring-api>uuid": { + "globals": { + "crypto": true + } + }, + "@metamask/eth-snap-keyring>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/eth-snap-keyring>uuid": { + "globals": { + "crypto": true + } + }, "@metamask/eth-token-tracker": { "globals": { "console.warn": true diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 21f77e06a822..d7bb04fd769d 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -1264,6 +1264,19 @@ "koa>content-disposition>safe-buffer": true } }, + "@metamask/eth-snap-keyring": { + "globals": { + "console.error": true + }, + "packages": { + "@ethereumjs/tx": true, + "@metamask/eth-snap-keyring>@metamask/keyring-api": true, + "@metamask/eth-snap-keyring>@metamask/utils": true, + "@metamask/eth-snap-keyring>uuid": true, + "browserify>events": true, + "superstruct": true + } + }, "@metamask/eth-snap-keyring>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, @@ -1290,6 +1303,49 @@ "crypto": true } }, + "@metamask/eth-snap-keyring>@metamask/keyring-api": { + "packages": { + "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": true, + "@metamask/eth-snap-keyring>@metamask/keyring-api>uuid": true, + "superstruct": true + } + }, + "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/eth-snap-keyring>@metamask/keyring-api>uuid": { + "globals": { + "crypto": true + } + }, + "@metamask/eth-snap-keyring>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/eth-snap-keyring>uuid": { + "globals": { + "crypto": true + } + }, "@metamask/eth-token-tracker": { "globals": { "console.warn": true diff --git a/ui/pages/confirm-transaction/confirm-transaction.component.js b/ui/pages/confirm-transaction/confirm-transaction.component.js index 8ea69cbbb778..b570ea059164 100644 --- a/ui/pages/confirm-transaction/confirm-transaction.component.js +++ b/ui/pages/confirm-transaction/confirm-transaction.component.js @@ -47,7 +47,6 @@ import ConfirmSignatureRequest from '../confirm-signature-request'; import ConfirmTokenTransactionSwitch from './confirm-token-transaction-switch'; const ConfirmTransaction = () => { - console.log('here'); const dispatch = useDispatch(); const history = useHistory(); const { id: paramsTransactionId } = useParams(); @@ -58,8 +57,6 @@ const ConfirmTransaction = () => { const mostRecentOverviewPage = useSelector(getMostRecentOverviewPage); const sendTo = useSelector(getSendTo); - console.log('sendTo', sendTo); - const unconfirmedTxsSorted = useSelector(unconfirmedTransactionsListSelector); const unconfirmedTxs = useSelector(unconfirmedTransactionsHashSelector); @@ -95,8 +92,6 @@ const ConfirmTransaction = () => { const { id, type } = transaction; const transactionId = id && String(id); const isValidTokenMethod = isTokenMethodAction(type); - console.log('transactionId', transactionId); - console.log('transactionId', paramsTransactionId); const isValidTransactionId = transactionId && (!paramsTransactionId || paramsTransactionId === transactionId); diff --git a/ui/selectors/confirm-transaction.js b/ui/selectors/confirm-transaction.js index 5646bc27035f..70566ab9a0d2 100644 --- a/ui/selectors/confirm-transaction.js +++ b/ui/selectors/confirm-transaction.js @@ -107,7 +107,6 @@ export const unconfirmedTransactionsHashSelector = createSelector( }, {}, ); - console.log(111, filteredUnapprovedTxs); return { ...filteredUnapprovedTxs, From 95d686a54f29757297575a8e3995fee53398267b Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Tue, 29 Aug 2023 01:29:00 +0800 Subject: [PATCH 060/235] fix: change identities to internal accounts in permissions controller --- .../controllers/permissions/specifications.js | 61 +++- .../permissions/specifications.test.js | 345 ++++++++++++++---- app/scripts/metamask-controller.js | 25 +- 3 files changed, 338 insertions(+), 93 deletions(-) diff --git a/app/scripts/controllers/permissions/specifications.js b/app/scripts/controllers/permissions/specifications.js index 42f685bfbf2e..f1954ea76b16 100644 --- a/app/scripts/controllers/permissions/specifications.js +++ b/app/scripts/controllers/permissions/specifications.js @@ -50,10 +50,10 @@ const CaveatFactories = Object.freeze({ * PermissionController. * * @param {{ - * getIdentities: () => Record, + * getInternalAccounts: () => Record, * }} options - Options bag. */ -export const getCaveatSpecifications = ({ getIdentities }) => { +export const getCaveatSpecifications = ({ getInternalAccounts }) => { return { [CaveatTypes.restrictReturnedAccounts]: { type: CaveatTypes.restrictReturnedAccounts, @@ -66,7 +66,7 @@ export const getCaveatSpecifications = ({ getIdentities }) => { }, validator: (caveat, _origin, _target) => - validateCaveatAccounts(caveat.value, getIdentities), + validateCaveatAccounts(caveat.value, getInternalAccounts), }, ///: BEGIN:ONLY_INCLUDE_IN(snaps) @@ -95,7 +95,7 @@ export const getCaveatSpecifications = ({ getIdentities }) => { */ export const getPermissionSpecifications = ({ getAllAccounts, - getIdentities, + getInternalAccounts, captureKeyringTypesWithMissingIdentities, }) => { return { @@ -130,31 +130,49 @@ export const getPermissionSpecifications = ({ methodImplementation: async (_args) => { const accounts = await getAllAccounts(); - const identities = getIdentities(); + const internalAccounts = getInternalAccounts(); return accounts.sort((firstAddress, secondAddress) => { - if (!identities[firstAddress]) { - captureKeyringTypesWithMissingIdentities(identities, accounts); + const firstAccount = internalAccounts.find( + (internalAccount) => + internalAccount.address.toLowerCase() === + firstAddress.toLowerCase(), + ); + + const secondAccount = internalAccounts.find( + (internalAccount) => + internalAccount.address.toLowerCase() === + secondAddress.toLowerCase(), + ); + + if (!firstAccount) { + captureKeyringTypesWithMissingIdentities( + internalAccounts, + accounts, + ); throw new Error(`Missing identity for address: "${firstAddress}".`); - } else if (!identities[secondAddress]) { - captureKeyringTypesWithMissingIdentities(identities, accounts); + } else if (!secondAccount) { + captureKeyringTypesWithMissingIdentities( + internalAccounts, + accounts, + ); throw new Error( `Missing identity for address: "${secondAddress}".`, ); } else if ( - identities[firstAddress].lastSelected === - identities[secondAddress].lastSelected + firstAccount.metadata?.lastSelected === + secondAccount.metadata?.lastSelected ) { return 0; - } else if (identities[firstAddress].lastSelected === undefined) { + } else if (firstAccount.metadata?.lastSelected === undefined) { return 1; - } else if (identities[secondAddress].lastSelected === undefined) { + } else if (secondAccount.metadata?.lastSelected === undefined) { return -1; } return ( - identities[secondAddress].lastSelected - - identities[firstAddress].lastSelected + secondAccount.metadata?.lastSelected - + firstAccount.metadata?.lastSelected ); }); }, @@ -181,17 +199,17 @@ export const getPermissionSpecifications = ({ * corresponds to a PreferencesController identity. * * @param {string[]} accounts - The accounts associated with the caveat. - * @param {() => Record} getIdentities - Gets all + * @param {() => Record} getInternalAccounts - Gets all * PreferencesController identities. */ -function validateCaveatAccounts(accounts, getIdentities) { +function validateCaveatAccounts(accounts, getInternalAccounts) { if (!Array.isArray(accounts) || accounts.length === 0) { throw new Error( `${PermissionNames.eth_accounts} error: Expected non-empty array of Ethereum addresses.`, ); } - const identities = getIdentities(); + const internalAccounts = getInternalAccounts(); accounts.forEach((address) => { if (!address || typeof address !== 'string') { throw new Error( @@ -199,7 +217,12 @@ function validateCaveatAccounts(accounts, getIdentities) { ); } - if (!identities[address]) { + if ( + !internalAccounts.find( + (internalAccount) => + internalAccount.address.toLowerCase() === address.toLowerCase(), + ) + ) { throw new Error( `${PermissionNames.eth_accounts} error: Received unrecognized address: "${address}".`, ); diff --git a/app/scripts/controllers/permissions/specifications.test.js b/app/scripts/controllers/permissions/specifications.test.js index f716ddaba269..6957ae6da438 100644 --- a/app/scripts/controllers/permissions/specifications.test.js +++ b/app/scripts/controllers/permissions/specifications.test.js @@ -47,10 +47,10 @@ describe('PermissionController specifications', () => { describe('restrictReturnedAccounts', () => { describe('decorator', () => { it('only returns array members included in the caveat value', async () => { - const getIdentities = jest.fn(); - const { decorator } = getCaveatSpecifications({ getIdentities })[ - CaveatTypes.restrictReturnedAccounts - ]; + const getInternalAccounts = jest.fn(); + const { decorator } = getCaveatSpecifications({ + getInternalAccounts, + })[CaveatTypes.restrictReturnedAccounts]; const method = async () => ['0x1', '0x2', '0x3']; const caveat = { @@ -62,10 +62,10 @@ describe('PermissionController specifications', () => { }); it('returns an empty array if no array members are included in the caveat value', async () => { - const getIdentities = jest.fn(); - const { decorator } = getCaveatSpecifications({ getIdentities })[ - CaveatTypes.restrictReturnedAccounts - ]; + const getInternalAccounts = jest.fn(); + const { decorator } = getCaveatSpecifications({ + getInternalAccounts, + })[CaveatTypes.restrictReturnedAccounts]; const method = async () => ['0x1', '0x2', '0x3']; const caveat = { @@ -77,10 +77,10 @@ describe('PermissionController specifications', () => { }); it('returns an empty array if the method result is an empty array', async () => { - const getIdentities = jest.fn(); - const { decorator } = getCaveatSpecifications({ getIdentities })[ - CaveatTypes.restrictReturnedAccounts - ]; + const getInternalAccounts = jest.fn(); + const { decorator } = getCaveatSpecifications({ + getInternalAccounts, + })[CaveatTypes.restrictReturnedAccounts]; const method = async () => []; const caveat = { @@ -94,10 +94,10 @@ describe('PermissionController specifications', () => { describe('validator', () => { it('rejects invalid array values', () => { - const getIdentities = jest.fn(); - const { validator } = getCaveatSpecifications({ getIdentities })[ - CaveatTypes.restrictReturnedAccounts - ]; + const getInternalAccounts = jest.fn(); + const { validator } = getCaveatSpecifications({ + getInternalAccounts, + })[CaveatTypes.restrictReturnedAccounts]; [null, 'foo', {}, []].forEach((invalidValue) => { expect(() => validator({ value: invalidValue })).toThrow( @@ -107,10 +107,10 @@ describe('PermissionController specifications', () => { }); it('rejects falsy or non-string addresses', () => { - const getIdentities = jest.fn(); - const { validator } = getCaveatSpecifications({ getIdentities })[ - CaveatTypes.restrictReturnedAccounts - ]; + const getInternalAccounts = jest.fn(); + const { validator } = getCaveatSpecifications({ + getInternalAccounts, + })[CaveatTypes.restrictReturnedAccounts]; [[{}], [[]], [null], ['']].forEach((invalidValue) => { expect(() => validator({ value: invalidValue })).toThrow( @@ -120,16 +120,62 @@ describe('PermissionController specifications', () => { }); it('rejects addresses that have no corresponding identity', () => { - const getIdentities = jest.fn().mockImplementationOnce(() => { - return { - '0x1': true, - '0x3': true, - }; + const getInternalAccounts = jest.fn().mockImplementationOnce(() => { + return [ + { + address: '0x1', + id: '21066553-d8c8-4cdc-af33-efc921cd3ca9', + metadata: { + lastSelected: 1, + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + { + address: '0x3', + id: 'ff8fda69-d416-4d25-80a2-efb77bc7d4ad', + metadata: { + lastSelected: 3, + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account 3', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + ]; }); - const { validator } = getCaveatSpecifications({ getIdentities })[ - CaveatTypes.restrictReturnedAccounts - ]; + const { validator } = getCaveatSpecifications({ + getInternalAccounts, + })[CaveatTypes.restrictReturnedAccounts]; expect(() => validator({ value: ['0x1', '0x2', '0x3'] })).toThrow( /Received unrecognized address:/u, @@ -151,10 +197,10 @@ describe('PermissionController specifications', () => { describe('eth_accounts', () => { describe('factory', () => { it('constructs a valid eth_accounts permission', () => { - const getIdentities = jest.fn(); + const getInternalAccounts = jest.fn(); const getAllAccounts = jest.fn(); const { factory } = getPermissionSpecifications({ - getIdentities, + getInternalAccounts, getAllAccounts, })[RestrictedMethods.eth_accounts]; @@ -178,10 +224,10 @@ describe('PermissionController specifications', () => { }); it('throws an error if no approvedAccounts are specified', () => { - const getIdentities = jest.fn(); + const getInternalAccounts = jest.fn(); const getAllAccounts = jest.fn(); const { factory } = getPermissionSpecifications({ - getIdentities, + getInternalAccounts, getAllAccounts, })[RestrictedMethods.eth_accounts]; @@ -194,10 +240,10 @@ describe('PermissionController specifications', () => { }); it('throws an error if any caveats are specified directly', () => { - const getIdentities = jest.fn(); + const getInternalAccounts = jest.fn(); const getAllAccounts = jest.fn(); const { factory } = getPermissionSpecifications({ - getIdentities, + getInternalAccounts, getAllAccounts, })[RestrictedMethods.eth_accounts]; @@ -221,26 +267,111 @@ describe('PermissionController specifications', () => { describe('methodImplementation', () => { it('returns the keyring accounts in lastSelected order', async () => { - const getIdentities = jest.fn().mockImplementationOnce(() => { - return { - '0x1': { - lastSelected: 1, + const getInternalAccounts = jest.fn().mockImplementationOnce(() => { + return [ + { + address: '0x1', + id: '21066553-d8c8-4cdc-af33-efc921cd3ca9', + metadata: { + lastSelected: 1, + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, - '0x2': {}, - '0x3': { - lastSelected: 3, + { + address: '0x2', + id: '0bd7348e-bdfe-4f67-875c-de831a583857', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, - '0x4': { - lastSelected: 3, + { + address: '0x3', + id: 'ff8fda69-d416-4d25-80a2-efb77bc7d4ad', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + lastSelected: 3, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, - }; + { + address: '0x4', + id: '0bd7348e-bdfe-4f67-875c-de831a583857', + metadata: { + lastSelected: 3, + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + ]; }); const getAllAccounts = jest .fn() .mockImplementationOnce(() => ['0x1', '0x2', '0x3', '0x4']); const { methodImplementation } = getPermissionSpecifications({ - getIdentities, + getInternalAccounts, getAllAccounts, })[RestrictedMethods.eth_accounts]; @@ -253,22 +384,64 @@ describe('PermissionController specifications', () => { }); it('throws if a keyring account is missing an address (case 1)', async () => { - const getIdentities = jest.fn().mockImplementationOnce(() => { - return { - '0x2': { - lastSelected: 3, + const getInternalAccounts = jest.fn().mockImplementationOnce(() => { + return [ + { + address: '0x2', + id: '0bd7348e-bdfe-4f67-875c-de831a583857', + metadata: { + lastSelected: 2, + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, - '0x3': { - lastSelected: 3, + { + address: '0x3', + id: 'ff8fda69-d416-4d25-80a2-efb77bc7d4ad', + metadata: { + lastSelected: 3, + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, - }; + ]; }); const getAllAccounts = jest .fn() .mockImplementationOnce(() => ['0x1', '0x2', '0x3']); const { methodImplementation } = getPermissionSpecifications({ - getIdentities, + getInternalAccounts, getAllAccounts, captureKeyringTypesWithMissingIdentities: jest.fn(), })[RestrictedMethods.eth_accounts]; @@ -279,22 +452,64 @@ describe('PermissionController specifications', () => { }); it('throws if a keyring account is missing an address (case 2)', async () => { - const getIdentities = jest.fn().mockImplementationOnce(() => { - return { - '0x1': { - lastSelected: 1, + const getInternalAccounts = jest.fn().mockImplementationOnce(() => { + return [ + { + address: '0x1', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + lastSelected: 1, + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, - '0x3': { - lastSelected: 3, + { + address: '0x3', + id: 'ff8fda69-d416-4d25-80a2-efb77bc7d4ad', + metadata: { + lastSelected: 3, + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, - }; + ]; }); const getAllAccounts = jest .fn() .mockImplementationOnce(() => ['0x1', '0x2', '0x3']); const { methodImplementation } = getPermissionSpecifications({ - getIdentities, + getInternalAccounts, getAllAccounts, captureKeyringTypesWithMissingIdentities: jest.fn(), })[RestrictedMethods.eth_accounts]; @@ -307,10 +522,10 @@ describe('PermissionController specifications', () => { describe('validator', () => { it('accepts valid permissions', () => { - const getIdentities = jest.fn(); + const getInternalAccounts = jest.fn(); const getAllAccounts = jest.fn(); const { validator } = getPermissionSpecifications({ - getIdentities, + getInternalAccounts, getAllAccounts, })[RestrictedMethods.eth_accounts]; @@ -331,10 +546,10 @@ describe('PermissionController specifications', () => { }); it('rejects invalid caveats', () => { - const getIdentities = jest.fn(); + const getInternalAccounts = jest.fn(); const getAllAccounts = jest.fn(); const { validator } = getPermissionSpecifications({ - getIdentities, + getInternalAccounts, getAllAccounts, })[RestrictedMethods.eth_accounts]; diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 3016dbe07d90..e59775b3a04a 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -829,9 +829,6 @@ export default class MetamaskController extends EventEmitter { this.keyringController = this.coreKeyringController.getEthKeyringController(); - const getIdentities = () => - this.preferencesController.store.getState().identities; - const accountsControllerMessenger = this.controllerMessenger.getRestricted({ name: 'AccountsController', allowedEvents: [ @@ -881,26 +878,36 @@ export default class MetamaskController extends EventEmitter { ], }), state: initState.PermissionController, - caveatSpecifications: getCaveatSpecifications({ getIdentities }), + caveatSpecifications: getCaveatSpecifications({ + getInternalAccounts: this.accountsController.listAccounts.bind( + this.accountsController, + ), + }), permissionSpecifications: { ...getPermissionSpecifications({ - getIdentities, + getInternalAccounts: this.accountsController.listAccounts.bind( + this.accountsController, + ), getAllAccounts: this.keyringController.getAccounts.bind( this.keyringController, ), captureKeyringTypesWithMissingIdentities: ( - identities = {}, + internalAccounts = [], accounts = [], ) => { const accountsMissingIdentities = accounts.filter( - (address) => !identities[address], + (address) => + !internalAccounts.find( + (account) => + account.address.toLowerCase() === address.toLowerCase(), + ), ); const keyringTypesWithMissingIdentities = accountsMissingIdentities.map((address) => this.coreKeyringController.getAccountKeyringType(address), ); - const identitiesCount = Object.keys(identities || {}).length; + const internalAccountCount = internalAccounts.length; const accountTrackerCount = Object.keys( this.accountTracker.store.getState().accounts || {}, @@ -908,7 +915,7 @@ export default class MetamaskController extends EventEmitter { captureException( new Error( - `Attempt to get permission specifications failed because their were ${accounts.length} accounts, but ${identitiesCount} identities, and the ${keyringTypesWithMissingIdentities} keyrings included accounts with missing identities. Meanwhile, there are ${accountTrackerCount} accounts in the account tracker.`, + `Attempt to get permission specifications failed because their were ${accounts.length} accounts, but ${internalAccountCount} identities, and the ${keyringTypesWithMissingIdentities} keyrings included accounts with missing identities. Meanwhile, there are ${accountTrackerCount} accounts in the account tracker.`, ), ); }, From 8ccfd69c5e468cb5968bed5431f8ec7a2092a65a Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Tue, 29 Aug 2023 11:25:03 +0800 Subject: [PATCH 061/235] fix: update error snapshot --- test/e2e/nft/erc721-interaction.spec.js | 494 ++++++++++++++++++ ...rs-after-init-opt-in-background-state.json | 3 +- .../errors-after-init-opt-in-ui-state.json | 2 +- 3 files changed, 496 insertions(+), 3 deletions(-) create mode 100644 test/e2e/nft/erc721-interaction.spec.js diff --git a/test/e2e/nft/erc721-interaction.spec.js b/test/e2e/nft/erc721-interaction.spec.js new file mode 100644 index 000000000000..e979a8530600 --- /dev/null +++ b/test/e2e/nft/erc721-interaction.spec.js @@ -0,0 +1,494 @@ +const { strict: assert } = require('assert'); +const { convertToHexValue, withFixtures, openDapp } = require('../helpers'); +const { SMART_CONTRACTS } = require('../seeder/smart-contracts'); +const FixtureBuilder = require('../fixture-builder'); + +describe('ERC721 NFTs testdapp interaction', function () { + const smartContract = SMART_CONTRACTS.NFTS; + const ganacheOptions = { + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: convertToHexValue(25000000000000000000), + }, + ], + }; + + it('should prompt users to add their NFTs to their wallet (one by one)', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + smartContract, + title: this.test.title, + failOnConsoleError: false, + }, + async ({ driver, _, contractRegistry }) => { + const contract = contractRegistry.getContractAddress(smartContract); + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // Open Dapp and wait for deployed contract + await openDapp(driver, contract); + await driver.findClickableElement('#deployButton'); + + // mint NFT + await driver.fill('#mintAmountInput', '5'); + await driver.clickElement({ text: 'Mint', tag: 'button' }); + + // Notification + await driver.waitUntilXWindowHandles(3); + let windowHandles = await driver.getAllWindowHandles(); + const [extension] = windowHandles; + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + await driver.waitForSelector({ + css: '.confirm-page-container-summary__action__name', + text: 'Deposit', + }); + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindow(extension); + await driver.clickElement('[data-testid="home__activity-tab"]'); + const transactionItem = await driver.waitForSelector({ + css: '[data-testid="activity-list-item-action"]', + text: 'Deposit', + }); + assert.equal(await transactionItem.isDisplayed(), true); + + // verify the mint transaction has finished + await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); + const nftsMintStatus = await driver.findElement({ + css: '#nftsStatus', + text: 'Mint completed', + }); + assert.equal(await nftsMintStatus.isDisplayed(), true); + + // watch 3 of the nfts + await driver.clickElement({ text: 'Watch NFT 1', tag: 'button' }); + await driver.clickElement({ text: 'Watch NFT 2', tag: 'button' }); + await driver.clickElement({ text: 'Watch NFT 3', tag: 'button' }); + + await driver.waitUntilXWindowHandles(3); + windowHandles = await driver.getAllWindowHandles(); + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + + // confirm watchNFT + await driver.waitForSelector({ + css: '.mm-text--heading-lg', + text: 'Add suggested NFTs', + }); + await driver.clickElement({ text: 'Add NFTs', tag: 'button' }); + await driver.switchToWindow(extension); + await driver.clickElement({ text: 'NFTs', tag: 'button' }); + await driver.findElement({ text: 'TestDappNFTs (3)' }); + const nftsListItemsFirstCheck = await driver.findElements( + '.nft-item__container', + ); + assert.equal(nftsListItemsFirstCheck.length, 3); + + await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); + await driver.clickElement({ text: 'Watch NFT 4', tag: 'button' }); + await driver.clickElement({ text: 'Watch NFT 5', tag: 'button' }); + await driver.clickElement({ text: 'Watch NFT 6', tag: 'button' }); + + await driver.waitUntilXWindowHandles(3); + windowHandles = await driver.getAllWindowHandles(); + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + + // confirm watchNFT + await driver.waitForSelector({ + css: '.mm-text--heading-lg', + text: 'Add suggested NFTs', + }); + await driver.clickElement({ text: 'Add NFTs', tag: 'button' }); + await driver.switchToWindow(extension); + await driver.clickElement({ text: 'NFTs', tag: 'button' }); + await driver.findElement({ text: 'TestDappNFTs (6)' }); + const nftsListItemsSecondCheck = await driver.findElements( + '.nft-item__container', + ); + assert.equal(nftsListItemsSecondCheck.length, 6); + }, + ); + }); + + it('should prompt users to add their NFTs to their wallet (all at once)', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + smartContract, + title: this.test.title, + failOnConsoleError: false, + }, + async ({ driver, _, contractRegistry }) => { + const contract = contractRegistry.getContractAddress(smartContract); + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // Open Dapp and wait for deployed contract + await openDapp(driver, contract); + await driver.findClickableElement('#deployButton'); + + // mint NFT + await driver.fill('#mintAmountInput', '5'); + await driver.clickElement({ text: 'Mint', tag: 'button' }); + + // Notification + await driver.waitUntilXWindowHandles(3); + let windowHandles = await driver.getAllWindowHandles(); + const [extension] = windowHandles; + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + await driver.waitForSelector({ + css: '.confirm-page-container-summary__action__name', + text: 'Deposit', + }); + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindow(extension); + await driver.clickElement('[data-testid="home__activity-tab"]'); + const transactionItem = await driver.waitForSelector({ + css: '[data-testid="activity-list-item-action"]', + text: 'Deposit', + }); + assert.equal(await transactionItem.isDisplayed(), true); + // verify the mint transaction has finished + await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); + const nftsMintStatus = await driver.findElement({ + css: '#nftsStatus', + text: 'Mint completed', + }); + assert.equal(await nftsMintStatus.isDisplayed(), true); + + // watch all nfts + await driver.clickElement({ text: 'Watch all NFTs', tag: 'button' }); + + await driver.waitUntilXWindowHandles(3); + windowHandles = await driver.getAllWindowHandles(); + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + + // confirm watchNFT + await driver.waitForSelector({ + css: '.mm-text--heading-lg', + text: 'Add suggested NFTs', + }); + + await driver.findElements('.confirm-add-suggested-nft__nft-list-item'); + const suggestedNftListItems = await driver.findElements( + '.confirm-add-suggested-nft__nft-list-item', + ); + // there are 6 nfts to add because one is minted as part of the fixture + assert.equal(suggestedNftListItems.length, 6); + + // remove one nft from the list + const removeButtons = await driver.findElements( + '.confirm-add-suggested-nft__nft-remove', + ); + await removeButtons[0].click(); + + await driver.clickElement({ text: 'Add NFTs', tag: 'button' }); + await driver.switchToWindow(extension); + await driver.clickElement({ text: 'NFTs', tag: 'button' }); + await driver.findElement({ text: 'TestDappNFTs (5)' }); + const nftsListItemsSecondCheck = await driver.findElements( + '.nft-item__container', + ); + + assert.equal(nftsListItemsSecondCheck.length, 5); + }, + ); + }); + + it('should transfer a single ERC721 NFT from one account to another', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + smartContract, + title: this.test.title, + failOnConsoleError: false, + }, + async ({ driver, _, contractRegistry }) => { + const contract = contractRegistry.getContractAddress(smartContract); + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // Open Dapp and wait for deployed contract + await openDapp(driver, contract); + await driver.findClickableElement('#deployButton'); + + // Click Transer + await driver.fill('#transferTokenInput', '1'); + await driver.clickElement('#transferFromButton'); + await driver.waitUntilXWindowHandles(3); + const windowHandles = await driver.getAllWindowHandles(); + const [extension] = windowHandles; + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + + // Confirm transfer + await driver.waitForSelector({ + css: '.mm-text--heading-md', + text: 'TestDappNFTs', + }); + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindow(extension); + await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.waitForSelector( + '.transaction-list__completed-transactions .activity-list-item:nth-of-type(1)', + ); + + // Verify transaction + await driver.findElement({ text: 'Send TDN' }); + }, + ); + }); + + it('should approve an address to transfer a single ERC721 NFT', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + smartContract, + title: this.test.title, + failOnConsoleError: false, + }, + async ({ driver, _, contractRegistry }) => { + const contract = contractRegistry.getContractAddress(smartContract); + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // Open Dapp and wait for deployed contract + await openDapp(driver, contract); + await driver.findClickableElement('#deployButton'); + + // Click Approve + const approveInput = await driver.findElement('#approveTokenInput'); + await approveInput.clear(); + await approveInput.sendKeys('1'); + await driver.clickElement('#approveButton'); + + await driver.waitUntilXWindowHandles(3); + const windowHandles = await driver.getAllWindowHandles(); + const [extension] = windowHandles; + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + + // Verify dialog + const title = await driver.findElement( + '[data-testid="confirm-approve-title"]', + ); + await driver.clickElement({ + text: 'View full transaction details', + css: '.confirm-approve-content__small-blue-text', + }); + const [func] = await driver.findElements( + '.confirm-approve-content__data .confirm-approve-content__small-text', + ); + assert.equal( + await title.getText(), + 'Allow access to and transfer of your TestDappNFTs (#1)?', + ); + assert.equal(await func.getText(), 'Function: Approve'); + + // Confirm approval + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindow(extension); + await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.waitForSelector( + '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', + ); + + // Verify transaction + const completedTx = await driver.waitForSelector({ + css: '[data-testid="activity-list-item-action"]', + text: 'Approve TDN spending cap', + }); + assert.equal(await completedTx.isDisplayed(), true); + }, + ); + }); + + it('should enable approval for a third party address to manage all ERC721 NFTs', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + smartContract, + title: this.test.title, + failOnConsoleError: false, + }, + async ({ driver, _, contractRegistry }) => { + const contract = contractRegistry.getContractAddress(smartContract); + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // Open Dapp and wait for deployed contract + await openDapp(driver, contract); + await driver.findClickableElement('#deployButton'); + + // Enable Set approval for all + await driver.clickElement('#setApprovalForAllButton'); + await driver.waitUntilXWindowHandles(3); + const windowHandles = await driver.getAllWindowHandles(); + const [extension] = windowHandles; + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + + // Verify dialog + const title = await driver.findElement( + '[data-testid="confirm-approve-title"]', + ); + await driver.clickElement({ + text: 'View full transaction details', + css: '.confirm-approve-content__small-blue-text', + }); + const [func, params] = await driver.findElements( + '.confirm-approve-content__data .confirm-approve-content__small-text', + ); + assert.equal( + await title.getText(), + 'Allow access to and transfer of all your TestDappNFTs?', + ); + assert.equal(await func.getText(), 'Function: SetApprovalForAll'); + assert.equal(await params.getText(), 'Parameters: true'); + + // Confirm enabling set approval for all + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + await driver.clickElement({ text: 'Approve', tag: 'button' }); + + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindow(extension); + await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.waitForSelector( + '.transaction-list__completed-transactions .activity-list-item:nth-of-type(1)', + ); + + // Verify transaction + const completedTx = await driver.waitForSelector({ + css: '[data-testid="activity-list-item-action"]', + text: 'Approve TDN with no spend limit', + }); + assert.equal(await completedTx.isDisplayed(), true); + }, + ); + }); + + it('should disable approval for a third party address to manage all ERC721 NFTs', async function () { + await withFixtures( + { + dapp: true, + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + smartContract, + title: this.test.title, + failOnConsoleError: false, + }, + async ({ driver, _, contractRegistry }) => { + const contract = contractRegistry.getContractAddress(smartContract); + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // Open Dapp and wait for deployed contract + await openDapp(driver, contract); + await driver.findClickableElement('#deployButton'); + + // Disable Set approval for all + await driver.clickElement('#revokeButton'); + await driver.waitUntilXWindowHandles(3); + const windowHandles = await driver.getAllWindowHandles(); + const [extension] = windowHandles; + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + + // Verify dialog + const title = await driver.findElement( + '[data-testid="confirm-approve-title"]', + ); + await driver.clickElement({ + text: 'View full transaction details', + css: '.confirm-approve-content__small-blue-text', + }); + const [func, params] = await driver.findElements( + '.confirm-approve-content__data .confirm-approve-content__small-text', + ); + const proceedWithCautionIsDisplayed = await driver.isElementPresent( + '.dialog--error', + ); + assert.equal( + await title.getText(), + 'Revoke permission to access and transfer all of your TestDappNFTs?', + ); + assert.equal(await func.getText(), 'Function: SetApprovalForAll'); + assert.equal(await params.getText(), 'Parameters: false'); + assert.equal(proceedWithCautionIsDisplayed, false); + + // Confirm disabling set approval for all + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + + await driver.waitUntilXWindowHandles(2); + await driver.switchToWindow(extension); + await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.waitForSelector( + '.transaction-list__completed-transactions .transaction-list-item:nth-of-type(1)', + ); + + // Verify transaction + const completedTx = await driver.waitForSelector({ + css: '[data-testid="activity-list-item-action"]', + text: 'Approve TDN with no spend limit', + }); + assert.equal(await completedTx.isDisplayed(), true); + }, + ); + }); +}); diff --git a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json index 2af8eaa93abf..7f19f7508614 100644 --- a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json +++ b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json @@ -131,8 +131,7 @@ "snapRegistryList": "object", "transactionSecurityCheckEnabled": "boolean", "theme": "string", - "isLineaMainnetReleased": "boolean", - "selectedAddress": "string" + "isLineaMainnetReleased": "boolean" }, "SignatureController": { "unapprovedMsgs": "object", diff --git a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json index 959791e02982..7e07699b2823 100644 --- a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json +++ b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json @@ -88,6 +88,7 @@ "openSeaEnabled": "boolean", "advancedGasFee": "object", "incomingTransactionsPreferences": "object", + "identities": "object", "lostIdentities": "object", "forgottenPassword": false, "ipfsGateway": "dweb.link", @@ -98,7 +99,6 @@ "transactionSecurityCheckEnabled": "boolean", "theme": "string", "isLineaMainnetReleased": "boolean", - "selectedAddress": "string", "metaMetricsId": "fake-metrics-id", "eventsBeforeMetricsOptIn": "object", "traits": "object", From 56c69aa956e6fafd5d6efbbefa082f7f634b9587 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Tue, 29 Aug 2023 14:32:42 +0800 Subject: [PATCH 062/235] fix: update backup to save accountsControllerState --- app/scripts/lib/backup.js | 14 +++++++++-- app/scripts/lib/backup.test.js | 45 ++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/app/scripts/lib/backup.js b/app/scripts/lib/backup.js index 01c49e0b14cb..7fda93995766 100644 --- a/app/scripts/lib/backup.js +++ b/app/scripts/lib/backup.js @@ -5,11 +5,13 @@ export default class Backup { const { preferencesController, addressBookController, + accountsController, networkController, trackMetaMetricsEvent, } = opts; this.preferencesController = preferencesController; + this.accountsController = accountsController; this.addressBookController = addressBookController; this.networkController = networkController; this._trackMetaMetricsEvent = trackMetaMetricsEvent; @@ -17,7 +19,8 @@ export default class Backup { async restoreUserData(jsonString) { const existingPreferences = this.preferencesController.store.getState(); - const { preferences, addressBook, network } = JSON.parse(jsonString); + const { preferences, addressBook, network, internalAccounts } = + JSON.parse(jsonString); if (preferences) { preferences.identities = existingPreferences.identities; preferences.lostIdentities = existingPreferences.lostIdentities; @@ -34,7 +37,11 @@ export default class Backup { this.networkController.loadBackup(network); } - if (preferences || addressBook || network) { + if (internalAccounts) { + this.accountsController.loadBackup(internalAccounts); + } + + if (preferences || addressBook || network || internalAccounts) { this._trackMetaMetricsEvent({ event: 'User Data Imported', category: 'Backup', @@ -45,6 +52,9 @@ export default class Backup { async backupUserData() { const userData = { preferences: { ...this.preferencesController.store.getState() }, + internalAccounts: { + internalAccounts: this.accountsController.state.internalAccounts, + }, addressBook: { ...this.addressBookController.state }, network: { networkConfigurations: diff --git a/app/scripts/lib/backup.test.js b/app/scripts/lib/backup.test.js index 93aee74bddd7..ea6028d23c8b 100644 --- a/app/scripts/lib/backup.test.js +++ b/app/scripts/lib/backup.test.js @@ -68,6 +68,21 @@ function getMockNetworkController() { return { state, loadBackup }; } +function getMockAccountsController() { + const state = { + internalAccounts: { + accounts: {}, + }, + selectedAccount: '', + }; + + const loadBackup = ({ internalAccounts }) => { + Object.assign(state, { internalAccounts }); + }; + + return { state, loadBackup }; +} + const jsonData = JSON.stringify({ addressBook: { addressBook: { @@ -148,6 +163,35 @@ const jsonData = JSON.stringify({ customNetworkListEnabled: false, textDirection: 'auto', }, + internalAccounts: { + accounts: { + 'fcbcdca4-cc47-4bc8-b455-b14421e9277e': { + address: '0x129af01f4b770b30615f049790e1e206ebaa7b10', + id: 'fcbcdca4-cc47-4bc8-b455-b14421e9277e', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + lastSelected: 1693289751176, + }, + name: 'Account 1', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'fcbcdca4-cc47-4bc8-b455-b14421e9277e', + }, }); describe('Backup', function () { @@ -156,6 +200,7 @@ describe('Backup', function () { preferencesController: getMockPreferencesController(), addressBookController: getMockAddressBookController(), networkController: getMockNetworkController(), + accountsController: getMockAccountsController(), trackMetaMetricsEvent: sinon.stub(), }); }; From 418db3a265aa548ffe1c9907109e755e0da270a0 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Wed, 30 Aug 2023 22:44:33 +0800 Subject: [PATCH 063/235] fix: add accountsController to backup --- app/scripts/metamask-controller.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index f54ff8c168c8..f6404fa9086a 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1201,6 +1201,7 @@ export default class MetamaskController extends EventEmitter { this.backup = new Backup({ preferencesController: this.preferencesController, addressBookController: this.addressBookController, + accountsController: this.accountsController, networkController: this.networkController, trackMetaMetricsEvent: this.metaMetricsController.trackEvent.bind( this.metaMetricsController, From dbf742b63016656fb6efea8a59c59a26f68bd453 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 31 Aug 2023 10:45:59 +0800 Subject: [PATCH 064/235] fix: uncomment tests --- test/e2e/run-all.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/e2e/run-all.js b/test/e2e/run-all.js index 674e1a007373..811f6b8fb94c 100644 --- a/test/e2e/run-all.js +++ b/test/e2e/run-all.js @@ -119,10 +119,10 @@ async function main() { } else { const testDir = path.join(__dirname, 'tests'); testPaths = [ - // ...(await getTestPathsForTestDir(testDir)), + ...(await getTestPathsForTestDir(testDir)), ...(await getTestPathsForTestDir(path.join(__dirname, 'swaps'))), - // ...(await getTestPathsForTestDir(path.join(__dirname, 'nft'))), - // ...(await getTestPathsForTestDir(path.join(__dirname, 'metrics'))), + ...(await getTestPathsForTestDir(path.join(__dirname, 'nft'))), + ...(await getTestPathsForTestDir(path.join(__dirname, 'metrics'))), path.join(__dirname, 'metamask-ui.spec.js'), ]; From 7ed783d4853bb0253ec01f2a8eca6f1d87a2ea48 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 31 Aug 2023 10:47:27 +0800 Subject: [PATCH 065/235] fix: use listener for selectedAccountChange inplace of onPreferencesStateChange in TokensController --- app/scripts/metamask-controller.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index f6404fa9086a..c3604f95848e 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -427,8 +427,18 @@ export default class MetamaskController extends EventEmitter { this.tokensController = new TokensController({ messenger: tokensControllerMessenger, chainId: this.networkController.state.providerConfig.chainId, - onPreferencesStateChange: this.preferencesController.store.subscribe.bind( - this.preferencesController.store, + // TODO: The tokens controller is not updated to the latest version, it currently does not support internalAccounts. + // This is a temporary fix to prevent the tokens controller from breaking. + onPreferencesStateChange: (listener) => + this.controllerMessenger.subscribe( + `AccountsController:selectedAccountChange`, + (newlySelectedInternalAccount) => { + console.log( + 'newlySelectedInternalAccount', + newlySelectedInternalAccount, + ); + listener(newlySelectedInternalAccount.address); + }, ), onNetworkStateChange: networkControllerMessenger.subscribe.bind( networkControllerMessenger, From 1992b301e6599716962f9e381db450cd89762e00 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 31 Aug 2023 11:58:14 +0800 Subject: [PATCH 066/235] fix: onPreferencesStateChange payload for TokensController and fix test --- app/scripts/controllers/detect-tokens.test.js | 81 +++++++++++-------- app/scripts/metamask-controller.js | 6 +- 2 files changed, 50 insertions(+), 37 deletions(-) diff --git a/app/scripts/controllers/detect-tokens.test.js b/app/scripts/controllers/detect-tokens.test.js index 5253f890e3dd..2e1c690315ee 100644 --- a/app/scripts/controllers/detect-tokens.test.js +++ b/app/scripts/controllers/detect-tokens.test.js @@ -232,27 +232,6 @@ describe('DetectTokensController', function () { }); preferences.setUseTokenDetection(true); - tokensController = new TokensController({ - config: { provider }, - onPreferencesStateChange: preferences.store.subscribe.bind( - preferences.store, - ), - onNetworkStateChange: networkControllerMessenger.subscribe.bind( - networkControllerMessenger, - 'NetworkController:stateChange', - ), - }); - - assetsContractController = new AssetsContractController({ - onPreferencesStateChange: preferences.store.subscribe.bind( - preferences.store, - ), - onNetworkStateChange: networkControllerMessenger.subscribe.bind( - networkControllerMessenger, - 'NetworkController:stateChange', - ), - }); - controllerMessenger = new ControllerMessenger(); const accountsControllerMessenger = controllerMessenger.getRestricted({ @@ -270,14 +249,14 @@ describe('DetectTokensController', function () { internalAccounts: { accounts: { 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { - address: '0x7e57e2', + address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', + name: 'Account 1', options: {}, supportedMethods: [ 'personal_sign', @@ -300,7 +279,7 @@ describe('DetectTokensController', function () { type: 'HD Key Tree', }, }, - name: 'Test Account', + name: 'Account 2', options: {}, supportedMethods: [ 'personal_sign', @@ -322,6 +301,34 @@ describe('DetectTokensController', function () { onSnapStateChange: sinon.spy(), onKeyringStateChange: sinon.spy(), }); + + tokensController = new TokensController({ + config: { + provider, + selectedAddress: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', + }, + onPreferencesStateChange: (listener) => + controllerMessenger.subscribe( + `AccountsController:selectedAccountChange`, + (newlySelectedInternalAccount) => { + listener({ selectedAddress: newlySelectedInternalAccount.address }); + }, + ), + onNetworkStateChange: networkControllerMessenger.subscribe.bind( + networkControllerMessenger, + 'NetworkController:stateChange', + ), + }); + + assetsContractController = new AssetsContractController({ + onPreferencesStateChange: preferences.store.subscribe.bind( + preferences.store, + ), + onNetworkStateChange: networkControllerMessenger.subscribe.bind( + networkControllerMessenger, + 'NetworkController:stateChange', + ), + }); }); afterEach(function () { @@ -485,16 +492,26 @@ describe('DetectTokensController', function () { const existingTokenAddress = erc20ContractAddresses[0]; const existingToken = tokenList[existingTokenAddress]; - await tokensController.addDetectedTokens([ + accountsController.setSelectedAccount( + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + ); + + await tokensController.addDetectedTokens( + [ + { + address: existingToken.address, + symbol: existingToken.symbol, + decimals: existingToken.decimals, + aggregators: undefined, + image: undefined, + isERC721: undefined, + }, + ], { - address: existingToken.address, - symbol: existingToken.symbol, - decimals: existingToken.decimals, - aggregators: undefined, - image: undefined, - isERC721: undefined, + selectedAddress: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', + chainId: '0x1', }, - ]); + ); const tokenAddressToAdd = erc20ContractAddresses[1]; const tokenToAdd = tokenList[tokenAddressToAdd]; sandbox diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index c3604f95848e..6a7ac13395a3 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -433,11 +433,7 @@ export default class MetamaskController extends EventEmitter { this.controllerMessenger.subscribe( `AccountsController:selectedAccountChange`, (newlySelectedInternalAccount) => { - console.log( - 'newlySelectedInternalAccount', - newlySelectedInternalAccount, - ); - listener(newlySelectedInternalAccount.address); + listener({ selectedAddress: newlySelectedInternalAccount.address }); }, ), onNetworkStateChange: networkControllerMessenger.subscribe.bind( From 217c59d4e240f4671e4a727169c1619d860f7a21 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 31 Aug 2023 16:44:00 +0800 Subject: [PATCH 067/235] fix: update policy and change from default export of AccountsController --- .../controllers/accounts-controller.ts | 183 +++++----- app/scripts/controllers/detect-tokens.test.js | 2 +- app/scripts/metamask-controller.js | 7 +- builds.yml | 2 + lavamoat/browserify/beta/policy.json | 51 ++- lavamoat/browserify/desktop/policy.json | 51 ++- lavamoat/browserify/flask/policy.json | 51 ++- lavamoat/browserify/main/policy.json | 51 ++- lavamoat/browserify/mmi/policy.json | 51 ++- .../phishing-detection.spec.js | 315 ++++++++++++++++++ yarn.lock | 40 ++- 11 files changed, 702 insertions(+), 102 deletions(-) create mode 100644 test/e2e/tests/phishing-controller/phishing-detection.spec.js diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index 586a03f9c2ff..a2f444f92bf6 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -7,11 +7,10 @@ import type { KeyringController, KeyringControllerEvents, } from '@metamask/keyring-controller'; -///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) -import type { SnapControllerEvents } from '@metamask/snaps-controllers'; -import type { SnapControllerState } from '@metamask/snaps-controllers-flask'; -import type { Snap } from '@metamask/snaps-utils'; -///: END:ONLY_INCLUDE_IN(keyring-snaps) +import type { + SnapControllerEvents, + SnapControllerState, +} from '@metamask/snaps-controllers'; import { sha256FromString } from 'ethereumjs-util'; import type { Patch } from 'immer'; import { v4 as uuid } from 'uuid'; @@ -74,7 +73,7 @@ const defaultState: AccountsControllerState = { }, }; -export default class AccountsController extends BaseControllerV2< +export class AccountsController extends BaseControllerV2< typeof controllerName, AccountsControllerState, AccountsControllerMessenger @@ -85,30 +84,30 @@ export default class AccountsController extends BaseControllerV2< getAccounts: KeyringController['getAccounts']; + keyringApiEnabled: boolean; + constructor({ messenger, state, + keyringApiEnabled, getKeyringForAccount, getKeyringByType, getAccounts, - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) onSnapStateChange, - ///: END:ONLY_INCLUDE_IN(keyring-snaps) onKeyringStateChange, }: { messenger: AccountsControllerMessenger; state: AccountsControllerState; + keyringApiEnabled?: boolean; getKeyringForAccount: KeyringController['getKeyringForAccount']; getKeyringByType: KeyringController['getKeyringsByType']; getAccounts: KeyringController['getAccounts']; onKeyringStateChange: ( listener: (keyringState: KeyringControllerState) => void, ) => void; - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) onSnapStateChange: ( listener: (snapState: SnapControllerState) => void, ) => void; - ///: END:ONLY_INCLUDE_IN(keyring-snaps) }) { super({ messenger, @@ -123,39 +122,32 @@ export default class AccountsController extends BaseControllerV2< this.getKeyringForAccount = getKeyringForAccount; this.getKeyringByType = getKeyringByType; this.getAccounts = getAccounts; + this.keyringApiEnabled = Boolean(keyringApiEnabled); - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) - // eslint-disable-next-line @typescript-eslint/no-misused-promises - onSnapStateChange(async (snapState: SnapControllerState) => { - // only check if snaps changed in status - const { snaps } = snapState; - const accounts = this.listAccounts(); - - const disabledSnaps: Snap[] = Object.values(snaps).filter( - (snap) => !snap.enabled || !snap.blocked, - ); - - const accountsToUpdate = accounts.filter( - (account) => - account.metadata.snap && - disabledSnaps.find((snap) => snap.id === account.metadata.snap?.id), - ); - - this.update((currentState: AccountsControllerState) => { - accountsToUpdate.forEach((account) => { - if ( - currentState.internalAccounts.accounts[account.id]?.metadata?.snap - ) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore this account is guaranteed to have snap metadata - currentState.internalAccounts.accounts[ - account.id - ].metadata.snap.enabled = false; - } + if (this.keyringApiEnabled) { + // eslint-disable-next-line @typescript-eslint/no-misused-promises + onSnapStateChange(async (snapState: SnapControllerState) => { + // only check if snaps changed in status + const { snaps } = snapState; + const accounts = this.listAccounts(); + + this.update((currentState: AccountsControllerState) => { + accounts.forEach((account) => { + const currentAccount = + currentState.internalAccounts.accounts[account.id]; + if (currentAccount?.metadata.snap) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore this account is guaranteed to have snap metadata + currentState.internalAccounts.accounts[ + account.id + ].metadata.snap.enabled = + snaps[currentAccount.metadata.snap.id].enabled && + !snaps[currentAccount.metadata.snap.id].blocked; + } + }); }); }); - }); - ///: END:ONLY_INCLUDE_IN(keyring-snaps) + } onKeyringStateChange( // eslint-disable-next-line @typescript-eslint/no-misused-promises @@ -250,18 +242,54 @@ export default class AccountsController extends BaseControllerV2< return this.getAccountExpect(this.state.internalAccounts.selectedAccount); } + setSelectedAccount(accountId: string): void { + const account = this.getAccountExpect(accountId); + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore Type instantiation is excessively deep and possibly infinite. + this.update((currentState: AccountsControllerState) => { + currentState.internalAccounts.accounts[account.id].metadata.lastSelected = + Date.now(); + currentState.internalAccounts.selectedAccount = account.id; + }); + + this.messagingSystem.publish(`${this.name}:selectedAccountChange`, account); + } + + setAccountName(accountId: string, accountName: string): void { + const account = this.getAccountExpect(accountId); + + if ( + this.listAccounts().find( + (internalAccount) => + internalAccount.name === accountName && + internalAccount.id !== accountId, + ) + ) { + throw new Error('Account name already exists'); + } + + this.update((currentState: AccountsControllerState) => { + currentState.internalAccounts.accounts[accountId] = { + ...account, + name: accountName, + }; + }); + } + async updateAccounts(): Promise { let legacyAccounts = await this.#listLegacyAccounts(); - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) - const snapAccounts = await this.#listSnapAccounts(); - // remove duplicate accounts that are retrieved from the snap keyring. - legacyAccounts = legacyAccounts.filter( - (account) => - !snapAccounts.find( - (snapAccount) => snapAccount.address === account.address, - ), - ); - ///: END:ONLY_INCLUDE_IN(keyring-snaps) + let snapAccounts: InternalAccount[] = []; + if (this.keyringApiEnabled) { + snapAccounts = await this.#listSnapAccounts(); + // remove duplicate accounts that are retrieved from the snap keyring. + legacyAccounts = legacyAccounts.filter( + (account) => + !snapAccounts.find( + (snapAccount) => snapAccount.address === account.address, + ), + ); + } // keyring type map. const keyringTypes = new Map(); @@ -269,9 +297,7 @@ export default class AccountsController extends BaseControllerV2< const accounts: Record = [ ...legacyAccounts, - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) ...snapAccounts, - ///: END:ONLY_INCLUDE_IN(keyring-snaps) ].reduce((internalAccountMap, internalAccount) => { const keyringTypeName = keyringTypeToName( internalAccount.metadata.keyring.type, @@ -306,20 +332,28 @@ export default class AccountsController extends BaseControllerV2< }); } + loadBackup(backup: AccountsControllerState): void { + if (backup.internalAccounts) { + this.update((currentState: AccountsControllerState) => { + currentState.internalAccounts = backup.internalAccounts; + }); + } + } + async #listSnapAccounts(): Promise { const [snapKeyring] = this.getKeyringByType(SnapKeyring.type); - const snapAccounts = - (await (snapKeyring as SnapKeyring)?.listAccounts(false)) ?? []; + const snapAccounts = await (snapKeyring as SnapKeyring).listAccounts(false); for (const account of snapAccounts) { - const snapId = account.metadata.snap?.id as string; + // The snap account is guaranteed to have a snap metadata + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const snapId = account.metadata.snap!.id!; account.metadata = { snap: { id: snapId, enabled: true, - name: account.name, }, keyring: { type: (snapKeyring as SnapKeyring).type, @@ -336,7 +370,6 @@ export default class AccountsController extends BaseControllerV2< const internalAccounts: Omit[] = []; for (const address of addresses) { const keyring = await this.getKeyringForAccount(address); - // TODO: this is done until the keyrings all implement the InternalAccount interface const v4options = { random: sha256FromString(address).slice(0, 16), }; @@ -370,39 +403,6 @@ export default class AccountsController extends BaseControllerV2< ); } - setSelectedAccount(accountId: string): void { - const account = this.getAccountExpect(accountId); - - this.update((currentState: AccountsControllerState) => { - currentState.internalAccounts.accounts[account.id].metadata.lastSelected = - Date.now(); - currentState.internalAccounts.selectedAccount = account.id; - }); - - this.messagingSystem.publish(`${this.name}:selectedAccountChange`, account); - } - - setAccountName(accountId: string, accountName: string): void { - const account = this.getAccountExpect(accountId); - - if ( - this.listAccounts().find( - (internalAccount) => - internalAccount.name === accountName && - internalAccount.id !== accountId, - ) - ) { - throw new Error('Account name already exists'); - } - - this.update((currentState: AccountsControllerState) => { - currentState.internalAccounts.accounts[accountId] = { - ...account, - name: accountName, - }; - }); - } - #handleSelectedAccountRemoved() { const previousAccount = this.listAccounts() .filter( @@ -436,8 +436,6 @@ export default class AccountsController extends BaseControllerV2< account.address.toLowerCase() === newAddress!.toLowerCase(), ); - // console.log('new account in onKeyringStateChange', newAccount); - // set the first new account as the selected account // eslint-disable-next-line @typescript-eslint/no-non-null-assertion this.setSelectedAccount(newAccount!.id); @@ -477,6 +475,7 @@ export function keyringTypeToName(keyringType: string): string { return 'Custody'; } default: { + console.warn(`Unknown keyring ${keyringType}`); return 'Account'; } } diff --git a/app/scripts/controllers/detect-tokens.test.js b/app/scripts/controllers/detect-tokens.test.js index 2e1c690315ee..3b8c2dd13f3b 100644 --- a/app/scripts/controllers/detect-tokens.test.js +++ b/app/scripts/controllers/detect-tokens.test.js @@ -15,7 +15,7 @@ import { NETWORK_TYPES } from '../../../shared/constants/network'; import { toChecksumHexAddress } from '../../../shared/modules/hexstring-utils'; import DetectTokensController from './detect-tokens'; import PreferencesController from './preferences'; -import AccountsController from './accounts-controller'; +import { AccountsController } from './accounts-controller'; function buildMessenger() { return new ControllerMessenger().getRestricted({ diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 6a7ac13395a3..29f18e7d5895 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -156,7 +156,7 @@ import { getTokenValueParam } from '../../shared/lib/metamask-controller-utils'; import { isManifestV3 } from '../../shared/modules/mv3.utils'; import { hexToDecimal } from '../../shared/modules/conversion.utils'; import { ACTION_QUEUE_METRICS_E2E_TEST } from '../../shared/constants/test-flags'; -import AccountsController from './controllers/accounts-controller'; +import { AccountsController } from './controllers/accounts-controller'; ///: BEGIN:ONLY_INCLUDE_IN(blockaid) import { createPPOMMiddleware } from './lib/ppom/ppom-middleware'; @@ -435,7 +435,7 @@ export default class MetamaskController extends EventEmitter { (newlySelectedInternalAccount) => { listener({ selectedAddress: newlySelectedInternalAccount.address }); }, - ), + ), onNetworkStateChange: networkControllerMessenger.subscribe.bind( networkControllerMessenger, 'NetworkController:stateChange', @@ -845,6 +845,8 @@ export default class MetamaskController extends EventEmitter { ], }); + const keyringApiEnabled = process.env.KEYRING_API_ENABLED ?? false; + this.accountsController = new AccountsController({ messenger: accountsControllerMessenger, state: initState.AccountsController, @@ -862,6 +864,7 @@ export default class MetamaskController extends EventEmitter { keyringControllerMessenger, 'KeyringController:stateChange', ), + keyringApiEnabled, ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) onSnapStateChange: this.controllerMessenger.subscribe.bind( this.controllerMessenger, diff --git a/builds.yml b/builds.yml index 0504aaabc630..7d22a12984f2 100644 --- a/builds.yml +++ b/builds.yml @@ -26,6 +26,7 @@ buildTypes: - ALLOW_LOCAL_SNAPS: false - REQUIRE_SNAPS_ALLOWLIST: true - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.consensys.io/1.0.1/index.html + - KEYRING_API_ENABLED: false # Main build uses the default browser manifest manifestOverrides: false @@ -62,6 +63,7 @@ buildTypes: - SUPPORT_REQUEST_LINK: https://metamask-flask.zendesk.com/hc/en-us/requests/new - INFURA_ENV_KEY_REF: INFURA_FLASK_PROJECT_ID - SEGMENT_WRITE_KEY_REF: SEGMENT_FLASK_WRITE_KEY + - KEYRING_API: true isPrerelease: true manifestOverrides: ./app/build-types/flask/manifest/ diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 7272f1e8ce6d..11af7ccde4b0 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -730,6 +730,25 @@ "@babel/runtime": true } }, + "@metamask/accounts-controller": { + "globals": { + "console.warn": true + }, + "packages": { + "@metamask/accounts-controller>@metamask/base-controller": true, + "@metamask/eth-snap-keyring": true, + "ethereumjs-util": true, + "uuid": true + } + }, + "@metamask/accounts-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, "@metamask/address-book-controller": { "packages": { "@metamask/base-controller": true, @@ -772,12 +791,12 @@ "@ethersproject/contracts": true, "@ethersproject/providers": true, "@metamask/assets-controllers>@metamask/abi-utils": true, + "@metamask/assets-controllers>@metamask/controller-utils": true, "@metamask/assets-controllers>@metamask/rpc-errors": true, "@metamask/assets-controllers>abort-controller": true, "@metamask/assets-controllers>multiformats": true, "@metamask/base-controller": true, "@metamask/contract-metadata": true, - "@metamask/controller-utils": true, "@metamask/metamask-eth-abis": true, "@metamask/utils": true, "browserify>events": true, @@ -806,6 +825,36 @@ "superstruct": true } }, + "@metamask/assets-controllers>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": true + } + }, + "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/assets-controllers>@metamask/rpc-errors": { "packages": { "@metamask/utils": true, diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index 3db8c61aea41..8507a3205d8e 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -730,6 +730,25 @@ "@babel/runtime": true } }, + "@metamask/accounts-controller": { + "globals": { + "console.warn": true + }, + "packages": { + "@metamask/accounts-controller>@metamask/base-controller": true, + "@metamask/eth-snap-keyring": true, + "ethereumjs-util": true, + "uuid": true + } + }, + "@metamask/accounts-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, "@metamask/address-book-controller": { "packages": { "@metamask/base-controller": true, @@ -772,12 +791,12 @@ "@ethersproject/contracts": true, "@ethersproject/providers": true, "@metamask/assets-controllers>@metamask/abi-utils": true, + "@metamask/assets-controllers>@metamask/controller-utils": true, "@metamask/assets-controllers>@metamask/rpc-errors": true, "@metamask/assets-controllers>abort-controller": true, "@metamask/assets-controllers>multiformats": true, "@metamask/base-controller": true, "@metamask/contract-metadata": true, - "@metamask/controller-utils": true, "@metamask/metamask-eth-abis": true, "@metamask/utils": true, "browserify>events": true, @@ -806,6 +825,36 @@ "superstruct": true } }, + "@metamask/assets-controllers>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": true + } + }, + "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/assets-controllers>@metamask/rpc-errors": { "packages": { "@metamask/utils": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index ee17e377857b..b19377ec2887 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -730,6 +730,25 @@ "@babel/runtime": true } }, + "@metamask/accounts-controller": { + "globals": { + "console.warn": true + }, + "packages": { + "@metamask/accounts-controller>@metamask/base-controller": true, + "@metamask/eth-snap-keyring": true, + "ethereumjs-util": true, + "uuid": true + } + }, + "@metamask/accounts-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, "@metamask/address-book-controller": { "packages": { "@metamask/base-controller": true, @@ -772,12 +791,12 @@ "@ethersproject/contracts": true, "@ethersproject/providers": true, "@metamask/assets-controllers>@metamask/abi-utils": true, + "@metamask/assets-controllers>@metamask/controller-utils": true, "@metamask/assets-controllers>@metamask/rpc-errors": true, "@metamask/assets-controllers>abort-controller": true, "@metamask/assets-controllers>multiformats": true, "@metamask/base-controller": true, "@metamask/contract-metadata": true, - "@metamask/controller-utils": true, "@metamask/metamask-eth-abis": true, "@metamask/utils": true, "browserify>events": true, @@ -806,6 +825,36 @@ "superstruct": true } }, + "@metamask/assets-controllers>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": true + } + }, + "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/assets-controllers>@metamask/rpc-errors": { "packages": { "@metamask/utils": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index db96c9850956..943f27ec125d 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -730,6 +730,25 @@ "@babel/runtime": true } }, + "@metamask/accounts-controller": { + "globals": { + "console.warn": true + }, + "packages": { + "@metamask/accounts-controller>@metamask/base-controller": true, + "@metamask/eth-snap-keyring": true, + "ethereumjs-util": true, + "uuid": true + } + }, + "@metamask/accounts-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, "@metamask/address-book-controller": { "packages": { "@metamask/base-controller": true, @@ -772,12 +791,12 @@ "@ethersproject/contracts": true, "@ethersproject/providers": true, "@metamask/assets-controllers>@metamask/abi-utils": true, + "@metamask/assets-controllers>@metamask/controller-utils": true, "@metamask/assets-controllers>@metamask/rpc-errors": true, "@metamask/assets-controllers>abort-controller": true, "@metamask/assets-controllers>multiformats": true, "@metamask/base-controller": true, "@metamask/contract-metadata": true, - "@metamask/controller-utils": true, "@metamask/metamask-eth-abis": true, "@metamask/utils": true, "browserify>events": true, @@ -806,6 +825,36 @@ "superstruct": true } }, + "@metamask/assets-controllers>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": true + } + }, + "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/assets-controllers>@metamask/rpc-errors": { "packages": { "@metamask/utils": true, diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index d7bb04fd769d..1f6601158260 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -871,6 +871,25 @@ "browserify>events": true } }, + "@metamask/accounts-controller": { + "globals": { + "console.warn": true + }, + "packages": { + "@metamask/accounts-controller>@metamask/base-controller": true, + "@metamask/eth-snap-keyring": true, + "ethereumjs-util": true, + "uuid": true + } + }, + "@metamask/accounts-controller>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, "@metamask/address-book-controller": { "packages": { "@metamask/base-controller": true, @@ -913,12 +932,12 @@ "@ethersproject/contracts": true, "@ethersproject/providers": true, "@metamask/assets-controllers>@metamask/abi-utils": true, + "@metamask/assets-controllers>@metamask/controller-utils": true, "@metamask/assets-controllers>@metamask/rpc-errors": true, "@metamask/assets-controllers>abort-controller": true, "@metamask/assets-controllers>multiformats": true, "@metamask/base-controller": true, "@metamask/contract-metadata": true, - "@metamask/controller-utils": true, "@metamask/metamask-eth-abis": true, "@metamask/utils": true, "browserify>events": true, @@ -947,6 +966,36 @@ "superstruct": true } }, + "@metamask/assets-controllers>@metamask/controller-utils": { + "globals": { + "URL": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": true, + "@metamask/controller-utils>@spruceid/siwe-parser": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": true + } + }, + "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/assets-controllers>@metamask/rpc-errors": { "packages": { "@metamask/utils": true, diff --git a/test/e2e/tests/phishing-controller/phishing-detection.spec.js b/test/e2e/tests/phishing-controller/phishing-detection.spec.js new file mode 100644 index 000000000000..2e29a2411ac3 --- /dev/null +++ b/test/e2e/tests/phishing-controller/phishing-detection.spec.js @@ -0,0 +1,315 @@ +const { strict: assert } = require('assert'); + +const { convertToHexValue, withFixtures, openDapp } = require('../../helpers'); +const FixtureBuilder = require('../../fixture-builder'); +const { + METAMASK_HOTLIST_DIFF_URL, + METAMASK_STALELIST_URL, + BlockProvider, +} = require('./helpers'); + +const { + setupPhishingDetectionMocks, + mockConfigLookupOnWarningPage, +} = require('./mocks'); + +describe('Phishing Detection', function () { + const ganacheOptions = { + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: convertToHexValue(25000000000000000000), + }, + ], + }; + + describe('Phishing Detection Mock', function () { + it('should be updated to use v1 of the API', function () { + // Update the fixture in phishing-controller/mocks.js if this test fails + assert.equal( + METAMASK_STALELIST_URL, + 'https://phishing-detection.metafi.codefi.network/v1/stalelist', + ); + assert.equal( + METAMASK_HOTLIST_DIFF_URL, + 'https://phishing-detection.metafi.codefi.network/v1/diffsSince', + ); + }); + }); + + it('should display the MetaMask Phishing Detection page and take the user to the blocked page if they continue', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions, + title: this.test.title, + testSpecificMock: async (mockServer) => { + return setupPhishingDetectionMocks(mockServer, { + blockProvider: BlockProvider.MetaMask, + blocklist: ['127.0.0.1'], + }); + }, + dapp: true, + failOnConsoleError: false, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + await openDapp(driver); + await driver.clickElement({ + text: 'continue to the site.', + }); + const header = await driver.findElement('h1'); + assert.equal(await header.getText(), 'E2E Test Dapp'); + }, + ); + }); + + it('should display the MetaMask Phishing Detection page in an iframe and take the user to the blocked page if they continue', async function () { + const DAPP_WITH_IFRAMED_PAGE_ON_BLOCKLIST = 'http://localhost:8080/'; + const IFRAMED_HOSTNAME = '127.0.0.1'; + + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions, + title: this.test.title, + testSpecificMock: async (mockServer) => { + return setupPhishingDetectionMocks(mockServer, { + blockProvider: BlockProvider.MetaMask, + blocklist: [IFRAMED_HOSTNAME], + }); + }, + dapp: true, + dappPaths: ['mock-page-with-iframe'], + dappOptions: { + numberOfDapps: 2, + }, + failOnConsoleError: false, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + await driver.openNewPage(DAPP_WITH_IFRAMED_PAGE_ON_BLOCKLIST); + + const iframe = await driver.findElement('iframe'); + + await driver.switchToFrame(iframe); + await driver.clickElement({ + text: 'Open this warning in a new tab', + }); + await driver.switchToWindowWithTitle('MetaMask Phishing Detection'); + await driver.clickElement({ + text: 'continue to the site.', + }); + const header = await driver.findElement('h1'); + assert.equal(await header.getText(), 'E2E Test Dapp'); + }, + ); + }); + + it('should display the MetaMask Phishing Detection page in an iframe but should NOT take the user to the blocked page if it is not an accessible resource', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions, + title: this.test.title, + testSpecificMock: async (mockServer) => { + return setupPhishingDetectionMocks(mockServer, { + blockProvider: BlockProvider.MetaMask, + blocklist: ['127.0.0.1'], + }); + }, + dapp: true, + dappPaths: ['mock-page-with-disallowed-iframe'], + dappOptions: { + numberOfDapps: 2, + }, + failOnConsoleError: false, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + await driver.openNewPage( + `http://localhost:8080?extensionUrl=${driver.extensionUrl}`, + ); + + const iframe = await driver.findElement('iframe'); + + await driver.switchToFrame(iframe); + await driver.clickElement({ + text: 'Open this warning in a new tab', + }); + await driver.switchToWindowWithTitle('MetaMask Phishing Detection'); + await driver.clickElement({ + text: 'continue to the site.', + }); + + // Ensure we're not on the wallet home page + await driver.assertElementNotPresent('[data-testid="wallet-balance"]'); + }, + ); + }); + + it('should navigate the user to eth-phishing-detect to dispute a block if the phishing warning page fails to identify the source', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions, + title: this.test.title, + testSpecificMock: (mockServer) => { + setupPhishingDetectionMocks(mockServer, { + blockProvider: BlockProvider.MetaMask, + blocklist: ['127.0.0.1'], + }); + mockConfigLookupOnWarningPage(mockServer, { statusCode: 500 }); + }, + dapp: true, + failOnConsoleError: false, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + await openDapp(driver); + + await driver.clickElement({ text: 'report a detection problem.' }); + + // wait for page to load before checking URL. + await driver.findElement({ + text: `Empty page by ${BlockProvider.MetaMask}`, + }); + assert.equal( + await driver.getCurrentUrl(), + `https://github.com/MetaMask/eth-phishing-detect/issues/new?title=[Legitimate%20Site%20Blocked]%20127.0.0.1&body=http%3A%2F%2F127.0.0.1%3A8080%2F`, + ); + }, + ); + }); + + it('should navigate the user to eth-phishing-detect to dispute a block from MetaMask', async function () { + // Must be site on actual eth-phishing-detect blocklist + const phishingSite = new URL('https://test.metamask-phishing.io'); + + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions, + title: this.test.title, + testSpecificMock: async (mockServer) => { + return setupPhishingDetectionMocks(mockServer, { + blockProvider: BlockProvider.MetaMask, + blocklist: [phishingSite.hostname], + }); + }, + dapp: true, + failOnConsoleError: false, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + await driver.openNewPage(phishingSite.href); + + await driver.clickElement({ text: 'report a detection problem.' }); + + // wait for page to load before checking URL. + await driver.findElement({ + text: `Empty page by ${BlockProvider.MetaMask}`, + }); + assert.equal( + await driver.getCurrentUrl(), + `https://github.com/MetaMask/eth-phishing-detect/issues/new?title=[Legitimate%20Site%20Blocked]%20${encodeURIComponent( + phishingSite.hostname, + )}&body=${encodeURIComponent(phishingSite.href)}`, + ); + }, + ); + }); + + it('should navigate the user to PhishFort to dispute a Phishfort Block', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions, + title: this.test.title, + testSpecificMock: async (mockServer) => { + return setupPhishingDetectionMocks(mockServer, { + blockProvider: BlockProvider.PhishFort, + blocklist: ['127.0.0.1'], + }); + }, + dapp: true, + failOnConsoleError: false, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + await driver.openNewPage('http://127.0.0.1:8080'); + + await driver.clickElement({ text: 'report a detection problem.' }); + + // wait for page to load before checking URL. + await driver.findElement({ + text: `Empty page by ${BlockProvider.PhishFort}`, + }); + assert.equal( + await driver.getCurrentUrl(), + `https://github.com/phishfort/phishfort-lists/issues/new?title=[Legitimate%20Site%20Blocked]%20127.0.0.1&body=http%3A%2F%2F127.0.0.1%3A8080%2F`, + ); + }, + ); + }); + + it('should open a new extension expanded view when clicking back to safety button', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions, + title: this.test.title, + testSpecificMock: async (mockServer) => { + return setupPhishingDetectionMocks(mockServer, { + blockProvider: BlockProvider.MetaMask, + blocklist: ['127.0.0.1'], + }); + }, + dapp: true, + dappPaths: ['mock-page-with-disallowed-iframe'], + dappOptions: { + numberOfDapps: 2, + }, + failOnConsoleError: false, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + await driver.openNewPage( + `http://localhost:8080?extensionUrl=${driver.extensionUrl}`, + ); + + const iframe = await driver.findElement('iframe'); + + await driver.switchToFrame(iframe); + await driver.clickElement({ + text: 'Open this warning in a new tab', + }); + await driver.switchToWindowWithTitle('MetaMask Phishing Detection'); + await driver.clickElement({ + text: 'Back to safety', + }); + + // Ensure we're redirected to wallet home page + const homePage = await driver.findElement('.home__main-view'); + const homePageDisplayed = await homePage.isDisplayed(); + + assert.equal(homePageDisplayed, true); + }, + ); + }); +}); diff --git a/yarn.lock b/yarn.lock index 7b5433dae326..bd8583433b77 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3865,6 +3865,16 @@ __metadata: languageName: node linkType: hard +"@metamask/base-controller@npm:^3.2.1": + version: 3.2.1 + resolution: "@metamask/base-controller@npm:3.2.1" + dependencies: + "@metamask/utils": "npm:^6.2.0" + immer: "npm:^9.0.6" + checksum: ff4db984a72c942694b0ab849ec61f1c36423e6c6b7144a560f52fb6449e91dd4ce3b937a3b7e092468d0c679f305cc0c805085593f9b83acd98fbfe6f971b69 + languageName: node + linkType: hard + "@metamask/browser-passworder@npm:^4.0.2, @metamask/browser-passworder@npm:^4.1.0": version: 4.1.0 resolution: "@metamask/browser-passworder@npm:4.1.0" @@ -3894,7 +3904,7 @@ __metadata: languageName: node linkType: hard -"@metamask/controller-utils@npm:^4.0.0, @metamask/controller-utils@npm:^4.0.1, @metamask/controller-utils@npm:^4.1.0, @metamask/controller-utils@npm:^4.2.0, @metamask/controller-utils@npm:^4.3.0, @metamask/controller-utils@npm:^4.3.1": +"@metamask/controller-utils@npm:^4.0.0, @metamask/controller-utils@npm:^4.1.0, @metamask/controller-utils@npm:^4.2.0, @metamask/controller-utils@npm:^4.3.0, @metamask/controller-utils@npm:^4.3.1": version: 4.3.1 resolution: "@metamask/controller-utils@npm:4.3.1" dependencies: @@ -3910,6 +3920,22 @@ __metadata: languageName: node linkType: hard +"@metamask/controller-utils@npm:^4.0.1, @metamask/controller-utils@npm:^4.3.2": + version: 4.3.2 + resolution: "@metamask/controller-utils@npm:4.3.2" + dependencies: + "@metamask/eth-query": "npm:^3.0.1" + "@metamask/utils": "npm:^6.2.0" + "@spruceid/siwe-parser": "npm:1.1.3" + eth-ens-namehash: "npm:^2.0.8" + eth-rpc-errors: "npm:^4.0.2" + ethereumjs-util: "npm:^7.0.10" + ethjs-unit: "npm:^0.1.6" + fast-deep-equal: "npm:^3.1.3" + checksum: 16c82bdeeb99f96f2fb22132646e6aea66ada1a8427ba17e9c7d31e0bf32be6df7696d75030e30a4ab9be76c08a9d52dc3b25c21804a1328643c1240540ea621 + languageName: node + linkType: hard + "@metamask/design-tokens@npm:^1.12.0, @metamask/design-tokens@npm:^1.6.0": version: 1.12.0 resolution: "@metamask/design-tokens@npm:1.12.0" @@ -4550,7 +4576,17 @@ __metadata: languageName: node linkType: hard -"@metamask/preferences-controller@npm:^4.1.0, @metamask/preferences-controller@npm:^4.2.0": +"@metamask/preferences-controller@npm:^4.1.0": + version: 4.4.0 + resolution: "@metamask/preferences-controller@npm:4.4.0" + dependencies: + "@metamask/base-controller": "npm:^3.2.1" + "@metamask/controller-utils": "npm:^4.3.2" + checksum: b22372f85e672f3843427a76aca8b675273136f01e68739e81cb2eb391e6d960ccc79473af23b63b22237b5093fcaca41224c1ca4a98582606f4b14b0a9ccd54 + languageName: node + linkType: hard + +"@metamask/preferences-controller@npm:^4.2.0": version: 4.2.0 resolution: "@metamask/preferences-controller@npm:4.2.0" dependencies: From 536027afcd0b84524f2e09536012fa44646c55b9 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 31 Aug 2023 16:47:27 +0800 Subject: [PATCH 068/235] chore: update yarn.lock --- yarn.lock | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/yarn.lock b/yarn.lock index 2ded2f409cc1..605716d0d43a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3865,16 +3865,6 @@ __metadata: languageName: node linkType: hard -"@metamask/base-controller@npm:^3.2.1": - version: 3.2.1 - resolution: "@metamask/base-controller@npm:3.2.1" - dependencies: - "@metamask/utils": "npm:^6.2.0" - immer: "npm:^9.0.6" - checksum: ff4db984a72c942694b0ab849ec61f1c36423e6c6b7144a560f52fb6449e91dd4ce3b937a3b7e092468d0c679f305cc0c805085593f9b83acd98fbfe6f971b69 - languageName: node - linkType: hard - "@metamask/browser-passworder@npm:^4.0.2, @metamask/browser-passworder@npm:^4.1.0": version: 4.1.0 resolution: "@metamask/browser-passworder@npm:4.1.0" @@ -3920,22 +3910,6 @@ __metadata: languageName: node linkType: hard -"@metamask/controller-utils@npm:^4.0.1, @metamask/controller-utils@npm:^4.3.2": - version: 4.3.2 - resolution: "@metamask/controller-utils@npm:4.3.2" - dependencies: - "@metamask/eth-query": "npm:^3.0.1" - "@metamask/utils": "npm:^6.2.0" - "@spruceid/siwe-parser": "npm:1.1.3" - eth-ens-namehash: "npm:^2.0.8" - eth-rpc-errors: "npm:^4.0.2" - ethereumjs-util: "npm:^7.0.10" - ethjs-unit: "npm:^0.1.6" - fast-deep-equal: "npm:^3.1.3" - checksum: 16c82bdeeb99f96f2fb22132646e6aea66ada1a8427ba17e9c7d31e0bf32be6df7696d75030e30a4ab9be76c08a9d52dc3b25c21804a1328643c1240540ea621 - languageName: node - linkType: hard - "@metamask/design-tokens@npm:^1.12.0, @metamask/design-tokens@npm:^1.6.0": version: 1.12.0 resolution: "@metamask/design-tokens@npm:1.12.0" From 1c915a80a642628cdf174d1ed7cd2d767ab5c631 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 31 Aug 2023 18:16:48 +0800 Subject: [PATCH 069/235] fix: update build.yml --- builds.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/builds.yml b/builds.yml index b4fa9fe9768a..3c8ee9c5ab44 100644 --- a/builds.yml +++ b/builds.yml @@ -38,6 +38,7 @@ buildTypes: - SEGMENT_BETA_WRITE_KEY - INFURA_ENV_KEY_REF: INFURA_BETA_PROJECT_ID - SEGMENT_WRITE_KEY_REF: SEGMENT_BETA_WRITE_KEY + - KEYRING_API_ENABLED: false # Modifies how the version is displayed. # eg. instead of 10.25.0 -> 10.25.0-beta.2 isPrerelease: true @@ -63,7 +64,7 @@ buildTypes: - SUPPORT_REQUEST_LINK: https://metamask-flask.zendesk.com/hc/en-us/requests/new - INFURA_ENV_KEY_REF: INFURA_FLASK_PROJECT_ID - SEGMENT_WRITE_KEY_REF: SEGMENT_FLASK_WRITE_KEY - - KEYRING_API: true + - KEYRING_API_ENABLED: true isPrerelease: true manifestOverrides: ./app/build-types/flask/manifest/ @@ -83,6 +84,7 @@ buildTypes: - SUPPORT_REQUEST_LINK: https://metamask-flask.zendesk.com/hc/en-us/requests/new - INFURA_ENV_KEY_REF: INFURA_FLASK_PROJECT_ID - SEGMENT_WRITE_KEY_REF: SEGMENT_FLASK_WRITE_KEY + - KEYRING_API_ENABLED: false isPrerelease: true manifestOverrides: ./app/build-types/desktop/manifest/ @@ -97,6 +99,7 @@ buildTypes: - MMI_CONFIGURATION_SERVICE_URL: https://configuration.metamask-institutional.io/v1/configuration/default - SUPPORT_LINK: https://mmi-support.zendesk.com/hc/en-us - SUPPORT_REQUEST_LINK: https://mmi-support.zendesk.com/hc/en-us/requests/new + - KEYRING_API_ENABLED: false # For some reason, MMI uses this type of versioning # Leaving it on for backwards compatibility isPrerelease: true @@ -115,6 +118,7 @@ features: # Whether to verify that a snap can be installed using an allow list - REQUIRE_SNAPS_ALLOWLIST - IFRAME_EXECUTION_ENVIRONMENT_URL + - KEYRING_API_ENABLED assets: - ./{app,shared,ui}/**/snaps/** desktop: From 4df1db44d8bca6ae83b4baa259ba312feb8d6b66 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 31 Aug 2023 18:33:22 +0800 Subject: [PATCH 070/235] chore: update policy.json --- lavamoat/browserify/beta/policy.json | 51 +------------------------ lavamoat/browserify/desktop/policy.json | 51 +------------------------ lavamoat/browserify/flask/policy.json | 51 +------------------------ lavamoat/browserify/main/policy.json | 51 +------------------------ lavamoat/browserify/mmi/policy.json | 51 +------------------------ 5 files changed, 5 insertions(+), 250 deletions(-) diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 11af7ccde4b0..7272f1e8ce6d 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -730,25 +730,6 @@ "@babel/runtime": true } }, - "@metamask/accounts-controller": { - "globals": { - "console.warn": true - }, - "packages": { - "@metamask/accounts-controller>@metamask/base-controller": true, - "@metamask/eth-snap-keyring": true, - "ethereumjs-util": true, - "uuid": true - } - }, - "@metamask/accounts-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, "@metamask/address-book-controller": { "packages": { "@metamask/base-controller": true, @@ -791,12 +772,12 @@ "@ethersproject/contracts": true, "@ethersproject/providers": true, "@metamask/assets-controllers>@metamask/abi-utils": true, - "@metamask/assets-controllers>@metamask/controller-utils": true, "@metamask/assets-controllers>@metamask/rpc-errors": true, "@metamask/assets-controllers>abort-controller": true, "@metamask/assets-controllers>multiformats": true, "@metamask/base-controller": true, "@metamask/contract-metadata": true, + "@metamask/controller-utils": true, "@metamask/metamask-eth-abis": true, "@metamask/utils": true, "browserify>events": true, @@ -825,36 +806,6 @@ "superstruct": true } }, - "@metamask/assets-controllers>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": true, - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true, - "ethjs>ethjs-unit": true - } - }, - "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/key-tree>@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, "@metamask/assets-controllers>@metamask/rpc-errors": { "packages": { "@metamask/utils": true, diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index 8507a3205d8e..3db8c61aea41 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -730,25 +730,6 @@ "@babel/runtime": true } }, - "@metamask/accounts-controller": { - "globals": { - "console.warn": true - }, - "packages": { - "@metamask/accounts-controller>@metamask/base-controller": true, - "@metamask/eth-snap-keyring": true, - "ethereumjs-util": true, - "uuid": true - } - }, - "@metamask/accounts-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, "@metamask/address-book-controller": { "packages": { "@metamask/base-controller": true, @@ -791,12 +772,12 @@ "@ethersproject/contracts": true, "@ethersproject/providers": true, "@metamask/assets-controllers>@metamask/abi-utils": true, - "@metamask/assets-controllers>@metamask/controller-utils": true, "@metamask/assets-controllers>@metamask/rpc-errors": true, "@metamask/assets-controllers>abort-controller": true, "@metamask/assets-controllers>multiformats": true, "@metamask/base-controller": true, "@metamask/contract-metadata": true, + "@metamask/controller-utils": true, "@metamask/metamask-eth-abis": true, "@metamask/utils": true, "browserify>events": true, @@ -825,36 +806,6 @@ "superstruct": true } }, - "@metamask/assets-controllers>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": true, - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true, - "ethjs>ethjs-unit": true - } - }, - "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/key-tree>@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, "@metamask/assets-controllers>@metamask/rpc-errors": { "packages": { "@metamask/utils": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index b19377ec2887..ee17e377857b 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -730,25 +730,6 @@ "@babel/runtime": true } }, - "@metamask/accounts-controller": { - "globals": { - "console.warn": true - }, - "packages": { - "@metamask/accounts-controller>@metamask/base-controller": true, - "@metamask/eth-snap-keyring": true, - "ethereumjs-util": true, - "uuid": true - } - }, - "@metamask/accounts-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, "@metamask/address-book-controller": { "packages": { "@metamask/base-controller": true, @@ -791,12 +772,12 @@ "@ethersproject/contracts": true, "@ethersproject/providers": true, "@metamask/assets-controllers>@metamask/abi-utils": true, - "@metamask/assets-controllers>@metamask/controller-utils": true, "@metamask/assets-controllers>@metamask/rpc-errors": true, "@metamask/assets-controllers>abort-controller": true, "@metamask/assets-controllers>multiformats": true, "@metamask/base-controller": true, "@metamask/contract-metadata": true, + "@metamask/controller-utils": true, "@metamask/metamask-eth-abis": true, "@metamask/utils": true, "browserify>events": true, @@ -825,36 +806,6 @@ "superstruct": true } }, - "@metamask/assets-controllers>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": true, - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true, - "ethjs>ethjs-unit": true - } - }, - "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/key-tree>@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, "@metamask/assets-controllers>@metamask/rpc-errors": { "packages": { "@metamask/utils": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 943f27ec125d..db96c9850956 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -730,25 +730,6 @@ "@babel/runtime": true } }, - "@metamask/accounts-controller": { - "globals": { - "console.warn": true - }, - "packages": { - "@metamask/accounts-controller>@metamask/base-controller": true, - "@metamask/eth-snap-keyring": true, - "ethereumjs-util": true, - "uuid": true - } - }, - "@metamask/accounts-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, "@metamask/address-book-controller": { "packages": { "@metamask/base-controller": true, @@ -791,12 +772,12 @@ "@ethersproject/contracts": true, "@ethersproject/providers": true, "@metamask/assets-controllers>@metamask/abi-utils": true, - "@metamask/assets-controllers>@metamask/controller-utils": true, "@metamask/assets-controllers>@metamask/rpc-errors": true, "@metamask/assets-controllers>abort-controller": true, "@metamask/assets-controllers>multiformats": true, "@metamask/base-controller": true, "@metamask/contract-metadata": true, + "@metamask/controller-utils": true, "@metamask/metamask-eth-abis": true, "@metamask/utils": true, "browserify>events": true, @@ -825,36 +806,6 @@ "superstruct": true } }, - "@metamask/assets-controllers>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": true, - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true, - "ethjs>ethjs-unit": true - } - }, - "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/key-tree>@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, "@metamask/assets-controllers>@metamask/rpc-errors": { "packages": { "@metamask/utils": true, diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 1f6601158260..d7bb04fd769d 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -871,25 +871,6 @@ "browserify>events": true } }, - "@metamask/accounts-controller": { - "globals": { - "console.warn": true - }, - "packages": { - "@metamask/accounts-controller>@metamask/base-controller": true, - "@metamask/eth-snap-keyring": true, - "ethereumjs-util": true, - "uuid": true - } - }, - "@metamask/accounts-controller>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, "@metamask/address-book-controller": { "packages": { "@metamask/base-controller": true, @@ -932,12 +913,12 @@ "@ethersproject/contracts": true, "@ethersproject/providers": true, "@metamask/assets-controllers>@metamask/abi-utils": true, - "@metamask/assets-controllers>@metamask/controller-utils": true, "@metamask/assets-controllers>@metamask/rpc-errors": true, "@metamask/assets-controllers>abort-controller": true, "@metamask/assets-controllers>multiformats": true, "@metamask/base-controller": true, "@metamask/contract-metadata": true, + "@metamask/controller-utils": true, "@metamask/metamask-eth-abis": true, "@metamask/utils": true, "browserify>events": true, @@ -966,36 +947,6 @@ "superstruct": true } }, - "@metamask/assets-controllers>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": true, - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true, - "ethereumjs-util": true, - "ethjs>ethjs-unit": true - } - }, - "@metamask/assets-controllers>@metamask/controller-utils>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/key-tree>@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, - "superstruct": true - } - }, "@metamask/assets-controllers>@metamask/rpc-errors": { "packages": { "@metamask/utils": true, From 3c607bffc8d6ef3544b4b93ab3e8351f3a8903a3 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 31 Aug 2023 18:54:19 +0800 Subject: [PATCH 071/235] fix: account-tracker and select-action-modal test --- app/scripts/lib/account-tracker.test.js | 2 +- .../select-action-modal.test.js | 29 ++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/app/scripts/lib/account-tracker.test.js b/app/scripts/lib/account-tracker.test.js index 8a79bb84cc81..19c9d8525060 100644 --- a/app/scripts/lib/account-tracker.test.js +++ b/app/scripts/lib/account-tracker.test.js @@ -4,7 +4,7 @@ import { ControllerMessenger } from '@metamask/base-controller'; import { SINGLE_CALL_BALANCES_ADDRESS } from '../constants/contracts'; import { createTestProviderTools } from '../../../test/stub/provider'; -import AccountsController from '../controllers/accounts-controller'; +import { AccountsController } from '../controllers/accounts-controller'; import AccountTracker from './account-tracker'; const noop = () => true; diff --git a/ui/components/multichain/select-action-modal/select-action-modal.test.js b/ui/components/multichain/select-action-modal/select-action-modal.test.js index e951a59bbbba..6dfaadb1bab3 100644 --- a/ui/components/multichain/select-action-modal/select-action-modal.test.js +++ b/ui/components/multichain/select-action-modal/select-action-modal.test.js @@ -64,13 +64,40 @@ describe('Select Action Modal', () => { address: '0x1', }, }, + internalAccounts: { + accounts: { + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0x1', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + keyring: { + type: 'HD Key Tree', + }, + }, + name: 'Test Account', + options: {}, + supportedMethods: [ + 'personal_sign', + 'eth_sendTransaction', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v2', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + }, + selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + }, accounts: { '0x1': { address: '0x1', balance: '0x1F4', }, }, - selectedAddress: '0x1', keyrings: [ { type: KeyringType.imported, From 4e812f4ebc23abd41b5be0f6e268cc1b99a51b5c Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 31 Aug 2023 20:37:11 +0800 Subject: [PATCH 072/235] fix: update snapshots --- test/e2e/nft/erc721-interaction.spec.js | 24 ++++++++++++++----- .../errors-after-init-opt-in-ui-state.json | 3 ++- ...s-before-init-opt-in-background-state.json | 2 -- .../errors-before-init-opt-in-ui-state.json | 2 -- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/test/e2e/nft/erc721-interaction.spec.js b/test/e2e/nft/erc721-interaction.spec.js index e979a8530600..bbfd544e76cf 100644 --- a/test/e2e/nft/erc721-interaction.spec.js +++ b/test/e2e/nft/erc721-interaction.spec.js @@ -72,9 +72,12 @@ describe('ERC721 NFTs testdapp interaction', function () { assert.equal(await nftsMintStatus.isDisplayed(), true); // watch 3 of the nfts - await driver.clickElement({ text: 'Watch NFT 1', tag: 'button' }); - await driver.clickElement({ text: 'Watch NFT 2', tag: 'button' }); - await driver.clickElement({ text: 'Watch NFT 3', tag: 'button' }); + await driver.fill('#watchNFTInput', '1'); + await driver.clickElement({ text: 'Watch NFT', tag: 'button' }); + await driver.fill('#watchNFTInput', '2'); + await driver.clickElement({ text: 'Watch NFT', tag: 'button' }); + await driver.fill('#watchNFTInput', '3'); + await driver.clickElement({ text: 'Watch NFT', tag: 'button' }); await driver.waitUntilXWindowHandles(3); windowHandles = await driver.getAllWindowHandles(); @@ -83,6 +86,12 @@ describe('ERC721 NFTs testdapp interaction', function () { windowHandles, ); + // avoid race condition + await driver.waitForSelector({ + css: '.confirm-add-suggested-nft__nft-tokenId', + text: '#3', + }); + // confirm watchNFT await driver.waitForSelector({ css: '.mm-text--heading-lg', @@ -98,9 +107,12 @@ describe('ERC721 NFTs testdapp interaction', function () { assert.equal(nftsListItemsFirstCheck.length, 3); await driver.switchToWindowWithTitle('E2E Test Dapp', windowHandles); - await driver.clickElement({ text: 'Watch NFT 4', tag: 'button' }); - await driver.clickElement({ text: 'Watch NFT 5', tag: 'button' }); - await driver.clickElement({ text: 'Watch NFT 6', tag: 'button' }); + await driver.fill('#watchNFTInput', '4'); + await driver.clickElement({ text: 'Watch NFT', tag: 'button' }); + await driver.fill('#watchNFTInput', '5'); + await driver.clickElement({ text: 'Watch NFT', tag: 'button' }); + await driver.fill('#watchNFTInput', '6'); + await driver.clickElement({ text: 'Watch NFT', tag: 'button' }); await driver.waitUntilXWindowHandles(3); windowHandles = await driver.getAllWindowHandles(); diff --git a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json index b580a39491e1..898133b8aba2 100644 --- a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json +++ b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json @@ -51,12 +51,12 @@ "showBetaHeader": false, "showProductTour": true, "trezorModel": null, + "hadAdvancedGasFeesSetPriorToMigration92_3": false, "nftsDropdownState": {}, "termsOfUseLastAgreed": "number", "qrHardware": {}, "usedNetworks": { "0x1": true, "0x5": true, "0x539": true }, "snapsInstallPrivacyWarningShown": true, - "hadAdvancedGasFeesSetPriorToMigration92_3": false, "serviceWorkerLastActiveTime": 0, "currentAppVersion": "string", "previousAppVersion": "", @@ -93,6 +93,7 @@ "openSeaEnabled": false, "advancedGasFee": {}, "incomingTransactionsPreferences": {}, + "identities": "object", "lostIdentities": "object", "forgottenPassword": false, "ipfsGateway": "string", diff --git a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json b/test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json index 5ea9844527b0..6be1cb1dcd42 100644 --- a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json +++ b/test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json @@ -80,7 +80,6 @@ "dismissSeedBackUpReminder": true, "featureFlags": {}, "forgottenPassword": false, - "identities": "object", "infuraBlocked": false, "ipfsGateway": "string", "knownMethodData": "object", @@ -93,7 +92,6 @@ "showTestNetworks": false, "useNativeCurrencyAsPrimaryCurrency": true }, - "selectedAddress": "string", "theme": "light", "useBlockie": false, "useNftDetection": false, diff --git a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json b/test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json index 87e9b74f808d..44c293c12def 100644 --- a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json +++ b/test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json @@ -80,7 +80,6 @@ "dismissSeedBackUpReminder": true, "featureFlags": {}, "forgottenPassword": false, - "identities": "object", "infuraBlocked": false, "ipfsGateway": "string", "knownMethodData": "object", @@ -93,7 +92,6 @@ "showTestNetworks": false, "useNativeCurrencyAsPrimaryCurrency": true }, - "selectedAddress": "string", "theme": "light", "useBlockie": false, "useNftDetection": false, From 5f0d88990195623679d35a5dabd1245649d07690 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 31 Aug 2023 20:42:14 +0800 Subject: [PATCH 073/235] fix: re-add gas-estimates --- test/e2e/tests/gas-estimates.spec.js | 250 +++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 test/e2e/tests/gas-estimates.spec.js diff --git a/test/e2e/tests/gas-estimates.spec.js b/test/e2e/tests/gas-estimates.spec.js new file mode 100644 index 000000000000..f9f27029a0d6 --- /dev/null +++ b/test/e2e/tests/gas-estimates.spec.js @@ -0,0 +1,250 @@ +const { + convertToHexValue, + withFixtures, + logInWithBalanceValidation, +} = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); +const { CHAIN_IDS } = require('../../../shared/constants/network'); + +describe('Gas estimates generated by MetaMask', function () { + const baseGanacheOptions = { + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: convertToHexValue(25000000000000000000), + }, + ], + }; + const preLondonGanacheOptions = { + ...baseGanacheOptions, + hardfork: 'berlin', + }; + const postLondonGanacheOptions = { + ...baseGanacheOptions, + hardfork: 'london', + }; + + describe('Send on a network that is EIP-1559 compatible', function () { + it('show expected gas defaults', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: postLondonGanacheOptions, + title: this.test.title, + }, + async ({ driver, ganacheServer }) => { + await driver.navigate(); + await logInWithBalanceValidation(driver, ganacheServer); + + await driver.clickElement('[data-testid="eth-overview-send"]'); + + await driver.fill( + 'input[placeholder="Enter public address (0x) or ENS name"]', + '0x2f318C334780961FB129D2a6c30D0763d9a5C970', + ); + + await driver.fill('.unit-input__input', '1'); + + // Check that the gas estimation is what we expect + await driver.findElement({ + cass: '[data-testid="confirm-gas-display"]', + text: '0.00043983', + }); + }, + ); + }); + + it('show expected gas defaults when API is down', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: postLondonGanacheOptions, + testSpecificMock: (mockServer) => { + mockServer + .forGet( + 'https://gas-api.metaswap.codefi.network/networks/1337/suggestedGasFees', + ) + .thenCallback(() => { + return { + json: { + error: 'cannot get gas prices for chain id 1337', + }, + statusCode: 503, + }; + }); + }, + title: this.test.title, + }, + async ({ driver, ganacheServer }) => { + await driver.navigate(); + await logInWithBalanceValidation(driver, ganacheServer); + + await driver.clickElement('[data-testid="eth-overview-send"]'); + + await driver.fill( + 'input[placeholder="Enter public address (0x) or ENS name"]', + '0x2f318C334780961FB129D2a6c30D0763d9a5C970', + ); + + await driver.fill('.unit-input__input', '1'); + + // Check that the gas estimation is what we expect + await driver.findElement({ + cass: '[data-testid="confirm-gas-display"]', + text: '0.00043983', + }); + }, + ); + }); + + it('show expected gas defaults when the network is not supported', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: postLondonGanacheOptions, + testSpecificMock: (mockServer) => { + mockServer + .forGet( + 'https://gas-api.metaswap.codefi.network/networks/1337/suggestedGasFees', + ) + .thenCallback(() => { + return { + statusCode: 422, + }; + }); + }, + title: this.test.title, + }, + async ({ driver, ganacheServer }) => { + await driver.navigate(); + await logInWithBalanceValidation(driver, ganacheServer); + + await driver.clickElement('[data-testid="eth-overview-send"]'); + + await driver.fill( + 'input[placeholder="Enter public address (0x) or ENS name"]', + '0x2f318C334780961FB129D2a6c30D0763d9a5C970', + ); + + await driver.fill('.unit-input__input', '1'); + + // Check that the gas estimation is what we expect + await driver.findElement({ + cass: '[data-testid="confirm-gas-display"]', + text: '0.00043983', + }); + }, + ); + }); + }); + + describe('Send on a network that is not EIP-1559 compatible', function () { + it('show expected gas defaults on a network supported by legacy gas API', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: { + ...preLondonGanacheOptions, + chainId: parseInt(CHAIN_IDS.BSC, 16), + }, + title: this.test.title, + }, + async ({ driver, ganacheServer }) => { + await driver.navigate(); + await logInWithBalanceValidation(driver, ganacheServer); + + await driver.clickElement('[data-testid="eth-overview-send"]'); + + await driver.fill( + 'input[placeholder="Enter public address (0x) or ENS name"]', + '0x2f318C334780961FB129D2a6c30D0763d9a5C970', + ); + + await driver.fill('.unit-input__input', '1'); + + // Check that the gas estimation is what we expect + await driver.findElement({ + cass: '[data-testid="confirm-gas-display"]', + text: '0.000042', + }); + }, + ); + }); + + it('show expected gas defaults on a network supported by legacy gas API when that API is down', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: { + ...preLondonGanacheOptions, + chainId: parseInt(CHAIN_IDS.BSC, 16), + }, + testSpecificMock: (mockServer) => { + mockServer + .forGet( + `https://gas-api.metaswap.codefi.network/networks/${parseInt( + CHAIN_IDS.BSC, + 16, + )}/gasPrices`, + ) + .thenCallback(() => { + return { + statusCode: 422, + }; + }); + }, + title: this.test.title, + }, + async ({ driver, ganacheServer }) => { + await driver.navigate(); + await logInWithBalanceValidation(driver, ganacheServer); + + await driver.clickElement('[data-testid="eth-overview-send"]'); + + await driver.fill( + 'input[placeholder="Enter public address (0x) or ENS name"]', + '0x2f318C334780961FB129D2a6c30D0763d9a5C970', + ); + + await driver.fill('.unit-input__input', '1'); + + // Check that the gas estimation is what we expect + await driver.findElement({ + cass: '[data-testid="confirm-gas-display"]', + text: '0.000042', + }); + }, + ); + }); + + it('show expected gas defaults on a network not supported by legacy gas API', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions: preLondonGanacheOptions, + title: this.test.title, + }, + async ({ driver, ganacheServer }) => { + await driver.navigate(); + await logInWithBalanceValidation(driver, ganacheServer); + + await driver.clickElement('[data-testid="eth-overview-send"]'); + + await driver.fill( + 'input[placeholder="Enter public address (0x) or ENS name"]', + '0x2f318C334780961FB129D2a6c30D0763d9a5C970', + ); + + await driver.fill('.unit-input__input', '1'); + + // Check that the gas estimation is what we expect + await driver.findElement({ + cass: '[data-testid="confirm-gas-display"]', + text: '0.000042', + }); + }, + ); + }); + }); +}); From 8cb1730448d987bb7f71219e0ad8e2ce9e257798 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 31 Aug 2023 21:26:24 +0800 Subject: [PATCH 074/235] fix: race condition to add nft 6 --- test/e2e/nft/erc721-interaction.spec.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/e2e/nft/erc721-interaction.spec.js b/test/e2e/nft/erc721-interaction.spec.js index bbfd544e76cf..21acf395d5b9 100644 --- a/test/e2e/nft/erc721-interaction.spec.js +++ b/test/e2e/nft/erc721-interaction.spec.js @@ -15,7 +15,7 @@ describe('ERC721 NFTs testdapp interaction', function () { ], }; - it('should prompt users to add their NFTs to their wallet (one by one)', async function () { + it.only('should prompt users to add their NFTs to their wallet (one by one)', async function () { await withFixtures( { dapp: true, @@ -121,6 +121,12 @@ describe('ERC721 NFTs testdapp interaction', function () { windowHandles, ); + // avoid race condition + await driver.waitForSelector({ + css: '.confirm-add-suggested-nft__nft-tokenId', + text: '#6', + }); + // confirm watchNFT await driver.waitForSelector({ css: '.mm-text--heading-lg', From 685b55a74932cd4cffd48fa9d895f6f8eb126c95 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 31 Aug 2023 22:18:30 +0800 Subject: [PATCH 075/235] fix: remove exclusive test --- test/e2e/nft/erc721-interaction.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/nft/erc721-interaction.spec.js b/test/e2e/nft/erc721-interaction.spec.js index 21acf395d5b9..47696f8b74ac 100644 --- a/test/e2e/nft/erc721-interaction.spec.js +++ b/test/e2e/nft/erc721-interaction.spec.js @@ -15,7 +15,7 @@ describe('ERC721 NFTs testdapp interaction', function () { ], }; - it.only('should prompt users to add their NFTs to their wallet (one by one)', async function () { + it('should prompt users to add their NFTs to their wallet (one by one)', async function () { await withFixtures( { dapp: true, From 7779f08ff354c01b9feba8320c0e1a5bf4c93162 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Fri, 1 Sep 2023 00:27:05 +0800 Subject: [PATCH 076/235] feat: update sentry to add AccountsController in SENTRY_BACKGROUND_STATE --- app/scripts/lib/setupSentry.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js index 6e2f21c2a331..5f75122d3934 100644 --- a/app/scripts/lib/setupSentry.js +++ b/app/scripts/lib/setupSentry.js @@ -32,6 +32,12 @@ export const SENTRY_BACKGROUND_STATE = { accounts: false, currentBlockGasLimit: true, }, + AccountsController: { + internalAccounts: { + accounts: true, + selectedAccount: true, + }, + }, AddressBookController: { addressBook: false, }, @@ -184,7 +190,6 @@ export const SENTRY_BACKGROUND_STATE = { showTestNetworks: true, useNativeCurrencyAsPrimaryCurrency: true, }, - selectedAddress: false, snapRegistryList: false, theme: true, transactionSecurityCheckEnabled: true, From e593e44d1b47fabb6498710c2a76ca0d4c7a8e16 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Fri, 1 Sep 2023 16:49:42 +0800 Subject: [PATCH 077/235] fix: migrate name to metadata in internalAccount --- .storybook/test-data.js | 26 ++-- .../controllers/accounts-controller.ts | 46 +++++-- app/scripts/controllers/detect-tokens.test.js | 10 +- .../permissions/specifications.test.js | 58 +++------ .../IncomingTransactionHelper.test.ts | 8 +- .../controllers/transactions/index.test.js | 24 ++-- app/scripts/lib/backup.test.js | 6 +- app/scripts/metamask-controller.js | 4 +- app/scripts/metamask-controller.test.js | 28 ++-- lavamoat/browserify/beta/policy.json | 22 +--- lavamoat/browserify/desktop/policy.json | 22 +--- lavamoat/browserify/flask/policy.json | 22 +--- lavamoat/browserify/main/policy.json | 22 +--- lavamoat/browserify/mmi/policy.json | 22 +--- test/data/mock-state.json | 24 ++-- test/e2e/fixture-builder.js | 32 ++--- ...rs-after-init-opt-in-background-state.json | 6 +- .../errors-after-init-opt-in-ui-state.json | 2 +- ...s-before-init-opt-in-background-state.json | 28 +++- .../errors-before-init-opt-in-ui-state.json | 28 +++- test/jest/mock-store.js | 24 ++-- .../account-list-item-component.test.js | 38 +++++- .../account-list-item/account-list-item.js | 23 +++- .../account-list-item.stories.js | 18 ++- .../unconnected-account-alert.test.js | 12 +- ...m-page-container-content.component.test.js | 24 ++-- .../recipient-group.component.js | 68 +++++----- .../edit-gas-fee-popover.test.js | 6 +- .../edit-gas-item/edit-gas-item.test.js | 6 +- .../edit-gas-tooltip/edit-gas-tooltip.test.js | 6 +- .../gas-details-item-title.test.js | 6 +- .../confirm-remove-account.component.js | 4 +- .../confirm-remove-account.test.js | 12 +- ui/components/app/nft-details/nft-details.js | 4 +- ui/components/app/nfts-tab/nfts-tab.test.js | 6 +- .../selected-account.component.js | 4 +- .../signature-request-header.js | 4 +- .../signature-request-original.test.js | 6 +- .../signature-request-data.test.js | 12 +- ...signature-request-header.component.test.js | 6 +- .../signature-request/signature-request.js | 4 +- .../signature-request.test.js | 68 ++++++++-- .../transaction-status-label.test.js | 24 ++-- .../app/wallet-overview/eth-overview.test.js | 12 +- .../wallet-overview/token-overview.test.js | 6 +- ...ive-replacement-token-notification.test.js | 6 +- .../wrong-network-notification.test.js | 6 +- .../account-details/account-details.js | 5 +- .../account-list-item-menu.js | 6 +- .../account-list-item/account-list-item.js | 13 +- .../account-list-item.test.js | 13 +- .../account-list-menu/account-list-menu.js | 2 +- .../account-list-menu.test.js | 6 +- .../multichain/app-header/app-header.js | 2 +- .../connected-site-menu.js | 2 +- .../connected-site-menu.test.js | 12 +- .../create-account/create-account.test.js | 6 +- .../select-action-modal.test.js | 6 +- ui/ducks/app/app.test.js | 6 +- ui/ducks/metamask/metamask.js | 5 +- ui/ducks/metamask/metamask.test.js | 66 ++++------ ui/ducks/send/send.test.js | 58 +++------ ui/helpers/utils/accounts.js | 2 +- ui/helpers/utils/accounts.test.js | 5 +- ui/hooks/useAddressDetails.js | 2 +- ui/hooks/useAddressDetails.test.js | 12 +- ui/hooks/useAssetDetails.test.js | 6 +- ui/pages/asset/components/token-asset.js | 2 +- .../confirm-add-suggested-token.test.js | 6 +- .../confirm-decrypt-message.component.test.js | 19 ++- ...rm-encryption-public-key.component.test.js | 18 +++ .../confirm-signature-request/index.test.js | 6 +- .../confirm-transaction-base.container.js | 7 +- .../confirm-transaction-base.test.js | 6 +- .../connected-accounts.stories.js | 12 +- .../connected-sites.container.js | 2 +- ...interactive-replacement-token-page.test.js | 7 +- .../add-recipient/add-recipient.component.js | 3 +- ui/pages/send/send.test.js | 6 +- ui/pages/token-allowance/token-allowance.js | 2 +- .../token-allowance/token-allowance.test.js | 12 +- .../token-details/token-details-page.test.js | 24 ++-- ui/selectors/institutional/selectors.test.js | 24 ++-- ...nonce-sorted-transactions-selector.test.js | 6 +- ui/selectors/permissions.test.js | 123 +++++------------- ui/selectors/selectors.js | 4 +- ui/selectors/selectors.test.js | 14 +- ui/selectors/transactions.test.js | 24 ++-- ui/store/actionConstants.test.js | 11 +- ui/store/actions.test.js | 24 ++-- 90 files changed, 658 insertions(+), 794 deletions(-) diff --git a/.storybook/test-data.js b/.storybook/test-data.js index 993d6ebd4a97..4657d916d91c 100644 --- a/.storybook/test-data.js +++ b/.storybook/test-data.js @@ -27,7 +27,7 @@ const state = { image: { src: 'images/global-menu-block-explorer.svg', }, - } + }, }, tokenList: { '0x514910771af9ca656af840dff83e8264ecf986ca': { @@ -306,20 +306,18 @@ const state = { address: '0x64a845a5b02460acf8a3d84503b0d68d028b4bb4', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'This is a Really Long Account Name', keyring: { type: 'HD Key Tree', }, }, - name: 'This is a Really Long Account Name', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -329,20 +327,18 @@ const state = { address: '0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e', id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', metadata: { + name: 'Account 2', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 2', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -352,20 +348,18 @@ const state = { address: '0x9d0ba4ddac06032527b140912ec808ab9451b788', id: '15e69915-2a1a-4019-93b3-916e11fd432f', metadata: { + name: 'Account 3', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 3', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -375,20 +369,18 @@ const state = { address: '0xeb9e64b93097bc15f01f13eae97015c57ab64823', id: '784225f4-d30b-4e77-a900-c8bbce735b88', metadata: { + name: 'Account 4', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 4', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index a2f444f92bf6..b0721b14f2b0 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -1,7 +1,7 @@ import type { RestrictedControllerMessenger } from '@metamask/base-controller'; import { BaseControllerV2 } from '@metamask/base-controller'; -import type { InternalAccount } from '@metamask/eth-snap-keyring'; import { SnapKeyring } from '@metamask/eth-snap-keyring'; +import type { InternalAccount } from '@metamask/keyring-api'; import type { KeyringControllerState, KeyringController, @@ -135,7 +135,7 @@ export class AccountsController extends BaseControllerV2< accounts.forEach((account) => { const currentAccount = currentState.internalAccounts.accounts[account.id]; - if (currentAccount?.metadata.snap) { + if (currentAccount && currentAccount.metadata.snap) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this account is guaranteed to have snap metadata currentState.internalAccounts.accounts[ @@ -218,12 +218,12 @@ export class AccountsController extends BaseControllerV2< if (!accountId) { return { id: '', - name: '', address: '', options: {}, - supportedMethods: [], + methods: [], type: 'eip155:eoa', metadata: { + name: '', keyring: { type: '', }, @@ -248,6 +248,8 @@ export class AccountsController extends BaseControllerV2< // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore Type instantiation is excessively deep and possibly infinite. this.update((currentState: AccountsControllerState) => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore lastSelected will be added in 0.2.2 currentState.internalAccounts.accounts[account.id].metadata.lastSelected = Date.now(); currentState.internalAccounts.selectedAccount = account.id; @@ -262,7 +264,7 @@ export class AccountsController extends BaseControllerV2< if ( this.listAccounts().find( (internalAccount) => - internalAccount.name === accountName && + internalAccount.metadata.name === accountName && internalAccount.id !== accountId, ) ) { @@ -272,7 +274,10 @@ export class AccountsController extends BaseControllerV2< this.update((currentState: AccountsControllerState) => { currentState.internalAccounts.accounts[accountId] = { ...account, - name: accountName, + metadata: { + ...account.metadata, + name: accountName, + }, }; }); } @@ -313,11 +318,15 @@ export class AccountsController extends BaseControllerV2< internalAccountMap[internalAccount.id] = { ...internalAccount, - name: existingAccount - ? existingAccount.name - : `${keyringTypeName} ${keyringAccountIndex + 1}`, + metadata: { ...internalAccount.metadata, + name: + existingAccount && existingAccount.metadata.name !== '' + ? existingAccount.metadata.name + : `${keyringTypeName} ${keyringAccountIndex + 1}`, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore lastSelected will be added in 0.2.2 lastSelected: existingAccount?.metadata?.lastSelected, }, }; @@ -354,20 +363,26 @@ export class AccountsController extends BaseControllerV2< snap: { id: snapId, enabled: true, + name: '', }, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore snap keyring not updated yet + name: '', keyring: { type: (snapKeyring as SnapKeyring).type, }, }; } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore lastSelected will be added in 0.2.2 return snapAccounts; } // Note: listLegacyAccounts is a temporary method until the keyrings all implement the InternalAccount interface - async #listLegacyAccounts(): Promise[]> { + async #listLegacyAccounts(): Promise { const addresses = await this.getAccounts(); - const internalAccounts: Omit[] = []; + const internalAccounts: InternalAccount[] = []; for (const address of addresses) { const keyring = await this.getKeyringForAccount(address); const v4options = { @@ -378,19 +393,18 @@ export class AccountsController extends BaseControllerV2< id: uuid(v4options), address, options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], type: 'eip155:eoa', metadata: { + name: '', keyring: { type: (keyring as any).type as string, }, @@ -411,7 +425,11 @@ export class AccountsController extends BaseControllerV2< .sort((accountA, accountB) => { // sort by lastSelected descending return ( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore (accountB.metadata?.lastSelected ?? 0) - + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore (accountA.metadata?.lastSelected ?? 0) ); })[0]; diff --git a/app/scripts/controllers/detect-tokens.test.js b/app/scripts/controllers/detect-tokens.test.js index 3b8c2dd13f3b..aa0faba53ca6 100644 --- a/app/scripts/controllers/detect-tokens.test.js +++ b/app/scripts/controllers/detect-tokens.test.js @@ -252,13 +252,13 @@ describe('DetectTokensController', function () { address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Account 1', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', 'eth_sendTransaction', 'eth_sign', @@ -275,20 +275,18 @@ describe('DetectTokensController', function () { address: '0xbc86727e770de68b1060c91f6bb6945c73e10388', id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', metadata: { + name: 'Account 2', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 2', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/app/scripts/controllers/permissions/specifications.test.js b/app/scripts/controllers/permissions/specifications.test.js index 6957ae6da438..a0f275d564a2 100644 --- a/app/scripts/controllers/permissions/specifications.test.js +++ b/app/scripts/controllers/permissions/specifications.test.js @@ -126,21 +126,19 @@ describe('PermissionController specifications', () => { address: '0x1', id: '21066553-d8c8-4cdc-af33-efc921cd3ca9', metadata: { + name: 'Test Account 1', lastSelected: 1, keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -150,21 +148,19 @@ describe('PermissionController specifications', () => { address: '0x3', id: 'ff8fda69-d416-4d25-80a2-efb77bc7d4ad', metadata: { + name: 'Test Account 3', lastSelected: 3, keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account 3', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -273,21 +269,19 @@ describe('PermissionController specifications', () => { address: '0x1', id: '21066553-d8c8-4cdc-af33-efc921cd3ca9', metadata: { + name: 'Test Account', lastSelected: 1, keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -297,20 +291,18 @@ describe('PermissionController specifications', () => { address: '0x2', id: '0bd7348e-bdfe-4f67-875c-de831a583857', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -320,21 +312,19 @@ describe('PermissionController specifications', () => { address: '0x3', id: 'ff8fda69-d416-4d25-80a2-efb77bc7d4ad', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, lastSelected: 3, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -344,14 +334,14 @@ describe('PermissionController specifications', () => { address: '0x4', id: '0bd7348e-bdfe-4f67-875c-de831a583857', metadata: { + name: 'Test Account', lastSelected: 3, keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', 'eth_sendTransaction', 'eth_sign', @@ -390,21 +380,19 @@ describe('PermissionController specifications', () => { address: '0x2', id: '0bd7348e-bdfe-4f67-875c-de831a583857', metadata: { + name: 'Test Account', lastSelected: 2, keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -414,21 +402,19 @@ describe('PermissionController specifications', () => { address: '0x3', id: 'ff8fda69-d416-4d25-80a2-efb77bc7d4ad', metadata: { + name: 'Test Account', lastSelected: 3, keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -458,21 +444,19 @@ describe('PermissionController specifications', () => { address: '0x1', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', lastSelected: 1, keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -482,21 +466,19 @@ describe('PermissionController specifications', () => { address: '0x3', id: 'ff8fda69-d416-4d25-80a2-efb77bc7d4ad', metadata: { + name: 'Test Account', lastSelected: 3, keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/app/scripts/controllers/transactions/IncomingTransactionHelper.test.ts b/app/scripts/controllers/transactions/IncomingTransactionHelper.test.ts index 104ec7b5519a..674dd4a4ce23 100644 --- a/app/scripts/controllers/transactions/IncomingTransactionHelper.test.ts +++ b/app/scripts/controllers/transactions/IncomingTransactionHelper.test.ts @@ -1,7 +1,7 @@ import { NetworkType } from '@metamask/controller-utils'; import type { BlockTracker, NetworkState } from '@metamask/network-controller'; -import { InternalAccount } from '@metamask/eth-snap-keyring'; +import { InternalAccount } from '@metamask/keyring-api'; import { TransactionMeta, TransactionStatus, @@ -27,20 +27,18 @@ const INTERNAL_ACCOUNT_MOCK: InternalAccount = { address: '0x1', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/app/scripts/controllers/transactions/index.test.js b/app/scripts/controllers/transactions/index.test.js index 1cb785eb34a7..f67abf8a28ef 100644 --- a/app/scripts/controllers/transactions/index.test.js +++ b/app/scripts/controllers/transactions/index.test.js @@ -66,20 +66,18 @@ const MOCK_INTERNAL_ACCOUNT = { id: '2d47e693-26c2-47cb-b374-6151199bbe3f', address: '0x88bb7F89eB5e5b30D3e15a57C68DBe03C6aCCB21', metadata: { + name: 'Account 1', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -395,20 +393,18 @@ describe('Transaction Controller', function () { address: selectedAddress, id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -1196,20 +1192,18 @@ describe('Transaction Controller', function () { address: selectedAddress, id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -1685,20 +1679,18 @@ describe('Transaction Controller', function () { address: selectedAddress, id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/app/scripts/lib/backup.test.js b/app/scripts/lib/backup.test.js index ea6028d23c8b..469811cdc37c 100644 --- a/app/scripts/lib/backup.test.js +++ b/app/scripts/lib/backup.test.js @@ -169,21 +169,19 @@ const jsonData = JSON.stringify({ address: '0x129af01f4b770b30615f049790e1e206ebaa7b10', id: 'fcbcdca4-cc47-4bc8-b455-b14421e9277e', metadata: { + name: 'Account 1', keyring: { type: 'HD Key Tree', }, lastSelected: 1693289751176, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index f6570d899f2b..ea4d1b396d05 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -614,7 +614,7 @@ export default class MetamaskController extends EventEmitter { this.appStateController = new AppStateController({ addUnlockListener: this.on.bind(this, 'unlock'), - isUnlocked: this.isUnlocked.bind(this), + isUnlocked: this.isUnlocked.bind(this) initState: initState.AppStateController, onInactiveTimeout: () => this.setLocked(), preferencesStore: this.preferencesController.store, @@ -3272,7 +3272,7 @@ export default class MetamaskController extends EventEmitter { setAccountName(accountId, accountName) { const accounts = this.accountsController.listAccounts(); - if (accounts.some((account) => account.name === accountName)) { + if (accounts.some((account) => account.metadata.name === accountName)) { throw new Error( `An account with the name ${accountName} already exists.`, ); diff --git a/app/scripts/metamask-controller.test.js b/app/scripts/metamask-controller.test.js index b6c2f59c7aef..fb86561324fb 100644 --- a/app/scripts/metamask-controller.test.js +++ b/app/scripts/metamask-controller.test.js @@ -125,13 +125,13 @@ const TEST_INTERNAL_ACCOUNT = { id: '2d47e693-26c2-47cb-b374-6151199bbe3f', address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', metadata: { + name: 'Account 1', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', 'eth_sendTransaction', 'eth_sign', @@ -540,22 +540,20 @@ describe('MetaMaskController', function () { id: 'e26b5b50-739e-4d6a-a9d1-a9163f480a52', address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], type: 'eip155:eoa', metadata: { + name: DEFAULT_LABEL, keyring: { type: 'HD Key Tree' }, }, - name: DEFAULT_LABEL, }); metamaskController.setAccountName(testAccount.id, 'Account Foo'); @@ -575,22 +573,20 @@ describe('MetaMaskController', function () { id: 'e26b5b50-739e-4d6a-a9d1-a9163f480a52', address: TEST_ADDRESS, options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], type: 'eip155:eoa', metadata: { + name: 'Account Foo', keyring: { type: 'HD Key Tree' }, }, - name: 'Account Foo', }); startTime = Date.now(); @@ -621,22 +617,20 @@ describe('MetaMaskController', function () { id: 'f73954ab-4605-459c-b0ff-23978b190709', address: TEST_ADDRESS_ALT, options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], type: 'eip155:eoa', metadata: { + name: DEFAULT_LABEL, keyring: { type: 'HD Key Tree' }, }, - name: DEFAULT_LABEL, }); }); @@ -678,22 +672,20 @@ describe('MetaMaskController', function () { id: 'e26b5b50-739e-4d6a-a9d1-a9163f480a52', address: TEST_ADDRESS, options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], type: 'eip155:eoa', metadata: { + name: DEFAULT_LABEL, keyring: { type: 'HD Key Tree' }, }, - name: DEFAULT_LABEL, }); }); }); diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 7272f1e8ce6d..4776e7155a61 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -1164,29 +1164,11 @@ }, "@metamask/eth-snap-keyring>@metamask/keyring-api": { "packages": { - "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": true, - "@metamask/eth-snap-keyring>@metamask/keyring-api>uuid": true, - "superstruct": true - } - }, - "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/key-tree>@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, + "@metamask/eth-snap-keyring>@metamask/utils": true, + "@metamask/eth-snap-keyring>uuid": true, "superstruct": true } }, - "@metamask/eth-snap-keyring>@metamask/keyring-api>uuid": { - "globals": { - "crypto": true - } - }, "@metamask/eth-snap-keyring>@metamask/utils": { "globals": { "TextDecoder": true, diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index 3db8c61aea41..d2eece79d56a 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -1235,29 +1235,11 @@ }, "@metamask/eth-snap-keyring>@metamask/keyring-api": { "packages": { - "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": true, - "@metamask/eth-snap-keyring>@metamask/keyring-api>uuid": true, - "superstruct": true - } - }, - "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/key-tree>@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, + "@metamask/eth-snap-keyring>@metamask/utils": true, + "@metamask/eth-snap-keyring>uuid": true, "superstruct": true } }, - "@metamask/eth-snap-keyring>@metamask/keyring-api>uuid": { - "globals": { - "crypto": true - } - }, "@metamask/eth-snap-keyring>@metamask/utils": { "globals": { "TextDecoder": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index ee17e377857b..76ff6d767a50 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -1235,29 +1235,11 @@ }, "@metamask/eth-snap-keyring>@metamask/keyring-api": { "packages": { - "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": true, - "@metamask/eth-snap-keyring>@metamask/keyring-api>uuid": true, - "superstruct": true - } - }, - "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/key-tree>@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, + "@metamask/eth-snap-keyring>@metamask/utils": true, + "@metamask/eth-snap-keyring>uuid": true, "superstruct": true } }, - "@metamask/eth-snap-keyring>@metamask/keyring-api>uuid": { - "globals": { - "crypto": true - } - }, "@metamask/eth-snap-keyring>@metamask/utils": { "globals": { "TextDecoder": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index db96c9850956..33ed4bdffa80 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -1164,29 +1164,11 @@ }, "@metamask/eth-snap-keyring>@metamask/keyring-api": { "packages": { - "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": true, - "@metamask/eth-snap-keyring>@metamask/keyring-api>uuid": true, - "superstruct": true - } - }, - "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/key-tree>@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, + "@metamask/eth-snap-keyring>@metamask/utils": true, + "@metamask/eth-snap-keyring>uuid": true, "superstruct": true } }, - "@metamask/eth-snap-keyring>@metamask/keyring-api>uuid": { - "globals": { - "crypto": true - } - }, "@metamask/eth-snap-keyring>@metamask/utils": { "globals": { "TextDecoder": true, diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index d7bb04fd769d..9f016fd6e4a4 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -1305,29 +1305,11 @@ }, "@metamask/eth-snap-keyring>@metamask/keyring-api": { "packages": { - "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": true, - "@metamask/eth-snap-keyring>@metamask/keyring-api>uuid": true, - "superstruct": true - } - }, - "@metamask/eth-snap-keyring>@metamask/keyring-api>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/key-tree>@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true, + "@metamask/eth-snap-keyring>@metamask/utils": true, + "@metamask/eth-snap-keyring>uuid": true, "superstruct": true } }, - "@metamask/eth-snap-keyring>@metamask/keyring-api>uuid": { - "globals": { - "crypto": true - } - }, "@metamask/eth-snap-keyring>@metamask/utils": { "globals": { "TextDecoder": true, diff --git a/test/data/mock-state.json b/test/data/mock-state.json index a2489b926aa5..047b63133d4f 100644 --- a/test/data/mock-state.json +++ b/test/data/mock-state.json @@ -138,20 +138,18 @@ "address": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", "id": "cf8dace4-9439-4bd4-b3a8-88c821c8fcb3", "metadata": { + "name": "Test Account", "keyring": { "type": "HD Key Tree" } }, - "name": "Test Account", "options": {}, - "supportedMethods": [ + "methods": [ "personal_sign", - "eth_sendTransaction", "eth_sign", "eth_signTransaction", "eth_signTypedData", "eth_signTypedData_v1", - "eth_signTypedData_v2", "eth_signTypedData_v3", "eth_signTypedData_v4" ], @@ -161,20 +159,18 @@ "address": "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b", "id": "07c2cfec-36c9-46c4-8115-3836d3ac9047", "metadata": { + "name": "Test Account 2", "keyring": { "type": "HD Key Tree" } }, - "name": "Test Account 2", "options": {}, - "supportedMethods": [ + "methods": [ "personal_sign", - "eth_sendTransaction", "eth_sign", "eth_signTransaction", "eth_signTypedData", "eth_signTypedData_v1", - "eth_signTypedData_v2", "eth_signTypedData_v3", "eth_signTypedData_v4" ], @@ -184,20 +180,18 @@ "address": "0xc42edfcc21ed14dda456aa0756c153f7985d8813", "id": "15e69915-2a1a-4019-93b3-916e11fd432f", "metadata": { + "name": "Ledger Hardware 2", "keyring": { "type": "Ledger Hardware" } }, - "name": "Ledger Hardware 2", "options": {}, - "supportedMethods": [ + "methods": [ "personal_sign", - "eth_sendTransaction", "eth_sign", "eth_signTransaction", "eth_signTypedData", "eth_signTypedData_v1", - "eth_signTypedData_v2", "eth_signTypedData_v3", "eth_signTypedData_v4" ], @@ -207,20 +201,18 @@ "address": "0xeb9e64b93097bc15f01f13eae97015c57ab64823", "id": "784225f4-d30b-4e77-a900-c8bbce735b88", "metadata": { + "name": "Test Account 3", "keyring": { "type": "HD Key Tree" } }, - "name": "Test Account 3", "options": {}, - "supportedMethods": [ + "methods": [ "personal_sign", - "eth_sendTransaction", "eth_sign", "eth_signTransaction", "eth_signTypedData", "eth_signTypedData_v1", - "eth_signTypedData_v2", "eth_signTypedData_v3", "eth_signTypedData_v4" ], diff --git a/test/e2e/fixture-builder.js b/test/e2e/fixture-builder.js index 568dca8f720f..15e338efc00c 100644 --- a/test/e2e/fixture-builder.js +++ b/test/e2e/fixture-builder.js @@ -22,22 +22,20 @@ function defaultFixture() { 'd5e45e4a-3b04-4a09-a5e1-39762e5c6be4': { id: 'd5e45e4a-3b04-4a09-a5e1-39762e5c6be4', address: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', - name: 'Account 1', metadata: { + name: 'Account 1', lastSelected: 1665507600000, keyring: { type: 'HD Key Tree', }, }, options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -283,13 +281,6 @@ function defaultFixture() { dismissSeedBackUpReminder: true, featureFlags: {}, forgottenPassword: false, - identities: { - '0x5cfe73b6021e818b776b421b1c4db2474086a7e1': { - address: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', - lastSelected: 1665507600000, - name: 'Account 1', - }, - }, infuraBlocked: false, ipfsGateway: 'dweb.link', knownMethodData: {}, @@ -302,7 +293,6 @@ function defaultFixture() { showTestNetworks: false, useNativeCurrencyAsPrimaryCurrency: true, }, - selectedAddress: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', theme: 'light', useBlockie: false, useNftDetection: false, @@ -693,23 +683,21 @@ class FixtureBuilder { selectedAccount: '2fdb2de6-80c7-4d2f-9f95-cb6895389843', accounts: { '2fdb2de6-80c7-4d2f-9f95-cb6895389843': { - name: 'Account 1', id: '2fdb2de6-80c7-4d2f-9f95-cb6895389843', address: '0x0cc5261ab8ce458dc977078a3623e2badd27afd3', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], type: 'eip155:eoa', metadata: { + name: 'Account 1', lastSelected: 1665507600000, keyring: { type: 'HD Key Tree', @@ -717,46 +705,42 @@ class FixtureBuilder { }, }, '58093703-57e9-4ea9-8545-49e8a75cb084': { - name: 'Account 2', id: '58093703-57e9-4ea9-8545-49e8a75cb084', address: '0x3ed0ee22e0685ebbf07b2360a8331693c413cc59', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], type: 'eip155:eoa', metadata: { + name: 'Account 2', keyring: { type: 'HD Key Tree', }, }, }, 'dd658aab-abf2-4f53-b735-c8a57151d447': { - name: 'Account 3', id: 'dd658aab-abf2-4f53-b735-c8a57151d447', address: '0xd38d853771fb546bd8b18b2f3638491bc0b0e906', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], type: 'eip155:eoa', metadata: { + name: 'Account 3', keyring: { type: 'HD Key Tree', }, diff --git a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json index 2f5cf33472ad..eecd7dc6a148 100644 --- a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json +++ b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json @@ -1,6 +1,8 @@ { "AccountTracker": { "accounts": "object" }, - "AccountsController": "object", + "AccountsController": { + "internalAccounts": { "accounts": {}, "selectedAccount": "" } + }, "AddressBookController": { "addressBook": "object" }, "AlertController": { "alertEnabledness": { "unconnectedAccount": true, "web3ShimUsage": true }, @@ -29,12 +31,12 @@ "showBetaHeader": false, "showProductTour": true, "trezorModel": null, + "hadAdvancedGasFeesSetPriorToMigration92_3": false, "nftsDropdownState": {}, "termsOfUseLastAgreed": "number", "qrHardware": {}, "usedNetworks": { "0x1": true, "0x5": true, "0x539": true }, "snapsInstallPrivacyWarningShown": true, - "hadAdvancedGasFeesSetPriorToMigration92_3": false, "serviceWorkerLastActiveTime": 0 }, "ApprovalController": { diff --git a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json index 898133b8aba2..82a23be8f4e4 100644 --- a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json +++ b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json @@ -12,7 +12,7 @@ "isUnlocked": false, "isAccountMenuOpen": false, "isNetworkMenuOpen": false, - "internalAccounts": "object", + "internalAccounts": { "accounts": {}, "selectedAccount": "" }, "unapprovedTxs": "object", "networkConfigurations": "object", "addressBook": "object", diff --git a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json b/test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json index 6be1cb1dcd42..c373c0a46b4c 100644 --- a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json +++ b/test/e2e/tests/state-snapshots/errors-before-init-opt-in-background-state.json @@ -1,6 +1,32 @@ { "data": { - "AccountsController": "object", + "AccountsController": { + "internalAccounts": { + "selectedAccount": "d5e45e4a-3b04-4a09-a5e1-39762e5c6be4", + "accounts": { + "d5e45e4a-3b04-4a09-a5e1-39762e5c6be4": { + "id": "d5e45e4a-3b04-4a09-a5e1-39762e5c6be4", + "address": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1", + "metadata": { + "name": "Account 1", + "lastSelected": 1665507600000, + "keyring": { "type": "HD Key Tree" } + }, + "options": {}, + "methods": [ + "personal_sign", + "eth_sign", + "eth_signTransaction", + "eth_signTypedData", + "eth_signTypedData_v1", + "eth_signTypedData_v3", + "eth_signTypedData_v4" + ], + "type": "eip155:eoa" + } + } + } + }, "AlertController": { "alertEnabledness": { "unconnectedAccount": true, "web3ShimUsage": true }, "unconnectedAccountAlertShownOrigins": "object", diff --git a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json b/test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json index 44c293c12def..fc47afa78432 100644 --- a/test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json +++ b/test/e2e/tests/state-snapshots/errors-before-init-opt-in-ui-state.json @@ -1,6 +1,32 @@ { "data": { - "AccountsController": "object", + "AccountsController": { + "internalAccounts": { + "selectedAccount": "d5e45e4a-3b04-4a09-a5e1-39762e5c6be4", + "accounts": { + "d5e45e4a-3b04-4a09-a5e1-39762e5c6be4": { + "id": "d5e45e4a-3b04-4a09-a5e1-39762e5c6be4", + "address": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1", + "metadata": { + "name": "Account 1", + "lastSelected": 1665507600000, + "keyring": { "type": "HD Key Tree" } + }, + "options": {}, + "methods": [ + "personal_sign", + "eth_sign", + "eth_signTransaction", + "eth_signTypedData", + "eth_signTypedData_v1", + "eth_signTypedData_v3", + "eth_signTypedData_v4" + ], + "type": "eip155:eoa" + } + } + } + }, "AlertController": { "alertEnabledness": { "unconnectedAccount": true, "web3ShimUsage": true }, "unconnectedAccountAlertShownOrigins": "object", diff --git a/test/jest/mock-store.js b/test/jest/mock-store.js index 715fdfe0486f..69c932279de5 100644 --- a/test/jest/mock-store.js +++ b/test/jest/mock-store.js @@ -236,20 +236,18 @@ export const createSwapsMockStore = () => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -259,20 +257,18 @@ export const createSwapsMockStore = () => { address: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb', id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', metadata: { + name: 'Test Account 2', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account 2', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -282,20 +278,18 @@ export const createSwapsMockStore = () => { address: '0x2f8d4a878cfa04a6e60d46362f5644deab66572d', id: '15e69915-2a1a-4019-93b3-916e11fd432f', metadata: { + name: 'Ledger Hardware 2', keyring: { type: 'Ledger Hardware', }, }, - name: 'Ledger Hardware 2', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -305,20 +299,18 @@ export const createSwapsMockStore = () => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: '784225f4-d30b-4e77-a900-c8bbce735b88', metadata: { + name: 'Test Account 3', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account 3', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/app/account-list-item/account-list-item-component.test.js b/ui/components/app/account-list-item/account-list-item-component.test.js index a2b607d5d778..6e17560be933 100644 --- a/ui/components/app/account-list-item/account-list-item-component.test.js +++ b/ui/components/app/account-list-item/account-list-item-component.test.js @@ -12,8 +12,25 @@ describe('AccountListItem Component', () => { const props = { account: { address: 'mockAddress', - name: 'mockName', balance: 'mockBalance', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + name: 'mockName', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [ + 'personal_sign', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, className: 'mockClassName', displayAddress: false, @@ -58,6 +75,25 @@ describe('AccountListItem Component', () => { ...props, account: { address: 'addressButNoName', + balance: 'mockBalance', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + name: '', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [ + 'personal_sign', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, }; diff --git a/ui/components/app/account-list-item/account-list-item.js b/ui/components/app/account-list-item/account-list-item.js index 25671dafab82..83bcfc6f23db 100644 --- a/ui/components/app/account-list-item/account-list-item.js +++ b/ui/components/app/account-list-item/account-list-item.js @@ -14,7 +14,11 @@ export default function AccountListItem({ hideDefaultMismatchWarning = false, ///: END:ONLY_INCLUDE_IN }) { - const { name, address, balance } = account || {}; + const { + address, + balance, + metadata: { name }, + } = account || {}; let showDefaultMismatchWarning = true; @@ -61,10 +65,21 @@ AccountListItem.propTypes = { * An account object that has name, address, and balance data */ account: PropTypes.shape({ + id: PropTypes.string.isRequired, address: PropTypes.string.isRequired, - balance: PropTypes.string, - name: PropTypes.string, - }), + balance: PropTypes.string.isRequired, + metadata: PropTypes.shape({ + name: PropTypes.string.isRequired, + snap: PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string, + enabled: PropTypes.bool, + }), + keyring: PropTypes.shape({ + type: PropTypes.string.isRequired, + }).isRequired, + }).isRequired, + }).isRequired, /** * Additional className to add to the root div element of AccountListItem */ diff --git a/ui/components/app/account-list-item/account-list-item.stories.js b/ui/components/app/account-list-item/account-list-item.stories.js index 5412fadbcf87..04ef1a5abb36 100644 --- a/ui/components/app/account-list-item/account-list-item.stories.js +++ b/ui/components/app/account-list-item/account-list-item.stories.js @@ -22,9 +22,25 @@ export default { }; const account = { - name: 'Account 2', address: '0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e', balance: '0x2d3142f5000', + metadata: { + name: 'Account 2', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [ + 'personal_sign', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }; export const DefaultStory = (args) => { diff --git a/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.test.js b/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.test.js index 89d8c8872486..e005012c538e 100644 --- a/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.test.js +++ b/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.test.js @@ -22,20 +22,18 @@ describe('Unconnected Account Alert', () => { address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Account 1', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -45,20 +43,18 @@ describe('Unconnected Account Alert', () => { address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', metadata: { + name: 'Account 2', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 2', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.test.js b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.test.js index 36756b923689..4845eba8ebf9 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.test.js +++ b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.test.js @@ -31,20 +31,18 @@ describe('Confirm Page Container Content', () => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -54,20 +52,18 @@ describe('Confirm Page Container Content', () => { address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', metadata: { + name: 'Test Account 2', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account 2', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -77,20 +73,18 @@ describe('Confirm Page Container Content', () => { address: '0xc42edfcc21ed14dda456aa0756c153f7985d8813', id: '15e69915-2a1a-4019-93b3-916e11fd432f', metadata: { + name: 'Ledger Hardware 2', keyring: { type: 'Ledger Hardware', }, }, - name: 'Ledger Hardware 2', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -100,20 +94,18 @@ describe('Confirm Page Container Content', () => { address: '0xeb9e64b93097bc15f01f13eae97015c57ab64823', id: '784225f4-d30b-4e77-a900-c8bbce735b88', metadata: { + name: 'Test Account 3', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account 3', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/app/contact-list/recipient-group/recipient-group.component.js b/ui/components/app/contact-list/recipient-group/recipient-group.component.js index 031761f6a340..87d806a956fd 100644 --- a/ui/components/app/contact-list/recipient-group/recipient-group.component.js +++ b/ui/components/app/contact-list/recipient-group/recipient-group.component.js @@ -40,43 +40,47 @@ export default function RecipientGroup({ {label} )} - {items.map(({ address, name }) => ( - onSelect(address, name)} - className={classnames({ - 'send__select-recipient-wrapper__group-item': !addressesEqual( - address, - selectedAddress, - ), - 'send__select-recipient-wrapper__group-item--selected': - addressesEqual(address, selectedAddress), - })} - padding={4} - > - + {items.map((item) => { + const { address } = item; + const name = item.name ? item.name : item.metadata.name; // item could be an address book entry or internal account + return ( onSelect(address, name)} + className={classnames({ + 'send__select-recipient-wrapper__group-item': !addressesEqual( + address, + selectedAddress, + ), + 'send__select-recipient-wrapper__group-item--selected': + addressesEqual(address, selectedAddress), + })} + padding={4} > - + - {name || ellipsify(address)} - - {name && ( - {ellipsify(address)} + {name || ellipsify(address)} - )} + {name && ( + + {ellipsify(address)} + + )} + - - ))} + ); + })} ); } @@ -86,7 +90,9 @@ RecipientGroup.propTypes = { items: PropTypes.arrayOf( PropTypes.shape({ address: PropTypes.string.isRequired, - name: PropTypes.string, + metadata: PropTypes.shape({ + name: PropTypes.string, + }), }), ), onSelect: PropTypes.func.isRequired, diff --git a/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.test.js b/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.test.js index 497c54ccd41e..8aa2623d2a57 100644 --- a/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.test.js +++ b/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.test.js @@ -67,20 +67,18 @@ const render = ({ txProps, contextProps } = {}) => { address: '0xAddress', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.test.js b/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.test.js index d4a08646f754..f1cfc717894c 100644 --- a/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.test.js +++ b/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.test.js @@ -76,20 +76,18 @@ const renderComponent = ({ address: '0xAddress', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/app/edit-gas-fee-popover/edit-gas-tooltip/edit-gas-tooltip.test.js b/ui/components/app/edit-gas-fee-popover/edit-gas-tooltip/edit-gas-tooltip.test.js index b2cbed5df009..2ba4e50a22c2 100644 --- a/ui/components/app/edit-gas-fee-popover/edit-gas-tooltip/edit-gas-tooltip.test.js +++ b/ui/components/app/edit-gas-fee-popover/edit-gas-tooltip/edit-gas-tooltip.test.js @@ -47,20 +47,18 @@ const renderComponent = (componentProps) => { address: '0xAddress', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/app/gas-details-item/gas-details-item-title/gas-details-item-title.test.js b/ui/components/app/gas-details-item/gas-details-item-title/gas-details-item-title.test.js index f1e9837e7819..fe8be78956b0 100644 --- a/ui/components/app/gas-details-item/gas-details-item-title/gas-details-item-title.test.js +++ b/ui/components/app/gas-details-item/gas-details-item-title/gas-details-item-title.test.js @@ -34,20 +34,18 @@ const render = () => { address: '0xAddress', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.component.js b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.component.js index 2a50b79f0d83..075495af8666 100644 --- a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.component.js +++ b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.component.js @@ -13,10 +13,10 @@ export default class ConfirmRemoveAccount extends Component { removeAccount: PropTypes.func.isRequired, account: PropTypes.shape({ id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, address: PropTypes.string.isRequired, balance: PropTypes.string.isRequired, metadata: PropTypes.shape({ + name: PropTypes.string.isRequired, snap: PropTypes.shape({ id: PropTypes.string.isRequired, name: PropTypes.string, @@ -58,7 +58,7 @@ export default class ConfirmRemoveAccount extends Component { {t('name')} - {account.name} + {account.metadata.name}
diff --git a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.test.js b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.test.js index 70ef3e919f03..3c152551d966 100644 --- a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.test.js +++ b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.test.js @@ -16,20 +16,18 @@ describe('Confirm Remove Account', () => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Account 1', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -48,20 +46,18 @@ describe('Confirm Remove Account', () => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Account 1', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/app/nft-details/nft-details.js b/ui/components/app/nft-details/nft-details.js index 22fc487d95e6..696c65455398 100644 --- a/ui/components/app/nft-details/nft-details.js +++ b/ui/components/app/nft-details/nft-details.js @@ -81,7 +81,9 @@ export default function NftDetails({ nft }) { const nftContractName = nftContracts.find(({ address: contractAddress }) => isEqualCaseInsensitive(contractAddress, address), )?.name; - const { name: selectedAccountName } = useSelector(getSelectedInternalAccount); + const { + metadata: { name: selectedAccountName }, + } = useSelector(getSelectedInternalAccount); const nftImageAlt = getNftImageAlt(nft); const nftImageURL = getAssetImageURL(imageOriginal ?? image, ipfsGateway); diff --git a/ui/components/app/nfts-tab/nfts-tab.test.js b/ui/components/app/nfts-tab/nfts-tab.test.js index 43e142fb8733..98ac3a2a0752 100644 --- a/ui/components/app/nfts-tab/nfts-tab.test.js +++ b/ui/components/app/nfts-tab/nfts-tab.test.js @@ -170,20 +170,18 @@ const render = ({ address: selectedAddress, id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/app/selected-account/selected-account.component.js b/ui/components/app/selected-account/selected-account.component.js index a914665986ac..e357123cff9a 100644 --- a/ui/components/app/selected-account/selected-account.component.js +++ b/ui/components/app/selected-account/selected-account.component.js @@ -106,7 +106,9 @@ class SelectedAccount extends Component { copyToClipboard(checksummedAddress); }} > -
{selectedAccount.name}
+
+ {selectedAccount.metadata.name} +
{ ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) diff --git a/ui/components/app/signature-request-header/signature-request-header.js b/ui/components/app/signature-request-header/signature-request-header.js index 6fb3149dc432..a328b541ad3d 100644 --- a/ui/components/app/signature-request-header/signature-request-header.js +++ b/ui/components/app/signature-request-header/signature-request-header.js @@ -32,6 +32,8 @@ const SignatureRequestHeader = ({ txData }) => { } = txData; const allAccounts = useSelector(accountsWithSendEtherInfoSelector); const fromAccount = getAccountByAddress(allAccounts, from); + + console.log(333, fromAccount); const nativeCurrency = useSelector(getNativeCurrency); const currentCurrency = useSelector(getCurrentCurrency); const currentChainId = useSelector(getCurrentChainId); @@ -70,7 +72,7 @@ const SignatureRequestHeader = ({ txData }) => { return ( { address: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Account 1', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -67,20 +65,18 @@ describe('Signature Request Data', () => { address: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF', id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', metadata: { + name: 'Account 2', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 2', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/app/signature-request/signature-request-header/signature-request-header.component.test.js b/ui/components/app/signature-request/signature-request-header/signature-request-header.component.test.js index 69795f28de04..aaf5a0fda7f2 100644 --- a/ui/components/app/signature-request/signature-request-header/signature-request-header.component.test.js +++ b/ui/components/app/signature-request/signature-request-header/signature-request-header.component.test.js @@ -7,7 +7,11 @@ import SignatureRequestHeader from './signature-request-header.component'; describe('SignatureRequestHeader', () => { const store = configureMockStore()(mockState); it('renders correctly with fromAccount', () => { - const fromAccount = { address: '0x' }; + const fromAccount = { + address: '0x', + metadata: { name: '' }, + balance: '0x', + }; const { container } = renderWithProvider( , diff --git a/ui/components/app/signature-request/signature-request.js b/ui/components/app/signature-request/signature-request.js index 0fdeb1c74abf..15051d1dd1cc 100644 --- a/ui/components/app/signature-request/signature-request.js +++ b/ui/components/app/signature-request/signature-request.js @@ -23,8 +23,8 @@ import { getTotalUnapprovedMessagesCount, ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) accountsWithSendEtherInfoSelector, - getSelectedAccount, getAccountType, + getSelectedInternalAccountWithBalance, ///: END:ONLY_INCLUDE_IN } from '../../../selectors'; import { @@ -124,7 +124,7 @@ const SignatureRequest = ({ txData }) => { ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) // Used to show a warning if the signing account is not the selected account // Largely relevant for contract wallet custodians - const selectedAccount = useSelector(getSelectedAccount); + const selectedAccount = useSelector(getSelectedInternalAccountWithBalance); const mmiActions = mmiActionsFactory(); const accountType = useSelector(getAccountType); const isNotification = getEnvironmentType() === ENVIRONMENT_TYPE_NOTIFICATION; diff --git a/ui/components/app/signature-request/signature-request.test.js b/ui/components/app/signature-request/signature-request.test.js index 25aad9ded96b..0ee506c08ec6 100644 --- a/ui/components/app/signature-request/signature-request.test.js +++ b/ui/components/app/signature-request/signature-request.test.js @@ -16,8 +16,9 @@ import { getMemoizedAddressBook, getPreferences, getSelectedAccount, - getInternalAccounts, + getSelectedInternalAccountWithBalance, getTotalUnapprovedMessagesCount, + getInternalAccounts, unconfirmedTransactionsHashSelector, } from '../../../selectors'; import SignatureRequest from './signature-request'; @@ -55,20 +56,18 @@ const mockStore = { address: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'John Doe', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -115,10 +114,31 @@ const generateUseSelectorRouter = (opts) => (selector) => { ]; case getInternalAccounts: return Object.values(opts.metamask.internalAccounts.accounts); + case getSelectedInternalAccountWithBalance: + return { + ...opts.metamask.internalAccounts.accounts[ + opts.metamask.internalAccounts.selectedAccount + ], + balance: + opts.metamask.accounts[ + opts.metamask.internalAccounts.accounts[ + opts.metamask.internalAccounts.selectedAccount + ].address + ]?.balance ?? 0, + }; case getMemoizedAddressBook: return []; case accountsWithSendEtherInfoSelector: - return Object.values(opts.metamask.accounts); + return Object.values(opts.metamask.internalAccounts.accounts).map( + (internalAccount) => { + return { + ...internalAccount, + ...(opts.metamask.accounts[internalAccount.address] ?? {}), + balance: + opts.metamask.accounts[internalAccount.address]?.balance ?? 0, + }; + }, + ); case unconfirmedTransactionsHashSelector: return {}; default: @@ -456,34 +476,58 @@ describe('Signature Request Component', () => { balance: '0x0', name: 'Account 1', }, + '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5': { + address: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', + balance: '0x0', + name: 'Account 2', + }, }, internalAccounts: { accounts: { - 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + 'b7e813d6-e31c-4bad-8615-8d4eff9f44f1': { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'b7e813d6-e31c-4bad-8615-8d4eff9f44f1', + metadata: { + name: 'Account 1', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [ + 'personal_sign', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { + address: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Account 2', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], type: 'eip155:eoa', }, }, - selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + selectedAccount: 'b7e813d6-e31c-4bad-8615-8d4eff9f44f1', }, }, }), diff --git a/ui/components/app/transaction-status-label/transaction-status-label.test.js b/ui/components/app/transaction-status-label/transaction-status-label.test.js index a9de09bab52e..392d86ee22e9 100644 --- a/ui/components/app/transaction-status-label/transaction-status-label.test.js +++ b/ui/components/app/transaction-status-label/transaction-status-label.test.js @@ -15,20 +15,18 @@ describe('TransactionStatusLabel Component', () => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -147,20 +145,18 @@ describe('TransactionStatusLabel Component', () => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Account 1', keyring: { type: 'Custody - Jupiter', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -211,20 +207,18 @@ describe('TransactionStatusLabel Component', () => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Account 1', keyring: { type: 'Custody - Jupiter', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -277,20 +271,18 @@ describe('TransactionStatusLabel Component', () => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Account 1', keyring: { type: 'Custody - Jupiter', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/app/wallet-overview/eth-overview.test.js b/ui/components/app/wallet-overview/eth-overview.test.js index 8acc1a39a62f..05042b20022a 100644 --- a/ui/components/app/wallet-overview/eth-overview.test.js +++ b/ui/components/app/wallet-overview/eth-overview.test.js @@ -54,20 +54,18 @@ describe('EthOverview', () => { address: '0x1', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Account 1', keyring: { type: KeyringType.imported, }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -77,20 +75,18 @@ describe('EthOverview', () => { address: '0x2', id: 'e9b992f9-e151-4317-b8b7-c771bb73dd02', metadata: { + name: 'Account 2', keyring: { type: KeyringType.imported, }, }, - name: 'Account 2', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/app/wallet-overview/token-overview.test.js b/ui/components/app/wallet-overview/token-overview.test.js index 67961994aa41..0de727d78b55 100644 --- a/ui/components/app/wallet-overview/token-overview.test.js +++ b/ui/components/app/wallet-overview/token-overview.test.js @@ -41,20 +41,18 @@ describe('TokenOverview', () => { address: '0x1', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.js b/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.js index 54f45d6ce700..69aaec27066a 100644 --- a/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.js +++ b/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.js @@ -51,20 +51,18 @@ describe('Interactive Replacement Token Notification', () => { address: '0xca8f1F0245530118D0cf14a06b01Daf8f76Cf281', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'Custody', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/institutional/wrong-network-notification/wrong-network-notification.test.js b/ui/components/institutional/wrong-network-notification/wrong-network-notification.test.js index c0e2dbfd5930..b63a681f9153 100644 --- a/ui/components/institutional/wrong-network-notification/wrong-network-notification.test.js +++ b/ui/components/institutional/wrong-network-notification/wrong-network-notification.test.js @@ -33,20 +33,18 @@ describe('Wrong Network Notification', function () { address: '0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Custody Account A', keyring: { type: 'Custody', }, }, - name: 'Custody Account A', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/multichain/account-details/account-details.js b/ui/components/multichain/account-details/account-details.js index 7890298f97fa..882c83b59b03 100644 --- a/ui/components/multichain/account-details/account-details.js +++ b/ui/components/multichain/account-details/account-details.js @@ -47,7 +47,10 @@ export const AccountDetails = ({ accountId }) => { const useBlockie = useSelector((state) => state.metamask.useBlockie); const accounts = useSelector(getMetaMaskAccountsOrdered); const account = useSelector((state) => getInternalAccount(state, accountId)); - const { name, address } = account; + const { + metadata: { name }, + address, + } = account; const [showHoldToReveal, setShowHoldToReveal] = useState(false); const [attemptingExport, setAttemptingExport] = useState(false); diff --git a/ui/components/multichain/account-list-item-menu/account-list-item-menu.js b/ui/components/multichain/account-list-item-menu/account-list-item-menu.js index fcd595510529..b12e99488700 100644 --- a/ui/components/multichain/account-list-item-menu/account-list-item-menu.js +++ b/ui/components/multichain/account-list-item-menu/account-list-item-menu.js @@ -237,14 +237,14 @@ AccountListItemMenu.propTypes = { */ account: PropTypes.shape({ id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, address: PropTypes.string.isRequired, balance: PropTypes.string.isRequired, metadata: PropTypes.shape({ + name: PropTypes.string.isRequired, snap: PropTypes.shape({ id: PropTypes.string.isRequired, - name: PropTypes.string, - enabled: PropTypes.bool, + name: PropTypes.string.isRequired, + enabled: PropTypes.bool.isRequired, }), keyring: PropTypes.shape({ type: PropTypes.string.isRequired, diff --git a/ui/components/multichain/account-list-item/account-list-item.js b/ui/components/multichain/account-list-item/account-list-item.js index 6cd395e4a5ea..e70223b0480a 100644 --- a/ui/components/multichain/account-list-item/account-list-item.js +++ b/ui/components/multichain/account-list-item/account-list-item.js @@ -167,16 +167,17 @@ export const AccountListItem = ({ textAlign={TextAlign.Left} ellipsis > - {account.name.length > MAXIMUM_CHARACTERS_WITHOUT_TOOLTIP ? ( + {account.metadata.name.length > + MAXIMUM_CHARACTERS_WITHOUT_TOOLTIP ? ( - {account.name} + {account.metadata.name} ) : ( - account.name + account.metadata.name )} @@ -239,7 +240,7 @@ export const AccountListItem = ({ ) : null} { describe('AccountListItem', () => { it('renders AccountListItem component and shows account name, address, and balance', () => { const { container } = render(); - expect(screen.getByText(account.name)).toBeInTheDocument(); + expect(screen.getByText(account.metadata.name)).toBeInTheDocument(); expect( screen.getByText(shortenAddress(toChecksumHexAddress(account.address))), ).toBeInTheDocument(); @@ -54,7 +54,10 @@ describe('AccountListItem', () => { selected: true, account: { ...account, - name: 'This is a super long name that requires tooltip', + metadata: { + ...account.metadata, + name: 'This is a super long name that requires tooltip', + }, }, }); expect( @@ -110,20 +113,18 @@ describe('AccountListItem', () => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Snap Account', keyring: { type: 'Snap Keyring', }, }, - name: 'Snap Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/multichain/account-list-menu/account-list-menu.js b/ui/components/multichain/account-list-menu/account-list-menu.js index ac27d5de561b..84b67f8d79d2 100644 --- a/ui/components/multichain/account-list-menu/account-list-menu.js +++ b/ui/components/multichain/account-list-menu/account-list-menu.js @@ -72,7 +72,7 @@ export const AccountListMenu = ({ onClose }) => { distance: 100, maxPatternLength: 32, minMatchCharLength: 1, - keys: ['name', 'address', 'id'], + keys: ['metadata.name', 'address', 'id'], }); fuse.setCollection(accounts); searchResults = fuse.search(searchQuery); diff --git a/ui/components/multichain/account-list-menu/account-list-menu.test.js b/ui/components/multichain/account-list-menu/account-list-menu.test.js index e0ac76c43749..d7981860e925 100644 --- a/ui/components/multichain/account-list-menu/account-list-menu.test.js +++ b/ui/components/multichain/account-list-menu/account-list-menu.test.js @@ -143,20 +143,18 @@ describe('AccountListMenu', () => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/multichain/app-header/app-header.js b/ui/components/multichain/app-header/app-header.js index f187448a153f..4950bd5de1a4 100644 --- a/ui/components/multichain/app-header/app-header.js +++ b/ui/components/multichain/app-header/app-header.js @@ -281,7 +281,7 @@ export const AppHeader = ({ location }) => { {internalAccount ? ( { dispatch(toggleAccountMenu()); diff --git a/ui/components/multichain/connected-site-menu/connected-site-menu.js b/ui/components/multichain/connected-site-menu/connected-site-menu.js index c299ac8127e6..8ed76f556c36 100644 --- a/ui/components/multichain/connected-site-menu/connected-site-menu.js +++ b/ui/components/multichain/connected-site-menu/connected-site-menu.js @@ -50,7 +50,7 @@ export const ConnectedSiteMenu = ({ title={ status === STATUS_NOT_CONNECTED ? t('statusNotConnectedAccount') - : `${selectedAccount?.name} ${text}` + : `${selectedAccount?.metadata.name} ${text}` } data-testid="multichain-connected-site-menu__tooltip" position="bottom" diff --git a/ui/components/multichain/connected-site-menu/connected-site-menu.test.js b/ui/components/multichain/connected-site-menu/connected-site-menu.test.js index 29ce8c73bc84..dc5ea74d6a21 100644 --- a/ui/components/multichain/connected-site-menu/connected-site-menu.test.js +++ b/ui/components/multichain/connected-site-menu/connected-site-menu.test.js @@ -19,20 +19,18 @@ describe('Connected Site Menu', () => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Account 1', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -42,20 +40,18 @@ describe('Connected Site Menu', () => { address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', metadata: { + name: 'Account 2', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 2', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/multichain/create-account/create-account.test.js b/ui/components/multichain/create-account/create-account.test.js index bbe6974509a4..2efd7f96ee4c 100644 --- a/ui/components/multichain/create-account/create-account.test.js +++ b/ui/components/multichain/create-account/create-account.test.js @@ -12,22 +12,20 @@ const render = (props = { onActionComplete: () => jest.fn() }) => { const mockInternalAccount = { id: '0179ecc1-19c2-4c78-8df9-e08b604665e9', - name: 'test', address: '0x1', metadata: { + name: 'test', keyring: { type: 'HD Key Tree', }, }, options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/components/multichain/select-action-modal/select-action-modal.test.js b/ui/components/multichain/select-action-modal/select-action-modal.test.js index 6dfaadb1bab3..a67d69f1e732 100644 --- a/ui/components/multichain/select-action-modal/select-action-modal.test.js +++ b/ui/components/multichain/select-action-modal/select-action-modal.test.js @@ -70,20 +70,18 @@ describe('Select Action Modal', () => { address: '0x1', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/ducks/app/app.test.js b/ui/ducks/app/app.test.js index 881760860c9d..8440d2ce5977 100644 --- a/ui/ducks/app/app.test.js +++ b/ui/ducks/app/app.test.js @@ -12,20 +12,18 @@ describe('App State', () => { address: '0xAddress', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Accounts 1', keyring: { type: 'HD Key Tree', }, }, - name: 'Accounts 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/ducks/metamask/metamask.js b/ui/ducks/metamask/metamask.js index b30d7b50a4f7..0877d07af994 100644 --- a/ui/ducks/metamask/metamask.js +++ b/ui/ducks/metamask/metamask.js @@ -93,7 +93,10 @@ export default function reduceMetamask(state = initialState, action) { ...metamaskState.internalAccounts.accounts, [accountId]: { ...metamaskState.internalAccounts.accounts[accountId], - name: label, + metadata: { + ...metamaskState.internalAccounts.accounts[accountId].metadata, + name: label, + }, }, }, }; diff --git a/ui/ducks/metamask/metamask.test.js b/ui/ducks/metamask/metamask.test.js index 55d8df8ba96a..179b9b9aea6c 100644 --- a/ui/ducks/metamask/metamask.test.js +++ b/ui/ducks/metamask/metamask.test.js @@ -26,20 +26,18 @@ describe('MetaMask Reducers', () => { address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Send Account 1', keyring: { type: 'HD Key Tree', }, }, - name: 'Send Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -49,20 +47,18 @@ describe('MetaMask Reducers', () => { address: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb', id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', metadata: { + name: 'Send Account 2', keyring: { type: 'HD Key Tree', }, }, - name: 'Send Account 2', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -72,20 +68,18 @@ describe('MetaMask Reducers', () => { address: '0x2f8d4a878cfa04a6e60d46362f5644deab66572d', id: '15e69915-2a1a-4019-93b3-916e11fd432f', metadata: { + name: 'Send Account 3', keyring: { type: 'HD Key Tree', }, }, - name: 'Send Account 3', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -95,20 +89,18 @@ describe('MetaMask Reducers', () => { address: '0xd85a4b6a394794842887b8284293d69163007bbb', id: '784225f4-d30b-4e77-a900-c8bbce735b88', metadata: { + name: 'Send Account 4', keyring: { type: 'HD Key Tree', }, }, - name: 'Send Account 4', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -210,20 +202,18 @@ describe('MetaMask Reducers', () => { address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Send Account 1', keyring: { type: 'HD Key Tree', }, }, - name: 'Send Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -249,20 +239,18 @@ describe('MetaMask Reducers', () => { address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Send Account 1', keyring: { type: 'HD Key Tree', }, }, - name: 'Send Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -286,20 +274,18 @@ describe('MetaMask Reducers', () => { address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'test label', keyring: { type: 'HD Key Tree', }, }, - name: 'test label', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -450,19 +436,18 @@ describe('MetaMask Reducers', () => { { id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Send Account 1', keyring: { type: 'HD Key Tree', }, }, options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -471,24 +456,22 @@ describe('MetaMask Reducers', () => { balance: '0x47c9d71831c76efe', nonce: '0x1b', address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825', - name: 'Send Account 1', }, { id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', metadata: { + name: 'Send Account 2', keyring: { type: 'HD Key Tree', }, }, options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -497,24 +480,22 @@ describe('MetaMask Reducers', () => { balance: '0x37452b1315889f80', nonce: '0xa', address: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb', - name: 'Send Account 2', }, { id: '15e69915-2a1a-4019-93b3-916e11fd432f', metadata: { + name: 'Send Account 3', keyring: { type: 'HD Key Tree', }, }, options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -523,24 +504,22 @@ describe('MetaMask Reducers', () => { balance: '0x30c9d71831c76efe', nonce: '0x1c', address: '0x2f8d4a878cfa04a6e60d46362f5644deab66572d', - name: 'Send Account 3', }, { id: '784225f4-d30b-4e77-a900-c8bbce735b88', metadata: { + name: 'Send Account 4', keyring: { type: 'HD Key Tree', }, }, options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -549,7 +528,6 @@ describe('MetaMask Reducers', () => { balance: '0x0', nonce: '0x0', address: '0xd85a4b6a394794842887b8284293d69163007bbb', - name: 'Send Account 4', }, { address: '0x06195827297c7a80a443b6894d3bdb8824b43896', diff --git a/ui/ducks/send/send.test.js b/ui/ducks/send/send.test.js index 56ae1cf7868e..d46bc09af077 100644 --- a/ui/ducks/send/send.test.js +++ b/ui/ducks/send/send.test.js @@ -1289,20 +1289,18 @@ describe('Send Slice', () => { address: mockAddress1, id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -1617,20 +1615,18 @@ describe('Send Slice', () => { address: mockAddress1, id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -1847,20 +1843,18 @@ describe('Send Slice', () => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -2176,20 +2170,18 @@ describe('Send Slice', () => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -2511,20 +2503,18 @@ describe('Send Slice', () => { address: mockAddress1, id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -2600,20 +2590,18 @@ describe('Send Slice', () => { balance: '0x0', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -2699,20 +2687,18 @@ describe('Send Slice', () => { address: mockAddress1, id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -2790,20 +2776,18 @@ describe('Send Slice', () => { balance: '0x0', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -2904,19 +2888,18 @@ describe('Send Slice', () => { address: mockAddress1, id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], type: 'eip155:eoa', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, @@ -3026,19 +3009,18 @@ describe('Send Slice', () => { balance: '0x0', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], type: 'eip155:eoa', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, diff --git a/ui/helpers/utils/accounts.js b/ui/helpers/utils/accounts.js index f47f54981a4b..d058ecc517da 100644 --- a/ui/helpers/utils/accounts.js +++ b/ui/helpers/utils/accounts.js @@ -13,7 +13,7 @@ export function getAccountNameErrorMessage( defaultAccountName, ) { const isDuplicateAccountName = accounts.some( - (item) => item.name.toLowerCase() === newAccountName.toLowerCase(), + (item) => item.metadata.name.toLowerCase() === newAccountName.toLowerCase(), ); const isEmptyAccountName = newAccountName === ''; diff --git a/ui/helpers/utils/accounts.test.js b/ui/helpers/utils/accounts.test.js index e0bea4312f76..fb03cf343010 100644 --- a/ui/helpers/utils/accounts.test.js +++ b/ui/helpers/utils/accounts.test.js @@ -7,7 +7,10 @@ import { import { BackgroundColor } from '../constants/design-system'; import { getAccountNameErrorMessage, getAvatarNetworkColor } from './accounts'; -const mockAccounts = [{ name: 'Account 1' }, { name: 'Account 2' }]; +const mockAccounts = [ + { metadata: { name: 'Account 1' } }, + { metadata: { name: 'Account 2' } }, +]; const mockLocalization = { t: jest.fn().mockReturnValue('Account') }; diff --git a/ui/hooks/useAddressDetails.js b/ui/hooks/useAddressDetails.js index aa1cd5d26289..96a7ed0f7e37 100644 --- a/ui/hooks/useAddressDetails.js +++ b/ui/hooks/useAddressDetails.js @@ -28,7 +28,7 @@ const useAddressDetails = (toAddress) => { return { toName: addressBookEntryObject.name, isTrusted: true }; } if (toAccount) { - return { toName: toAccount.name, isTrusted: true }; + return { toName: toAccount.metadata.name, isTrusted: true }; } if (tokenList[toAddress?.toLowerCase()]?.name) { return { diff --git a/ui/hooks/useAddressDetails.test.js b/ui/hooks/useAddressDetails.test.js index 76f3db93b097..4db47e8a91ab 100644 --- a/ui/hooks/useAddressDetails.test.js +++ b/ui/hooks/useAddressDetails.test.js @@ -19,20 +19,18 @@ const renderUseAddressDetails = (toAddress, stateVariables = {}) => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -92,20 +90,18 @@ describe('useAddressDetails', () => { address: '0x06195827297c7A80a443b6894d3BDB8824b43896', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Account 1', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/hooks/useAssetDetails.test.js b/ui/hooks/useAssetDetails.test.js index 4a0860f499d5..7ddbb19db534 100644 --- a/ui/hooks/useAssetDetails.test.js +++ b/ui/hooks/useAssetDetails.test.js @@ -26,20 +26,18 @@ const renderUseAssetDetails = ({ address: userAddress, id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/pages/asset/components/token-asset.js b/ui/pages/asset/components/token-asset.js index 15b353392699..027e97811e83 100644 --- a/ui/pages/asset/components/token-asset.js +++ b/ui/pages/asset/components/token-asset.js @@ -27,7 +27,7 @@ export default function TokenAsset({ token }) { const chainId = useSelector(getCurrentChainId); const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider); const selectedAccount = useSelector(getSelectedInternalAccount); - const selectedAccountName = selectedAccount.name; + const selectedAccountName = selectedAccount.metadata.name; const selectedAddress = selectedAccount.address; const history = useHistory(); const tokenTrackerLink = getTokenTrackerLink( diff --git a/ui/pages/confirm-add-suggested-token/confirm-add-suggested-token.test.js b/ui/pages/confirm-add-suggested-token/confirm-add-suggested-token.test.js index e62a71d3a5e7..2d26ac98bc9e 100644 --- a/ui/pages/confirm-add-suggested-token/confirm-add-suggested-token.test.js +++ b/ui/pages/confirm-add-suggested-token/confirm-add-suggested-token.test.js @@ -68,20 +68,18 @@ const renderComponent = (tokens = []) => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/pages/confirm-decrypt-message/confirm-decrypt-message.component.test.js b/ui/pages/confirm-decrypt-message/confirm-decrypt-message.component.test.js index 4939352d2bed..fb4231351d8a 100644 --- a/ui/pages/confirm-decrypt-message/confirm-decrypt-message.component.test.js +++ b/ui/pages/confirm-decrypt-message/confirm-decrypt-message.component.test.js @@ -80,7 +80,24 @@ const baseProps = { fromAccount: { address: '0x123456789abcdef', balance: '0x346ba7725f412cbfdb', - name: 'Antonio', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + name: 'Antonio', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [ + 'personal_sign', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, }; diff --git a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.test.js b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.test.js index 4d84fbbf6ddf..d039c2174c9d 100644 --- a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.test.js +++ b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.test.js @@ -29,6 +29,24 @@ const baseProps = { fromAccount: { address: '0x123456789abcdef', balance: '0x346ba7725f412cbfdb', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + name: 'Antonio', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [ + 'personal_sign', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', name: 'Antonio', }, }; diff --git a/ui/pages/confirm-signature-request/index.test.js b/ui/pages/confirm-signature-request/index.test.js index 051f2332b6fa..99e79e6b009b 100644 --- a/ui/pages/confirm-signature-request/index.test.js +++ b/ui/pages/confirm-signature-request/index.test.js @@ -37,20 +37,18 @@ const mockState = { address: '0x8eeee1781fd885ff5ddef7789486676961873d12', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Account 1', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js b/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js index 34283b76abf9..1044a14c2605 100644 --- a/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js +++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js @@ -145,7 +145,10 @@ const mapStateToProps = (state, ownProps) => { state, fromAddress, ); - const { name: fromName, balance } = fromAccount; + const { + metadata: { name: fromName }, + balance, + } = fromAccount; const isSendingAmount = type === TransactionType.simpleSend || !isEmptyHexString(amount); @@ -159,7 +162,7 @@ const mapStateToProps = (state, ownProps) => { const tokenList = getTokenList(state); const toName = - getFirstInternalAccountByAddress(state, toAddress)?.name || + getFirstInternalAccountByAddress(state, toAddress)?.metadata.name || tokenList[toAddress?.toLowerCase()]?.name || shortenAddress(toChecksumHexAddress(toAddress)); diff --git a/ui/pages/confirm-transaction-base/confirm-transaction-base.test.js b/ui/pages/confirm-transaction-base/confirm-transaction-base.test.js index 0735ce0a2c8b..227a7dd081fe 100644 --- a/ui/pages/confirm-transaction-base/confirm-transaction-base.test.js +++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.test.js @@ -123,20 +123,18 @@ const baseStore = { address: mockTxParamsFromAddress, id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Account 1', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/pages/connected-accounts/connected-accounts.stories.js b/ui/pages/connected-accounts/connected-accounts.stories.js index 1c63bf6024f2..ea9a997db08e 100644 --- a/ui/pages/connected-accounts/connected-accounts.stories.js +++ b/ui/pages/connected-accounts/connected-accounts.stories.js @@ -11,20 +11,18 @@ const accounts = [ address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Account 1', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -34,20 +32,18 @@ const accounts = [ address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', metadata: { + name: 'Test Account 2', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account 2', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/pages/connected-sites/connected-sites.container.js b/ui/pages/connected-sites/connected-sites.container.js index 27779b6bcf33..ac813d8fb2b2 100644 --- a/ui/pages/connected-sites/connected-sites.container.js +++ b/ui/pages/connected-sites/connected-sites.container.js @@ -36,7 +36,7 @@ const mapStateToProps = (state) => { } return { - accountLabel: getCurrentAccountWithSendEtherInfo(state).name, + accountLabel: getCurrentAccountWithSendEtherInfo(state).metadata.name, connectedSubjects, subjects: getPermissionSubjects(state), mostRecentOverviewPage: getMostRecentOverviewPage(state), diff --git a/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.test.js b/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.test.js index 219bfaa41f6f..54cf51123283 100644 --- a/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.test.js +++ b/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.test.js @@ -114,7 +114,12 @@ const render = ({ newState } = {}) => { mockState.metamask.internalAccounts.selectedAccount ], address, - name: accountName, + metadata: { + ...mockState.metamask.internalAccounts.accounts[ + mockState.metamask.internalAccounts.selectedAccount + ].metadata, + name: accountName, + }, }, }, }, diff --git a/ui/pages/send/send-content/add-recipient/add-recipient.component.js b/ui/pages/send/send-content/add-recipient/add-recipient.component.js index 67533a739787..23725cfaf6e5 100644 --- a/ui/pages/send/send-content/add-recipient/add-recipient.component.js +++ b/ui/pages/send/send-content/add-recipient/add-recipient.component.js @@ -168,7 +168,8 @@ export default class AddRecipient extends Component { if (userInput) { ownedAccounts = ownedAccounts.filter( (item) => - item.name.toLowerCase().indexOf(userInput.toLowerCase()) > -1 || + item.metadata.name.toLowerCase().indexOf(userInput.toLowerCase()) > + -1 || item.address.toLowerCase().indexOf(userInput.toLowerCase()) > -1, ); } diff --git a/ui/pages/send/send.test.js b/ui/pages/send/send.test.js index 7a5feefa047d..14e685c7f53a 100644 --- a/ui/pages/send/send.test.js +++ b/ui/pages/send/send.test.js @@ -85,20 +85,18 @@ const baseStore = { address: '0x0', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/pages/token-allowance/token-allowance.js b/ui/pages/token-allowance/token-allowance.js index 53568cd2105c..1c9fc2f78f58 100644 --- a/ui/pages/token-allowance/token-allowance.js +++ b/ui/pages/token-allowance/token-allowance.js @@ -349,7 +349,7 @@ export default function TokenAllowance({ { 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Custody Account A', keyring: { type: 'Custody', }, }, options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -207,7 +204,6 @@ describe('Institutional selectors', () => { balance: '0x47c9d71831c76efe', nonce: '0x1b', address: accountAddress, - name: 'Custody Account A', }, }, }, @@ -237,19 +233,18 @@ describe('Institutional selectors', () => { 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Custody Account A', keyring: { type: 'Custody', }, }, options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -258,7 +253,6 @@ describe('Institutional selectors', () => { balance: '0x47c9d71831c76efe', nonce: '0x1b', address: accountAddress, - name: 'Custody Account A', }, }, }, @@ -299,20 +293,18 @@ describe('Institutional selectors', () => { address: accountAddress, id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/selectors/nonce-sorted-transactions-selector.test.js b/ui/selectors/nonce-sorted-transactions-selector.test.js index 7c2005eac671..4abb7cace15e 100644 --- a/ui/selectors/nonce-sorted-transactions-selector.test.js +++ b/ui/selectors/nonce-sorted-transactions-selector.test.js @@ -86,20 +86,18 @@ const getStateTree = ({ address: SENDERS.ONE, id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/selectors/permissions.test.js b/ui/selectors/permissions.test.js index 44ac5bf132c0..4dc843f44452 100644 --- a/ui/selectors/permissions.test.js +++ b/ui/selectors/permissions.test.js @@ -17,20 +17,18 @@ describe('selectors', () => { address: '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Really Long Name That Should Be Truncated', keyring: { type: 'HD Key Tree', }, }, - name: 'Really Long Name That Should Be Truncated', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -111,20 +109,18 @@ describe('selectors', () => { address: '0x7250739de134d33ec7ab1ee592711e15098c9d2d', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Really Long Name That Should Be Truncated', keyring: { type: 'HD Key Tree', }, }, - name: 'Really Long Name That Should Be Truncated', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -270,20 +266,18 @@ describe('selectors', () => { address: '0x7250739de134d33ec7ab1ee592711e15098c9d2d', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Really Long Name That Should Be Truncated', keyring: { type: 'HD Key Tree', }, }, - name: 'Really Long Name That Should Be Truncated', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -293,21 +287,19 @@ describe('selectors', () => { address: '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5', id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', metadata: { + name: 'Account 1', lastSelected: 1586359844192, keyring: { type: 'HD Key Tree', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -317,22 +309,20 @@ describe('selectors', () => { address: '0xb3958fb96c8201486ae20be1d5c9f58083df343a', id: '15e69915-2a1a-4019-93b3-916e11fd432f', metadata: { + name: 'Account 2', lastActive: 1586359844192, lastSelected: 1586359844193, keyring: { type: 'HD Key Tree', }, }, - name: 'Account 2', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -342,21 +332,19 @@ describe('selectors', () => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: '784225f4-d30b-4e77-a900-c8bbce735b88', metadata: { + name: 'Account 3', lastSelected: 1586359844192, keyring: { type: 'HD Key Tree', }, }, - name: 'Account 3', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -366,20 +354,18 @@ describe('selectors', () => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: 'f9305241-c50f-4725-ad0f-cbd3f24ac7ab', metadata: { + name: 'Account 4', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 4', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -423,21 +409,19 @@ describe('selectors', () => { balance: undefined, id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Really Long Name That Should Be Truncated', lastActive: 1586359844192, keyring: { type: 'HD Key Tree', }, }, - name: 'Really Long Name That Should Be Truncated', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -448,22 +432,20 @@ describe('selectors', () => { balance: undefined, id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', metadata: { + name: 'Account 1', lastActive: 1586359844192, lastSelected: 1586359844192, keyring: { type: 'HD Key Tree', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -474,22 +456,20 @@ describe('selectors', () => { balance: undefined, id: '15e69915-2a1a-4019-93b3-916e11fd432f', metadata: { + name: 'Account 2', lastActive: 1586359844192, lastSelected: 1586359844193, keyring: { type: 'HD Key Tree', }, }, - name: 'Account 2', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -500,22 +480,20 @@ describe('selectors', () => { balance: undefined, id: '784225f4-d30b-4e77-a900-c8bbce735b88', metadata: { + name: 'Account 3', lastActive: 1586359844192, lastSelected: 1586359844192, keyring: { type: 'HD Key Tree', }, }, - name: 'Account 3', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -526,59 +504,24 @@ describe('selectors', () => { balance: undefined, id: 'f9305241-c50f-4725-ad0f-cbd3f24ac7ab', metadata: { + name: 'Account 4', lastActive: 1586359844192, keyring: { type: 'HD Key Tree', }, }, - name: 'Account 4', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], type: 'eip155:eoa', }, - // { - // address: '0xb3958fb96c8201486ae20be1d5c9f58083df343a', - // balance: undefined, - // name: 'Account 2', - // lastActive: 1586359844192, - // lastSelected: 1586359844193, - // }, - // { - // address: '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5', - // balance: undefined, - // name: 'Account 1', - // lastActive: 1586359844192, - // lastSelected: 1586359844192, - // }, - // { - // address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - // balance: undefined, - // name: 'Account 3', - // lastActive: 1586359844192, - // lastSelected: 1586359844192, - // }, - // { - // address: '0x7250739de134d33ec7ab1ee592711e15098c9d2d', - // balance: undefined, - // name: 'Really Long Name That Should Be Truncated', - // lastActive: 1586359844192, - // }, - // { - // address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4', - // balance: undefined, - // name: 'Account 4', - // lastActive: 1586359844192, - // }, ]); }); }); @@ -625,20 +568,18 @@ describe('selectors', () => { address: '0x7250739de134d33ec7ab1ee592711e15098c9d2d', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Really Long Name That Should Be Truncated', keyring: { type: 'HD Key Tree', }, }, - name: 'Really Long Name That Should Be Truncated', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -648,20 +589,18 @@ describe('selectors', () => { address: '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5', id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', metadata: { + name: 'Account 1', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 1', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -671,20 +610,18 @@ describe('selectors', () => { address: '0xb3958fb96c8201486ae20be1d5c9f58083df343a', id: '15e69915-2a1a-4019-93b3-916e11fd432f', metadata: { + name: 'Account 2', keyring: { type: 'HD Key Tree', }, }, - name: 'Account 2', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 6a2a296943e9..73b1b8fdc6b2 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -505,7 +505,7 @@ export function getAccountName(accounts, accountAddress) { const account = accounts.find((internalAccount) => isEqualCaseInsensitive(internalAccount.address, accountAddress), ); - return account && account.name !== '' ? account.name : ''; + return account && account.metadata.name !== '' ? account.metadata.name : ''; } export function getFirstInternalAccountByAddress(state, address) { @@ -541,7 +541,7 @@ export function accountsWithSendEtherInfoSelector(state) { export function getAccountsWithLabels(state) { return getMetaMaskAccountsOrdered(state).map( - ({ address, name, balance }) => ({ + ({ address, balance, metadata: { name } }) => ({ address, addressLabel: `${ name.length < TRUNCATED_NAME_CHAR_LIMIT diff --git a/ui/selectors/selectors.test.js b/ui/selectors/selectors.test.js index 12ef952586de..910d6cd5819f 100644 --- a/ui/selectors/selectors.test.js +++ b/ui/selectors/selectors.test.js @@ -467,20 +467,18 @@ describe('Selectors', () => { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -575,7 +573,9 @@ describe('Selectors', () => { expect(accountsWithSendEther[0].address).toStrictEqual( '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', ); - expect(accountsWithSendEther[0].name).toStrictEqual('Test Account'); + expect(accountsWithSendEther[0].metadata.name).toStrictEqual( + 'Test Account', + ); }); it('returns selected account with balance, address, and name from accountsWithSendEtherInfoSelector', () => { @@ -587,7 +587,9 @@ describe('Selectors', () => { expect(currentAccountwithSendEther.address).toStrictEqual( '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', ); - expect(currentAccountwithSendEther.name).toStrictEqual('Test Account'); + expect(currentAccountwithSendEther.metadata.name).toStrictEqual( + 'Test Account', + ); }); it('#getGasIsLoading', () => { diff --git a/ui/selectors/transactions.test.js b/ui/selectors/transactions.test.js index 7989532a600f..1f557e433954 100644 --- a/ui/selectors/transactions.test.js +++ b/ui/selectors/transactions.test.js @@ -40,20 +40,18 @@ describe('Transaction Selectors', () => { address: '0xAddress', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -148,20 +146,18 @@ describe('Transaction Selectors', () => { address: '0xAddress', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -238,20 +234,18 @@ describe('Transaction Selectors', () => { address: '0xAddress', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -352,20 +346,18 @@ describe('Transaction Selectors', () => { address: '0xAddress', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], diff --git a/ui/store/actionConstants.test.js b/ui/store/actionConstants.test.js index 136dd41b9665..1507503145b8 100644 --- a/ui/store/actionConstants.test.js +++ b/ui/store/actionConstants.test.js @@ -4,7 +4,7 @@ import * as actionConstants from './actionConstants'; describe('Redux actionConstants', () => { describe('SET_ACCOUNT_LABEL', () => { - it('updates the state.metamask.internalAccounts.accounts[accountId].name property of the state to the action.value.label', () => { + it('updates the state.metamask.internalAccounts.accounts[accountId].metadata.name property of the state to the action.value.label', () => { const accountId = 'foo'; const initialState = { metamask: { @@ -15,20 +15,18 @@ describe('Redux actionConstants', () => { address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825', id: accountId, metadata: { + name: 'bar', keyring: { type: 'HD Key Tree', }, }, - name: 'bar', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -53,7 +51,8 @@ describe('Redux actionConstants', () => { const resultingState = reducers(initialState, action); expect( - resultingState.metamask.internalAccounts.accounts[accountId].name, + resultingState.metamask.internalAccounts.accounts[accountId].metadata + .name, ).toStrictEqual(action.value.label); }); }); diff --git a/ui/store/actions.test.js b/ui/store/actions.test.js index 1f60f7c7b738..5bb8c81db820 100644 --- a/ui/store/actions.test.js +++ b/ui/store/actions.test.js @@ -27,20 +27,18 @@ const defaultState = { address: '0xFirstAddress', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', metadata: { + name: 'Test Account', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -268,20 +266,18 @@ describe('Actions', () => { address: '0xAnotherAddress', id: '22497cc9-e791-42b8-adef-2f13ef216b86', metadata: { + name: 'Test Account 2', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account 2', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -502,20 +498,18 @@ describe('Actions', () => { address: '0xNewAddress', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb5', metadata: { + name: 'new name', keyring: { type: 'HD Key Tree', }, }, - name: 'new name', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], @@ -1997,20 +1991,18 @@ describe('Actions', () => { address: '0xFirstAddress', id: '8e110453-2231-4e62-82de-29b913dfef4b', metadata: { + name: 'Test Account 2', keyring: { type: 'HD Key Tree', }, }, - name: 'Test Account 2', options: {}, - supportedMethods: [ + methods: [ 'personal_sign', - 'eth_sendTransaction', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData', 'eth_signTypedData_v1', - 'eth_signTypedData_v2', 'eth_signTypedData_v3', 'eth_signTypedData_v4', ], From 4e9d38edab4d2dacf79d8742161e05e846a8a312 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Fri, 1 Sep 2023 19:50:41 +0800 Subject: [PATCH 078/235] feat: add keyring-api dependency --- package.json | 1 + yarn.lock | 174 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+) diff --git a/package.json b/package.json index 83f10ab61eb0..ec6f1da0017b 100644 --- a/package.json +++ b/package.json @@ -249,6 +249,7 @@ "@metamask/gas-fee-controller": "^6.0.1", "@metamask/jazzicon": "^2.0.0", "@metamask/key-tree": "^9.0.0", + "@metamask/keyring-api": "^0.2.1", "@metamask/keyring-controller": "^7.2.0", "@metamask/logo": "^3.1.1", "@metamask/message-manager": "^7.3.0", diff --git a/yarn.lock b/yarn.lock index c50dbd7a127a..142687d3a0a8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4285,6 +4285,22 @@ __metadata: languageName: node linkType: hard +"@metamask/keyring-api@npm:^0.2.1": + version: 0.2.1 + resolution: "@metamask/keyring-api@npm:0.2.1" + dependencies: + "@metamask/providers": "npm:^11.0.0" + "@metamask/rpc-methods": "npm:^0.38.1-flask.1" + "@metamask/snaps-controllers": "npm:^0.38.2-flask.1" + "@metamask/snaps-utils": "npm:^0.38.2-flask.1" + "@metamask/utils": "npm:^8.0.0" + "@types/uuid": "npm:^9.0.1" + superstruct: "npm:^1.0.3" + uuid: "npm:^9.0.0" + checksum: 12ab6f6767f32bb75e6e6d134786e3feecb520df7e584b8eec3a0c8430dd8349bf9971707a2a61a00ac2efbe594d26adc68360f8dc291d4f0439fdbf513b2bc2 + languageName: node + linkType: hard + "@metamask/keyring-controller@npm:7.2.0": version: 7.2.0 resolution: "@metamask/keyring-controller@npm:7.2.0" @@ -4497,6 +4513,26 @@ __metadata: languageName: node linkType: hard +"@metamask/permission-controller@npm:^4.1.0": + version: 4.1.1 + resolution: "@metamask/permission-controller@npm:4.1.1" + dependencies: + "@metamask/approval-controller": "npm:^3.5.1" + "@metamask/base-controller": "npm:^3.2.1" + "@metamask/controller-utils": "npm:^4.3.2" + "@metamask/utils": "npm:^6.2.0" + "@types/deep-freeze-strict": "npm:^1.1.0" + deep-freeze-strict: "npm:^1.1.1" + eth-rpc-errors: "npm:^4.0.2" + immer: "npm:^9.0.6" + json-rpc-engine: "npm:^6.1.0" + nanoid: "npm:^3.1.31" + peerDependencies: + "@metamask/approval-controller": ^3.5.1 + checksum: 5e0d05ff1d56a9a58e031806528e6f7963227d5405ffd9c4df9623fc79ecaa703e26199066bdc77ec33e35abc25e2589d059b79f131d95e47c5e936991fdb817 + languageName: node + linkType: hard + "@metamask/phishing-controller@npm:^6.0.0": version: 6.0.0 resolution: "@metamask/phishing-controller@npm:6.0.0" @@ -4599,6 +4635,25 @@ __metadata: languageName: node linkType: hard +"@metamask/providers@npm:^11.1.1": + version: 11.1.1 + resolution: "@metamask/providers@npm:11.1.1" + dependencies: + "@metamask/object-multiplex": "npm:^1.1.0" + "@metamask/safe-event-emitter": "npm:^3.0.0" + detect-browser: "npm:^5.2.0" + eth-rpc-errors: "npm:^4.0.2" + extension-port-stream: "npm:^2.0.1" + fast-deep-equal: "npm:^3.1.3" + is-stream: "npm:^2.0.0" + json-rpc-engine: "npm:^6.1.0" + json-rpc-middleware-stream: "npm:^4.2.1" + pump: "npm:^3.0.0" + webextension-polyfill: "npm:^0.10.0" + checksum: 22bbf106c6ad77f35819f32d25bc860e2439626f2fe71a0377067e2631c7c113befdd3f06f3392bb2a4a99a3c2df4771065822cf135a15d8c995cf931f25d510 + languageName: node + linkType: hard + "@metamask/rate-limit-controller@npm:^3.0.0": version: 3.0.0 resolution: "@metamask/rate-limit-controller@npm:3.0.0" @@ -4655,6 +4710,23 @@ __metadata: languageName: node linkType: hard +"@metamask/rpc-methods@npm:^0.38.1-flask.1": + version: 0.38.1-flask.1 + resolution: "@metamask/rpc-methods@npm:0.38.1-flask.1" + dependencies: + "@metamask/key-tree": "npm:^9.0.0" + "@metamask/permission-controller": "npm:^4.1.0" + "@metamask/snaps-ui": "npm:^0.37.4-flask.1" + "@metamask/snaps-utils": "npm:^0.38.2-flask.1" + "@metamask/types": "npm:^1.1.0" + "@metamask/utils": "npm:^6.0.1" + "@noble/hashes": "npm:^1.3.1" + eth-rpc-errors: "npm:^4.0.3" + superstruct: "npm:^1.0.3" + checksum: b28adc2fe7e08a58f7760ffbd67bd365f2bed8e7b34857c83ed125d9f7204dbca6edfa5d8776dafbdf4a7862d3ef828079afbba857f0d4eca1ba273f655687da + languageName: node + linkType: hard + "@metamask/rpc-methods@npm:^1.0.2": version: 1.0.2 resolution: "@metamask/rpc-methods@npm:1.0.2" @@ -4820,6 +4892,35 @@ __metadata: languageName: node linkType: hard +"@metamask/snaps-controllers@npm:^0.38.2-flask.1": + version: 0.38.2-flask.1 + resolution: "@metamask/snaps-controllers@npm:0.38.2-flask.1" + dependencies: + "@metamask/approval-controller": "npm:^3.5.0" + "@metamask/base-controller": "npm:^3.2.0" + "@metamask/object-multiplex": "npm:^1.2.0" + "@metamask/permission-controller": "npm:^4.1.0" + "@metamask/post-message-stream": "npm:^6.1.2" + "@metamask/rpc-methods": "npm:^0.38.1-flask.1" + "@metamask/snaps-execution-environments": "npm:^0.38.2-flask.1" + "@metamask/snaps-registry": "npm:^1.2.1" + "@metamask/snaps-utils": "npm:^0.38.2-flask.1" + "@metamask/utils": "npm:^6.0.1" + "@xstate/fsm": "npm:^2.0.0" + concat-stream: "npm:^2.0.0" + eth-rpc-errors: "npm:^4.0.3" + gunzip-maybe: "npm:^1.4.2" + immer: "npm:^9.0.6" + json-rpc-engine: "npm:^6.1.0" + json-rpc-middleware-stream: "npm:^4.2.0" + nanoid: "npm:^3.1.31" + pump: "npm:^3.0.0" + readable-web-to-node-stream: "npm:^3.0.2" + tar-stream: "npm:^2.2.0" + checksum: 62f555c24b5200f082e796f8cc53a326dc35a34bd94fc98f66bef1160f2f3b78a9c71e2d2548687d043817df982433f794da4a012ef3230c4604f7ce2781159a + languageName: node + linkType: hard + "@metamask/snaps-controllers@npm:^1.0.2": version: 1.0.2 resolution: "@metamask/snaps-controllers@npm:1.0.2" @@ -4892,6 +4993,25 @@ __metadata: languageName: node linkType: hard +"@metamask/snaps-execution-environments@npm:^0.38.2-flask.1": + version: 0.38.2-flask.1 + resolution: "@metamask/snaps-execution-environments@npm:0.38.2-flask.1" + dependencies: + "@metamask/object-multiplex": "npm:^1.2.0" + "@metamask/post-message-stream": "npm:^6.1.2" + "@metamask/providers": "npm:^11.1.1" + "@metamask/rpc-methods": "npm:^0.38.1-flask.1" + "@metamask/snaps-utils": "npm:^0.38.2-flask.1" + "@metamask/utils": "npm:^6.0.1" + eth-rpc-errors: "npm:^4.0.3" + json-rpc-engine: "npm:^6.1.0" + nanoid: "npm:^3.1.31" + pump: "npm:^3.0.0" + superstruct: "npm:^1.0.3" + checksum: ae8f8991d5911cb4eff0145ab136549467f5e904f3530653dbb678f52a71f0a2bc17646b57ae0aceb9848db56e1fd110cef5c24916f247ac8d3e9eaac2cee6f3 + languageName: node + linkType: hard + "@metamask/snaps-execution-environments@npm:^1.0.2": version: 1.0.2 resolution: "@metamask/snaps-execution-environments@npm:1.0.2" @@ -4953,6 +5073,16 @@ __metadata: languageName: node linkType: hard +"@metamask/snaps-ui@npm:^0.37.4-flask.1": + version: 0.37.4-flask.1 + resolution: "@metamask/snaps-ui@npm:0.37.4-flask.1" + dependencies: + "@metamask/utils": "npm:^6.0.1" + superstruct: "npm:^1.0.3" + checksum: e57ca1e375d0c7860f198143789226552cb449a654e97b639f90a0cb577f9d46387c7c65b5dacc05b7fa613ed8499021df286590b6c633b6f5be8578d4d9f6a9 + languageName: node + linkType: hard + "@metamask/snaps-ui@npm:^1.0.2": version: 1.0.2 resolution: "@metamask/snaps-ui@npm:1.0.2" @@ -5052,6 +5182,35 @@ __metadata: languageName: node linkType: hard +"@metamask/snaps-utils@npm:^0.38.2-flask.1": + version: 0.38.2-flask.1 + resolution: "@metamask/snaps-utils@npm:0.38.2-flask.1" + dependencies: + "@babel/core": "npm:^7.20.12" + "@babel/types": "npm:^7.18.7" + "@metamask/base-controller": "npm:^3.2.0" + "@metamask/key-tree": "npm:^9.0.0" + "@metamask/permission-controller": "npm:^4.1.0" + "@metamask/snaps-registry": "npm:^1.2.1" + "@metamask/snaps-ui": "npm:^0.37.4-flask.1" + "@metamask/utils": "npm:^6.0.1" + "@noble/hashes": "npm:^1.3.1" + "@scure/base": "npm:^1.1.1" + chalk: "npm:^4.1.2" + cron-parser: "npm:^4.5.0" + eth-rpc-errors: "npm:^4.0.3" + fast-deep-equal: "npm:^3.1.3" + fast-json-stable-stringify: "npm:^2.1.0" + is-svg: "npm:^4.4.0" + rfdc: "npm:^1.3.0" + semver: "npm:^7.5.4" + ses: "npm:^0.18.7" + superstruct: "npm:^1.0.3" + validate-npm-package-name: "npm:^5.0.0" + checksum: 9f488976851c7bf6c1bebaa12a2542c651bb44a7df9901ee89b6e2aed0d610a9417c1994a7aa840fb321fb66dd6c2b2148035e9205f005aab22d29d47427c957 + languageName: node + linkType: hard + "@metamask/snaps-utils@npm:^1.0.2": version: 1.0.2 resolution: "@metamask/snaps-utils@npm:1.0.2" @@ -5164,6 +5323,20 @@ __metadata: languageName: node linkType: hard +"@metamask/utils@npm:^8.0.0": + version: 8.1.0 + resolution: "@metamask/utils@npm:8.1.0" + dependencies: + "@ethereumjs/tx": "npm:^4.1.2" + "@noble/hashes": "npm:^1.3.1" + "@types/debug": "npm:^4.1.7" + debug: "npm:^4.3.4" + semver: "npm:^7.5.4" + superstruct: "npm:^1.0.3" + checksum: 00400538ce635841ee97db6ad27ef9bb1e71a047899aa748789da9cbb21926eac37a91d366fbfaf1d3138b7a8d4bb2b5c23edf532f7896af3e377429d9ae577e + languageName: node + linkType: hard + "@multiformats/base-x@npm:^4.0.1": version: 4.0.1 resolution: "@multiformats/base-x@npm:4.0.1" @@ -24221,6 +24394,7 @@ __metadata: "@metamask/gas-fee-controller": "npm:^6.0.1" "@metamask/jazzicon": "npm:^2.0.0" "@metamask/key-tree": "npm:^9.0.0" + "@metamask/keyring-api": "npm:^0.2.1" "@metamask/keyring-controller": "npm:^7.2.0" "@metamask/logo": "npm:^3.1.1" "@metamask/message-manager": "npm:^7.3.0" From ee67d513909f90ebdd0847e22ecf03955db79c9c Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Sat, 2 Sep 2023 22:25:44 +0800 Subject: [PATCH 079/235] fix: set correct selectedAddress in computeEstimatedGasLimit and initializeSendState --- ui/ducks/send/send.js | 6 ++++-- .../send-content/send-asset-row/send-asset-row.component.js | 2 +- ui/store/actions.ts | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ui/ducks/send/send.js b/ui/ducks/send/send.js index a685244920f8..1c6c459a8bbc 100644 --- a/ui/ducks/send/send.js +++ b/ui/ducks/send/send.js @@ -504,6 +504,7 @@ export const computeEstimatedGasLimit = createAsyncThunk( const transaction = unapprovedTxs[draftTransaction.id]; const isNonStandardEthChain = getIsNonStandardEthChain(state); const chainId = getCurrentChainId(state); + const selectedAccount = getSelectedInternalAccount(state); let gasTotalForLayer1; if (isMultiLayerFeeNetwork) { @@ -531,7 +532,7 @@ export const computeEstimatedGasLimit = createAsyncThunk( const gasLimit = await estimateGasLimitForSend({ gasPrice: draftTransaction.gas.gasPrice, blockGasLimit: metamask.currentBlockGasLimit, - selectedAddress: metamask.selectedAddress, + selectedAddress: selectedAccount.address, sendToken: draftTransaction.asset.details, to: draftTransaction.recipient.address?.toLowerCase(), value: draftTransaction.amount.value, @@ -667,7 +668,8 @@ export const initializeSendState = createAsyncThunk( blockGasLimit: metamask.currentBlockGasLimit, selectedAddress: draftTransaction.fromAccount?.address ?? - sendState.selectedAccount.address, + sendState.selectedAccount.address ?? + account.address, sendToken: draftTransaction.asset.details, to: draftTransaction.recipient.address.toLowerCase(), value: draftTransaction.amount.value, diff --git a/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js b/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js index dfcd421338b7..e0c69ea17809 100644 --- a/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js +++ b/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js @@ -28,10 +28,10 @@ export default class SendAssetRow extends Component { accounts: PropTypes.object.isRequired, selectedAccount: PropTypes.shape({ id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, address: PropTypes.string.isRequired, balance: PropTypes.string.isRequired, metadata: PropTypes.shape({ + name: PropTypes.string.isRequired, snap: PropTypes.shape({ id: PropTypes.string.isRequired, name: PropTypes.string, diff --git a/ui/store/actions.ts b/ui/store/actions.ts index dee4877c2c20..88d1af2cbc4c 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -3912,7 +3912,7 @@ export function getNextNonce(): ThunkAction< AnyAction > { return async (dispatch, getState) => { - const address = getState().metamask.selectedAddress; + const { address } = getSelectedInternalAccount(getState()); let nextNonce; try { nextNonce = await submitRequestToBackground('getNextNonce', [ From b6d019e878da6353989fe3bc19f5e663df0fc70f Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Sat, 2 Sep 2023 23:31:30 +0800 Subject: [PATCH 080/235] fix: restore missing e2e test --- test/e2e/tests/edit-gas-fee.spec.js | 270 ++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 test/e2e/tests/edit-gas-fee.spec.js diff --git a/test/e2e/tests/edit-gas-fee.spec.js b/test/e2e/tests/edit-gas-fee.spec.js new file mode 100644 index 000000000000..965ffaec7054 --- /dev/null +++ b/test/e2e/tests/edit-gas-fee.spec.js @@ -0,0 +1,270 @@ +const { strict: assert } = require('assert'); +const { + convertToHexValue, + getWindowHandles, + withFixtures, + openDapp, +} = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); + +describe('Editing Confirm Transaction', function () { + it('allows selecting high, medium, low gas estimates on edit gas fee popover', async function () { + const ganacheOptions = { + hardfork: 'london', + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: convertToHexValue(25000000000000000000), + }, + ], + }; + await withFixtures( + { + fixtures: new FixtureBuilder() + .withTransactionControllerTypeTwoTransaction() + .build(), + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + const transactionAmounts = await driver.findElements( + '.currency-display-component__text', + ); + const transactionAmount = transactionAmounts[0]; + assert.equal(await transactionAmount.getText(), '1'); + + // update estimates to high + await driver.clickElement('[data-testid="edit-gas-fee-button"]'); + await driver.waitForSelector({ + text: 'sec', + tag: 'span', + }); + await driver.clickElement( + '[data-testid="edit-gas-fee-item-high"] > span:first-child', + ); + await driver.waitForSelector({ text: '🦍' }); + await driver.waitForSelector({ + text: 'Aggressive', + }); + + // update estimates to medium + await driver.clickElement('[data-testid="edit-gas-fee-button"]'); + await driver.clickElement( + '[data-testid="edit-gas-fee-item-medium"] > span:first-child', + ); + await driver.waitForSelector({ text: '🦊' }); + await driver.waitForSelector({ + text: 'Market', + }); + + // update estimates to low + await driver.clickElement('[data-testid="edit-gas-fee-button"]'); + await driver.clickElement( + '[data-testid="edit-gas-fee-item-low"] > span:first-child', + ); + await driver.waitForSelector({ text: '🐢' }); + await driver.waitForSelector({ + text: 'Low', + }); + await driver.waitForSelector('[data-testid="low-gas-fee-alert"]'); + + // confirms the transaction + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + + await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.wait(async () => { + const confirmedTxes = await driver.findElements( + '.transaction-list__completed-transactions .activity-list-item', + ); + return confirmedTxes.length === 1; + }, 10000); + + const txValues = await driver.findElements( + '[data-testid="transaction-list-item-primary-currency"]', + ); + assert.equal(txValues.length, 1); + assert.ok(/-1\s*ETH/u.test(await txValues[0].getText())); + }, + ); + }); + + it('allows accessing advance gas fee popover from edit gas fee popover', async function () { + const ganacheOptions = { + hardfork: 'london', + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: convertToHexValue(25000000000000000000), + }, + ], + }; + await withFixtures( + { + fixtures: new FixtureBuilder() + .withTransactionControllerTypeTwoTransaction() + .build(), + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + const transactionAmounts = await driver.findElements( + '.currency-display-component__text', + ); + const transactionAmount = transactionAmounts[0]; + assert.equal(await transactionAmount.getText(), '1'); + + // update estimates to high + await driver.clickElement('[data-testid="edit-gas-fee-button"]'); + await driver.waitForSelector({ + text: 'sec', + tag: 'span', + }); + await driver.clickElement('[data-testid="edit-gas-fee-item-custom"]'); + + // enter max fee + await driver.fill('[data-testid="base-fee-input"]', '8.5'); + + // enter priority fee + await driver.fill('[data-testid="priority-fee-input"]', '8.5'); + + // save default values + await driver.clickElement('input[type="checkbox"]'); + + // edit gas limit + await driver.clickElement('[data-testid="advanced-gas-fee-edit"]'); + await driver.fill('[data-testid="gas-limit-input"]', '100000'); + + // Submit gas fee changes + await driver.clickElement({ text: 'Save', tag: 'button' }); + + // has correct updated value on the confirm screen the transaction + await driver.waitForSelector({ + css: '.transaction-detail-item:nth-of-type(1) h6:nth-of-type(2)', + text: '0.00085 ETH', + }); + await driver.waitForSelector({ + css: '.transaction-detail-item:nth-of-type(2) h6:nth-of-type(2)', + text: '1.00085 ETH', + }); + + // confirms the transaction + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + + await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.wait(async () => { + const confirmedTxes = await driver.findElements( + '.transaction-list__completed-transactions .activity-list-item', + ); + return confirmedTxes.length === 1; + }, 10000); + + const txValues = await driver.findElements( + '[data-testid="transaction-list-item-primary-currency"]', + ); + assert.equal(txValues.length, 1); + assert.ok(/-1\s*ETH/u.test(await txValues[0].getText())); + }, + ); + }); + + it('should use dapp suggested estimates for transaction coming from dapp', async function () { + const ganacheOptions = { + hardfork: 'london', + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: convertToHexValue(25000000000000000000), + }, + ], + }; + await withFixtures( + { + fixtures: new FixtureBuilder() + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + title: this.test.title, + dapp: true, + }, + async ({ driver }) => { + await driver.navigate(); + + // login to extension + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // open dapp and connect + await openDapp(driver); + await driver.clickElement({ + text: 'Send EIP 1559 Transaction', + tag: 'button', + }); + + // check transaction in extension popup + const windowHandles = await getWindowHandles(driver, 3); + await driver.switchToWindow(windowHandles.popup); + await driver.waitForSelector({ text: '🌐' }); + await driver.waitForSelector({ + text: 'Site suggested', + }); + + await driver.clickElement('[data-testid="edit-gas-fee-button"]'); + await driver.waitForSelector({ + text: 'sec', + tag: 'span', + }); + await driver.clickElement( + '[data-testid="edit-gas-fee-item-dappSuggested"]', + ); + + const transactionAmounts = await driver.findElements( + '.currency-display-component__text', + ); + const transactionAmount = transactionAmounts[0]; + assert.equal(await transactionAmount.getText(), '0'); + + // has correct updated value on the confirm screen the transaction + const editedTransactionAmounts = await driver.findElements( + '.transaction-detail-item__row .transaction-detail-item__detail-values .currency-display-component__text:last-of-type', + ); + const editedTransactionAmount = editedTransactionAmounts[0]; + assert.equal(await editedTransactionAmount.getText(), '0.00021'); + + const editedTransactionFee = editedTransactionAmounts[1]; + assert.equal(await editedTransactionFee.getText(), '0.00021'); + + // confirms the transaction + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + + // transaction should correct values in activity tab + await driver.switchToWindow(windowHandles.extension); + await driver.clickElement('[data-testid="home__activity-tab"]'); + await driver.wait(async () => { + const confirmedTxes = await driver.findElements( + '.transaction-list__completed-transactions .activity-list-item', + ); + return confirmedTxes.length === 1; + }, 10000); + + const txValues = await driver.findElements( + '[data-testid="transaction-list-item-primary-currency"]', + ); + assert.equal(txValues.length, 1); + assert.ok(/-0\s*ETH/u.test(await txValues[0].getText())); + }, + ); + }); +}); From 64814577f63eaa0e934f081557f2a6558d6fe329 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Sat, 2 Sep 2023 23:47:11 +0800 Subject: [PATCH 081/235] fix: return empty if snapKeyring is not initialised --- app/scripts/controllers/accounts-controller.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index b0721b14f2b0..5139c166323c 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -353,6 +353,10 @@ export class AccountsController extends BaseControllerV2< const [snapKeyring] = this.getKeyringByType(SnapKeyring.type); const snapAccounts = await (snapKeyring as SnapKeyring).listAccounts(false); + // snap keyring is not available until the first account is created in the keyring controller + if (!snapKeyring) { + return []; + } for (const account of snapAccounts) { // The snap account is guaranteed to have a snap metadata From bc04e161af0dea1a66aadd63660fbdcaa9428062 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Sat, 2 Sep 2023 23:47:28 +0800 Subject: [PATCH 082/235] fix: missing accountsController arg in account-tracker test --- app/scripts/lib/account-tracker.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/scripts/lib/account-tracker.test.js b/app/scripts/lib/account-tracker.test.js index d57822786eda..6ef46b357cb9 100644 --- a/app/scripts/lib/account-tracker.test.js +++ b/app/scripts/lib/account-tracker.test.js @@ -195,6 +195,8 @@ describe('Account Tracker', () => { getState: noop, }, }, + controllerMessenger, + accountsController, onAccountRemoved, }); accountRemovedListener(VALID_ADDRESS); From 3ef16e7e690adf6cc66a16ff036926d4c902158d Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Sun, 3 Sep 2023 00:20:01 +0800 Subject: [PATCH 083/235] fix: confirm-remove-account and confirm-encryption-public-key stories, lint and dedupe deps --- .../controllers/accounts-controller.ts | 2 +- .../confirm-remove-account.stories.js | 20 ++++++++- .../confirm-encryption-public-key.stories.js | 2 +- yarn.lock | 43 +------------------ 4 files changed, 23 insertions(+), 44 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index 5139c166323c..03339f5e01b7 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -135,7 +135,7 @@ export class AccountsController extends BaseControllerV2< accounts.forEach((account) => { const currentAccount = currentState.internalAccounts.accounts[account.id]; - if (currentAccount && currentAccount.metadata.snap) { + if (currentAccount?.metadata?.snap) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this account is guaranteed to have snap metadata currentState.internalAccounts.accounts[ diff --git a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.stories.js b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.stories.js index 6d2610b0103a..a7e03634c45d 100644 --- a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.stories.js +++ b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.stories.js @@ -12,7 +12,25 @@ export default { }, args: { account: { - control: 'object', + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + name: 'Test Account', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [ + 'personal_sign', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', }, }, }; diff --git a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.stories.js b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.stories.js index d0ec8f1469f7..c85f904c80ca 100644 --- a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.stories.js +++ b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.stories.js @@ -65,7 +65,7 @@ export default { }, }, args: { - fromAccount: metamask.accountArray[0], + fromAccount: Object.values(metamask.internalAccounts.accounts)[0], history: { push: action('history.push()'), }, diff --git a/yarn.lock b/yarn.lock index 142687d3a0a8..ec1bc8a225d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4493,27 +4493,7 @@ __metadata: languageName: node linkType: hard -"@metamask/permission-controller@npm:^4.0.0": - version: 4.0.0 - resolution: "@metamask/permission-controller@npm:4.0.0" - dependencies: - "@metamask/approval-controller": "npm:^3.0.0" - "@metamask/base-controller": "npm:^3.0.0" - "@metamask/controller-utils": "npm:^4.0.0" - "@metamask/utils": "npm:^5.0.2" - "@types/deep-freeze-strict": "npm:^1.1.0" - deep-freeze-strict: "npm:^1.1.1" - eth-rpc-errors: "npm:^4.0.2" - immer: "npm:^9.0.6" - json-rpc-engine: "npm:^6.1.0" - nanoid: "npm:^3.1.31" - peerDependencies: - "@metamask/approval-controller": ^3.0.0 - checksum: bbb915e144983d7f891858bf248a7338f5ec1076c552cb1e2485d9bba12ce69d59f52dfc6e2033c37d8111b8866334f1dfed51cfe243088d3d61661e14bb3cc8 - languageName: node - linkType: hard - -"@metamask/permission-controller@npm:^4.1.0": +"@metamask/permission-controller@npm:^4.0.0, @metamask/permission-controller@npm:^4.1.0": version: 4.1.1 resolution: "@metamask/permission-controller@npm:4.1.1" dependencies: @@ -4616,26 +4596,7 @@ __metadata: languageName: node linkType: hard -"@metamask/providers@npm:^11.0.0, @metamask/providers@npm:^11.1.0": - version: 11.1.0 - resolution: "@metamask/providers@npm:11.1.0" - dependencies: - "@metamask/object-multiplex": "npm:^1.1.0" - "@metamask/safe-event-emitter": "npm:^3.0.0" - detect-browser: "npm:^5.2.0" - eth-rpc-errors: "npm:^4.0.2" - extension-port-stream: "npm:^2.0.1" - fast-deep-equal: "npm:^2.0.1" - is-stream: "npm:^2.0.0" - json-rpc-engine: "npm:^6.1.0" - json-rpc-middleware-stream: "npm:^4.2.1" - pump: "npm:^3.0.0" - webextension-polyfill: "npm:^0.10.0" - checksum: e844e1e7b60a2b85fae973134852bd2d4de291daae1774a6f05fdc429e711ecea02710240b1b6dfe9656f712a4d9a356a6bc3f162d977f1878127a167b6a8fdf - languageName: node - linkType: hard - -"@metamask/providers@npm:^11.1.1": +"@metamask/providers@npm:^11.0.0, @metamask/providers@npm:^11.1.0, @metamask/providers@npm:^11.1.1": version: 11.1.1 resolution: "@metamask/providers@npm:11.1.1" dependencies: From 3f744d3202f0562ad517d3acf1930a689e1def91 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Sun, 3 Sep 2023 00:37:16 +0800 Subject: [PATCH 084/235] chore: policy.json update --- lavamoat/browserify/beta/policy.json | 15 ++++++++++++++- lavamoat/browserify/desktop/policy.json | 15 ++++++++++++++- lavamoat/browserify/flask/policy.json | 15 ++++++++++++++- lavamoat/browserify/main/policy.json | 15 ++++++++++++++- lavamoat/browserify/mmi/policy.json | 15 ++++++++++++++- 5 files changed, 70 insertions(+), 5 deletions(-) diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 4776e7155a61..7810da2602c8 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -1829,14 +1829,27 @@ "packages": { "@metamask/base-controller": true, "@metamask/controller-utils": true, + "@metamask/permission-controller>@metamask/utils": true, "@metamask/permission-controller>nanoid": true, - "@metamask/utils": true, "deep-freeze-strict": true, "eth-rpc-errors": true, "immer": true, "json-rpc-engine": true } }, + "@metamask/permission-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/permission-controller>nanoid": { "globals": { "crypto.getRandomValues": true diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index d2eece79d56a..fcaade2ffbb1 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -1930,14 +1930,27 @@ "packages": { "@metamask/base-controller": true, "@metamask/controller-utils": true, + "@metamask/permission-controller>@metamask/utils": true, "@metamask/permission-controller>nanoid": true, - "@metamask/utils": true, "deep-freeze-strict": true, "eth-rpc-errors": true, "immer": true, "json-rpc-engine": true } }, + "@metamask/permission-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/permission-controller>nanoid": { "globals": { "crypto.getRandomValues": true diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 76ff6d767a50..56698331a9ee 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -1930,14 +1930,27 @@ "packages": { "@metamask/base-controller": true, "@metamask/controller-utils": true, + "@metamask/permission-controller>@metamask/utils": true, "@metamask/permission-controller>nanoid": true, - "@metamask/utils": true, "deep-freeze-strict": true, "eth-rpc-errors": true, "immer": true, "json-rpc-engine": true } }, + "@metamask/permission-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/permission-controller>nanoid": { "globals": { "crypto.getRandomValues": true diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 33ed4bdffa80..3154d4b58911 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -1836,14 +1836,27 @@ "packages": { "@metamask/base-controller": true, "@metamask/controller-utils": true, + "@metamask/permission-controller>@metamask/utils": true, "@metamask/permission-controller>nanoid": true, - "@metamask/utils": true, "deep-freeze-strict": true, "eth-rpc-errors": true, "immer": true, "json-rpc-engine": true } }, + "@metamask/permission-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/permission-controller>nanoid": { "globals": { "crypto.getRandomValues": true diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 9f016fd6e4a4..72c85d078aad 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -1970,14 +1970,27 @@ "packages": { "@metamask/base-controller": true, "@metamask/controller-utils": true, + "@metamask/permission-controller>@metamask/utils": true, "@metamask/permission-controller>nanoid": true, - "@metamask/utils": true, "deep-freeze-strict": true, "eth-rpc-errors": true, "immer": true, "json-rpc-engine": true } }, + "@metamask/permission-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/permission-controller>nanoid": { "globals": { "crypto.getRandomValues": true From b219dfe7c160435f8cf38fe19b1b8e3789e17429 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Sun, 3 Sep 2023 00:48:55 +0800 Subject: [PATCH 085/235] fix: order of snap keyring --- app/scripts/controllers/accounts-controller.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts index 03339f5e01b7..25b9655bc95b 100644 --- a/app/scripts/controllers/accounts-controller.ts +++ b/app/scripts/controllers/accounts-controller.ts @@ -351,13 +351,13 @@ export class AccountsController extends BaseControllerV2< async #listSnapAccounts(): Promise { const [snapKeyring] = this.getKeyringByType(SnapKeyring.type); - - const snapAccounts = await (snapKeyring as SnapKeyring).listAccounts(false); // snap keyring is not available until the first account is created in the keyring controller if (!snapKeyring) { return []; } + const snapAccounts = await (snapKeyring as SnapKeyring).listAccounts(false); + for (const account of snapAccounts) { // The snap account is guaranteed to have a snap metadata // eslint-disable-next-line @typescript-eslint/no-non-null-assertion From cc0763856ad21e45b1d43e3099491b74765c6e46 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Mon, 4 Sep 2023 08:08:10 +0800 Subject: [PATCH 086/235] fix: update DetectTokensController to use getCurrentSelectedAccount than importing the entire AccountsController --- app/scripts/controllers/detect-tokens.js | 7 +++-- app/scripts/controllers/detect-tokens.test.js | 27 ++++++++++++------- app/scripts/metamask-controller.js | 5 +++- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/app/scripts/controllers/detect-tokens.js b/app/scripts/controllers/detect-tokens.js index 24f68d55e95a..73a7e5ae3662 100644 --- a/app/scripts/controllers/detect-tokens.js +++ b/app/scripts/controllers/detect-tokens.js @@ -35,7 +35,7 @@ export default class DetectTokensController { * @param config.trackMetaMetricsEvent * @param config.messenger * @param config.controllerMessenger - * @param config.accountsController + * @param config.getCurrentSelectedAccount */ constructor({ messenger, @@ -48,7 +48,7 @@ export default class DetectTokensController { assetsContractController = null, trackMetaMetricsEvent, controllerMessenger, - accountsController, + getCurrentSelectedAccount, } = {}) { this.messenger = messenger; this.assetsContractController = assetsContractController; @@ -60,8 +60,7 @@ export default class DetectTokensController { this.tokenList = tokenList; this.useTokenDetection = this.preferences?.store.getState().useTokenDetection; - this.accountsController = accountsController; - this.selectedAddress = this.accountsController.getSelectedAccount().address; + this.selectedAddress = getCurrentSelectedAccount().address; this.tokenAddresses = this.tokensController?.state.tokens.map((token) => { return token.address; }); diff --git a/app/scripts/controllers/detect-tokens.test.js b/app/scripts/controllers/detect-tokens.test.js index 9400f8e6330c..31ff86a68b8c 100644 --- a/app/scripts/controllers/detect-tokens.test.js +++ b/app/scripts/controllers/detect-tokens.test.js @@ -341,7 +341,8 @@ describe('DetectTokensController', function () { new DetectTokensController({ messenger: buildMessenger(), interval: 1337, - accountsController, + getCurrentSelectedAccount: + accountsController.getSelectedAccount.bind(accountsController), controllerMessenger, }); assert.strictEqual(stub.getCall(0).args[1], 1337); @@ -359,7 +360,8 @@ describe('DetectTokensController', function () { tokenList: tokenListController, tokensController, assetsContractController, - accountsController, + getCurrentSelectedAccount: + accountsController.getSelectedAccount.bind(accountsController), controllerMessenger, }); controller.isOpen = true; @@ -398,7 +400,8 @@ describe('DetectTokensController', function () { tokenList: tokenListController, tokensController, assetsContractController, - accountsController, + getCurrentSelectedAccount: + accountsController.getSelectedAccount.bind(accountsController), controllerMessenger, }); controller.isOpen = true; @@ -425,7 +428,8 @@ describe('DetectTokensController', function () { tokensController, assetsContractController, trackMetaMetricsEvent: noop, - accountsController, + getCurrentSelectedAccount: + accountsController.getSelectedAccount.bind(accountsController), controllerMessenger, }); controller.isOpen = true; @@ -479,7 +483,8 @@ describe('DetectTokensController', function () { tokensController, assetsContractController, trackMetaMetricsEvent: noop, - accountsController, + getCurrentSelectedAccount: + accountsController.getSelectedAccount.bind(accountsController), controllerMessenger, }); controller.isOpen = true; @@ -549,7 +554,8 @@ describe('DetectTokensController', function () { tokenList: tokenListController, tokensController, assetsContractController, - accountsController, + getCurrentSelectedAccount: + accountsController.getSelectedAccount.bind(accountsController), controllerMessenger, }); controller.isOpen = true; @@ -571,7 +577,8 @@ describe('DetectTokensController', function () { tokenList: tokenListController, tokensController, assetsContractController, - accountsController, + getCurrentSelectedAccount: + accountsController.getSelectedAccount.bind(accountsController), controllerMessenger, }); controller.isOpen = true; @@ -592,7 +599,8 @@ describe('DetectTokensController', function () { tokenList: tokenListController, tokensController, assetsContractController, - accountsController, + getCurrentSelectedAccount: + accountsController.getSelectedAccount.bind(accountsController), controllerMessenger, }); controller.isOpen = true; @@ -615,7 +623,8 @@ describe('DetectTokensController', function () { keyringMemStore, tokensController, assetsContractController, - accountsController, + getCurrentSelectedAccount: + accountsController.getSelectedAccount.bind(accountsController), controllerMessenger, }); // trigger state update from preferences controller diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 5e4f4dbc5339..8d335674da3e 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1176,7 +1176,10 @@ export default class MetamaskController extends EventEmitter { messenger: detectTokensControllerMessenger, preferences: this.preferencesController, tokensController: this.tokensController, - accountsController: this.accountsController, + getCurrentSelectedAccount: + this.accountsController.getSelectedAccount.bind( + this.accountsController, + ), controllerMessenger: this.controllerMessenger, assetsContractController: this.assetsContractController, network: this.networkController, From 5b0116b0023b1ca1975f55b222ed47b0c02f0c47 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Mon, 4 Sep 2023 08:08:46 +0800 Subject: [PATCH 087/235] fix: update AlertController to use getCurrentSelectedAccount than importing the entire AccountsController --- app/scripts/controllers/alert.js | 8 ++++++-- app/scripts/metamask-controller.js | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/scripts/controllers/alert.js b/app/scripts/controllers/alert.js index e27861883804..ffc87db6408e 100644 --- a/app/scripts/controllers/alert.js +++ b/app/scripts/controllers/alert.js @@ -38,7 +38,11 @@ export default class AlertController { * @param {AlertControllerOptions} [opts] - Controller configuration parameters */ constructor(opts = {}) { - const { initState = {}, accountsController, controllerMessenger } = opts; + const { + initState = {}, + getCurrentSelectedAccount, + controllerMessenger, + } = opts; const state = { ...defaultState, alertEnabledness: { @@ -49,7 +53,7 @@ export default class AlertController { this.store = new ObservableStore(state); - this.selectedAddress = accountsController.getSelectedAccount().address; + this.selectedAddress = getCurrentSelectedAccount().address; this.controllerMessenger = controllerMessenger; diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 8d335674da3e..017d003d2f4e 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1198,7 +1198,10 @@ export default class MetamaskController extends EventEmitter { this.alertController = new AlertController({ initState: initState.AlertController, controllerMessenger: this.controllerMessenger, - accountsController: this.accountsController, + getCurrentSelectedAccount: + this.accountsController.getSelectedAccount.bind( + this.accountsController, + ), }); ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) From 6fee8e50b2e3d6af0cfb3fffb551a61504b66c58 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Tue, 5 Sep 2023 12:26:04 +0800 Subject: [PATCH 088/235] fix: update snapshot --- .../state-snapshots/errors-after-init-opt-in-ui-state.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json index ea07f0a3458a..562f9ca1227f 100644 --- a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json +++ b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json @@ -13,7 +13,7 @@ "isAccountMenuOpen": false, "isNetworkMenuOpen": false, "internalAccounts": { "accounts": {}, "selectedAccount": "" }, - "unapprovedTxs": "object", + "transactions": "object", "networkConfigurations": "object", "addressBook": "object", "contractExchangeRates": "object", @@ -153,7 +153,6 @@ "lastUpdated": "object", "notifications": "object", "accounts": "object", - "transactions": "object", "unapprovedDecryptMsgs": "object", "unapprovedDecryptMsgCount": 0, "unapprovedEncryptionPublicKeyMsgs": "object", From b0dd2bf8f4bbefe0a93712d3f9e9cd65a995e181 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Tue, 5 Sep 2023 16:50:26 +0800 Subject: [PATCH 089/235] fix: mmi to use accounts controller --- app/scripts/controllers/mmi-controller.js | 94 ++++++----- .../controllers/mmi-controller.test.js | 149 +++++++++++++++++- app/scripts/metamask-controller.js | 2 + 3 files changed, 205 insertions(+), 40 deletions(-) diff --git a/app/scripts/controllers/mmi-controller.js b/app/scripts/controllers/mmi-controller.js index 355d4ad27352..dff61294db1b 100644 --- a/app/scripts/controllers/mmi-controller.js +++ b/app/scripts/controllers/mmi-controller.js @@ -1,7 +1,6 @@ import EventEmitter from 'events'; import log from 'loglevel'; import { captureException } from '@sentry/browser'; -import { isEqual } from 'lodash'; import { CUSTODIAN_TYPES } from '@metamask-institutional/custody-keyring'; import { updateCustodianTransactions, @@ -21,7 +20,6 @@ import { BUILD_QUOTE_ROUTE, CONNECT_HARDWARE_ROUTE, } from '../../../ui/helpers/constants/routes'; -import { previousValueComparator } from '../lib/util'; import { getPermissionBackgroundApiMethods } from './permissions'; export default class MMIController extends EventEmitter { @@ -33,7 +31,6 @@ export default class MMIController extends EventEmitter { this.keyringController = opts.keyringController; this.txController = opts.txController; this.securityProviderRequest = opts.securityProviderRequest; - this.preferencesController = opts.preferencesController; this.appStateController = opts.appStateController; this.transactionUpdateController = opts.transactionUpdateController; this.custodyController = opts.custodyController; @@ -47,6 +44,8 @@ export default class MMIController extends EventEmitter { this.signatureController = opts.signatureController; this.platform = opts.platform; this.extension = opts.extension; + this.accountsController = opts.accountsController; + this.controllerMessenger = opts.controllerMessenger; // Prepare event listener after transactionUpdateController gets initiated this.transactionUpdateController.prepareEventListener( @@ -63,15 +62,12 @@ export default class MMIController extends EventEmitter { }); } - this.preferencesController.store.subscribe( - previousValueComparator(async (prevState, currState) => { - const { identities: prevIdentities } = prevState; - const { identities: currIdentities } = currState; - if (isEqual(prevIdentities, currIdentities)) { - return; - } + this.controllerMessenger.subscribe( + 'AccountsController:stateChange', + async (_newState, _changes) => { + // Changes of selected account, name changes, account additions and deletions will trigger a rerun await this.prepareMmiPortfolio(); - }, this.preferencesController.store.getState()), + }, ); this.signatureController.hub.on( @@ -240,10 +236,14 @@ export default class MMIController extends EventEmitter { const newAccounts = Object.keys(accounts); // Check if any address is already added - const identities = Object.keys( - this.preferencesController.store.getState().identities, - ); - if (newAccounts.some((address) => identities.indexOf(address) !== -1)) { + const existingInternalAccounts = this.accountsController.listAccounts(); + if ( + newAccounts.some((address) => + existingInternalAccounts.find( + (internalAccount) => internalAccount.address.toLowerCase === address, + ), + ) + ) { throw new Error('Cannot import duplicate accounts'); } @@ -296,11 +296,16 @@ export default class MMIController extends EventEmitter { await this.keyringController.addNewAccount(keyring); } - const allAccounts = await this.keyringController.getAccounts(); + const allInternalAccounts = await this.accountsController.listAccounts(); - this.preferencesController.setAddresses(allAccounts); const accountsToTrack = [ - ...new Set(oldAccounts.concat(allAccounts.map((a) => a.toLowerCase()))), + ...new Set( + oldAccounts.concat( + allInternalAccounts.map((internalAccount) => + internalAccount.address.toLowerCase(), + ), + ), + ), ]; // Create a Set of lowercased addresses from oldAccounts for efficient existence checks @@ -315,10 +320,10 @@ export default class MMIController extends EventEmitter { return acc; }, {}); - // Iterate over all accounts - allAccounts.forEach((address) => { + // Iterate over all internal accounts + allInternalAccounts.forEach((internalAccount) => { // Convert the address to lowercase for consistent comparisons - const lowercasedAddress = address.toLowerCase(); + const lowercasedAddress = internalAccount.address.toLowerCase(); // If the address is not in oldAccounts if (!oldAccountsSet.has(lowercasedAddress)) { @@ -328,7 +333,7 @@ export default class MMIController extends EventEmitter { // If the label is defined if (label) { // Set the label for the address - this.preferencesController.setAccountLabel(address, label); + this.accountsController.setAccountName(internalAccount.id, label); } } }); @@ -373,7 +378,7 @@ export default class MMIController extends EventEmitter { ) { let currentCustodyType; if (!custodianType) { - const address = this.preferencesController.getSelectedAddress(); + const address = this.accountsController.getSelectedAccount(); currentCustodyType = this.custodyController.getCustodyTypeByAddress( toChecksumHexAddress(address), ); @@ -464,12 +469,12 @@ export default class MMIController extends EventEmitter { async getCustodianJWTList(custodianName) { console.log('getCustodianJWTList', custodianName); - const { identities } = this.preferencesController.store.getState(); + const internalAccounts = this.accountsController.listAccounts(); const { mmiConfiguration } = this.mmiConfigurationController.store.getState(); - const addresses = Object.keys(identities); + const addresses = internalAccounts.map((account) => account.address); const tokenList = []; const { custodians } = mmiConfiguration; @@ -558,7 +563,15 @@ export default class MMIController extends EventEmitter { async handleMmiDashboardData() { await this.appStateController.getUnlockPromise(true); const keyringAccounts = await this.keyringController.getAccounts(); - const { identities } = this.preferencesController.store.getState(); + const internalAccounts = this.accountsController.listAccounts(); + // TODO: update handleMmiPortfolio to use internalAccounts + const identities = internalAccounts.map((internalAccount) => { + return { + address: internalAccount.address, + name: internalAccount.metadata.name, + }; + }); + const { metaMetricsId } = this.metaMetricsController.store.getState(); const getAccountDetails = (address) => this.custodyController.getAccountDetails(address); @@ -585,16 +598,14 @@ export default class MMIController extends EventEmitter { } async prepareMmiPortfolio() { - if (!process.env.IN_TEST) { - try { - const mmiDashboardData = await this.handleMmiDashboardData(); - const cookieSetUrls = - this.mmiConfigurationController.store.mmiConfiguration?.portfolio - ?.cookieSetUrls || []; - setDashboardCookie(mmiDashboardData, cookieSetUrls); - } catch (error) { - console.error(error); - } + try { + const mmiDashboardData = await this.handleMmiDashboardData(); + const cookieSetUrls = + this.mmiConfigurationController.store.mmiConfiguration?.portfolio + ?.cookieSetUrls || []; + setDashboardCookie(mmiDashboardData, cookieSetUrls); + } catch (error) { + console.error(error); } } @@ -641,10 +652,17 @@ export default class MMIController extends EventEmitter { async setAccountAndNetwork(origin, address, chainId) { await this.appStateController.getUnlockPromise(true); + console.log(address); const addressToLowerCase = address.toLowerCase(); - const selectedAddress = this.preferencesController.getSelectedAddress(); + const { address: selectedAddress } = + this.accountsController.getSelectedAccount(); if (selectedAddress.toLowerCase() !== addressToLowerCase) { - this.preferencesController.setSelectedAddress(addressToLowerCase); + const internalAccounts = this.accountsController.listAccounts(); + const newAccount = internalAccounts.find( + (internalAccount) => + internalAccount.address.toLowerCase() === addressToLowerCase, + ); + this.accountsController.setSelectedAccount(newAccount.id); } const selectedChainId = parseInt( this.networkController.state.providerConfig.chainId, diff --git a/app/scripts/controllers/mmi-controller.test.js b/app/scripts/controllers/mmi-controller.test.js index e4b26dd62f5b..7e15ceffcc6d 100644 --- a/app/scripts/controllers/mmi-controller.test.js +++ b/app/scripts/controllers/mmi-controller.test.js @@ -3,20 +3,123 @@ import { KeyringController } from '@metamask/eth-keyring-controller'; import { MmiConfigurationController } from '@metamask-institutional/custody-keyring'; import { TransactionUpdateController } from '@metamask-institutional/transaction-update'; import { SignatureController } from '@metamask/signature-controller'; +import { NetworkController } from '@metamask/network-controller'; import MMIController from './mmi-controller'; import TransactionController from './transactions'; import PreferencesController from './preferences'; import AppStateController from './app-state'; +import { AccountsController } from './accounts-controller'; +import { ControllerMessenger } from '@metamask/base-controller'; + +jest.mock('./permissions', () => ({ + getPermissionBackgroundApiMethods: () => ({ + addPermittedAccount: jest.fn().mockReturnValue(), + }), +})); + +const mockMetaMetrics = { + store: { + getState: jest.fn().mockReturnValue({ metaMetricsId: 'mock-metrics-id' }), + }, +}; +const mockExtension = { + runtime: { + id: 'mock-runtime-id', + }, +}; + +const mockAccount = { + address: '0x1', + id: 'mock-id', + metadata: { + name: 'Test Account', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [ + 'personal_sign', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', +}; +const mockAccount2 = { + address: '0x2', + id: 'mock-id-2', + metadata: { + name: 'Test Account 2', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [ + 'personal_sign', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', +}; describe('MMIController', function () { let mmiController; + let controllerMessenger; + let accountsController; + let networkController; beforeEach(function () { + controllerMessenger = new ControllerMessenger(); + accountsController = new AccountsController({ + state: { + internalAccounts: { + accounts: { + 'mock-id': mockAccount, + 'mock-id-2': mockAccount2, + }, + selectedAccount: mockAccount.id, + }, + }, + messenger: controllerMessenger.getRestricted({ + name: 'AccountsController', + }), + onKeyringStateChange: jest.fn(), + getKeyringForAccount: jest.fn(), + getKeyringByType: jest.fn(), + getAccounts: jest.fn(), + onSnapStateChange: jest.fn(), + onKeyringStateChange: jest.fn(), + }); + networkController = new NetworkController({ + messenger: controllerMessenger.getRestricted({ + name: 'NetworkController', + }), + state: {}, + infuraProjectId: 'mockInfuraProjectId', + trackMetaMetricsEvent: jest.fn(), + }); + mmiController = new MMIController({ mmiConfigurationController: new MmiConfigurationController(), keyringController: new KeyringController({ - initState: {}, + initState: { + keyrings: [ + { + type: 'HD Key Tree', + accounts: ['0x1', '0x2'], + }, + ], + }, }), transactionUpdateController: new TransactionUpdateController({ getCustodyKeyring: jest.fn(), @@ -33,6 +136,9 @@ describe('MMIController', function () { getCurrentChainId: jest.fn(), getNetworkId: jest.fn(), onNetworkStateChange: jest.fn(), + blockTracker: { + getLatestBlock: jest.fn().mockResolvedValue({}), + }, }), signatureController: new SignatureController({ messenger: { @@ -80,6 +186,11 @@ describe('MMIController', function () { }, }), custodianEventHandlerFactory: jest.fn(), + accountsController, + controllerMessenger, + networkController, + metaMetricsController: mockMetaMetrics, + extension: mockExtension, }); }); @@ -91,8 +202,9 @@ describe('MMIController', function () { it('should have all required properties', function () { expect(mmiController.opts).toBeDefined(); expect(mmiController.mmiConfigurationController).toBeDefined(); - expect(mmiController.preferencesController).toBeDefined(); expect(mmiController.transactionUpdateController).toBeDefined(); + expect(mmiController.accountsController).toBeDefined(); + expect(mmiController.controllerMessenger).toBeDefined(); }); }); @@ -143,4 +255,37 @@ describe('MMIController', function () { ); }); }); + + describe('AccountsController:stateChange event', function () { + it('should call prepareMmiPortfolio', async () => { + mmiController.txController._trackTransactionMetricsEvent = jest.fn(); + jest.spyOn(mmiController, 'prepareMmiPortfolio'); + await controllerMessenger.publish('AccountsController:stateChange', []); + + expect(mmiController.prepareMmiPortfolio).toHaveBeenCalled(); + }); + }); + + describe('setAccountAndNetwork', function () { + it('should set a new selected account if the selectedAddress and the address from the arguments is different', async () => { + mmiController.txController._trackTransactionMetricsEvent = jest.fn(); + await mmiController.setAccountAndNetwork( + 'mock-origin', + mockAccount2.address, + '0x1', + ); + const selectedAccount = accountsController.getSelectedAccount(); + expect(selectedAccount.id).toBe(mockAccount2.id); + }); + + it('should set a new selected account the accounts are the same', async () => { + await mmiController.setAccountAndNetwork( + 'mock-origin', + mockAccount.address, + '0x1', + ); + const selectedAccount = accountsController.getSelectedAccount(); + expect(selectedAccount.id).toBe(mockAccount.id); + }); + }); }); diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 017d003d2f4e..698ace0c9472 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1492,6 +1492,8 @@ export default class MetamaskController extends EventEmitter { networkController: this.networkController, permissionController: this.permissionController, signatureController: this.signatureController, + accountsController: this.accountsController, + controllerMessenger: this.controllerMessenger, platform: this.platform, extension: this.extension, }); From d0b693de120c8929a7408e904f5e8fb51c586e39 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Wed, 6 Sep 2023 09:06:50 +0800 Subject: [PATCH 090/235] feat: use eth-snap-keyring 0.2.0 --- package.json | 2 +- yarn.lock | 151 ++++++++------------------------------------------- 2 files changed, 23 insertions(+), 130 deletions(-) diff --git a/package.json b/package.json index ba25b6a5cfb5..7e1b9fdedbef 100644 --- a/package.json +++ b/package.json @@ -244,7 +244,7 @@ "@metamask/eth-json-rpc-middleware": "^11.0.0", "@metamask/eth-keyring-controller": "^10.0.1", "@metamask/eth-ledger-bridge-keyring": "^0.15.0", - "@metamask/eth-snap-keyring": "git+https://github.com/MetaMask/eth-snap-keyring.git#commit=543117c98e80c83378dbd8bb2bc87704ee0f96f0", + "@metamask/eth-snap-keyring": "^0.2.0", "@metamask/eth-token-tracker": "^4.0.0", "@metamask/eth-trezor-keyring": "^1.1.0", "@metamask/etherscan-link": "^2.2.0", diff --git a/yarn.lock b/yarn.lock index 88f58ed3d1a3..9cb175e2d6f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4151,19 +4151,19 @@ __metadata: languageName: node linkType: hard -"@metamask/eth-snap-keyring@git+https://github.com/MetaMask/eth-snap-keyring.git#commit=543117c98e80c83378dbd8bb2bc87704ee0f96f0": - version: 0.1.3 - resolution: "@metamask/eth-snap-keyring@https://github.com/MetaMask/eth-snap-keyring.git#commit=543117c98e80c83378dbd8bb2bc87704ee0f96f0" +"@metamask/eth-snap-keyring@npm:^0.2.0": + version: 0.2.0 + resolution: "@metamask/eth-snap-keyring@npm:0.2.0" dependencies: "@ethereumjs/tx": "npm:^4.1.2" "@metamask/eth-sig-util": "npm:^5.1.0" - "@metamask/keyring-api": "npm:^0.1.3" - "@metamask/snaps-controllers": "npm:^0.35.2-flask.1" - "@metamask/utils": "npm:^6.1.0" + "@metamask/keyring-api": "npm:^0.2.2" + "@metamask/snaps-controllers": "npm:^0.38.2-flask.1" + "@metamask/utils": "npm:^8.1.0" "@types/uuid": "npm:^9.0.1" superstruct: "npm:^1.0.3" uuid: "npm:^9.0.0" - checksum: 3215227629560912c4d8d097cb7a45116996022ecb60d816751be6e1d01ba7eb2d8de06eea670914003a9ff319107e99f820089e9b4cb7883df733799fcff560 + checksum: 986c607b72f3b1648613d71af959c9b94ffe5c27fb6a80f202015a76771331de971223eafc8c77567c148dbad2818a23c0f1a6541644ad5ebc8cc4e35b044553 languageName: node linkType: hard @@ -4270,24 +4270,25 @@ __metadata: languageName: node linkType: hard -"@metamask/keyring-api@npm:^0.1.3": - version: 0.1.3 - resolution: "@metamask/keyring-api@npm:0.1.3" +"@metamask/keyring-api@npm:^0.2.1": + version: 0.2.1 + resolution: "@metamask/keyring-api@npm:0.2.1" dependencies: "@metamask/providers": "npm:^11.0.0" - "@metamask/snaps-controllers": "npm:^0.35.2-flask.1" - "@metamask/snaps-utils": "npm:^0.35.2-flask.1" - "@metamask/utils": "npm:^6.0.1" + "@metamask/rpc-methods": "npm:^0.38.1-flask.1" + "@metamask/snaps-controllers": "npm:^0.38.2-flask.1" + "@metamask/snaps-utils": "npm:^0.38.2-flask.1" + "@metamask/utils": "npm:^8.0.0" "@types/uuid": "npm:^9.0.1" superstruct: "npm:^1.0.3" uuid: "npm:^9.0.0" - checksum: 96c3101482c795f910ebe8b7cd25cdb391d03e4fa46f2918afeb8125953eec0208b7ebddd43487f8ec4f3febecba3327624a5dc8c2a0a9571052d16fef75dfcd + checksum: 12ab6f6767f32bb75e6e6d134786e3feecb520df7e584b8eec3a0c8430dd8349bf9971707a2a61a00ac2efbe594d26adc68360f8dc291d4f0439fdbf513b2bc2 languageName: node linkType: hard -"@metamask/keyring-api@npm:^0.2.1": - version: 0.2.1 - resolution: "@metamask/keyring-api@npm:0.2.1" +"@metamask/keyring-api@npm:^0.2.2": + version: 0.2.2 + resolution: "@metamask/keyring-api@npm:0.2.2" dependencies: "@metamask/providers": "npm:^11.0.0" "@metamask/rpc-methods": "npm:^0.38.1-flask.1" @@ -4297,7 +4298,7 @@ __metadata: "@types/uuid": "npm:^9.0.1" superstruct: "npm:^1.0.3" uuid: "npm:^9.0.0" - checksum: 12ab6f6767f32bb75e6e6d134786e3feecb520df7e584b8eec3a0c8430dd8349bf9971707a2a61a00ac2efbe594d26adc68360f8dc291d4f0439fdbf513b2bc2 + checksum: c98d5228e89c710e31b792b94569316ab4afc94e472e485b7da7d3ef3b75b441e49784d9ac35dd8891242db5c21d2173f2c8ec58d1182d418563ff403b45fcc3 languageName: node linkType: hard @@ -4653,24 +4654,6 @@ __metadata: languageName: node linkType: hard -"@metamask/rpc-methods@npm:^0.35.2-flask.1": - version: 0.35.2-flask.1 - resolution: "@metamask/rpc-methods@npm:0.35.2-flask.1" - dependencies: - "@metamask/key-tree": "npm:^7.1.1" - "@metamask/permission-controller": "npm:^4.0.0" - "@metamask/snaps-ui": "npm:^0.35.2-flask.1" - "@metamask/snaps-utils": "npm:^0.35.2-flask.1" - "@metamask/types": "npm:^1.1.0" - "@metamask/utils": "npm:^6.0.1" - "@noble/hashes": "npm:^1.3.1" - eth-rpc-errors: "npm:^4.0.3" - nanoid: "npm:^3.1.31" - superstruct: "npm:^1.0.3" - checksum: c9d87bcefafb8dfbdaa1e11a1e41b089d6aa4e7ed14034ef482b64b448387e86188671cda314a11ae0b29ee8c9bb7459e43841d197c5e998d2209e383c686f1d - languageName: node - linkType: hard - "@metamask/rpc-methods@npm:^0.38.1-flask.1": version: 0.38.1-flask.1 resolution: "@metamask/rpc-methods@npm:0.38.1-flask.1" @@ -4823,36 +4806,6 @@ __metadata: languageName: node linkType: hard -"@metamask/snaps-controllers@npm:^0.35.2-flask.1": - version: 0.35.2-flask.1 - resolution: "@metamask/snaps-controllers@npm:0.35.2-flask.1" - dependencies: - "@metamask/approval-controller": "npm:^3.0.0" - "@metamask/base-controller": "npm:^3.0.0" - "@metamask/object-multiplex": "npm:^1.2.0" - "@metamask/permission-controller": "npm:^4.0.0" - "@metamask/post-message-stream": "npm:^6.1.2" - "@metamask/rpc-methods": "npm:^0.35.2-flask.1" - "@metamask/snaps-execution-environments": "npm:^0.35.2-flask.1" - "@metamask/snaps-registry": "npm:^1.2.1" - "@metamask/snaps-utils": "npm:^0.35.2-flask.1" - "@metamask/utils": "npm:^6.0.1" - "@xstate/fsm": "npm:^2.0.0" - concat-stream: "npm:^2.0.0" - cron-parser: "npm:^4.5.0" - eth-rpc-errors: "npm:^4.0.3" - gunzip-maybe: "npm:^1.4.2" - immer: "npm:^9.0.6" - json-rpc-engine: "npm:^6.1.0" - json-rpc-middleware-stream: "npm:^4.2.0" - nanoid: "npm:^3.1.31" - pump: "npm:^3.0.0" - readable-web-to-node-stream: "npm:^3.0.2" - tar-stream: "npm:^2.2.0" - checksum: e9bf758727960e321a36b6407f66a20c6b2095bed3ca70d24c46a261e5bbd8296856d520c950ac881650db28de490e07485afeaadd17c2bdd5c29f7de374f939 - languageName: node - linkType: hard - "@metamask/snaps-controllers@npm:^0.38.2-flask.1": version: 0.38.2-flask.1 resolution: "@metamask/snaps-controllers@npm:0.38.2-flask.1" @@ -4912,27 +4865,6 @@ __metadata: languageName: node linkType: hard -"@metamask/snaps-execution-environments@npm:^0.35.2-flask.1": - version: 0.35.2-flask.1 - resolution: "@metamask/snaps-execution-environments@npm:0.35.2-flask.1" - dependencies: - "@metamask/object-multiplex": "npm:^1.2.0" - "@metamask/post-message-stream": "npm:^6.1.2" - "@metamask/providers": "npm:^11.0.0" - "@metamask/rpc-methods": "npm:^0.35.2-flask.1" - "@metamask/snaps-utils": "npm:^0.35.2-flask.1" - "@metamask/utils": "npm:^6.0.1" - eth-rpc-errors: "npm:^4.0.3" - json-rpc-engine: "npm:^6.1.0" - nanoid: "npm:^3.1.31" - pump: "npm:^3.0.0" - ses: "npm:^0.18.1" - stream-browserify: "npm:^3.0.0" - superstruct: "npm:^1.0.3" - checksum: 9848e0310470290c976f54c785622cbaca60e95f866cfbdaf9b277e4f4f49fb864e6b7af8453beb9b322966dd7fb8699223ba7ecff7cdee38cb466572071d90e - languageName: node - linkType: hard - "@metamask/snaps-execution-environments@npm:^0.38.0-flask.1": version: 0.38.0-flask.1 resolution: "@metamask/snaps-execution-environments@npm:0.38.0-flask.1" @@ -5014,16 +4946,6 @@ __metadata: languageName: node linkType: hard -"@metamask/snaps-ui@npm:^0.35.2-flask.1": - version: 0.35.2-flask.1 - resolution: "@metamask/snaps-ui@npm:0.35.2-flask.1" - dependencies: - "@metamask/utils": "npm:^6.0.1" - superstruct: "npm:^1.0.3" - checksum: 30833668bb832cb8cf4a377d2dea132d5fab3eed8d4d7d77ee40cce6bc38f3a65327f210e7336734b28253d8fd9182868b9e040fb56703f39ad5a9f5b1ad3606 - languageName: node - linkType: hard - "@metamask/snaps-ui@npm:^0.37.2-flask.1": version: 0.37.2-flask.1 resolution: "@metamask/snaps-ui@npm:0.37.2-flask.1" @@ -5084,35 +5006,6 @@ __metadata: languageName: node linkType: hard -"@metamask/snaps-utils@npm:^0.35.2-flask.1": - version: 0.35.2-flask.1 - resolution: "@metamask/snaps-utils@npm:0.35.2-flask.1" - dependencies: - "@babel/core": "npm:^7.20.12" - "@babel/types": "npm:^7.18.7" - "@metamask/base-controller": "npm:^3.0.0" - "@metamask/key-tree": "npm:^7.1.1" - "@metamask/permission-controller": "npm:^4.0.0" - "@metamask/providers": "npm:^11.0.0" - "@metamask/snaps-registry": "npm:^1.2.1" - "@metamask/snaps-ui": "npm:^0.35.2-flask.1" - "@metamask/utils": "npm:^6.0.1" - "@noble/hashes": "npm:^1.3.1" - "@scure/base": "npm:^1.1.1" - cron-parser: "npm:^4.5.0" - eth-rpc-errors: "npm:^4.0.3" - fast-deep-equal: "npm:^3.1.3" - fast-json-stable-stringify: "npm:^2.1.0" - is-svg: "npm:^4.4.0" - rfdc: "npm:^1.3.0" - semver: "npm:^7.3.7" - ses: "npm:^0.18.1" - superstruct: "npm:^1.0.3" - validate-npm-package-name: "npm:^5.0.0" - checksum: 674a2bb4c06025307f94e1749d9ba2fd443b4e79f5ae995038e639b32c795aef7a858216fe61a4eff277de01f37a1d539d78b2d35bdf75fbf6712d61aa053fb8 - languageName: node - linkType: hard - "@metamask/snaps-utils@npm:^0.37.2-flask.1": version: 0.37.2-flask.1 resolution: "@metamask/snaps-utils@npm:0.37.2-flask.1" @@ -5270,7 +5163,7 @@ __metadata: languageName: node linkType: hard -"@metamask/utils@npm:^6.0.0, @metamask/utils@npm:^6.0.1, @metamask/utils@npm:^6.1.0, @metamask/utils@npm:^6.2.0": +"@metamask/utils@npm:^6.0.0, @metamask/utils@npm:^6.0.1, @metamask/utils@npm:^6.2.0": version: 6.2.0 resolution: "@metamask/utils@npm:6.2.0" dependencies: @@ -5284,7 +5177,7 @@ __metadata: languageName: node linkType: hard -"@metamask/utils@npm:^8.0.0": +"@metamask/utils@npm:^8.0.0, @metamask/utils@npm:^8.1.0": version: 8.1.0 resolution: "@metamask/utils@npm:8.1.0" dependencies: @@ -24347,7 +24240,7 @@ __metadata: "@metamask/eth-json-rpc-middleware": "npm:^11.0.0" "@metamask/eth-keyring-controller": "npm:^10.0.1" "@metamask/eth-ledger-bridge-keyring": "npm:^0.15.0" - "@metamask/eth-snap-keyring": "git+https://github.com/MetaMask/eth-snap-keyring.git#commit=543117c98e80c83378dbd8bb2bc87704ee0f96f0" + "@metamask/eth-snap-keyring": "npm:^0.2.0" "@metamask/eth-token-tracker": "npm:^4.0.0" "@metamask/eth-trezor-keyring": "npm:^1.1.0" "@metamask/etherscan-link": "npm:^2.2.0" From d03879dfefcf93c3136cc6c4a1bf57d40dc8dd5a Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Wed, 6 Sep 2023 22:41:37 +0800 Subject: [PATCH 091/235] fix: update to use preview version of accounts-controller from the core repo --- .../controllers/accounts-controller.ts | 504 ------------------ app/scripts/metamask-controller.js | 2 +- lavamoat/browserify/beta/policy.json | 11 + lavamoat/browserify/desktop/policy.json | 11 + lavamoat/browserify/flask/policy.json | 11 + lavamoat/browserify/main/policy.json | 11 + lavamoat/browserify/mmi/policy.json | 11 + package.json | 1 + yarn.lock | 47 +- 9 files changed, 102 insertions(+), 507 deletions(-) delete mode 100644 app/scripts/controllers/accounts-controller.ts diff --git a/app/scripts/controllers/accounts-controller.ts b/app/scripts/controllers/accounts-controller.ts deleted file mode 100644 index 25b9655bc95b..000000000000 --- a/app/scripts/controllers/accounts-controller.ts +++ /dev/null @@ -1,504 +0,0 @@ -import type { RestrictedControllerMessenger } from '@metamask/base-controller'; -import { BaseControllerV2 } from '@metamask/base-controller'; -import { SnapKeyring } from '@metamask/eth-snap-keyring'; -import type { InternalAccount } from '@metamask/keyring-api'; -import type { - KeyringControllerState, - KeyringController, - KeyringControllerEvents, -} from '@metamask/keyring-controller'; -import type { - SnapControllerEvents, - SnapControllerState, -} from '@metamask/snaps-controllers'; -import { sha256FromString } from 'ethereumjs-util'; -import type { Patch } from 'immer'; -import { v4 as uuid } from 'uuid'; - -const controllerName = 'AccountsController'; - -export type AccountsControllerState = { - internalAccounts: { - accounts: Record; - selectedAccount: string; // id of the selected account - }; -}; - -export type AccountsControllerGetStateAction = { - type: `${typeof controllerName}:getState`; - handler: () => AccountsControllerState; -}; - -export type AccountsControllerActions = AccountsControllerGetStateAction; - -export type AccountsControllerChangeEvent = { - type: `${typeof controllerName}:stateChange`; - payload: [AccountsControllerState, Patch[]]; -}; - -export type AccountsControllerSelectedAccountChangeEvent = { - type: `${typeof controllerName}:selectedAccountChange`; - payload: [InternalAccount]; -}; - -export type AccountsControllerEvents = - | AccountsControllerChangeEvent - | AccountsControllerSelectedAccountChangeEvent - | SnapControllerEvents - | KeyringControllerEvents; - -export type AccountsControllerMessenger = RestrictedControllerMessenger< - typeof controllerName, - AccountsControllerActions, - AccountsControllerEvents, - string, - string ->; - -const accountsControllerMetadata = { - internalAccounts: { - persist: true, - anonymous: false, - }, - selectedAccount: { - persist: true, - anonymous: false, - }, -}; - -const defaultState: AccountsControllerState = { - internalAccounts: { - accounts: {}, - selectedAccount: '', - }, -}; - -export class AccountsController extends BaseControllerV2< - typeof controllerName, - AccountsControllerState, - AccountsControllerMessenger -> { - getKeyringForAccount: KeyringController['getKeyringForAccount']; - - getKeyringByType: KeyringController['getKeyringsByType']; - - getAccounts: KeyringController['getAccounts']; - - keyringApiEnabled: boolean; - - constructor({ - messenger, - state, - keyringApiEnabled, - getKeyringForAccount, - getKeyringByType, - getAccounts, - onSnapStateChange, - onKeyringStateChange, - }: { - messenger: AccountsControllerMessenger; - state: AccountsControllerState; - keyringApiEnabled?: boolean; - getKeyringForAccount: KeyringController['getKeyringForAccount']; - getKeyringByType: KeyringController['getKeyringsByType']; - getAccounts: KeyringController['getAccounts']; - onKeyringStateChange: ( - listener: (keyringState: KeyringControllerState) => void, - ) => void; - onSnapStateChange: ( - listener: (snapState: SnapControllerState) => void, - ) => void; - }) { - super({ - messenger, - name: controllerName, - metadata: accountsControllerMetadata, - state: { - ...defaultState, - ...state, - }, - }); - - this.getKeyringForAccount = getKeyringForAccount; - this.getKeyringByType = getKeyringByType; - this.getAccounts = getAccounts; - this.keyringApiEnabled = Boolean(keyringApiEnabled); - - if (this.keyringApiEnabled) { - // eslint-disable-next-line @typescript-eslint/no-misused-promises - onSnapStateChange(async (snapState: SnapControllerState) => { - // only check if snaps changed in status - const { snaps } = snapState; - const accounts = this.listAccounts(); - - this.update((currentState: AccountsControllerState) => { - accounts.forEach((account) => { - const currentAccount = - currentState.internalAccounts.accounts[account.id]; - if (currentAccount?.metadata?.snap) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore this account is guaranteed to have snap metadata - currentState.internalAccounts.accounts[ - account.id - ].metadata.snap.enabled = - snaps[currentAccount.metadata.snap.id].enabled && - !snaps[currentAccount.metadata.snap.id].blocked; - } - }); - }); - }); - } - - onKeyringStateChange( - // eslint-disable-next-line @typescript-eslint/no-misused-promises - async (keyringState: KeyringControllerState): Promise => { - // check if there are any new accounts added - // TODO: change when accountAdded event is added to the keyring controller - - if (keyringState.isUnlocked) { - // TODO: ACCOUNTS_CONTROLLER keyring will return accounts instead of addresses, remove this flatMap after and just get the latest id - const updatedKeyringAddresses = keyringState.keyrings.flatMap( - (keyring) => keyring.accounts, - ); - const previousAccounts = this.listAccounts(); - - // if there are no overlaps between the addresses in the keyring and previous accounts, - // it means the keyring is being reinitialized because the vault is being restored with the same SRP - const overlaps = updatedKeyringAddresses.filter((address) => - previousAccounts.find( - (account) => - account.address.toLowerCase() === address.toLowerCase(), - ), - ); - - await this.updateAccounts(); - - if (updatedKeyringAddresses.length > previousAccounts.length) { - this.#handleNewAccountAdded( - updatedKeyringAddresses, - previousAccounts, - ); - } else if ( - updatedKeyringAddresses.length > 0 && - overlaps.length === 0 - ) { - // if the keyring is being reinitialized, the selected account will be reset to the first account - this.setSelectedAccount(this.listAccounts()[0].id); - } else if ( - updatedKeyringAddresses.length < previousAccounts.length && - overlaps.length > 0 && - !this.getAccount(this.state.internalAccounts.selectedAccount) - ) { - this.#handleSelectedAccountRemoved(); - } - } - }, - ); - - // if somehow the selected account becomes lost then select the first account - if ( - this.state.internalAccounts.selectedAccount !== '' && - !this.getAccount(this.state.internalAccounts.selectedAccount) - ) { - this.setSelectedAccount(this.listAccounts()[0]?.id); - } - } - - getAccount(accountId: string): InternalAccount | undefined { - return this.state.internalAccounts.accounts[accountId]; - } - - listAccounts(): InternalAccount[] { - return Object.values(this.state.internalAccounts.accounts); - } - - getAccountExpect(accountId: string): InternalAccount { - // Edge case where the extension is setup but the srp is not yet created - // certain ui elements will query the selected address before any accounts are created. - if (!accountId) { - return { - id: '', - address: '', - options: {}, - methods: [], - type: 'eip155:eoa', - metadata: { - name: '', - keyring: { - type: '', - }, - }, - }; - } - - const account = this.getAccount(accountId); - if (account === undefined) { - throw new Error(`Account Id ${accountId} not found`); - } - return account; - } - - getSelectedAccount(): InternalAccount { - return this.getAccountExpect(this.state.internalAccounts.selectedAccount); - } - - setSelectedAccount(accountId: string): void { - const account = this.getAccountExpect(accountId); - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Type instantiation is excessively deep and possibly infinite. - this.update((currentState: AccountsControllerState) => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore lastSelected will be added in 0.2.2 - currentState.internalAccounts.accounts[account.id].metadata.lastSelected = - Date.now(); - currentState.internalAccounts.selectedAccount = account.id; - }); - - this.messagingSystem.publish(`${this.name}:selectedAccountChange`, account); - } - - setAccountName(accountId: string, accountName: string): void { - const account = this.getAccountExpect(accountId); - - if ( - this.listAccounts().find( - (internalAccount) => - internalAccount.metadata.name === accountName && - internalAccount.id !== accountId, - ) - ) { - throw new Error('Account name already exists'); - } - - this.update((currentState: AccountsControllerState) => { - currentState.internalAccounts.accounts[accountId] = { - ...account, - metadata: { - ...account.metadata, - name: accountName, - }, - }; - }); - } - - async updateAccounts(): Promise { - let legacyAccounts = await this.#listLegacyAccounts(); - let snapAccounts: InternalAccount[] = []; - if (this.keyringApiEnabled) { - snapAccounts = await this.#listSnapAccounts(); - // remove duplicate accounts that are retrieved from the snap keyring. - legacyAccounts = legacyAccounts.filter( - (account) => - !snapAccounts.find( - (snapAccount) => snapAccount.address === account.address, - ), - ); - } - - // keyring type map. - const keyringTypes = new Map(); - const previousAccounts = this.state.internalAccounts.accounts; - - const accounts: Record = [ - ...legacyAccounts, - ...snapAccounts, - ].reduce((internalAccountMap, internalAccount) => { - const keyringTypeName = keyringTypeToName( - internalAccount.metadata.keyring.type, - ); - const keyringAccountIndex = keyringTypes.get(keyringTypeName) ?? 0; - if (keyringAccountIndex) { - keyringTypes.set(keyringTypeName, keyringAccountIndex + 1); - } else { - keyringTypes.set(keyringTypeName, 1); - } - - const existingAccount = previousAccounts[internalAccount.id]; - - internalAccountMap[internalAccount.id] = { - ...internalAccount, - - metadata: { - ...internalAccount.metadata, - name: - existingAccount && existingAccount.metadata.name !== '' - ? existingAccount.metadata.name - : `${keyringTypeName} ${keyringAccountIndex + 1}`, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore lastSelected will be added in 0.2.2 - lastSelected: existingAccount?.metadata?.lastSelected, - }, - }; - - return internalAccountMap; - }, {} as Record); - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Type instantiation is excessively deep and possibly infinite. - this.update((currentState: AccountsControllerState) => { - currentState.internalAccounts.accounts = accounts; - }); - } - - loadBackup(backup: AccountsControllerState): void { - if (backup.internalAccounts) { - this.update((currentState: AccountsControllerState) => { - currentState.internalAccounts = backup.internalAccounts; - }); - } - } - - async #listSnapAccounts(): Promise { - const [snapKeyring] = this.getKeyringByType(SnapKeyring.type); - // snap keyring is not available until the first account is created in the keyring controller - if (!snapKeyring) { - return []; - } - - const snapAccounts = await (snapKeyring as SnapKeyring).listAccounts(false); - - for (const account of snapAccounts) { - // The snap account is guaranteed to have a snap metadata - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const snapId = account.metadata.snap!.id!; - - account.metadata = { - snap: { - id: snapId, - enabled: true, - name: '', - }, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore snap keyring not updated yet - name: '', - keyring: { - type: (snapKeyring as SnapKeyring).type, - }, - }; - } - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore lastSelected will be added in 0.2.2 - return snapAccounts; - } - - // Note: listLegacyAccounts is a temporary method until the keyrings all implement the InternalAccount interface - async #listLegacyAccounts(): Promise { - const addresses = await this.getAccounts(); - const internalAccounts: InternalAccount[] = []; - for (const address of addresses) { - const keyring = await this.getKeyringForAccount(address); - const v4options = { - random: sha256FromString(address).slice(0, 16), - }; - - internalAccounts.push({ - id: uuid(v4options), - address, - options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', - metadata: { - name: '', - keyring: { - type: (keyring as any).type as string, - }, - }, - }); - } - - return internalAccounts.filter( - (account) => account.metadata.keyring.type !== 'Snap Keyring', - ); - } - - #handleSelectedAccountRemoved() { - const previousAccount = this.listAccounts() - .filter( - (account) => account.id !== this.state.internalAccounts.selectedAccount, - ) - .sort((accountA, accountB) => { - // sort by lastSelected descending - return ( - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - (accountB.metadata?.lastSelected ?? 0) - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - (accountA.metadata?.lastSelected ?? 0) - ); - })[0]; - - this.setSelectedAccount(previousAccount.id); - } - - #handleNewAccountAdded( - updatedKeyringAddresses: string[], - previousAccounts: InternalAccount[], - ) { - const newAddress = updatedKeyringAddresses.find( - (address) => - !previousAccounts.find( - (account) => account.address.toLowerCase() === address.toLowerCase(), - ), - ); - - const newAccount = this.listAccounts().find( - (account) => - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - account.address.toLowerCase() === newAddress!.toLowerCase(), - ); - - // set the first new account as the selected account - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.setSelectedAccount(newAccount!.id); - } -} - -/** - * Returns the name of the keyring type. - * - * @param keyringType - The type of the keyring. - * @returns The name of the keyring type. - */ -export function keyringTypeToName(keyringType: string): string { - switch (keyringType) { - case 'Simple Key Pair': { - return 'Account'; - } - case 'HD Key Tree': { - return 'Account'; - } - case 'Trezor Hardware': { - return 'Trezor'; - } - case 'Ledger Hardware': { - return 'Ledger'; - } - case 'Lattice Hardware': { - return 'Lattice'; - } - case 'QR Hardware Wallet Device': { - return 'QR'; - } - case 'Snap Keyring': { - return 'Snap Account'; - } - case 'Custody': { - return 'Custody'; - } - default: { - console.warn(`Unknown keyring ${keyringType}`); - return 'Account'; - } - } -} diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 698ace0c9472..5cd3b9a573c1 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -96,6 +96,7 @@ import { } from '@metamask/controller-utils'; import { wordlist } from '@metamask/scure-bip39/dist/wordlists/english'; +import { AccountsController } from '@metamask-previews/accounts-controller'; ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) import { toChecksumHexAddress } from '../../shared/modules/hexstring-utils'; ///: END:ONLY_INCLUDE_IN @@ -156,7 +157,6 @@ import { getTokenValueParam } from '../../shared/lib/metamask-controller-utils'; import { isManifestV3 } from '../../shared/modules/mv3.utils'; import { hexToDecimal } from '../../shared/modules/conversion.utils'; import { ACTION_QUEUE_METRICS_E2E_TEST } from '../../shared/constants/test-flags'; -import { AccountsController } from './controllers/accounts-controller'; ///: BEGIN:ONLY_INCLUDE_IN(blockaid) import { createPPOMMiddleware } from './lib/ppom/ppom-middleware'; diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 9469a18a65dc..827ecd19e2c7 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -730,6 +730,17 @@ "@babel/runtime": true } }, + "@metamask-previews/accounts-controller": { + "globals": { + "console.warn": true + }, + "packages": { + "@metamask/base-controller": true, + "@metamask/eth-snap-keyring": true, + "ethereumjs-util": true, + "uuid": true + } + }, "@metamask/address-book-controller": { "packages": { "@metamask/base-controller": true, diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index cf72534084ac..98cc5ae00e9c 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -730,6 +730,17 @@ "@babel/runtime": true } }, + "@metamask-previews/accounts-controller": { + "globals": { + "console.warn": true + }, + "packages": { + "@metamask/base-controller": true, + "@metamask/eth-snap-keyring": true, + "ethereumjs-util": true, + "uuid": true + } + }, "@metamask/address-book-controller": { "packages": { "@metamask/base-controller": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index ccd8988b332c..6eb6d2c8633d 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -730,6 +730,17 @@ "@babel/runtime": true } }, + "@metamask-previews/accounts-controller": { + "globals": { + "console.warn": true + }, + "packages": { + "@metamask/base-controller": true, + "@metamask/eth-snap-keyring": true, + "ethereumjs-util": true, + "uuid": true + } + }, "@metamask/address-book-controller": { "packages": { "@metamask/base-controller": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 4121c2d7c7cb..94c53cd2b766 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -730,6 +730,17 @@ "@babel/runtime": true } }, + "@metamask-previews/accounts-controller": { + "globals": { + "console.warn": true + }, + "packages": { + "@metamask/base-controller": true, + "@metamask/eth-snap-keyring": true, + "ethereumjs-util": true, + "uuid": true + } + }, "@metamask/address-book-controller": { "packages": { "@metamask/base-controller": true, diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index dbb1f1f99654..7fda8440bb2e 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -871,6 +871,17 @@ "browserify>events": true } }, + "@metamask-previews/accounts-controller": { + "globals": { + "console.warn": true + }, + "packages": { + "@metamask/base-controller": true, + "@metamask/eth-snap-keyring": true, + "ethereumjs-util": true, + "uuid": true + } + }, "@metamask/address-book-controller": { "packages": { "@metamask/base-controller": true, diff --git a/package.json b/package.json index 7e1b9fdedbef..56f2e435e1f6 100644 --- a/package.json +++ b/package.json @@ -231,6 +231,7 @@ "@metamask-institutional/rpc-allowlist": "^1.0.0", "@metamask-institutional/sdk": "^0.1.18", "@metamask-institutional/transaction-update": "^0.1.25", + "@metamask-previews/accounts-controller": "1.0.0-preview.c338244", "@metamask/address-book-controller": "^3.0.0", "@metamask/announcement-controller": "^4.0.0", "@metamask/approval-controller": "^3.4.0", diff --git a/yarn.lock b/yarn.lock index 9cb175e2d6f2..7a3b08e65bdc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3752,6 +3752,28 @@ __metadata: languageName: node linkType: hard +"@metamask-previews/accounts-controller@npm:1.0.0-preview.c338244": + version: 1.0.0-preview.c338244 + resolution: "@metamask-previews/accounts-controller@npm:1.0.0-preview.c338244" + dependencies: + "@metamask/base-controller": "npm:^3.2.1" + "@metamask/eth-snap-keyring": "npm:^0.2.0" + "@metamask/keyring-api": "npm:^0.2.2" + "@metamask/keyring-controller": "npm:^7.3.0" + "@metamask/snaps-controllers": "npm:^1.0.1" + "@metamask/snaps-utils": "npm:^1.0.1" + "@metamask/utils": "npm:^6.2.0" + eth-rpc-errors: "npm:^4.0.2" + ethereumjs-util: "npm:^7.0.10" + immer: "npm:^9.0.6" + nanoid: "npm:^3.1.31" + uuid: "npm:^8.3.2" + peerDependencies: + "@metamask/keyring-controller": ^7.3.0 + checksum: b579187b83a1db18bce2fde0054a063d8bbacd96a1c2d7d56c0430dd6ea2b5713c64d383ae57a77d8192e55a08f711e9959f5acef03d63986fa995dd70db63b8 + languageName: node + linkType: hard + "@metamask/abi-utils@npm:^1.2.0": version: 1.2.0 resolution: "@metamask/abi-utils@npm:1.2.0" @@ -4322,6 +4344,26 @@ __metadata: languageName: node linkType: hard +"@metamask/keyring-controller@npm:^7.3.0": + version: 7.3.0 + resolution: "@metamask/keyring-controller@npm:7.3.0" + dependencies: + "@keystonehq/metamask-airgapped-keyring": "npm:^0.13.1" + "@metamask/base-controller": "npm:^3.2.1" + "@metamask/eth-keyring-controller": "npm:^13.0.0" + "@metamask/message-manager": "npm:^7.3.1" + "@metamask/preferences-controller": "npm:^4.4.0" + "@metamask/utils": "npm:^6.2.0" + async-mutex: "npm:^0.2.6" + ethereumjs-util: "npm:^7.0.10" + ethereumjs-wallet: "npm:^1.0.1" + immer: "npm:^9.0.6" + peerDependencies: + "@metamask/preferences-controller": ^4.4.0 + checksum: 080d39f068c128a7217eaae5399f37208854a8079575ed85ad392c907811a78d49ae87e142ad158d572306422e525c79e0d0fc5818d80ab88e5c0c98852eb668 + languageName: node + linkType: hard + "@metamask/keyring-controller@patch:@metamask/keyring-controller@npm%3A7.2.0#~/.yarn/patches/@metamask-keyring-controller-npm-7.2.0-fcc0c7893b.patch": version: 7.2.0 resolution: "@metamask/keyring-controller@patch:@metamask/keyring-controller@npm%3A7.2.0#~/.yarn/patches/@metamask-keyring-controller-npm-7.2.0-fcc0c7893b.patch::version=7.2.0&hash=6f51dc" @@ -4835,7 +4877,7 @@ __metadata: languageName: node linkType: hard -"@metamask/snaps-controllers@npm:^1.0.2": +"@metamask/snaps-controllers@npm:^1.0.1, @metamask/snaps-controllers@npm:^1.0.2": version: 1.0.2 resolution: "@metamask/snaps-controllers@npm:1.0.2" dependencies: @@ -5065,7 +5107,7 @@ __metadata: languageName: node linkType: hard -"@metamask/snaps-utils@npm:^1.0.2": +"@metamask/snaps-utils@npm:^1.0.1, @metamask/snaps-utils@npm:^1.0.2": version: 1.0.2 resolution: "@metamask/snaps-utils@npm:1.0.2" dependencies: @@ -24221,6 +24263,7 @@ __metadata: "@metamask-institutional/rpc-allowlist": "npm:^1.0.0" "@metamask-institutional/sdk": "npm:^0.1.18" "@metamask-institutional/transaction-update": "npm:^0.1.25" + "@metamask-previews/accounts-controller": "npm:1.0.0-preview.c338244" "@metamask/address-book-controller": "npm:^3.0.0" "@metamask/announcement-controller": "npm:^4.0.0" "@metamask/approval-controller": "npm:^3.4.0" From 52c094ebf3cfbddefd9627a2a378f16a84d114ed Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Wed, 6 Sep 2023 22:54:39 +0800 Subject: [PATCH 092/235] fix: test imports of AccountsController and yarn dedupe --- app/scripts/controllers/detect-tokens.test.js | 2 +- .../controllers/mmi-controller.test.js | 2 +- app/scripts/lib/account-tracker.test.js | 2 +- lavamoat/browserify/beta/policy.json | 34 ++++++++++++++----- lavamoat/browserify/desktop/policy.json | 34 ++++++++++++++----- lavamoat/browserify/flask/policy.json | 34 ++++++++++++++----- lavamoat/browserify/main/policy.json | 34 ++++++++++++++----- lavamoat/browserify/mmi/policy.json | 34 ++++++++++++++----- yarn.lock | 18 +--------- 9 files changed, 134 insertions(+), 60 deletions(-) diff --git a/app/scripts/controllers/detect-tokens.test.js b/app/scripts/controllers/detect-tokens.test.js index 31ff86a68b8c..525a2cd5d916 100644 --- a/app/scripts/controllers/detect-tokens.test.js +++ b/app/scripts/controllers/detect-tokens.test.js @@ -11,11 +11,11 @@ import { } from '@metamask/assets-controllers'; import { toHex } from '@metamask/controller-utils'; import { NetworkController } from '@metamask/network-controller'; +import { AccountsController } from '@metamask-previews/accounts-controller'; import { NETWORK_TYPES } from '../../../shared/constants/network'; import { toChecksumHexAddress } from '../../../shared/modules/hexstring-utils'; import DetectTokensController from './detect-tokens'; import PreferencesController from './preferences'; -import { AccountsController } from './accounts-controller'; function buildMessenger() { return new ControllerMessenger().getRestricted({ diff --git a/app/scripts/controllers/mmi-controller.test.js b/app/scripts/controllers/mmi-controller.test.js index 7e15ceffcc6d..75be1fd32736 100644 --- a/app/scripts/controllers/mmi-controller.test.js +++ b/app/scripts/controllers/mmi-controller.test.js @@ -4,12 +4,12 @@ import { MmiConfigurationController } from '@metamask-institutional/custody-keyr import { TransactionUpdateController } from '@metamask-institutional/transaction-update'; import { SignatureController } from '@metamask/signature-controller'; import { NetworkController } from '@metamask/network-controller'; +import { AccountsController } from '@metamask-previews/accounts-controller'; import MMIController from './mmi-controller'; import TransactionController from './transactions'; import PreferencesController from './preferences'; import AppStateController from './app-state'; -import { AccountsController } from './accounts-controller'; import { ControllerMessenger } from '@metamask/base-controller'; jest.mock('./permissions', () => ({ diff --git a/app/scripts/lib/account-tracker.test.js b/app/scripts/lib/account-tracker.test.js index 6ef46b357cb9..455c2177c7cb 100644 --- a/app/scripts/lib/account-tracker.test.js +++ b/app/scripts/lib/account-tracker.test.js @@ -1,10 +1,10 @@ import EventEmitter from 'events'; import { ControllerMessenger } from '@metamask/base-controller'; +import { AccountsController } from '@metamask-previews/accounts-controller'; import { SINGLE_CALL_BALANCES_ADDRESS } from '../constants/contracts'; import { createTestProviderTools } from '../../../test/stub/provider'; -import { AccountsController } from '../controllers/accounts-controller'; import AccountTracker from './account-tracker'; const noop = () => true; diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 827ecd19e2c7..9f461d6809dd 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -1140,9 +1140,9 @@ }, "packages": { "@ethereumjs/tx": true, - "@metamask/eth-snap-keyring>@metamask/keyring-api": true, "@metamask/eth-snap-keyring>@metamask/utils": true, "@metamask/eth-snap-keyring>uuid": true, + "@metamask/keyring-api": true, "browserify>events": true, "superstruct": true } @@ -1173,13 +1173,6 @@ "crypto": true } }, - "@metamask/eth-snap-keyring>@metamask/keyring-api": { - "packages": { - "@metamask/eth-snap-keyring>@metamask/utils": true, - "@metamask/eth-snap-keyring>uuid": true, - "superstruct": true - } - }, "@metamask/eth-snap-keyring>@metamask/utils": { "globals": { "TextDecoder": true, @@ -1581,6 +1574,31 @@ "TextEncoder": true } }, + "@metamask/keyring-api": { + "packages": { + "@metamask/keyring-api>@metamask/utils": true, + "@metamask/keyring-api>uuid": true, + "superstruct": true + } + }, + "@metamask/keyring-api>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/keyring-api>uuid": { + "globals": { + "crypto": true + } + }, "@metamask/keyring-controller": { "packages": { "@metamask/base-controller": true, diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index 98cc5ae00e9c..5e5f6d99a837 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -1211,9 +1211,9 @@ }, "packages": { "@ethereumjs/tx": true, - "@metamask/eth-snap-keyring>@metamask/keyring-api": true, "@metamask/eth-snap-keyring>@metamask/utils": true, "@metamask/eth-snap-keyring>uuid": true, + "@metamask/keyring-api": true, "browserify>events": true, "superstruct": true } @@ -1244,13 +1244,6 @@ "crypto": true } }, - "@metamask/eth-snap-keyring>@metamask/keyring-api": { - "packages": { - "@metamask/eth-snap-keyring>@metamask/utils": true, - "@metamask/eth-snap-keyring>uuid": true, - "superstruct": true - } - }, "@metamask/eth-snap-keyring>@metamask/utils": { "globals": { "TextDecoder": true, @@ -1675,6 +1668,31 @@ "TextEncoder": true } }, + "@metamask/keyring-api": { + "packages": { + "@metamask/keyring-api>@metamask/utils": true, + "@metamask/keyring-api>uuid": true, + "superstruct": true + } + }, + "@metamask/keyring-api>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/keyring-api>uuid": { + "globals": { + "crypto": true + } + }, "@metamask/keyring-controller": { "packages": { "@metamask/base-controller": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 6eb6d2c8633d..61054a2f1513 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -1211,9 +1211,9 @@ }, "packages": { "@ethereumjs/tx": true, - "@metamask/eth-snap-keyring>@metamask/keyring-api": true, "@metamask/eth-snap-keyring>@metamask/utils": true, "@metamask/eth-snap-keyring>uuid": true, + "@metamask/keyring-api": true, "browserify>events": true, "superstruct": true } @@ -1244,13 +1244,6 @@ "crypto": true } }, - "@metamask/eth-snap-keyring>@metamask/keyring-api": { - "packages": { - "@metamask/eth-snap-keyring>@metamask/utils": true, - "@metamask/eth-snap-keyring>uuid": true, - "superstruct": true - } - }, "@metamask/eth-snap-keyring>@metamask/utils": { "globals": { "TextDecoder": true, @@ -1675,6 +1668,31 @@ "TextEncoder": true } }, + "@metamask/keyring-api": { + "packages": { + "@metamask/keyring-api>@metamask/utils": true, + "@metamask/keyring-api>uuid": true, + "superstruct": true + } + }, + "@metamask/keyring-api>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/keyring-api>uuid": { + "globals": { + "crypto": true + } + }, "@metamask/keyring-controller": { "packages": { "@metamask/base-controller": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 94c53cd2b766..47931a47a254 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -1140,9 +1140,9 @@ }, "packages": { "@ethereumjs/tx": true, - "@metamask/eth-snap-keyring>@metamask/keyring-api": true, "@metamask/eth-snap-keyring>@metamask/utils": true, "@metamask/eth-snap-keyring>uuid": true, + "@metamask/keyring-api": true, "browserify>events": true, "superstruct": true } @@ -1173,13 +1173,6 @@ "crypto": true } }, - "@metamask/eth-snap-keyring>@metamask/keyring-api": { - "packages": { - "@metamask/eth-snap-keyring>@metamask/utils": true, - "@metamask/eth-snap-keyring>uuid": true, - "superstruct": true - } - }, "@metamask/eth-snap-keyring>@metamask/utils": { "globals": { "TextDecoder": true, @@ -1581,6 +1574,31 @@ "TextEncoder": true } }, + "@metamask/keyring-api": { + "packages": { + "@metamask/keyring-api>@metamask/utils": true, + "@metamask/keyring-api>uuid": true, + "superstruct": true + } + }, + "@metamask/keyring-api>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/keyring-api>uuid": { + "globals": { + "crypto": true + } + }, "@metamask/keyring-controller": { "packages": { "@metamask/base-controller": true, diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 7fda8440bb2e..238122284e7f 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -1281,9 +1281,9 @@ }, "packages": { "@ethereumjs/tx": true, - "@metamask/eth-snap-keyring>@metamask/keyring-api": true, "@metamask/eth-snap-keyring>@metamask/utils": true, "@metamask/eth-snap-keyring>uuid": true, + "@metamask/keyring-api": true, "browserify>events": true, "superstruct": true } @@ -1314,13 +1314,6 @@ "crypto": true } }, - "@metamask/eth-snap-keyring>@metamask/keyring-api": { - "packages": { - "@metamask/eth-snap-keyring>@metamask/utils": true, - "@metamask/eth-snap-keyring>uuid": true, - "superstruct": true - } - }, "@metamask/eth-snap-keyring>@metamask/utils": { "globals": { "TextDecoder": true, @@ -1722,6 +1715,31 @@ "TextEncoder": true } }, + "@metamask/keyring-api": { + "packages": { + "@metamask/keyring-api>@metamask/utils": true, + "@metamask/keyring-api>uuid": true, + "superstruct": true + } + }, + "@metamask/keyring-api>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, + "@metamask/keyring-api>uuid": { + "globals": { + "crypto": true + } + }, "@metamask/keyring-controller": { "packages": { "@metamask/base-controller": true, diff --git a/yarn.lock b/yarn.lock index 7a3b08e65bdc..e1181805d13c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4292,23 +4292,7 @@ __metadata: languageName: node linkType: hard -"@metamask/keyring-api@npm:^0.2.1": - version: 0.2.1 - resolution: "@metamask/keyring-api@npm:0.2.1" - dependencies: - "@metamask/providers": "npm:^11.0.0" - "@metamask/rpc-methods": "npm:^0.38.1-flask.1" - "@metamask/snaps-controllers": "npm:^0.38.2-flask.1" - "@metamask/snaps-utils": "npm:^0.38.2-flask.1" - "@metamask/utils": "npm:^8.0.0" - "@types/uuid": "npm:^9.0.1" - superstruct: "npm:^1.0.3" - uuid: "npm:^9.0.0" - checksum: 12ab6f6767f32bb75e6e6d134786e3feecb520df7e584b8eec3a0c8430dd8349bf9971707a2a61a00ac2efbe594d26adc68360f8dc291d4f0439fdbf513b2bc2 - languageName: node - linkType: hard - -"@metamask/keyring-api@npm:^0.2.2": +"@metamask/keyring-api@npm:^0.2.1, @metamask/keyring-api@npm:^0.2.2": version: 0.2.2 resolution: "@metamask/keyring-api@npm:0.2.2" dependencies: From 71e76bc66d5316991a1d8bb058777737b1d6a9e5 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Wed, 6 Sep 2023 23:07:24 +0800 Subject: [PATCH 093/235] fix: InternalAccount import from eth-snap-keyring to keyring-api --- .../controllers/transactions/IncomingTransactionHelper.ts | 2 +- app/scripts/migrations/097.test.ts | 2 +- app/scripts/migrations/097.ts | 2 +- ui/store/actions.ts | 2 +- ui/store/store.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/scripts/controllers/transactions/IncomingTransactionHelper.ts b/app/scripts/controllers/transactions/IncomingTransactionHelper.ts index 5fa366dadfaa..f90d0220a157 100644 --- a/app/scripts/controllers/transactions/IncomingTransactionHelper.ts +++ b/app/scripts/controllers/transactions/IncomingTransactionHelper.ts @@ -3,7 +3,7 @@ import type { BlockTracker, NetworkState } from '@metamask/network-controller'; import type { Hex } from '@metamask/utils'; import log from 'loglevel'; -import { InternalAccount } from '@metamask/eth-snap-keyring'; +import { InternalAccount } from '@metamask/keyring-api'; import { TransactionMeta } from '../../../../shared/constants/transaction'; import { RemoteTransactionSource } from './types'; diff --git a/app/scripts/migrations/097.test.ts b/app/scripts/migrations/097.test.ts index c8732fba6cb8..fb053e1d6f1e 100644 --- a/app/scripts/migrations/097.test.ts +++ b/app/scripts/migrations/097.test.ts @@ -1,6 +1,6 @@ import { v4 as uuid } from 'uuid'; import { sha256FromString } from 'ethereumjs-util'; -import { InternalAccount } from '@metamask/eth-snap-keyring'; +import { InternalAccount } from '@metamask/keyring-api'; import { migrate } from './097'; const MOCK_ADDRESS = '0x0'; diff --git a/app/scripts/migrations/097.ts b/app/scripts/migrations/097.ts index 568dc2206863..bc904b9457cb 100644 --- a/app/scripts/migrations/097.ts +++ b/app/scripts/migrations/097.ts @@ -1,4 +1,4 @@ -import { InternalAccount } from '@metamask/eth-snap-keyring'; +import { InternalAccount } from '@metamask/keyring-api'; import { sha256FromString } from 'ethereumjs-util'; import { v4 as uuid } from 'uuid'; import { cloneDeep } from 'lodash'; diff --git a/ui/store/actions.ts b/ui/store/actions.ts index 78ef59d9d24c..af088024ac32 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -22,7 +22,7 @@ import { NonEmptyArray } from '@metamask/controller-utils'; ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) import { HandlerType } from '@metamask/snaps-utils'; ///: END:ONLY_INCLUDE_IN -import { InternalAccount } from '@metamask/eth-snap-keyring'; +import { InternalAccount } from '@metamask/keyring-api'; import { getMethodDataAsync } from '../helpers/utils/transactions.util'; import switchDirection from '../../shared/lib/switch-direction'; import { diff --git a/ui/store/store.ts b/ui/store/store.ts index 419e42b2a201..d0917c828b18 100644 --- a/ui/store/store.ts +++ b/ui/store/store.ts @@ -3,7 +3,7 @@ import { configureStore as baseConfigureStore } from '@reduxjs/toolkit'; import devtoolsEnhancer from 'remote-redux-devtools'; import { ApprovalControllerState } from '@metamask/approval-controller'; import { GasEstimateType, GasFeeEstimates } from '@metamask/gas-fee-controller'; -import { InternalAccount } from '@metamask/eth-snap-keyring'; +import { InternalAccount } from '@metamask/keyring-api'; import rootReducer from '../ducks'; import { LedgerTransportTypes } from '../../shared/constants/hardware-wallets'; import { TransactionMeta } from '../../shared/constants/transaction'; From c3511c9ccb2805c965a73a50ca3fd2e45a4551a5 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 7 Sep 2023 10:13:42 +0800 Subject: [PATCH 094/235] fix: bump keyring-api dep and fix 097 migration's account schema --- app/scripts/migrations/097.ts | 22 ++++++++-------------- package.json | 2 +- yarn.lock | 4 ++-- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/app/scripts/migrations/097.ts b/app/scripts/migrations/097.ts index bc904b9457cb..0c4f27059303 100644 --- a/app/scripts/migrations/097.ts +++ b/app/scripts/migrations/097.ts @@ -1,4 +1,8 @@ -import { InternalAccount } from '@metamask/keyring-api'; +import { + EthAccountType, + InternalAccount, + EthMethod, +} from '@metamask/keyring-api'; import { sha256FromString } from 'ethereumjs-util'; import { v4 as uuid } from 'uuid'; import { cloneDeep } from 'lodash'; @@ -71,26 +75,16 @@ function moveIdentitiesToAccountsController(state: Record) { accounts[expectedId] = { address: identity.address, id: expectedId, - name: identity.name, options: {}, metadata: { + name: identity.name, lastSelected: identity.lastSelected ?? null, keyring: { type: 'HD Key Tree', }, }, - supportedMethods: [ - 'personal_sign', - 'eth_sendTransaction', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v2', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }; }); diff --git a/package.json b/package.json index 416111b44c94..0bd288aed215 100644 --- a/package.json +++ b/package.json @@ -252,7 +252,7 @@ "@metamask/gas-fee-controller": "^6.0.1", "@metamask/jazzicon": "^2.0.0", "@metamask/key-tree": "^9.0.0", - "@metamask/keyring-api": "^0.2.1", + "@metamask/keyring-api": "^0.2.2", "@metamask/keyring-controller": "^7.2.0", "@metamask/logo": "^3.1.1", "@metamask/message-manager": "^7.3.0", diff --git a/yarn.lock b/yarn.lock index fc6d433a3c78..1373a35d0fdb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4292,7 +4292,7 @@ __metadata: languageName: node linkType: hard -"@metamask/keyring-api@npm:^0.2.1, @metamask/keyring-api@npm:^0.2.2": +"@metamask/keyring-api@npm:^0.2.2": version: 0.2.2 resolution: "@metamask/keyring-api@npm:0.2.2" dependencies: @@ -24275,7 +24275,7 @@ __metadata: "@metamask/gas-fee-controller": "npm:^6.0.1" "@metamask/jazzicon": "npm:^2.0.0" "@metamask/key-tree": "npm:^9.0.0" - "@metamask/keyring-api": "npm:^0.2.1" + "@metamask/keyring-api": "npm:^0.2.2" "@metamask/keyring-controller": "npm:^7.2.0" "@metamask/logo": "npm:^3.1.1" "@metamask/message-manager": "npm:^7.3.0" From f864acaa8a6ce86d576cc35fa0ad5739878f3705 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 7 Sep 2023 10:23:14 +0800 Subject: [PATCH 095/235] feat: update accounts-controller to subscribe to events instead of using onChange --- app/scripts/metamask-controller.js | 10 ---------- lavamoat/browserify/beta/policy.json | 2 ++ lavamoat/browserify/desktop/policy.json | 2 ++ lavamoat/browserify/flask/policy.json | 2 ++ lavamoat/browserify/main/policy.json | 2 ++ lavamoat/browserify/mmi/policy.json | 2 ++ package.json | 2 +- yarn.lock | 10 +++++----- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 6aa437c1b642..0104db8352e1 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -863,17 +863,7 @@ export default class MetamaskController extends EventEmitter { getAccounts: this.coreKeyringController.getAccounts.bind( this.coreKeyringController, ), - onKeyringStateChange: keyringControllerMessenger.subscribe.bind( - keyringControllerMessenger, - 'KeyringController:stateChange', - ), keyringApiEnabled, - ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) - onSnapStateChange: this.controllerMessenger.subscribe.bind( - this.controllerMessenger, - 'SnapController:stateChange', - ), - ///: END:ONLY_INCLUDE_IN }); this.permissionController = new PermissionController({ diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 9f461d6809dd..a1020cae4cdd 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -732,11 +732,13 @@ }, "@metamask-previews/accounts-controller": { "globals": { + "console.log": true, "console.warn": true }, "packages": { "@metamask/base-controller": true, "@metamask/eth-snap-keyring": true, + "@metamask/keyring-api": true, "ethereumjs-util": true, "uuid": true } diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index 5e5f6d99a837..e097791cce34 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -732,11 +732,13 @@ }, "@metamask-previews/accounts-controller": { "globals": { + "console.log": true, "console.warn": true }, "packages": { "@metamask/base-controller": true, "@metamask/eth-snap-keyring": true, + "@metamask/keyring-api": true, "ethereumjs-util": true, "uuid": true } diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 61054a2f1513..a8cb96037246 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -732,11 +732,13 @@ }, "@metamask-previews/accounts-controller": { "globals": { + "console.log": true, "console.warn": true }, "packages": { "@metamask/base-controller": true, "@metamask/eth-snap-keyring": true, + "@metamask/keyring-api": true, "ethereumjs-util": true, "uuid": true } diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 47931a47a254..3babfe219c48 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -732,11 +732,13 @@ }, "@metamask-previews/accounts-controller": { "globals": { + "console.log": true, "console.warn": true }, "packages": { "@metamask/base-controller": true, "@metamask/eth-snap-keyring": true, + "@metamask/keyring-api": true, "ethereumjs-util": true, "uuid": true } diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 238122284e7f..068a5ab0fb43 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -873,11 +873,13 @@ }, "@metamask-previews/accounts-controller": { "globals": { + "console.log": true, "console.warn": true }, "packages": { "@metamask/base-controller": true, "@metamask/eth-snap-keyring": true, + "@metamask/keyring-api": true, "ethereumjs-util": true, "uuid": true } diff --git a/package.json b/package.json index 0bd288aed215..904b7c0aa968 100644 --- a/package.json +++ b/package.json @@ -231,7 +231,7 @@ "@metamask-institutional/rpc-allowlist": "^1.0.0", "@metamask-institutional/sdk": "^0.1.18", "@metamask-institutional/transaction-update": "^0.1.25", - "@metamask-previews/accounts-controller": "1.0.0-preview.c338244", + "@metamask-previews/accounts-controller": "1.0.0-preview.dd5d578", "@metamask/address-book-controller": "^3.0.0", "@metamask/announcement-controller": "^4.0.0", "@metamask/approval-controller": "^3.4.0", diff --git a/yarn.lock b/yarn.lock index 1373a35d0fdb..be48540d6617 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3752,9 +3752,9 @@ __metadata: languageName: node linkType: hard -"@metamask-previews/accounts-controller@npm:1.0.0-preview.c338244": - version: 1.0.0-preview.c338244 - resolution: "@metamask-previews/accounts-controller@npm:1.0.0-preview.c338244" +"@metamask-previews/accounts-controller@npm:1.0.0-preview.dd5d578": + version: 1.0.0-preview.dd5d578 + resolution: "@metamask-previews/accounts-controller@npm:1.0.0-preview.dd5d578" dependencies: "@metamask/base-controller": "npm:^3.2.1" "@metamask/eth-snap-keyring": "npm:^0.2.0" @@ -3770,7 +3770,7 @@ __metadata: uuid: "npm:^8.3.2" peerDependencies: "@metamask/keyring-controller": ^7.3.0 - checksum: b579187b83a1db18bce2fde0054a063d8bbacd96a1c2d7d56c0430dd6ea2b5713c64d383ae57a77d8192e55a08f711e9959f5acef03d63986fa995dd70db63b8 + checksum: 60fc010c280d7298e23088a8914f6ba1ff09d5fadc39968c294ee166a5200dea1f8fcbc2ec13fa9d49deb6179576db84445a0ea19a6e223ecd1b8a42c40a551f languageName: node linkType: hard @@ -24247,7 +24247,7 @@ __metadata: "@metamask-institutional/rpc-allowlist": "npm:^1.0.0" "@metamask-institutional/sdk": "npm:^0.1.18" "@metamask-institutional/transaction-update": "npm:^0.1.25" - "@metamask-previews/accounts-controller": "npm:1.0.0-preview.c338244" + "@metamask-previews/accounts-controller": "npm:1.0.0-preview.dd5d578" "@metamask/address-book-controller": "npm:^3.0.0" "@metamask/announcement-controller": "npm:^4.0.0" "@metamask/approval-controller": "npm:^3.4.0" From 328fdc4d05392ca31fda73f0a4fb161a76c102ef Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 7 Sep 2023 16:31:34 +0800 Subject: [PATCH 096/235] fix: 097 test --- app/scripts/migrations/097.test.ts | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/app/scripts/migrations/097.test.ts b/app/scripts/migrations/097.test.ts index fb053e1d6f1e..485e1ff50b43 100644 --- a/app/scripts/migrations/097.test.ts +++ b/app/scripts/migrations/097.test.ts @@ -1,6 +1,6 @@ import { v4 as uuid } from 'uuid'; import { sha256FromString } from 'ethereumjs-util'; -import { InternalAccount } from '@metamask/keyring-api'; +import { EthMethod, InternalAccount } from '@metamask/keyring-api'; import { migrate } from './097'; const MOCK_ADDRESS = '0x0'; @@ -56,24 +56,14 @@ function expectedInternalAccount( address, id: addressToUUID(address), metadata: { + name: nickname, keyring: { type: 'HD Key Tree', }, lastSelected: lastSelected ? expect.any(Number) : null, }, - name: nickname, options: {}, - supportedMethods: [ - 'personal_sign', - 'eth_sendTransaction', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v2', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], + methods: [...Object.values(EthMethod)], type: 'eip155:eoa', }; } From 886fe911ce1503a155fa5d46f7a9dc817ac95948 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 7 Sep 2023 18:07:49 +0800 Subject: [PATCH 097/235] fix: mmi controller test --- .../controllers/mmi-controller.test.js | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/app/scripts/controllers/mmi-controller.test.js b/app/scripts/controllers/mmi-controller.test.js index 75be1fd32736..9b9e0b1c4174 100644 --- a/app/scripts/controllers/mmi-controller.test.js +++ b/app/scripts/controllers/mmi-controller.test.js @@ -11,6 +11,7 @@ import TransactionController from './transactions'; import PreferencesController from './preferences'; import AppStateController from './app-state'; import { ControllerMessenger } from '@metamask/base-controller'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; jest.mock('./permissions', () => ({ getPermissionBackgroundApiMethods: () => ({ @@ -39,16 +40,8 @@ const mockAccount = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }; const mockAccount2 = { address: '0x2', @@ -60,16 +53,8 @@ const mockAccount2 = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }; describe('MMIController', function () { @@ -92,6 +77,12 @@ describe('MMIController', function () { }, messenger: controllerMessenger.getRestricted({ name: 'AccountsController', + allowedEvents: [ + 'SnapController:stateChange', + 'KeyringController:accountRemoved', + 'KeyringController:stateChange', + 'AccountsController:selectedAccountChange', + ], }), onKeyringStateChange: jest.fn(), getKeyringForAccount: jest.fn(), From 26d50a5b9d7470977cf5f4ad0004798137c2b048 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Thu, 7 Sep 2023 22:09:00 +0800 Subject: [PATCH 098/235] fix: update tests to use EthAccountType and EthMethod --- .storybook/test-data.js | 49 +---- app/scripts/controllers/detect-tokens.test.js | 27 +-- .../permissions/specifications.test.js | 123 ++---------- .../IncomingTransactionHelper.test.ts | 18 +- .../controllers/transactions/index.test.js | 49 +---- app/scripts/lib/backup.test.js | 13 +- app/scripts/metamask-controller.test.js | 63 ++---- test/jest/mock-store.js | 49 +---- .../account-list-item-component.test.js | 25 +-- .../account-list-item.stories.js | 13 +- .../unconnected-account-alert.test.js | 25 +-- ...m-page-container-content.component.test.js | 49 +---- .../edit-gas-fee-popover.test.js | 13 +- .../edit-gas-item/edit-gas-item.test.js | 13 +- .../edit-gas-tooltip/edit-gas-tooltip.test.js | 13 +- .../gas-details-item-title.test.js | 13 +- .../confirm-remove-account.stories.js | 13 +- .../confirm-remove-account.test.js | 25 +-- ui/components/app/nfts-tab/nfts-tab.test.js | 13 +- .../signature-request-original.test.js | 13 +- .../signature-request-data.test.js | 25 +-- .../signature-request.test.js | 37 +--- .../transaction-status-label.test.js | 49 +---- .../app/wallet-overview/eth-overview.test.js | 25 +-- .../wallet-overview/token-overview.test.js | 13 +- ...ive-replacement-token-notification.test.js | 13 +- .../wrong-network-notification.test.js | 13 +- .../account-list-item.test.js | 13 +- .../account-list-menu.test.js | 13 +- .../connected-site-menu.test.js | 25 +-- .../create-account/create-account.test.js | 13 +- .../select-action-modal.test.js | 13 +- ui/ducks/app/app.test.js | 13 +- ui/ducks/metamask/metamask.test.js | 133 +++---------- ui/ducks/send/send.test.js | 169 +++------------- ui/hooks/useAddressDetails.test.js | 25 +-- ui/hooks/useAssetDetails.test.js | 13 +- .../confirm-add-suggested-token.test.js | 13 +- .../confirm-decrypt-message.component.test.js | 13 +- ...rm-encryption-public-key.component.test.js | 13 +- .../confirm-signature-request/index.test.js | 13 +- .../confirm-transaction-base.test.js | 13 +- .../connected-accounts.stories.js | 25 +-- ui/pages/send/send.test.js | 13 +- .../token-allowance/token-allowance.test.js | 25 +-- .../token-details/token-details-page.test.js | 49 +---- ui/selectors/institutional/selectors.test.js | 49 +---- ...nonce-sorted-transactions-selector.test.js | 13 +- ui/selectors/permissions.test.js | 181 +++--------------- ui/selectors/selectors.test.js | 13 +- ui/selectors/transactions.test.js | 49 +---- ui/store/actionConstants.test.js | 13 +- ui/store/actions.test.js | 49 +---- 53 files changed, 341 insertions(+), 1427 deletions(-) diff --git a/.storybook/test-data.js b/.storybook/test-data.js index 0c1632936666..bf5a45787cbc 100644 --- a/.storybook/test-data.js +++ b/.storybook/test-data.js @@ -3,6 +3,7 @@ import { KeyringType } from '../shared/constants/keyring'; import { NetworkType } from '@metamask/controller-utils'; import { NetworkStatus } from '@metamask/network-controller'; import { CHAIN_IDS } from '../shared/constants/network'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; const state = { invalidCustomNetwork: { @@ -312,16 +313,8 @@ const state = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '07c2cfec-36c9-46c4-8115-3836d3ac9047': { address: '0xb19ac54efa18cc3a14a5b821bfec73d284bf0c5e', @@ -333,16 +326,8 @@ const state = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '15e69915-2a1a-4019-93b3-916e11fd432f': { address: '0x9d0ba4ddac06032527b140912ec808ab9451b788', @@ -354,16 +339,8 @@ const state = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '784225f4-d30b-4e77-a900-c8bbce735b88': { address: '0xeb9e64b93097bc15f01f13eae97015c57ab64823', @@ -375,16 +352,8 @@ const state = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/app/scripts/controllers/detect-tokens.test.js b/app/scripts/controllers/detect-tokens.test.js index 525a2cd5d916..fe29997163fa 100644 --- a/app/scripts/controllers/detect-tokens.test.js +++ b/app/scripts/controllers/detect-tokens.test.js @@ -10,6 +10,7 @@ import { AssetsContractController, } from '@metamask/assets-controllers'; import { toHex } from '@metamask/controller-utils'; +import { EthMethod, EthAccountType } from '@metamask/keyring-api'; import { NetworkController } from '@metamask/network-controller'; import { AccountsController } from '@metamask-previews/accounts-controller'; import { NETWORK_TYPES } from '../../../shared/constants/network'; @@ -259,18 +260,8 @@ describe('DetectTokensController', function () { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sendTransaction', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v2', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '07c2cfec-36c9-46c4-8115-3836d3ac9047': { address: '0xbc86727e770de68b1060c91f6bb6945c73e10388', @@ -282,16 +273,8 @@ describe('DetectTokensController', function () { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/app/scripts/controllers/permissions/specifications.test.js b/app/scripts/controllers/permissions/specifications.test.js index a0f275d564a2..0f70dfcfb79d 100644 --- a/app/scripts/controllers/permissions/specifications.test.js +++ b/app/scripts/controllers/permissions/specifications.test.js @@ -1,4 +1,5 @@ import { SnapCaveatType } from '@metamask/rpc-methods'; +import { EthMethod, EthAccountType } from '@metamask/keyring-api'; import { CaveatTypes, RestrictedMethods, @@ -133,16 +134,8 @@ describe('PermissionController specifications', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, { address: '0x3', @@ -155,16 +148,8 @@ describe('PermissionController specifications', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, ]; }); @@ -276,16 +261,8 @@ describe('PermissionController specifications', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, { address: '0x2', @@ -297,16 +274,8 @@ describe('PermissionController specifications', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, { address: '0x3', @@ -319,16 +288,8 @@ describe('PermissionController specifications', () => { lastSelected: 3, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, { address: '0x4', @@ -341,18 +302,8 @@ describe('PermissionController specifications', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sendTransaction', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v2', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, ]; }); @@ -387,16 +338,8 @@ describe('PermissionController specifications', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, { address: '0x3', @@ -409,16 +352,8 @@ describe('PermissionController specifications', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, ]; }); @@ -451,16 +386,8 @@ describe('PermissionController specifications', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, { address: '0x3', @@ -473,16 +400,8 @@ describe('PermissionController specifications', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, ]; }); diff --git a/app/scripts/controllers/transactions/IncomingTransactionHelper.test.ts b/app/scripts/controllers/transactions/IncomingTransactionHelper.test.ts index 674dd4a4ce23..2b6aa7611dbe 100644 --- a/app/scripts/controllers/transactions/IncomingTransactionHelper.test.ts +++ b/app/scripts/controllers/transactions/IncomingTransactionHelper.test.ts @@ -1,7 +1,11 @@ import { NetworkType } from '@metamask/controller-utils'; import type { BlockTracker, NetworkState } from '@metamask/network-controller'; -import { InternalAccount } from '@metamask/keyring-api'; +import { + EthAccountType, + EthMethod, + InternalAccount, +} from '@metamask/keyring-api'; import { TransactionMeta, TransactionStatus, @@ -33,16 +37,8 @@ const INTERNAL_ACCOUNT_MOCK: InternalAccount = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }; const FROM_BLOCK_HEX_MOCK = '0x20'; const FROM_BLOCK_DECIMAL_MOCK = 32; diff --git a/app/scripts/controllers/transactions/index.test.js b/app/scripts/controllers/transactions/index.test.js index da0fee7fb09f..f19af91a343b 100644 --- a/app/scripts/controllers/transactions/index.test.js +++ b/app/scripts/controllers/transactions/index.test.js @@ -6,6 +6,7 @@ import { TransactionFactory } from '@ethereumjs/tx'; import { ObservableStore } from '@metamask/obs-store'; import { ApprovalType } from '@metamask/controller-utils'; import sinon from 'sinon'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { errorCodes, ethErrors } from 'eth-rpc-errors'; import { @@ -72,16 +73,8 @@ const MOCK_INTERNAL_ACCOUNT = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }; async function flushPromises() { @@ -388,16 +381,8 @@ describe('Transaction Controller', function () { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }; const recipientAddress = '0xc684832530fcbddae4b4230a47e991ddcec2831d'; @@ -1187,16 +1172,8 @@ describe('Transaction Controller', function () { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }; const recipientAddress = '0xc42edfcc21ed14dda456aa0756c153f7985d8813'; @@ -1674,16 +1651,8 @@ describe('Transaction Controller', function () { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }; const recipientAddress = '0xc42edfcc21ed14dda456aa0756c153f7985d8813'; diff --git a/app/scripts/lib/backup.test.js b/app/scripts/lib/backup.test.js index 469811cdc37c..fa88204ddf80 100644 --- a/app/scripts/lib/backup.test.js +++ b/app/scripts/lib/backup.test.js @@ -1,4 +1,5 @@ import { strict as assert } from 'assert'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import sinon from 'sinon'; import Backup from './backup'; @@ -176,16 +177,8 @@ const jsonData = JSON.stringify({ lastSelected: 1693289751176, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'fcbcdca4-cc47-4bc8-b455-b14421e9277e', diff --git a/app/scripts/metamask-controller.test.js b/app/scripts/metamask-controller.test.js index fb86561324fb..be96a88167a4 100644 --- a/app/scripts/metamask-controller.test.js +++ b/app/scripts/metamask-controller.test.js @@ -15,6 +15,7 @@ import { METAMASK_STALELIST_FILE, METAMASK_HOTLIST_DIFF_FILE, } from '@metamask/phishing-controller'; +import { EthMethod, EthAccountType } from '@metamask/keyring-api'; import { v4 as uuid } from 'uuid'; import { sha256FromString } from 'ethereumjs-util'; import { NetworkType } from '@metamask/controller-utils'; @@ -131,18 +132,8 @@ const TEST_INTERNAL_ACCOUNT = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sendTransaction', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v2', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }; const NOTIFICATION_ID = 'NHL8f2eSSTn9TKBamRLiU'; @@ -540,16 +531,8 @@ describe('MetaMaskController', function () { id: 'e26b5b50-739e-4d6a-a9d1-a9163f480a52', address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, metadata: { name: DEFAULT_LABEL, keyring: { type: 'HD Key Tree' }, @@ -573,16 +556,8 @@ describe('MetaMaskController', function () { id: 'e26b5b50-739e-4d6a-a9d1-a9163f480a52', address: TEST_ADDRESS, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, metadata: { name: 'Account Foo', keyring: { type: 'HD Key Tree' }, @@ -617,16 +592,8 @@ describe('MetaMaskController', function () { id: 'f73954ab-4605-459c-b0ff-23978b190709', address: TEST_ADDRESS_ALT, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, metadata: { name: DEFAULT_LABEL, keyring: { type: 'HD Key Tree' }, @@ -672,16 +639,8 @@ describe('MetaMaskController', function () { id: 'e26b5b50-739e-4d6a-a9d1-a9163f480a52', address: TEST_ADDRESS, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, metadata: { name: DEFAULT_LABEL, keyring: { type: 'HD Key Tree' }, diff --git a/test/jest/mock-store.js b/test/jest/mock-store.js index be28f24113f1..8644f222e887 100644 --- a/test/jest/mock-store.js +++ b/test/jest/mock-store.js @@ -1,5 +1,6 @@ import { NetworkType } from '@metamask/controller-utils'; import { NetworkStatus } from '@metamask/network-controller'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { CHAIN_IDS } from '../../shared/constants/network'; import { KeyringType } from '../../shared/constants/keyring'; @@ -242,16 +243,8 @@ export const createSwapsMockStore = () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '07c2cfec-36c9-46c4-8115-3836d3ac9047': { address: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb', @@ -263,16 +256,8 @@ export const createSwapsMockStore = () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '15e69915-2a1a-4019-93b3-916e11fd432f': { address: '0x2f8d4a878cfa04a6e60d46362f5644deab66572d', @@ -284,16 +269,8 @@ export const createSwapsMockStore = () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '784225f4-d30b-4e77-a900-c8bbce735b88': { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', @@ -305,16 +282,8 @@ export const createSwapsMockStore = () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/components/app/account-list-item/account-list-item-component.test.js b/ui/components/app/account-list-item/account-list-item-component.test.js index 6e17560be933..4618e9b26c1e 100644 --- a/ui/components/app/account-list-item/account-list-item-component.test.js +++ b/ui/components/app/account-list-item/account-list-item-component.test.js @@ -1,6 +1,7 @@ import React from 'react'; import configureStore from 'redux-mock-store'; import { fireEvent } from '@testing-library/react'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { renderWithProvider } from '../../../../test/lib/render-helpers'; import mockState from '../../../../test/data/mock-state.json'; import AccountListItem from './account-list-item'; @@ -21,16 +22,8 @@ describe('AccountListItem Component', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, className: 'mockClassName', displayAddress: false, @@ -84,16 +77,8 @@ describe('AccountListItem Component', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }; diff --git a/ui/components/app/account-list-item/account-list-item.stories.js b/ui/components/app/account-list-item/account-list-item.stories.js index 04ef1a5abb36..5dc128a0edc9 100644 --- a/ui/components/app/account-list-item/account-list-item.stories.js +++ b/ui/components/app/account-list-item/account-list-item.stories.js @@ -1,4 +1,5 @@ import React from 'react'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import README from './README.mdx'; import AccountListItem from './account-list-item'; @@ -31,16 +32,8 @@ const account = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }; export const DefaultStory = (args) => { diff --git a/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.test.js b/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.test.js index e005012c538e..8b59bb1517d7 100644 --- a/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.test.js +++ b/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.test.js @@ -5,6 +5,7 @@ import thunk from 'redux-thunk'; import { fireEvent } from '@testing-library/react'; import configureMockStore from 'redux-mock-store'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { tick } from '../../../../../test/lib/tick'; import { renderWithProvider } from '../../../../../test/lib/render-helpers'; @@ -28,16 +29,8 @@ describe('Unconnected Account Alert', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '07c2cfec-36c9-46c4-8115-3836d3ac9047': { address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', @@ -49,16 +42,8 @@ describe('Unconnected Account Alert', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.test.js b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.test.js index 4845eba8ebf9..be473eec602e 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.test.js +++ b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.test.js @@ -1,6 +1,7 @@ import { fireEvent } from '@testing-library/react'; import React from 'react'; import configureMockStore from 'redux-mock-store'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { TransactionType } from '../../../../../shared/constants/transaction'; import { renderWithProvider } from '../../../../../test/lib/render-helpers'; import { @@ -37,16 +38,8 @@ describe('Confirm Page Container Content', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '07c2cfec-36c9-46c4-8115-3836d3ac9047': { address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', @@ -58,16 +51,8 @@ describe('Confirm Page Container Content', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '15e69915-2a1a-4019-93b3-916e11fd432f': { address: '0xc42edfcc21ed14dda456aa0756c153f7985d8813', @@ -79,16 +64,8 @@ describe('Confirm Page Container Content', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '784225f4-d30b-4e77-a900-c8bbce735b88': { address: '0xeb9e64b93097bc15f01f13eae97015c57ab64823', @@ -100,16 +77,8 @@ describe('Confirm Page Container Content', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.test.js b/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.test.js index 8aa2623d2a57..535f72ffe947 100644 --- a/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.test.js +++ b/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.test.js @@ -1,5 +1,6 @@ import React from 'react'; import { screen } from '@testing-library/react'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { EditGasModes } from '../../../../shared/constants/gas'; import { renderWithProvider } from '../../../../test/lib/render-helpers'; @@ -73,16 +74,8 @@ const render = ({ txProps, contextProps } = {}) => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.test.js b/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.test.js index f1cfc717894c..c8b45a700139 100644 --- a/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.test.js +++ b/ui/components/app/edit-gas-fee-popover/edit-gas-item/edit-gas-item.test.js @@ -1,5 +1,6 @@ import React from 'react'; import { screen } from '@testing-library/react'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { EditGasModes, @@ -82,16 +83,8 @@ const renderComponent = ({ }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/components/app/edit-gas-fee-popover/edit-gas-tooltip/edit-gas-tooltip.test.js b/ui/components/app/edit-gas-fee-popover/edit-gas-tooltip/edit-gas-tooltip.test.js index 2ba4e50a22c2..06565063a1bb 100644 --- a/ui/components/app/edit-gas-fee-popover/edit-gas-tooltip/edit-gas-tooltip.test.js +++ b/ui/components/app/edit-gas-fee-popover/edit-gas-tooltip/edit-gas-tooltip.test.js @@ -1,4 +1,5 @@ import React from 'react'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import configureStore from '../../../../store/store'; import { renderWithProvider } from '../../../../../test/jest'; import { GasFeeContextProvider } from '../../../../contexts/gasFee'; @@ -53,16 +54,8 @@ const renderComponent = (componentProps) => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/components/app/gas-details-item/gas-details-item-title/gas-details-item-title.test.js b/ui/components/app/gas-details-item/gas-details-item-title/gas-details-item-title.test.js index fe8be78956b0..7c21406d1c02 100644 --- a/ui/components/app/gas-details-item/gas-details-item-title/gas-details-item-title.test.js +++ b/ui/components/app/gas-details-item/gas-details-item-title/gas-details-item-title.test.js @@ -1,5 +1,6 @@ import React from 'react'; import { screen, waitFor } from '@testing-library/react'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { CHAIN_IDS } from '../../../../../shared/constants/network'; import { GasFeeContextProvider } from '../../../../contexts/gasFee'; @@ -40,16 +41,8 @@ const render = () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.stories.js b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.stories.js index a7e03634c45d..a7f9931fa03f 100644 --- a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.stories.js +++ b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.stories.js @@ -1,4 +1,5 @@ import React from 'react'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import ConfirmRemoveAccount from '.'; export default { @@ -21,16 +22,8 @@ export default { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, }; diff --git a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.test.js b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.test.js index 3c152551d966..bd5b03556373 100644 --- a/ui/components/app/modals/confirm-remove-account/confirm-remove-account.test.js +++ b/ui/components/app/modals/confirm-remove-account/confirm-remove-account.test.js @@ -1,6 +1,7 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import { fireEvent } from '@testing-library/react'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { renderWithProvider } from '../../../../../test/lib/render-helpers'; import ConfirmRemoveAccount from '.'; @@ -22,16 +23,8 @@ describe('Confirm Remove Account', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -52,16 +45,8 @@ describe('Confirm Remove Account', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + mmethods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, chainId: '0x99', rpcPrefs: {}, diff --git a/ui/components/app/nfts-tab/nfts-tab.test.js b/ui/components/app/nfts-tab/nfts-tab.test.js index 98ac3a2a0752..967a88706def 100644 --- a/ui/components/app/nfts-tab/nfts-tab.test.js +++ b/ui/components/app/nfts-tab/nfts-tab.test.js @@ -1,6 +1,7 @@ import React from 'react'; import { fireEvent, screen } from '@testing-library/react'; import reactRouterDom from 'react-router-dom'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import configureStore from '../../../store/store'; import { renderWithProvider } from '../../../../test/jest/rendering'; import { SECURITY_ROUTE } from '../../../helpers/constants/routes'; @@ -176,16 +177,8 @@ const render = ({ }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/components/app/signature-request-original/signature-request-original.test.js b/ui/components/app/signature-request-original/signature-request-original.test.js index 90205535a0b1..67fdb25953d2 100644 --- a/ui/components/app/signature-request-original/signature-request-original.test.js +++ b/ui/components/app/signature-request-original/signature-request-original.test.js @@ -2,6 +2,7 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import { fireEvent, screen } from '@testing-library/react'; import { act } from 'react-dom/test-utils'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { MESSAGE_TYPE } from '../../../../shared/constants/app'; import { SECURITY_PROVIDER_MESSAGE_SEVERITY } from '../../../../shared/constants/security-provider'; import mockState from '../../../../test/data/mock-state.json'; @@ -73,16 +74,8 @@ const props = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }; diff --git a/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js b/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js index e3132e1e011b..33c9ac602c49 100644 --- a/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js +++ b/ui/components/app/signature-request/signature-request-data/signature-request-data.test.js @@ -1,5 +1,6 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { renderWithProvider } from '../../../../../test/lib/render-helpers'; import { sanitizeMessage } from '../../../../helpers/utils/util'; import Identicon from '../../../ui/identicon'; @@ -50,16 +51,8 @@ describe('Signature Request Data', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '07c2cfec-36c9-46c4-8115-3836d3ac9047': { address: '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF', @@ -71,16 +64,8 @@ describe('Signature Request Data', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/components/app/signature-request/signature-request.test.js b/ui/components/app/signature-request/signature-request.test.js index 0ee506c08ec6..e1d6647a6bdb 100644 --- a/ui/components/app/signature-request/signature-request.test.js +++ b/ui/components/app/signature-request/signature-request.test.js @@ -2,6 +2,7 @@ import React from 'react'; import { useSelector } from 'react-redux'; import { fireEvent } from '@testing-library/react'; import configureMockStore from 'redux-mock-store'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import mockState from '../../../../test/data/mock-state.json'; import { renderWithProvider } from '../../../../test/lib/render-helpers'; import { SECURITY_PROVIDER_MESSAGE_SEVERITY } from '../../../../shared/constants/security-provider'; @@ -62,16 +63,8 @@ const mockStore = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -494,16 +487,8 @@ describe('Signature Request Component', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { address: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', @@ -515,16 +500,8 @@ describe('Signature Request Component', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'b7e813d6-e31c-4bad-8615-8d4eff9f44f1', diff --git a/ui/components/app/transaction-status-label/transaction-status-label.test.js b/ui/components/app/transaction-status-label/transaction-status-label.test.js index 392d86ee22e9..da9923d3e803 100644 --- a/ui/components/app/transaction-status-label/transaction-status-label.test.js +++ b/ui/components/app/transaction-status-label/transaction-status-label.test.js @@ -1,6 +1,7 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { renderWithProvider } from '../../../../test/lib/render-helpers'; import TransactionStatusLabel from '.'; @@ -21,16 +22,8 @@ describe('TransactionStatusLabel Component', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -151,16 +144,8 @@ describe('TransactionStatusLabel Component', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -213,16 +198,8 @@ describe('TransactionStatusLabel Component', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -277,16 +254,8 @@ describe('TransactionStatusLabel Component', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/components/app/wallet-overview/eth-overview.test.js b/ui/components/app/wallet-overview/eth-overview.test.js index 05042b20022a..8d948afb0435 100644 --- a/ui/components/app/wallet-overview/eth-overview.test.js +++ b/ui/components/app/wallet-overview/eth-overview.test.js @@ -2,6 +2,7 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; import { fireEvent, waitFor } from '@testing-library/react'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { CHAIN_IDS } from '../../../../shared/constants/network'; import { renderWithProvider } from '../../../../test/jest/rendering'; import { KeyringType } from '../../../../shared/constants/keyring'; @@ -60,16 +61,8 @@ describe('EthOverview', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, 'e9b992f9-e151-4317-b8b7-c771bb73dd02': { address: '0x2', @@ -81,16 +74,8 @@ describe('EthOverview', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/components/app/wallet-overview/token-overview.test.js b/ui/components/app/wallet-overview/token-overview.test.js index 0de727d78b55..8cfffae1105d 100644 --- a/ui/components/app/wallet-overview/token-overview.test.js +++ b/ui/components/app/wallet-overview/token-overview.test.js @@ -2,6 +2,7 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; import { fireEvent, waitFor } from '@testing-library/react'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { CHAIN_IDS } from '../../../../shared/constants/network'; import { renderWithProvider } from '../../../../test/jest/rendering'; import { KeyringType } from '../../../../shared/constants/keyring'; @@ -47,16 +48,8 @@ describe('TokenOverview', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.js b/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.js index 69aaec27066a..a5cc0c435ac1 100644 --- a/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.js +++ b/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.js @@ -2,6 +2,7 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; import { screen, fireEvent } from '@testing-library/react'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { act } from 'react-dom/test-utils'; import { sha256 } from '../../../../shared/modules/hash.utils'; import { KeyringType } from '../../../../shared/constants/keyring'; @@ -57,16 +58,8 @@ describe('Interactive Replacement Token Notification', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount, diff --git a/ui/components/institutional/wrong-network-notification/wrong-network-notification.test.js b/ui/components/institutional/wrong-network-notification/wrong-network-notification.test.js index b63a681f9153..af1fe5a8c756 100644 --- a/ui/components/institutional/wrong-network-notification/wrong-network-notification.test.js +++ b/ui/components/institutional/wrong-network-notification/wrong-network-notification.test.js @@ -1,5 +1,6 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { renderWithProvider } from '../../../../test/lib/render-helpers'; import testData from '../../../../.storybook/test-data'; import WrongNetworkNotification from '.'; @@ -39,16 +40,8 @@ describe('Wrong Network Notification', function () { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/components/multichain/account-list-item/account-list-item.test.js b/ui/components/multichain/account-list-item/account-list-item.test.js index 31051f203ceb..cd846ca8c2f5 100644 --- a/ui/components/multichain/account-list-item/account-list-item.test.js +++ b/ui/components/multichain/account-list-item/account-list-item.test.js @@ -2,6 +2,7 @@ import React from 'react'; import { screen, fireEvent } from '@testing-library/react'; import { toChecksumHexAddress } from '@metamask/controller-utils'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { renderWithProvider } from '../../../../test/jest'; import configureStore from '../../../store/store'; import mockState from '../../../../test/data/mock-state.json'; @@ -119,16 +120,8 @@ describe('AccountListItem', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }); diff --git a/ui/components/multichain/account-list-menu/account-list-menu.test.js b/ui/components/multichain/account-list-menu/account-list-menu.test.js index d7981860e925..07715f71e52b 100644 --- a/ui/components/multichain/account-list-menu/account-list-menu.test.js +++ b/ui/components/multichain/account-list-menu/account-list-menu.test.js @@ -1,6 +1,7 @@ /* eslint-disable jest/require-top-level-describe */ import React from 'react'; import reactRouterDom from 'react-router-dom'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { fireEvent, renderWithProvider, waitFor } from '../../../../test/jest'; import configureStore from '../../../store/store'; import mockState from '../../../../test/data/mock-state.json'; @@ -149,16 +150,8 @@ describe('AccountListMenu', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, }, diff --git a/ui/components/multichain/connected-site-menu/connected-site-menu.test.js b/ui/components/multichain/connected-site-menu/connected-site-menu.test.js index dc5ea74d6a21..08e9df0b907c 100644 --- a/ui/components/multichain/connected-site-menu/connected-site-menu.test.js +++ b/ui/components/multichain/connected-site-menu/connected-site-menu.test.js @@ -1,5 +1,6 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { renderWithProvider } from '../../../../test/jest'; import { STATUS_CONNECTED, @@ -25,16 +26,8 @@ describe('Connected Site Menu', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '07c2cfec-36c9-46c4-8115-3836d3ac9047': { address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', @@ -46,16 +39,8 @@ describe('Connected Site Menu', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: '07c2cfec-36c9-46c4-8115-3836d3ac9047', diff --git a/ui/components/multichain/create-account/create-account.test.js b/ui/components/multichain/create-account/create-account.test.js index 2efd7f96ee4c..84a6a5e94d8a 100644 --- a/ui/components/multichain/create-account/create-account.test.js +++ b/ui/components/multichain/create-account/create-account.test.js @@ -1,5 +1,6 @@ /* eslint-disable jest/require-top-level-describe */ import React from 'react'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { fireEvent, renderWithProvider, waitFor } from '../../../../test/jest'; import configureStore from '../../../store/store'; import mockState from '../../../../test/data/mock-state.json'; @@ -20,16 +21,8 @@ const mockInternalAccount = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }; const mockAddNewAccount = jest.fn().mockReturnValue(mockInternalAccount); diff --git a/ui/components/multichain/select-action-modal/select-action-modal.test.js b/ui/components/multichain/select-action-modal/select-action-modal.test.js index a67d69f1e732..6e2e41b42993 100644 --- a/ui/components/multichain/select-action-modal/select-action-modal.test.js +++ b/ui/components/multichain/select-action-modal/select-action-modal.test.js @@ -2,6 +2,7 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; import { fireEvent, waitFor } from '@testing-library/react'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import mockState from '../../../../test/data/mock-state.json'; import { renderWithProvider } from '../../../../test/jest/rendering'; @@ -76,16 +77,8 @@ describe('Select Action Modal', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/ducks/app/app.test.js b/ui/ducks/app/app.test.js index ff9293f18be9..4b26aa826f98 100644 --- a/ui/ducks/app/app.test.js +++ b/ui/ducks/app/app.test.js @@ -1,3 +1,4 @@ +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import * as actionConstants from '../../store/actionConstants'; import { HardwareDeviceNames } from '../../../shared/constants/hardware-wallets'; import reduceApp from './app'; @@ -18,16 +19,8 @@ describe('App State', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'mock-id', diff --git a/ui/ducks/metamask/metamask.test.js b/ui/ducks/metamask/metamask.test.js index 8bbd7654c15b..dca2830186b4 100644 --- a/ui/ducks/metamask/metamask.test.js +++ b/ui/ducks/metamask/metamask.test.js @@ -1,5 +1,6 @@ import { NetworkType } from '@metamask/controller-utils'; import { NetworkStatus } from '@metamask/network-controller'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { TransactionStatus } from '../../../shared/constants/transaction'; import * as actionConstants from '../../store/actionConstants'; import reduceMetamask, { @@ -31,16 +32,8 @@ describe('MetaMask Reducers', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '07c2cfec-36c9-46c4-8115-3836d3ac9047': { address: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb', @@ -52,16 +45,8 @@ describe('MetaMask Reducers', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '15e69915-2a1a-4019-93b3-916e11fd432f': { address: '0x2f8d4a878cfa04a6e60d46362f5644deab66572d', @@ -73,16 +58,8 @@ describe('MetaMask Reducers', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '784225f4-d30b-4e77-a900-c8bbce735b88': { address: '0xd85a4b6a394794842887b8284293d69163007bbb', @@ -94,16 +71,8 @@ describe('MetaMask Reducers', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -207,16 +176,8 @@ describe('MetaMask Reducers', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -244,16 +205,8 @@ describe('MetaMask Reducers', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -279,16 +232,8 @@ describe('MetaMask Reducers', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }); }); @@ -441,16 +386,8 @@ describe('MetaMask Reducers', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, code: '0x', balance: '0x47c9d71831c76efe', nonce: '0x1b', @@ -465,16 +402,8 @@ describe('MetaMask Reducers', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, code: '0x', balance: '0x37452b1315889f80', nonce: '0xa', @@ -489,16 +418,8 @@ describe('MetaMask Reducers', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, code: '0x', balance: '0x30c9d71831c76efe', nonce: '0x1c', @@ -513,16 +434,8 @@ describe('MetaMask Reducers', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, code: '0x', balance: '0x0', nonce: '0x0', diff --git a/ui/ducks/send/send.test.js b/ui/ducks/send/send.test.js index c2c1ac6d589e..e83496651ec7 100644 --- a/ui/ducks/send/send.test.js +++ b/ui/ducks/send/send.test.js @@ -4,6 +4,7 @@ import thunk from 'redux-thunk'; import { BigNumber } from '@ethersproject/bignumber'; import { NetworkType } from '@metamask/controller-utils'; import { NetworkStatus } from '@metamask/network-controller'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { CONTRACT_ADDRESS_ERROR, INSUFFICIENT_FUNDS_ERROR, @@ -1295,16 +1296,8 @@ describe('Send Slice', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -1470,16 +1463,8 @@ describe('Send Slice', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'mock-id', @@ -1552,16 +1537,8 @@ describe('Send Slice', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'mock-id', @@ -1633,16 +1610,8 @@ describe('Send Slice', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'mock-id', @@ -1707,16 +1676,8 @@ describe('Send Slice', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -1941,16 +1902,8 @@ describe('Send Slice', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -2268,16 +2221,8 @@ describe('Send Slice', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -2447,16 +2392,8 @@ describe('Send Slice', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'mock-id', @@ -2647,16 +2584,8 @@ describe('Send Slice', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -2736,16 +2665,8 @@ describe('Send Slice', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, gas: { error: null, @@ -2833,16 +2754,8 @@ describe('Send Slice', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -2924,16 +2837,8 @@ describe('Send Slice', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, gas: { error: null, @@ -3030,16 +2935,8 @@ describe('Send Slice', () => { address: mockAddress1, id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, metadata: { name: 'Test Account', keyring: { @@ -3153,16 +3050,8 @@ describe('Send Slice', () => { balance: '0x0', id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, metadata: { name: 'Test Account', keyring: { diff --git a/ui/hooks/useAddressDetails.test.js b/ui/hooks/useAddressDetails.test.js index 4db47e8a91ab..0773ebe8d264 100644 --- a/ui/hooks/useAddressDetails.test.js +++ b/ui/hooks/useAddressDetails.test.js @@ -1,6 +1,7 @@ import React from 'react'; import { Provider } from 'react-redux'; import { renderHook } from '@testing-library/react-hooks'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import configureStore from '../store/store'; import useAddressDetails from './useAddressDetails'; @@ -25,16 +26,8 @@ const renderUseAddressDetails = (toAddress, stateVariables = {}) => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -96,16 +89,8 @@ describe('useAddressDetails', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/hooks/useAssetDetails.test.js b/ui/hooks/useAssetDetails.test.js index 7ddbb19db534..a62091ac228b 100644 --- a/ui/hooks/useAssetDetails.test.js +++ b/ui/hooks/useAssetDetails.test.js @@ -1,6 +1,7 @@ import React from 'react'; import { Provider } from 'react-redux'; import { renderHook } from '@testing-library/react-hooks'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import configureStore from '../store/store'; import * as Actions from '../store/actions'; @@ -32,16 +33,8 @@ const renderUseAssetDetails = ({ }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/pages/confirm-add-suggested-token/confirm-add-suggested-token.test.js b/ui/pages/confirm-add-suggested-token/confirm-add-suggested-token.test.js index 2d26ac98bc9e..52c3f3555096 100644 --- a/ui/pages/confirm-add-suggested-token/confirm-add-suggested-token.test.js +++ b/ui/pages/confirm-add-suggested-token/confirm-add-suggested-token.test.js @@ -2,6 +2,7 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; import { fireEvent, screen } from '@testing-library/react'; import { ApprovalType } from '@metamask/controller-utils'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { resolvePendingApproval, rejectPendingApproval, @@ -74,16 +75,8 @@ const renderComponent = (tokens = []) => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/pages/confirm-decrypt-message/confirm-decrypt-message.component.test.js b/ui/pages/confirm-decrypt-message/confirm-decrypt-message.component.test.js index fb4231351d8a..bdd49dd21369 100644 --- a/ui/pages/confirm-decrypt-message/confirm-decrypt-message.component.test.js +++ b/ui/pages/confirm-decrypt-message/confirm-decrypt-message.component.test.js @@ -1,5 +1,6 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import mockState from '../../../test/data/mock-state.json'; import { renderWithProvider } from '../../../test/lib/render-helpers'; import ConfirmDecryptMessage from './confirm-decrypt-message.component'; @@ -88,16 +89,8 @@ const baseProps = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }; diff --git a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.test.js b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.test.js index d039c2174c9d..1cd76046bd4a 100644 --- a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.test.js +++ b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.test.js @@ -1,5 +1,6 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import mockState from '../../../test/data/mock-state.json'; import { renderWithProvider } from '../../../test/lib/render-helpers'; import ConfirmEncryptionPublicKey from './confirm-encryption-public-key.component'; @@ -37,16 +38,8 @@ const baseProps = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, name: 'Antonio', }, }; diff --git a/ui/pages/confirm-signature-request/index.test.js b/ui/pages/confirm-signature-request/index.test.js index 99e79e6b009b..f75a0e30aee2 100644 --- a/ui/pages/confirm-signature-request/index.test.js +++ b/ui/pages/confirm-signature-request/index.test.js @@ -1,5 +1,6 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { renderWithProvider } from '../../../test/lib/render-helpers'; import ConfTx from '.'; @@ -43,16 +44,8 @@ const mockState = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/pages/confirm-transaction-base/confirm-transaction-base.test.js b/ui/pages/confirm-transaction-base/confirm-transaction-base.test.js index 0fa23efaa145..85092c079ae6 100644 --- a/ui/pages/confirm-transaction-base/confirm-transaction-base.test.js +++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.test.js @@ -5,6 +5,7 @@ import { fireEvent } from '@testing-library/react'; import { NetworkType } from '@metamask/controller-utils'; import { NetworkStatus } from '@metamask/network-controller'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { renderWithProvider } from '../../../test/lib/render-helpers'; import { setBackgroundConnection } from '../../../test/jest'; import { INITIAL_SEND_STATE_FOR_EXISTING_DRAFT } from '../../../test/jest/mocks'; @@ -130,16 +131,8 @@ const baseStore = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/pages/connected-accounts/connected-accounts.stories.js b/ui/pages/connected-accounts/connected-accounts.stories.js index ea9a997db08e..7f158c14148f 100644 --- a/ui/pages/connected-accounts/connected-accounts.stories.js +++ b/ui/pages/connected-accounts/connected-accounts.stories.js @@ -1,5 +1,6 @@ import React from 'react'; import { action } from '@storybook/addon-actions'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import ConnectedAccounts from './connected-accounts.component'; export default { @@ -17,16 +18,8 @@ const accounts = [ }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, { address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', @@ -38,16 +31,8 @@ const accounts = [ }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, ]; diff --git a/ui/pages/send/send.test.js b/ui/pages/send/send.test.js index f1d3f284e1af..6408936275cb 100644 --- a/ui/pages/send/send.test.js +++ b/ui/pages/send/send.test.js @@ -3,6 +3,7 @@ import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; import { useLocation } from 'react-router-dom'; import { NetworkType } from '@metamask/controller-utils'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { SEND_STAGES, startNewDraftTransaction } from '../../ducks/send'; import { domainInitialState } from '../../ducks/domains'; import { CHAIN_IDS } from '../../../shared/constants/network'; @@ -91,16 +92,8 @@ const baseStore = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/pages/token-allowance/token-allowance.test.js b/ui/pages/token-allowance/token-allowance.test.js index cba30a5b5782..53b73f10e12f 100644 --- a/ui/pages/token-allowance/token-allowance.test.js +++ b/ui/pages/token-allowance/token-allowance.test.js @@ -4,6 +4,7 @@ import { act, fireEvent } from '@testing-library/react'; import thunk from 'redux-thunk'; import { NetworkType } from '@metamask/controller-utils'; import { NetworkStatus } from '@metamask/network-controller'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { renderWithProvider } from '../../../test/lib/render-helpers'; import { KeyringType } from '../../../shared/constants/keyring'; import TokenAllowance from './token-allowance'; @@ -34,16 +35,8 @@ const state = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '07c2cfec-36c9-46c4-8115-3836d3ac9047': { address: '0xc42edfcc21ed14dda456aa0756c153f7985d8813', @@ -55,16 +48,8 @@ const state = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/pages/token-details/token-details-page.test.js b/ui/pages/token-details/token-details-page.test.js index 9b872f84932e..18e505cdc073 100644 --- a/ui/pages/token-details/token-details-page.test.js +++ b/ui/pages/token-details/token-details-page.test.js @@ -1,6 +1,7 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import { fireEvent } from '@testing-library/react'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { renderWithProvider } from '../../../test/lib/render-helpers'; import Identicon from '../../components/ui/identicon'; import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils'; @@ -21,16 +22,8 @@ const state = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '07c2cfec-36c9-46c4-8115-3836d3ac9047': { address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', @@ -42,16 +35,8 @@ const state = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '15e69915-2a1a-4019-93b3-916e11fd432f': { address: '0xc42edfcc21ed14dda456aa0756c153f7985d8813', @@ -63,16 +48,8 @@ const state = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '784225f4-d30b-4e77-a900-c8bbce735b88': { address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', @@ -84,16 +61,8 @@ const state = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/selectors/institutional/selectors.test.js b/ui/selectors/institutional/selectors.test.js index be995eef7719..8c2d4cbe40d8 100644 --- a/ui/selectors/institutional/selectors.test.js +++ b/ui/selectors/institutional/selectors.test.js @@ -1,4 +1,5 @@ import { toChecksumAddress } from 'ethereumjs-util'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { toHex } from '@metamask/controller-utils'; import { getConfiguredCustodians, @@ -31,16 +32,8 @@ function buildState(overrides = {}) { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, code: '0x', balance: '0x47c9d71831c76efe', nonce: '0x1b', @@ -190,16 +183,8 @@ describe('Institutional selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, code: '0x', balance: '0x47c9d71831c76efe', nonce: '0x1b', @@ -239,16 +224,8 @@ describe('Institutional selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, code: '0x', balance: '0x47c9d71831c76efe', nonce: '0x1b', @@ -299,16 +276,8 @@ describe('Institutional selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/selectors/nonce-sorted-transactions-selector.test.js b/ui/selectors/nonce-sorted-transactions-selector.test.js index 02149b149e03..9af5ff457d66 100644 --- a/ui/selectors/nonce-sorted-transactions-selector.test.js +++ b/ui/selectors/nonce-sorted-transactions-selector.test.js @@ -1,4 +1,5 @@ import { head, last } from 'lodash'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { CHAIN_IDS } from '../../shared/constants/network'; import { TransactionStatus, @@ -92,16 +93,8 @@ const getStateTree = ({ }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/selectors/permissions.test.js b/ui/selectors/permissions.test.js index 4dc843f44452..d003e92de8cd 100644 --- a/ui/selectors/permissions.test.js +++ b/ui/selectors/permissions.test.js @@ -1,3 +1,4 @@ +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { CHAIN_IDS } from '../../shared/constants/network'; import { getConnectedSubjectsForSelectedAddress, @@ -23,16 +24,8 @@ describe('selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -115,16 +108,8 @@ describe('selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -272,16 +257,8 @@ describe('selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '07c2cfec-36c9-46c4-8115-3836d3ac9047': { address: '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5', @@ -294,16 +271,8 @@ describe('selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '15e69915-2a1a-4019-93b3-916e11fd432f': { address: '0xb3958fb96c8201486ae20be1d5c9f58083df343a', @@ -317,16 +286,8 @@ describe('selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '784225f4-d30b-4e77-a900-c8bbce735b88': { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', @@ -339,16 +300,8 @@ describe('selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, 'f9305241-c50f-4725-ad0f-cbd3f24ac7ab': { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', @@ -360,16 +313,8 @@ describe('selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -416,16 +361,8 @@ describe('selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, { address: '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5', @@ -440,16 +377,8 @@ describe('selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, { address: '0xb3958fb96c8201486ae20be1d5c9f58083df343a', @@ -464,16 +393,8 @@ describe('selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', @@ -488,16 +409,8 @@ describe('selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, { address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', @@ -511,16 +424,8 @@ describe('selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, ]); }); @@ -574,16 +479,8 @@ describe('selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '07c2cfec-36c9-46c4-8115-3836d3ac9047': { address: '0x8e5d75d60224ea0c33d0041e75de68b1c3cb6dd5', @@ -595,16 +492,8 @@ describe('selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, '15e69915-2a1a-4019-93b3-916e11fd432f': { address: '0xb3958fb96c8201486ae20be1d5c9f58083df343a', @@ -616,16 +505,8 @@ describe('selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/selectors/selectors.test.js b/ui/selectors/selectors.test.js index 910d6cd5819f..27125c8a19bc 100644 --- a/ui/selectors/selectors.test.js +++ b/ui/selectors/selectors.test.js @@ -1,5 +1,6 @@ import { deepClone } from '@metamask/snaps-utils'; import { ApprovalType, NetworkType } from '@metamask/controller-utils'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import mockState from '../../test/data/mock-state.json'; import { KeyringType } from '../../shared/constants/keyring'; import { @@ -473,16 +474,8 @@ describe('Selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }); }); diff --git a/ui/selectors/transactions.test.js b/ui/selectors/transactions.test.js index 6061b372ca6d..fbc92d0313c7 100644 --- a/ui/selectors/transactions.test.js +++ b/ui/selectors/transactions.test.js @@ -1,4 +1,5 @@ import { ApprovalType } from '@metamask/controller-utils'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import { CHAIN_IDS } from '../../shared/constants/network'; import { TransactionStatus } from '../../shared/constants/transaction'; import { @@ -46,16 +47,8 @@ describe('Transaction Selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -152,16 +145,8 @@ describe('Transaction Selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -241,16 +226,8 @@ describe('Transaction Selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -348,16 +325,8 @@ describe('Transaction Selectors', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', diff --git a/ui/store/actionConstants.test.js b/ui/store/actionConstants.test.js index 1507503145b8..a8493d7e3d82 100644 --- a/ui/store/actionConstants.test.js +++ b/ui/store/actionConstants.test.js @@ -1,4 +1,5 @@ import freeze from 'deep-freeze-strict'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import reducers from '../ducks'; import * as actionConstants from './actionConstants'; @@ -21,16 +22,8 @@ describe('Redux actionConstants', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, }, diff --git a/ui/store/actions.test.js b/ui/store/actions.test.js index 5bb8c81db820..1a316f7b9a4b 100644 --- a/ui/store/actions.test.js +++ b/ui/store/actions.test.js @@ -1,6 +1,7 @@ import sinon from 'sinon'; import configureStore from 'redux-mock-store'; import thunk from 'redux-thunk'; +import { EthAccountType, EthMethod } from '@metamask/keyring-api'; import enLocale from '../../app/_locales/en/messages.json'; import MetaMaskController from '../../app/scripts/metamask-controller'; import { TransactionStatus } from '../../shared/constants/transaction'; @@ -33,16 +34,8 @@ const defaultState = { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', @@ -272,16 +265,8 @@ describe('Actions', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: '22497cc9-e791-42b8-adef-2f13ef216b86', @@ -504,16 +489,8 @@ describe('Actions', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, ], }), @@ -1997,16 +1974,8 @@ describe('Actions', () => { }, }, options: {}, - methods: [ - 'personal_sign', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v1', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - ], - type: 'eip155:eoa', + methods: [...Object.values(EthMethod)], + type: EthAccountType.Eoa, }, }, selectedAccount: '8e110453-2231-4e62-82de-29b913dfef4b', From a8a6c07bff923c21c2200216c99b7250138775d4 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Fri, 8 Sep 2023 11:27:30 +0800 Subject: [PATCH 099/235] fix: update keyring controller and metametrics to use accounts controller --- app/scripts/controllers/metametrics.js | 2 +- app/scripts/controllers/metametrics.test.js | 174 +++++++++++++++++++- app/scripts/controllers/preferences.js | 158 ------------------ app/scripts/metamask-controller.js | 85 ++++++---- app/scripts/metamask-controller.test.js | 110 ++++++++----- lavamoat/browserify/beta/policy.json | 22 --- lavamoat/browserify/desktop/policy.json | 22 --- lavamoat/browserify/flask/policy.json | 22 --- lavamoat/browserify/main/policy.json | 22 --- lavamoat/browserify/mmi/policy.json | 22 --- 10 files changed, 289 insertions(+), 350 deletions(-) diff --git a/app/scripts/controllers/metametrics.js b/app/scripts/controllers/metametrics.js index 20a7cdcb5493..2ec41f1b58d5 100644 --- a/app/scripts/controllers/metametrics.js +++ b/app/scripts/controllers/metametrics.js @@ -747,7 +747,7 @@ export default class MetaMetricsController { [MetaMetricsUserTrait.NftAutodetectionEnabled]: metamaskState.useNftDetection, [MetaMetricsUserTrait.NumberOfAccounts]: Object.values( - metamaskState.identities, + metamaskState.internalAccounts.accounts, ).length, [MetaMetricsUserTrait.NumberOfNftCollections]: this._getAllUniqueNFTAddressesLength(metamaskState.allNfts), diff --git a/app/scripts/controllers/metametrics.test.js b/app/scripts/controllers/metametrics.test.js index 09170d4eee8f..081e24dcb5ac 100644 --- a/app/scripts/controllers/metametrics.test.js +++ b/app/scripts/controllers/metametrics.test.js @@ -12,6 +12,7 @@ import waitUntilCalled from '../../../test/lib/wait-until-called'; import { CHAIN_IDS, CURRENCY_SYMBOLS } from '../../../shared/constants/network'; import * as Utils from '../lib/util'; import MetaMetricsController from './metametrics'; +import { EthAccountType } from '@metamask/keyring-api'; const segment = createSegmentMock(2, 10000); @@ -946,7 +947,37 @@ describe('MetaMetricsController', function () { }, 'network-configuration-id-3': { chainId: '0xaf' }, }, - identities: [{}, {}], + internalAccounts: { + accounts: { + 'mock-id': { + address: '0x0', + id: 'mock-id', + metadata: { + name: 'Account 1', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [...Object.values(EthAccountType)], + type: EthAccountType.Eoa, + }, + 'mock-id-2': { + address: '0x1', + id: 'mock-id-2', + metadata: { + name: 'Account 2', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [...Object.values(EthAccountType)], + type: EthAccountType.Eoa, + }, + }, + selectedAccount: 'mock-id', + }, ledgerTransportType: 'web-hid', openSeaEnabled: true, useNftDetection: false, @@ -999,7 +1030,37 @@ describe('MetaMetricsController', function () { }, ledgerTransportType: 'web-hid', openSeaEnabled: true, - identities: [{}, {}], + internalAccounts: { + accounts: { + 'mock-id': { + address: '0x0', + id: 'mock-id', + metadata: { + name: 'Account 1', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [...Object.values(EthAccountType)], + type: EthAccountType.Eoa, + }, + 'mock-id-2': { + address: '0x1', + id: 'mock-id-2', + metadata: { + name: 'Account 2', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [...Object.values(EthAccountType)], + type: EthAccountType.Eoa, + }, + }, + selectedAccount: 'mock-id', + }, useNftDetection: false, theme: 'default', useTokenDetection: true, @@ -1022,7 +1083,50 @@ describe('MetaMetricsController', function () { }, ledgerTransportType: 'web-hid', openSeaEnabled: false, - identities: [{}, {}, {}], + internalAccounts: { + accounts: { + 'mock-id': { + address: '0x0', + id: 'mock-id', + metadata: { + name: 'Account 1', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [...Object.values(EthAccountType)], + type: EthAccountType.Eoa, + }, + 'mock-id-2': { + address: '0x1', + id: 'mock-id-2', + metadata: { + name: 'Account 2', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [...Object.values(EthAccountType)], + type: EthAccountType.Eoa, + }, + 'mock-id-3': { + address: '0x2', + id: 'mock-id-3', + metadata: { + name: 'Account 3', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [...Object.values(EthAccountType)], + type: EthAccountType.Eoa, + }, + }, + selectedAccount: 'mock-id', + }, useNftDetection: false, theme: 'default', useTokenDetection: true, @@ -1051,7 +1155,37 @@ describe('MetaMetricsController', function () { }, ledgerTransportType: 'web-hid', openSeaEnabled: true, - identities: [{}, {}], + internalAccounts: { + accounts: { + 'mock-id': { + address: '0x0', + id: 'mock-id', + metadata: { + name: 'Account 1', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [...Object.values(EthAccountType)], + type: EthAccountType.Eoa, + }, + 'mock-id-2': { + address: '0x1', + id: 'mock-id-2', + metadata: { + name: 'Account 2', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [...Object.values(EthAccountType)], + type: EthAccountType.Eoa, + }, + }, + selectedAccount: 'mock-id', + }, useNftDetection: true, theme: 'default', useTokenDetection: true, @@ -1070,7 +1204,37 @@ describe('MetaMetricsController', function () { }, ledgerTransportType: 'web-hid', openSeaEnabled: true, - identities: [{}, {}], + internalAccounts: { + accounts: { + 'mock-id': { + address: '0x0', + id: 'mock-id', + metadata: { + name: 'Account 1', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [...Object.values(EthAccountType)], + type: EthAccountType.Eoa, + }, + 'mock-id-2': { + address: '0x1', + id: 'mock-id-2', + metadata: { + name: 'Account 2', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [...Object.values(EthAccountType)], + type: EthAccountType.Eoa, + }, + }, + selectedAccount: 'mock-id', + }, useNftDetection: true, theme: 'default', useTokenDetection: true, diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 5c1f169834ab..51f3cc0fd4d2 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -1,5 +1,4 @@ import { ObservableStore } from '@metamask/obs-store'; -import { normalize as normalizeAddress } from 'eth-sig-util'; import { CHAIN_IDS, IPFS_DEFAULT_GATEWAY_URL, @@ -36,7 +35,6 @@ export default class PreferencesController { * Feature flags can be set by the global function `setPreference(feature, enabled)`, and so should not expose any sensitive behavior. * @property {object} store.knownMethodData Contains all data methods known by the user * @property {string} store.currentLocale The preferred language locale key - * @property {string} store.selectedAddress A hex string that matches the currently selected address in the app */ constructor(opts = {}) { const addedNonMainNetwork = Object.values( @@ -80,7 +78,6 @@ export default class PreferencesController { }, knownMethodData: {}, currentLocale: opts.initLangCode, - identities: {}, lostIdentities: {}, forgottenPassword: false, preferences: { @@ -305,161 +302,6 @@ export default class PreferencesController { return textDirection; } - /** - * Updates identities to only include specified addresses. Removes identities - * not included in addresses array - * - * @param {string[]} addresses - An array of hex addresses - */ - setAddresses(addresses) { - const oldIdentities = this.store.getState().identities; - - const identities = addresses.reduce((ids, address, index) => { - const oldId = oldIdentities[address] || {}; - ids[address] = { name: `Account ${index + 1}`, address, ...oldId }; - return ids; - }, {}); - - this.store.updateState({ identities }); - } - - /** - * Removes an address from state - * - * @param {string} address - A hex address - * @returns {string} the address that was removed - */ - removeAddress(address) { - const { identities } = this.store.getState(); - - if (!identities[address]) { - throw new Error(`${address} can't be deleted cause it was not found`); - } - delete identities[address]; - this.store.updateState({ identities }); - - // If the selected account is no longer valid, - // select an arbitrary other account: - if (address === this.getSelectedAddress()) { - const [selected] = Object.keys(identities); - this.setSelectedAddress(selected); - } - - return address; - } - - /** - * Adds addresses to the identities object without removing identities - * - * @param {string[]} addresses - An array of hex addresses - */ - addAddresses(addresses) { - const { identities } = this.store.getState(); - addresses.forEach((address) => { - // skip if already exists - if (identities[address]) { - return; - } - // add missing identity - const identityCount = Object.keys(identities).length; - - identities[address] = { name: `Account ${identityCount + 1}`, address }; - }); - this.store.updateState({ identities }); - } - - /** - * Synchronizes identity entries with known accounts. - * Removes any unknown identities, and returns the resulting selected address. - * - * @param {Array} addresses - known to the vault. - * @returns {Promise} selectedAddress the selected address. - */ - syncAddresses(addresses) { - if (!Array.isArray(addresses) || addresses.length === 0) { - throw new Error('Expected non-empty array of addresses. Error #11201'); - } - - const { identities, lostIdentities } = this.store.getState(); - - const newlyLost = {}; - Object.keys(identities).forEach((identity) => { - if (!addresses.includes(identity)) { - newlyLost[identity] = identities[identity]; - delete identities[identity]; - } - }); - - // Identities are no longer present. - if (Object.keys(newlyLost).length > 0) { - // store lost accounts - Object.keys(newlyLost).forEach((key) => { - lostIdentities[key] = newlyLost[key]; - }); - } - - this.store.updateState({ identities, lostIdentities }); - this.addAddresses(addresses); - - // If the selected account is no longer valid, - // select an arbitrary other account: - let selected = this.getSelectedAddress(); - if (!addresses.includes(selected)) { - [selected] = addresses; - this.setSelectedAddress(selected); - } - - return selected; - } - - /** - * Setter for the `selectedAddress` property - * - * @param {string} _address - A new hex address for an account - */ - setSelectedAddress(_address) { - const address = normalizeAddress(_address); - - const { identities } = this.store.getState(); - const selectedIdentity = identities[address]; - if (!selectedIdentity) { - throw new Error(`Identity for '${address} not found`); - } - - selectedIdentity.lastSelected = Date.now(); - this.store.updateState({ identities, selectedAddress: address }); - } - - /** - * Getter for the `selectedAddress` property - * - * @returns {string} The hex address for the currently selected account - */ - getSelectedAddress() { - return this.store.getState().selectedAddress; - } - - /** - * Sets a custom label for an account - * - * @param {string} account - the account to set a label for - * @param {string} label - the custom label for the account - * @returns {Promise} - */ - async setAccountLabel(account, label) { - if (!account) { - throw new Error( - `setAccountLabel requires a valid address, got ${String(account)}`, - ); - } - const address = normalizeAddress(account); - const { identities } = this.store.getState(); - identities[address] = identities[address] || {}; - identities[address].name = label; - this.store.updateState({ identities }); - return label; - } - /** * Updates the `featureFlags` property, which is an object. One property within that object will be set to a boolean. * diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 0104db8352e1..4549e7f55397 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -805,21 +805,36 @@ export default class MetamaskController extends EventEmitter { encryptor: opts.encryptor || undefined, cacheEncryptionKey: isManifestV3, messenger: keyringControllerMessenger, - removeIdentity: this.preferencesController.removeAddress.bind( - this.preferencesController, - ), - setAccountLabel: this.preferencesController.setAccountLabel.bind( - this.preferencesController, - ), - setSelectedAddress: this.preferencesController.setSelectedAddress.bind( - this.preferencesController, - ), - syncIdentities: this.preferencesController.syncAddresses.bind( - this.preferencesController, - ), - updateIdentities: this.preferencesController.setAddresses.bind( - this.preferencesController, - ), + removeIdentity: async () => + await this.accountsController.updateAccounts(), + setAccountLabel: (address, label) => { + const accountToBeNamed = this.accountsController + .listAccounts() + .find( + (account) => + account.address.toLowerCase() === address.toLowerCase(), + ); + if (accountToBeNamed) { + this.accountsController.setAccountName(accountToBeNamed.id, label); + } + }, + setSelectedAddress: (address) => { + const accountToBeSet = this.accountsController + .listAccounts() + .find( + (account) => + account.address.toLowerCase() === address.toLowerCase(), + ); + if (accountToBeSet) { + this.accountsController.setSelectedAccount(accountToBeSet); + } + }, + syncIdentities: async () => { + await this.accountsController.updateAccounts(); + }, + // TODO: This will be removed, the accounts controller listens to the keyring controller state changes. + // eslint-disable-next-line no-empty-function + updateIdentities: () => {}, }); this.controllerMessenger.subscribe('KeyringController:unlock', () => @@ -2436,9 +2451,6 @@ export default class MetamaskController extends EventEmitter { this.networkController, ), // PreferencesController - setSelectedAddress: preferencesController.setSelectedAddress.bind( - preferencesController, - ), addToken: tokensController.addToken.bind(tokensController), updateTokenType: tokensController.updateTokenType.bind(tokensController), setAccountLabel: @@ -3519,25 +3531,26 @@ export default class MetamaskController extends EventEmitter { const keyring = await this.getKeyringForDevice(deviceName, hdPath); keyring.setAccountToUnlock(index); - const oldAccounts = await this.keyringController.getAccounts(); const keyState = await this.keyringController.addNewAccount(keyring); - const newAccounts = await this.keyringController.getAccounts(); - this.preferencesController.setAddresses(newAccounts); - newAccounts.forEach((address) => { - if (!oldAccounts.includes(address)) { - const label = this.getAccountLabel( - deviceName === HardwareDeviceNames.qr - ? keyring.getName() - : deviceName, - index, - hdPathDescription, - ); - // Set the account label to Trezor 1 / Ledger 1 / QR Hardware 1, etc - this.preferencesController.setAccountLabel(address, label); - // Select the account - this.preferencesController.setSelectedAddress(address); - } - }); + await this.accountsController.updateAccounts(); + const newlyAddedAccount = this.accountsController.getSelectedAccount(); + console.log( + this.getAccountLabel( + deviceName === HardwareDeviceNames.qr ? keyring.getName() : deviceName, + index, + hdPathDescription, + ), + index, + hdPathDescription, + ); + await this.accountsController.setAccountName( + newlyAddedAccount.id, + this.getAccountLabel( + deviceName === HardwareDeviceNames.qr ? keyring.getName() : deviceName, + index, + hdPathDescription, + ), + ); const { identities } = this.preferencesController.store.getState(); return { ...keyState, identities }; diff --git a/app/scripts/metamask-controller.test.js b/app/scripts/metamask-controller.test.js index be96a88167a4..3c797f0f218b 100644 --- a/app/scripts/metamask-controller.test.js +++ b/app/scripts/metamask-controller.test.js @@ -417,8 +417,6 @@ describe('MetaMaskController', function () { const password = 'password'; await metamaskController.createNewVaultAndKeychain(password); - const fakeAddress = '0xbad0'; - metamaskController.preferencesController.addAddresses([fakeAddress]); await metamaskController.submitPassword(password); const addresses = @@ -497,7 +495,7 @@ describe('MetaMaskController', function () { ); }); - it('should clear previous accounts after vault restoration', async function () { + it.only('should clear previous accounts after vault restoration', async function () { sandbox.stub(metamaskController, 'getBalance'); metamaskController.getBalance.callsFake(() => { return Promise.resolve('0x0'); @@ -852,7 +850,34 @@ describe('MetaMaskController', function () { let accountToUnlock; let windowOpenStub; let addNewAccountStub; - let getAccountsStub; + let getAccountExpectStub; + let updateAccountsStub; + let listAccountsStub; + + const generateInternalAccountMock = (index) => { + return { + address: `0x${index}`, + id: `mock-id-${index}`, + metadata: { + name: `Trezor ${index}`, + keyring: { + type: 'Trezor Hardware', + }, + }, + options: {}, + methods: [ + 'personal_sign', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }; + }; + beforeEach(async function () { accountToUnlock = 10; windowOpenStub = sinon.stub(window, 'open'); @@ -864,22 +889,34 @@ describe('MetaMaskController', function () { ); addNewAccountStub.returns('0x123'); - getAccountsStub = sinon.stub( - metamaskController.keyringController, - 'getAccounts', - ); - // Need to return different address to mock the behavior of - // adding a new account from the keyring - getAccountsStub.onCall(0).returns(Promise.resolve(['0x1'])); - getAccountsStub.onCall(1).returns(Promise.resolve(['0x2'])); - getAccountsStub.onCall(2).returns(Promise.resolve(['0x3'])); - getAccountsStub.onCall(3).returns(Promise.resolve(['0x4'])); - sinon.spy(metamaskController.preferencesController, 'setAddresses'); - sinon.spy( - metamaskController.preferencesController, - 'setSelectedAddress', - ); - sinon.spy(metamaskController.preferencesController, 'setAccountLabel'); + getAccountExpectStub = sinon.stub( + metamaskController.accountsController, + 'getAccountExpect', + ); + + getAccountExpectStub.returns(generateInternalAccountMock(11)); + + listAccountsStub = sinon.stub( + metamaskController.accountsController, + 'listAccounts', + ); + + listAccountsStub.returns([ + generateInternalAccountMock(0), + generateInternalAccountMock(1), + generateInternalAccountMock(2), + generateInternalAccountMock(3), + ]); + + updateAccountsStub = sinon.stub( + metamaskController.accountsController, + 'updateAccounts', + ); + + updateAccountsStub.resolves(); + + sinon.spy(metamaskController.accountsController, 'setAccountName'); + await metamaskController .connectHardware(HardwareDeviceNames.trezor, 0, `m/44'/1'/0'/0`) .catch(() => null); @@ -893,10 +930,9 @@ describe('MetaMaskController', function () { afterEach(function () { window.open.restore(); metamaskController.keyringController.addNewAccount.restore(); - metamaskController.keyringController.getAccounts.restore(); - metamaskController.preferencesController.setAddresses.restore(); - metamaskController.preferencesController.setSelectedAddress.restore(); - metamaskController.preferencesController.setAccountLabel.restore(); + metamaskController.accountsController.listAccounts.restore(); + metamaskController.accountsController.updateAccounts.restore(); + metamaskController.accountsController.getAccountExpect.restore(); }); it('should set unlockedAccount in the keyring', async function () { @@ -911,26 +947,20 @@ describe('MetaMaskController', function () { assert(metamaskController.keyringController.addNewAccount.calledOnce); }); - it('should call keyringController.getAccounts ', async function () { - assert(metamaskController.keyringController.getAccounts.called); + it('should call accountsController.updateAccounts', async function () { + assert(metamaskController.accountsController.updateAccounts.calledOnce); }); - it('should call preferencesController.setAddresses', async function () { - assert( - metamaskController.preferencesController.setAddresses.calledOnce, + it('should set the name of the account', async function () { + assert(metamaskController.accountsController.setAccountName.calledOnce); + console.log( + metamaskController.accountsController.setAccountName.getCall(0).args, ); - }); - - it('should call preferencesController.setSelectedAddress', async function () { - assert( - metamaskController.preferencesController.setSelectedAddress - .calledOnce, - ); - }); - - it('should call preferencesController.setAccountLabel', async function () { assert( - metamaskController.preferencesController.setAccountLabel.calledOnce, + metamaskController.accountsController.setAccountName.calledWith( + 'mock-id-11', + 'Trezor 11', + ), ); }); }); diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index a1020cae4cdd..a0328fa383a3 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -3608,28 +3608,6 @@ "eth-rpc-errors>fast-safe-stringify": true } }, - "eth-sig-util": { - "packages": { - "browserify>buffer": true, - "eth-sig-util>ethereumjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true, - "ethereumjs-abi": true - } - }, - "eth-sig-util>ethereumjs-util": { - "packages": { - "@metamask/ppom-validator>elliptic": true, - "bn.js": true, - "browserify>assert": true, - "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, - "ethereumjs-util>rlp": true, - "koa>content-disposition>safe-buffer": true - } - }, "eth-sig-util>ethereumjs-util>ethjs-util": { "packages": { "browserify>buffer": true, diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index e097791cce34..98ee4e605c52 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -4102,28 +4102,6 @@ "eth-rpc-errors>fast-safe-stringify": true } }, - "eth-sig-util": { - "packages": { - "browserify>buffer": true, - "eth-sig-util>ethereumjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true, - "ethereumjs-abi": true - } - }, - "eth-sig-util>ethereumjs-util": { - "packages": { - "@metamask/ppom-validator>elliptic": true, - "bn.js": true, - "browserify>assert": true, - "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, - "ethereumjs-util>rlp": true, - "koa>content-disposition>safe-buffer": true - } - }, "eth-sig-util>ethereumjs-util>ethjs-util": { "packages": { "browserify>buffer": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index a8cb96037246..cc022780d524 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -4118,28 +4118,6 @@ "eth-rpc-errors>fast-safe-stringify": true } }, - "eth-sig-util": { - "packages": { - "browserify>buffer": true, - "eth-sig-util>ethereumjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true, - "ethereumjs-abi": true - } - }, - "eth-sig-util>ethereumjs-util": { - "packages": { - "@metamask/ppom-validator>elliptic": true, - "bn.js": true, - "browserify>assert": true, - "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, - "ethereumjs-util>rlp": true, - "koa>content-disposition>safe-buffer": true - } - }, "eth-sig-util>ethereumjs-util>ethjs-util": { "packages": { "browserify>buffer": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 3babfe219c48..5db3093bb7b1 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -3887,28 +3887,6 @@ "eth-rpc-errors>fast-safe-stringify": true } }, - "eth-sig-util": { - "packages": { - "browserify>buffer": true, - "eth-sig-util>ethereumjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true, - "ethereumjs-abi": true - } - }, - "eth-sig-util>ethereumjs-util": { - "packages": { - "@metamask/ppom-validator>elliptic": true, - "bn.js": true, - "browserify>assert": true, - "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, - "ethereumjs-util>rlp": true, - "koa>content-disposition>safe-buffer": true - } - }, "eth-sig-util>ethereumjs-util>ethjs-util": { "packages": { "browserify>buffer": true, diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 068a5ab0fb43..69d74523ada3 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -3749,28 +3749,6 @@ "eth-rpc-errors>fast-safe-stringify": true } }, - "eth-sig-util": { - "packages": { - "browserify>buffer": true, - "eth-sig-util>ethereumjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true, - "ethereumjs-abi": true - } - }, - "eth-sig-util>ethereumjs-util": { - "packages": { - "@metamask/ppom-validator>elliptic": true, - "bn.js": true, - "browserify>assert": true, - "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, - "ethereumjs-util>rlp": true, - "koa>content-disposition>safe-buffer": true - } - }, "eth-sig-util>ethereumjs-util>ethjs-util": { "packages": { "browserify>buffer": true, From 837c8a113e3469aa710a395b5e958238795c9773 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Fri, 8 Sep 2023 15:15:02 +0800 Subject: [PATCH 100/235] fix: preference test and error snapshots --- app/scripts/controllers/preferences.test.js | 137 ------------------ ...rs-after-init-opt-in-background-state.json | 5 +- .../errors-after-init-opt-in-ui-state.json | 1 - 3 files changed, 1 insertion(+), 142 deletions(-) diff --git a/app/scripts/controllers/preferences.test.js b/app/scripts/controllers/preferences.test.js index de312b7e0fa3..7525d6c8c6bc 100644 --- a/app/scripts/controllers/preferences.test.js +++ b/app/scripts/controllers/preferences.test.js @@ -75,143 +75,6 @@ describe('preferences controller', () => { }); }); - describe('setAddresses', () => { - it('should keep a map of addresses to names and addresses in the store', () => { - preferencesController.setAddresses(['0xda22le', '0x7e57e2']); - - const { identities } = preferencesController.store.getState(); - expect(identities).toStrictEqual({ - '0xda22le': { - name: 'Account 1', - address: '0xda22le', - }, - '0x7e57e2': { - name: 'Account 2', - address: '0x7e57e2', - }, - }); - }); - - it('should replace its list of addresses', () => { - preferencesController.setAddresses(['0xda22le', '0x7e57e2']); - preferencesController.setAddresses(['0xda22le77', '0x7e57e277']); - - const { identities } = preferencesController.store.getState(); - expect(identities).toStrictEqual({ - '0xda22le77': { - name: 'Account 1', - address: '0xda22le77', - }, - '0x7e57e277': { - name: 'Account 2', - address: '0x7e57e277', - }, - }); - }); - }); - - describe('onAccountRemoved', () => { - it('should remove an address from state', () => { - const testAddress = '0xda22le'; - let accountRemovedListener; - const onAccountRemoved = (callback) => { - accountRemovedListener = callback; - }; - preferencesController = new PreferencesController({ - initLangCode: 'en_US', - tokenListController, - onInfuraIsBlocked: jest.fn(), - onInfuraIsUnblocked: jest.fn(), - initState: { - identities: { - [testAddress]: { - name: 'Account 1', - address: testAddress, - }, - }, - }, - onAccountRemoved, - networkConfigurations: NETWORK_CONFIGURATION_DATA, - }); - - accountRemovedListener(testAddress); - - expect( - preferencesController.store.getState().identities['0xda22le'], - ).toStrictEqual(undefined); - }); - - it('should throw an error if address not found', () => { - const testAddress = '0xda22le'; - let accountRemovedListener; - const onAccountRemoved = (callback) => { - accountRemovedListener = callback; - }; - preferencesController = new PreferencesController({ - initLangCode: 'en_US', - tokenListController, - onInfuraIsBlocked: jest.fn(), - onInfuraIsUnblocked: jest.fn(), - initState: { - identities: { - '0x7e57e2': { - name: 'Account 1', - address: '0x7e57e2', - }, - }, - }, - onAccountRemoved, - networkConfigurations: NETWORK_CONFIGURATION_DATA, - }); - expect(() => { - accountRemovedListener(testAddress); - }).toThrow(`${testAddress} can't be deleted cause it was not found`); - }); - }); - - describe('removeAddress', () => { - it('should remove an address from state', () => { - preferencesController.setAddresses(['0xda22le', '0x7e57e2']); - - preferencesController.removeAddress('0xda22le'); - - expect( - preferencesController.store.getState().identities['0xda22le'], - ).toStrictEqual(undefined); - }); - - it('should switch accounts if the selected address is removed', () => { - preferencesController.setAddresses(['0xda22le', '0x7e57e2']); - - preferencesController.setSelectedAddress('0x7e57e2'); - preferencesController.removeAddress('0x7e57e2'); - expect(preferencesController.getSelectedAddress()).toStrictEqual( - '0xda22le', - ); - }); - }); - - describe('setAccountLabel', () => { - it('should update a label for the given account', () => { - preferencesController.setAddresses(['0xda22le', '0x7e57e2']); - - expect( - preferencesController.store.getState().identities['0xda22le'], - ).toStrictEqual({ - name: 'Account 1', - address: '0xda22le', - }); - - preferencesController.setAccountLabel('0xda22le', 'Dazzle'); - expect( - preferencesController.store.getState().identities['0xda22le'], - ).toStrictEqual({ - name: 'Dazzle', - address: '0xda22le', - }); - }); - }); - describe('setPasswordForgotten', () => { it('should default to false', () => { expect( diff --git a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json index 626073f9f47e..311625878d28 100644 --- a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json +++ b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json @@ -137,7 +137,6 @@ "incomingTransactionsPreferences": {}, "knownMethodData": "object", "currentLocale": "en", - "identities": "object", "lostIdentities": "object", "forgottenPassword": false, "preferences": { @@ -219,7 +218,5 @@ "allIgnoredTokens": {}, "allDetectedTokens": {} }, - "TxController": { - "transactions": "object" - } + "TxController": { "transactions": "object" } } diff --git a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json index 562f9ca1227f..77cc38729b3d 100644 --- a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json +++ b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json @@ -93,7 +93,6 @@ "openSeaEnabled": false, "advancedGasFee": {}, "incomingTransactionsPreferences": {}, - "identities": "object", "lostIdentities": "object", "forgottenPassword": false, "ipfsGateway": "string", From d5b4324eadfdfd503e929a01b4d1a16a607f4b04 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Fri, 8 Sep 2023 15:32:50 +0800 Subject: [PATCH 101/235] chore: fix lint --- app/scripts/controllers/metametrics.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/controllers/metametrics.test.js b/app/scripts/controllers/metametrics.test.js index 081e24dcb5ac..781318f61029 100644 --- a/app/scripts/controllers/metametrics.test.js +++ b/app/scripts/controllers/metametrics.test.js @@ -1,6 +1,7 @@ import { strict as assert } from 'assert'; import sinon from 'sinon'; import { toHex } from '@metamask/controller-utils'; +import { EthAccountType } from '@metamask/keyring-api'; import { ENVIRONMENT_TYPE_BACKGROUND } from '../../../shared/constants/app'; import { createSegmentMock } from '../lib/segment'; import { @@ -12,7 +13,6 @@ import waitUntilCalled from '../../../test/lib/wait-until-called'; import { CHAIN_IDS, CURRENCY_SYMBOLS } from '../../../shared/constants/network'; import * as Utils from '../lib/util'; import MetaMetricsController from './metametrics'; -import { EthAccountType } from '@metamask/keyring-api'; const segment = createSegmentMock(2, 10000); From b9a624903fa206d40a233c2f6a8cda18c2f90716 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Fri, 8 Sep 2023 15:39:08 +0800 Subject: [PATCH 102/235] fix: remove only --- app/scripts/metamask-controller.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/metamask-controller.test.js b/app/scripts/metamask-controller.test.js index 3c797f0f218b..4fc4802068d7 100644 --- a/app/scripts/metamask-controller.test.js +++ b/app/scripts/metamask-controller.test.js @@ -495,7 +495,7 @@ describe('MetaMaskController', function () { ); }); - it.only('should clear previous accounts after vault restoration', async function () { + it('should clear previous accounts after vault restoration', async function () { sandbox.stub(metamaskController, 'getBalance'); metamaskController.getBalance.callsFake(() => { return Promise.resolve('0x0'); From 11d1e3fe5fd2ac01ecc783c1a3e7e81319680e79 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Fri, 8 Sep 2023 15:46:06 +0800 Subject: [PATCH 103/235] fix: remove eth-sig-util dep --- lavamoat/browserify/beta/policy.json | 84 ++++++++++++------------- lavamoat/browserify/desktop/policy.json | 84 ++++++++++++------------- lavamoat/browserify/flask/policy.json | 84 ++++++++++++------------- lavamoat/browserify/main/policy.json | 84 ++++++++++++------------- lavamoat/browserify/mmi/policy.json | 84 ++++++++++++------------- package.json | 1 - yarn.lock | 15 +---- 7 files changed, 211 insertions(+), 225 deletions(-) diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index a0328fa383a3..f16be978f461 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -1024,11 +1024,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1098,9 +1098,9 @@ "@metamask/eth-ledger-bridge-keyring>eth-sig-util": { "packages": { "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "browserify>buffer": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true, "ethereumjs-abi": true } }, @@ -1110,7 +1110,7 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, + "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, @@ -1153,11 +1153,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1629,11 +1629,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1719,11 +1719,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1741,6 +1741,25 @@ "crypto": true } }, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": { + "globals": { + "crypto": true, + "msCrypto": true, + "nacl": "write" + }, + "packages": { + "browserify>browser-resolve": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": { + "globals": { + "atob": true, + "btoa": true + }, + "packages": { + "browserify>browser-resolve": true + } + }, "@metamask/message-manager>jsonschema": { "packages": { "browserify>url": true @@ -3608,32 +3627,6 @@ "eth-rpc-errors>fast-safe-stringify": true } }, - "eth-sig-util>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, - "eth-sig-util>tweetnacl": { - "globals": { - "crypto": true, - "msCrypto": true, - "nacl": "write" - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "eth-sig-util>tweetnacl-util": { - "globals": { - "atob": true, - "btoa": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "ethereumjs-abi": { "packages": { "bn.js": true, @@ -3647,12 +3640,19 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, + "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, + "ethereumjs-abi>ethereumjs-util>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "ethereumjs-util": { "packages": { "bn.js": true, diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index 98ee4e605c52..6da4964fbd63 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -1095,11 +1095,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1169,9 +1169,9 @@ "@metamask/eth-ledger-bridge-keyring>eth-sig-util": { "packages": { "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "browserify>buffer": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true, "ethereumjs-abi": true } }, @@ -1181,7 +1181,7 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, + "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, @@ -1224,11 +1224,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1723,11 +1723,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1813,11 +1813,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1835,6 +1835,25 @@ "crypto": true } }, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": { + "globals": { + "crypto": true, + "msCrypto": true, + "nacl": "write" + }, + "packages": { + "browserify>browser-resolve": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": { + "globals": { + "atob": true, + "btoa": true + }, + "packages": { + "browserify>browser-resolve": true + } + }, "@metamask/message-manager>jsonschema": { "packages": { "browserify>url": true @@ -4102,32 +4121,6 @@ "eth-rpc-errors>fast-safe-stringify": true } }, - "eth-sig-util>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, - "eth-sig-util>tweetnacl": { - "globals": { - "crypto": true, - "msCrypto": true, - "nacl": "write" - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "eth-sig-util>tweetnacl-util": { - "globals": { - "atob": true, - "btoa": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "ethereumjs-abi": { "packages": { "bn.js": true, @@ -4141,12 +4134,19 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, + "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, + "ethereumjs-abi>ethereumjs-util>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "ethereumjs-util": { "packages": { "bn.js": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index cc022780d524..ef1664fb713b 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -1095,11 +1095,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1169,9 +1169,9 @@ "@metamask/eth-ledger-bridge-keyring>eth-sig-util": { "packages": { "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "browserify>buffer": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true, "ethereumjs-abi": true } }, @@ -1181,7 +1181,7 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, + "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, @@ -1224,11 +1224,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1723,11 +1723,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1813,11 +1813,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1835,6 +1835,25 @@ "crypto": true } }, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": { + "globals": { + "crypto": true, + "msCrypto": true, + "nacl": "write" + }, + "packages": { + "browserify>browser-resolve": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": { + "globals": { + "atob": true, + "btoa": true + }, + "packages": { + "browserify>browser-resolve": true + } + }, "@metamask/message-manager>jsonschema": { "packages": { "browserify>url": true @@ -4118,32 +4137,6 @@ "eth-rpc-errors>fast-safe-stringify": true } }, - "eth-sig-util>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, - "eth-sig-util>tweetnacl": { - "globals": { - "crypto": true, - "msCrypto": true, - "nacl": "write" - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "eth-sig-util>tweetnacl-util": { - "globals": { - "atob": true, - "btoa": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "ethereumjs-abi": { "packages": { "bn.js": true, @@ -4157,12 +4150,19 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, + "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, + "ethereumjs-abi>ethereumjs-util>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "ethereumjs-util": { "packages": { "bn.js": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 5db3093bb7b1..328996152e40 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -1024,11 +1024,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1098,9 +1098,9 @@ "@metamask/eth-ledger-bridge-keyring>eth-sig-util": { "packages": { "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "browserify>buffer": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true, "ethereumjs-abi": true } }, @@ -1110,7 +1110,7 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, + "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, @@ -1153,11 +1153,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1629,11 +1629,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1719,11 +1719,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1741,6 +1741,25 @@ "crypto": true } }, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": { + "globals": { + "crypto": true, + "msCrypto": true, + "nacl": "write" + }, + "packages": { + "browserify>browser-resolve": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": { + "globals": { + "atob": true, + "btoa": true + }, + "packages": { + "browserify>browser-resolve": true + } + }, "@metamask/message-manager>jsonschema": { "packages": { "browserify>url": true @@ -3887,32 +3906,6 @@ "eth-rpc-errors>fast-safe-stringify": true } }, - "eth-sig-util>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, - "eth-sig-util>tweetnacl": { - "globals": { - "crypto": true, - "msCrypto": true, - "nacl": "write" - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "eth-sig-util>tweetnacl-util": { - "globals": { - "atob": true, - "btoa": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "ethereumjs-abi": { "packages": { "bn.js": true, @@ -3926,12 +3919,19 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, + "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, + "ethereumjs-abi>ethereumjs-util>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "ethereumjs-util": { "packages": { "bn.js": true, diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 69d74523ada3..477c8f034973 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -1165,11 +1165,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1239,9 +1239,9 @@ "@metamask/eth-ledger-bridge-keyring>eth-sig-util": { "packages": { "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "browserify>buffer": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true, "ethereumjs-abi": true } }, @@ -1251,7 +1251,7 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, + "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, @@ -1294,11 +1294,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1770,11 +1770,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1860,11 +1860,11 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, - "eth-sig-util>tweetnacl": true, - "eth-sig-util>tweetnacl-util": true + "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": { @@ -1882,6 +1882,25 @@ "crypto": true } }, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": { + "globals": { + "crypto": true, + "msCrypto": true, + "nacl": "write" + }, + "packages": { + "browserify>browser-resolve": true + } + }, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": { + "globals": { + "atob": true, + "btoa": true + }, + "packages": { + "browserify>browser-resolve": true + } + }, "@metamask/message-manager>jsonschema": { "packages": { "browserify>url": true @@ -3749,32 +3768,6 @@ "eth-rpc-errors>fast-safe-stringify": true } }, - "eth-sig-util>ethereumjs-util>ethjs-util": { - "packages": { - "browserify>buffer": true, - "ethjs>ethjs-util>is-hex-prefixed": true, - "ethjs>ethjs-util>strip-hex-prefix": true - } - }, - "eth-sig-util>tweetnacl": { - "globals": { - "crypto": true, - "msCrypto": true, - "nacl": "write" - }, - "packages": { - "browserify>browser-resolve": true - } - }, - "eth-sig-util>tweetnacl-util": { - "globals": { - "atob": true, - "btoa": true - }, - "packages": { - "browserify>browser-resolve": true - } - }, "ethereumjs-abi": { "packages": { "bn.js": true, @@ -3788,12 +3781,19 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, - "eth-sig-util>ethereumjs-util>ethjs-util": true, + "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, + "ethereumjs-abi>ethereumjs-util>ethjs-util": { + "packages": { + "browserify>buffer": true, + "ethjs>ethjs-util>is-hex-prefixed": true, + "ethjs>ethjs-util>strip-hex-prefix": true + } + }, "ethereumjs-util": { "packages": { "bn.js": true, diff --git a/package.json b/package.json index 904b7c0aa968..a06e15b5b371 100644 --- a/package.json +++ b/package.json @@ -311,7 +311,6 @@ "eth-method-registry": "^2.0.0", "eth-query": "^2.1.2", "eth-rpc-errors": "^4.0.2", - "eth-sig-util": "^3.0.0", "ethereum-ens-network-map": "^1.0.2", "ethereumjs-abi": "^0.6.4", "ethereumjs-util": "^7.0.10", diff --git a/yarn.lock b/yarn.lock index be48540d6617..43ce120d0567 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16139,18 +16139,6 @@ __metadata: languageName: node linkType: hard -"eth-sig-util@npm:^3.0.0": - version: 3.0.1 - resolution: "eth-sig-util@npm:3.0.1" - dependencies: - ethereumjs-abi: "npm:^0.6.8" - ethereumjs-util: "npm:^5.1.1" - tweetnacl: "npm:^1.0.3" - tweetnacl-util: "npm:^0.15.0" - checksum: 2f6a68b72569528c310f429136284596e28aac9de4874ef62af6ae76340193991c02cc88b50388ac8c5d3dc120c635d62e59eb7d6e49df51e75d20d9e45c70dc - languageName: node - linkType: hard - "ethereum-bloom-filters@npm:^1.0.6": version: 1.0.7 resolution: "ethereum-bloom-filters@npm:1.0.7" @@ -16214,7 +16202,7 @@ __metadata: languageName: node linkType: hard -"ethereumjs-abi@npm:0.6.8, ethereumjs-abi@npm:^0.6.4, ethereumjs-abi@npm:^0.6.8": +"ethereumjs-abi@npm:0.6.8, ethereumjs-abi@npm:^0.6.4": version: 0.6.8 resolution: "ethereumjs-abi@npm:0.6.8" dependencies: @@ -24417,7 +24405,6 @@ __metadata: eth-method-registry: "npm:^2.0.0" eth-query: "npm:^2.1.2" eth-rpc-errors: "npm:^4.0.2" - eth-sig-util: "npm:^3.0.0" ethereum-ens-network-map: "npm:^1.0.2" ethereumjs-abi: "npm:^0.6.4" ethereumjs-util: "npm:^7.0.10" From 5e205f918fbbbd65b57dd794cce30d74a4da572c Mon Sep 17 00:00:00 2001 From: MetaMask Bot Date: Fri, 8 Sep 2023 08:03:10 +0000 Subject: [PATCH 104/235] Update LavaMoat policies --- lavamoat/build-system/policy.json | 132 ++---------------------------- 1 file changed, 8 insertions(+), 124 deletions(-) diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json index 96fef5e24515..4ab9521cfbeb 100644 --- a/lavamoat/build-system/policy.json +++ b/lavamoat/build-system/policy.json @@ -1134,21 +1134,6 @@ "string.prototype.matchall>side-channel": true } }, - "@storybook/addon-mdx-gfm>@storybook/node-logger>npmlog>gauge>has-unicode": { - "builtin": { - "os.type": true - }, - "globals": { - "process.env.LANG": true, - "process.env.LC_ALL": true, - "process.env.LC_CTYPE": true - } - }, - "@storybook/addon-mdx-gfm>@storybook/node-logger>npmlog>gauge>wide-align": { - "packages": { - "yargs>string-width": true - } - }, "@storybook/core>@storybook/core-server>x-default-browser>default-browser-id>untildify>os-homedir": { "builtin": { "os.homedir": true @@ -5014,7 +4999,6 @@ "@lavamoat/allow-scripts>@npmcli/run-script>node-gyp>npmlog": true, "gulp-watch>chokidar>fsevents>node-pre-gyp>detect-libc": true, "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt": true, - "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog": true, "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf": true, "gulp-watch>chokidar>fsevents>node-pre-gyp>semver": true } @@ -5072,20 +5056,9 @@ }, "packages": { "@storybook/core>@storybook/core-server>x-default-browser>default-browser-id>untildify>os-homedir": true, - "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-homedir": true, "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-tmpdir": true } }, - "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-homedir": { - "builtin": { - "os.homedir": true - }, - "globals": { - "process.env": true, - "process.getuid": true, - "process.platform": true - } - }, "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-tmpdir": { "globals": { "process.env.SystemRoot": true, @@ -5096,70 +5069,6 @@ "process.platform": true } }, - "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog": { - "builtin": { - "events.EventEmitter": true, - "util": true - }, - "globals": { - "process.nextTick": true, - "process.stderr": true - }, - "packages": { - "@storybook/addon-mdx-gfm>@storybook/node-logger>npmlog>console-control-strings": true, - "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet": true, - "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge": true, - "nyc>yargs>set-blocking": true - } - }, - "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet": { - "builtin": { - "events.EventEmitter": true, - "util.inherits": true - }, - "packages": { - "koa>delegates": true, - "readable-stream": true - } - }, - "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge": { - "builtin": { - "util.format": true - }, - "globals": { - "clearInterval": true, - "process": true, - "setImmediate": true, - "setInterval": true - }, - "packages": { - "@storybook/addon-mdx-gfm>@storybook/node-logger>npmlog>console-control-strings": true, - "@storybook/addon-mdx-gfm>@storybook/node-logger>npmlog>gauge>has-unicode": true, - "@storybook/addon-mdx-gfm>@storybook/node-logger>npmlog>gauge>wide-align": true, - "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>aproba": true, - "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width": true, - "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi": true, - "nyc>signal-exit": true, - "react>object-assign": true - } - }, - "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width": { - "packages": { - "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width>is-fullwidth-code-point": true, - "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi": true, - "gulp>gulp-cli>yargs>string-width>code-point-at": true - } - }, - "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width>is-fullwidth-code-point": { - "packages": { - "gulp>gulp-cli>yargs>string-width>is-fullwidth-code-point>number-is-nan": true - } - }, - "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi": { - "packages": { - "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi>ansi-regex": true - } - }, "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf": { "builtin": { "assert": true, @@ -5171,34 +5080,9 @@ "setTimeout": true }, "packages": { - "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob": true, "nyc>glob": true } }, - "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob": { - "builtin": { - "assert": true, - "events.EventEmitter": true, - "fs": true, - "path.join": true, - "path.resolve": true, - "util": true - }, - "globals": { - "console.error": true, - "process.cwd": true, - "process.nextTick": true, - "process.platform": true - }, - "packages": { - "eslint>minimatch": true, - "gulp-watch>path-is-absolute": true, - "nyc>glob>fs.realpath": true, - "nyc>glob>inflight": true, - "pump>once": true, - "pumpify>inherits": true - } - }, "gulp-watch>chokidar>fsevents>node-pre-gyp>semver": { "globals": { "console": true, @@ -6646,13 +6530,6 @@ "process.platform": true } }, - "mockttp>portfinder>mkdirp": { - "builtin": { - "fs": true, - "path.dirname": true, - "path.resolve": true - } - }, "nock>debug": { "builtin": { "tty.isatty": true, @@ -8260,7 +8137,14 @@ "path.dirname": true }, "packages": { - "mockttp>portfinder>mkdirp": true + "stylelint>file-entry-cache>flat-cache>write>mkdirp": true + } + }, + "stylelint>file-entry-cache>flat-cache>write>mkdirp": { + "builtin": { + "fs": true, + "path.dirname": true, + "path.resolve": true } }, "stylelint>global-modules": { From 128656551fb0578a4cdc484ff60f219356cf9e21 Mon Sep 17 00:00:00 2001 From: Daniel Rocha Date: Wed, 13 Sep 2023 14:13:09 +0200 Subject: [PATCH 105/235] chore: update to new bridge and API (#20828) --- app/scripts/metamask-controller.js | 10 +- package.json | 6 +- yarn.lock | 168 ++++++++++++++++++++++++++++- 3 files changed, 173 insertions(+), 11 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 4549e7f55397..a7f3f19a1001 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -781,7 +781,12 @@ export default class MetamaskController extends EventEmitter { ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) additionalKeyrings.push( (() => { - const builder = () => new SnapKeyring(this.snapController); + const builder = () => + new SnapKeyring(this.snapController, { + saveState: async () => { + await this.keyringController.persistAllKeyrings(); + }, + }); builder.type = SnapKeyring.type; return builder; })(), @@ -2016,9 +2021,6 @@ export default class MetamaskController extends EventEmitter { ///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) getSnapKeyring: this.getSnapKeyring.bind(this), - saveSnapKeyring: async () => { - await this.keyringController.persistAllKeyrings(); - }, ///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(snaps) }), diff --git a/package.json b/package.json index a06e15b5b371..e3b9db57f469 100644 --- a/package.json +++ b/package.json @@ -245,14 +245,14 @@ "@metamask/eth-json-rpc-middleware": "^11.0.0", "@metamask/eth-keyring-controller": "^10.0.1", "@metamask/eth-ledger-bridge-keyring": "^0.15.0", - "@metamask/eth-snap-keyring": "^0.2.0", + "@metamask/eth-snap-keyring": "github:MetaMask/eth-snap-keyring#52a82c96546fa5dad22c73d4045a07e1b6d1b722", "@metamask/eth-token-tracker": "^4.0.0", "@metamask/eth-trezor-keyring": "^1.1.0", "@metamask/etherscan-link": "^2.2.0", "@metamask/gas-fee-controller": "^6.0.1", "@metamask/jazzicon": "^2.0.0", "@metamask/key-tree": "^9.0.0", - "@metamask/keyring-api": "^0.2.2", + "@metamask/keyring-api": "^0.2.3", "@metamask/keyring-controller": "^7.2.0", "@metamask/logo": "^3.1.1", "@metamask/message-manager": "^7.3.0", @@ -267,7 +267,7 @@ "@metamask/providers": "^11.1.0", "@metamask/rate-limit-controller": "^3.0.0", "@metamask/rpc-methods": "^1.0.2", - "@metamask/rpc-methods-flask": "npm:@metamask/rpc-methods@0.37.2-flask.1", + "@metamask/rpc-methods-flask": "npm:@metamask/rpc-methods@0.38.2-flask.1", "@metamask/safe-event-emitter": "^2.0.0", "@metamask/scure-bip39": "^2.0.3", "@metamask/signature-controller": "^5.3.0", diff --git a/yarn.lock b/yarn.lock index 43ce120d0567..af92513106fc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4173,6 +4173,22 @@ __metadata: languageName: node linkType: hard +"@metamask/eth-snap-keyring@github:MetaMask/eth-snap-keyring#52a82c96546fa5dad22c73d4045a07e1b6d1b722": + version: 0.2.0 + resolution: "@metamask/eth-snap-keyring@https://github.com/MetaMask/eth-snap-keyring.git#commit=52a82c96546fa5dad22c73d4045a07e1b6d1b722" + dependencies: + "@ethereumjs/tx": "npm:^4.1.2" + "@metamask/eth-sig-util": "npm:^5.1.0" + "@metamask/keyring-api": "github:MetaMask/keyring-api#8b51af7ac82c5d8654ba9c07aed96e3aa2526d97" + "@metamask/snaps-controllers": "npm:^0.38.2-flask.1" + "@metamask/utils": "npm:^8.1.0" + "@types/uuid": "npm:^9.0.1" + superstruct: "npm:^1.0.3" + uuid: "npm:^9.0.0" + checksum: 80ae5fec21aa50e707b64d35cb3bbbfe916c69f7c6819a24b004e14ddedeb2925a0fa46e908864b6a234b774009706e87e3676652a3a5bdff2fd5a50d6894bb6 + languageName: node + linkType: hard + "@metamask/eth-snap-keyring@npm:^0.2.0": version: 0.2.0 resolution: "@metamask/eth-snap-keyring@npm:0.2.0" @@ -4264,6 +4280,17 @@ __metadata: languageName: node linkType: hard +"@metamask/json-rpc-engine@npm:^7.1.1": + version: 7.1.1 + resolution: "@metamask/json-rpc-engine@npm:7.1.1" + dependencies: + "@metamask/rpc-errors": "npm:^6.0.0" + "@metamask/safe-event-emitter": "npm:^3.0.0" + "@metamask/utils": "npm:^8.1.0" + checksum: 91320ab6bdc4577a96b26b1b06e71b77c65abbc02fd8d30c53a8a63d93b28cb82619031cc45542085b94f7115d46e3dcb16620fa5f5cb1f387cb3bebcff36ae9 + languageName: node + linkType: hard + "@metamask/key-tree@npm:^7.1.1": version: 7.1.1 resolution: "@metamask/key-tree@npm:7.1.1" @@ -4292,6 +4319,22 @@ __metadata: languageName: node linkType: hard +"@metamask/keyring-api@github:MetaMask/keyring-api#8b51af7ac82c5d8654ba9c07aed96e3aa2526d97": + version: 0.2.3 + resolution: "@metamask/keyring-api@https://github.com/MetaMask/keyring-api.git#commit=8b51af7ac82c5d8654ba9c07aed96e3aa2526d97" + dependencies: + "@metamask/providers": "npm:^12.0.0" + "@metamask/rpc-methods": "npm:^0.38.1-flask.1" + "@metamask/snaps-controllers": "npm:^0.38.2-flask.1" + "@metamask/snaps-utils": "npm:^0.38.2-flask.1" + "@metamask/utils": "npm:^8.1.0" + "@types/uuid": "npm:^9.0.1" + superstruct: "npm:^1.0.3" + uuid: "npm:^9.0.0" + checksum: a9720bb1788e109ee6ba3f0f7191c34a38f4185117f3891ffd5f97365b0b3c06b5942ecaf895c775dfa3c6173c4ae711b0c26870ea8315f2f2440ea415895fb6 + languageName: node + linkType: hard + "@metamask/keyring-api@npm:^0.2.2": version: 0.2.2 resolution: "@metamask/keyring-api@npm:0.2.2" @@ -4308,6 +4351,22 @@ __metadata: languageName: node linkType: hard +"@metamask/keyring-api@npm:^0.2.3": + version: 0.2.3 + resolution: "@metamask/keyring-api@npm:0.2.3" + dependencies: + "@metamask/providers": "npm:^12.0.0" + "@metamask/rpc-methods": "npm:^0.38.1-flask.1" + "@metamask/snaps-controllers": "npm:^0.38.2-flask.1" + "@metamask/snaps-utils": "npm:^0.38.2-flask.1" + "@metamask/utils": "npm:^8.1.0" + "@types/uuid": "npm:^9.0.1" + superstruct: "npm:^1.0.3" + uuid: "npm:^9.0.0" + checksum: a9720bb1788e109ee6ba3f0f7191c34a38f4185117f3891ffd5f97365b0b3c06b5942ecaf895c775dfa3c6173c4ae711b0c26870ea8315f2f2440ea415895fb6 + languageName: node + linkType: hard + "@metamask/keyring-controller@npm:7.2.0": version: 7.2.0 resolution: "@metamask/keyring-controller@npm:7.2.0" @@ -4642,6 +4701,26 @@ __metadata: languageName: node linkType: hard +"@metamask/providers@npm:^12.0.0": + version: 12.0.0 + resolution: "@metamask/providers@npm:12.0.0" + dependencies: + "@metamask/json-rpc-engine": "npm:^7.1.1" + "@metamask/object-multiplex": "npm:^1.1.0" + "@metamask/rpc-errors": "npm:^6.0.0" + "@metamask/safe-event-emitter": "npm:^3.0.0" + "@metamask/utils": "npm:^8.1.0" + detect-browser: "npm:^5.2.0" + extension-port-stream: "npm:^2.1.1" + fast-deep-equal: "npm:^3.1.3" + is-stream: "npm:^2.0.0" + json-rpc-middleware-stream: "npm:^4.2.1" + pump: "npm:^3.0.0" + webextension-polyfill: "npm:^0.10.0" + checksum: 8c3895593a71de6e165276f00069b57f83b5bb6991b6bb9444ae556d0ceb3252d56b546eb136b19b854b919c4368bf30b37c993da8904ea8ddf200323759e715 + languageName: node + linkType: hard + "@metamask/rate-limit-controller@npm:^3.0.0": version: 3.0.0 resolution: "@metamask/rate-limit-controller@npm:3.0.0" @@ -4663,7 +4742,34 @@ __metadata: languageName: node linkType: hard -"@metamask/rpc-methods-flask@npm:@metamask/rpc-methods@0.37.2-flask.1, @metamask/rpc-methods@npm:^0.37.2-flask.1": +"@metamask/rpc-errors@npm:^6.0.0": + version: 6.0.0 + resolution: "@metamask/rpc-errors@npm:6.0.0" + dependencies: + "@metamask/utils": "npm:^8.0.0" + fast-safe-stringify: "npm:^2.0.6" + checksum: f907a01d061fe9354fa88a1891adeb393505f7a679342fcbc46ec81385558ac1791b442c6b68f5df61765d7927b54b988f562b5dd2bfa09150d25d39298e3eaa + languageName: node + linkType: hard + +"@metamask/rpc-methods-flask@npm:@metamask/rpc-methods@0.38.2-flask.1": + version: 0.38.2-flask.1 + resolution: "@metamask/rpc-methods@npm:0.38.2-flask.1" + dependencies: + "@metamask/key-tree": "npm:^9.0.0" + "@metamask/permission-controller": "npm:^4.1.0" + "@metamask/snaps-ui": "npm:^0.37.4-flask.1" + "@metamask/snaps-utils": "npm:^0.38.3-flask.1" + "@metamask/types": "npm:^1.1.0" + "@metamask/utils": "npm:^7.1.0" + "@noble/hashes": "npm:^1.3.1" + eth-rpc-errors: "npm:^4.0.3" + superstruct: "npm:^1.0.3" + checksum: a9b49d49df69708cd8805909e25b67b0ff75ec8299035e2cedd1295ae17a68c3cb53cf87788da729c54135e8872e93cc901f27be6ad429db6efd66dd50488a0d + languageName: node + linkType: hard + +"@metamask/rpc-methods@npm:^0.37.2-flask.1": version: 0.37.2-flask.1 resolution: "@metamask/rpc-methods@npm:0.37.2-flask.1" dependencies: @@ -4962,6 +5068,17 @@ __metadata: languageName: node linkType: hard +"@metamask/snaps-registry@npm:^1.2.2": + version: 1.2.2 + resolution: "@metamask/snaps-registry@npm:1.2.2" + dependencies: + "@metamask/utils": "npm:^7.1.0" + "@noble/secp256k1": "npm:^1.7.1" + superstruct: "npm:^1.0.3" + checksum: b7273d5554081749c92610c7da7d9407c7f33eef9184d8297e9f204be902f4825f8d9cee561135c5eed9b4d978ef4e3b3ec4cbdbd669ac36d9f7ad433389668f + languageName: node + linkType: hard + "@metamask/snaps-ui-flask@npm:@metamask/snaps-ui@0.37.3-flask.1, @metamask/snaps-ui@npm:^0.37.3-flask.1": version: 0.37.3-flask.1 resolution: "@metamask/snaps-ui@npm:0.37.3-flask.1" @@ -5091,6 +5208,35 @@ __metadata: languageName: node linkType: hard +"@metamask/snaps-utils@npm:^0.38.3-flask.1": + version: 0.38.3-flask.1 + resolution: "@metamask/snaps-utils@npm:0.38.3-flask.1" + dependencies: + "@babel/core": "npm:^7.20.12" + "@babel/types": "npm:^7.18.7" + "@metamask/base-controller": "npm:^3.2.0" + "@metamask/key-tree": "npm:^9.0.0" + "@metamask/permission-controller": "npm:^4.1.0" + "@metamask/snaps-registry": "npm:^1.2.2" + "@metamask/snaps-ui": "npm:^0.37.4-flask.1" + "@metamask/utils": "npm:^7.1.0" + "@noble/hashes": "npm:^1.3.1" + "@scure/base": "npm:^1.1.1" + chalk: "npm:^4.1.2" + cron-parser: "npm:^4.5.0" + eth-rpc-errors: "npm:^4.0.3" + fast-deep-equal: "npm:^3.1.3" + fast-json-stable-stringify: "npm:^2.1.0" + is-svg: "npm:^4.4.0" + rfdc: "npm:^1.3.0" + semver: "npm:^7.5.4" + ses: "npm:^0.18.7" + superstruct: "npm:^1.0.3" + validate-npm-package-name: "npm:^5.0.0" + checksum: 002a685195b433a3c3e5bb927f9f494271526998f3c44a58cce3737d35fc76f3b5317419048b68404b88508c8435e85fa0da55787ed4a4044ef319c8f1282807 + languageName: node + linkType: hard + "@metamask/snaps-utils@npm:^1.0.1, @metamask/snaps-utils@npm:^1.0.2": version: 1.0.2 resolution: "@metamask/snaps-utils@npm:1.0.2" @@ -5203,6 +5349,20 @@ __metadata: languageName: node linkType: hard +"@metamask/utils@npm:^7.1.0": + version: 7.1.0 + resolution: "@metamask/utils@npm:7.1.0" + dependencies: + "@ethereumjs/tx": "npm:^4.1.2" + "@noble/hashes": "npm:^1.3.1" + "@types/debug": "npm:^4.1.7" + debug: "npm:^4.3.4" + semver: "npm:^7.5.4" + superstruct: "npm:^1.0.3" + checksum: 35259e67d53d7c56cd2c001a525b75baf799f1a74a357cdb3f0b23fa2be7fb3b01d3fe676c2942c0abdf23e4e4e337380c6456376f90fe69a43e7fa39097d8be + languageName: node + linkType: hard + "@metamask/utils@npm:^8.0.0, @metamask/utils@npm:^8.1.0": version: 8.1.0 resolution: "@metamask/utils@npm:8.1.0" @@ -24255,7 +24415,7 @@ __metadata: "@metamask/eth-json-rpc-middleware": "npm:^11.0.0" "@metamask/eth-keyring-controller": "npm:^10.0.1" "@metamask/eth-ledger-bridge-keyring": "npm:^0.15.0" - "@metamask/eth-snap-keyring": "npm:^0.2.0" + "@metamask/eth-snap-keyring": "github:MetaMask/eth-snap-keyring#52a82c96546fa5dad22c73d4045a07e1b6d1b722" "@metamask/eth-token-tracker": "npm:^4.0.0" "@metamask/eth-trezor-keyring": "npm:^1.1.0" "@metamask/etherscan-link": "npm:^2.2.0" @@ -24263,7 +24423,7 @@ __metadata: "@metamask/gas-fee-controller": "npm:^6.0.1" "@metamask/jazzicon": "npm:^2.0.0" "@metamask/key-tree": "npm:^9.0.0" - "@metamask/keyring-api": "npm:^0.2.2" + "@metamask/keyring-api": "npm:^0.2.3" "@metamask/keyring-controller": "npm:^7.2.0" "@metamask/logo": "npm:^3.1.1" "@metamask/message-manager": "npm:^7.3.0" @@ -24279,7 +24439,7 @@ __metadata: "@metamask/providers": "npm:^11.1.0" "@metamask/rate-limit-controller": "npm:^3.0.0" "@metamask/rpc-methods": "npm:^1.0.2" - "@metamask/rpc-methods-flask": "npm:@metamask/rpc-methods@0.37.2-flask.1" + "@metamask/rpc-methods-flask": "npm:@metamask/rpc-methods@0.38.2-flask.1" "@metamask/safe-event-emitter": "npm:^2.0.0" "@metamask/scure-bip39": "npm:^2.0.3" "@metamask/signature-controller": "npm:^5.3.0" From cc3e426685591e6d8e32c9b2e5092e3fecf39c21 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Wed, 13 Sep 2023 20:45:20 +0800 Subject: [PATCH 106/235] Add extra confirmation when removing keyring snap (#20714) * feat: add extra confirmation when removing keyring snap * fix: input validation * fix: update view-snap to check for keyring accounts * feat: add keyring snap texts * fix: test and move keyringSnapRemovalWarning to its own folder * fix: remove log * fix: typo * chore: update account property name `supportedMethods` -> `methods` --------- Co-authored-by: Daniel Rocha <68558152+danroc@users.noreply.github.com> --- app/_locales/en/messages.json | 19 ++ test/data/mock-send-state.json | 8 +- .../keyring-snap-removal-warning/index.ts | 1 + .../keyring-account-list-item.tsx | 69 +++++++ .../keyring-snap-removal-warning.stories.js | 59 ++++++ .../keyring-snap-removal-warning.test.tsx | 122 ++++++++++++ .../keyring-snap-removal-warning.tsx | 183 ++++++++++++++++++ .../app/snaps/snap-removal-result/index.ts | 1 + .../snap-removal-result.tsx | 52 +++++ .../snap-remove-warning.js | 74 +++---- .../snap-remove-warning.stories.js | 2 +- .../snap-remove-warning.test.tsx | 36 ++++ .../settings/snaps/view-snap/view-snap.js | 28 ++- ui/store/actions.ts | 2 +- 14 files changed, 615 insertions(+), 41 deletions(-) create mode 100644 ui/components/app/snaps/keyring-snap-removal-warning/index.ts create mode 100644 ui/components/app/snaps/keyring-snap-removal-warning/keyring-account-list-item.tsx create mode 100644 ui/components/app/snaps/keyring-snap-removal-warning/keyring-snap-removal-warning.stories.js create mode 100644 ui/components/app/snaps/keyring-snap-removal-warning/keyring-snap-removal-warning.test.tsx create mode 100644 ui/components/app/snaps/keyring-snap-removal-warning/keyring-snap-removal-warning.tsx create mode 100644 ui/components/app/snaps/snap-removal-result/index.ts create mode 100644 ui/components/app/snaps/snap-removal-result/snap-removal-result.tsx create mode 100644 ui/components/app/snaps/snap-remove-warning/snap-remove-warning.test.tsx diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 0f4a987282dd..78332e191854 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -489,6 +489,9 @@ "backupApprovalNotice": { "message": "Backup your Secret Recovery Phrase to keep your wallet and funds secure." }, + "backupKeyringSnapReminder": { + "message": "Be sure you can access any accounts created by this snap on your own before removing it" + }, "backupNow": { "message": "Backup now" }, @@ -2104,6 +2107,16 @@ "message": "JSON File", "description": "format for importing an account" }, + "keyringAccountName": { + "message": "Account name" + }, + "keyringAccountPublicAddress": { + "message": "Public Address" + }, + "keyringSnapRemoveConfirmation": { + "message": "Type $1 to confirm you want to remove this snap:", + "description": "Asks user to input the name nap prior to deleting the snap. $1 is the snap name" + }, "keystone": { "message": "Keystone" }, @@ -3501,6 +3514,12 @@ "removeJWTDescription": { "message": "Are you sure you want to remove this token? All accounts assigned to this token will be removed from extension as well: " }, + "removeKeyringSnap": { + "message": "Removing this snap removes these accounts from MetaMask:" + }, + "removeKeyringSnapToolTip": { + "message": "The snap controls the accounts, and by removing it, the accounts will be removed from MetaMask, too, but they will remain in the blockchain." + }, "removeNFT": { "message": "Remove NFT" }, diff --git a/test/data/mock-send-state.json b/test/data/mock-send-state.json index 3ce8c50c8a97..3f6ba3ab0a32 100644 --- a/test/data/mock-send-state.json +++ b/test/data/mock-send-state.json @@ -129,7 +129,7 @@ }, "name": "Test Account", "options": {}, - "supportedMethods": [ + "methods": [ "personal_sign", "eth_sendTransaction", "eth_sign", @@ -152,7 +152,7 @@ }, "name": "Test Account 2", "options": {}, - "supportedMethods": [ + "methods": [ "personal_sign", "eth_sendTransaction", "eth_sign", @@ -175,7 +175,7 @@ }, "name": "Ledger Hardware 2", "options": {}, - "supportedMethods": [ + "methods": [ "personal_sign", "eth_sendTransaction", "eth_sign", @@ -198,7 +198,7 @@ }, "name": "Test Account 3", "options": {}, - "supportedMethods": [ + "methods": [ "personal_sign", "eth_sendTransaction", "eth_sign", diff --git a/ui/components/app/snaps/keyring-snap-removal-warning/index.ts b/ui/components/app/snaps/keyring-snap-removal-warning/index.ts new file mode 100644 index 000000000000..85d2c02bb062 --- /dev/null +++ b/ui/components/app/snaps/keyring-snap-removal-warning/index.ts @@ -0,0 +1 @@ +export { default } from './keyring-snap-removal-warning'; diff --git a/ui/components/app/snaps/keyring-snap-removal-warning/keyring-account-list-item.tsx b/ui/components/app/snaps/keyring-snap-removal-warning/keyring-account-list-item.tsx new file mode 100644 index 000000000000..34f3b10d6b28 --- /dev/null +++ b/ui/components/app/snaps/keyring-snap-removal-warning/keyring-account-list-item.tsx @@ -0,0 +1,69 @@ +import React from 'react'; +import { InternalAccount } from '@metamask/keyring-api'; +import { ButtonIcon, IconName, Text, Box } from '../../../component-library'; +import { + BlockSize, + BorderColor, + BorderRadius, + Display, + FlexDirection, + IconColor, + JustifyContent, + OverflowWrap, + TextColor, +} from '../../../../helpers/constants/design-system'; +import { useI18nContext } from '../../../../hooks/useI18nContext'; + +export const KeyringAccountListItem = ({ + account, + snapUrl, +}: { + account: InternalAccount; + snapUrl: string; +}) => { + const t = useI18nContext(); + return ( + + + + {t('keyringAccountName')} + {account.metadata.name} + + + + {t('keyringAccountPublicAddress')} + + {account.address} + + + + { + global.platform.openTab({ + url: snapUrl, + }); + }} + /> + + + ); +}; diff --git a/ui/components/app/snaps/keyring-snap-removal-warning/keyring-snap-removal-warning.stories.js b/ui/components/app/snaps/keyring-snap-removal-warning/keyring-snap-removal-warning.stories.js new file mode 100644 index 000000000000..d11680ed5c2c --- /dev/null +++ b/ui/components/app/snaps/keyring-snap-removal-warning/keyring-snap-removal-warning.stories.js @@ -0,0 +1,59 @@ +import React from 'react'; +import KeyringSnapRemovalWarning from './keyring-snap-removal-warning'; + +export default { + title: 'Components/App/Snaps/KeyringSnapRemovalWarning', + component: KeyringSnapRemovalWarning, + argTypes: { + onCancel: { + action: 'onCancel', + }, + onSubmit: { + action: 'onSubmit', + }, + snapName: { + control: 'text', + }, + snapUrl: { + control: 'text', + }, + isOpen: { + control: 'boolean', + }, + keyringAccounts: { + control: 'array', + }, + }, + args: { + snapName: 'ABC Snap', + snapUrl: 'mock-url', + isOpen: true, + keyringAccounts: [ + { + address: '0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b', + id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', + metadata: { + name: 'Test Account 2', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [ + 'personal_sign', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + ], + }, +}; + +export const DefaultStory = (args) => ; + +DefaultStory.storyName = 'Default'; diff --git a/ui/components/app/snaps/keyring-snap-removal-warning/keyring-snap-removal-warning.test.tsx b/ui/components/app/snaps/keyring-snap-removal-warning/keyring-snap-removal-warning.test.tsx new file mode 100644 index 000000000000..4b979afe583f --- /dev/null +++ b/ui/components/app/snaps/keyring-snap-removal-warning/keyring-snap-removal-warning.test.tsx @@ -0,0 +1,122 @@ +import React from 'react'; +import { waitFor, fireEvent } from '@testing-library/react'; +import { Snap } from '@metamask/snaps-utils'; +import { renderWithProvider } from '../../../../../test/jest'; +import messages from '../../../../../app/_locales/en/messages.json'; +import KeyringSnapRemovalWarning from './keyring-snap-removal-warning'; + +const mockOnClose = jest.fn(); +const mockOnCancel = jest.fn(); +const mockOnBack = jest.fn(); +const mockOnSubmit = jest.fn(); + +const mockSnap = { + id: 'mock-snap-id', + manifest: { + proposedName: 'mock-snap', + }, +} as Snap; + +const defaultArgs = { + isOpen: true, + snap: mockSnap, + onClose: mockOnClose, + onCancel: mockOnCancel, + onBack: mockOnBack, + onSubmit: mockOnSubmit, + keyringAccounts: [ + { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + id: 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3', + metadata: { + name: 'Test Account', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [ + 'personal_sign', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + { + address: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb', + id: '07c2cfec-36c9-46c4-8115-3836d3ac9047', + metadata: { + name: 'Test Account 2', + keyring: { + type: 'HD Key Tree', + }, + }, + options: {}, + methods: [ + 'personal_sign', + 'eth_sign', + 'eth_signTransaction', + 'eth_signTypedData', + 'eth_signTypedData_v1', + 'eth_signTypedData_v3', + 'eth_signTypedData_v4', + ], + type: 'eip155:eoa', + }, + ], +}; + +describe('Keyring Snap Remove Warning', () => { + it('show render the keyring snap warning and content', () => { + const { getByText } = renderWithProvider( + , + ); + expect( + getByText(messages.backupKeyringSnapReminder.message), + ).toBeInTheDocument(); + expect(getByText(messages.removeKeyringSnap.message)).toBeInTheDocument(); + + for (const account of defaultArgs.keyringAccounts) { + expect(getByText(account.metadata.name)).toBeInTheDocument(); + expect(getByText(account.address)).toBeInTheDocument(); + } + }); + + it('displays the keyring snap confirmation removal modal', async () => { + const { getByText, getByTestId, getAllByText } = renderWithProvider( + , + ); + + const nextButton = getByText('Continue'); + + fireEvent.click(nextButton); + + await waitFor(() => { + // translation is broken into three pieces + expect(getByText(/Type/u)).toBeInTheDocument(); + expect( + getByText(mockSnap.manifest?.proposedName as string), + ).toBeInTheDocument(); + expect( + getByText(/to confirm you want to remove this snap:/u), + ).toBeInTheDocument(); + }); + + const confirmationInput = getByTestId('remove-snap-confirmation-input'); + + fireEvent.change(confirmationInput, { + target: { value: mockSnap.manifest?.proposedName }, + }); + + await waitFor(() => { + const removeSnapButton = getAllByText('Remove snap')[1]; + expect(removeSnapButton).not.toBeDisabled(); + fireEvent.click(removeSnapButton); + expect(mockOnSubmit).toBeCalled(); + }); + }); +}); diff --git a/ui/components/app/snaps/keyring-snap-removal-warning/keyring-snap-removal-warning.tsx b/ui/components/app/snaps/keyring-snap-removal-warning/keyring-snap-removal-warning.tsx new file mode 100644 index 000000000000..69a64e5c2fea --- /dev/null +++ b/ui/components/app/snaps/keyring-snap-removal-warning/keyring-snap-removal-warning.tsx @@ -0,0 +1,183 @@ +import React, { useState } from 'react'; +import { InternalAccount } from '@metamask/keyring-api'; +import { Snap } from '@metamask/snaps-utils'; +import { + BannerAlert, + Box, + Button, + ButtonSize, + ButtonVariant, + Modal, + ModalContent, + ModalHeader, + ModalOverlay, + Text, + TextField, +} from '../../../component-library'; +import { + BlockSize, + Display, + FlexDirection, + FontWeight, + JustifyContent, + Severity, +} from '../../../../helpers/constants/design-system'; +import { useI18nContext } from '../../../../hooks/useI18nContext'; +import InfoTooltip from '../../../ui/info-tooltip'; +import { KeyringAccountListItem } from './keyring-account-list-item'; + +export default function KeyringRemovalSnapWarning({ + snap, + keyringAccounts, + onCancel, + onClose, + onBack, + onSubmit, + isOpen, +}: { + snap: Snap; + keyringAccounts: InternalAccount[]; + onCancel: () => void; + onClose: () => void; + onBack: () => void; + onSubmit: () => void; + isOpen: boolean; +}) { + const t = useI18nContext(); + const [showConfirmation, setShowConfirmation] = useState(false); + const [confirmedRemoval, setConfirmedRemoval] = useState(false); + const [confirmationInput, setConfirmationInput] = useState(''); + const [error, setError] = useState(false); + + const validateConfirmationInput = (input: string): boolean => { + setError(false); + if (input === snap.manifest.proposedName) { + return true; + } + setError(true); + return false; + }; + + return ( + <> + + + + { + setShowConfirmation(false); + onBack(); + }} + onClose={() => { + setShowConfirmation(false); + onClose(); + }} + > + {t('removeSnap')} + + {showConfirmation === false ? ( + <> + + {t('backupKeyringSnapReminder')} + + + {t('removeKeyringSnap')} + + + {keyringAccounts.map((account, index) => { + return ( + + ); + })} + + ) : ( + <> + + + {t('backupKeyringSnapReminder')} + + + {t('keyringSnapRemoveConfirmation', [ + + {snap.manifest.proposedName} + , + ])} + + {/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */} + {/* @ts-ignore TODO: fix TextField props */} + { + setConfirmationInput(e.target.value); + setConfirmedRemoval( + validateConfirmationInput(e.target.value), + ); + }} + error={error} + inputProps={{ + 'data-testid': 'remove-snap-confirmation-input', + }} + type="text" + /> + + + )} + + + + + + + + ); +} diff --git a/ui/components/app/snaps/snap-removal-result/index.ts b/ui/components/app/snaps/snap-removal-result/index.ts new file mode 100644 index 000000000000..81046071afa6 --- /dev/null +++ b/ui/components/app/snaps/snap-removal-result/index.ts @@ -0,0 +1 @@ +export { default } from './snap-removal-result'; diff --git a/ui/components/app/snaps/snap-removal-result/snap-removal-result.tsx b/ui/components/app/snaps/snap-removal-result/snap-removal-result.tsx new file mode 100644 index 000000000000..dcd39a862881 --- /dev/null +++ b/ui/components/app/snaps/snap-removal-result/snap-removal-result.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { + Box, + Icon, + IconName, + Modal, + ModalContent, + ModalHeader, + ModalOverlay, + Text, +} from '../../../component-library'; +import { + AlignItems, + Display, + FlexDirection, + JustifyContent, +} from '../../../../helpers/constants/design-system'; + +export default function SnapRemovalResult({ + success, + snapName, + isOpen, + onClose, +}: { + success: boolean; + snapName: string; + isOpen: boolean; + onClose: () => void; +}) { + return ( + + + + + + + {`${snapName} ${success ? 'removed' : 'not removed'}`} + + + + ); +} diff --git a/ui/components/app/snaps/snap-remove-warning/snap-remove-warning.js b/ui/components/app/snaps/snap-remove-warning/snap-remove-warning.js index 593cf1c3bc6d..2a9e9e711670 100644 --- a/ui/components/app/snaps/snap-remove-warning/snap-remove-warning.js +++ b/ui/components/app/snaps/snap-remove-warning/snap-remove-warning.js @@ -9,8 +9,8 @@ import { ModalContent, ModalHeader, ModalOverlay, - BUTTON_VARIANT, - BUTTON_SIZES, + ButtonSize, + ButtonVariant, } from '../../../component-library'; import { @@ -26,39 +26,45 @@ export default function SnapRemoveWarning({ snapName, }) { const t = useI18nContext(); + return ( - - - - {t('pleaseConfirm')} - {t('removeSnapConfirmation', [snapName])} - - - - - - + <> + + + + {t('pleaseConfirm')} + {t('removeSnapConfirmation', [snapName])} + + + + + + + + ); } diff --git a/ui/components/app/snaps/snap-remove-warning/snap-remove-warning.stories.js b/ui/components/app/snaps/snap-remove-warning/snap-remove-warning.stories.js index c38ef8113670..36481568d5b4 100644 --- a/ui/components/app/snaps/snap-remove-warning/snap-remove-warning.stories.js +++ b/ui/components/app/snaps/snap-remove-warning/snap-remove-warning.stories.js @@ -19,7 +19,7 @@ export default { }, }, args: { - snapName: 'Snap Name', + snapName: 'ABC Snap', isOpen: true, }, }; diff --git a/ui/components/app/snaps/snap-remove-warning/snap-remove-warning.test.tsx b/ui/components/app/snaps/snap-remove-warning/snap-remove-warning.test.tsx new file mode 100644 index 000000000000..2efe0cbb25a2 --- /dev/null +++ b/ui/components/app/snaps/snap-remove-warning/snap-remove-warning.test.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { waitFor, fireEvent } from '@testing-library/react'; +import { renderWithProvider } from '../../../../../test/jest'; +import SnapRemoveWarning from './snap-remove-warning'; + +const mockOnCancel = jest.fn(); +const mockOnSubmit = jest.fn(); +const snapName = 'test-snap'; + +const defaultArgs = { + isOpen: true, + onCancel: mockOnCancel, + onSubmit: mockOnSubmit, + snapName, + snapUrl: 'test-snap-url', +}; + +describe('Snap Remove Warning', () => { + describe('Snap Warning', () => { + it('should render the snap warning and content', async () => { + const { getByText } = renderWithProvider( + , + ); + expect(getByText('Please confirm')).toBeInTheDocument(); + expect( + getByText(`Are you sure you want to remove ${snapName}?`), + ).toBeInTheDocument(); + + await waitFor(() => { + const removeSnapButton = getByText('Remove snap'); + fireEvent.click(removeSnapButton); + expect(mockOnSubmit).toBeCalled(); + }); + }); + }); +}); diff --git a/ui/pages/settings/snaps/view-snap/view-snap.js b/ui/pages/settings/snaps/view-snap/view-snap.js index b21dcf169d58..35f835ef21ae 100644 --- a/ui/pages/settings/snaps/view-snap/view-snap.js +++ b/ui/pages/settings/snaps/view-snap/view-snap.js @@ -17,6 +17,7 @@ import { import SnapAuthorshipExpanded from '../../../../components/app/snaps/snap-authorship-expanded'; import Box from '../../../../components/ui/box'; import SnapRemoveWarning from '../../../../components/app/snaps/snap-remove-warning'; +import KeyringSnapRemovalWarning from '../../../../components/app/snaps/keyring-snap-removal-warning'; import ConnectedSitesList from '../../../../components/app/connected-sites-list'; import { SNAPS_LIST_ROUTE } from '../../../../helpers/constants/routes'; @@ -31,6 +32,7 @@ import { getPermissions, getPermissionSubjects, getTargetSubjectMetadata, + getInternalAccounts, } from '../../../../selectors'; import { getSnapName } from '../../../../helpers/utils/util'; import { Text } from '../../../../components/component-library'; @@ -50,6 +52,7 @@ function ViewSnap() { const snap = Object.entries(snaps) .map(([_, snapState]) => snapState) .find((snapState) => snapState.id === decodedSnapId); + const internalAccounts = useSelector(getInternalAccounts); const [isShowingRemoveWarning, setIsShowingRemoveWarning] = useState(false); const [isDescriptionOpen, setIsDescriptionOpen] = useState(false); @@ -79,6 +82,15 @@ function ViewSnap() { const targetSubjectMetadata = useSelector((state) => getTargetSubjectMetadata(state, snap?.id), ); + const isKeyringSnap = Boolean( + subjects[snap?.id]?.permissions?.snap_manageAccounts, + ); + const keyringAccounts = internalAccounts.filter( + (internalAccount) => + isKeyringSnap && + internalAccount.metadata.keyring.type === 'Snap Keyring' && + internalAccount.metadata.snap.id === snap?.id, + ); const dispatch = useDispatch(); const onDisconnect = (connectedOrigin, snapId) => { @@ -190,13 +202,27 @@ function ViewSnap() { setIsShowingRemoveWarning(false)} onSubmit={async () => { await dispatch(removeSnap(snap.id)); }} snapName={snapName} /> + setIsShowingRemoveWarning(false)} + onClose={() => setIsShowingRemoveWarning(false)} + onBack={() => setIsShowingRemoveWarning(false)} + onSubmit={async () => { + await dispatch(removeSnap(snap.id)); + }} + isOpen={isShowingRemoveWarning && isKeyringSnap} + /> diff --git a/ui/store/actions.ts b/ui/store/actions.ts index af088024ac32..cf69b188e7a2 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -1185,7 +1185,7 @@ export function removeSnap( }, })) as unknown as any[]; for (const account of accounts) { - dispatch(removeAccount(account.address.toLowerCase())); + dispatch(removeAccount(account.id)); } } ///: END:ONLY_INCLUDE_IN From c158e5a90e08b3c33261da12443f57c3b08a5af3 Mon Sep 17 00:00:00 2001 From: Daniel Rocha <68558152+danroc@users.noreply.github.com> Date: Wed, 13 Sep 2023 15:21:09 +0200 Subject: [PATCH 107/235] chore: update `keyring-api` --- package.json | 2 +- yarn.lock | 32 ++++++++++++++++---------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index e3b9db57f469..d209c3ab165f 100644 --- a/package.json +++ b/package.json @@ -252,7 +252,7 @@ "@metamask/gas-fee-controller": "^6.0.1", "@metamask/jazzicon": "^2.0.0", "@metamask/key-tree": "^9.0.0", - "@metamask/keyring-api": "^0.2.3", + "@metamask/keyring-api": "github:MetaMask/keyring-api#19025afe6bceec66d927f7352753c2c8b3c54013", "@metamask/keyring-controller": "^7.2.0", "@metamask/logo": "^3.1.1", "@metamask/message-manager": "^7.3.0", diff --git a/yarn.lock b/yarn.lock index af92513106fc..5f2b28389312 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4319,9 +4319,9 @@ __metadata: languageName: node linkType: hard -"@metamask/keyring-api@github:MetaMask/keyring-api#8b51af7ac82c5d8654ba9c07aed96e3aa2526d97": +"@metamask/keyring-api@github:MetaMask/keyring-api#19025afe6bceec66d927f7352753c2c8b3c54013": version: 0.2.3 - resolution: "@metamask/keyring-api@https://github.com/MetaMask/keyring-api.git#commit=8b51af7ac82c5d8654ba9c07aed96e3aa2526d97" + resolution: "@metamask/keyring-api@https://github.com/MetaMask/keyring-api.git#commit=19025afe6bceec66d927f7352753c2c8b3c54013" dependencies: "@metamask/providers": "npm:^12.0.0" "@metamask/rpc-methods": "npm:^0.38.1-flask.1" @@ -4331,39 +4331,39 @@ __metadata: "@types/uuid": "npm:^9.0.1" superstruct: "npm:^1.0.3" uuid: "npm:^9.0.0" - checksum: a9720bb1788e109ee6ba3f0f7191c34a38f4185117f3891ffd5f97365b0b3c06b5942ecaf895c775dfa3c6173c4ae711b0c26870ea8315f2f2440ea415895fb6 + checksum: 02ded223bbea479de2bcb0c6fa4f879bfe1f72bb41e3bb02fececa97467aa131e0744fa39c6901333739c12e50343e051cbfadcb4988df5ab081b7e5ab4bc26d languageName: node linkType: hard -"@metamask/keyring-api@npm:^0.2.2": - version: 0.2.2 - resolution: "@metamask/keyring-api@npm:0.2.2" +"@metamask/keyring-api@github:MetaMask/keyring-api#8b51af7ac82c5d8654ba9c07aed96e3aa2526d97": + version: 0.2.3 + resolution: "@metamask/keyring-api@https://github.com/MetaMask/keyring-api.git#commit=8b51af7ac82c5d8654ba9c07aed96e3aa2526d97" dependencies: - "@metamask/providers": "npm:^11.0.0" + "@metamask/providers": "npm:^12.0.0" "@metamask/rpc-methods": "npm:^0.38.1-flask.1" "@metamask/snaps-controllers": "npm:^0.38.2-flask.1" "@metamask/snaps-utils": "npm:^0.38.2-flask.1" - "@metamask/utils": "npm:^8.0.0" + "@metamask/utils": "npm:^8.1.0" "@types/uuid": "npm:^9.0.1" superstruct: "npm:^1.0.3" uuid: "npm:^9.0.0" - checksum: c98d5228e89c710e31b792b94569316ab4afc94e472e485b7da7d3ef3b75b441e49784d9ac35dd8891242db5c21d2173f2c8ec58d1182d418563ff403b45fcc3 + checksum: a9720bb1788e109ee6ba3f0f7191c34a38f4185117f3891ffd5f97365b0b3c06b5942ecaf895c775dfa3c6173c4ae711b0c26870ea8315f2f2440ea415895fb6 languageName: node linkType: hard -"@metamask/keyring-api@npm:^0.2.3": - version: 0.2.3 - resolution: "@metamask/keyring-api@npm:0.2.3" +"@metamask/keyring-api@npm:^0.2.2": + version: 0.2.2 + resolution: "@metamask/keyring-api@npm:0.2.2" dependencies: - "@metamask/providers": "npm:^12.0.0" + "@metamask/providers": "npm:^11.0.0" "@metamask/rpc-methods": "npm:^0.38.1-flask.1" "@metamask/snaps-controllers": "npm:^0.38.2-flask.1" "@metamask/snaps-utils": "npm:^0.38.2-flask.1" - "@metamask/utils": "npm:^8.1.0" + "@metamask/utils": "npm:^8.0.0" "@types/uuid": "npm:^9.0.1" superstruct: "npm:^1.0.3" uuid: "npm:^9.0.0" - checksum: a9720bb1788e109ee6ba3f0f7191c34a38f4185117f3891ffd5f97365b0b3c06b5942ecaf895c775dfa3c6173c4ae711b0c26870ea8315f2f2440ea415895fb6 + checksum: c98d5228e89c710e31b792b94569316ab4afc94e472e485b7da7d3ef3b75b441e49784d9ac35dd8891242db5c21d2173f2c8ec58d1182d418563ff403b45fcc3 languageName: node linkType: hard @@ -24423,7 +24423,7 @@ __metadata: "@metamask/gas-fee-controller": "npm:^6.0.1" "@metamask/jazzicon": "npm:^2.0.0" "@metamask/key-tree": "npm:^9.0.0" - "@metamask/keyring-api": "npm:^0.2.3" + "@metamask/keyring-api": "github:MetaMask/keyring-api#19025afe6bceec66d927f7352753c2c8b3c54013" "@metamask/keyring-controller": "npm:^7.2.0" "@metamask/logo": "npm:^3.1.1" "@metamask/message-manager": "npm:^7.3.0" From 99a150106ac694af1660f557ee8c7a075e87ee1c Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Tue, 12 Sep 2023 11:10:55 +0200 Subject: [PATCH 108/235] Fix unit test --- shared/constants/permissions.test.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/shared/constants/permissions.test.js b/shared/constants/permissions.test.js index f1ef4a5563a2..0bc4e9cc37db 100644 --- a/shared/constants/permissions.test.js +++ b/shared/constants/permissions.test.js @@ -24,12 +24,14 @@ describe('EndowmentPermissions', () => { }); }); +const FlaskOnlyPermissions = ['snap_manageAccounts', 'snap_getLocale']; + describe('RestrictedMethods', () => { it('has the expected permission keys', () => { // this is done because we there is a difference between flask and stable permissions // the code fence in `shared/constants/snaps/permissions.ts` is not supported in jest const mainBuildRestrictedMethodPermissions = Object.keys(RestrictedMethods) - .filter((key) => key !== 'snap_manageAccounts') + .filter((key) => !FlaskOnlyPermissions.includes(key)) .sort(); expect(mainBuildRestrictedMethodPermissions).toStrictEqual( @@ -54,7 +56,7 @@ describe('Flask Restricted Methods', () => { it('has the expected flask permission keys', () => { const flaskExcludedSnapPermissions = Object.keys( ExcludedSnapPermissions, - ).filter((key) => key !== 'snap_manageAccounts'); + ).filter((key) => !FlaskOnlyPermissions.includes(key)); expect(Object.keys(RestrictedMethods).sort()).toStrictEqual( [ From 814454aa32b0eabcc3cd6926f89fb7bd55851dbc Mon Sep 17 00:00:00 2001 From: Daniel Rocha <68558152+danroc@users.noreply.github.com> Date: Wed, 13 Sep 2023 15:38:40 +0200 Subject: [PATCH 109/235] chore: update `yarn.lock` --- yarn.lock | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/yarn.lock b/yarn.lock index 5f2b28389312..60a181400874 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5057,18 +5057,7 @@ __metadata: languageName: node linkType: hard -"@metamask/snaps-registry@npm:^1.2.1": - version: 1.2.1 - resolution: "@metamask/snaps-registry@npm:1.2.1" - dependencies: - "@metamask/utils": "npm:^6.0.0" - "@noble/secp256k1": "npm:^1.7.1" - superstruct: "npm:^1.0.3" - checksum: de16245fd26b98f9bab7764838f7911aec0ecc409dd814b3ed6fe39a1cb2ea579c3a31deafbd348082942f6aae1a82d8e2dd8fd46fb071c3d1e4974b0d07e87a - languageName: node - linkType: hard - -"@metamask/snaps-registry@npm:^1.2.2": +"@metamask/snaps-registry@npm:^1.2.1, @metamask/snaps-registry@npm:^1.2.2": version: 1.2.2 resolution: "@metamask/snaps-registry@npm:1.2.2" dependencies: @@ -5335,7 +5324,7 @@ __metadata: languageName: node linkType: hard -"@metamask/utils@npm:^6.0.0, @metamask/utils@npm:^6.0.1, @metamask/utils@npm:^6.2.0": +"@metamask/utils@npm:^6.0.1, @metamask/utils@npm:^6.2.0": version: 6.2.0 resolution: "@metamask/utils@npm:6.2.0" dependencies: From c2e4bd314bf8c353000f78a1ed5eef84eb1f22cf Mon Sep 17 00:00:00 2001 From: Daniel Rocha <68558152+danroc@users.noreply.github.com> Date: Wed, 13 Sep 2023 16:14:49 +0200 Subject: [PATCH 110/235] chore: update `keyring-api` --- package.json | 2 +- yarn.lock | 32 ++++++++++++++++---------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index d209c3ab165f..9a72549ea9b3 100644 --- a/package.json +++ b/package.json @@ -252,7 +252,7 @@ "@metamask/gas-fee-controller": "^6.0.1", "@metamask/jazzicon": "^2.0.0", "@metamask/key-tree": "^9.0.0", - "@metamask/keyring-api": "github:MetaMask/keyring-api#19025afe6bceec66d927f7352753c2c8b3c54013", + "@metamask/keyring-api": "^0.2.4", "@metamask/keyring-controller": "^7.2.0", "@metamask/logo": "^3.1.1", "@metamask/message-manager": "^7.3.0", diff --git a/yarn.lock b/yarn.lock index 60a181400874..55706d1ba6e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4319,9 +4319,9 @@ __metadata: languageName: node linkType: hard -"@metamask/keyring-api@github:MetaMask/keyring-api#19025afe6bceec66d927f7352753c2c8b3c54013": +"@metamask/keyring-api@github:MetaMask/keyring-api#8b51af7ac82c5d8654ba9c07aed96e3aa2526d97": version: 0.2.3 - resolution: "@metamask/keyring-api@https://github.com/MetaMask/keyring-api.git#commit=19025afe6bceec66d927f7352753c2c8b3c54013" + resolution: "@metamask/keyring-api@https://github.com/MetaMask/keyring-api.git#commit=8b51af7ac82c5d8654ba9c07aed96e3aa2526d97" dependencies: "@metamask/providers": "npm:^12.0.0" "@metamask/rpc-methods": "npm:^0.38.1-flask.1" @@ -4331,39 +4331,39 @@ __metadata: "@types/uuid": "npm:^9.0.1" superstruct: "npm:^1.0.3" uuid: "npm:^9.0.0" - checksum: 02ded223bbea479de2bcb0c6fa4f879bfe1f72bb41e3bb02fececa97467aa131e0744fa39c6901333739c12e50343e051cbfadcb4988df5ab081b7e5ab4bc26d + checksum: a9720bb1788e109ee6ba3f0f7191c34a38f4185117f3891ffd5f97365b0b3c06b5942ecaf895c775dfa3c6173c4ae711b0c26870ea8315f2f2440ea415895fb6 languageName: node linkType: hard -"@metamask/keyring-api@github:MetaMask/keyring-api#8b51af7ac82c5d8654ba9c07aed96e3aa2526d97": - version: 0.2.3 - resolution: "@metamask/keyring-api@https://github.com/MetaMask/keyring-api.git#commit=8b51af7ac82c5d8654ba9c07aed96e3aa2526d97" +"@metamask/keyring-api@npm:^0.2.2": + version: 0.2.2 + resolution: "@metamask/keyring-api@npm:0.2.2" dependencies: - "@metamask/providers": "npm:^12.0.0" + "@metamask/providers": "npm:^11.0.0" "@metamask/rpc-methods": "npm:^0.38.1-flask.1" "@metamask/snaps-controllers": "npm:^0.38.2-flask.1" "@metamask/snaps-utils": "npm:^0.38.2-flask.1" - "@metamask/utils": "npm:^8.1.0" + "@metamask/utils": "npm:^8.0.0" "@types/uuid": "npm:^9.0.1" superstruct: "npm:^1.0.3" uuid: "npm:^9.0.0" - checksum: a9720bb1788e109ee6ba3f0f7191c34a38f4185117f3891ffd5f97365b0b3c06b5942ecaf895c775dfa3c6173c4ae711b0c26870ea8315f2f2440ea415895fb6 + checksum: c98d5228e89c710e31b792b94569316ab4afc94e472e485b7da7d3ef3b75b441e49784d9ac35dd8891242db5c21d2173f2c8ec58d1182d418563ff403b45fcc3 languageName: node linkType: hard -"@metamask/keyring-api@npm:^0.2.2": - version: 0.2.2 - resolution: "@metamask/keyring-api@npm:0.2.2" +"@metamask/keyring-api@npm:^0.2.4": + version: 0.2.4 + resolution: "@metamask/keyring-api@npm:0.2.4" dependencies: - "@metamask/providers": "npm:^11.0.0" + "@metamask/providers": "npm:^12.0.0" "@metamask/rpc-methods": "npm:^0.38.1-flask.1" "@metamask/snaps-controllers": "npm:^0.38.2-flask.1" "@metamask/snaps-utils": "npm:^0.38.2-flask.1" - "@metamask/utils": "npm:^8.0.0" + "@metamask/utils": "npm:^8.1.0" "@types/uuid": "npm:^9.0.1" superstruct: "npm:^1.0.3" uuid: "npm:^9.0.0" - checksum: c98d5228e89c710e31b792b94569316ab4afc94e472e485b7da7d3ef3b75b441e49784d9ac35dd8891242db5c21d2173f2c8ec58d1182d418563ff403b45fcc3 + checksum: d61e2bf7252135e5bb099bb10886fcbd4c25392e3bfe9beb267b57f97e653b687e727fd67726492723837b66c40cd226e2539c5a80ebfbe1e56ebf9e93f93728 languageName: node linkType: hard @@ -24412,7 +24412,7 @@ __metadata: "@metamask/gas-fee-controller": "npm:^6.0.1" "@metamask/jazzicon": "npm:^2.0.0" "@metamask/key-tree": "npm:^9.0.0" - "@metamask/keyring-api": "github:MetaMask/keyring-api#19025afe6bceec66d927f7352753c2c8b3c54013" + "@metamask/keyring-api": "npm:^0.2.4" "@metamask/keyring-controller": "npm:^7.2.0" "@metamask/logo": "npm:^3.1.1" "@metamask/message-manager": "npm:^7.3.0" From 6ef9eb424816189d3b91d8a48e6b01de457c5183 Mon Sep 17 00:00:00 2001 From: Daniel Rocha <68558152+danroc@users.noreply.github.com> Date: Wed, 13 Sep 2023 16:15:22 +0200 Subject: [PATCH 111/235] chore: ignore `snap_getLocale` in unit tests --- shared/constants/snaps/permissions.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared/constants/snaps/permissions.ts b/shared/constants/snaps/permissions.ts index 3642e2187166..ab8fa6895e72 100644 --- a/shared/constants/snaps/permissions.ts +++ b/shared/constants/snaps/permissions.ts @@ -17,6 +17,8 @@ export const ExcludedSnapPermissions = Object.freeze({ ///: BEGIN:ONLY_INCLUDE_IN(build-main) snap_manageAccounts: 'This permission is still in development and therefore not available.', + snap_getLocale: + 'This permission is still in development and therefore not available.', ///: END:ONLY_INCLUDE_IN eth_accounts: 'eth_accounts is disabled. For more information please see https://github.com/MetaMask/snaps/issues/990.', From e932791a4813cd46462562163085bb5b2014cb3e Mon Sep 17 00:00:00 2001 From: Daniel Rocha <68558152+danroc@users.noreply.github.com> Date: Wed, 13 Sep 2023 16:16:02 +0200 Subject: [PATCH 112/235] chore: update `yarn.lock` --- yarn.lock | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/yarn.lock b/yarn.lock index 55706d1ba6e7..b68e42874fbf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4335,23 +4335,7 @@ __metadata: languageName: node linkType: hard -"@metamask/keyring-api@npm:^0.2.2": - version: 0.2.2 - resolution: "@metamask/keyring-api@npm:0.2.2" - dependencies: - "@metamask/providers": "npm:^11.0.0" - "@metamask/rpc-methods": "npm:^0.38.1-flask.1" - "@metamask/snaps-controllers": "npm:^0.38.2-flask.1" - "@metamask/snaps-utils": "npm:^0.38.2-flask.1" - "@metamask/utils": "npm:^8.0.0" - "@types/uuid": "npm:^9.0.1" - superstruct: "npm:^1.0.3" - uuid: "npm:^9.0.0" - checksum: c98d5228e89c710e31b792b94569316ab4afc94e472e485b7da7d3ef3b75b441e49784d9ac35dd8891242db5c21d2173f2c8ec58d1182d418563ff403b45fcc3 - languageName: node - linkType: hard - -"@metamask/keyring-api@npm:^0.2.4": +"@metamask/keyring-api@npm:^0.2.2, @metamask/keyring-api@npm:^0.2.4": version: 0.2.4 resolution: "@metamask/keyring-api@npm:0.2.4" dependencies: From 766f53eadc84b6148c75fc4a47b0e351422ae297 Mon Sep 17 00:00:00 2001 From: Daniel Rocha <68558152+danroc@users.noreply.github.com> Date: Wed, 13 Sep 2023 16:32:45 +0200 Subject: [PATCH 113/235] chore: update `eth-snap-keyring` --- package.json | 2 +- yarn.lock | 139 ++++++++++++++++++++++++--------------------------- 2 files changed, 67 insertions(+), 74 deletions(-) diff --git a/package.json b/package.json index 9a72549ea9b3..d8486c55a415 100644 --- a/package.json +++ b/package.json @@ -245,7 +245,7 @@ "@metamask/eth-json-rpc-middleware": "^11.0.0", "@metamask/eth-keyring-controller": "^10.0.1", "@metamask/eth-ledger-bridge-keyring": "^0.15.0", - "@metamask/eth-snap-keyring": "github:MetaMask/eth-snap-keyring#52a82c96546fa5dad22c73d4045a07e1b6d1b722", + "@metamask/eth-snap-keyring": "^0.2.1", "@metamask/eth-token-tracker": "^4.0.0", "@metamask/eth-trezor-keyring": "^1.1.0", "@metamask/etherscan-link": "^2.2.0", diff --git a/yarn.lock b/yarn.lock index b68e42874fbf..42083d1716e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3784,6 +3784,16 @@ __metadata: languageName: node linkType: hard +"@metamask/abi-utils@npm:^2.0.2": + version: 2.0.2 + resolution: "@metamask/abi-utils@npm:2.0.2" + dependencies: + "@metamask/utils": "npm:^8.0.0" + superstruct: "npm:^1.0.3" + checksum: 150218e81d4e494196ce967f203a4fa6c03c07dc4e319cf72429cb37586e851adf9b0b89e341faeab38c5f03f6f8dff175486653e9a6da6c7fa9e4c9f96430e9 + languageName: node + linkType: hard + "@metamask/address-book-controller@npm:^3.0.0": version: 3.0.0 resolution: "@metamask/address-book-controller@npm:3.0.0" @@ -4133,7 +4143,7 @@ __metadata: languageName: node linkType: hard -"@metamask/eth-sig-util@npm:^5.0.0, @metamask/eth-sig-util@npm:^5.0.1, @metamask/eth-sig-util@npm:^5.0.2, @metamask/eth-sig-util@npm:^5.1.0": +"@metamask/eth-sig-util@npm:^5.0.0, @metamask/eth-sig-util@npm:^5.0.1, @metamask/eth-sig-util@npm:^5.0.2": version: 5.1.0 resolution: "@metamask/eth-sig-util@npm:5.1.0" dependencies: @@ -4161,6 +4171,21 @@ __metadata: languageName: node linkType: hard +"@metamask/eth-sig-util@npm:^7.0.0": + version: 7.0.0 + resolution: "@metamask/eth-sig-util@npm:7.0.0" + dependencies: + "@ethereumjs/util": "npm:^8.1.0" + "@metamask/abi-utils": "npm:^2.0.2" + "@metamask/utils": "npm:^8.1.0" + ethereum-cryptography: "npm:^2.1.2" + ethjs-util: "npm:^0.1.6" + tweetnacl: "npm:^1.0.3" + tweetnacl-util: "npm:^0.15.1" + checksum: c399e615749ac78224d5e68883eff9bfb856eb26225d218937ac5ccb84e529157c0b1244dce449eb3dcb408a7830f2b4c0c1b2a6b1653049d93b3d76aae17860 + languageName: node + linkType: hard + "@metamask/eth-simple-keyring@npm:^5.0.0": version: 5.0.0 resolution: "@metamask/eth-simple-keyring@npm:5.0.0" @@ -4173,35 +4198,19 @@ __metadata: languageName: node linkType: hard -"@metamask/eth-snap-keyring@github:MetaMask/eth-snap-keyring#52a82c96546fa5dad22c73d4045a07e1b6d1b722": - version: 0.2.0 - resolution: "@metamask/eth-snap-keyring@https://github.com/MetaMask/eth-snap-keyring.git#commit=52a82c96546fa5dad22c73d4045a07e1b6d1b722" - dependencies: - "@ethereumjs/tx": "npm:^4.1.2" - "@metamask/eth-sig-util": "npm:^5.1.0" - "@metamask/keyring-api": "github:MetaMask/keyring-api#8b51af7ac82c5d8654ba9c07aed96e3aa2526d97" - "@metamask/snaps-controllers": "npm:^0.38.2-flask.1" - "@metamask/utils": "npm:^8.1.0" - "@types/uuid": "npm:^9.0.1" - superstruct: "npm:^1.0.3" - uuid: "npm:^9.0.0" - checksum: 80ae5fec21aa50e707b64d35cb3bbbfe916c69f7c6819a24b004e14ddedeb2925a0fa46e908864b6a234b774009706e87e3676652a3a5bdff2fd5a50d6894bb6 - languageName: node - linkType: hard - -"@metamask/eth-snap-keyring@npm:^0.2.0": - version: 0.2.0 - resolution: "@metamask/eth-snap-keyring@npm:0.2.0" +"@metamask/eth-snap-keyring@npm:^0.2.0, @metamask/eth-snap-keyring@npm:^0.2.1": + version: 0.2.1 + resolution: "@metamask/eth-snap-keyring@npm:0.2.1" dependencies: - "@ethereumjs/tx": "npm:^4.1.2" - "@metamask/eth-sig-util": "npm:^5.1.0" - "@metamask/keyring-api": "npm:^0.2.2" + "@ethereumjs/tx": "npm:^4.2.0" + "@metamask/eth-sig-util": "npm:^7.0.0" + "@metamask/keyring-api": "npm:^0.2.3" "@metamask/snaps-controllers": "npm:^0.38.2-flask.1" "@metamask/utils": "npm:^8.1.0" "@types/uuid": "npm:^9.0.1" superstruct: "npm:^1.0.3" uuid: "npm:^9.0.0" - checksum: 986c607b72f3b1648613d71af959c9b94ffe5c27fb6a80f202015a76771331de971223eafc8c77567c148dbad2818a23c0f1a6541644ad5ebc8cc4e35b044553 + checksum: f6bf86d31a8ef3af7dc617d8bb29dd0c78f249571ea142b141d90936e50c145d857d9cc4da6ab0e460a5636d554ef59594bb377356b3d544fa6cff7ca386954f languageName: node linkType: hard @@ -4319,23 +4328,7 @@ __metadata: languageName: node linkType: hard -"@metamask/keyring-api@github:MetaMask/keyring-api#8b51af7ac82c5d8654ba9c07aed96e3aa2526d97": - version: 0.2.3 - resolution: "@metamask/keyring-api@https://github.com/MetaMask/keyring-api.git#commit=8b51af7ac82c5d8654ba9c07aed96e3aa2526d97" - dependencies: - "@metamask/providers": "npm:^12.0.0" - "@metamask/rpc-methods": "npm:^0.38.1-flask.1" - "@metamask/snaps-controllers": "npm:^0.38.2-flask.1" - "@metamask/snaps-utils": "npm:^0.38.2-flask.1" - "@metamask/utils": "npm:^8.1.0" - "@types/uuid": "npm:^9.0.1" - superstruct: "npm:^1.0.3" - uuid: "npm:^9.0.0" - checksum: a9720bb1788e109ee6ba3f0f7191c34a38f4185117f3891ffd5f97365b0b3c06b5942ecaf895c775dfa3c6173c4ae711b0c26870ea8315f2f2440ea415895fb6 - languageName: node - linkType: hard - -"@metamask/keyring-api@npm:^0.2.2, @metamask/keyring-api@npm:^0.2.4": +"@metamask/keyring-api@npm:^0.2.2, @metamask/keyring-api@npm:^0.2.3, @metamask/keyring-api@npm:^0.2.4": version: 0.2.4 resolution: "@metamask/keyring-api@npm:0.2.4" dependencies: @@ -5383,12 +5376,12 @@ __metadata: languageName: node linkType: hard -"@noble/curves@npm:1.0.0, @noble/curves@npm:~1.0.0": - version: 1.0.0 - resolution: "@noble/curves@npm:1.0.0" +"@noble/curves@npm:1.1.0, @noble/curves@npm:~1.1.0": + version: 1.1.0 + resolution: "@noble/curves@npm:1.1.0" dependencies: - "@noble/hashes": "npm:1.3.0" - checksum: 6db884e03b3f6c773317bcf4611bf1d9adb8084eab0bf6158407cc998c9c5dcb0560741bdd0aaca9c4393c9e8a3dcd7592b4148a6cfd561d0a00addb77a6129f + "@noble/hashes": "npm:1.3.1" + checksum: 7028e3f19a4a2a601f9159e5423f51ae86ab231bed79a6e40649b063e1ed7f55f5da0475f1377bd2c5a8e5fc485af9ce0549ad89da6b983d6af48e5d0a2041ca languageName: node linkType: hard @@ -5406,20 +5399,20 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.3.0": - version: 1.3.0 - resolution: "@noble/hashes@npm:1.3.0" - checksum: 4680a71941c06ac897cc9eab9d229717d5af1147cea5e8cd4942190c817426ad3173ded750d897f58d764b869f9347d4fc3f6b3c16574541ac81906efa9ddc36 - languageName: node - linkType: hard - -"@noble/hashes@npm:^1.0.0, @noble/hashes@npm:^1.1.3, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:~1.3.0": +"@noble/hashes@npm:1.3.1": version: 1.3.1 resolution: "@noble/hashes@npm:1.3.1" checksum: 39474bab7e7813dbbfd8750476f48046d3004984e161fcd4333e40ca823f07b069010b35a20246e5b4ac20858e29913172a4d69720fd1e93620f7bedb70f9b72 languageName: node linkType: hard +"@noble/hashes@npm:^1.0.0, @noble/hashes@npm:^1.1.3, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:~1.3.0, @noble/hashes@npm:~1.3.1": + version: 1.3.2 + resolution: "@noble/hashes@npm:1.3.2" + checksum: 685f59d2d44d88e738114b71011d343a9f7dce9dfb0a121f1489132f9247baa60bc985e5ec6f3213d114fbd1e1168e7294644e46cbd0ce2eba37994f28eeb51b + languageName: node + linkType: hard + "@noble/hashes@npm:~1.1.1": version: 1.1.3 resolution: "@noble/hashes@npm:1.1.3" @@ -5876,14 +5869,14 @@ __metadata: languageName: node linkType: hard -"@scure/bip32@npm:1.3.0": - version: 1.3.0 - resolution: "@scure/bip32@npm:1.3.0" +"@scure/bip32@npm:1.3.1": + version: 1.3.1 + resolution: "@scure/bip32@npm:1.3.1" dependencies: - "@noble/curves": "npm:~1.0.0" - "@noble/hashes": "npm:~1.3.0" + "@noble/curves": "npm:~1.1.0" + "@noble/hashes": "npm:~1.3.1" "@scure/base": "npm:~1.1.0" - checksum: 1fabcc7f2215910b35980bfc455c03fc4ae7f848efed066fe3867960a8dfceb6141c932496434fc2cfbf385d270ff9efdfce2571992e4584103f82e45ac2103f + checksum: 0595955374dfa54a60adfa33d4793fd8b27230e962aaceb5bb5fcf8ccbb935184aa2c45154ec9bdfb26a1877b2ae0a8e4808c9a5464d4ffd971120740b816def languageName: node linkType: hard @@ -5897,13 +5890,13 @@ __metadata: languageName: node linkType: hard -"@scure/bip39@npm:1.2.0": - version: 1.2.0 - resolution: "@scure/bip39@npm:1.2.0" +"@scure/bip39@npm:1.2.1": + version: 1.2.1 + resolution: "@scure/bip39@npm:1.2.1" dependencies: "@noble/hashes": "npm:~1.3.0" "@scure/base": "npm:~1.1.0" - checksum: 2a260eefea0b2658c5d3b2cb982479ef650552c3007e57f667b445943c79717eb923c1a104a664b4873bc210aeb59859bf890c3e7b47fb51ed5b94dc96f75105 + checksum: 2ea368bbed34d6b1701c20683bf465e147f231a9e37e639b8c82f585d6f978bb0f3855fca7ceff04954ae248b3e313f5d322d0210614fb7acb402739415aaf31 languageName: node linkType: hard @@ -16316,15 +16309,15 @@ __metadata: languageName: node linkType: hard -"ethereum-cryptography@npm:^2.0.0": - version: 2.0.0 - resolution: "ethereum-cryptography@npm:2.0.0" +"ethereum-cryptography@npm:^2.0.0, ethereum-cryptography@npm:^2.1.2": + version: 2.1.2 + resolution: "ethereum-cryptography@npm:2.1.2" dependencies: - "@noble/curves": "npm:1.0.0" - "@noble/hashes": "npm:1.3.0" - "@scure/bip32": "npm:1.3.0" - "@scure/bip39": "npm:1.2.0" - checksum: 1f87b4d322fce0801d38741955df1dec20861939ea0c0a89dddf182906f21453f7134662e09fe268e35be9a3848f61667349836b5eb5f4efd6b9a02c1e3bcc85 + "@noble/curves": "npm:1.1.0" + "@noble/hashes": "npm:1.3.1" + "@scure/bip32": "npm:1.3.1" + "@scure/bip39": "npm:1.2.1" + checksum: 78983d01ac95047158ec03237ba318152b2c707ccc6a44225da11c72ed6ca575ca0c1630eaf9878fc82fe26272d6624939ef6f020cc89ddddfb941a7393ab909 languageName: node linkType: hard @@ -24388,7 +24381,7 @@ __metadata: "@metamask/eth-json-rpc-middleware": "npm:^11.0.0" "@metamask/eth-keyring-controller": "npm:^10.0.1" "@metamask/eth-ledger-bridge-keyring": "npm:^0.15.0" - "@metamask/eth-snap-keyring": "github:MetaMask/eth-snap-keyring#52a82c96546fa5dad22c73d4045a07e1b6d1b722" + "@metamask/eth-snap-keyring": "npm:^0.2.1" "@metamask/eth-token-tracker": "npm:^4.0.0" "@metamask/eth-trezor-keyring": "npm:^1.1.0" "@metamask/etherscan-link": "npm:^2.2.0" From 6cbd8d8a4fc5055f035c720cb3585e34cee61f38 Mon Sep 17 00:00:00 2001 From: Daniel Rocha <68558152+danroc@users.noreply.github.com> Date: Wed, 13 Sep 2023 17:40:34 +0200 Subject: [PATCH 114/235] test: fix permissions unit tests --- shared/constants/permissions.test.js | 15 +++++++-------- shared/constants/snaps/permissions.ts | 2 -- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/shared/constants/permissions.test.js b/shared/constants/permissions.test.js index 0bc4e9cc37db..740553b8c678 100644 --- a/shared/constants/permissions.test.js +++ b/shared/constants/permissions.test.js @@ -39,7 +39,8 @@ describe('RestrictedMethods', () => { 'eth_accounts', ...Object.keys(restrictedMethodPermissionBuilders).filter( (targetName) => - !Object.keys(ExcludedSnapPermissions).includes(targetName), + !Object.keys(ExcludedSnapPermissions).includes(targetName) && + !FlaskOnlyPermissions.includes(targetName), ), ].sort(), ); @@ -54,16 +55,14 @@ jest.mock('@metamask/rpc-methods', () => describe('Flask Restricted Methods', () => { it('has the expected flask permission keys', () => { - const flaskExcludedSnapPermissions = Object.keys( - ExcludedSnapPermissions, - ).filter((key) => !FlaskOnlyPermissions.includes(key)); + const flaskMethods = [ + ...new Set([...Object.keys(RestrictedMethods), ...FlaskOnlyPermissions]), + ].sort(); - expect(Object.keys(RestrictedMethods).sort()).toStrictEqual( + expect(flaskMethods).toStrictEqual( [ 'eth_accounts', - ...Object.keys(restrictedMethodPermissionBuilders).filter( - (targetName) => !flaskExcludedSnapPermissions.includes(targetName), - ), + ...Object.keys(restrictedMethodPermissionBuilders), ].sort(), ); }); diff --git a/shared/constants/snaps/permissions.ts b/shared/constants/snaps/permissions.ts index ab8fa6895e72..3642e2187166 100644 --- a/shared/constants/snaps/permissions.ts +++ b/shared/constants/snaps/permissions.ts @@ -17,8 +17,6 @@ export const ExcludedSnapPermissions = Object.freeze({ ///: BEGIN:ONLY_INCLUDE_IN(build-main) snap_manageAccounts: 'This permission is still in development and therefore not available.', - snap_getLocale: - 'This permission is still in development and therefore not available.', ///: END:ONLY_INCLUDE_IN eth_accounts: 'eth_accounts is disabled. For more information please see https://github.com/MetaMask/snaps/issues/990.', From f69d4f269b2ca4ff11557fb12f0f9dd878c63d0e Mon Sep 17 00:00:00 2001 From: MetaMask Bot Date: Wed, 13 Sep 2023 21:10:10 +0000 Subject: [PATCH 115/235] Update LavaMoat policies --- lavamoat/browserify/beta/policy.json | 142 +++++++++++---------- lavamoat/browserify/desktop/policy.json | 157 +++++++++++++----------- lavamoat/browserify/flask/policy.json | 157 +++++++++++++----------- lavamoat/browserify/main/policy.json | 142 +++++++++++---------- lavamoat/browserify/mmi/policy.json | 142 +++++++++++---------- 5 files changed, 373 insertions(+), 367 deletions(-) diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index f16be978f461..6d445be7f9dd 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -161,29 +161,13 @@ }, "packages": { "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, "browserify>buffer": true, "browserify>events": true, "browserify>insert-module-globals>is-buffer": true } }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": true, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true - } - }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { "globals": { "Headers": true, @@ -208,6 +192,7 @@ "crypto": true }, "packages": { + "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true } }, @@ -939,7 +924,7 @@ "@metamask/eth-json-rpc-middleware>clone": true, "@metamask/eth-json-rpc-middleware>pify": true, "@metamask/eth-json-rpc-middleware>safe-stable-stringify": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "eth-rpc-errors": true, "json-rpc-engine": true } @@ -978,7 +963,7 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "@metamask/scure-bip39": true, "browserify>buffer": true } @@ -1050,7 +1035,7 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "browserify>buffer": true, "browserify>events": true, "mocha>serialize-javascript>randombytes": true @@ -1106,17 +1091,25 @@ }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": { "packages": { + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": true, "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, "koa>content-disposition>safe-buffer": true } }, + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/eth-ledger-bridge-keyring>hdkey": { "packages": { "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": true, @@ -1142,6 +1135,7 @@ }, "packages": { "@ethereumjs/tx": true, + "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, "@metamask/eth-snap-keyring>@metamask/utils": true, "@metamask/eth-snap-keyring>uuid": true, "@metamask/keyring-api": true, @@ -1152,27 +1146,32 @@ "@metamask/eth-snap-keyring>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils": true, + "@metamask/eth-snap-keyring>@metamask/utils": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, - "bn.js": true, "browserify>buffer": true, "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils": { "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": true, + "superstruct": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": { "globals": { - "TextEncoder": true, - "crypto": true + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true } }, "@metamask/eth-snap-keyring>@metamask/utils": { @@ -1328,6 +1327,17 @@ "browserify>events": true } }, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, + "bn.js": true, + "browserify>buffer": true, + "ethereumjs-abi>ethereumjs-util>ethjs-util": true + } + }, "@metamask/eth-trezor-keyring>@metamask/utils": { "globals": { "TextDecoder": true, @@ -1342,7 +1352,7 @@ }, "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": { "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web": { @@ -1628,7 +1638,7 @@ "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, @@ -1636,21 +1646,6 @@ "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/keyring-controller>@metamask/utils": { "globals": { "TextDecoder": true, @@ -1666,26 +1661,39 @@ }, "@metamask/keyring-controller>ethereumjs-wallet": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": true, "@truffle/codec>utf8": true, "browserify>buffer": true, "browserify>crypto-browserify": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethereumjs-util>ethereum-cryptography>scrypt-js": true, "mocha>serialize-javascript>randombytes": true, "uuid": true } }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": { + "packages": { + "browserify>assert": true, + "browserify>buffer": true, + "browserify>crypto-browserify>create-hmac": true, + "ethereumjs-util>ethereum-cryptography>bs58check": true, + "ethereumjs-util>ethereum-cryptography>hash.js": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "koa>content-disposition>safe-buffer": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, @@ -1718,7 +1726,7 @@ "@metamask/message-manager>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, @@ -1726,21 +1734,6 @@ "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": { "globals": { "crypto": true, @@ -3640,12 +3633,20 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": true, "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "ethereumjs-abi>ethereumjs-util>ethjs-util": { "packages": { "browserify>buffer": true, @@ -3715,14 +3716,9 @@ }, "ethereumjs-util>ethereum-cryptography": { "packages": { - "browserify>assert": true, "browserify>buffer": true, - "browserify>crypto-browserify>create-hmac": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, - "ethereumjs-util>ethereum-cryptography>hash.js": true, "ethereumjs-util>ethereum-cryptography>keccak": true, "ethereumjs-util>ethereum-cryptography>secp256k1": true, - "koa>content-disposition>safe-buffer": true, "mocha>serialize-javascript>randombytes": true } }, diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index 6da4964fbd63..57bdc4e13ec4 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -161,29 +161,13 @@ }, "packages": { "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, "browserify>buffer": true, "browserify>events": true, "browserify>insert-module-globals>is-buffer": true } }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": true, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true - } - }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { "globals": { "Headers": true, @@ -208,6 +192,7 @@ "crypto": true }, "packages": { + "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true } }, @@ -1010,7 +995,7 @@ "@metamask/eth-json-rpc-middleware>clone": true, "@metamask/eth-json-rpc-middleware>pify": true, "@metamask/eth-json-rpc-middleware>safe-stable-stringify": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "eth-rpc-errors": true, "json-rpc-engine": true } @@ -1049,7 +1034,7 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "@metamask/scure-bip39": true, "browserify>buffer": true } @@ -1121,7 +1106,7 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "browserify>buffer": true, "browserify>events": true, "mocha>serialize-javascript>randombytes": true @@ -1177,17 +1162,25 @@ }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": { "packages": { + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": true, "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, "koa>content-disposition>safe-buffer": true } }, + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/eth-ledger-bridge-keyring>hdkey": { "packages": { "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": true, @@ -1213,6 +1206,7 @@ }, "packages": { "@ethereumjs/tx": true, + "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, "@metamask/eth-snap-keyring>@metamask/utils": true, "@metamask/eth-snap-keyring>uuid": true, "@metamask/keyring-api": true, @@ -1223,27 +1217,32 @@ "@metamask/eth-snap-keyring>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils": true, + "@metamask/eth-snap-keyring>@metamask/utils": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, - "bn.js": true, "browserify>buffer": true, "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils": { "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": true, + "superstruct": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": { "globals": { - "TextEncoder": true, - "crypto": true + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true } }, "@metamask/eth-snap-keyring>@metamask/utils": { @@ -1399,6 +1398,17 @@ "browserify>events": true } }, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, + "bn.js": true, + "browserify>buffer": true, + "ethereumjs-abi>ethereumjs-util>ethjs-util": true + } + }, "@metamask/eth-trezor-keyring>@metamask/utils": { "globals": { "TextDecoder": true, @@ -1413,7 +1423,7 @@ }, "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": { "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web": { @@ -1722,7 +1732,7 @@ "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, @@ -1730,21 +1740,6 @@ "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/keyring-controller>@metamask/utils": { "globals": { "TextDecoder": true, @@ -1760,26 +1755,39 @@ }, "@metamask/keyring-controller>ethereumjs-wallet": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": true, "@truffle/codec>utf8": true, "browserify>buffer": true, "browserify>crypto-browserify": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethereumjs-util>ethereum-cryptography>scrypt-js": true, "mocha>serialize-javascript>randombytes": true, "uuid": true } }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": { + "packages": { + "browserify>assert": true, + "browserify>buffer": true, + "browserify>crypto-browserify>create-hmac": true, + "ethereumjs-util>ethereum-cryptography>bs58check": true, + "ethereumjs-util>ethereum-cryptography>hash.js": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "koa>content-disposition>safe-buffer": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, @@ -1812,7 +1820,7 @@ "@metamask/message-manager>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, @@ -1820,21 +1828,6 @@ "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": { "globals": { "crypto": true, @@ -2128,7 +2121,20 @@ }, "@metamask/rpc-methods-flask>@metamask/snaps-ui": { "packages": { - "@metamask/rpc-methods-flask>@metamask/utils": true, + "@metamask/rpc-methods-flask>@metamask/snaps-ui>@metamask/utils": true, + "superstruct": true + } + }, + "@metamask/rpc-methods-flask>@metamask/snaps-ui>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, "superstruct": true } }, @@ -4134,12 +4140,20 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": true, "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "ethereumjs-abi>ethereumjs-util>ethjs-util": { "packages": { "browserify>buffer": true, @@ -4209,14 +4223,9 @@ }, "ethereumjs-util>ethereum-cryptography": { "packages": { - "browserify>assert": true, "browserify>buffer": true, - "browserify>crypto-browserify>create-hmac": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, - "ethereumjs-util>ethereum-cryptography>hash.js": true, "ethereumjs-util>ethereum-cryptography>keccak": true, "ethereumjs-util>ethereum-cryptography>secp256k1": true, - "koa>content-disposition>safe-buffer": true, "mocha>serialize-javascript>randombytes": true } }, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index ef1664fb713b..25972ed54477 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -161,29 +161,13 @@ }, "packages": { "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, "browserify>buffer": true, "browserify>events": true, "browserify>insert-module-globals>is-buffer": true } }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": true, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true - } - }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { "globals": { "Headers": true, @@ -208,6 +192,7 @@ "crypto": true }, "packages": { + "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true } }, @@ -1010,7 +995,7 @@ "@metamask/eth-json-rpc-middleware>clone": true, "@metamask/eth-json-rpc-middleware>pify": true, "@metamask/eth-json-rpc-middleware>safe-stable-stringify": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "eth-rpc-errors": true, "json-rpc-engine": true } @@ -1049,7 +1034,7 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "@metamask/scure-bip39": true, "browserify>buffer": true } @@ -1121,7 +1106,7 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "browserify>buffer": true, "browserify>events": true, "mocha>serialize-javascript>randombytes": true @@ -1177,17 +1162,25 @@ }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": { "packages": { + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": true, "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, "koa>content-disposition>safe-buffer": true } }, + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/eth-ledger-bridge-keyring>hdkey": { "packages": { "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": true, @@ -1213,6 +1206,7 @@ }, "packages": { "@ethereumjs/tx": true, + "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, "@metamask/eth-snap-keyring>@metamask/utils": true, "@metamask/eth-snap-keyring>uuid": true, "@metamask/keyring-api": true, @@ -1223,27 +1217,32 @@ "@metamask/eth-snap-keyring>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils": true, + "@metamask/eth-snap-keyring>@metamask/utils": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, - "bn.js": true, "browserify>buffer": true, "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils": { "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": true, + "superstruct": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": { "globals": { - "TextEncoder": true, - "crypto": true + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true } }, "@metamask/eth-snap-keyring>@metamask/utils": { @@ -1399,6 +1398,17 @@ "browserify>events": true } }, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, + "bn.js": true, + "browserify>buffer": true, + "ethereumjs-abi>ethereumjs-util>ethjs-util": true + } + }, "@metamask/eth-trezor-keyring>@metamask/utils": { "globals": { "TextDecoder": true, @@ -1413,7 +1423,7 @@ }, "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": { "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web": { @@ -1722,7 +1732,7 @@ "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, @@ -1730,21 +1740,6 @@ "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/keyring-controller>@metamask/utils": { "globals": { "TextDecoder": true, @@ -1760,26 +1755,39 @@ }, "@metamask/keyring-controller>ethereumjs-wallet": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": true, "@truffle/codec>utf8": true, "browserify>buffer": true, "browserify>crypto-browserify": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethereumjs-util>ethereum-cryptography>scrypt-js": true, "mocha>serialize-javascript>randombytes": true, "uuid": true } }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": { + "packages": { + "browserify>assert": true, + "browserify>buffer": true, + "browserify>crypto-browserify>create-hmac": true, + "ethereumjs-util>ethereum-cryptography>bs58check": true, + "ethereumjs-util>ethereum-cryptography>hash.js": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "koa>content-disposition>safe-buffer": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, @@ -1812,7 +1820,7 @@ "@metamask/message-manager>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, @@ -1820,21 +1828,6 @@ "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": { "globals": { "crypto": true, @@ -2144,7 +2137,20 @@ }, "@metamask/rpc-methods-flask>@metamask/snaps-ui": { "packages": { - "@metamask/rpc-methods-flask>@metamask/utils": true, + "@metamask/rpc-methods-flask>@metamask/snaps-ui>@metamask/utils": true, + "superstruct": true + } + }, + "@metamask/rpc-methods-flask>@metamask/snaps-ui>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, "superstruct": true } }, @@ -4150,12 +4156,20 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": true, "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "ethereumjs-abi>ethereumjs-util>ethjs-util": { "packages": { "browserify>buffer": true, @@ -4225,14 +4239,9 @@ }, "ethereumjs-util>ethereum-cryptography": { "packages": { - "browserify>assert": true, "browserify>buffer": true, - "browserify>crypto-browserify>create-hmac": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, - "ethereumjs-util>ethereum-cryptography>hash.js": true, "ethereumjs-util>ethereum-cryptography>keccak": true, "ethereumjs-util>ethereum-cryptography>secp256k1": true, - "koa>content-disposition>safe-buffer": true, "mocha>serialize-javascript>randombytes": true } }, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 328996152e40..6a6201509ccf 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -161,29 +161,13 @@ }, "packages": { "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, "browserify>buffer": true, "browserify>events": true, "browserify>insert-module-globals>is-buffer": true } }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": true, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true - } - }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { "globals": { "Headers": true, @@ -208,6 +192,7 @@ "crypto": true }, "packages": { + "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true } }, @@ -939,7 +924,7 @@ "@metamask/eth-json-rpc-middleware>clone": true, "@metamask/eth-json-rpc-middleware>pify": true, "@metamask/eth-json-rpc-middleware>safe-stable-stringify": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "eth-rpc-errors": true, "json-rpc-engine": true } @@ -978,7 +963,7 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "@metamask/scure-bip39": true, "browserify>buffer": true } @@ -1050,7 +1035,7 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "browserify>buffer": true, "browserify>events": true, "mocha>serialize-javascript>randombytes": true @@ -1106,17 +1091,25 @@ }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": { "packages": { + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": true, "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, "koa>content-disposition>safe-buffer": true } }, + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/eth-ledger-bridge-keyring>hdkey": { "packages": { "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": true, @@ -1142,6 +1135,7 @@ }, "packages": { "@ethereumjs/tx": true, + "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, "@metamask/eth-snap-keyring>@metamask/utils": true, "@metamask/eth-snap-keyring>uuid": true, "@metamask/keyring-api": true, @@ -1152,27 +1146,32 @@ "@metamask/eth-snap-keyring>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils": true, + "@metamask/eth-snap-keyring>@metamask/utils": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, - "bn.js": true, "browserify>buffer": true, "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils": { "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": true, + "superstruct": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": { "globals": { - "TextEncoder": true, - "crypto": true + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true } }, "@metamask/eth-snap-keyring>@metamask/utils": { @@ -1328,6 +1327,17 @@ "browserify>events": true } }, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, + "bn.js": true, + "browserify>buffer": true, + "ethereumjs-abi>ethereumjs-util>ethjs-util": true + } + }, "@metamask/eth-trezor-keyring>@metamask/utils": { "globals": { "TextDecoder": true, @@ -1342,7 +1352,7 @@ }, "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": { "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web": { @@ -1628,7 +1638,7 @@ "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, @@ -1636,21 +1646,6 @@ "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/keyring-controller>@metamask/utils": { "globals": { "TextDecoder": true, @@ -1666,26 +1661,39 @@ }, "@metamask/keyring-controller>ethereumjs-wallet": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": true, "@truffle/codec>utf8": true, "browserify>buffer": true, "browserify>crypto-browserify": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethereumjs-util>ethereum-cryptography>scrypt-js": true, "mocha>serialize-javascript>randombytes": true, "uuid": true } }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": { + "packages": { + "browserify>assert": true, + "browserify>buffer": true, + "browserify>crypto-browserify>create-hmac": true, + "ethereumjs-util>ethereum-cryptography>bs58check": true, + "ethereumjs-util>ethereum-cryptography>hash.js": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "koa>content-disposition>safe-buffer": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, @@ -1718,7 +1726,7 @@ "@metamask/message-manager>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, @@ -1726,21 +1734,6 @@ "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": { "globals": { "crypto": true, @@ -3919,12 +3912,20 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": true, "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "ethereumjs-abi>ethereumjs-util>ethjs-util": { "packages": { "browserify>buffer": true, @@ -3994,14 +3995,9 @@ }, "ethereumjs-util>ethereum-cryptography": { "packages": { - "browserify>assert": true, "browserify>buffer": true, - "browserify>crypto-browserify>create-hmac": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, - "ethereumjs-util>ethereum-cryptography>hash.js": true, "ethereumjs-util>ethereum-cryptography>keccak": true, "ethereumjs-util>ethereum-cryptography>secp256k1": true, - "koa>content-disposition>safe-buffer": true, "mocha>serialize-javascript>randombytes": true } }, diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 477c8f034973..429e593f0a00 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -161,29 +161,13 @@ }, "packages": { "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": true, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": true, + "@ethereumjs/tx>ethereum-cryptography": true, "browserify>buffer": true, "browserify>events": true, "browserify>insert-module-globals>is-buffer": true } }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": true, - "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true - } - }, - "@ethereumjs/tx>@ethereumjs/util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@ethereumjs/tx>@ethereumjs/util>micro-ftch": { "globals": { "Headers": true, @@ -208,6 +192,7 @@ "crypto": true }, "packages": { + "@ethereumjs/tx>ethereum-cryptography>@noble/curves": true, "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true } }, @@ -1080,7 +1065,7 @@ "@metamask/eth-json-rpc-middleware>clone": true, "@metamask/eth-json-rpc-middleware>pify": true, "@metamask/eth-json-rpc-middleware>safe-stable-stringify": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "eth-rpc-errors": true, "json-rpc-engine": true } @@ -1119,7 +1104,7 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-hd-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "@metamask/scure-bip39": true, "browserify>buffer": true } @@ -1191,7 +1176,7 @@ "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@metamask/eth-keyring-controller>@metamask/eth-simple-keyring>ethereum-cryptography": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true, "browserify>buffer": true, "browserify>events": true, "mocha>serialize-javascript>randombytes": true @@ -1247,17 +1232,25 @@ }, "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util": { "packages": { + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": true, "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true, "koa>content-disposition>safe-buffer": true } }, + "@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/eth-ledger-bridge-keyring>hdkey": { "packages": { "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": true, @@ -1283,6 +1276,7 @@ }, "packages": { "@ethereumjs/tx": true, + "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true, "@metamask/eth-snap-keyring>@metamask/utils": true, "@metamask/eth-snap-keyring>uuid": true, "@metamask/keyring-api": true, @@ -1293,27 +1287,32 @@ "@metamask/eth-snap-keyring>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils": true, + "@metamask/eth-snap-keyring>@metamask/utils": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, - "bn.js": true, "browserify>buffer": true, "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils": { "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": true, + "superstruct": true } }, - "@metamask/eth-snap-keyring>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { + "@metamask/eth-snap-keyring>@metamask/eth-sig-util>@metamask/abi-utils>@metamask/utils": { "globals": { - "TextEncoder": true, - "crypto": true + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true } }, "@metamask/eth-snap-keyring>@metamask/utils": { @@ -1469,6 +1468,17 @@ "browserify>events": true } }, + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": { + "packages": { + "@ethereumjs/tx>@ethereumjs/util": true, + "@ethereumjs/tx>ethereum-cryptography": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, + "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, + "bn.js": true, + "browserify>buffer": true, + "ethereumjs-abi>ethereumjs-util>ethjs-util": true + } + }, "@metamask/eth-trezor-keyring>@metamask/utils": { "globals": { "TextDecoder": true, @@ -1483,7 +1493,7 @@ }, "@metamask/eth-trezor-keyring>@trezor/connect-plugin-ethereum": { "packages": { - "@metamask/eth-snap-keyring>@metamask/eth-sig-util": true + "@metamask/eth-trezor-keyring>@metamask/eth-sig-util": true } }, "@metamask/eth-trezor-keyring>@trezor/connect-web": { @@ -1769,7 +1779,7 @@ "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, @@ -1777,21 +1787,6 @@ "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/keyring-controller>@metamask/eth-keyring-controller>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/keyring-controller>@metamask/utils": { "globals": { "TextDecoder": true, @@ -1807,26 +1802,39 @@ }, "@metamask/keyring-controller>ethereumjs-wallet": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": true, "@truffle/codec>utf8": true, "browserify>buffer": true, "browserify>crypto-browserify": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>ethereum-cryptography>bs58check": true, "ethereumjs-util>ethereum-cryptography>scrypt-js": true, "mocha>serialize-javascript>randombytes": true, "uuid": true } }, + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": { + "packages": { + "browserify>assert": true, + "browserify>buffer": true, + "browserify>crypto-browserify>create-hmac": true, + "ethereumjs-util>ethereum-cryptography>bs58check": true, + "ethereumjs-util>ethereum-cryptography>hash.js": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "koa>content-disposition>safe-buffer": true, + "mocha>serialize-javascript>randombytes": true + } + }, "@metamask/keyring-controller>ethereumjs-wallet>ethereumjs-util": { "packages": { + "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, "bn.js": true, "browserify>assert": true, "browserify>buffer": true, "browserify>insert-module-globals>is-buffer": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, @@ -1859,7 +1867,7 @@ "@metamask/message-manager>@metamask/eth-sig-util": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": true, + "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": true, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl-util": true, "bn.js": true, @@ -1867,21 +1875,6 @@ "ethereumjs-abi>ethereumjs-util>ethjs-util": true } }, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": true - } - }, - "@metamask/message-manager>@metamask/eth-sig-util>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "@metamask/message-manager>@metamask/eth-sig-util>tweetnacl": { "globals": { "crypto": true, @@ -3781,12 +3774,20 @@ "bn.js": true, "browserify>assert": true, "browserify>buffer": true, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": true, "ethereumjs-abi>ethereumjs-util>ethjs-util": true, "ethereumjs-util>create-hash": true, - "ethereumjs-util>ethereum-cryptography": true, "ethereumjs-util>rlp": true } }, + "ethereumjs-abi>ethereumjs-util>ethereum-cryptography": { + "packages": { + "browserify>buffer": true, + "ethereumjs-util>ethereum-cryptography>keccak": true, + "ethereumjs-util>ethereum-cryptography>secp256k1": true, + "mocha>serialize-javascript>randombytes": true + } + }, "ethereumjs-abi>ethereumjs-util>ethjs-util": { "packages": { "browserify>buffer": true, @@ -3856,14 +3857,9 @@ }, "ethereumjs-util>ethereum-cryptography": { "packages": { - "browserify>assert": true, "browserify>buffer": true, - "browserify>crypto-browserify>create-hmac": true, - "ethereumjs-util>ethereum-cryptography>bs58check": true, - "ethereumjs-util>ethereum-cryptography>hash.js": true, "ethereumjs-util>ethereum-cryptography>keccak": true, "ethereumjs-util>ethereum-cryptography>secp256k1": true, - "koa>content-disposition>safe-buffer": true, "mocha>serialize-javascript>randombytes": true } }, From 88586adc22e64052fd9626aa1c567dccbce85a9e Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Mon, 11 Sep 2023 21:50:44 +0800 Subject: [PATCH 116/235] chore: update policy --- lavamoat/build-system/policy.json | 132 ++++++++++++++++++++++++++++-- 1 file changed, 124 insertions(+), 8 deletions(-) diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json index 4ab9521cfbeb..96fef5e24515 100644 --- a/lavamoat/build-system/policy.json +++ b/lavamoat/build-system/policy.json @@ -1134,6 +1134,21 @@ "string.prototype.matchall>side-channel": true } }, + "@storybook/addon-mdx-gfm>@storybook/node-logger>npmlog>gauge>has-unicode": { + "builtin": { + "os.type": true + }, + "globals": { + "process.env.LANG": true, + "process.env.LC_ALL": true, + "process.env.LC_CTYPE": true + } + }, + "@storybook/addon-mdx-gfm>@storybook/node-logger>npmlog>gauge>wide-align": { + "packages": { + "yargs>string-width": true + } + }, "@storybook/core>@storybook/core-server>x-default-browser>default-browser-id>untildify>os-homedir": { "builtin": { "os.homedir": true @@ -4999,6 +5014,7 @@ "@lavamoat/allow-scripts>@npmcli/run-script>node-gyp>npmlog": true, "gulp-watch>chokidar>fsevents>node-pre-gyp>detect-libc": true, "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog": true, "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf": true, "gulp-watch>chokidar>fsevents>node-pre-gyp>semver": true } @@ -5056,9 +5072,20 @@ }, "packages": { "@storybook/core>@storybook/core-server>x-default-browser>default-browser-id>untildify>os-homedir": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-homedir": true, "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-tmpdir": true } }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-homedir": { + "builtin": { + "os.homedir": true + }, + "globals": { + "process.env": true, + "process.getuid": true, + "process.platform": true + } + }, "gulp-watch>chokidar>fsevents>node-pre-gyp>nopt>osenv>os-tmpdir": { "globals": { "process.env.SystemRoot": true, @@ -5069,6 +5096,70 @@ "process.platform": true } }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog": { + "builtin": { + "events.EventEmitter": true, + "util": true + }, + "globals": { + "process.nextTick": true, + "process.stderr": true + }, + "packages": { + "@storybook/addon-mdx-gfm>@storybook/node-logger>npmlog>console-control-strings": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge": true, + "nyc>yargs>set-blocking": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>are-we-there-yet": { + "builtin": { + "events.EventEmitter": true, + "util.inherits": true + }, + "packages": { + "koa>delegates": true, + "readable-stream": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge": { + "builtin": { + "util.format": true + }, + "globals": { + "clearInterval": true, + "process": true, + "setImmediate": true, + "setInterval": true + }, + "packages": { + "@storybook/addon-mdx-gfm>@storybook/node-logger>npmlog>console-control-strings": true, + "@storybook/addon-mdx-gfm>@storybook/node-logger>npmlog>gauge>has-unicode": true, + "@storybook/addon-mdx-gfm>@storybook/node-logger>npmlog>gauge>wide-align": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>aproba": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi": true, + "nyc>signal-exit": true, + "react>object-assign": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width": { + "packages": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width>is-fullwidth-code-point": true, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi": true, + "gulp>gulp-cli>yargs>string-width>code-point-at": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>string-width>is-fullwidth-code-point": { + "packages": { + "gulp>gulp-cli>yargs>string-width>is-fullwidth-code-point>number-is-nan": true + } + }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi": { + "packages": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>npmlog>gauge>strip-ansi>ansi-regex": true + } + }, "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf": { "builtin": { "assert": true, @@ -5080,9 +5171,34 @@ "setTimeout": true }, "packages": { + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob": true, "nyc>glob": true } }, + "gulp-watch>chokidar>fsevents>node-pre-gyp>rimraf>glob": { + "builtin": { + "assert": true, + "events.EventEmitter": true, + "fs": true, + "path.join": true, + "path.resolve": true, + "util": true + }, + "globals": { + "console.error": true, + "process.cwd": true, + "process.nextTick": true, + "process.platform": true + }, + "packages": { + "eslint>minimatch": true, + "gulp-watch>path-is-absolute": true, + "nyc>glob>fs.realpath": true, + "nyc>glob>inflight": true, + "pump>once": true, + "pumpify>inherits": true + } + }, "gulp-watch>chokidar>fsevents>node-pre-gyp>semver": { "globals": { "console": true, @@ -6530,6 +6646,13 @@ "process.platform": true } }, + "mockttp>portfinder>mkdirp": { + "builtin": { + "fs": true, + "path.dirname": true, + "path.resolve": true + } + }, "nock>debug": { "builtin": { "tty.isatty": true, @@ -8137,14 +8260,7 @@ "path.dirname": true }, "packages": { - "stylelint>file-entry-cache>flat-cache>write>mkdirp": true - } - }, - "stylelint>file-entry-cache>flat-cache>write>mkdirp": { - "builtin": { - "fs": true, - "path.dirname": true, - "path.resolve": true + "mockttp>portfinder>mkdirp": true } }, "stylelint>global-modules": { From 57970ebc79bf9b9a228a4839659aabd600b34024 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Mon, 11 Sep 2023 21:51:06 +0800 Subject: [PATCH 117/235] fix: remove identities references --- test/e2e/snaps/keyring-api/test-snap-keyring-sign.spec.ts | 4 ++++ .../signature-request-siwe.stories.js | 4 ++-- .../wrong-network-notification.stories.js | 7 ------- .../select-action-modal/select-action-modal.test.js | 5 ----- ui/ducks/send/send.test.js | 3 --- ui/pages/confirm-signature-request/index.js | 2 -- ui/store/actions.test.js | 3 --- 7 files changed, 6 insertions(+), 22 deletions(-) create mode 100644 test/e2e/snaps/keyring-api/test-snap-keyring-sign.spec.ts diff --git a/test/e2e/snaps/keyring-api/test-snap-keyring-sign.spec.ts b/test/e2e/snaps/keyring-api/test-snap-keyring-sign.spec.ts new file mode 100644 index 000000000000..b81e7b6ef742 --- /dev/null +++ b/test/e2e/snaps/keyring-api/test-snap-keyring-sign.spec.ts @@ -0,0 +1,4 @@ +import * as tests from '../../tests/signature-request.spec'; +import { installTestKeyringSnap } from './helper'; + +tests.signatureTests('Snap Simple Keyring', installTestKeyringSnap); diff --git a/ui/components/app/signature-request-siwe/signature-request-siwe.stories.js b/ui/components/app/signature-request-siwe/signature-request-siwe.stories.js index f2dd0b0731ca..792143c69c12 100644 --- a/ui/components/app/signature-request-siwe/signature-request-siwe.stories.js +++ b/ui/components/app/signature-request-siwe/signature-request-siwe.stories.js @@ -3,8 +3,8 @@ import testData from '../../../../.storybook/test-data'; import README from './README.mdx'; import SignatureRequestSIWE from './signature-request-siwe'; -const { identities, selectedAddress } = testData.metamask; -const otherIdentity = Object.values(identities)[0]; +const { internalAccounts, selectedAddress } = testData.metamask; +const otherIdentity = Object.values(internalAccounts)[0]; export default { title: 'Components/App/SignatureRequestSIWE', diff --git a/ui/components/institutional/wrong-network-notification/wrong-network-notification.stories.js b/ui/components/institutional/wrong-network-notification/wrong-network-notification.stories.js index 3c4ec6bca430..7f0f01e40df1 100644 --- a/ui/components/institutional/wrong-network-notification/wrong-network-notification.stories.js +++ b/ui/components/institutional/wrong-network-notification/wrong-network-notification.stories.js @@ -18,19 +18,12 @@ const customData = { '0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275': '0x0', }, }, - selectedAddress: '0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275', custodianSupportedChains: { '0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275': { supportedChains: ['1', '2'], custodianName: 'saturn', }, }, - identities: { - '0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275': { - name: 'Custody Account A', - address: '0x5Ab19e7091dD208F352F8E727B6DCC6F8aBB6275', - }, - }, keyrings: [ { type: 'Custody', diff --git a/ui/components/multichain/select-action-modal/select-action-modal.test.js b/ui/components/multichain/select-action-modal/select-action-modal.test.js index 6e2e41b42993..e716cdc3aea6 100644 --- a/ui/components/multichain/select-action-modal/select-action-modal.test.js +++ b/ui/components/multichain/select-action-modal/select-action-modal.test.js @@ -60,11 +60,6 @@ describe('Select Action Modal', () => { }, useCurrencyRateCheck: true, conversionRate: 2, - identities: { - '0x1': { - address: '0x1', - }, - }, internalAccounts: { accounts: { 'cf8dace4-9439-4bd4-b3a8-88c821c8fcb3': { diff --git a/ui/ducks/send/send.test.js b/ui/ducks/send/send.test.js index e83496651ec7..40c20638c0e4 100644 --- a/ui/ducks/send/send.test.js +++ b/ui/ducks/send/send.test.js @@ -1695,9 +1695,6 @@ describe('Send Slice', () => { address: mockAddress1, }, }, - identities: { - [mockAddress1]: {}, - }, }, send: { ...getInitialSendStateWithExistingTxState({ diff --git a/ui/pages/confirm-signature-request/index.js b/ui/pages/confirm-signature-request/index.js index 35c5b9a824ed..f87cd66af3bf 100644 --- a/ui/pages/confirm-signature-request/index.js +++ b/ui/pages/confirm-signature-request/index.js @@ -55,7 +55,6 @@ const ConfirmTxScreen = ({ match }) => { ); const sendTo = useSelector(getSendTo); const { - identities, currentCurrency, unapprovedMsgs, unapprovedPersonalMsgs, @@ -187,7 +186,6 @@ const ConfirmTxScreen = ({ match }) => { history={history} txData={txData} key={txData.id} - identities={identities} currentCurrency={currentCurrency} blockGasLimit={blockGasLimit} ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) diff --git a/ui/store/actions.test.js b/ui/store/actions.test.js index 1a316f7b9a4b..491d6e5da5ae 100644 --- a/ui/store/actions.test.js +++ b/ui/store/actions.test.js @@ -276,9 +276,6 @@ describe('Actions', () => { '0xAnotherAddress': '0x0', }, }, - identities: { - '0xAnotherAddress': {}, - }, }), ); From 74f1e43bea9f70b168bdd49915e70fbb0a58c8bf Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Fri, 15 Sep 2023 12:24:24 +0800 Subject: [PATCH 118/235] fix: updates the paramater names for getPermissionSpecifications --- app/scripts/controllers/permissions/specifications.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/permissions/specifications.js b/app/scripts/controllers/permissions/specifications.js index f1954ea76b16..2b5edcf0ca70 100644 --- a/app/scripts/controllers/permissions/specifications.js +++ b/app/scripts/controllers/permissions/specifications.js @@ -82,11 +82,11 @@ export const getCaveatSpecifications = ({ getInternalAccounts }) => { * * @param {{ * getAllAccounts: () => Promise, - * getIdentities: () => Record, + * getInternalAccounts: () => Record, * }} options - Options bag. * @param options.getAllAccounts - A function that returns all Ethereum accounts * in the current MetaMask instance. - * @param options.getIdentities - A function that returns the + * @param options.getInternalAccounts - A function that returns the * `PreferencesController` identity objects for all Ethereum accounts in the * @param options.captureKeyringTypesWithMissingIdentities - A function that * captures extra error information about the "Missing identity for address" From d12b518b605b612bfddd9244ab9eb29920a2419a Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Fri, 15 Sep 2023 12:25:01 +0800 Subject: [PATCH 119/235] fix: removes identities in from setupSentry --- app/scripts/lib/setupSentry.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js index 0c20816459b4..be914143a447 100644 --- a/app/scripts/lib/setupSentry.js +++ b/app/scripts/lib/setupSentry.js @@ -174,7 +174,6 @@ export const SENTRY_BACKGROUND_STATE = { dismissSeedBackUpReminder: true, featureFlags: true, forgottenPassword: true, - identities: false, incomingTransactionsPreferences: true, infuraBlocked: true, ipfsGateway: false, From 9177e906253883b6797758ba82b79edfb12f1bc5 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Fri, 15 Sep 2023 12:25:40 +0800 Subject: [PATCH 120/235] fix: updates jsdoc to change identities to InternalAccounts --- shared/constants/metametrics.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/constants/metametrics.ts b/shared/constants/metametrics.ts index ab43e4a546be..076723f4f9cc 100644 --- a/shared/constants/metametrics.ts +++ b/shared/constants/metametrics.ts @@ -313,7 +313,7 @@ export type MetaMetricsUserTraits = { */ nft_autodetection_enabled?: number; /** - * A number representing the number of identities (accounts) added to the + * A number representing the number of InternalAccounts (accounts) added to the * user's wallet. */ number_of_accounts?: number; @@ -400,7 +400,7 @@ export enum MetaMetricsUserTrait { */ NftAutodetectionEnabled = 'nft_autodetection_enabled', /** - * Identified when identities change. + * Identified when InternalAccounts change. */ NumberOfAccounts = 'number_of_accounts', /** From 1abc4de2b42f0b2d29221a2f8c2cb21e9fefd571 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Fri, 8 Sep 2023 11:11:05 -0230 Subject: [PATCH 121/235] Publish MMI builds alongside stable releases (#20788) MMI builds are now published alongside stable releases, in the same manner as Flask. They will be included in future GitHub release pages, and tracked using separate git tags. Sentry sourcemaps are uploaded for them during the release process as well. Closes https://github.com/MetaMask/metamask-extension/issues/20782 --- .circleci/config.yml | 3 ++ .../scripts/release-create-gh-release.sh | 36 +++++++++++-------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 78528233631e..8473915d8a41 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1202,6 +1202,9 @@ jobs: - run: name: Publish Flask release to Sentry command: yarn sentry:publish --build-type flask + - run: + name: Publish MMI release to Sentry + command: yarn sentry:publish --build-type mmi - run: name: Create GitHub release command: | diff --git a/.circleci/scripts/release-create-gh-release.sh b/.circleci/scripts/release-create-gh-release.sh index 54d3946a97c3..e138e20c5b59 100755 --- a/.circleci/scripts/release-create-gh-release.sh +++ b/.circleci/scripts/release-create-gh-release.sh @@ -26,29 +26,33 @@ function install_github_cli () popd } -function print_flask_version () +function print_build_version () { - local flask_filename - flask_filename="$(find ./builds-flask -type f -name 'metamask-flask-chrome-*.zip' -exec basename {} .zip \;)" + local build_type="${1}"; shift - local flask_build_filename_prefix - flask_build_filename_prefix='metamask-flask-chrome-' - local flask_build_filename_prefix_size - flask_build_filename_prefix_size="${#flask_build_filename_prefix}" + local filename + filename="$(find "./builds-${build_type}" -type f -name "metamask-${build_type}-chrome-*.zip" -exec basename {} .zip \;)" + + local build_filename_prefix + build_filename_prefix="metamask-${build_type}-chrome-" + local build_filename_prefix_size + build_filename_prefix_size="${#build_filename_prefix}" # Use substring parameter expansion to remove the filename prefix, leaving just the version - echo "${flask_filename:$flask_build_filename_prefix_size}" + echo "${filename:$build_filename_prefix_size}" } -function publish_flask_tag () + +function publish_tag () { - local flask_version="${1}"; shift + local build_name="${1}"; shift + local build_version="${1}"; shift git config user.email "metamaskbot@users.noreply.github.com" git config user.name "MetaMask Bot" - git tag -a "v${flask_version}" -m "Flask version ${flask_version}" + git tag -a "v${build_version}" -m "${build_name} version ${build_version}" repo_slug="$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME" - git push "https://$GITHUB_TOKEN@github.com/$repo_slug" "v${flask_version}" + git push "https://$GITHUB_TOKEN@github.com/$repo_slug" "v${build_version}" } current_commit_msg=$(git show -s --format='%s' HEAD) @@ -56,7 +60,8 @@ current_commit_msg=$(git show -s --format='%s' HEAD) if [[ $current_commit_msg =~ Version[-[:space:]](v[[:digit:]]+.[[:digit:]]+.[[:digit:]]+) ]] then tag="${BASH_REMATCH[1]}" - flask_version="$(print_flask_version)" + flask_version="$(print_build_version 'flask')" + mmi_version="$(print_build_version 'mmi')" install_github_cli @@ -67,12 +72,15 @@ then --attach builds/metamask-firefox-*.zip \ --attach builds-flask/metamask-flask-chrome-*.zip \ --attach builds-flask/metamask-flask-firefox-*.zip \ + --attach builds-mmi/metamask-mmi-chrome-*.zip \ + --attach builds-mmi/metamask-mmi-firefox-*.zip \ --message "Version ${tag##v}" \ --message "$release_body" \ --commitish "$CIRCLE_SHA1" \ "$tag" - publish_flask_tag "${flask_version}" + publish_tag 'Flask' "${flask_version}" + publish_tag 'MMI' "${mmi_version}" else printf '%s\n' 'Version not found in commit message; skipping GitHub Release' exit 0 From d3f649376f40fa3bd8d8cdf3a14a7a1cccadfc9c Mon Sep 17 00:00:00 2001 From: David Walsh Date: Fri, 8 Sep 2023 09:16:38 -0500 Subject: [PATCH 122/235] UX: Multichain: Remove hover background on Account Picker (#20794) --- .../__snapshots__/account-picker.test.js.snap | 4 ++-- ui/components/multichain/account-picker/account-picker.js | 6 +++--- .../app-header/__snapshots__/app-header.test.js.snap | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ui/components/multichain/account-picker/__snapshots__/account-picker.test.js.snap b/ui/components/multichain/account-picker/__snapshots__/account-picker.test.js.snap index e7570d155e86..fac4f07c3017 100644 --- a/ui/components/multichain/account-picker/__snapshots__/account-picker.test.js.snap +++ b/ui/components/multichain/account-picker/__snapshots__/account-picker.test.js.snap @@ -3,11 +3,11 @@ exports[`AccountPicker renders properly 1`] = `
+ ); }; diff --git a/ui/components/multichain/app-header/__snapshots__/app-header.test.js.snap b/ui/components/multichain/app-header/__snapshots__/app-header.test.js.snap index 27d8a85e77eb..67d265f76e1e 100644 --- a/ui/components/multichain/app-header/__snapshots__/app-header.test.js.snap +++ b/ui/components/multichain/app-header/__snapshots__/app-header.test.js.snap @@ -228,11 +228,11 @@ exports[`App Header should match snapshot 1`] = `
+
+
+
+ Unknown address +
+
+
+ +
+
+
+
+
+ + + 0xc0f...4979 + +
+
+
+

+ You are interacting with an unknown contract address. If you trust this author, set a personal display name to identify it going forward. +

+
+
+ +
+ + +
+
+ +
+ + +
+ +
+
+ +`; + +exports[`NameDetails renders with saved name 1`] = ` + +
+
+
+
+
+