Skip to content

[pull] main from MetaMask:main#306

Merged
pull[bot] merged 9 commits into
Reality2byte:mainfrom
MetaMask:main
Nov 7, 2025
Merged

[pull] main from MetaMask:main#306
pull[bot] merged 9 commits into
Reality2byte:mainfrom
MetaMask:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Nov 7, 2025

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

wachunei and others added 9 commits November 7, 2025 12:14
<!--
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 pull request enhances the flexibility of the `ListItemSelect`
component by allowing custom props to be passed directly to its nested
`ListItem` component. This makes it easier to customize accessibility
and other properties when using `ListItemSelect`.

**Component extensibility improvements:**

* Added a new optional `listItemProps` prop to the `ListItemSelectProps`
interface, allowing consumers to pass custom props to the nested
`ListItem` component.
* Updated the `ListItemSelect` component implementation to spread
`listItemProps` onto the nested `ListItem` element.
[[1]](diffhunk://#diff-b1ce9235b1fa82fff3758d3a8cefedb7decb33dd7445bf3411fb53925c9b06baR25)
[[2]](diffhunk://#diff-b1ce9235b1fa82fff3758d3a8cefedb7decb33dd7445bf3411fb53925c9b06baL37-R38)

**Testing enhancements:**

* Added a test to verify that custom `listItemProps` are correctly
passed through to the nested `ListItem`, ensuring that properties like
`accessibilityHint` are set as expected.

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

## **Manual testing steps**

N/A

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

- [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]
> Adds `listItemProps` to `ListItemSelect` to forward props to its
nested `ListItem`, with a test verifying passthrough (e.g.,
accessibility hints).
> 
> - **Component Library**
>   - **`ListItemSelect`**:
> - Adds optional `listItemProps` to `ListItemSelectProps` and spreads
onto nested `ListItem` in `ListItemSelect.tsx`.
>   - **Tests**:
> - Adds test ensuring `listItemProps` (e.g., `accessibilityHint`,
`testID`) are passed through to the nested `ListItem`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
5e7b8bf. 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**
Re-order migrations 105, 106, 107

Removal of migration 104 redux-persist slicing. No longer needed

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

- [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]
> Reorders and repurposes migrations (104–106), removes 107, updates
inflation/deflation thresholds, and aligns tests with the new behaviors.
> 
> - **Migrations**:
> - **104**: Simplified to only reset `PhishingController.urlScanCache`;
adds error reporting for invalid state.
> - **105**: Now removes `RatesController` from
`engine.backgroundState`; no-ops if absent; standardized error handling.
> - **106**: Now cleans PPOM MMKV storage (`PPOMDB`); logic moved from
former `107`; returns unchanged state; error captured.
>   - **Removed**: `107` migration and its tests.
> - **Index** (`migrations/index.ts`): Dropped `107` from
`migrationList`; changed inflate trigger to `> 106` and deflate on last
version `>= 106`.
> - **Tests**:
> - Updated/added tests for 104–106 reflecting new responsibilities and
error messages.
> - Adjusted async migration flow tests to new version thresholds;
removed old 107 tests; renamed for concision.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
a52e123. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Aslau Mario-Daniel <marioaslau@gmail.com>
## **Description**

- Account group rows in settings view
  show tracked/total supported addresses labels
  show the appropriate CTA icon depending on tracked addresses

- Account group modal spawnable via settings view
  show unsupported header/addresses
  remove unsupported account type banner/alert
  aways show headers (tracked/untracked/unsupported)

## **Changelog**

CHANGELOG entry: show tracked/untracked in reward settings view

## **Related Issue**

https://consensyssoftware.atlassian.net/browse/RWDS-769

## **Screenshots/Recordings**

<img width="920" height="1486" alt="image"
src="https://github.com/user-attachments/assets/9187c873-f5d0-4d16-b2ce-c5b8351b5977"
/>

<img width="984" height="1724" alt="image"
src="https://github.com/user-attachments/assets/96bb17ea-77d7-478d-b7be-bd6d6fe23eea"
/>

## **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]
> Adds tracked/total labels to account group rows, always shows
tracked/untracked/unsupported sections in the opt-in modal, refines
address processing and button logic, and updates tests/i18n accordingly.
> 
> - **Rewards Settings UI**:
> - Show tracked/total label via
`strings('rewards.link_account_group.tracked_count')` in
`RewardSettingsAccountGroup`.
> - Contextual CTA icon (`check` when all tracked, `add` otherwise);
disable link when no opted-out accounts.
>   - Minor layout tweaks; remove balance/Privacy Mode logic.
> - **Opt-in Modal (`RewardOptInAccountGroupModal`)**:
> - Refactor address flattening with wildcard/invalid-scope handling;
treat `isSupported: undefined` as supported and filter EVM testnets.
> - Always render section headers: `tracked`, `untracked`, and new
`unsupported`; remove unsupported banner.
> - Link button shows only when supported, untracked addresses exist;
`onClose` triggers `navigation.goBack`.
> - Update item testIDs to `flat-list-item-<address>-<scope>` and use
`MultichainAddressRow` fields.
> - **Account Group List**:
> - Optimize `allAddresses` via `getAddressesForGroup`; provide
`getItemType` to `FlashList`; header spacing tweaks; stable skeleton
keys.
> - **i18n**:
> - Add `rewards.link_account_group.unsupported` and
`rewards.link_account_group.tracked_count`.
> - **Tests**:
> - Large test updates to reflect new testIDs, sections, button states,
loading, key extraction, item typing, and edge cases (wildcards, invalid
scopes, missing data).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
ff4d9e9. 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 PR fixes the issue when the user selects a BTC network, it would
switch the user to the first multichain account.

<!--
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: Changing networks to btc does not switch the selected
account.

## **Related issues**

Fixes:
#22236 (comment)

## **Manual testing steps**

```gherkin
Feature: network switching

  Scenario: user wants to change the network filter
    Given the user is using a multichain account

    When user selected the btc network
    Then the account does not change.
```

## **Screenshots/Recordings**

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

### **Before**

<!-- [screenshots/recordings] -->

### **After**



https://github.com/user-attachments/assets/ee43b688-8f64-4d16-bde9-b7efecef6cfe



<!-- [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]
> Stops auto-switching to a BTC account when toggling a popular BTC
network; BTC address selection now only occurs during custom BTC network
selection.
> 
> - **Hooks (`useNetworkSelection.ts`)**:
> - Remove Bitcoin-specific `Engine.setSelectedAddress` logic from
`selectPopularNetwork`; keep BTC address handling only in
`selectCustomNetwork`.
> - Simplify `selectPopularNetwork` dependencies to exclude Bitcoin
internals.
> - **Tests (`useNetworkSelection.test.ts`)**:
> - Delete test asserting BTC address is set on `selectPopularNetwork`
for Bitcoin networks.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b4746e4. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…unding fees and live data (#22229)

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

Fixes bug where close position view showed incorrect receive amounts,
sometimes displaying negative values when position value had dropped.

Root causes:
1. Used stale position data from route params instead of live WebSocket
updates
2. HyperLiquid's marginUsed already includes PnL, but code was
double-counting
3. Recalculated PnL from prices, which missed accumulated funding fees
4. Timing mismatch between price updates and position updates

Changes:
- Add usePerpsLivePositions to subscribe to real-time position data
- Use livePosition.marginUsed which already includes accumulated PnL and
funding fees
- Use livePosition.positionValue for fee calculations to keep margin and
fees synchronized
- Remove effectivePnL recalculation that missed funding fees
- Round margin and fees separately before subtraction for transparent
calculation
- Update tests to reflect that marginUsed includes PnL from HyperLiquid

Result:
- Position card and close position view now show matching margin values
- Funding fees correctly included in all calculations
- No more incorrect negative receive amounts
- Calculation transparency: displayed margin - displayed fees =
displayed receive amount

<!--
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/TAT-1956    

## **Manual testing steps**

```gherkin
Feature: Close Position Calculation with Funding Fees

  Scenario: Close position with accumulated funding fees shows correct receive amount
    Given I have an open position with the following details:
      | Coin          | ETH    |
      | Margin Used   | $100   |
      | Unrealized PnL| -$5    |
      | Entry Price   | $2000  |
      | Current Price | $2000  |
    When I navigate to the close position view
    And I view the close position summary
    Then the margin displayed should be "$100"
    And the receive amount should match "margin - fees"
    And the receive amount should be positive
    And the receive amount should not be negative or zero

  Scenario: Receive amount calculation matches visual breakdown
    Given I have an open position
    When I view the close position summary
    Then the displayed margin should be rounded to 2 decimals
    And the displayed fees should be rounded to 2 decimals
    And the receive amount should equal "rounded margin minus rounded fees"
    And the calculation should be transparent to the user
```

## **Screenshots/Recordings**

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

### **Before**

<!-- [screenshots/recordings] -->

### **After**


https://github.com/user-attachments/assets/29289663-7b77-45f7-8ff6-c48917e1e21a

<!-- [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]
> Close Position view now uses live position data (incl. funding fees)
and computes receive amount as rounded margin minus rounded fees, with
updated PnL/effective price logic and tests.
> 
> - **Perps Close Position (UI)**:
> - Subscribe to `usePerpsLivePositions` and derive `isLong`, `absSize`,
`marginUsed`, and `unrealizedPnl` from live data.
> - Rework P&L logic: `effectivePnL` uses live `pnl` for `market`
orders; for `limit`, uses `limitPrice` (fallback `currentPrice`).
> - Compute `positionValue` and `closingValue` with current/limit price
in deps; remove ref-based price shortcuts.
> - Recalculate `receiveAmount` as `(close% of marginUsed) - fees` with
per-component rounding; update `Summary` `totalMargin` to `(close% of
marginUsed)`.
> - Pass `livePosition` to `handleClosePosition`; include updated
`receivedAmount` and `realizedPnl` in params.
> - Derive `unrealizedPnlPercent` by back-calculating initial margin
from `marginUsed - pnl`.
> - **Tests**:
> - Mock `usePerpsLivePositions` and update expectations: receive =
`marginUsed - fees`; PnL display uses live `unrealizedPnl`.
> - Add price update sync test ensuring P&L/margin react to live
price/position changes.
> - Adjust confirmation assertions (e.g., `receivedAmount: 1405`) and
various limit/market calculation cases.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
5c3d3be. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: abretonc7s <107169956+abretonc7s@users.noreply.github.com>
## **Description**

Users were reporting that the TabsBar component in the Wallet view was
not horizontally scrollable when tabs overflowed, particularly when
device font size settings were increased.

**Root causes identified:**

1. **Overflow detection didn't account for container padding** - The
component has `px-4` (32px total) padding, but the overflow calculation
compared total content width against the full container width, not the
available space minus padding.

2. **Underline positioning race condition** - With font scaling, layout
measurements would race with font rendering, causing the underline to
have inconsistent width/position on initial load.

3. **No dynamic recalculation** - When font size changed after initial
load, the overflow detection would not recalculate, leaving tabs
non-scrollable even when they overflowed.

**Solution:**

- Fixed overflow detection to account for container's 32px horizontal
padding in both calculation points
- Added layout change detection to re-animate underline when tabs resize
due to font scaling
- Implemented dynamic recalculation of scroll state when any tab's
layout changes significantly (>1px)
- Used refs to avoid circular dependencies and performance issues

## **Changelog**

CHANGELOG entry: Fixed TabsBar not being horizontally scrollable when
tabs overflow, especially with increased font size settings

## **Related issues**

Fixes: 

## **Manual testing steps**

```gherkin
Feature: TabsBar horizontal scrolling with increased font size

  Scenario: user increases device font size with many tabs
    Given user has multiple tabs visible in the Wallet view (Tokens, Perps, Predictions, NFTs)
    And tabs fit within the screen width at default font size

    When user increases device font size in Settings > Display & Brightness > Text Size
    Then tabs should become horizontally scrollable
    And the underline indicator should correctly match the width of active tab
    And user should be able to swipe horizontally to see all tabs

  Scenario: user views tabs with default font size
    Given user has multiple tabs in the Wallet view
    And device font size is at default setting
    And tabs do not overflow the screen width

    When user views the Wallet screen
    Then tabs should not be scrollable
    And all tabs should be visible without scrolling
    And the underline should correctly align with active tab

  Scenario: user switches between tabs after font size increase
    Given user has increased device font size
    And tabs are horizontally scrollable due to overflow

    When user taps on a different tab or swipes to navigate
    Then the underline should animate smoothly to the new tab
    And the ScrollView should automatically scroll to show the active tab
    And the underline width should match the tab width accurately
```

## **Screenshots/Recordings**

### **Before**

https://github.com/user-attachments/assets/3359232b-c54a-4d6b-9124-c6e194de7fc1

### **After**

https://github.com/user-attachments/assets/b83a5cc9-9232-4fb1-bbde-3e73d6c75332

## **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]
> Improves TabsBar by accounting for container padding in overflow
detection and re-animating the underline when tab layouts change (e.g.,
font scaling).
> 
> - **TabsBar
(`app/component-library/components-temp/Tabs/TabsBar/TabsBar.tsx`)**
> - **Overflow detection**: Accounts for container padding (`-32px`)
when computing `shouldScroll`.
>   - **Dynamic layout handling**:
> - Detects significant tab layout changes (>1px) and recalculates
scroll state.
> - Re-animates active tab underline via `requestAnimationFrame`; added
`activeIndexRef` to sync with `activeIndex`.
> - **Stability/cleanup**: Cancels in-flight animations and pending RAF
callbacks on updates/unmount.
>   - **Deps**: Updates effect/callback deps to include `animateToTab`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
f60d961. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…22291)

## **Description**

Fixed Toast component theme not updating when switching between light
and dark mode in production builds (TestFlight). The issue only affected
production builds while working correctly in development/simulator.

### Root Cause:
The Toast component had an empty dependency array `[]` in its `useMemo`
hook (line 69), which cached the initial theme styles and never updated
when the theme changed. This was a remnant from when Toast used
inverse/hardcoded theming.

### Solution:
Updated the `useMemo` dependency array to properly track `[styles.base,
animatedStyle]`, ensuring the component re-renders with correct theme
colors when theme changes occur.

## **Changelog**

CHANGELOG entry: Fixed Toast component not updating theme colors when
switching between light and dark mode

## **Related issues**

Fixes: Theme change issue in Toast component

## **Manual testing steps**

```gherkin
Feature: Toast theme updates correctly

  Scenario: User switches device theme while Toast is visible
    Given the app is running with a visible Toast notification
    
    When user switches from light mode to dark mode (or vice versa) in device settings
    Then the Toast should update to match the new theme colors immediately
    
  Scenario: Toast appears with correct theme in production build
    Given the app is running in a TestFlight production build
    And user has dark mode enabled
    
    When a Toast notification appears
    Then the Toast displays with correct dark theme colors (not stuck in light theme)
```

## **Screenshots/Recordings**

### **Before**
Toast remained in previous theme colors when device theme was changed in
production builds.


https://github.com/user-attachments/assets/d96faa41-10c3-4777-baf0-cb33ec137309

### **After**
Toast correctly updates to match current theme in both development and
production builds.


https://github.com/user-attachments/assets/aea3a725-0aa1-4412-bd56-5bde79fbfbbd

## **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
- [ ] 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]
> Update `Toast` `baseStyle` `useMemo` to depend on `styles.base` and
`animatedStyle` (and simplify its type) so styling updates correctly.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
1a4dca6. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…in-app browser) (#22012)

## **Description**

Fixes: https://github.com/MetaMask/mobile-planning/issues/2341

This PR fixes an issue where MetaMask deeplinks clicked within the
in-app browser or carousel banners were redirecting users to the app
store instead of navigating internally within the app.

### Problem
When users clicked MetaMask deeplinks (e.g.,
`https://link.metamask.io/swap`, `metamask://dapp/uniswap.org`) from
within the app:
- **In-App Browser**: Links would attempt to open the app externally,
causing an app store redirect
- **Carousel Banners**: Action links would trigger OS-level handling
instead of internal navigation

This occurred because these URLs were being passed to the OS linking
system (`Linking.openURL()`), which would try to open MetaMask again,
resulting in an app store redirect since the app was already running.

### Solution
The fix intercepts MetaMask deeplinks and routes them through
`SharedDeeplinkManager` for internal handling:

1. **Created utility function** (`isInternalDeepLink`) to identify
MetaMask URLs that should be handled internally
2. **Updated BrowserTab** to intercept deeplinks in
`onShouldStartLoadWithRequest` and use `browserCallBack` for in-browser
navigation
3. **Updated Carousel** to differentiate between internal deeplinks and
external URLs
4. **Added comprehensive unit tests** covering all deeplink types and
edge cases

The `browserCallBack` mechanism allows deeplinks that should stay in the
browser (e.g., `dapp://` URLs) to navigate the current WebView tab,
while other deeplinks (e.g., `swap`, `buy-crypto`) navigate to their
respective app screens.

## **Changelog**

CHANGELOG entry: Improve handling of links originating from in-app
browser and carousel

## **Related issues**

Fixes: #[ISSUE_NUMBER]

## **Manual testing steps**

```gherkin
Feature: Internal deeplink handling in browser

  Scenario: user clicks MetaMask dapp deeplink in browser
    Given user has opened a website in the in-app browser
    And the website contains a link to "https://link.metamask.io/dapp/uniswap.org"
    
    When user taps the deeplink
    Then the current browser tab navigates to "https://uniswap.org"
    And the user remains in the browser (no app store redirect)

  Scenario: user clicks MetaMask feature deeplink in browser
    Given user has opened a website in the in-app browser
    And the website contains a link to "https://link.metamask.io/swap"
    
    When user taps the deeplink
    Then the app navigates to the Swap screen
    And the browser is exited

  Scenario: user clicks MetaMask deeplink in carousel
    Given user is viewing the wallet home screen
    And a carousel banner contains a MetaMask deeplink
    
    When user taps the carousel banner
    Then the app navigates to the appropriate feature screen
    And no app store redirect occurs

  Scenario: user clicks external link in browser
    Given user has opened a website in the in-app browser
    And the website contains a regular external link
    
    When user taps the external link
    Then the link behaves as normal (opens in browser or externally)

Feature: Deeplink type detection

  Scenario: utility correctly identifies internal deeplinks
    Given various URL types are tested
    
    When "https://link.metamask.io/swap" is checked
    Then it is identified as internal deeplink
    
    When "metamask://dapp/uniswap.org" is checked
    Then it is identified as internal deeplink
    
    When "https://google.com" is checked
    Then it is identified as external URL
```

### Additional Testing Steps:
1. **Browser Test Page**: Create an HTML page with test links covering:
   - Universal links: `https://link.metamask.io/dapp/uniswap.org`
   - Custom schemes: `metamask://dapp/app.aave.com`, `dapp://curve.fi`
- Feature links: `https://link.metamask.io/swap`, `/buy-crypto`, `/home`
   - External links: `https://ethereum.org` (control group)

2. **Unit Tests**: Run `yarn jest app/util/deeplinks/index.test.ts`

3. **TypeScript**: Run `yarn lint:tsc` to verify type safety

## **Screenshots/Recordings**

### **Before**
<!-- User clicks metamask deeplink in browser → App store opens (broken
behavior) -->

### **After**
<!-- User clicks metamask deeplink in browser → Navigates internally
(fixed behavior) -->

## **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
- [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]
> Intercept MetaMask deeplinks in the in-app browser and carousel to
handle them via SharedDeeplinkManager while opening only external URLs
with the OS; add isInternalDeepLink utility and tests.
> 
> - **Deeplink handling**:
> - Add `util/deeplinks/isInternalDeepLink` to detect MetaMask internal
links (universal and custom schemes).
> - In `BrowserTab`, intercept internal links in
`onShouldStartLoadWithRequest` and route via
`SharedDeeplinkManager.parse` with `origin:
AppConstants.DEEPLINKS.ORIGIN_IN_APP_BROWSER` and `browserCallBack`
support; block WebView load for these.
> - In `Carousel`, differentiate links: internal via
`SharedDeeplinkManager.parse` (`origin: ORIGIN_CAROUSEL`), external via
`Linking.openURL`.
> - Extend `AppConstants.DEEPLINKS` with `ORIGIN_CAROUSEL` and
`ORIGIN_IN_APP_BROWSER`.
> - **Tests**:
> - Add `app/util/deeplinks/index.test.ts` covering schemes/hosts and
edge cases.
> - Update `Carousel` tests to assert external vs internal link behavior
and correct origins; mock `Linking.openURL`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
924a4bc. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
….59.0 (#22288)

## **Description**

The back arrow in `PerpsHomeScreen` was using `navigation.goBack()`,
which would work correctly when navigating from Main wallet view → Perps
Home → Main wallet view

But when entering `PerpsHomeScreen` from another entry point, such as
PerpsOnboarding, it would create a loop when navigating from Perps
Tutorial → Perps Home (back arrow would return to tutorial)

This PR fixes this by changing this to `navigateToWallet` which
explicitly navigates to the wallet home screen as expected

## **Changelog**

CHANGELOG entry: Fix navigation loop from PerpsHomeScreen

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/TAT-1984

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

- [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]
> PerpsHomeView back arrow now always navigates to wallet home; tests
updated to assert wallet navigation.
> 
> - **UI/Perps**:
> - `PerpsHomeView.tsx`: Change back handler from `navigateBack` to
`navigateToWallet` to avoid navigation loops; keep search navigation via
`navigateToMarketList`.
> - **Tests**:
> - `PerpsHomeView.test.tsx`: Update mocks and expectations to use
`navigateToWallet` for back action; clear relevant mocks; retain
existing behavior checks for sections and actions.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
3695aa8. 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 Nov 7, 2025
@pull pull Bot added the ⤵️ pull label Nov 7, 2025
@pull pull Bot merged commit e30bced into Reality2byte:main Nov 7, 2025
0 of 6 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.

9 participants