[pull] main from MetaMask:main#787
Merged
Merged
Conversation
## **Description**
Adds remote-config support for the new Predict portfolio feature flag
introduced by PRED-898.
This PR wires `predictPortfolio` through the existing Predict feature
flag pipeline:
- Adds the typed flag shape: `{ enabled: boolean; minimumVersion: string
}`
- Defaults malformed or missing config to `{ enabled: false,
minimumVersion: '' }`
- Parses the flag through the Predict schema/resolver flow
- Applies existing version-gated feature flag validation
- Exposes `selectPredictPortfolioEnabledFlag`
- Covers default, enabled, disabled, malformed, progressive rollout, and
minimum-version behavior in unit tests
This PR does not gate UI or routes yet. It only adds the flag
infrastructure needed for the portfolio module and positions screen to
consume later.
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes:
[PRED-898](https://consensyssoftware.atlassian.net/browse/PRED-898)
## **Manual testing steps**
```gherkin
Feature: Predict portfolio remote feature flag
Scenario: portfolio flag is absent or disabled
Given the Predict remote config does not include predictPortfolio
When the Predict feature flags are resolved
Then selectPredictPortfolioEnabledFlag returns false
Scenario: portfolio flag is enabled for the current app version
Given the Predict remote config includes predictPortfolio enabled with a passing minimumVersion
When the Predict feature flags are resolved
Then selectPredictPortfolioEnabledFlag returns true
Scenario: portfolio flag config is malformed
Given the Predict remote config includes malformed predictPortfolio values
When the Predict feature flags are resolved
Then selectPredictPortfolioEnabledFlag returns false
```
## **Screenshots/Recordings**
N/A. This is feature flag plumbing only and has no user-visible UI
changes.
### **Before**
N/A
### **After**
N/A
## **Pre-merge author checklist**
- [ ] 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).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] 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**
- [ ] 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.
## Test plan
```bash
node .yarn/releases/yarn-4.14.1.cjs jest app/components/UI/Predict/schemas/flags.test.ts app/components/UI/Predict/utils/resolvePredictFeatureFlags.test.ts app/components/UI/Predict/selectors/featureFlags/index.test.ts
```
Result: 3 test suites passed, 139 tests passed.
[PRED-898]:
https://consensyssoftware.atlassian.net/browse/PRED-898?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Flag-only plumbing with conservative false defaults; no user-facing
routes or trading behavior changes in this diff.
>
> **Overview**
> Adds **Predict portfolio** remote feature flag plumbing so later work
can gate portfolio UI and routes without changing this PR.
>
> The remote key `predictPortfolio` is resolved through the existing
version-gated boolean path in `resolvePredictFeatureFlags`, surfaced on
`PredictFeatureFlags` as `predictPortfolioEnabled`, and exposed via
`selectPredictPortfolioEnabledFlag`. Defaults stay **off** when the flag
is missing, invalid, below `minimumVersion`, or not version-gated
(including empty `minimumVersion`). Unit tests cover resolver and
selector behavior (enabled/disabled, malformed config, progressive
rollout unwrap).
>
> **No navigation or UI is gated yet**—only flag infrastructure and
tests.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8081140. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…on, and Spending Limit (#30571) <!-- 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** Polishes the Money Account integration across the Card surface so that money-account funding sources are identified, labeled, and managed consistently from Card Home through Spending Limit. What changed: - **`CardFundingToken.isMoneyAccountEntry` flag** baked at the selector layer (`selectCardPrimaryToken`, `selectCardFundingTokens`, `selectCardAvailableTokens`, `selectCardLineaUsdcToken`) via a pure `isMoneyAccountEntry(walletAddress, moneyAccounts)` predicate. All consumers now read one boolean instead of recomputing the comparison; future Veda-vault detection becomes a one-line change in the predicate. - **Card Home** — SVG hex address on the card art is replaced with the localized `"Money account"` label when `primaryToken.isMoneyAccountEntry` is true; `truncateAddress` no longer mangles non-hex input. - **Add Funds** — when the primary funding source is a money account, the button stays enabled and routes to the existing `MoneyAddMoneySheet` (`Routes.MONEY.MODALS.ADD_MONEY_SHEET`) instead of going through swap / deposit checks. - **Asset Selection sheet** — per-row hex address is substituted with the money-account label whenever the row's token is a money-account entry (covers both the primary-source case and other rows). - **Spending Limit** introduces a fourth `flow` value `'enable_card'` (Card Home "Enable Card" CTA) so the screen can behave like onboarding for token + Money-Account logic without triggering onboarding-only chrome (hidden back button, replace-style routing). Entry-point flow labels were also corrected: `manageSpendingLimitAction` → `'manage'`, the `AssetSelectionBottomSheet` NotEnabled tap → `'enable'`. - **Spending Limit lock semantics** — new `isMoneyAccountLocked` boolean decouples the locked state from `isMoneyAccountSource`. Lock fires only on the manage flow when `priorityToken.isMoneyAccountEntry` is true (regardless of balance). Onboarding-like flows still preselect Money Account when funded but rows remain pressable; switching the account via the picker now surfaces a Spend-and-Earn CTA. - **Money Account delegation re-submit** — `useMoneyAccountCardLinkage` exposes a new `canSubmitMoneyAccountDelegation` predicate that does not include `!isAlreadyDelegated`. `confirmLinkInBackground` now uses it, so Manage Limit can update the cap (or revoke by submitting `'0'`) on an already-delegated money-account token. `canLink` continues to gate the first-time link CTA. - **Render-tree cleanup** — Account and Token rows on the Spending Limit screen are now dedicated subcomponents (`AccountRow`, `TokenRow` under `Views/SpendingLimit/components/`), removing ~180 lines of inline IIFE JSX from the parent and stripping 12 unused imports. Chevron is shown when the row is actionable: account row when not locked; token row only when not locked AND not money-account-sourced. Reason for the change: Money Account is being introduced as an EOA-style funding source for the Card. Without these polishes, the user would see raw hex addresses, be unable to update the delegation cap after the initial link, and get inconsistent flow gating between Card Home entry points. ## **Changelog** CHANGELOG entry: Improved the Card experience for Money Account users — Card Home and Asset Selection now display "Money account" instead of the raw address, Add Funds routes to the Money Account add-funds sheet, and Manage Limit can update or revoke the delegation cap on an already-linked Money Account. ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: Money Account on Card Scenario: Card Home renders the Money Account label Given the user has a Money Account as primary funding source When they open Card Home Then the card art shows "Money account" instead of the raw hex address And no raw hex address appears in any Card Home surface Scenario: Add Funds routes to the Money Account sheet Given the user has a Money Account as primary funding source When they tap "Add funds" on Card Home Then the Money Account add-funds bottom sheet opens And the standard swap/deposit flow is not triggered Scenario: Asset Selection labels money-account rows Given the user has at least one money-account token in their funding list When they open the Asset Selection bottom sheet Then each money-account row shows "Money account" in place of the hex address Scenario: Manage Limit locks rows when the primary token is a Money Account Given the user has a Money Account as primary funding source When they tap "Manage limit" Then both the Account and Token rows are locked (non-pressable, no chevron) And the Spend-and-Earn CTA is not shown Scenario: Manage Limit updates the delegation cap on an already-delegated Money Account Given the user has previously linked their Money Account to the Card When they open Manage Limit, change the limit (or set it to 0 to revoke), and confirm Then the controller re-runs linkMoneyAccountCard with the new delegation amount And the success toast is shown Scenario: Enable Card from Card Home shows the Money Account CTA Given the user has funds in their Money Account And they have a Card but no delegation yet When they tap "Enable Card" on Card Home Then Money Account is preselected as the source And the back button is visible And switching to another account via the picker reveals the "Spend & Earn" CTA Scenario: Enabling a NotEnabled token from Asset Selection shows the Money Account CTA Given the user has funds in their Money Account When they tap a NotEnabled token in the Asset Selection sheet Then Spending Limit opens with that token preselected And the "Spend & Earn" CTA is visible And tapping it switches the source to Money Account ``` ## **Screenshots/Recordings** ### **Before** N/A ### **After** N/A ## **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 is ambiguous, a checked 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. <!-- Generated with the help of the pr-description AI skill --> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes card funding navigation, delegation submit paths, and spending-limit flow gating across several user-facing entry points; well-covered by tests but touches money-account linkage behavior. > > **Overview** > This PR unifies **Money Account** as a Card funding source end-to-end: selectors set **`isMoneyAccountEntry`** on funding tokens (via `isMoneyAccountEntry(walletAddress, moneyAccounts)`), and Card surfaces use that flag instead of re-deriving wallet matches. > > **Card Home & funding actions:** The card art shows the localized **Money account** label instead of hex when the primary token is a money-account entry; **`truncateAddress`** leaves non-hex labels intact. **Add funds** stays enabled without swaps and opens **`MoneyAddMoneySheet`**. **Enable card** navigates to Spending Limit with **`flow: 'enable_card'`**; **Manage spending limit** uses **`flow: 'manage'`** (tests/views aligned). > > **Spending Limit:** New **`enable_card`** flow separates “enable card from home” from onboarding/manage. **`isMoneyAccountLocked`** locks account/token rows only on **manage** when the priority token is a money-account entry; onboarding-like flows keep rows pressable and adjust Money Account CTA / balance-loading rules. Account/token UI moves into **`AccountRow`** / **`TokenRow`**. > > **Delegation:** **`canSubmitMoneyAccountDelegation`** allows **`confirmLinkInBackground`** when already delegated so users can update cap or revoke (`'0'`). > > **Asset selection:** NotEnabled tokens open Spending Limit with **`flow: 'enable'`**; rows show the money-account label instead of truncated hex when applicable. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 9e2c14f. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description**
Removes the unused temporary CustomSpendCap component from
`app/component-library/components-temp/CustomSpendCap`.
This also removes its nested CustomInput helper, which was only used by
CustomSpendCap. A reference search confirms there are no remaining app,
test, or Storybook references.
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: temporary component cleanup
Scenario: CustomSpendCap temp component is removed
Given the repository is on this branch
When searching for CustomSpendCap and CustomInput references
Then no app, test, or Storybook references are found
```
## **Screenshots/Recordings**
N/A. Code cleanup only.
### **Before**
N/A
### **After**
N/A
## **Validation**
- `rg -n
"CustomSpendCap|CustomInput|CUSTOM_SPEND_CAP|CUSTOM_INPUT|components-temp/CustomSpendCap"
app tests .storybook --glob '!node_modules/**'` returned no matches.
## **Pre-merge author checklist**
- [ ] 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
- [ ] 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
- [ ] I've tested with a power user scenario
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
## **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.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Low risk cleanup that removes an unused temporary component and its
tests/styles; functional behavior should be unchanged as there are no
remaining references.
>
> **Overview**
> Removes the unused temporary `CustomSpendCap` component under
`app/component-library/components-temp/CustomSpendCap`, including its
nested `CustomInput` helper, constants, styles, types, index exports,
and associated tests.
>
> Updates `docs/bigint-migration-guide.md` to drop the now-removed
`CustomSpendCap` entries from the team ownership/burndown list.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
11caeab. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: George Marshall <georgewrmarshall@users.noreply.github.com>
Co-authored-by: George Marshall <george.marshall@consensys.net>
## **Description** On the Tokens full view, opening the Sort bottom sheet silently reset the user's sort preference back to "Declining balance" — even when no row was tapped. The reset originated from a `useFocusEffect` cleanup, which fires on **blur** (e.g. when a modal opens on top) rather than only on unmount. Switched to `useEffect` with an unmount-only cleanup so the reset still fires when the user leaves the full view back to the wallet, but does not fire when the screen merely blurs behind the sort sheet. ## **Changelog** CHANGELOG entry: Fixed a bug where the Tokens full view sort preference would silently reset to "Declining balance" when opening the Sort bottom sheet. ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TMCU-813 ## **Manual testing steps** ```gherkin Feature: Token sort preference persists across opening the Sort bottom sheet Scenario: User selects Alphabetical, then re-opens the Sort sheet Given the user is on the Tokens full view And tokens are currently sorted by "Declining balance ($ high-low)" When the user taps the sort icon And the user taps "Alphabetically (A–Z)" Then the sheet dismisses And tokens are sorted alphabetically A–Z When the user taps the sort icon again Then the Sort bottom sheet shows "Alphabetically (A–Z)" as selected And tokens behind the sheet remain in alphabetical order When the user dismisses the sheet without tapping any row Then tokens remain in alphabetical order Scenario: Sort resets when leaving the full view Given the user is on the Tokens full view with sort set to "Alphabetically" When the user taps back (or swipes back) to the wallet And re-enters the Tokens full view Then the sort is reset to the default "Declining balance" ``` ## **Screenshots/Recordings** https://github.com/user-attachments/assets/6afc8d00-0626-41bc-9c7a-b3d749e93177 ### **Before** Uploading before-sort.mov… ### **After** https://github.com/user-attachments/assets/6afc8d00-0626-41bc-9c7a-b3d749e93177 ## **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 is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] 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] > **Low Risk** > Small lifecycle fix in one screen; behavior is more correct and limited to token sort preferences when a feature flag is on. > > **Overview** > Fixes token sort resetting when the Sort bottom sheet opens on **Tokens full view**. > > **`TokensFullView`** previously used **`useFocusEffect`** cleanup to restore **`DEFAULT_TOKEN_SORT_CONFIG`** when homepage sections v1 is enabled. That cleanup runs on **blur** (e.g. modal/sheet on top), so opening the sort sheet wiped the user's choice without a tap. > > The reset now runs only on **unmount** via **`useEffect`** cleanup, so sort persists while the sheet is open and still resets when leaving the full view back to the wallet. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 2051fd5. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description**
Fixes the Activity tab underline getting stuck on the wrong tab after
changing the network filter, when conditional tabs (e.g. Perps) are
added or removed.
<details>
<summary>Detailed explanation (root cause and fix)</summary>
### Root cause
The underline position is driven by measurements captured in
`tabLayouts.current` and updated by `onLayout` callbacks in `TabsBar`.
When the set of tabs changes (for example, Perps becomes
enabled/disabled after a network filter change), `TabsBar` was resetting
`tabLayouts.current` with `new Array(tabs.length)`. This produces a
**sparse array**.
`TabsBar` then used `Array.prototype.every(...)` to determine that all
tab layouts were available. On sparse arrays, `every(...)` **skips
holes**, so the check could incorrectly return `true` even when only a
subset of tab layouts had actually been measured.
That caused `layoutsReady` to become `true` prematurely and allowed
`animateToTab(...)` to run against incomplete layout data. In the common
failure case, the underline would animate to the last-measured tab and
then refuse to move when the user switched back to a tab whose layout
entry was still missing, leaving the underline stuck on the wrong tab.
### Fix
This PR makes the layout readiness checks robust and ensures we
re-measure after structural tab changes:
1. **Use dense arrays for layout resets**
- Replace `new Array(n)` with `Array.from({ length: n }, () =>
undefined)` so the array has no holes.
2. **Make "all measured" checks strict**
- Introduce `areAllTabLayoutsMeasured(...)`, which requires
`layouts.length === tabCount` and that every slot is defined with a
positive width.
3. **Force re-measurement when tabs change**
- Add a `layoutGeneration` value that is incremented on structural tab
changes and included in the `Tab` key so React remounts each `Tab` and
reliably re-fires `onLayout` after add/remove.
4. **Recover underline position as soon as the active tab is measured**
- After storing a layout, if the active tab has a valid layout we
schedule `animateToTab(activeIdx)` via `requestAnimationFrame`, so the
underline updates promptly even while other tabs are still measuring.
### What changed in practice
- After a tab add/remove, the underline will only be considered ready
once measurements exist for the relevant tab(s).
- The active tab's underline can re-position as soon as that tab's
layout is available, preventing the underline from vanishing or sticking
during transitions.
</details>
## **Changelog**
CHANGELOG entry: Fixed a bug where the Activity tab underline could get
stuck on the wrong tab after changing networks.
## **Related issues**
Fixes: #30365
Relates-to: https://consensyssoftware.atlassian.net/browse/TMCU-755
## **Manual testing steps**
```gherkin
Feature: Activity tab underline stays in sync when tabs change
Scenario: underline remains aligned after network filter changes tab set
Given the user is on the Activity screen with multiple tabs visible (e.g. Transactions, Transfers, Perps, Predictions)
And the tab underline is visible under the active tab
When the user changes the network filter so a conditional tab is removed (e.g. Perps)
Then the underline stays aligned with the currently selected tab
When the user changes the network filter so the conditional tab is added back
And the user switches between Transactions, Transfers, Perps, and Predictions
Then the underline follows the active tab and does not get stuck on a different tab
```
## **Screenshots/Recordings**
### **Before**
Tab underline could remain under the wrong tab (e.g. Predictions) while
Transactions content was shown, after changing the network filter.
### **After**
Tab underline stays aligned with the active tab when conditional tabs
are added or removed.
https://github.com/user-attachments/assets/5f320905-6daa-451d-8db8-379ff7621a28
## **Pre-merge author checklist**
- [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 — existing `TabsBar` unit tests
pass (55/55); no new tests required for layout measurement edge case
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable — N/A (inline helpers are self-explanatory)
- [ ] 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
- [ ] I've tested with a power user scenario
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
## **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.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Localized TabsBar layout/animation logic with no auth, data, or API
impact; behavior change is limited to tab underline positioning and
scroll detection timing.
>
> **Overview**
> Fixes the **TabsBar** animated underline staying on the wrong tab when
the tab list changes (e.g. conditional Activity tabs appearing after a
network filter change).
>
> Layout state now uses **dense** arrays (`Array.from` + `undefined`
slots) and a strict **`areAllTabLayoutsMeasured`** helper so
sparse-array holes cannot make readiness checks pass early. On
structural tab changes, **`layoutGeneration`** is bumped and included in
each **`Tab`** `key` to remount tabs and re-fire **`onLayout`**,
replacing the old container-width reset trick.
>
> **`handleTabLayout`** repositions the underline via
**`requestAnimationFrame`** as soon as the **active** tab has valid
measurements, and **`activeIndex`** animation only runs when all layouts
are truly measured.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
cb4c130. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description** Replaces the bar chart stepper asset (`mm_how_it_works.png`) used in the "How it works" section on the Money home with the updated illustration from the design spec. Reference: [Figma — Update the how it works image on home](https://www.figma.com/design/XKZ8hRqSn2iTiuzmlQLuYQ/Money-account?node-id=8391-20692&m=dev) ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: [MUSD-842](https://consensyssoftware.atlassian.net/browse/MUSD-842) ## **Manual testing steps** ```gherkin Feature: Updated "How it works" illustration on Money home Scenario: user opens the Money home Given the user has the Money account feature enabled When the user navigates to the Money home screen Then the "How it works" section displays the updated bar chart stepper illustration ``` ## **Screenshots/Recordings** ### **Before** ### **After** <img width="1206" height="2622" alt="image" src="https://github.com/user-attachments/assets/d913cf78-0705-49d0-9515-ba4916935480" /> ## **Pre-merge author checklist** - [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 - [ ] I've tested with a power user scenario - [ ] I've instrumented key operations with Sentry traces for production performance metrics ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] 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. [MUSD-842]: https://consensyssoftware.atlassian.net/browse/MUSD-842?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Visual-only PNG replacement with no logic, navigation, or API changes. > > **Overview** > Swaps the **`mm_how_it_works.png`** illustration for the design-spec bar chart stepper. **No app code or import paths change**—existing references in **`MoneyCondensedInfoCards`** (and its tests) keep the same filename, so the **How it works** condensed card on Money home shows the new artwork automatically. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit b37bfcb. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Migrates the MultichainAccounts temporary component internals away from deprecated component-library imports and onto `@metamask/design-system-react-native` equivalents. This updates account rows, external account rows, account selector list pieces, address rows, checkboxes, search fields, text, icons, sensitive text, and avatar usage. It also adds a small avatar variant compatibility helper so legacy persisted selector values such as `Maskicon`, `JazzIcon`, and `Blockies` continue to map to the DS `AvatarAccountVariant` API. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/MUL-1693 ## **Manual testing steps** ```gherkin Feature: Multichain account component DS migration Scenario: account selector and address rows preserve existing behavior Given a wallet with multichain account groups and network addresses When the account selector and multichain address list are opened Then account rows, external account rows, network avatars, checkboxes, copy actions, and search fields render and behave as before ``` ## **Screenshots/Recordings** https://github.com/user-attachments/assets/153a7587-0b2f-4398-b894-d768577452dc ## **Pre-merge author checklist** - [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 - [ ] 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** - [ ] 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** > Medium risk because it replaces core account-selector UI primitives (avatars, text, search, checkbox, toast wiring) with Design System components, which could cause subtle rendering/interaction regressions across account selection flows. > > **Overview** > Migrates the temporary MultichainAccounts UI components (`AccountCell`, selector list cells/headers, external account rows, address rows, and address rows list) from deprecated component-library primitives to `@metamask/design-system-react-native` equivalents (text, icons, sensitive text, avatars, search, checkbox). > > Introduces `avatarAccountVariant` compatibility helpers to map legacy persisted avatar type strings (`Maskicon`/`JazzIcon`/`Blockies`) to DS `AvatarAccountVariant`, and updates tests to assert DS components/testIDs (including new checkbox icon and network avatar test IDs) and to use timer-safe `act`/fake-timer handling for copy/toast feedback. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 9a035d1. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- 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** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> Part **2 of 2** for [MUL-1689](https://consensyssoftware.atlassian.net/browse/MUL-1689). **Base branch:** `gar/refactor/mul-1689/part-1` (merge part 1 first, or rebase this branch onto `main` after part 1 lands and retarget to `main`). Migrates the Account Details **shell** and related tests from `app/component-library` to `@metamask/design-system-react-native`: - `BaseAccountDetails/index.tsx` — design-system `HeaderBase` (`titleTestID` for title queries), `startButtonIconProps` for back, `AvatarAccount` with mapping from settings `AvatarAccountType` to `AvatarAccountVariant`, `Text` / `Icon` with semantic tokens. - `BaseAccountDetails/styles.ts` — remove obsolete text color style now covered by `TextColor`. - `SmartAccountModal.tsx` — design-system `HeaderBase`, `Text`, nested learn-more `Text` with `TextColor.InfoDefault`. - Tests — narrower `AvatarAccountType` import path; `HardwareAccountDetails` header title assertion uses the same `header-title` test id as design-system `HeaderBase`. Depends on part 1 for a consistent Account Details tree. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Refs: https://consensyssoftware.atlassian.net/browse/MUL-1689 ## **Manual testing steps** ```gherkin Feature: Multichain Account Details (shell and modal, part 2) Scenario: Account details header and back navigation Given the user opened Multichain Account Details from the accounts flow When the header shows the account name Then the back control returns to the previous screen without layout regressions Scenario: Smart Account modal from account details Given an EVM account with Smart Account entry available When the user opens the Smart Account modal Then the modal title and description render and Learn more opens the webview flow as before ``` ## **Screenshots/Recordings** <img width="300" alt="Simulator Screenshot - iPhone 16 - 2026-05-19 at 17 19 07" src="https://github.com/user-attachments/assets/fb332055-a10a-4d22-abf4-661c26499c11" /> <img width="300" alt="Simulator Screenshot - iPhone 16 - 2026-05-19 at 17 20 09" src="https://github.com/user-attachments/assets/592473e8-871f-48c6-ab95-a18c52276257" /> ## **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) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] 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 - [x] 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 is ambiguous, a checked 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. [MUL-1689]: https://consensyssoftware.atlassian.net/browse/MUL-1689?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > UI-only component swap with preserved navigation, test IDs, and avatar mapping; no auth or credential logic changes in this diff. > > **Overview** > Migrates the multichain **Account Details** shell (`BaseAccountDetails`) and **Smart Account** modal from `app/component-library` to `@metamask/design-system-react-native`, keeping behavior and test IDs aligned with the previous UI. > > **`BaseAccountDetails`** now uses design-system `HeaderBase` with `titleTestID` `header-title` and `startButtonIconProps` for back (replacing `ButtonLink` + `Icon`), `AvatarAccount` with a `toAvatarAccountVariant` bridge from settings `AvatarAccountType`, and `Text` / `Icon` with `TextVariant`, `FontWeight`, `TextColor`, and `IconColor` instead of theme-driven styles. Row styling drops the local `text` color rule in favor of tokens. > > **`SmartAccountModal`** follows the same header pattern and updates body copy to design-system `Text`, including learn-more styling via `TextColor.InfoDefault`. > > Related unit tests import `AvatarAccountType` from the narrower path and assert the header title via `header-title` where the legacy `HEADERBASE_TITLE_TEST_ID` constant was removed. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 92afdd3. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
## **Description**
Adds address poisoning detection to the send flow recipient screen. When
a user enters a recipient address, the app now checks whether the
address is similar to a known address from the user's address book or
transaction history.
When a poisoning match is detected:
- An error banner warns the user about the potential address poisoning
attack
- An expandable accordion lets the user compare the entered address
against the known safe address, with differing characters highlighted
for easy visual identification
- The paste-to-auto-review flow is blocked so the user must manually
acknowledge and proceed
## **Changelog**
CHANGELOG entry: Added address poisoning detection warning to the send
flow, alerting users when a recipient address is suspiciously similar to
a known address
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: Address poisoning detection in send flow
Scenario: User enters an address that looks similar to a known address
Given the user has previously transacted with address 0xABC...1234
And a poisoning address 0xABC...5674 exists (matching prefix/suffix)
When user enters the poisoning address as a recipient
Then an error banner displays "Address poisoning detected"
And the banner contains an expandable "Compare addresses" accordion
And expanding the accordion shows both addresses with differing characters highlighted
And the entered address shows diffs in red
And the known address shows diffs in green
Scenario: User pastes a poisoning address
Given the user has previously transacted with a known address
And a poisoning address exists for that known address
When user pastes the poisoning address into the recipient field
Then the auto-review flow is blocked
And the user sees the poisoning warning before proceeding
Scenario: User enters a safe address
Given the user enters a valid recipient address
And no similar known addresses are found
When the address validation completes
Then no poisoning warning is shown
And the Review button is enabled as usual
```
## **Screenshots/Recordings**
### **Before**
<!-- [screenshots/recordings] -->
### **After**
<img width="568" height="1084" alt="Screenshot 2026-03-10 at 5 07 36 PM"
src="https://github.com/user-attachments/assets/e9540d4f-c8f8-445c-86c0-3345e6e25941"
/>
<img width="568" height="1084" alt="Screenshot 2026-03-10 at 5 07 45 PM"
src="https://github.com/user-attachments/assets/c8fa3135-5ba8-49be-b7f1-a3c0d75b35ee"
/>
<img width="568" height="1084" alt="Screenshot 2026-03-10 at 11 29
35 PM"
src="https://github.com/user-attachments/assets/cb16aa73-4402-40ca-8a49-7fdebf2449c4"
/>
<img width="568" height="1084" alt="Screenshot 2026-03-10 at 11 29
52 PM"
src="https://github.com/user-attachments/assets/9b1c81c1-bfe5-4c77-81c7-33df7546fe3a"
/>
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
- [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.
## **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.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Touches recipient selection and confirmation UX for fund transfers and
Engine controller init order; alerts are non-blocking but wrong
detection could annoy users or miss attacks.
>
> **Overview**
> Adds **address poisoning detection** across send and transaction
confirmation using `PhishingController.checkAddressPoisoning`, backed by
`@metamask/phishing-controller` **^17.2.0** and
**address-book-controller** **^7.1.2**.
>
> On the **send recipient** screen, a validated recipient is checked for
lookalike addresses; matches show an error banner with a **Compare
addresses** accordion (`DiffHighlightedAddress` highlights diffs in red
vs. green). **Paste-to-auto-review** is skipped when a poisoning match
exists so users must proceed manually.
>
> **Transfer confirmation** surfaces the same risk via
`useAddressPoisoningAlert` (non-blocking danger alert with compare UI),
**From/To** row styling (error text + “Poisoned” badge), and alert
metrics. **Engine** initializes `AddressBookController` before
`PhishingController`, extends the phishing messenger for address book
state, and tests hydration of known recipients from persisted address
book.
>
> Minor: full-screen confirm scroll content uses `flexGrow` instead of
`flex`; new i18n strings for poisoning and compare labels.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
165233f. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
….79.0 (#29755) ## **Description** Play Store–shaped Android issues (merged `prodRelease` manifest / AAB structure) are easy to miss until late in release. This PR runs **non-blocking** checks on the **same AAB** produced by `build.yml` after the Android Gradle release step, instead of a separate CI job on every PR. **What changed:** - After `main` Android **Release** builds (not Debug / e2e), run `:app:lintProdRelease` and **bundletool validate** on the existing `prodRelease` AAB via `scripts/android-play-store-check-slack.mjs` (always exits 0; failures are collected, not job-fatal). - For **`main-rc`** builds, upload `android-play-store-check-slack.md` and surface failures in the **Slack RC notification** (`slack-rc-notification.yml` + `slack-rc-notification.mjs`). - Add a reusable composite action (`.github/actions/android-play-store-manifest-check`) for standalone/manual validation; add `lint-baseline.xml` and CI Gradle tweaks so lint can run in GHA. RC builds keep shipping; release owners get lint/bundletool issues in Slack when checks fail. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/MCRM-73 https://consensyssoftware.atlassian.net/browse/MCWP-478 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <img width="737" height="575" alt="image" src="https://github.com/user-attachments/assets/864b6672-f355-4715-bce4-6ecc5ecc5c03" /> ### **After** <img width="743" height="742" alt="image" src="https://github.com/user-attachments/assets/64ef5ef3-3d97-4f52-98af-bdc27a9388ea" /> ## **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. --> - [ ] 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). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] 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 is ambiguous, a checked 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. --------- Co-authored-by: Cursor <cursoragent@cursor.com>
https://consensyssoftware.atlassian.net/browse/WAPI-1386 <!-- 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** Currently when a MM Connect deeplink is used once, it cannot be used again even if the connection failed to establish for some reason unless the app is restarted. This PR changes it so that a deeplink can be reused but only if a connection has not already successfully been established with it. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Improves MM Connect deeplink handling ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **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. --> - [ ] 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). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] 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 is ambiguous, a checked 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** > Touches connection-establishment control flow and capacity eviction ordering; mistakes could lead to skipped connections or unexpected evictions, though changes are localized and covered by new tests. > > **Overview** > **Enables sequential reuse of MM Connect (MWP) deeplinks after failures** by clearing the in-flight deeplink guard (`deeplinks`) in a `finally` block, so the same URL can be retried without restarting the app. > > Adds a duplicate-connection safeguard in `handleConnectDeeplink` to **skip creating a new connection when a connection with the same session `id` already exists**, and updates tests to cover sequential duplicate handling and retry-after-failure behavior. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 3e1f731. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description**
The APY for the `dev-monad` vault for the money account is zero, but we
don't show it, making UAT and design reviews harder
## **Changelog**
CHANGELOG entry: show even zero APY values on money home
## **Related issues**
Fixes: N/A
## **Manual testing steps**
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
## **Screenshots/Recordings**
### **Before**
<img width="735" height="1600" alt="image"
src="https://github.com/user-attachments/assets/17df48b0-435e-4d8f-b24e-b41be37db0f2"
/>
### **After**
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
- [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 is ambiguous, a checked 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]
> **Low Risk**
> Small Money UI visibility change with tests; no auth, payments, or
data-layer changes.
>
> **Overview**
> Money home now **shows APY when the rate is 0%**, not only when it is
strictly positive. **`MoneyBalanceSummary`**, **`MoneyHowItWorks`**, and
**`MoneyWhatYouGet`** switch from `isPositiveNumber` to a new
**`isPositiveNumberOrZero`** guard so the label, info button, and inline
copy render for zero APY while **undefined** and **negative** values
stay hidden.
>
> Unit tests are updated to expect visible **0% APY** UI and
**`number.test.ts`** covers the new helper.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
009b809. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
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.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )