Skip to content

[pull] main from MetaMask:main#496

Merged
pull[bot] merged 11 commits into
Reality2byte:mainfrom
MetaMask:main
Feb 4, 2026
Merged

[pull] main from MetaMask:main#496
pull[bot] merged 11 commits into
Reality2byte:mainfrom
MetaMask:main

Conversation

@pull

@pull pull Bot commented Feb 4, 2026

Copy link
Copy Markdown

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 : )

vinnyhoward and others added 11 commits February 3, 2026 17:46
## **Description**

This PR addresses multiple UI revision requests for the "Scan your
hardware wallet to connect" screen in the Add wallet flow. Mirrored
design with `ShareAddressQR`

1. Centered the reader
2. Added white transparent background
3. Moved hint text above the box
4. Updated copy
5. Fixed white clipping issue at the top and bottom of modal

## **Changelog**

CHANGELOG entry: Fixed hardware wallet scan screen layout with centered
reader, blurred edges, and improved text positioning

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/MDP-680

## **Manual testing steps**

```gherkin
Feature: Scan hardware wallet screen
 
  Scenario: user views the scan hardware wallet screen
    Given the user is on the Add wallet flow
 
    When user navigates to the QR-based hardware wallet scan screen
    Then the scanning frame should be centered on the screen
    And the edges around the frame should have a blurred/gradient effect
    And the text "Scan your hardware wallet" should appear above the frame
    And the "Scanning..." text should appear below the frame
```

## **Screenshots/Recordings**

| before | after |
| -------- | ------- |
|
![before](https://github.com/user-attachments/assets/ed18b487-cc79-425e-b0d0-4afd3f24c7d5)
|
![after](https://github.com/user-attachments/assets/e66cb627-38cc-4649-8bee-6302ce0564a7)
|

### **Before**

`~`

### **After**

`~`

## **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**

- [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]
> **Medium Risk**
> Primarily UI/layout changes to the QR scanning modal, but it also
refactors error analytics emission and adjusts modal/window positioning
which could affect scanner usability on different devices.
> 
> **Overview**
> Refines the QR-based hardware wallet scanner modal to match the app’s
other QR scanner UI: adds a full-screen overlay with centered frame,
moves the hint text above the frame, and shows scanning progress below.
> 
> Updates modal presentation (`coverScreen`, `statusBarTranslucent`),
revises camera/no-permission layouts, and tweaks styles/positioning
(absolute layout, overlay shading, close button placement). Also
centralizes hardware-wallet error analytics into a reusable
`sendErrorAnalytics` helper and updates English copy keys from
`hint_text`/`purpose_*` to `hint_text_pair` and `hint_text_sign`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
dfff06f. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…5545)

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**
Moves the "Earn %" CTA for Ethereum and Tron to be next to the asset
name. This fix is needed because large token balances are causing the
"Earn %" CTA to clip into the percentage changed text.
<!--
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?
-->

## **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: moved the "Earn %" CTA for Ethereum and Tron to be next
to the asset name

## **Related issues**

Fixes: [MUSD-279: Move the Earn CTAs next to ETH and Tron contextually
next to the asset
name's](https://consensyssoftware.atlassian.net/browse/MUSD-279)

## **Manual testing steps**

```gherkin
Feature: Earn call-to-action placement in token list

  Scenario: user sees stake call-to-action next to token name
    When user views ETH and the token in the token list
    When user has non-zero token balance
    Then a Stake call-to-action is displayed inline next to the token name
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->
Earn CTA collides with the percentage changed text for large token
balances.
### **After**

<!-- [screenshots/recordings] -->
<img width="454" height="81" alt="Screenshot 2026-02-02 at 3 50 50 PM"
src="https://github.com/user-attachments/assets/21a1671f-2d66-4017-bc2b-1c78fcfd4e02"
/>
<img width="454" height="81" alt="Screenshot 2026-02-02 at 3 51 07 PM"
src="https://github.com/user-attachments/assets/690691a3-ebf9-43ea-a8a8-5f298c66c3bd"
/>

## **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]
> **Low Risk**
> Low risk UI-only layout change in `TokenListItem` that repositions the
Earn/Stake CTA; main risk is minor alignment/regression across different
token name lengths and badges.
> 
> **Overview**
> Moves the token list item Earn/Stake CTA (via `renderEarnCta()`) from
the secondary balance row to sit inline next to the asset name/label,
preventing it from colliding with large balance/percentage-change text.
> 
> Adds an `assetNameContainer` row wrapper style to align the name/label
and CTA horizontally.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9de9bcc. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **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?
-->

This PR updates the `useAnalytics` hook type definitions to support the
types for the `createEventBuilder` method.

## **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/MCWP-317
(additional change)

## **Manual testing steps**

N/A

## **Screenshots/Recordings**

N/A

### **Before**

N/A

### **After**

N/A

## **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]
> **Low Risk**
> Type-only change that broadens `createEventBuilder`’s input union; low
runtime risk but may affect TypeScript compile expectations where this
hook is consumed.
> 
> **Overview**
> Updates `useAnalytics` hook typings so `createEventBuilder` accepts
additional analytics event types (`IMetaMetricsEvent` and
`ITrackingEvent`) alongside `string`/`AnalyticsTrackingEvent`, improving
type compatibility for callers.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
73287df. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

This is a simple PR that updates the @metamask/storage-service to 1.0.0.
No breaking changes, we are just updating the version to 1 as it is
going to be used in prod.

CHANGELOG entry: null

<!--
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?
-->

## **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:

## **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**

- [ ] 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.

## **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 dependency bump with no code changes, but it could introduce
runtime regressions if `@metamask/storage-service` behavior changed
between 0.0.1 and 1.0.0.
> 
> **Overview**
> Updates the `@metamask/storage-service` dependency from `^0.0.1` to
`^1.0.0` and refreshes `yarn.lock` to resolve the new package version
(including its updated transitive dependency on `@metamask/utils`).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
e9f26f6. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **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?
-->

Several E2E tests are still using the
`remoteFeatureMultichainAccountsAccountDetailsV2` util to mock the
remote feature flag value. This PR removes the usage of this method with
the value `true` since this is already the default behaviour covered by
the default fixture.

## **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: null

## **Manual testing steps**

Not applicable

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

Not applicable

## **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.

## **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**
> Test-only changes remove explicit enabling of
`enableMultichainAccountsState2`; risk is low but could cause E2E flakes
if the default feature-flag behavior changes in the test harness.
> 
> **Overview**
> Removes explicit mocking of the
`remoteFeatureMultichainAccountsAccountDetailsV2(true)` remote feature
flag across multiple multichain E2E/regression specs, relying on the
default-enabled behavior instead.
> 
> Cleans up related imports and `testSpecificMock` blocks (including the
multichain provider snap test and multichain asset-list regression),
simplifying fixture setup while preserving the existing test flows.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
63da2a2. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…25603)

## **Description**

convert promise chains to async/await in AnimatedQRScanner

## **Changelog**

CHANGELOG entry:null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/MDP-680

## **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**

`~`

### **After**

`~`

## **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**

- [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**
> Low risk refactor limited to error-analytics plumbing; behavior should
be equivalent but could affect when/if analytics fire if the async
keyring lookup throws differently.
> 
> **Overview**
> Refactors `AnimatedQRScanner` error analytics to replace
`.then/.catch` promise chaining with `async/await` and a `try/catch`
around the QR keyring device-name lookup.
> 
> Analytics events for `MetaMetricsEvents.HARDWARE_WALLET_ERROR` are
still emitted with `device_model` set to the resolved keyring name, or
`'Unknown'` if lookup fails, with no functional changes outside this
error-reporting path.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8ed2614. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

This PR updates the Browser Tabs View to match the new design
specifications.

**Key changes:**

1. **Replaced bottom action bar with top navigation bar** - Removed the
old bottom bar (Close All / + / Done buttons) and added a new top
navigation bar with:
   - Back button (ArrowLeft icon) on the left
   - "Opened tabs" title centered
   - Add button (Add icon) on the right

2. **Updated back button behavior** - The back button now navigates to
the Explore page (TrendingView) when:
   - No tabs exist, OR
   - The active tab was closed

3. **Updated "+" button behavior** - Creates a new empty tab
(DiscoveryTab) and immediately dismisses the tabs view

4. **Converted tabs from list to 2-column grid layout** - Tabs are now
displayed in a more compact grid format with smaller thumbnails

5. **Removed Close All functionality** - This feature has been removed
from the UI

### Files Changed

| File | Changes |
|------|---------|
| `app/components/UI/Tabs/index.js` | Removed bottom bar, added top nav
bar, grid layout |
| `app/components/UI/Tabs/TabThumbnail/TabThumbnail.styles.ts` | Updated
dimensions for grid |
| `app/components/Views/Browser/index.js` | Enhanced closeTabsView
navigation logic |
| `app/components/Views/BrowserTab/BrowserView.testIds.ts` |
Added/deprecated test IDs |
| `app/components/UI/Tabs/index.test.tsx` | Updated tests and snapshots
|
| `locales/languages/en.json` | Added new localization strings |

## **Changelog**

CHANGELOG entry: Updated the Browser Tabs View with a new top navigation
bar, 2-column grid layout, and improved navigation behavior

## **Related issues**

Fixes:
**Jira Ticket:** https://consensyssoftware.atlassian.net/browse/MCWP-266

## **Manual testing steps**

```gherkin
Feature: Browser Tabs View

  Scenario: User opens tabs view and sees new UI
    Given user has multiple browser tabs open
    When user taps the tabs button to open tabs view
    Then user sees a top bar with back button, "Opened tabs" title, and add button
    And tabs are displayed in a 2-column grid layout

  Scenario: User creates a new tab from tabs view
    Given user is in the tabs view
    When user taps the add (+) button
    Then a new empty tab is created
    And the tabs view is dismissed
    And user is switched to the new tab

  Scenario: User navigates back with active tab
    Given user has browser tabs open
    And user is in the tabs view
    When user taps the back button
    Then the tabs view is dismissed
    And user returns to the active tab

  Scenario: User navigates back with no tabs
    Given user has no browser tabs open
    And user is in the tabs view
    When user taps the back button
    Then user is navigated to the Explore page

  Scenario: User navigates back after closing active tab
    Given user has closed the active tab in tabs view
    When user taps the back button
    Then user is navigated to the Explore page
```

## **Screenshots/Recordings**

### **Before**

<!-- Add screenshot of old tabs view with bottom bar -->

### **After**

<!-- Add screenshot of new tabs view with top bar and grid layout -->



https://github.com/user-attachments/assets/100407f6-9b8b-4dfc-b53e-b70a0ce9d65e



## **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**

- [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]
> **Medium Risk**
> Medium risk because it changes core tab-management UX (new-tab
creation return value, scroll positioning, and close-tabs navigation)
and removes the `closeAllTabs` flow, which could regress navigation or
tab state handling.
> 
> **Overview**
> Updates the Browser Tabs view UI to match new designs by replacing the
bottom action bar (*Close all / + / Done*) with a top bar containing
back/add icon buttons and an `Opened tabs` title.
> 
> Switches the tabs list to a 2-column grid with new sizing constants
(`Tabs.constants.ts`) and updated `TabThumbnail` dimensions/spacing,
including updated scroll-to-active-tab positioning for the grid.
> 
> Changes behavior so `newTab()` returns success/failure (used to keep
the tabs view open when the max-tabs modal is shown) and so closing the
tabs view navigates to Explore (`Routes.TRENDING_VIEW`) when there are
no tabs or the active tab no longer exists; removes `closeAllTabs`
plumbing across Browser/Tabs types and call sites.
> 
> Refreshes snapshots, expands unit coverage (including a large
`Browser.functions.test.tsx` suite), updates smoke tests, and adds new
i18n strings and test IDs (with deprecated IDs retained for
compatibility).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0276675. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
…eed (#25461)

Add a new "Hot" tab category for prediction markets that can be
dynamically configured via remote feature flags. The flag controls both
visibility and custom query parameters for filtering markets, enabling
backend-driven tab configuration without app updates.

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Summary
- Adds a new "Hot" tab to the Predict feed that is controlled by a
remote feature flag
- The Hot tab supports configurable query parameters passed directly to
the Polymarket API
- When enabled, the Hot tab appears as the first tab in the feed
 
 How It Works
1. **Remote Feature Flag**: The `predictHotTab` flag controls:
   - `enabled`: Whether the Hot tab is displayed
- `queryParams`: Raw query string passed to Polymarket API (e.g.,
`"&tag_id=149&order=volume24hr"`)
2. **API Behavior**: When Hot tab is active with custom query params:
   - Only `limit`, `offset`, and `customQueryParams` are sent to the API
- Default filters (active, archived, closed, liquidity_min, volume_min)
are bypassed
   - This allows full control of the API query via the feature flag
3. **Default State**: Flag is disabled by default with fallback query
params

<!--
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?
-->

## **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/PRED-539?atlOrigin=eyJpIjoiYTBiZTQ4MTY3NzlkNDE4YzgzMWRlZDJlN2EyMjNiNDAiLCJwIjoiaiJ9

## **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**

- [ ] 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.

## **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**
> Changes Predict feed navigation and market-fetching behavior by adding
a new `hot` category with remotely supplied raw query params that can
bypass default API filters, which could affect results and pagination if
misconfigured.
> 
> **Overview**
> Adds a new **remote feature-flagged “Hot” tab** to `PredictFeed`,
inserted as the first tab when `predictHotTab` is enabled (with version
gating and a default fallback), and wires its `queryParams` through to
market fetching.
> 
> Extends `usePredictMarketData`/provider params with
`customQueryParams` and updates the Polymarket API query builder to, for
the `hot` category only, optionally construct the request using just
`limit`/`offset` plus the provided raw query string (otherwise falling
back to the existing default filters). Includes locale text for “Hot”
and adds/updates unit tests covering selector validation, tab
rendering/analytics session start, hook refetching, and Polymarket URL
construction.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9f8c5cb. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

This PR adds a sticky Buy/Sell action bar to the Token Details page
(V2), allowing users to quickly swap into or out of the token they're
viewing.

To test this please make sure you have `isTokenDetailsRevampedEnabled`
return `true`

### Buy Button Logic

```
User taps Buy
    ├─ Has tokens on same chain? → Use highest USD value token → Open Swap
    ├─ Has tokens on any chain? → Use highest USD value token → Open Bridge/Swap
    └─ No eligible tokens? → Route to On-Ramp (buy crypto with cash)
```

- **Destination**: Always the current token being viewed
- **Source**: Smartly selected based on user's portfolio

### Sell Button Logic

```
User taps Sell
    ├─ Destination = getDefaultDestToken(chainId)
    │   ├─ Ethereum, Linea → mUSD
    │   ├─ Optimism, Arbitrum, Base, Avalanche, Sei, Monad → USDC
    │   └─ BSC, Polygon, zkSync → USDT
    │
    └─ If source === default dest (e.g., selling mUSD)?
        └─ Fallback to native token (ETH, BNB, etc.)
```

- **Source**: Always the current token being viewed
- **Destination**: Set as defined and will be handled automatically by
swap UI
- **Visibility**: Sell button only appears if user has balance > 0

## **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: Added Buy/Sell sticky action bar to Token Details page
with smart token selection

## **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] -->
<img width="376" height="773" alt="Screenshot 2026-02-02 at 10 56 02"
src="https://github.com/user-attachments/assets/d68a3f44-cd62-4f2d-9b88-87e343b043b7"
/>
<img width="385" height="772" alt="Screenshot 2026-02-02 at 10 56 37"
src="https://github.com/user-attachments/assets/e5301851-2320-4416-a515-175f18a3337e"
/>

## **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.

## **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**
> Adds new Token Details action UI and new swap/on-ramp routing logic
based on the user’s asset map, which could affect navigation into
swaps/bridge flows. Although gated behind a temporary flag (default
`false`), the address normalization change may impact asset lookup
behavior broadly if assumptions differ.
> 
> **Overview**
> **Token Details V2 now supports a feature-flagged sticky action
footer** (`BottomSheetFooter`) below the transactions view, padding for
safe-area insets. The footer always shows **Buy** and conditionally
shows **Sell** only when the viewed token has a positive balance.
> 
> **Action handling is extended in `useTokenActions`** with
`handleBuyPress`/`handleSellPress`: Buy selects a swap/bridge source
token by choosing the highest-fiat-balance asset (preferring same-chain,
else any chain; allows cross-chain native-token zero-address matching),
and falls back to on-ramp when no eligible assets exist; Sell opens
swaps with the current token as the source and leaves destination
undefined for the swap UI.
> 
> Separately, `useTokenBalance` now normalizes token addresses via
`toFormattedAddress` before `selectAsset` lookup, and new/updated tests
cover the footer visibility and the new action selection behavior.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b8cdb3e. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ode cleanup (#25237)

## **Description**

Replaces the static empty state with a featured markets experience and
adds A/B testing capability to experiment with different presentation
styles.

### **Core Changes**

**A/B Test Implementation:**
- Added `predictHomeFeaturedVariant` feature flag with version gating
support
- **Carousel variant** (default): Horizontal scrolling cards with market
details and price charts
- **List variant**: Vertical list using `PredictMarketRowItem` for a
more compact view
- `PredictHomeFeatured` component routes to the appropriate variant
based on feature flag

**New Component Architecture:**
- `PredictHomePositions`: Orchestrator that fetches positions and
decides what to render
- `PredictHomeFeatured`: Router component for A/B test variants
- `PredictHomeFeaturedCarousel`: Carousel variant (horizontal cards)
- `PredictHomeFeaturedList`: List variant (vertical row items)
- `PredictHomeFeaturedSkeleton`: Variant-aware loading skeleton
- `PredictHomeSkeleton`: Row-style skeleton matching position list
layout
- `PredictHomeAccountState`: Balance/claim card wrapper
- `PredictHomePositionList`: Active + claimable positions list

**Variant-Specific Analytics Entry Points:**
Each variant has its own entry point for measuring A/B test conversion
rates:

| Entry Point | Value | Used By |
|-------------|-------|---------|
| `HOMEPAGE_FEATURED_CAROUSEL` | `'homepage_featured_carousel'` |
Carousel variant |
| `HOMEPAGE_FEATURED_LIST` | `'homepage_featured_list'` | List variant |

This enables filtering analytics by `entry_point` to compare:
- Impressions per variant
- Click-through rates
- Trade conversion rates

**UX Improvements:**
- Balance card hidden when user has no positions (only shows with active
positions)
- Variant-specific loading skeletons match the actual content layout
- Fixed UI flash on account switch via stale data detection in
`usePredictPositions`

### **Dead Code Removal**

Removed unused components superseded by the new `PredictHome`
architecture:
- `PredictPositions/` directory (replaced by `PredictHomePositions`)
- `PredictPositionSkeleton/` directory (only used by `PredictPositions`)
- `PredictPositionEmpty/` directory (replaced by
`PredictHomeFeaturedCarousel`)

**Total: ~1,500 lines of dead code removed**

## **Changelog**

CHANGELOG entry: Added A/B test for homepage featured section (carousel
vs list) with variant-specific analytics; replaced empty predictions
state with featured markets; hide balance card when no positions exist;
removed dead code

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/PRED-552

## **Manual testing steps**

```gherkin
Feature: Predictions empty state shows featured markets with A/B test

  Scenario: user views positions tab with no active predictions (carousel variant)
    Given user has no active prediction positions
    And predictHomeFeaturedVariant flag is set to "carousel" (or not set)
    When user views the Positions section
    Then user sees a "Trending" header with an arrow
    And user sees a horizontal carousel of market cards
    And user does NOT see the balance/account state card
    And analytics events use entry_point: 'homepage_featured_carousel'

  Scenario: user views positions tab with no active predictions (list variant)
    Given user has no active prediction positions
    And predictHomeFeaturedVariant flag is set to "list"
    When user views the Positions section
    Then user sees a "Trending" header with an arrow
    And user sees a vertical list of market row items
    And user does NOT see the balance/account state card
    And analytics events use entry_point: 'homepage_featured_list'

  Scenario: loading skeleton matches variant
    Given user has no active prediction positions
    When positions are being refreshed
    Then loading skeleton style matches the configured variant
    (carousel shows horizontal card skeletons, list shows row skeletons)

  Scenario: user views positions tab with active predictions
    Given user has active prediction positions
    When user views the Positions section
    Then user sees the balance/account state card
    And user sees their active positions list

  Scenario: switching accounts shows loading state correctly
    Given user A has positions and user B has no positions
    When user switches from account A to account B
    Then user sees a skeleton loading state (no UI flash)
    Then user sees the featured section (empty state)
```

## **Feature Flag Configuration**

```typescript
// Remote feature flag structure
{
  predictHomeFeaturedVariant: {
    enabled: true,
    minimumVersion: "7.x.x",  // Version gating
    variant: "carousel" | "list"
  }
}
```

## **Analytics Query Example**

```sql
-- Compare A/B test variant performance
SELECT 
  entry_point,
  COUNT(*) as impressions,
  COUNT(CASE WHEN event = 'market_details_viewed' THEN 1 END) as market_views,
  COUNT(CASE WHEN event = 'predict_trade_initiated' THEN 1 END) as trades,
  ROUND(COUNT(CASE WHEN event = 'predict_trade_initiated' THEN 1 END) * 100.0 / 
        NULLIF(COUNT(CASE WHEN event = 'market_details_viewed' THEN 1 END), 0), 2) as conversion_rate
FROM predict_events
WHERE entry_point IN ('homepage_featured_carousel', 'homepage_featured_list')
GROUP BY entry_point
```

## **Screenshots/Recordings**

### **Before**

<!-- User will add screenshots -->

### **After**

<!-- User will add screenshots -->
https://www.loom.com/share/ab7bd7b9ac23480fb2f1a6b4ec461ce2

## **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**
> Moderate UI/UX refactor in the Predict tab that changes
loading/empty-state behavior and navigation/analytics entry points; risk
is mainly regressions in rendering, refresh, and tracking across account
switches.
> 
> **Overview**
> Replaces the old `PredictPositions`/empty-state flow with a new
`PredictHome`-based orchestration (`PredictHomePositions`) that decides
between **featured markets** (when no positions), **account state +
positions list** (when positions exist), and variant-aware **skeleton
states** during initial load/refresh.
> 
> Adds an A/B test for the featured section via a version-gated remote
flag `predictHomeFeaturedVariant`, routing between a `Section`-backed
carousel and a `usePredictMarketData`-backed list, and introduces new
analytics `entryPoint`s (`homepage_featured_carousel`,
`homepage_featured_list`).
> 
> Introduces `PredictEntryPointContext` and updates multiple market
card/row components to prefer a context-provided `entryPoint` over
props/defaults (while preserving Trending overrides), and hardens
`usePredictPositions` to avoid UI flashes on account switch by treating
previously-loaded data as stale and initializing `isLoading` based on
`loadOnMount`.
> 
> Cleans up dead code by deleting `PredictPositions`,
`PredictPositionEmpty`, and `PredictPositionSkeleton`, and updates
`PredictTabView` and tests to use the new `PredictHomePositions`
refresh/error surface.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
58f39b9. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

iOS source maps were not being uploaded to bitrise due to a bad path

<img width="1599" height="830" alt="Screenshot 2026-02-03 at 5 13 13 PM"
src="https://github.com/user-attachments/assets/44f82ea7-5ca8-4ff6-a43b-40fdf7de7981"
/>

`react-native-xcode.sh` cds into the the `PROJECT_ROOT` before creating
the source maps, so it was creating the source maps OUTSIDE of the repo.
Hence the odd file path we see in the screenshot.



## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: N/A

## **Manual testing steps**

1. Create a PR and check that the iOS source maps are uploaded to
bitrise.

## **Screenshots/Recordings**

N/A

## **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**

- [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**
> Low risk shell-script change that only affects where the iOS JS
sourcemap is written; main risk is CI/build pipeline expectations around
artifact paths.
> 
> **Overview**
> Fixes iOS sourcemap generation in CI by forcing React Native/Sentry
bundling to write the sourcemap to a **stable, repo-root-relative**
location.
> 
> `scripts/ios/bundle-js-and-sentry-upload.sh` now creates
`sourcemaps/ios/` and exports `SOURCEMAP_FILE` (default
`sourcemaps/ios/index.js.map`) so Bitrise can reliably collect and
deploy the artifact.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0c6f1db. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@pull pull Bot locked and limited conversation to collaborators Feb 4, 2026
@pull pull Bot added the ⤵️ pull label Feb 4, 2026
@pull pull Bot merged commit e922e16 into Reality2byte:main Feb 4, 2026
17 of 59 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants