Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Merge extension and mobile controllers #700

Open
Gudahtt opened this issue Mar 1, 2022 · 7 comments
Open

Merge extension and mobile controllers #700

Gudahtt opened this issue Mar 1, 2022 · 7 comments

Comments

@Gudahtt
Copy link
Member

Gudahtt commented Mar 1, 2022

We want to use one shared set of controllers on both MetaMask extension and MetaMask mobile. This is to reduce to maintenance burden of each team, so that it is easier for us to provide a stable and secure codebase.

This issue description is still a work in progress. This will be updated with a list of each set of controllers to merge.

Each pair of controllers is listed in this checklist, each with sub-tasks that roughly map out the work required to merge the two controllers.

Tasks

Extract any API interactions or complex utility functions

Much of the complexity in our controllers is tied to functionality that is better managed as a separate module. Extracting API interactions and complex functionality can simplify the migration process and reduce maintenance.

Edit: More context from Mark: This refers to "reducing the scope of what controllers are responsible for (I guess you could call it the single responsibility principle)".

Refactor to be more easily understood

Some of our controllers are built in a way that makes them very difficult to reason about. For example, they might expose too many internal methods/properties, or they might have race conditions and complex polling logic. We need to understand how these controllers work in order to merge them, so we may have to spend some time simplifying them before merging in some cases.

Edit: More context from Mark: This is a "prompt to think about the controller API and simplifying it ... to improve the code first in cases where it would be really valuable, where it might save time and produce a better result".

Write comprehensive unit tests

By writing comprehensive unit tests for the controllers before we merge them, we can reduce the chance of introducing a regression.

Normalize the functionality across both controllers

The more similar we make the two controllers prior to merging them, the easier the final step will be.

Migrate

Migrate the extension and mobile projects to use the new shared controller. This is the last step.

Checklist

@mcmire
Copy link
Contributor

mcmire commented Mar 23, 2022

Notes from Monday's standup:

We probably need to prioritize Network and Keyring over other controllers.

  • We're starting to ramp up work on multi-network support
  • We've been wanting to fix the keyring stuff for a long time

@Gudahtt
Copy link
Member Author

Gudahtt commented Apr 8, 2022

I have just finished making a first pass on this, checking off anything that is clearly completed already. 40 tasks are completed out of 188, that's our starting point.

@mcmire
Copy link
Contributor

mcmire commented Apr 8, 2022

Nice!!

@Gudahtt
Copy link
Member Author

Gudahtt commented Jun 26, 2023

Here are a few jotnotes regarding the current status of remaining migrations:

Potentially straightforward (4):

  • AccountTracker / Cached Balances
  • TokenBalances
  • TokenDetection
  • PermissionLog

Collaboration (6):

  • AppState
    • Tricky
  • Preferences
    • Tricky
  • Announcement
    • Check with mobile team first
  • ENS
    • Integration is leftover
  • Swaps
    • Swaps team
  • SmartTransactions
    • Involve swaps team

Not applicable at the moment (5):

  • Alert
    • Not relevant to mobile
  • Snap
    • Snaps
  • Notification
    • Snaps
  • Onboarding
    • Mobile feature that they don't currently support
  • MetaMetrics
    • Major effort already planned to be done by mobile team

@mcmire
Copy link
Contributor

mcmire commented Jul 14, 2023

I've created #1509 which is related to this effort.

MajorLift added a commit to MetaMask/metamask-extension that referenced this issue Mar 14, 2024
…nDetectionController` (#22928)

## **Description**

This commit replaces
[`DetectTokensController`](https://github.com/MetaMask/metamask-extension/blob/68cc610976485d0071400cb2d4c3ea18cc6b15d9/app/scripts/controllers/detect-tokens.js)
with the core repo's
[`TokenDetectionController`](https://github.com/MetaMask/core/blob/main/packages/assets-controllers/src/TokenDetectionController.ts).

This represents the final step of Shared Libraries' initiative to a)
consolidate the core repo's `TokenDetectionController`, the extension's
`DetectTokensController`, and relevant mobile patches to
`@metamask/assets-controllers`, with the goal of b) migrating both
extension and mobile to use the consolidated controller in core.

This also represents a full conversion to TypeScript for
`DetectTokensController` and its unit tests.

[![Open in GitHub
Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/22928?quickstart=1)

## **Related issues**

- Contributes to: 
  - MetaMask/core#700
  - MetaMask/core#1812
- Closes: 
  - #23127
  - #23322
- Blocked by: 
  - MetaMask/core#3916
    - MetaMask/core#3923
- MetaMask/core#4007
(`@metamask/assets-controllers` v26)

## **Manual testing steps**

- Check whether issue no. 4 in this comment
#23010 (comment)
can be reproed in this branch.

## Changelog

### `metamask-extension`

- `MetamaskController` class:
- Define a `preferencesControllerMessenger` instance which only allows
the `PreferencesController:getState` action and
`PreferencesController:stateChange` event.
- Add a subscription to the preferences-controller observable store,
with a listener that publishes a `PreferencesController:stateChange`
event.
- `PreferencesController`:
  - Add `messenger` as an optional constructor options object property.
  - Register a `PreferencesController:getState` action handler.
- **BREAKING:** Replace all imports of `toChecksumHexAddress` from
`@metamask/controller-utils` with imports from the internal
`shared/modules/hexstring-utils` module.
- **BREAKING:** Bump `@metamask/assets-controllers` to `^26.0.0`.
  - Remove patch.
- **BREAKING:** Bump `@metamask/accounts-controller` to `^11.0.0`.
  - Remove unused diff in patch.
- **BREAKING:** Bump `@metamask/keyring-controller` to `^13.0.0`.
  - Remove patch.
- **BREAKING:** Remove `@metamask/polling-controller` as a dependency.
  - Required by `test-yarn-dedupe` CI run.
- Bump `@metamask/controller-utils` to `^8.0.4`.

### `TokenDetectionController` (compared to `DetectTokensController`)

- **BREAKING:** Inherit from `StaticIntervalPollingController` instead
of `StaticIntervalPollingControllerOnly`

- Constructor and class fields:
- **BREAKING:** Remove `preferences`, `network`, `tokenList`,
`tokensController`, `assetsContractController`,
`getCurrentSelectedAccount`, `getNetworkClientById` as constructor
options, and add required option `getBalancesInSingleCall`.
- **BREAKING:** Remove `disableLegacyInterval` class field and
constructor option.
- `#restartTokenDetection` always resets polling interval to default
regardless of whether legacy or new polling is being used.
- **BREAKING:** Add a `#disabled` private class field, which blocks all
network requests if set to true, and add `disabled` as an optional
constructor option, which defaults to 'true' if omitted.
- **BREAKING:** Remove `isOpen` class field, and replace by adding
`enable`, `disable` public methods.
- Add optional constructor option `selectedAddress`. If omitted, its
value is populated by calling the
`AccountsController:getSelectedAccount` action.

- Messenger:
- **BREAKING:** Newly subscribe to the
`PreferencesController:stateChange`,
`AccountsController:selectedAccountChange`, `KeyringController:lock`,
`KeyringController:unlock` events.
- **BREAKING:** Newly allow messenger actions
`AccountsController:getSelectedAccount`,
`NetworkController:getNetworkClientById`,
`NetworkController:getNetworkConfigurationByNetworkClientId`,
`NetworkController:getState`, `KeyringController:getState`,
`PreferencesController:getState`, `TokenListController:getState`,
`TokensController:getState`, and `TokensController:addDetectedTokens`.

- **BREAKING:** `detectTokens` replaces the `detectNewTokens` method.
- **BREAKING:** Now expects an options object with optional properties
`selectedAddress`, `networkClientId`, removing the `chainId` option.
- **BREAKING:** Passes lists of full `Token` types to
`TokensController:addDetectedTokens` instead of objects containing only
`{ address, decimals, symbol }`.
  - Processes an arbitrary number of tokens in batches of 1000.
- Previously, `detectTokens` was limited to two batches, with the first
batch being limited to 1000 tokens.
- If the `getBalancesInSingleCall` callback fails, it does not throw an
error or exit early, and the method continues processing the next batch
of tokens.

- **BREAKING:** `#restartTokenDetection` is a private method instead of
public.

- **BREAKING:** Replace the `getChainIdFromNetworkStore` method with the
private method `#getCorrectChainIdAndNetworkClientId`.

- **BREAKING:** `#trackMetaMetricsEvents` is a private method instead of
protected.
- Passes string literals instead of extension shared constants into
`_trackMetaMetricsEvent`.

### `TokensController`

- **BREAKING:** Newly allows `NetworkController:getNetworkClientById`
messenger action.
- **BREAKING:** Newly subscribes to
`NetworkController:networkDidChange`,
`PreferencesController:stateChange`, `TokenListController:stateChange`
events.
- **BREAKING:** Unsubscribes from `NetworkController:stateChange` event.

## **Screenshots/Recordings**

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've clearly explained what problem this PR is solving and how it
is solved.
- [x] I've linked related issues
- [x] I've included manual testing steps
- [ ] I've included screenshots/recordings if applicable
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
- [x] I’ve properly set the pull request status:
  - [x] In case it's not yet "ready for review", I've set it to "draft".
- [x] In case it's "ready for review", I've changed it from "draft" to
"non-draft".

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
davidmurdoch pushed a commit to MetaMask/metamask-extension that referenced this issue Mar 14, 2024
…nDetectionController` (#22928)

## **Description**

This commit replaces
[`DetectTokensController`](https://github.com/MetaMask/metamask-extension/blob/68cc610976485d0071400cb2d4c3ea18cc6b15d9/app/scripts/controllers/detect-tokens.js)
with the core repo's
[`TokenDetectionController`](https://github.com/MetaMask/core/blob/main/packages/assets-controllers/src/TokenDetectionController.ts).

This represents the final step of Shared Libraries' initiative to a)
consolidate the core repo's `TokenDetectionController`, the extension's
`DetectTokensController`, and relevant mobile patches to
`@metamask/assets-controllers`, with the goal of b) migrating both
extension and mobile to use the consolidated controller in core.

This also represents a full conversion to TypeScript for
`DetectTokensController` and its unit tests.

[![Open in GitHub
Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/22928?quickstart=1)

## **Related issues**

- Contributes to: 
  - MetaMask/core#700
  - MetaMask/core#1812
- Closes: 
  - #23127
  - #23322
- Blocked by: 
  - MetaMask/core#3916
    - MetaMask/core#3923
- MetaMask/core#4007
(`@metamask/assets-controllers` v26)

## **Manual testing steps**

- Check whether issue no. 4 in this comment
#23010 (comment)
can be reproed in this branch.

## Changelog

### `metamask-extension`

- `MetamaskController` class:
- Define a `preferencesControllerMessenger` instance which only allows
the `PreferencesController:getState` action and
`PreferencesController:stateChange` event.
- Add a subscription to the preferences-controller observable store,
with a listener that publishes a `PreferencesController:stateChange`
event.
- `PreferencesController`:
  - Add `messenger` as an optional constructor options object property.
  - Register a `PreferencesController:getState` action handler.
- **BREAKING:** Replace all imports of `toChecksumHexAddress` from
`@metamask/controller-utils` with imports from the internal
`shared/modules/hexstring-utils` module.
- **BREAKING:** Bump `@metamask/assets-controllers` to `^26.0.0`.
  - Remove patch.
- **BREAKING:** Bump `@metamask/accounts-controller` to `^11.0.0`.
  - Remove unused diff in patch.
- **BREAKING:** Bump `@metamask/keyring-controller` to `^13.0.0`.
  - Remove patch.
- **BREAKING:** Remove `@metamask/polling-controller` as a dependency.
  - Required by `test-yarn-dedupe` CI run.
- Bump `@metamask/controller-utils` to `^8.0.4`.

### `TokenDetectionController` (compared to `DetectTokensController`)

- **BREAKING:** Inherit from `StaticIntervalPollingController` instead
of `StaticIntervalPollingControllerOnly`

- Constructor and class fields:
- **BREAKING:** Remove `preferences`, `network`, `tokenList`,
`tokensController`, `assetsContractController`,
`getCurrentSelectedAccount`, `getNetworkClientById` as constructor
options, and add required option `getBalancesInSingleCall`.
- **BREAKING:** Remove `disableLegacyInterval` class field and
constructor option.
- `#restartTokenDetection` always resets polling interval to default
regardless of whether legacy or new polling is being used.
- **BREAKING:** Add a `#disabled` private class field, which blocks all
network requests if set to true, and add `disabled` as an optional
constructor option, which defaults to 'true' if omitted.
- **BREAKING:** Remove `isOpen` class field, and replace by adding
`enable`, `disable` public methods.
- Add optional constructor option `selectedAddress`. If omitted, its
value is populated by calling the
`AccountsController:getSelectedAccount` action.

- Messenger:
- **BREAKING:** Newly subscribe to the
`PreferencesController:stateChange`,
`AccountsController:selectedAccountChange`, `KeyringController:lock`,
`KeyringController:unlock` events.
- **BREAKING:** Newly allow messenger actions
`AccountsController:getSelectedAccount`,
`NetworkController:getNetworkClientById`,
`NetworkController:getNetworkConfigurationByNetworkClientId`,
`NetworkController:getState`, `KeyringController:getState`,
`PreferencesController:getState`, `TokenListController:getState`,
`TokensController:getState`, and `TokensController:addDetectedTokens`.

- **BREAKING:** `detectTokens` replaces the `detectNewTokens` method.
- **BREAKING:** Now expects an options object with optional properties
`selectedAddress`, `networkClientId`, removing the `chainId` option.
- **BREAKING:** Passes lists of full `Token` types to
`TokensController:addDetectedTokens` instead of objects containing only
`{ address, decimals, symbol }`.
  - Processes an arbitrary number of tokens in batches of 1000.
- Previously, `detectTokens` was limited to two batches, with the first
batch being limited to 1000 tokens.
- If the `getBalancesInSingleCall` callback fails, it does not throw an
error or exit early, and the method continues processing the next batch
of tokens.

- **BREAKING:** `#restartTokenDetection` is a private method instead of
public.

- **BREAKING:** Replace the `getChainIdFromNetworkStore` method with the
private method `#getCorrectChainIdAndNetworkClientId`.

- **BREAKING:** `#trackMetaMetricsEvents` is a private method instead of
protected.
- Passes string literals instead of extension shared constants into
`_trackMetaMetricsEvent`.

### `TokensController`

- **BREAKING:** Newly allows `NetworkController:getNetworkClientById`
messenger action.
- **BREAKING:** Newly subscribes to
`NetworkController:networkDidChange`,
`PreferencesController:stateChange`, `TokenListController:stateChange`
events.
- **BREAKING:** Unsubscribes from `NetworkController:stateChange` event.

## **Screenshots/Recordings**

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've clearly explained what problem this PR is solving and how it
is solved.
- [x] I've linked related issues
- [x] I've included manual testing steps
- [ ] I've included screenshots/recordings if applicable
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
- [x] I’ve properly set the pull request status:
  - [x] In case it's not yet "ready for review", I've set it to "draft".
- [x] In case it's "ready for review", I've changed it from "draft" to
"non-draft".

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants
@mcmire @Gudahtt @xinnanyemm and others