Skip to content

[pull] main from MetaMask:main#319

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

[pull] main from MetaMask:main#319
pull[bot] merged 19 commits into
Reality2byte:mainfrom
MetaMask:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Nov 12, 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 : )

matthewwalsh0 and others added 19 commits November 12, 2025 11:35
## **Description**

Fix scrolling in the MetaMask Pay asset picker on Android.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:
[#6147](MetaMask/MetaMask-planning#6147)

## **Manual testing steps**

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

- [ ] 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]
> Switches asset picker and network filter to use
react-native-gesture-handler ScrollView to fix Android scrolling.
> 
> - **Mobile UI**:
> - Replace `react-native` `ScrollView` with
`react-native-gesture-handler` in
`app/components/Views/confirmations/components/network-filter/network-filter.tsx`
and
`app/components/Views/confirmations/components/send/asset/asset.tsx`.
>   - Minor `ScrollView` prop formatting cleanup in `asset.tsx`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
a7e0901. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Show additional details in Predict claim confirmation if single won
position.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: [6004](MetaMask/MetaMask-planning#6004)

## **Manual testing steps**

## **Screenshots/Recordings**

### **Before**

### **After**

<img width="300" alt="Claim Single"
src="https://github.com/user-attachments/assets/088c99d2-d3b7-4852-9009-357ad4ccd546"
/>

## **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]
> Enhances Predict claim footer to display detailed info for a single
win and refactors component structure with accompanying tests.
> 
> - **Predict claim footer** (`predict-claim-footer.tsx`):
> - Show single-win details: large token avatar, market title, formatted
fiat amount, and outcome.
> - Refactor into `SingleWin` and `MultipleWinnings` subcomponents;
memoize fiat formatting; return null when no won positions.
> - **Tests**:
> - Add tests for single-win extra info, avatar count (max 3), button
press, and fallback selected address.
> - Update mocks/render helper to support `singlePosition` and
`accountMock`.
> - Remove predict-claim footer render check from generic `Footer` tests
and drop unused `TransactionType` import.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8073f69. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…22517)

## **Description**

This PR fixes an issue in the Perps Market Tabs component where the
TabsList wasn't properly re-rendering when the number of visible tabs
changed.


## **Changelog**


CHANGELOG entry: Fixed an issue where perps market tabs would not update
correctly when the number of visible tabs changed

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: Perps Market Tabs Rendering

  Scenario: user switches between market states that affect tab visibility
    Given user is on the perps market details view with active position
    
    When user closes their position or opens new positions
    Then the tabs should correctly update to reflect the current state (position tab should appear/disappear)
    And the active tab selection should remain consistent
```

## **Screenshots/Recordings**

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


### **Before**

<!-- [screenshots/recordings] -->
No visible change

### **After**

<!-- [screenshots/recordings] -->
No visible change

## **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]
> Ensure `TabsList` remounts when the number of visible tabs changes by
incorporating `tabsToRender.length` into the component key.
> 
> - **Perps UI**:
> - **Tabs re-rendering**: Update `tabsKey` in `PerpsMarketTabs.tsx` to
`tabs-${tabs.length}-${tabsToRender.length}` so `TabsList` remounts when
the visible tab count changes.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
e03f2b2. 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?
-->

- Introduced PortManager to handle port allocation and release for
various servers.
- Updated Ganache, MockServerE2E, DappServer, CommandQueueServer,
FixtureServer, and AnvilManager to utilize PortManager for setting and
releasing ports.
- Added methods to set server ports and handle server status in
respective classes.
- Implemented retry logic for starting resources with automatic port
management to avoid conflicts.
- Updated FixtureUtils to include new port management functions and
ensure correct RPC URLs are used based on allocated ports.
- Update swaps tests to use Anvil (from ganache)

## **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
- [ ] 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 PortManager-driven dynamic port allocation with retries and
platform handling, refactors test servers/utilities to use it, migrates
swaps tests to Anvil, and standardizes “Network fee” casing.
> 
> - **E2E Infra (Port Management)**:
> - Introduces `PortManager` for dynamic/random port allocation
(single/multi-instance), release, and BrowserStack fallbacks; adds
robust retry start helpers (`startResourceWithRetry`,
`startMultiInstanceResourceWithRetry`).
> - Implements Android `adb reverse` mapping, iOS LaunchArgs, and
MockServer host-side fallback→actual port translation.
> - **Server/Utility Refactors**:
> - Update `Ganache`, `AnvilManager`, `FixtureServer`,
`CommandQueueServer`, `DappServer`, `MockServerE2E` to `setServerPort`,
track status, and release ports; `DappServer` supports multi-instance.
> - Revamps `FixtureUtils`/`FixtureHelper` APIs (`getDappUrl*`,
`get*PortForFixture`, RPC/Dapp URL rewrites) and improves
network-store/shim host resolution.
> - **Tests**:
>   - New comprehensive `PortManager.test.ts`.
> - Migrate swaps tests to Anvil; update fixtures and helpers to new
APIs; remove manual reverse logic.
> - **UX/Text**:
> - Standardize casing to `Network fee` across tests and
`locales/languages/en.json`.
> - **Misc**:
>   - Adjust allowlist/mocks; minor README formatting.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
f63e958. 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?
-->

## **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: fix error message when trying to import an SRP with an
account that is already imported via private key

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/MUL-491

## **Manual testing steps**

1. Import private key account
2. Import SRP that includes this private key account
3. Verify that the error message "The account you are trying to import
is a duplicate." is shown

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

<img width="925" height="903" alt="image"
src="https://github.com/user-attachments/assets/77abb409-feac-4ba4-92bd-387d122928dd"
/>

## **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 explicit handling and user-facing message when an SRP import
fails due to a duplicate account, with tests and i18n updates.
> 
> - **Import SRP View
(`app/components/Views/ImportNewSecretRecoveryPhrase/index.tsx`)**:
> - Refactor error handling to `switch` and add case for
`KeyringController - The account you are trying to import is a
duplicate`, showing `error_duplicate_account` alert.
> - **Tests
(`app/components/Views/ImportNewSecretRecoveryPhrase/index.test.tsx`)**:
> - Add test to assert duplicate account import error triggers the
correct alert.
> - **Localization (`locales/languages/en.json`)**:
> - Add `import_new_secret_recovery_phrase.error_duplicate_account`
copy.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
f43d802. 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**
As part of developing the "Trending" feature we needed to add a global
search that would allow searching amongst trending tokens, perps,
trending predictions...

I have developed a MODULAR search hook and global search that allows
searching across all existing sections and allows for easy integration
of new sections.

If a new section is added, the user will have to only modify the
configuration in `exploreSearchConfig` like this:
<img width="387" height="328" alt="image"
src="https://github.com/user-attachments/assets/e00ce4fb-3831-422e-80a3-30d2436cddad"
/>

and add the necessary hook inside `useExplorerSearch`:
<img width="416" height="449" alt="image"
src="https://github.com/user-attachments/assets/78366050-4ab8-4859-ad09-095077be89cf"
/>

Everything else is handled automatically which makes it **easy** for
developers to add new configurations

<!--
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: added new trending search functionality

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-1528 &
https://consensyssoftware.atlassian.net/browse/ASSETS-1527

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



https://github.com/user-attachments/assets/d912d5d0-4cd1-45c9-8a94-459d437f03aa



## **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]
> Introduces an Explore Search flow with a modular search hook, UI
components, navigation, i18n, and tests, enabling search across tokens,
perps, and predictions from the Trending tab.
> 
> - **Trending / Explore Search**:
>   - **UI**:
> - Add `ExploreSearchBar` and `ExploreSearchScreen` with
`ExploreSearchResults` list (headers, items, skeletons).
> - Integrate search entry in `TrendingView` (button + navigation), wrap
with `PerpsStreamProvider`.
>   - **Hook & Config**:
> - Add generic `useExploreSearch` (200ms debounce, top-3 on empty,
per-section filtering).
> - Define configurable sections in `exploreSearchConfig` for `tokens`,
`perps`, `predictions` with item renderers and key extractors.
>   - **Navigation**:
> - Add route `Routes.EXPLORE_SEARCH`; register in `TrendingView` stack;
update imports in `MainNavigator`.
>   - **i18n**:
> - Extend `trending` strings: `search_placeholder`, `perps`,
`predictions`, `no_results`.
>   - **Tests**:
> - Add tests for `ExploreSearchBar`, `ExploreSearchResults`,
`useExploreSearch`, and update `TrendingView` tests for search button
and navigation.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b35671b. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

### Summary

Adds Segment analytics tracking for QR Scanner usage to measure feature
adoption and understand user scanning patterns.

### Events Added

- **QR Scanner Opened** - Tracks when QR scanner is opened with camera
permission granted
- **QR Scanned** - Tracks all QR code scan attempts with
success/failure, type classification, and detailed scan results

### Properties

**QR Scanned** includes:
- `scan_success` (boolean) - Technical success: camera successfully read
the QR code
- `qr_type` (string) - Classification: `"seed phrase"` | `"private key"`
| `"send flow"` | `"wallet connect"` | `"deeplink"` | `"url"`
- `scan_result` (string) - Functional outcome: `"completed"` |
`"deeplink_handled"` | `"url_navigation_confirmed"` |
`"unrecognized_qr_code"` | `"invalid_address_format"` |
`"url_navigation_cancelled"` | `"wallet_locked"`

### Use Cases

- Measure scanner success rate (filter by `scan_result` to exclude
failures)
- Understand QR type distribution (`qr_type` breakdown)
- Debug scan failures (`scan_result` analysis)
- Improve UX by identifying common failure patterns
- Track WalletConnect connection initiation via QR codes

### Implementation Details

#### QR_SCANNER_OPENED
- Fires once per scanner session when permission is granted and camera
is available
- Includes global properties only 

#### QR_SCANNED

- Tracks all 6 QR code types with appropriate success/failure states:
- Seed Phrase 
- Private Key 
- Send Flow 
- Wallet Connect 
- Deeplink 
- URL 

Segment PR: Consensys/segment-schema#360

## **Changelog**

CHANGELOG entry:  Added segment events for QR scanning

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/TMCU-66

## **Manual testing steps**

```gherkin
Feature: QR Scanner Metrics Tracking

  Scenario: QR Scanner Opened event fires when scanner is accessed
    Given the user is on the MetaMask Mobile homepage
    And camera permissions are granted
    
    When user taps the QR scanner icon
    Then the QR scanner opens
    And "QR Scanner Opened" event is tracked with no custom properties
    And the event appears in console logs and Segment debugger

  Scenario: user scans a seed phrase QR code
    Given the QR scanner is open
    And a QR code containing a 12-word seed phrase is displayed
    
    When user scans the seed phrase QR code
    Then "QR Scanned" event is tracked
    And scan_success property is true
    And qr_type property is "seed phrase"

  Scenario: user scans a private key QR code
    Given the QR scanner is open
    And a QR code containing "0x" followed by 64 hex characters is displayed
    
    When user scans the private key QR code
    Then "QR Scanned" event is tracked
    And scan_success property is true
    And qr_type property is "private key"

  Scenario: user scans a valid Ethereum address in send flow
    Given the user is in the Send Flow screen
    And user taps the QR scanner icon
    And a QR code containing a valid Ethereum address is displayed
    
    When user scans the address QR code
    Then "QR Scanned" event is tracked
    And scan_success property is true
    And qr_type property is "send flow"

  Scenario: user scans an invalid address in send flow
    Given the user is in the Send Flow screen
    And user taps the QR scanner icon
    And a QR code containing invalid address text is displayed
    
    When user scans the invalid QR code
    Then "QR Scanned" event is tracked
    And scan_success property is false
    And qr_type property is "send flow"
    And an error alert is displayed

  Scenario: user scans a WalletConnect URI
    Given the QR scanner is open
    And a QR code containing a WalletConnect URI (wc:...) is displayed
    
    When user scans the WalletConnect QR code
    Then "QR Scanned" event is tracked
    And scan_success property is true
    And qr_type property is "wallet connect"

  Scenario: user scans a MetaMask deeplink
    Given the QR scanner is open
    And a QR code containing "metamask-sdk://" or "metamask-sync:" is displayed
    
    When user scans the deeplink QR code
    Then "QR Scanned" event is tracked
    And scan_success property is true
    And qr_type property is "deeplink"

  Scenario: user scans a URL and confirms navigation
    Given the QR scanner is open
    And a QR code containing "https://example.com" is displayed
    
    When user scans the URL QR code
    And user taps "Continue" on the confirmation dialog
    Then "QR Scanned" event is tracked
    And scan_success property is true
    And qr_type property is "url"

  Scenario: user scans a URL and cancels navigation
    Given the QR scanner is open
    And a QR code containing "https://example.com" is displayed
    
    When user scans the URL QR code
    And user taps "Cancel" on the confirmation dialog
    Then "QR Scanned" event is tracked
    And scan_success property is false
    And qr_type property is "url"
```

## **Screenshots/Recordings**

### Seed Phrase Flow


https://github.com/user-attachments/assets/6f8357c3-f1e4-467b-8c6a-9188a71948f4

### Private Key Flow


https://github.com/user-attachments/assets/1ce6f4cf-62e7-4bde-bce5-8d14bf9fba50

### Send Flow - Valid Address

__Send flow is currently broken there is a PR
[here](#21498) to fix
the issue. The video is just a demonstration of the event being
tracked__


https://github.com/user-attachments/assets/909d5687-9789-41b5-be45-4503a1bb0e53

### Send Flow - Unknown Address


https://github.com/user-attachments/assets/fd15c33c-e90a-4427-a7ed-684a741a075f

### Send Flow - Invalid Address


https://github.com/user-attachments/assets/34f27530-b1d6-4035-9713-19955c501090

### Wallet Connect


https://github.com/user-attachments/assets/b41f9fcc-a6a1-4440-9bba-63be4305ad4e

### SDK

### Website - Accept


https://github.com/user-attachments/assets/d7f00d09-a03a-4e6c-9056-99575ed2302d

### Website - Cancel


https://github.com/user-attachments/assets/2c3d9cff-36cd-475c-958e-e16034030e46

### **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]
> Adds MetaMetrics tracking for QR Scanner open/scan with standardized
properties and QR type detection, plus comprehensive tests and event
definitions.
> 
> - **Analytics**:
> - Add `QR_SCANNER_OPENED` and `QR_SCANNED` to
`core/Analytics/MetaMetrics.events.ts`.
>   - Track scanner open when permission granted and camera available.
> - Track scans with properties: `scan_success`, `qr_type`,
`scan_result` across types (`seed phrase`, `private key`, `send flow`,
`wallet connect`, `deeplink`, `url`), including outcomes (e.g., URL
confirm/cancel, wallet locked, invalid address, deeplink handled).
> - **QR Scanner**:
> - New `app/components/Views/QRScanner/constants.ts` for event keys, QR
types, and scan result values.
> - New `getQRType` in `app/components/Views/QRScanner/utils.ts` to
classify scanned content.
> - Update `app/components/Views/QRScanner/index.tsx` to emit events,
handle URL redirection flow, SDK/deeplink handling, and wallet-locked
checks; minor typing/refactors.
> - **Tests**:
>   - Expand `index.test.tsx` to validate event emission for all paths.
>   - Add `utils.test.ts` to verify `getQRType` classification logic.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
e419028. 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 enables live PnL (Profit and Loss) updates in the Perps Market
Tabs by subscribing to real-time price updates from the WebSocket
stream.

## **Changelog**

CHANGELOG entry: Fixed live PnL updates in Perps market tabs to reflect
real-time price changes

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: Live PnL updates in Perps Market Tabs

  Scenario: user views position with live PnL updates
    Given user has an open perpetual position
    And user is on the Perps Market Tabs screen
    
    When market price changes
    Then the unrealized PnL and ROE values update in real-time
    And the position card reflects current market conditions
```

## **Screenshots/Recordings**

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

### **Before**

No visible changes

### **After**

No visible changes

## **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]
> Enable live PnL updates by passing `useLivePnl: true` to
`usePerpsLivePositions` in `PerpsMarketTabs.tsx`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
32657d9. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Nicholas Smith <nick.smith@consensys.net>
<!--
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 introduces **AppStateAPI**, a new centralized API for monitoring
React Native app state changes (foreground/background/inactive) and
managing lock timers.

### **Reason for the change**

Currently, app state monitoring is scattered across the codebase with
direct React Native `AppState` imports in multiple components. This
creates tight coupling and makes it difficult to:
- Track which components are monitoring app state
- Test app state behavior consistently
- Manage lock timers in a centralized way
- Ensure proper cleanup of native listeners

### **The improvement/solution**

**AppStateAPI** provides a clean, singleton-based API with the following
benefits:

1. **Centralized Monitoring**: Single source of truth for app state
changes
2. **EventEmitter Pattern**: Components can subscribe to specific events
(`foreground`, `background`, `inactive`, `change`) without tight
coupling
3. **Separation of Concerns**: The API only monitors and emits events—it
does NOT perform locking. State machines/sagas handle actual locking
logic
4. **Lock Timer Management**: Built-in timer functionality for auto-lock
features with background timer support
5. **Clean Lifecycle**: Explicit `initialize()` and `cleanup()` methods
with proper native listener management
6. **Type Safety**: Full TypeScript implementation with exported types

### **Key Features**

- **App State Events**: `foreground`, `background`, `inactive`, `change`
- **Lock Timer**: `startLockTimer(duration, callback)`,
`clearLockTimer()`, `getLockTimerRemaining()`, `isLockTimerActive()`
- **State Queries**: `getCurrentAppState()`, `isAppInForeground()`,
`isAppInBackground()`, `isAppInactive()`
- **Lifecycle**: `initialize()`, `cleanup()`, `isInitialized()`

### **Architecture Summary**

| Component | Status | Lines | Purpose |

|------------------------|--------|-------|----------------------------------|
| AppStateAPI | ✅ New | 267 | Monitor app state & lock timers |
| Authentication.ts | ✅ Existing | 1230 | Keep using (works well) |
| State Machines (Sagas) | 🔄 Update | 234 | Will use AppStateAPI events
|
| LockManagerService | ⚠️ Deprecate | 122 | Gradually migrate away |

This PR includes debug instrumentation in `Root/index.tsx` for manual
testing (dev mode only).

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Refs: [Add issue number here]

## **Manual testing steps**

```gherkin
Feature: AppStateAPI monitors app state changes

  Scenario: Developer tests app state monitoring in development mode
    Given the app is running in development mode
    And AppStateAPI is initialized in Root component
    
    When the app is launched
    Then console logs should show "APPSTATEAPI: 🔵 Initializing AppStateAPI for manual testing"
    And console logs should show "APPSTATEAPI: 🔵 Starting 10-second lock timer"
    And console logs should display current app state as "active"

  Scenario: Developer backgrounds the app
    Given the app is running in foreground
    And AppStateAPI is initialized
    
    When the developer backgrounds the app
    Then console logs should show "APPSTATEAPI: 🔴 App BACKGROUNDED"
    And the background event should be emitted with state "background"

  Scenario: Developer foregrounds the app
    Given the app is running in background
    And AppStateAPI is initialized
    
    When the developer brings the app to foreground
    Then console logs should show "APPSTATEAPI: 🟢 App FOREGROUNDED"
    And the foreground event should be emitted with state "active"

  Scenario: Lock timer expires while app is backgrounded
    Given the app is running
    And a 10-second lock timer has been started
    
    When the developer backgrounds the app for more than 10 seconds
    Then console logs should show "APPSTATEAPI: ⏰ Lock timer EXPIRED"
    And the timer callback should be invoked

  Scenario: Developer checks AppStateAPI state queries
    Given the app is running
    And AppStateAPI is initialized
    
    When the developer views the console logs
    Then logs should show "Is in foreground?" with a boolean value
    And logs should show "Lock timer active?" with a boolean value
    And logs should show the current app state

  Scenario: AppStateAPI cleanup on unmount
    Given the app is running with AppStateAPI initialized
    
    When the Root component unmounts
    Then console logs should show "Cleaning up AppStateAPI"
    And all event listeners should be removed
    And lock timers should be cleared
```

## **Screenshots/Recordings**


https://github.com/user-attachments/assets/b9dfe51e-9ab9-45cc-802d-7f5fd9281c38

### **Before**

No centralized app state monitoring—components directly import
`AppState` from React Native.

### **After**

New `AppStateAPI` provides centralized monitoring with console output in
dev mode:

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Introduce a singleton AppState service that emits app state events and
manages a lock timer, with comprehensive tests and exports.
> 
> - **Core**:
> - **`app/core/AppStateService/AppStateService.ts`**: New singleton
`AppStateServiceImplementation` (EventEmitter-based) to monitor React
Native `AppState` and emit `foreground`, `background`, `inactive`, and
`change` events.
> - Provides lifecycle methods: `initialize()`, `cleanup()`,
`isInitialized()`.
> - Adds lock timer utilities: `startLockTimer()`, `clearLockTimer()`,
`getLockTimerRemaining()`, `isLockTimerActive()` using
`react-native-background-timer`.
>     - Exports singleton `AppStateService` and `AppStateStatus` type.
> - **Exports**:
> - **`app/core/AppStateService/index.ts`**: Re-exports service,
implementation, and types.
> - **Tests**:
> - **`app/core/AppStateService/AppStateService.test.ts`**:
Comprehensive unit tests mocking React Native and background timer to
verify initialization/cleanup, event emissions, lock timer behavior, and
state query helpers.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
574d3df. 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**
Current BUGBOT rules and are too verbose and don't consistently run in
the pipeline without manual intervention. This change updates the file
structure as per the Cursor docs and simplifies the rule.

1. Changes BUGBOT file location for more consistent ci running
2. Replaces verbose rules with simple rules and adds markdown links so
Cursor can read them.

<!--
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?
3. 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**
This test fork repo shows the rule now hits every Unit Test violation in
the Unit Testing Guidelines. Including

Test naming violations
AAA pattern violations
TypeScript type violations
Import/require violations
Test isolation violations
Assertion quality violations
Test complexity violations


https://github.com/michaelmccallam/metamask-mobileBugbotTest/pull/6/files

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

### **Before**
Didn't pick up on the rules consistently 

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

### **After**
Now picks up on each rule in the Unit Testing Guidelines and calls it
out in the comments.
<img width="730" height="441" alt="Screenshot 2025-11-08 at 09 50 23"
src="https://github.com/user-attachments/assets/ffd7a768-d012-49ae-92ec-e05a67266c5e"
/>


<!-- [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
- [ ] 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]
> Moves BUGBOT rules to `.cursor/BUGBOT.md` and streamlines content,
updating test file pattern and guideline link.
> 
> - **BUGBOT rules**:
> - **Relocation**: Move from `.cursor/rules/BUGBOT.md` to
`.cursor/BUGBOT.md`.
> - **Simplification**: Replace verbose rule set with concise core
mission and minimal execution protocol.
> - **Testing pattern**: Update naming pattern to
``*.test.{ts,tsx,js,jsx}``.
> - **Guidelines link**: Reference `rules/unit-testing-guidelines.mdc`
from new location.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
6949b1f. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
# Predict Buy: Rewards Display and Fee Consolidation

## Overview

This PR adds rewards point estimation and consolidates fee display in
the Predict Buy confirmation screen. Users can now see estimated
MetaMask Rewards points they'll earn from their transaction, and view
detailed fee breakdowns through an intuitive bottom sheet.

CHANGELOG entry: null


https://github.com/user-attachments/assets/cf20a4e3-1375-4f9b-97ff-c75a3d68f737

## Changes

### 🎁 Rewards Integration

- **Added "Est. points" row** to the Predict Buy confirmation screen
  - Displays estimated rewards points based on MetaMask fee
- **Calculation**: `Math.round(metamaskFee * 100)` (1 point per cent
spent on MM fee)
  - Position: Last row after "Total"
  - White text with gray info icon for consistency
  - Reuses `RewardsAnimations` component from Swap/Bridge features
- Conditional display based on `rewardsEnabled` feature flag and
transaction amount

### 💰 Fee Display Consolidation

- **Consolidated two fee rows into single "Fees" row**
  - Previously: Separate "Provider fee" and "MetaMask fee" rows
  - Now: Single "Fees" row showing sum of both fees
  - Added gray info icon that opens detailed breakdown

- **New Fee Breakdown Bottom Sheet** (`PredictFeeBreakdownSheet`)
  - Displays individual fee breakdown:
    - Polymarket fee (provider fee)
    - MetaMask fee
  - Opens when user taps info icon next to "Fees"
  - Closes without navigating back (uses `shouldNavigateBack={false}`)

### 🎨 UI/UX Improvements

- **Fee Summary Row Order**:
  1. Fees (consolidated, with info icon)
  2. Total
  3. Est. points (when rewards enabled)

- **Styling**:
  - Est. points text: White (`TextColor.Default`)
  - Info icons: Gray (`IconColor.Alternative`)
  - Consistent with design system

## Technical Details

### Files Modified

#### Components

- **`PredictBuyPreview.tsx`**
  - Import `selectRewardsEnabledFlag` selector
  - Calculate `estimatedPoints` from `metamaskFee`
  - Add `isFeeBreakdownVisible` state
  - Add `handleFeesInfoPress` and `handleFeeBreakdownClose` callbacks
  - Pass rewards props to `PredictFeeSummary`
  - Conditionally render `PredictFeeBreakdownSheet`

- **`PredictFeeSummary.tsx`**
  - Remove individual fee rows
  - Add consolidated "Fees" row with `ButtonIcon`
  - Calculate `totalFees = providerFee + metamaskFee`
  - Move rewards row to last position (after Total)
  - Update text colors (white for Est. points label)
  - Add `onFeesInfoPress` callback prop

#### New Files

- **`PredictFeeBreakdownSheet.tsx`**
  - Bottom sheet component for fee breakdown
  - Displays provider and MetaMask fees separately
  - Uses `shouldNavigateBack={false}` to prevent parent modal closure
  - Accepts `onClose` callback

- **`PredictFeeBreakdownSheet/index.ts`**
  - Export file for new component

#### Localization

- **`locales/languages/en.json`**
  ```json
  {
    "predict.fee_summary.fees": "Fees",
    "predict.fee_summary.provider_fee_label": "Polymarket fee",
    "predict.fee_summary.estimated_points": "Est. points",
    "predict.fee_summary.points_tooltip": "Points",
"predict.fee_summary.points_tooltip_content_1": "Points are how you earn
MetaMask Rewards for completing transactions, like when you swap,
bridge, or predict.",
"predict.fee_summary.points_tooltip_content_2": "Keep in mind this value
is an estimate and will be finalized once the transaction is complete.
Points can take up to 1 hour to be confirmed in your Rewards balance."
  }
  ```

### Tests

#### New Tests (22 total)

- **`PredictFeeSummary.test.tsx`** (12 tests)
  - Consolidated fees display and calculation
  - Fees info icon callback handling
  - Rewards row conditional rendering
  - Rewards row positioning
  - Edge cases (zero fees, missing callbacks)

- **`PredictFeeBreakdownSheet.test.tsx`** (10 tests - New file)
  - Bottom sheet rendering
  - Fee display (Polymarket and MetaMask)
  - `shouldNavigateBack` behavior
  - Close callback handling
  - Ref methods exposure

- **`PredictBuyPreview.test.tsx`** (10 new tests)
  - Rewards calculation formula
  - Rewards point rounding
  - Feature flag conditional display
  - Fee breakdown sheet visibility
  - Loading state propagation

#### Updated Tests (1)

- Fixed existing test to expect "Fees" instead of "Provider fee"

**Total Test Results**: 2,038 tests passing ✅

## Rewards Calculation Logic

```typescript
// Formula: 1 point per cent spent on MetaMask fee
const estimatedPoints = useMemo(
  () => Math.round(metamaskFee * 100),
  [metamaskFee],
);

// Display conditions
const shouldShowRewards = rewardsEnabled && currentValue > 0;
```

### Examples:
- MetaMask fee: $0.50 → **50 points**
- MetaMask fee: $1.23 → **123 points**
- MetaMask fee: $0.00 → **0 points**

## Component Reusability

This implementation reuses existing components:
- ✅ `RewardsAnimations` (from Bridge/Swap)
- ✅ `KeyValueRow` (component library)
- ✅ `ButtonIcon` (design system)
- ✅ `BottomSheet` (design system)
- ✅ Design system tokens (`TextColor`, `IconColor`)

## Feature Flags

- **Rewards display**: Controlled by `selectRewardsEnabledFlag`
- **Fee breakdown**: Always available

## Testing Checklist

- [x] Unit tests for all new components
- [x] Unit tests for modified components
- [x] All existing tests passing (2,038 tests)
- [x] No linter errors
- [x] Tests follow AAA pattern
- [x] Tests follow project guidelines (no "should" in names)
- [x] Edge cases covered (zero values, missing callbacks, etc.)

## Manual Testing

### Test Scenarios

1. **Rewards Display**
   - [ ] Verify Est. points row appears when rewards enabled
   - [ ] Verify points calculation: fee * 100 rounded
   - [ ] Verify Est. points row does NOT appear when rewards disabled
   - [ ] Verify Est. points row does NOT appear when amount is 0

2. **Fee Consolidation**
   - [ ] Verify single "Fees" row shows sum of provider + MetaMask fees
   - [ ] Verify info icon appears next to "Fees" label
   - [ ] Verify tapping info icon opens bottom sheet
   - [ ] Verify bottom sheet shows individual fee breakdown

3. **Bottom Sheet Behavior**
- [ ] Verify bottom sheet displays "Polymarket fee" and "MetaMask fee"
   - [ ] Verify closing bottom sheet does NOT close parent modal
   - [ ] Verify bottom sheet closes on swipe down
   - [ ] Verify bottom sheet closes on backdrop tap

4. **Visual/Styling**
   - [ ] Verify Est. points text is white
   - [ ] Verify all info icons are gray
   - [ ] Verify row order: Fees → Total → Est. points
   - [ ] Verify layout on different screen sizes

## Before/After

### Before
```
Provider fee     $0.10
MetaMask fee     $0.04
Total            $10.14
```

### After
```
Fees [i]         $0.14    ← Tappable info icon
Total            $10.14
Est. points [i]  14       ← New rewards row (white text)
```

### Fee Breakdown Sheet (when tapping [i])
```
╔════════════════════════╗
║ Fees                   ║
╠════════════════════════╣
║ Polymarket fee  $0.10  ║
║ MetaMask fee    $0.04  ║
╚════════════════════════╝
```

## Commit History

1. `feat: Add rewards row to Predict Buy confirmation screen` - Initial
rewards implementation
2. `refactor: Consolidate fee rows and add breakdown sheet` - Fee
consolidation
3. `refactor: Move Est. points row to end and use white text` - Final
positioning and styling
4. `test: Add comprehensive tests for rewards and fee breakdown
features` - Complete test coverage

## Related Issues/PRs

- Related to rewards feature integration
- Consistent with Swap/Bridge rewards display patterns

## Checklist

- [x] Code follows project coding guidelines
- [x] Code follows React Native UI development guidelines
- [x] Used design system components
(`@metamask/design-system-react-native`)
- [x] Used Tailwind CSS with `useTailwind()` hook
- [x] No StyleSheet.create() used
- [x] Proper TypeScript types (no `any`)
- [x] Comprehensive unit tests added
- [x] All tests passing
- [x] No linter errors
- [x] Localization strings added
- [x] Feature flag integrated
- [x] Component reusability maintained
- [x] Follows AAA test pattern
- [x] No breaking changes


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Adds rewards point estimation and consolidates fee display with a
tappable fees breakdown sheet in Predict Buy.
> 
> - **Predict UI**:
> - `PredictFeeSummary`: Replace separate fee rows with a single "Fees"
row (info icon), display total fees, and add "Est. points" row using
`RewardsAnimations`.
> - `PredictBuyPreview`: Compute `estimatedPoints =
Math.round(metamaskFee * 100)`, gate rewards by
`selectRewardsEnabledFlag`, and open fee breakdown via
`onFeesInfoPress`; pass rewards/fees props.
> - **New Component**:
> - `PredictFeeBreakdownSheet`: Bottom sheet showing per-fee breakdown
(`Polymarket fee`, `MetaMask fee`), `shouldNavigateBack=false`,
`onClose` support.
> - **Localization**:
> - Add strings for `predict.fee_summary.fees`, `provider_fee_label`,
`estimated_points`, points tooltips/error content.
> - **Tests**:
> - Add tests for `PredictFeeBreakdownSheet` and rewards/fees behavior;
update existing expectations from "Provider fee" to "Fees".
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
01962c5. 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**

Adds the Tron network to swaps/bridge.

<!--
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: added Tron network support in swaps

## **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]
> Adds Tron support to swaps and bridge, filters non‑tradable Tron
tokens, updates fee/status handling, defaults, and dependencies.
> 
> - **Bridge/Swaps Integration**
> - Allow `TrxScope.Mainnet` in swaps (`isSwapsAllowed`) and bridge
(`ALLOWED_BRIDGE_CHAIN_IDS`, network name map).
> - Add Tron default swap token (`USDT` TRC20) in
`default-swap-dest-tokens.ts` and BIP44 pairs.
> - **Token Handling**
> - New `isTradableToken` utility to exclude Tron resource tokens
(`Energy`, `Bandwidth`, `Max Bandwidth`).
> - `useTokens` now filters non‑tradable tokens, normalizes non‑EVM
addresses, and improves deduping/exclusions.
> - **UI/Logic**
> - `TransactionDetails`: safer multichain fee sum (handles partially
fungible fees) and unified status selection.
>   - Asset utils: mark Solana/Tron assets as swaps‑allowed.
> - **Tests**
> - Extensive tests for non‑EVM normalization, Tron token filtering,
deduplication, and edge cases.
> - **Dependencies**
> - Bump `@metamask/bridge-controller` and
`@metamask/bridge-status-controller` to `^60.1.0`;
`@metamask/tron-wallet-snap` to `^1.7.x` (lockfile updated).
> - **Docs**
>   - Minor README fixes (overlay usage, sample E2E notes).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b88a55b. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: GeorgeGkas <georgegkas@gmail.com>
…#22173)

## **Description**

Removed `Text` component wrappers from `BottomSheetHeader` children
across the codebase to ensure consistency with the new API pattern where
`BottomSheetHeader` handles text styling internally.

This refactoring removes redundant `Text` components that were wrapping
string content inside `BottomSheetHeader`. The `BottomSheetHeader`
component now handles the text styling directly, ensuring a consistent
appearance across all bottom sheet headers in the app.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Part of: https://consensyssoftware.atlassian.net/browse/MDP-343

## **Manual testing steps**

```gherkin
Feature: Bottom Sheet Headers Display Correctly

  Scenario: user views various bottom sheets with headers
    Given the app is running
    
    When user opens any bottom sheet modal with a header (e.g., network selector, payment method selector, region selector, account permissions, etc.)
    Then the header text should display correctly with proper styling
    And the header should be visually consistent with other bottom sheet headers
```

## **Screenshots/Recordings**

### **Before**

N/A - Internal refactoring, no visual changes. We can trust the
component to handle styling correctly.

### **After**

N/A - Internal refactoring, no visual changes. We can trust the
component to handle styling correctly.

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

---

### **Changes Summary**

**11 component files updated:**
- NetworkSettings/index.js (4 instances)
- NetworkListBottomSheet.tsx
- TooltipModal/index.tsx
- AccountPermissionsConfirmRevokeAll.tsx
- NetworkSelector/NetworkSelector.tsx
- RpcSelectionModal/RpcSelectionModal.tsx
- NetworkManager/index.tsx
- PermittedNetworksInfoSheet.tsx
- ConnectionDetails/ConnectionDetails.tsx
- RegionSelectorModal/RegionSelectorModal.tsx
- PaymentMethodSelectorModal.tsx

**5 test snapshots updated:**
- RegionSelectorModal (8 snapshots)
- PaymentMethodSelectorModal (1 snapshot)
- AccountPermissionsConfirmRevokeAll (1 snapshot)
- ConnectionDetails (1 snapshot)
- PermittedNetworksInfoSheet (1 snapshot)

**Total:** 16 files changed, 54 insertions(+), 60 deletions(-)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Refactors BottomSheetHeader to take raw string children across
modals/selectors and updates tests/snapshots and small header style
expectations.
> 
> - **UI/BottomSheetHeader refactor**:
> - Replace `<Text>` wrappers with raw string children in
`BottomSheetHeader` across:
> - Bridge: `BlockaidModal`, `BridgeNetworkSelectorBase`,
`BridgeTokenSelectorBase`, `QuoteExpiredModal`, `SlippageModal`,
`TransactionDetails/BlockExplorersModal`.
> - Ramp (Deposit): `PaymentMethodSelectorModal`, `RegionSelectorModal`.
> - Account Permissions: `AccountPermissionsConfirmRevokeAll`,
`ConnectionDetails`, `PermittedNetworksInfoSheet`.
> - Networks: `NetworkManager`, `AddAsset/NetworkListBottomSheet`,
`NetworkSelector`.
>     - Misc: `TooltipModal`.
> - **Tests/Snapshots**:
> - Update snapshots to new header structure: add
`testID="header-title"`, center text, and expect fontSize 16.
> - Adjust NetworkManager tests to assert `testID="header"` instead of
mocked header ID; extend icon mocks.
> - **Styles**:
> - Remove unused `heading` style in `NetworkSettings` styles; align
header typography via `BottomSheetHeader`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
ddcd7e7. 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 is to set up EAS updates. Same as:
#17431. Trying to merge
it in again. It was reverted due to Android e2e fails. I applied this
expo patch to fix it:
#22506

<!--
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: Added EAS updates initial setup

## **Related issues**

Fixes:

## **Manual testing steps**

## **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]
> Adds EAS OTA updates: central version/config, build-time channel
injection for iOS/Android, UI debug info, test mocks, and required
deps/patches.
> 
> - **OTA Infrastructure**:
> - Add `ota.config.js` (single source for `OTA_VERSION`,
`RUNTIME_VERSION`, `PROJECT_ID`, `UPDATE_URL`) and re-export via
`app/constants/ota.ts` (adds `getFullVersion`).
> - Configure Expo in `app.config.js` with `expo.updates.url`, runtime
version, request headers; set Hermes on iOS.
>   - Import `expo-asset` in `index.js` to resolve OTA-bundled assets.
> - **Build/CI**:
> - New `scripts/update-expo-channel.js` injects channel/runtime/URL and
enable flags into Android `AndroidManifest.xml` and iOS
`ios/Expo.plist`; invoked from `scripts/build.sh`.
> - Register `scripts/update-expo-channel.js` in `.github/CODEOWNERS`
and add `EXPO_PROJECT_ID` to `.js.env.example`.
> - **iOS**:
> - Add `ios/Expo.plist` and include in Xcode project; enable Hermes in
`Podfile` and properties; bring in `EXUpdates` (+ related pods) in
`Podfile.lock`.
> - **Android**:
> - Apply Yarn patch to `expo-updates` (removes Android test preload
hook) via `.yarn/patches/...`.
> - **App UI**:
> - Enhance Settings > App Information to display OTA status (enabled,
project/update IDs, channel, runtime version, status) and show full
version with OTA suffix.
> - **Testing**:
> - Add `app/__mocks__/expo-updates.ts` and Jest mapper for
`expo-updates`.
> - **Selectors**:
>   - Make `accounts` selectors null-safe with defaults.
> - **Dependencies**:
> - Add `expo-asset`, `expo-updates` (patched) and related
Yarn/CocoaPods updates.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
c2b1284. 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>
# Predict GTM (Go-To-Market) Modal

## Overview
This PR implements a marketing announcement modal for the Predict
feature, similar to the existing Perps GTM Modal. The modal appears once
after user login when both the Predict feature and the GTM modal feature
flags are enabled.

CHANGELOG entry: null

## Screenshots

<img width="720" height="460" alt="image"
src="https://github.com/user-attachments/assets/96ee0747-cd2e-4062-b210-f4fe283a8a5b"
/>

## Changes

### New Components
- **`PredictGTMModal`**
(`app/components/UI/Predict/components/PredictGTMModal/`)
  - Full-screen modal with custom background image
  - Title: "PREDICT AND WIN"
- Description: "Trade on the outcome of real-world events, like sports
or elections."
- Two action buttons: "Get started" (primary) and "Not now" (secondary)
  - Responsive styling with proper scaling across different screen sizes

### Navigation Updates
- **`app/components/UI/Predict/routes/index.tsx`**
  - Added `PredictGTMModal` to the `PredictModalStack`
- Integrated modal stack into `PredictScreenStack` at
`Routes.PREDICT.MODALS.ROOT`
  - Follows the same pattern as Perps navigation structure

- **`app/components/Views/Wallet/index.tsx`**
- Added `checkAndNavigateToPredictGTM` function to trigger modal on
login
  - Modal only shows once per app session (tracked via storage flag)
  - Conditionally triggered based on feature flags

### Storage & Analytics
- **`app/constants/storage.ts`**
  - Added `PREDICT_GTM_MODAL_SHOWN` constant for persistence

- **`app/components/UI/Predict/constants/eventNames.ts`**
  - Added analytics event constants:
    - `PREDICT_GTM_WHATS_NEW_MODAL`
    - `PREDICT_GTM_MODAL_ENGAGE` (for "Get started")
    - `PREDICT_GTM_MODAL_DECLINE` (for "Not now")

### Feature Flags
- **`app/components/UI/Predict/selectors/featureFlags/index.ts`**
  - Added `selectPredictGtmOnboardingModalEnabledFlag` selector
- Checks both local env var (`MM_PREDICT_GTM_MODAL_ENABLED`) and remote
feature flag

### Localization
- **`locales/languages/en.json`**
  - Added `predict.gtm_content` strings:
    - `title`: "PREDICT AND WIN"
- `title_description`: "Trade on the outcome of real-world events, like
sports or elections."
    - `get_started`: "Get started"
    - `not_now`: "Not now"

### Assets
- **`app/images/predict-marketing.png`**
  - Background image for the modal
  - Full-screen background with character and "Yes/No" buttons design

## Design Details

### Colors
- Title & Description: `theme.colors.accent02.light` (light purple
#EAC2FF)
- "Get started" button: White background with dark text
- "Not now" button: Transparent background with white text

### Typography
- **Title**: MM Poly font, 400 weight, 50px size, 100% line height,
center aligned
- **Description**: System default font, 500 weight, 16px size, 24px line
height, center aligned

### Background Image
- Sized proportionally to screen dimensions (1.07x width, 1.12x height)
- Ensures full edge-to-edge coverage across all device sizes

## Navigation Flow

### Modal Trigger
1. User logs in to the app
2. Wallet screen checks if Predict and GTM modal flags are enabled
3. If flags are enabled and modal hasn't been shown before, navigate to
modal

### User Actions
**"Get started" button:**
1. Tracks analytics event (`PREDICT_GTM_MODAL_ENGAGE`)
2. Sets storage flag to prevent re-showing
3. Navigates to Wallet Home
4. Navigates to Predict Market List (feed)
5. Result: User lands on Predict feed with Wallet in back stack

**"Not now" button:**
1. Tracks analytics event (`PREDICT_GTM_MODAL_DECLINE`)
2. Sets storage flag to prevent re-showing
3. Navigates back to Wallet Home

### Back Navigation
- From Predict feed: Returns to Wallet (modal is dismissed)
- Modal never reappears in the same app session (tracked via storage +
useRef)

## Feature Flags

### Required Flags
1. **`selectPredictEnabledFlag`** - Enables the entire Predict feature
2. **`selectPredictGtmOnboardingModalEnabledFlag`** - Enables the GTM
modal specifically

### Environment Variables
- `MM_PREDICT_GTM_MODAL_ENABLED=true` - Local override for modal flag

## Testing

### Manual Testing
1. Enable feature flags (set both to `true` in selectors for testing)
2. Clear app storage or use a fresh install
3. Log in to the app
4. Modal should appear automatically
5. Test "Get started" → should navigate to Predict feed
6. Go back → should return to Wallet (not modal)
7. Restart app → modal should NOT appear again

### Test Different Screen Sizes
The modal uses responsive scaling. Test on:
- iPhone SE (small)
- iPhone 14 (medium)
- iPhone 14 Pro Max (large)

### Storage Reset (for testing)
To reset and see the modal again during testing:
```javascript
// In React Native Debugger console or via code
import StorageWrapper from './store/storage-wrapper';
await StorageWrapper.removeItem('@MetaMask:predictGTMModalShown');
```

## Analytics Events

All events use `MetaMetricsEvents.WHATS_NEW_LINK_CLICKED` with
properties:
- `feature`: `'predict-gtm-whats-new-modal'`
- `action`: `'engage'` (Get started) or `'decline'` (Not now)
- Device metadata included via `generateDeviceAnalyticsMetaData()`

## Files Changed

### New Files
-
`app/components/UI/Predict/components/PredictGTMModal/PredictGTMModal.tsx`
-
`app/components/UI/Predict/components/PredictGTMModal/PredictGTMModal.styles.ts`
- `app/components/UI/Predict/components/PredictGTMModal/index.ts`
- `app/images/predict-marketing.png`

### Modified Files
- `app/components/UI/Predict/routes/index.tsx`
- `app/components/Views/Wallet/index.tsx`
- `app/constants/storage.ts`
- `app/components/UI/Predict/constants/eventNames.ts`
- `app/components/UI/Predict/selectors/featureFlags/index.ts`
- `locales/languages/en.json`

## Architecture Notes

### Pattern Consistency
This implementation follows the exact same pattern as the Perps GTM
Modal:
- Modal stack structure
- Feature flag logic
- Storage tracking
- Analytics events
- Navigation behavior

### One-Time Display Logic
The modal shows only once per app session using:
1. **Storage flag** (`PREDICT_GTM_MODAL_SHOWN`) - Persists across app
restarts
2. **useRef guard** in Wallet component - Prevents re-triggering during
navigation

### Navigation Strategy
Uses two separate `navigate()` calls (not `CommonActions.reset()`) to:
- Preserve navigation history
- Maintain tab state
- Work correctly with deep links
- Match Perps implementation

## Future Enhancements

Potential improvements for future PRs:
- Add unit tests for `PredictGTMModal` component
- Add integration tests for navigation flow
- Support for dynamic content via remote config
- A/B testing variants
- Localization for additional languages

## Related Issues

_Link to related Jira tickets or GitHub issues_

## Checklist

- [x] Component follows MetaMask Mobile design system patterns
- [x] Responsive design tested on multiple screen sizes
- [x] Analytics events properly tracked
- [x] Storage flag prevents re-showing
- [x] Navigation behavior matches Perps pattern
- [x] Feature flags implemented correctly
- [x] Localization strings added
- [x] No linter errors
- [ ] Unit tests added (future enhancement)
- [ ] Integration tests added (future enhancement)


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Introduces a full-screen Predict GTM modal shown once via feature
flags, wired into navigation, storage, analytics, and covered by unit
tests.
> 
> - **Predict GTM Modal**:
> - Adds `PredictGTMModal` component with responsive styles and
background image (`PredictGTMModal.tsx/.styles.ts`, `index.ts`).
> - Tracks engage/decline with
`MetaMetricsEvents.WHATS_NEW_LINK_CLICKED` and new constants.
> - Sets `PREDICT_GTM_MODAL_SHOWN` to prevent re-showing; navigates to
`Wallet` and Predict feed.
> - **Navigation**:
> - Registers modal in Predict modal stack (`routes/index.tsx`) and adds
route `Routes.PREDICT.MODALS.GTM_MODAL`.
> - **Wallet behavior**:
> - Shows modal once after login when both Predict and GTM modal flags
are enabled; checks storage and navigates (`Views/Wallet/index.tsx`).
> - **Feature Flags**:
> - Adds selector `selectPredictGtmOnboardingModalEnabledFlag` using
remote or `MM_PREDICT_GTM_MODAL_ENABLED` (`selectors/featureFlags`).
> - **Analytics**:
> - Adds GTM modal event constants (`PREDICT_GTM_WHATS_NEW_MODAL`,
`PREDICT_GTM_MODAL_ENGAGE`, `PREDICT_GTM_MODAL_DECLINE`).
> - **Storage**:
>   - Adds `PREDICT_GTM_MODAL_SHOWN` key (`constants/storage.ts`).
> - **Localization**:
>   - Adds `predict.gtm_content` strings (`en.json`).
> - **Tests**:
> - Unit tests for modal behavior and Wallet gating/mocks
(`PredictGTMModal.test.tsx`, updates to `Views/Wallet/index.test.tsx`).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9f219d1. 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**
Scanning an invalid QR code, the invalid QR code alert is showing
multiple times.

The fix: when there is an error scanning QR code, in the parseDeeplink
file we return true so it stops at line 257 in QRScanner:
https://app.bitrise.io/app/be69d4368ee7e86d/pipelines/9e507fa7-b997-40cc-831a-6f186aef992e

builds for testing:
https://app.bitrise.io/app/be69d4368ee7e86d/pipelines/9e507fa7-b997-40cc-831a-6f186aef992e

<!--
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:Fixed a bug that was causing invalid QR code alert
showing multiple times

## **Related issues**

Fixes: #12908

## **Manual testing steps**

```gherkin
Feature: QR Code Scanner - Invalid QR Code Handling

  Scenario: User scans an invalid QR code
    Given the user is on the QR code scanner screen
    
    When the user scans an invalid QR code "0xB8B4EE5B1b693971eB60bDa15211570df2dB221L"
    Then the user should be navigated back to the home screen
    And an alert should be displayed with title "This is not a valid address"
    And the alert should contain the message about unrecognized QR code
    
    When the user taps "OK" on the alert
    Then the alert should be dismissed
    And the user should remain on the home screen
```

## **Screenshots/Recordings**

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

### **Before**
Android
![Android
Before](https://github.com/user-attachments/assets/85a57e9b-fbdd-4729-bcd5-a9804fa5c993)

iOS
![iOS
before](https://github.com/user-attachments/assets/fdd2ea9a-81ff-4449-ac30-0519ecb5dc2c)

### **After**
Android
![Android
after](https://github.com/user-attachments/assets/fd93d964-82dc-4bd3-b210-bda676472509)

iOS
![iOS
After](https://github.com/user-attachments/assets/fff2f431-88c2-44fc-9f46-9f889a41e258)

<!-- [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]
> Ensures invalid QR scans navigate back, show a single specific alert,
and return handled to stop repeat alerts.
> 
> - **Deeplink parsing
(`app/core/DeeplinkManager/ParseManager/parseDeeplink.ts`)**:
>   - On parse error from QR origin:
>     - Call `onHandled()` before alert to navigate back.
>     - Show QR-specific "unrecognized address" alert.
>     - Return `true` to mark as handled and prevent repeat alerts.
>   - Otherwise, show generic `Invalid URL` alert.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
6f3a038. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…22542)

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

Fixed a bug in the Predict feature where optimistic position updates
were incorrectly applied when querying for claimable positions.
Previously, when calling `getPositions({claimable: false})` after
creating or updating a position optimistically, the API would return no
results (as expected, since newly created/updated positions are not
claimable), but the code would still inject the optimistic position into
the results. This caused positions to incorrectly appear as claimable
when they were not.

The fix ensures that CREATE/UPDATE optimistic updates are only applied
to non-claimable position queries, since it's impossible to create or
update a position that is immediately claimable.

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

```gherkin
Feature: Predict optimistic position updates

  Scenario: user creates a position and queries claimable positions
    Given the user has created a new Predict position optimistically
    And the API has not yet returned the created position

    When user queries positions with claimable: false
    Then the optimistic position should not appear in the results
```

## **Screenshots/Recordings**

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

### **Before**

<!-- Optimistic positions would incorrectly appear when querying with
claimable: false -->

### **After**

<!-- Optimistic positions are correctly excluded from claimable queries
-->

## **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]
> Prevents optimistic CREATE/UPDATE positions from appearing in
claimable queries and short-circuits updates for claimable API
positions; minor withdraw param typing tweak.
> 
> - **Predict/PolymarketProvider**:
>   - **Optimistic updates**:
> - `applyOptimisticPositionUpdates` now accepts `claimable` and avoids
adding optimistic positions when `claimable` is true.
> - `isApiPositionUpdated` treats claimable API positions as already
updated.
> - `getPositions` passes `claimable` into
`applyOptimisticPositionUpdates`.
>   - **Withdraw**:
> - Use `callData` directly in transaction params (`prepareWithdraw`),
removing unnecessary `Hex` cast.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7b12627. 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 validates geo restriction for add funds.

<!--
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/MMQA-1139

## **Manual testing steps**

```
https://github.com/MetaMask/metamask-mobile/actions/runs/19267849354/job/55088929298?pr=22490#step:13:209
https://github.com/MetaMask/metamask-mobile/actions/runs/19267849354/job/55090297847?pr=22490#step:13:254
```

## **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]
> Adds e2e page object and selector for Predict “Add funds” and a test
asserting geo-restriction modal when invoked from balance.
> 
> - **E2E Tests**:
> - Add new scenario in
`e2e/specs/predict/predict-geo-restriction.spec.ts` verifying the
geo-restriction modal appears when tapping `Add funds` from the
Predictions balance and returns to the balance after dismissal.
> - **Page Objects**:
> - Introduce `e2e/pages/Predict/PredictAddFunds.ts` with
`tapAddFunds()` using text-matching to trigger the action.
> - **Selectors**:
> - Add `PredictAddFundsSelectorText.ADD_FUNDS` in
`e2e/selectors/Predict/Predict.selectors.ts` sourced from
`enContent.predict.deposit.add_funds`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
e2defb6. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

This PR isolates input-related fixes that were originally bundled in
#21199 (which was reverted in #22342). These specific fixes did not
cause any issues and should be preserved.

The main changes include:
1. **Font weight fix for Input component** - Added explicit `fontWeight`
property to ensure proper text rendering in TextField inputs
2. **ImportSRP modal overlay fix** - Fixed overlay style interpolation
to prevent visual artifacts during the seed phrase import modal
animation
3. **Card delegation improvements** - Enhanced delegation logic to
properly handle zero-value delegations and checksum addresses for EVM
networks

These fixes improve the overall stability and user experience of input
fields and related UI components across the app.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Related to #21199 (original PR with font preloader changes)
Related to #22342 (revert of #21199)

## **Manual testing steps**

```gherkin
Feature: Input component rendering and functionality

  Scenario: user enters text in TextField components
    Given user is on any screen with text input fields
    When user types text into input fields
    Then text should render correctly with proper font weight and styling
    
  Scenario: user imports wallet via seed phrase
    Given user is on the import wallet flow
    When user opens the seed phrase modal
    Then modal should display without overlay artifacts
    
  Scenario: user manages card delegation
    Given user has external wallet details configured
    When user sets a delegation amount of zero
    Then system should not call updateTokenPriority
    And delegation should complete successfully
```

## **Screenshots/Recordings**

N/A - These are fixes for existing functionality

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

## **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 consistent input lineHeight and applies Geist font styles to
password-related views, updating snapshots accordingly.
> 
> - **Frontend**:
> - **Input/TextField**: Set explicit `lineHeight` in
`components/Form/TextField/foundation/Input/Input.styles.ts` for
consistent baseline alignment across platforms.
>   - **Password Screens**:
> - `Views/EnterPasswordSimple/index.js`: Apply `fontStyles.normal` to
prompt text.
> - `Views/RevealPrivateCredential/styles.ts`: Apply `fontStyles.normal`
to `input` style.
> - **Tests**:
> - Update snapshots across multiple views to reflect added `lineHeight`
and `fontFamily` styling on inputs.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7bb6459. 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 12, 2025
@pull pull Bot added the ⤵️ pull label Nov 12, 2025
@pull pull Bot merged commit 9be12a6 into Reality2byte:main Nov 12, 2025
5 of 8 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.