-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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: ComposableController
instantiation and functionality is broken
#10073
Labels
Sev2-normal
An issue that may lead to users misunderstanding some limited risks they are taking
team-wallet-framework
type-bug
Something isn't working
Comments
Merged
3 tasks
gauthierpetetin
added
the
Sev2-normal
An issue that may lead to users misunderstanding some limited risks they are taking
label
Jun 28, 2024
This was referenced Jul 23, 2024
Closed
7 tasks
MajorLift
added a commit
to MetaMask/core
that referenced
this issue
Aug 20, 2024
… safeguards (#4467) ## Overview This commit fixes issues with the `ComposableController` class's interface, and its logic for validating V1 and V2 controllers. These changes will enable `ComposableController` to function correctly downstream in the Mobile Engine, and eventually the Wallet Framework POC. ## Explanation The previous approach of generating mock controller classes from the `ComposableControllerState` input using the `GetChildControllers` was flawed, because the mock controllers would always be incomplete, complicating attempts at validation. Instead, we now rely on the downstream consumer to provide both a composed type of state schemas (`ComposableControllerState`) and a type union of the child controller instances (`ChildControllers`). For example, in mobile, we can use (with some adjustments) `EngineState` for the former, and `Controllers[keyof Controllers]` for the latter. The validation logic for V1 controllers has also been updated. Due to breaking changes made to the private properties of `BaseControllerV1` (#3959), mobile V1 controllers relying on versions prior to these changes were introduced were incompatible with the up-to-date `BaseControllerV1` version that the composable-controller package references. In this commit, the validator type `BaseControllerV1Instance` filters out the problematic private properties by using the `PublicInterface` type. Because the public API of `BaseControllerV1` has been relatively constant, this removes the type errors that previously occurred in mobile when passing V1 controllers into `ComposableController`. ## References - Closes #4448 - Contributes to #4213 - Next steps MetaMask/metamask-mobile#10073 - See MetaMask/metamask-mobile#10011 ## Changelog ### `@metamask/composable-controller` (major) ### Changed - **BREAKING:** Add two required generic parameters to the `ComposableController` class: `ComposedControllerState` (constrained by `LegacyComposableControllerStateConstraint`) and `ChildControllers` (constrained by `ControllerInstance`) ([#4467](#4467)). - **BREAKING:** The type guard `isBaseController` now validates that the input has an object-type property named `metadata` in addition to its existing checks. - **BREAKING:** The type guard `isBaseControllerV1` now validates that the input has object-type properties `config`, `state`, and function-type property `subscribe`, in addition to its existing checks. - **BREAKING:** Narrow `LegacyControllerStateConstraint` type from `BaseState | StateConstraint` to `BaseState & object | StateConstraint`. - Add an optional generic parameter `ControllerName` to the `RestrictedControllerMessengerConstraint` type, which extends `string` and defaults to `string`. ### Fixed - **BREAKING:** The `ComposableController` class raises a type error if a non-controller with no `state` property is passed into the `ChildControllers` generic parameter or the `controllers` constructor option. - Previously, a runtime error was thrown at class instantiation with no type-level enforcement. - When the `ComposableController` class is instantiated, its messenger now attempts to subscribe to all child controller `stateChange` events that are included in the messenger's events allowlist. - This was always the expected behavior, but a bug introduced in `@metamask/[email protected]` caused `stateChange` event subscriptions to fail. - `isBaseController` and `isBaseControllerV1` no longer return false negatives. - The `instanceof` operator is no longer used to validate that the input is a subclass of `BaseController` or `BaseControllerV1`. - The `ChildControllerStateChangeEvents` type checks that the child controller's state extends from the `StateConstraintV1` type instead of from `Record<string, unknown>`. ([#4467](#4467)) - V1 controllers define their state types using the `interface` keyword, which are incompatible with `Record<string, unknown>` by default. This resulted in `ChildControllerStateChangeEvents` failing to generate `stateChange` events for V1 controllers and returning `never`. ## Checklist - [x] I've updated the test suite for new or updated code as appropriate - [x] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [x] I've highlighted breaking changes using the "BREAKING" category above as appropriate
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
Sev2-normal
An issue that may lead to users misunderstanding some limited risks they are taking
team-wallet-framework
type-bug
Something isn't working
What is this about?
Explanation
ComposableController
usage in the mobile Engine is currently broken in two ways.ComposableController
's constructor has a type constraint that is incompatible with V1 members of thecontrollers
input array.Up until now, this error has been suppressed with the following comment, which is incorrect:
// @ts-expect-error The ComposableController needs to be updated to support BaseControllerV2
ComposableController
has supported V2 controllers since before its first release (see Add BaseControllerV2 support to ComposableController core#447).ComposableController
constructor has always been aControllerMessenger
class instance, when it should have been aRestrictedControllerMessenger
.This grants the
ComposableController
wider permissions than intended (we only want to allowstateChange
events for all child controllers), and generally goes against our recommended usage pattern for messengers.(However, it shouldn't prevent the
controllerMessenger
orComposableController
state from subscribing to state updates from child controllers)Solution
Add tests toEngine.test.js
file verifying that thedatamodel
has subscribed to state updates from all child controllers (both those with amessagingSystem
, and V1 controllers with nomessagingSystem
).Bump
@metamask/composable-controller
to the latest version which offers better type safety and quality-of-life improvements.@metamask/[email protected]
features widespreadany
usage, which would unnecessarily complicate any debugging efforts.controllers
, attempt to resolve by bumping V1 controllers from mobile.context
have a V2 release, except forSwapsController
, which has a V2 upgrade being implemented by the accounts team, andAssetsContractController
, which will be upgraded into a non-controller, necessitating changes inComposableController
([composable-controller] Enable handling of input that includes non-controllers with empty state core#4444).If unsuccessful, wait until the issue is fixed from the
ComposableController
side: MetaMask/core#4448Scenario
No response
Design
No response
Technical Details
No response
Threat Modeling Framework
No response
Acceptance Criteria
No response
Stakeholder review needed before the work gets merged
References
No response
The text was updated successfully, but these errors were encountered: