Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

fix: Apply major ComposableController API updates that fix broken functionality #10441

Draft
wants to merge 68 commits into
base: main
Choose a base branch
from

Conversation

MajorLift
Copy link
Contributor

@MajorLift MajorLift commented Jul 26, 2024

Description

This commit updates @metamask/composable-controller to ^9.0.0.

This involves fixing bugs outlined in #10073, and applying the major changes to the ComposableController API that has accumulated between the intervening versions.

Blocked by

Changelog

Changed

  • BREAKING: Bump @metamask/composable-controller from ^3.0.0 to ^9.0.0 (#10441)
    • BREAKING: Instantiate ComposableController class constructor option messenger with a RestrictedControllerMessenger instance derived from the controllerMessenger class field instance of Engine, instead of passing in the controllerMessenger instance directly.
    • BREAKING: Narrow external actions allowlist for messenger instance passed into ComposableController constructor from GlobalActions['type'] to an empty union.
    • BREAKING: Narrow external events allowlist for messenger instance passed into ComposableController constructor from GlobalEvents['type'] to a union of the stateChange events of all controllers included in the EngineState type.
  • BREAKING: Convert the EngineState interface to use type alias syntax to ensure compatibility with types used in MetaMask controllers (#10441)

Fixed

  • BREAKING: Narrow Engine class datamodel field from any to ComposableController<EngineState, Controllers[keyof Controllers]> (#10441)
  • BREAKING: The Engine class state getter method now normalizes null into 0 for the conversionRate values of all native currencies keyed in the currencyRates object of CurrencyRatesControllerState (#10441)
  • Widen Engine class controllerMessenger so that the its allowlists include all internal actions and events of the controllers defined in EngineState (#10441)
  • ComposableController can be instantiated with any collection of child controller instances, regardless of the BaseController package version the child controller inherits from (#10441)
    • Fix type errors caused by child controllers inheriting from outdated BaseControllerV1 versions.
    • Restore previously suppressed type-level validation for controllers constructor option.

Related issues

Manual testing steps

Screenshots/Recordings

Pre-merge author checklist

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.

Copy link
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@MajorLift MajorLift linked an issue Jul 26, 2024 that may be closed by this pull request
9 tasks
Copy link

socket-security bot commented Jul 26, 2024

New and removed dependencies detected. Learn more about Socket for GitHub ↗︎

Package New capabilities Transitives Size Publisher
npm/@metamask/[email protected] None 0 106 kB metamaskbot

🚮 Removed packages: npm/@metamask/[email protected]

View full report↗︎

@MajorLift MajorLift force-pushed the jongsun/fix-composable-controller branch 6 times, most recently from 815f836 to 992908f Compare July 31, 2024 23:18
@MajorLift MajorLift added the No QA Needed Apply this label when your PR does not need any QA effort. label Jul 31, 2024
@MajorLift MajorLift force-pushed the jongsun/fix-composable-controller branch 3 times, most recently from 6209b1f to a519205 Compare August 1, 2024 01:07
@MajorLift MajorLift added the DO-NOT-MERGE Pull requests that should not be merged label Aug 1, 2024
@MajorLift MajorLift requested a review from a team August 1, 2024 04:22
Copy link
Contributor Author

@MajorLift MajorLift left a comment

Choose a reason for hiding this comment

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

Notes for reviewers:

Comment on lines 1480 to 1543
this.datamodel = new ComposableController<
EngineState,
Controllers[keyof Controllers]
>({
controllers,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The controllers argument no longer requires a ts-expect-error directive, because its type is supplied via generic argument from the source-of-truth for the controllers array (i.e. Controllers).

Comment on lines 1485 to 1544
// @ts-expect-error Resolve/patch mismatch between base-controller versions
// ts(2322) - Property '#private' in type 'RestrictedControllerMessenger' refers to a different member that cannot be accessed from within type 'RestrictedControllerMessenger'
messenger: this.controllerMessenger.getRestricted({
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This ts-expect-error directive is required due to the @metamask/base-controller version mismatch issue that is affecting most of the controller instantiations in the Engine class.

I've put up a preview branch that demonstrates that pinning base-controller to the latest version using yarn resolutions resolves this issue: #10374.

In practice, this directive will be removed as the controller versions in mobile are upgraded.

Comment on lines 1509 to 1592
/**
* V1/V2 controllers incorrectly defined with a `messagingSystem` that is missing its `stateChange` event.
* ! These `stateChange` events must be included in the datamodel's events allowlist.
* TODO: Upstream fixes in the source packages are required for the following controllers.
*/
// @ts-expect-error BaseControllerV2, messenger defined without `stateChange` event type
'AuthenticationController:stateChange',
// @ts-expect-error BaseControllerV2, messenger defined without `stateChange` event type
'LoggingController:stateChange',
// @ts-expect-error BaseControllerV1, has `messagingSystem` but as private field, messenger defined without `stateChange` event type
'NftController:stateChange',
// @ts-expect-error BaseControllerV2, messenger defined without `stateChange` event type
'NotificationServicesController:stateChange',
// @ts-expect-error BaseControllerV2, messenger defined without `stateChange` event type
'PhishingController:stateChange',
// @ts-expect-error BaseControllerV2, messenger defined without `stateChange` event type
'PPOMController:stateChange',
// @ts-expect-error BaseControllerV2, messenger defined without `stateChange` event type
'SnapsRegistry:stateChange',
// @ts-expect-error BaseControllerV2, `TokenBalancesControllerState` import error
'TokenBalancesController:stateChange',
// @ts-expect-error BaseControllerV2, messenger defined without `stateChange` event type
'UserStorageController:stateChange',
Copy link
Contributor Author

@MajorLift MajorLift Aug 1, 2024

Choose a reason for hiding this comment

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

These are stateChange events that need to be included in this allowlist, but are throwing errors because of misdefined controllers or messenger typing in their upstream source packages.

I have documented the causes in the comments, and the preview branch demonstrates working fixes for these that use yarn patches.

The wallet framework team has created a ticket to address these issues: MetaMask/core#4579. While the updated controllers are being released, the yarn patch fixes could also be cherry-picked from the preview branch.

Here, I have applied ts-expect-error directives to ensure that the ComposableControllerMessenger is defined with the correct allowlist at runtime, even if the associated types are not yet fully defined.

Comment on lines 1533 to 1606
/**
* V1 controllers that should be excluded from the datamodel's events allowlist for now.
* TODO: Each of these events should be added to the allowlist once its controller is migrated to V2.
*/
// 'AccountTrackerController:stateChange', // StaticIntervalPollingControllerV1, no `messagingSystem`
// 'AddressBookController:stateChange', // BaseControllerV1, no `messagingSystem`
// 'SmartTransactionsController:stateChange', // StaticIntervalPollingControllerV1, no `messagingSystem`
// 'SwapsController:stateChange', // BaseControllerV1, no `messagingSystem`
// 'TokenRatesController:stateChange', // StaticIntervalPollingControllerV1, no `messagingSystem`
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These are stateChange events that eventually need to be included in this allowlist, but are blocked by their controllers lacking a messagingSystem.

These controllers have been upgraded to V2 or are currently in the process of being upgraded. These events should be uncommented as mobile migrates to using the upgraded V2 versions.

The end result of these changes can be seen in the preview branch: https://github.com/MetaMask/metamask-mobile/pull/10374/files#diff-1a656ef42f595bb9c6c1251b29808fd70d31da7a3e1a6e9be85574ad866dc1b0R1508-R1536

app/core/Engine.ts Outdated Show resolved Hide resolved
// TODO: Replace "any" with type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
datamodel: any;
datamodel: ComposableController<EngineState, Controllers[keyof Controllers]>;
Copy link
Contributor Author

@MajorLift MajorLift Aug 1, 2024

Choose a reason for hiding this comment

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

This was causing implicit any types to spread throughout the file. See below.

Comment on lines +2039 to +2120
currencyRates: Object.fromEntries(
Object.entries(CurrencyRateController.currencyRates).map(([k, v]) => [
k,
{ ...v, conversionRate: v.conversionRate ?? 0 },
]),
),
Copy link
Contributor Author

@MajorLift MajorLift Aug 1, 2024

Choose a reason for hiding this comment

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

This CurrencyRateController object has been implicitly typed as any since this year-old change, along with all of the state objects destructured in the preceding lines (https://github.com/MetaMask/metamask-mobile/pull/10441/files#diff-1a656ef42f595bb9c6c1251b29808fd70d31da7a3e1a6e9be85574ad866dc1b0R2001-R2033).

Because of this, when the CurrencyRateController class's state type was significantly altered in a breaking change introduced by @metamask/[email protected], the resulting type error was suppressed, causing this runtime bug to go undetected.

The type error is now restored, as a side effect of the any typing of the datamodel class field being fixed.

Previously, there was only one top-level conversionRate property in the CurrencyRateController object that was being modified. I have fixed the logic so that all nested conversionRate properties for all currencies are normalized to 0 if they have a null value. Please let me know if this isn't the expected behavior.

Copy link
Contributor

Choose a reason for hiding this comment

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

Nice catch

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added a test for this change, but sonarcloud is still complaining that lines 2099 and 2101 are uncovered: e107dc3

Copy link
Contributor Author

@MajorLift MajorLift Sep 6, 2024

Choose a reason for hiding this comment

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

Sonarcloud issue fixed here: 0b70f89

Comment on lines +307 to +347
// Interfaces are incompatible with our controllers and data types by default.
// Adding an index signature fixes this, but at the cost of widening the type unnecessarily.
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
export type EngineState = {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@MajorLift MajorLift marked this pull request as ready for review August 1, 2024 05:03
@MajorLift MajorLift requested review from a team as code owners August 1, 2024 05:03
@MajorLift MajorLift force-pushed the jongsun/fix-composable-controller branch 2 times, most recently from f501427 to 2c0475a Compare August 1, 2024 18:28
@MajorLift MajorLift removed the DO-NOT-MERGE Pull requests that should not be merged label Aug 1, 2024
@MajorLift MajorLift marked this pull request as draft August 1, 2024 18:57
@MajorLift MajorLift force-pushed the jongsun/fix-composable-controller branch 2 times, most recently from 8e8fc98 to 2a010d3 Compare August 1, 2024 19:51
@MajorLift MajorLift marked this pull request as ready for review August 1, 2024 20:11
@MajorLift MajorLift force-pushed the jongsun/fix-composable-controller branch from 908c281 to 73a608b Compare August 1, 2024 22:15
Copy link

sonarcloud bot commented Oct 3, 2024

@mcmire
Copy link
Contributor

mcmire commented Oct 23, 2024

@MajorLift Is this PR still relevant? It looks like maybe, but it has also been open for a while I'm noticing, so I'm not sure if it needs to be updated or something.

@cryptodev-2s
Copy link
Contributor

@MajorLift Is this PR still relevant? It looks like maybe, but it has also been open for a while I'm noticing, so I'm not sure if it needs to be updated or something.

Yes still relevant I am taking over this work

@cryptodev-2s cryptodev-2s added the Run Smoke E2E Triggers smoke e2e on Bitrise label Oct 23, 2024
Copy link
Contributor

github-actions bot commented Oct 23, 2024

https://bitrise.io/ Bitrise

❌❌❌ pr_smoke_e2e_pipeline failed on Bitrise! ❌❌❌

Commit hash: fe66a38
Build link: https://app.bitrise.io/app/be69d4368ee7e86d/pipelines/ebfbbc58-1f83-4239-8a71-224f9a3645bc

Note

  • You can kick off another pr_smoke_e2e_pipeline on Bitrise by removing and re-applying the Run Smoke E2E label on the pull request

Tip

  • Check the documentation if you have any doubts on how to understand the failure on bitrise

@MajorLift MajorLift added Run Smoke E2E Triggers smoke e2e on Bitrise and removed Run Smoke E2E Triggers smoke e2e on Bitrise labels Nov 14, 2024
Copy link
Contributor

https://bitrise.io/ Bitrise

🔄🔄🔄 pr_smoke_e2e_pipeline started on Bitrise...🔄🔄🔄

Commit hash: 49f4ae0
Build link: https://app.bitrise.io/app/be69d4368ee7e86d/pipelines/73593585-1c9f-4513-a048-8acd6ae4284e

Note

  • This comment will auto-update when build completes
  • You can kick off another pr_smoke_e2e_pipeline on Bitrise by removing and re-applying the Run Smoke E2E label on the pull request

@MajorLift MajorLift force-pushed the jongsun/fix-composable-controller branch from 49f4ae0 to 24d9936 Compare November 14, 2024 18:09
@MajorLift MajorLift added Run Smoke E2E Triggers smoke e2e on Bitrise and removed Run Smoke E2E Triggers smoke e2e on Bitrise labels Nov 14, 2024
Copy link
Contributor

https://bitrise.io/ Bitrise

🔄🔄🔄 pr_smoke_e2e_pipeline started on Bitrise...🔄🔄🔄

Commit hash: 24d9936
Build link: https://app.bitrise.io/app/be69d4368ee7e86d/pipelines/f0a01847-8e29-401d-97fe-52a8bd283ba7

Note

  • This comment will auto-update when build completes
  • You can kick off another pr_smoke_e2e_pipeline on Bitrise by removing and re-applying the Run Smoke E2E label on the pull request

@MajorLift MajorLift added Run Smoke E2E Triggers smoke e2e on Bitrise and removed Run Smoke E2E Triggers smoke e2e on Bitrise labels Nov 14, 2024
Copy link
Contributor

github-actions bot commented Nov 14, 2024

https://bitrise.io/ Bitrise

❌❌❌ pr_smoke_e2e_pipeline failed on Bitrise! ❌❌❌

Commit hash: eaf1ee2
Build link: https://app.bitrise.io/app/be69d4368ee7e86d/pipelines/005c893f-9abe-40dd-9801-d057e62e8b0a

Note

  • You can kick off another pr_smoke_e2e_pipeline on Bitrise by removing and re-applying the Run Smoke E2E label on the pull request

Tip

  • Check the documentation if you have any doubts on how to understand the failure on bitrise

@MajorLift MajorLift removed the DO-NOT-MERGE Pull requests that should not be merged label Nov 14, 2024
@MajorLift MajorLift marked this pull request as draft November 14, 2024 18:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Run Smoke E2E Triggers smoke e2e on Bitrise team-wallet-framework
Projects
Status: Needs more work from the author
Development

Successfully merging this pull request may close these issues.

fix: ComposableController instantiation and functionality is broken
5 participants