chore(runway): cherry-pick fix(card): update feature flag listener on CardController#29376
Merged
joaoloureirop merged 1 commit intoApr 27, 2026
Merged
Conversation
… CardController (#29350) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** This branch refreshes **card home data and Baanx configuration** when **remote card feature flags** change, and fixes a **race** where a slow **unauthenticated** `fetchCardHomeData` could overwrite state **after** successful **submitCredentials**. **Feature flags** - [`app/selectors/featureFlagController/card/index.ts`](app/selectors/featureFlagController/card/index.ts): exports **`defaultCardFeatureFlag`** and **`resolveCardFeatureFlag`** (empty remote payload → defaults). **`selectCardFeatureFlag`** now uses **`resolveCardFeatureFlag`** so the same resolution rules apply in Redux selectors and Engine. **BaanxProvider / init** - [`BaanxProvider.ts`](app/core/Engine/controllers/card-controller/providers/BaanxProvider.ts): accepts optional **`getCardFeatureFlag`** (lazy) in addition to legacy **`cardFeatureFlag`**. A private getter resolves **`cardFeatureFlag`** on each read so URLs/constants track the latest remote flags without recreating the provider. - [`card-controller/index.ts`](app/core/Engine/controllers/card-controller/index.ts): passes **`getCardFeatureFlag`** from **`RemoteFeatureFlagController:getState`** + **`resolveCardFeatureFlag`** into **`BaanxProvider`**. **CardController** - Subscribes to **`RemoteFeatureFlagController:stateChange`** with a **selector** that serializes **`remoteFeatureFlags.cardFeature`** so only meaningful card-flag updates run the handler. - **`#handleCardFeatureFlagChange`**: if an EVM address is selected, **`invalidateFetch()`**, clears **`cardHomeData`** / sets **`cardHomeDataStatus`** to **`idle`**, then refetches card home data. - **`#fetchCardHomeDataWithLogging`**: centralizes **`fetchCardHomeData`** + **`Logger.error`** for account switch, feature-flag refresh, **`submitCredentials`**, and **`validateAndRefreshSession`**. - **`#triggerCardholderCheck`** (accounts API URL path): uses **`resolveCardFeatureFlag`** instead of ad-hoc casting. - **`submitCredentials`**: sets **`cardHomeData`** to **`null`** and status **`idle`**, calls **`invalidateFetch()`**, then fetches—so in-flight unauthenticated responses cannot win over authenticated data. **Messenger / types** - [`card-controller-messenger/index.ts`](app/core/Engine/messengers/card-controller-messenger/index.ts): allows event **`RemoteFeatureFlagController:stateChange`**. - [`types.ts`](app/core/Engine/controllers/card-controller/types.ts): **`CardControllerAllowedEvents`** includes **`RemoteFeatureFlagControllerStateChangeEvent`**. **Tests** - [`CardController.test.ts`](app/core/Engine/controllers/card-controller/CardController.test.ts): subscription to remote feature-flag state; handler clears state and refetches; **`drops in-flight unauthenticated card home data after successful auth`**. - [`BaanxProvider.test.ts`](app/core/Engine/controllers/card-controller/providers/BaanxProvider.test.ts): **`getCardFeatureFlag`** read **lazily** during **`getOnChainAssets`**. ## **Changelog** CHANGELOG entry: Card — **`CardController`** listens for **`RemoteFeatureFlagController:stateChange`** and refetches card home data when **`cardFeature`** changes; **`BaanxProvider`** resolves card feature flags lazily; shared **`resolveCardFeatureFlag`**; **`submitCredentials`** invalidates in-flight fetches and resets card home state to avoid stale unauthenticated data after login. ## **Related issues** Fixes: #29348 <!-- Add GitHub issue link when available, e.g. Fixes #12345 --> ## **Manual testing steps** ```gherkin Feature: Card home and Baanx flags stay in sync with remote card feature flags Scenario: Remote card feature flag updates while card tab is open Given the user is on an EVM account with card session and card home loaded When remote `cardFeature` changes (e.g. rollout or config update) Then card home data is cleared to idle and refetched And Baanx-backed calls use the updated flag-derived config on subsequent requests Scenario: Login while an unauthenticated card home fetch is still in flight Given an unauthenticated card home fetch has not completed When the user completes submitCredentials successfully Then authenticated card home data wins and a late unauthenticated response does not overwrite it Scenario: Card feature flag change with no selected EVM address When RemoteFeatureFlagController emits a card-related change but no EVM address is selected Then the handler returns early without refetch errors ``` ## **Screenshots/Recordings** <!-- Optional: behavior is mostly data-layer; attach if you verify on device after a forced remote flag change. --> ### **Before** <!-- Card home could stay stale until manual refresh; rare stale data after fast login during slow unauthenticated fetch. --> ### **After** <!-- Card home refetches when `cardFeature` changes; submitCredentials path drops stale in-flight unauthenticated results. --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [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-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] 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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Updates card state refresh triggers and fetch invalidation logic around auth and feature-flag changes; risk is moderate due to new event subscriptions and potential for extra network calls or missed updates if selectors are wrong. > > **Overview** > **Card home data now refreshes when remote `cardFeature` flags change.** `CardController` subscribes to `RemoteFeatureFlagController:stateChange`, clears `cardHomeData`/status back to `idle`, invalidates any in-flight fetch, and refetches. > > **Fixes a race where slow unauthenticated fetches could overwrite authenticated state.** After successful `submitCredentials`, the controller resets home data, bumps the fetch generation, and refetches via a shared `#fetchCardHomeDataWithLogging` helper (also used by account-switch and session refresh paths). > > **Feature-flag resolution and consumption were tightened.** Adds `resolveCardFeatureFlag` (and exports `defaultCardFeatureFlag`) to normalize empty remote payloads to defaults; `BaanxProvider` can now read flags lazily via a `getCardFeatureFlag` callback wired in `cardControllerInit`, and the card-controller messenger/types allow the new remote-flag stateChange event. > > Tests add coverage for the new subscription behavior, the stale-fetch drop after auth, and lazy flag reads in `BaanxProvider`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 0d9863b. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
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. |
Contributor
🔍 Smart E2E Test Selection⏭️ Smart E2E selection skipped - PR targets a release branch (release/*) All E2E tests pre-selected. |
joaoloureirop
approved these changes
Apr 27, 2026
|
Contributor
|
✅ E2E Fixture Validation — Schema is up to date |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Description
This branch refreshes card home data and Baanx configuration when
remote card feature flags change, and fixes a race where a slow
unauthenticated
fetchCardHomeDatacould overwrite state aftersuccessful submitCredentials.
Feature flags
app/selectors/featureFlagController/card/index.ts:exports
defaultCardFeatureFlagandresolveCardFeatureFlag(empty remote payload → defaults).
selectCardFeatureFlagnow usesresolveCardFeatureFlagso the same resolution rules apply in Reduxselectors and Engine.
BaanxProvider / init
BaanxProvider.ts:accepts optional
getCardFeatureFlag(lazy) in addition to legacycardFeatureFlag. A private getter resolvescardFeatureFlagon each read so URLs/constants track the latest remote flags without
recreating the provider.
card-controller/index.ts:passes
getCardFeatureFlagfromRemoteFeatureFlagController:getState+resolveCardFeatureFlagintoBaanxProvider.CardController
RemoteFeatureFlagController:stateChangewith aselector that serializes
remoteFeatureFlags.cardFeaturesoonly meaningful card-flag updates run the handler.
#handleCardFeatureFlagChange: if an EVM address is selected,invalidateFetch(), clearscardHomeData/ setscardHomeDataStatustoidle, then refetches card home data.#fetchCardHomeDataWithLogging: centralizesfetchCardHomeData+Logger.errorfor account switch,feature-flag refresh,
submitCredentials, andvalidateAndRefreshSession.#triggerCardholderCheck(accounts API URL path): usesresolveCardFeatureFlaginstead of ad-hoc casting.submitCredentials: setscardHomeDatatonullandstatus
idle, callsinvalidateFetch(), then fetches—soin-flight unauthenticated responses cannot win over authenticated data.
Messenger / types
card-controller-messenger/index.ts:allows event
RemoteFeatureFlagController:stateChange.types.ts:CardControllerAllowedEventsincludesRemoteFeatureFlagControllerStateChangeEvent.Tests
CardController.test.ts:subscription to remote feature-flag state; handler clears state and
refetches;
drops in-flight unauthenticated card home data after successful auth.BaanxProvider.test.ts:getCardFeatureFlagread lazily duringgetOnChainAssets.Changelog
CHANGELOG entry: Card —
CardControllerlistens forRemoteFeatureFlagController:stateChangeand refetches card homedata when
cardFeaturechanges;BaanxProviderresolves cardfeature flags lazily; shared
resolveCardFeatureFlag;submitCredentialsinvalidates in-flight fetches and resets cardhome state to avoid stale unauthenticated data after login.
Related issues
Fixes: #29348
Manual testing steps
Screenshots/Recordings
Before
After
Pre-merge author checklist
Docs and MetaMask Mobile
Coding
Standards.
if applicable
guidelines).
Not required for external contributors.
Performance checks (if applicable)
SRPs
to import wallets with many accounts and tokens
performance metrics
trace()for usage andaddTokenfor an example
For performance guidelines and tooling, see the Performance
Guide.
Pre-merge reviewer checklist
app, test code being changed).
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
Note
Medium Risk
Updates card state refresh triggers and fetch invalidation logic
around auth and feature-flag changes; risk is moderate due to new event
subscriptions and potential for extra network calls or missed updates if
selectors are wrong.
Overview
Card home data now refreshes when remote
cardFeatureflagschange.
CardControllersubscribes toRemoteFeatureFlagController:stateChange, clearscardHomeData/statusback to
idle, invalidates any in-flight fetch, and refetches.Fixes a race where slow unauthenticated fetches could overwrite
authenticated state. After successful
submitCredentials, thecontroller resets home data, bumps the fetch generation, and refetches
via a shared
#fetchCardHomeDataWithLogginghelper (also used byaccount-switch and session refresh paths).
Feature-flag resolution and consumption were tightened. Adds
resolveCardFeatureFlag(and exportsdefaultCardFeatureFlag) tonormalize empty remote payloads to defaults;
BaanxProvidercan nowread flags lazily via a
getCardFeatureFlagcallback wired incardControllerInit, and the card-controller messenger/types allow thenew remote-flag stateChange event.
Tests add coverage for the new subscription behavior, the stale-fetch
drop after auth, and lazy flag reads in
BaanxProvider.Reviewed by Cursor Bugbot for commit
0d9863b. Bugbot is set up for automated
code reviews on this repo. Configure
here.