Skip to content

feat(card): add CardController shell to Engine#27020

Merged
Brunonascdev merged 4 commits into
mainfrom
feat/mm-card-controller-phase-1
Mar 4, 2026
Merged

feat(card): add CardController shell to Engine#27020
Brunonascdev merged 4 commits into
mainfrom
feat/mm-card-controller-phase-1

Conversation

@Brunonascdev

@Brunonascdev Brunonascdev commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

Description

Introduces the CardController shell into the Engine as the first step toward the multi-provider Card architecture.

Why: The Card feature is tightly coupled to Baanx with business logic scattered across hooks, views, and a 2,600-line SDK monolith. To support multiple card providers and clean up the architecture, we need a proper Engine controller that owns the Card feature's persistent state. This PR lays the foundation — an inert controller that holds state and syncs it to Redux via the standard Engine batcher. No user-facing changes.

What changed:

New files:

  • app/core/Engine/controllers/card-controller/types.ts: Defines CardControllerState (5 fields: selectedCountry, activeProviderId, isAuthenticated, cardholderAccounts, providerData), default state factory, and action/event/messenger types.
  • app/core/Engine/controllers/card-controller/CardController.ts: Bare-bones controller extending BaseController. All state is persisted and marked usedInUi: true. No business logic yet — provider delegation comes in subsequent PRs.
  • app/core/Engine/controllers/card-controller/index.ts: Init function following the standard Engine pattern — reads persisted state, creates controller instance.
  • app/core/Engine/messengers/card-controller-messenger/index.ts: Simple messenger with no delegated actions/events (those will be added when the controller needs to talk to KeyringController, TransactionController, etc.).
  • app/selectors/cardController.ts: Four selectors: selectCardSelectedCountry, selectCardActiveProviderId, selectIsCardAuthenticated, selectCardholderAccounts.

Modified files:

  • app/core/Engine/types.ts: Added CardController to Controllers, EngineState, GlobalActions, GlobalEvents, and ControllersToInitialize.
  • app/core/Engine/Engine.ts: Registered init function, destructured from controllersByName, added to this.context and state getter.
  • app/core/Engine/messengers/index.ts: Added CardController entry to CONTROLLER_MESSENGERS.
  • app/core/Engine/constants.ts: Added 'CardController:stateChange' to BACKGROUND_STATE_CHANGE_EVENT_NAMES.
  • app/util/test/initial-background-state.json: Added CardController default state to the test fixture.
  • .github/CODEOWNERS: Assigned app/core/Engine/controllers/card-controller, app/core/Engine/messengers/card-controller-messenger, and app/selectors/cardController.ts to @MetaMask/card.

Test files:

  • CardController.test.ts: Tests controller construction with default state, partial state, and full persisted state.
  • index.test.ts: Tests the init function returns a controller instance, uses default state when none is persisted, and uses persisted state when provided.
  • cardController.test.ts: Tests all four selectors with populated state, empty state, and undefined CardController state (fallback values).

Changelog

CHANGELOG entry: null

Related issues

Fixes:

Manual testing steps

Feature: CardController initialization

  Scenario: Controller initializes with default state on fresh install
    Given the app is freshly installed
    When the Engine initializes
    Then state.engine.backgroundState.CardController exists
    And selectedCountry is null
    And activeProviderId is null
    And isAuthenticated is false
    And cardholderAccounts is an empty array
    And providerData is an empty object

  Scenario: Controller state persists across app restarts
    Given the app has been launched before
    And CardController state was persisted
    When the Engine initializes again
    Then the persisted CardController state is restored

  Scenario: No user-facing changes
    Given the user is on any screen in the app
    When the app loads
    Then nothing visually changes
    And the Card feature continues to work as before

Screenshots/Recordings

No UI changes — this is an infrastructure-only PR.

Before

No CardController in Engine. Card state managed entirely by Redux slice.

After

CardController exists in Engine with default state. Syncs to state.engine.backgroundState.CardController. Existing Card feature behavior is unchanged.

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.

Note

Medium Risk
Medium risk because it updates core Engine initialization/types and introduces new persisted background state, which could affect startup or state serialization despite having no business logic yet.

Overview
Introduces a new CardController (BaseController) that persists Card feature state (selectedCountry, activeProviderId, isAuthenticated, cardholderAccounts, providerData) and exposes it via the standard Engine background state batching.

Wires the controller into Engine initialization and messaging (Engine.ts, messengers/index.ts, types.ts, constants.ts) so CardController state is included in Engine.state, state-change subscriptions, and debug/state log fixtures.

Adds initial selectors in selectors/cardController.ts, plus unit tests for controller construction/init and selector fallbacks, and updates CODEOWNERS for new Card Engine paths.

Written by Cursor Bugbot for commit 8363bb1. This will update automatically on new commits. Configure here.

@Brunonascdev Brunonascdev self-assigned this Mar 4, 2026
@Brunonascdev Brunonascdev requested a review from a team as a code owner March 4, 2026 20:05
@Brunonascdev Brunonascdev added the no-changelog no-changelog Indicates no external facing user changes, therefore no changelog documentation needed label Mar 4, 2026
@Brunonascdev Brunonascdev changed the title feat(card): add CardController initial structure feat(card): add CardController shell to Engine Mar 4, 2026
@github-actions

github-actions Bot commented Mar 4, 2026

Copy link
Copy Markdown
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.

@metamaskbot metamaskbot added the team-card Card Team label Mar 4, 2026
@github-actions github-actions Bot added the size-M label Mar 4, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Comment thread app/selectors/cardController.test.ts
@github-actions

github-actions Bot commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeCard
  • Selected Performance tags: None (no tests recommended)
  • Risk Level: medium
  • AI Confidence: 85%
click to see 🤖 AI reasoning details

E2E Test Selection:
This PR introduces a new CardController to the MetaMask Mobile Engine. The changes are well-structured and follow proper patterns for adding a new controller:

  1. New CardController: A Phase 6 (business logic) controller that manages MetaMask Card feature state including selectedCountry, activeProviderId, isAuthenticated, cardholderAccounts, and providerData.

  2. Proper Engine Integration:

    • Added to Engine.ts initialization
    • Registered in BACKGROUND_STATE_CHANGE_EVENT_NAMES for Redux sync
    • Added messenger configuration
    • Added type definitions
  3. No Dependencies: The CardController has no getController() calls, meaning it doesn't depend on other controllers. This makes it an isolated, low-risk addition.

  4. Redux Selectors: New selectors created for accessing CardController state from Redux.

  5. Test Infrastructure: Updated initial-background-state.json and log snapshots with CardController default state.

The SmokeCard tag is appropriate because:

  • Existing Card E2E tests exist that test Card home screen, Add Funds button, and Card management
  • These tests will validate that the new controller integrates properly with the Card UI
  • The controller manages state that the Card UI components will consume

Risk is medium (not low) because:

  • This modifies Engine.ts (critical file)
  • Adds a new controller to the initialization flow
  • Changes affect Redux state structure

However, the changes are additive (not modifying existing behavior) and follow established patterns, so comprehensive testing beyond SmokeCard is not necessary.

Performance Test Selection:
The CardController is a new state management controller that doesn't impact rendering performance, app startup time, or critical user flows. It's a thin coordination layer for Card feature state with no complex computations, no UI rendering changes, and no impact on existing performance-critical paths like account lists, login, swaps, or asset loading. The controller simply manages persisted state (country, provider, auth status) and syncs to Redux. No performance tests are needed.

View GitHub Actions results

@github-actions

github-actions Bot commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

⚠️ E2E Fixture Validation — Structural changes detected

Category Count
New keys 66
Missing keys 0
Type mismatches 0
Value mismatches 7 (informational)

The committed fixture schema is out of date. To update, comment:

@metamaskbot update-mobile-fixture

View full details | Download diff report

@sonarqubecloud

sonarqubecloud Bot commented Mar 4, 2026

Copy link
Copy Markdown

@Cal-L Cal-L left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM from platform

@Brunonascdev Brunonascdev added this pull request to the merge queue Mar 4, 2026
Merged via the queue into main with commit 8bab3bf Mar 4, 2026
89 checks passed
@Brunonascdev Brunonascdev deleted the feat/mm-card-controller-phase-1 branch March 4, 2026 23:31
@github-actions github-actions Bot locked and limited conversation to collaborators Mar 4, 2026
@metamaskbot metamaskbot added the release-7.69.0 Issue or pull request that will be included in release 7.69.0 label Mar 4, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

no-changelog no-changelog Indicates no external facing user changes, therefore no changelog documentation needed release-7.69.0 Issue or pull request that will be included in release 7.69.0 size-M team-card Card Team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants