Skip to content

[pull] main from MetaMask:main#740

Merged
pull[bot] merged 8 commits intoReality2byte:mainfrom
MetaMask:main
May 7, 2026
Merged

[pull] main from MetaMask:main#740
pull[bot] merged 8 commits intoReality2byte:mainfrom
MetaMask:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented May 7, 2026

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

Jwhiles and others added 8 commits May 7, 2026 17:32
#29141)

<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **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: Add chomp-api-service and
money-account-upgrade-controller - initialise money account upgrade
process when user visits the money account route.

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Adds new Engine services/controllers that bootstrap on keyring unlock
and triggers an account upgrade flow on Money navigation, increasing
risk of unexpected network calls or upgrade attempts. Changes touch
Engine initialization/state wiring and navigation entrypoints but are
guarded with logging, readiness checks, and deduping.
> 
> **Overview**
> Automatically kicks off the Money account upgrade flow when the user
navigates to the Money home by introducing `MoneyAccountStackGate`,
which dispatches the new `upgradeMoneyAccount` thunk on mount.
> 
> Adds `ChompApiService` (configured via the new remote flag
`earnChompApiConfig` with a dev-URL fallback) and a
`MoneyAccountUpgradeController` that bootstraps after keyring unlock by
fetching CHOMP service details and initializing upgrade parameters.
> 
> Wires both new clients into `Engine` (init, messengers, types, state
fixtures, and background state events), updates E2E API mocks to cover
the CHOMP service-details endpoint, and adds unit tests for the new init
and upgrade behaviors.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
64bdcb7. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…9863)

## **Description**

The "Your balance" heading on the Money Hub screen
(`CashTokensFullView`) was rendered between the screen header and the
scrollable list, leaving it pinned at the top while content scrolled
beneath it. This created a visually disconnected UX between the heading
and the list.

The heading is now moved into each scrollable container so it scrolls
naturally with the rest of the page:

- Funded path: passed as `ListHeaderComponent` of the FlashList inside
`<TokenList>`.
- Empty-state path: rendered as the first child of the existing
`ScrollView`.
- Skeleton path: rendered as the first child of the skeleton's
`ScrollView`.

To reach FlashList's header slot from the screen, an additive
`listHeaderComponent` prop was added to `<Tokens>` and `<TokenList>`,
mirroring the existing `listFooterComponent` pattern (opt-in, no
behavior change for existing callers). A small `wrapEdgeNode` helper
deduplicates the `-mx-4` padding-compensation that header and footer
both need in `isFullView` mode.

Note: `<Tokens>` / `<TokenList>` belong to the wallet team. Touching
them was the minimal way to reach FlashList's header slot — flagging for
wallet-team awareness during review.

## **Changelog**

CHANGELOG entry: Fixed a bug where the "Your balance" heading on the
Money Hub stayed pinned to the top of the screen instead of scrolling
with the content.

## **Related issues**

Fixes:
[MUSD-779](https://consensyssoftware.atlassian.net/browse/MUSD-779)

## **Manual testing steps**

\`\`\`gherkin
Feature: Money Hub Your balance heading scrolls with content

  Scenario: user with mUSD scrolls the Money Hub
    Given the user has mUSD balance on at least one chain
    And the user is on the Money Hub
    When the user scrolls down
Then the "Your balance" heading scrolls off-screen with the rest of the
content
    When the user scrolls back to the top
Then the "Your balance" heading reappears in flow above the mUSD list

  Scenario: user without mUSD scrolls the Money Hub empty state
    Given the user has no mUSD balance
    And the user is on the Money Hub
    When the user scrolls down
Then the "Your balance" heading scrolls off-screen with the empty-state
content
\`\`\`

## **Screenshots/Recordings**

### **Before**

### **After**


https://github.com/user-attachments/assets/51a85271-a4da-465f-9d65-0491bcd1831a


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

#### Performance checks (if applicable)

- [ ] I've tested on Android
- [ ] I've tested with a power user scenario
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics

## **Pre-merge reviewer checklist**

- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

[MUSD-779]:
https://consensyssoftware.atlassian.net/browse/MUSD-779?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UI/layout change that threads a new optional
`listHeaderComponent` prop through `Tokens`/`TokenList`; main risk is
minor rendering/padding regressions in full-view/empty-state paths.
> 
> **Overview**
> Fixes Money Hub (CashTokensFullView) so the **"Your balance"** heading
scrolls with the token content instead of staying pinned.
> 
> This adds an optional `listHeaderComponent` prop to `Tokens` and
`TokenList`, wiring it through both the map-rendered list and the
FlashList `ListHeaderComponent`, and updates the empty-state and
skeleton ScrollViews to render the header at the top. It also
deduplicates full-view edge padding compensation for both header and
footer via `wrapEdgeNode`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8ab8ff1. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

> Removes the remaining legacy `wdio` E2E testing layer, deleting WDIO
`Selectors`/`Gestures` helpers plus a large set of WDIO
screen-object/page-object modules.
> 
> Also drops the old `tests/framework/utils/MobileBrowser.js`
Chrome/Safari launcher/navigation helper, continuing the shift toward
the newer Appwright-based page objects.
> 

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

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because this deletes a large set of legacy WDIO-based E2E
helpers/page objects; any remaining hidden references in test runners or
scripts would break CI, though it should be low impact if the migration
to Appwright/Playwright is complete.
> 
> **Overview**
> Removes the remaining legacy WDIO E2E layer by deleting `wdio/helpers`
(`Selectors`, `Gestures`) and a broad set of `wdio/screen-objects`
page-object modules.
> 
> Also deletes the old `tests/framework/utils/MobileBrowser.js`
launcher/navigation helper (Chrome/Safari handling), further
consolidating E2E coverage on the newer Appwright/Playwright-based page
objects.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
b2f7316. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

After a rebalance, the Ondo positions list could remain stale for up to
60 seconds while the activity list (which is not cached on the client)
showed the up-to-date trade. Both views read the same upstream data, so
the divergence was purely a client-side cache artifact in
`RewardsController.getOndoCampaignPortfolioPosition`.

This PR sets `ONDO_CAMPAIGN_PORTFOLIO_POSITION_CACHE_THRESHOLD_MS` to
`0`, which makes `wrapWithCache` always treat the entry as stale and
fetch fresh from the API. The mirrored Redux state
(`state.ondoCampaignPortfolio[…]`) is still written on each fetch, so
selectors continue to render the latest snapshot — only the staleness
window is removed.

Agreed on the approach with @jonathan.deyoung and @christian.montoya in
[this Slack
thread](https://consensys.slack.com/archives/C09372GAN59/p1778101253654439);
flagged as a quick win for today's RC. Jonathan's call: low-risk because
traffic to this endpoint is low and hits read-only servers, and the
longer-term fix (timestamp-aligning positions and activity, à la S1) is
parked as Perps follow-up work.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: N/A — driven by Slack thread linked above.

## **Manual testing steps**

```gherkin
Feature: Ondo positions stay in sync with activity after a rebalance

  Scenario: user rebalances and immediately reopens the campaign details
    Given the user has an active Ondo GM portfolio with at least one position
    When the user performs a rebalance (e.g. swap GE for MSFT)
    And the user navigates back into the Ondo campaign details screen within 60s
    Then the positions list reflects the post-rebalance holdings (MSFT present, GE absent)
    And the positions list matches the activity list
```

## **Screenshots/Recordings**

### **Before**

<!-- Stale positions list immediately after rebalance — see attached
images in the Slack thread. -->

### **After**

<!-- Positions list matches activity list immediately after rebalance.
-->

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

#### Performance checks (if applicable)

- [ ] I've tested on Android
- [ ] I've tested with a power user scenario
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Disables several short-lived client caches, increasing request
frequency for authenticated rewards endpoints; main risk is
performance/network impact and potential rate-limiting, not data
integrity.
> 
> **Overview**
> Removes the client-side TTL for several rewards “live snapshot” reads
by setting their cache thresholds to `0`, forcing fresh API fetches
while still mirroring responses into controller state for selectors.
> 
> This applies to Ondo leaderboard position, Ondo portfolio position,
Ondo first-page activity, and Perps trading leaderboard position, and
updates unit tests and generated action-type docs to reflect the new
always-fresh behavior (including re-fetching even when a recent
not-found sentinel exists).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
e77be61. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## **Description**

-
"?~campaign=ondo&__branch_flow_id=1580894552734833035&~referring_browser=Chrome"
would fail to be parsed correctly, the campaign param we extract would
be null, and the user would end up in the rewards dashboard instead of
the ondo details campaign page.

- Added support for upcoming perps trading comp deeplink 

## **Changelog**

CHANGELOG entry: null

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: small, localized change to rewards deeplink query parsing
that may only affect navigation routing for rewards campaign links.
> 
> **Overview**
> Rewards deeplink parsing now falls back to reading Branch-style
`~campaign` when `campaign` is missing, preventing campaign links from
dropping users onto the generic rewards dashboard.
> 
> It also expands allowed campaign values to include the new
`perps-comp` campaign so those deeplinks can route correctly.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
ddca21a. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

> Removes the custom Yarn patching of `appwright` (and related
`form-data` override) and drops `appwright` from dependencies/unplugged
resolutions.
> 
> Deletes the Appwright-based E2E/performance test harness
(`tests/appwright.config.ts` plus the `Appwright*` helpers and
performance fixture exports), leaving the repo without
Appwright-specific test entrypoints.
> 
> Updates `yarn.lock` accordingly to prune `appwright` and a large set
of transitive packages (notably `ffmpeg`/`sharp`/`webdriver*` related
entries) and to simplify some version ranges/dedupes.
> 

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

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it removes `appwright` and associated
performance/E2E fixtures/config, which may break or change how CI or
local performance test runs are invoked even though it doesn’t touch
production app code.
> 
> **Overview**
> Removes `appwright` from the repo by deleting the custom Yarn patch
and dropping the dependency/resolution overrides in `package.json`.
> 
> Deletes the Appwright-based E2E/performance test entrypoints and
helper/fixture modules under `tests/`, and updates `yarn.lock` to prune
`appwright` and a large set of related transitive packages (notably
webdriver/ffmpeg/sharp-related).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
3e24b60. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Version Bump After Release

This PR bumps the main branch version from 7.77.0 to 7.78.0 after
cutting the release branch.

### Why this is needed:
- **Nightly builds**: Each nightly build needs to be one minor version
ahead of the current release candidate
- **Version conflicts**: Prevents conflicts between nightlies and
release candidates
- **Platform alignment**: Maintains version alignment between MetaMask
mobile and extension
- **Update systems**: Ensures nightlies are accepted by app stores and
browser update systems

### What changed:
- Version bumped from `7.77.0` to `7.78.0`
- Platform: `mobile`
- Files updated by `set-semvar-version.sh` script

### Next steps:
This PR should be **manually reviewed and merged by the release
manager** to maintain proper version flow.

### Related:
- Release version: 7.77.0
- Release branch: release/7.77.0
- Platform: mobile
- Test mode: false

---
*This PR was automatically created by the
`create-platform-release-pr.sh` script.*

Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

  Upgrades the core mobile stack from React Native 0.76.9 to 0.81.5,
  React 18.3 to 19.1, and Expo SDK 52 to 54. Includes all necessary
  migration fixes for breaking changes in the new architecture, test
  infrastructure updates, and dependency alignment.

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

### Core stack
- **React Native** 0.76.9 → 0.81.5
- **React** 18.3.1 → 19.1.0 (and `react-test-renderer` to match)
- **Expo SDK** 52 → 54 (every `expo-*` package bumped to its SDK 54
line)
- **Hermes** updated alongside RN 0.81
- **`@react-native-community/cli` (+ `cli-platform-android`/`-ios`)**
15.0.1 → 20.0.0
- **`@react-native/metro-config`** 0.76.9 → 0.81.5
- **`@types/react`** ^18.2.6 → ^19.1.0
- **iOS app entry point migrated from Objective-C (`main.m`) to Swift
(`AppDelegate.swift`)** as required by the RN 0.81 iOS template

### React Native ecosystem libraries
- **`react-native-screens`** 3.37.0 → 4.16.0 (major)
- **`react-native-safe-area-context`** ^5.4.0 → ~5.6.0
- **`react-native-reanimated`** ^3.17.2 → 3.19.0
- **`react-native-gesture-handler`** ^2.25.0 → ~2.28.0
- **`react-native-mmkv`** ^3.2.0 → ^4.1.2 (major; resolves to 4.3.1)
- **`react-native-pager-view`** ^6.7.0 → 6.9.1
- **`react-native-nitro-modules`** ^0.29.6 → 0.35.5
- **`react-native-svg`** ^15.11.1 → 15.12.1
- **`react-native-video`** ^6.10.1 → ^6.19.0
- **`react-native-vision-camera`** ^4.6.4 → ^4.7.3
- **`react-native-view-shot`** ^3.1.2 → 4.0.3 (major; legacy
`patch-package` patch dropped)
- **`react-native-qrcode-svg`** 5.1.2 → 6.3.21 (major; legacy patch
dropped)
- **`react-native-performance`** ^5.1.2 → ^6.0.0 (major; legacy patch
dropped)
- **`react-native-release-profiler`** ^0.4.0 → ^0.4.4
- **`@react-native-community/slider`** ^4.4.3 → 5.0.1 (major)
- **`@react-native-async-storage/async-storage`** ^1.23.1 → 2.2.0
(major)
- **`@react-native-community/viewpager`** new direct dep (patched) to
keep legacy paged-view consumers building under RN 0.81
- **`lottie-react-native`** 6.7.2 → ~7.3.1 (major)
- **`rive-react-native`** 9.3.4 → ^9.8.0 (legacy patch dropped)

### Native / platform integrations
- **`@sentry/react-native`** ~6.15.0 → ~7.2.0
- **`@segment/analytics-react-native`** ^2.20.3 → ^2.21.4
- **`@solana-mobile/mobile-wallet-adapter-protocol`** ^2.2.5 added
(replaces the removed Solana shim path)

### Tooling / test infra
- **`detox`** ^20.35.0 → ^20.43.0
- **`@expo/fingerprint`** ^0.15.0 → ~0.15.4
- **`pretty-format/react-is`** pinned to ^19.0.0 (resolution; required
for React 19 test compat)
- New global mock: `tests/module-mocking/sentry/react-native.ts`
(E2E-only Sentry shim selected by `metro.config.js` when `IS_TEST=true`)
- `tsconfig.json` path aliases for selected `@metamask/*` dist subpaths

## Breaking Changes Addressed

### React 19
- Removed `defaultProps` from all function components (deprecated in
React 18.3, removed in 19)
- `useRef` now requires an explicit initial value — every `useRef<T>()`
updated to `useRef<T>(null)`
- `RefObject<T>` typing tightened — call sites switched to `RefObject<T
| null>` where they were assuming non-null
- `React.cloneElement` generics tightened — added explicit type
parameters where inference no longer narrows
- `ReactChild` removed — switched to `ReactNode`
- Migrated hook tests from `@testing-library/react-hooks` (unmaintained
on React 19) to `@testing-library/react-native` `renderHook`
- Updated mocked ref parameters from `{}` to `undefined` to match the
new `forwardRef` signature
- Updated test `rerender()` call sites to the new return shape

### React Native 0.81
- Added a `BackHandler.removeEventListener` shim (the static method was
removed; `addEventListener` now returns a subscription)
- Migrated iOS entry point to **Swift `AppDelegate.swift`** + new
`LaunchScreen.xib` (deleted `main.m`)
- `MMKV` is now a type-only export and `.remove()` was renamed to
`.delete()` (`react-native-mmkv` v4)
- `NavigationContainerRef` requires a generic parameter
(`@react-navigation/native` v7)
- `BlurEvent` / `FocusEvent` typing changes on `TextInput` callbacks
- `refreshControl` prop typing on virtualized lists
- New `MessageEvent` (private) usage in `WebSocket` is internal — Snaps
continue to boot via the existing
`patches/@MetaMask+post-message-stream+10.0.0.patch` (no shim needed)
- Patched `@metamask/react-native-webview`,
`@metamask/react-native-button`, `@metamask/react-native-payments`,
`@metamask/react-native-acm` for RN 0.81 / React 19 compatibility (see
TODO list below)
- Fixed `expo-modules-core` `EventEmitter` mock, `Linking` mock path
(now `.default.openURL`), safe-area / screens snapshots

### Snaps
- `AbstractExecutionService` renamed to `ExecutionService` in
`@metamask/snaps-controllers`
- Allowed `XMLSerializer` and `DOMParser` inside the snap iframe via the
new yarn patch on `@metamask/snaps-execution-environments` (replaces the
runtime HTML mutation we previously carried in
`SnapsExecutionWebView.tsx`)
- Restored upstream `pump` usage in snap/background bridges (rolled back
local stream-cleanup defensive code in `MobilePortStream.js` and
`execution-service-init.ts`)

### Test infrastructure
- Fixed wallet adapter tests (dynamic import race with
`@expensify/react-native-wallet`)
- Restored the `isClosingRef` guard in `BottomSheetDialog` to prevent
double `goBack` (MUSD-406) and rolled back a faulty `lodash.debounce`
attempt
- Fixed `PolymarketProvider` fetch mocks (missing `response.text()`)
- Fixed `useTokenSearch` throttle timing, `EarnLendingWithdrawal` mock
ordering
- Updated `initial-background-state.json` fixture, `useTailwind` mock,
`reanimatedLogger` config
- E2E: fixed URL editor dismissal and snap error assertions across
platforms; raised default Detox timeout

### Build / CI
- iOS `Podfile.lock` regenerated for RN 0.81's new Pod graph
- iOS `PrivacyInfo.xcprivacy` updated for the SDK 54 surface
- Android: `CMAKE_VERSION` pinned for RN 0.81's NDK build
- E2E CI workflows append `${{ github.run_id }}` to native-build cache
keys (Android APKs/Gradle, iOS DerivedData) to force fresh builds during
the upgrade rollout
- `.depcheckrc.yml` ignores extended for short-name Babel plugins

## Dependencies Patched (`.yarn/patches/`)

**MetaMask-owned (see TODO below — should be upstreamed and the patches
dropped):**
- `@metamask/react-native-acm@1.2.0`
- `@metamask/react-native-button@3.0.0`
- `@metamask/react-native-payments@2.0.2`
- `@metamask/react-native-webview@14.6.0`
- `@metamask/snaps-execution-environments@11.0.2`

**Third-party (need upstream PRs or version bumps as they ship RN
0.81-compatible releases):**
- `react-native@0.81.5` (RN itself — small follow-up patch on top of
0.81.5)
- `@react-native-community/viewpager@3.3.0`
- `@braze/react-native-sdk@19.1.0` (ReactModuleInfo signature change)
- `react-native-aes-crypto-forked` (we maintain the fork; can be folded
into the fork repo)
- `react-native-fast-crypto@2.2.0`
- `react-native-gzip@1.1.0`
- `react-native-i18n@2.0.15` (deprecated upstream — long-term replace)
- `react-native-os@1.2.6`
- `react-native-sensors@5.3.0`
- `reactotron-core-client@2.9.7`
- `expo-web-browser@14.0.2`

**Legacy `patches/` (patch-package) entries removed in this PR**
because the upstream packages or our own forks now cover them, or
because the patched version is no longer installed:
`@metamask+react-native-button+3.0.0`,
`@metamask+react-native-payments+2.0.0`,
`react-native+0.76.9`,
`react-native-aes-crypto-forked+1.2.1`,
`react-native-fast-crypto+2.2.0`,
`react-native-performance+5.1.2`,
`react-native-qrcode-svg+5.1.2`,
`react-native-view-shot+3.8.0`,
`expo-updates-npm-0.27.4`. Net result: no orphan patches carried
forward.

## TODO — follow-ups after this PR is merged

Several Yarn patches added by this upgrade target packages we own under
`@metamask/*`. They unblock RN 0.81 today, but we should publish fixed
releases and drop the local patches in follow-up PRs:

- **`@metamask/react-native-acm@1.2.0`** — RN 0.81's Kotlin rewrite of
  `ReactContextBaseJavaModule` removed the `currentActivity` synthetic
accessor (now `getCurrentActivity()`) and made `onNewIntent(intent:
Intent)`
non-nullable. Patch updates the 4 affected sites in
`GoogleAcmModule.kt`.
  → Publish a 1.x compatible release that compiles against RN 0.81.
- **`@metamask/react-native-button@3.0.0`** —
`TouchableOpacity.propTypes`,
`Text.propTypes` and `ViewPropTypes.style` no longer exist on RN 0.81 /
React 19. Patch falls back to `PropTypes.any`/`PropTypes.bool`
defensively.
→ Replace `propTypes` with TypeScript types or PropTypes.shape literals
  upstream.
- **`@metamask/react-native-payments@2.0.2`** — Bumps Android
`compileSdk`/`buildTools`/`targetSdk` from 28 → 36 and drops the removed
  `ReactBridge` import. → Publish a release with the SDK bump (and
optionally migrate the module to Kotlin / TurboModules while we're
there).
- **`@metamask/react-native-webview@14.6.0`** — Adds
`codegenConfig.ios.componentProvider`/`modulesProvider` entries needed
by
RN 0.81's Fabric codegen so `RNCWebView` and `RNCWebViewModule` register
correctly. → Cherry-pick into the next published release; this is purely
  a `package.json` metadata fix.
- **`@metamask/snaps-execution-environments@11.0.2`** — Adds
`XMLSerializer`
  and `DOMParser` to the LavaMoat `scuttleGlobalThis.exceptions` list in
  `dist/webpack/webview/index.html` so snaps can run inside the iframe
  after lockdown. (This replaces the runtime HTML mutation we previously
carried in `SnapsExecutionWebView.tsx`.) → Land the equivalent change in
`snaps` upstream so the scuttle exceptions are baked into the published
  HTML.

Other notable patches added here target third-party packages we don't
own
(see the "Third-party" list above); they'll need separate upstream PRs
or
version bumps as those projects publish RN 0.81-compatible releases.

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

## **Manual testing steps**

Because this PR moves the entire native floor (RN 0.81 / React 19 / Expo
54),
the surfaces most likely to regress are the ones that cross the
JS↔native
bridge or rely on WebViews, animations, and platform integrations. Run
the
scenarios below on **both iOS and Android** (release-style build
preferred so
LavaMoat lockdown and Hermes kick in).

```gherkin
Feature: RN 0.81 / React 19 / Expo 54 upgrade smoke

  Scenario: In-place upgrade from the latest production build
    Given a device with the latest store version of MetaMask Mobile installed
    And a wallet that has been used (multiple accounts, custom networks, contacts, NFTs, recent txs, push enabled, biometrics enabled)
    When the user installs this build over the existing one (without uninstalling)
    Then the app launches without crashing on cold start
    And redux-persist migrations run cleanly (no migration errors in logs)
    And accounts, custom networks, contacts, hidden tokens, NFT collections, transaction history, and address book entries are preserved
    And MMKV-backed storage opens (no "Failed to open MMKV" or version mismatch errors)
    And biometric unlock still works without re-prompting for a password reset
    And push-notification token registration still resolves
    And no data needs to be re-imported

  Scenario: In-place upgrade from an older minor (n-3 versions back)
    Given a device with a 3-versions-old build of MetaMask Mobile and a used wallet
    When the user installs this build over it
    Then the chained migrations execute in order with no errors
    And the same continuity assertions as above hold

  Scenario: Onboarding — create new wallet
    Given a fresh install
    When the user creates a new wallet, sets a password, and skips backup
    Then onboarding completes and the wallet screen renders without animation glitches
    And the BackHandler shim does not trigger duplicate goBacks on Android

  Scenario: Onboarding — import via SRP
    Given a fresh install
    When the user imports an existing 12-word SRP via "Import using Secret Recovery Phrase"
    Then accounts populate and the home screen loads with balances

  Scenario: Manual backup flow (Steps 1, 2, 3)
    Given a wallet that has not yet completed manual backup
    When the user walks through ManualBackupStep1 → 2 → 3
    Then the SRP is shown, verification succeeds, and Step 3 navigates to HomeNav without re-registering the Android back handler twice

  Scenario: Send ETH (legacy + EIP-1559)
    Given a funded EOA on Sepolia and Mainnet
    When the user sends ETH to another address using both legacy and 1559 gas
    Then the confirmation sheet renders, the user signs, and the tx appears in Activity → confirmed

  Scenario: Token send + ERC-20 approval
    Given a funded EOA with USDC on Mainnet
    When the user sends USDC and (separately) approves a spender via dApp
    Then both flows render their confirmation sheets correctly and the txs land

  Scenario: Swap (single-chain) + Bridge (cross-chain)
    Given a funded EOA
    When the user performs a Swap and a Bridge from the wallet UI
    Then quotes load, approvals (if needed) sign, the user can switch routes, and the txs land

  Scenario: Smart transactions (STX) on Mainnet
    Given an account with STX enabled
    When the user submits a swap eligible for STX
    Then the STX status sheet renders, polls, and resolves to confirmed without flicker

  Scenario: Transaction batching (EIP-7702 / 5792)
    Given a smart account that supports batched txs
    When the user signs a batch confirmation
    Then the batch appears in Activity with the correct sub-txs

  Scenario: Hardware wallet — Ledger BLE
    Given a Ledger device paired via BLE
    When the user signs an EVM transaction using the Ledger account
    Then the BLE connection succeeds, the user approves on-device, and the tx is broadcast

  Scenario: WalletConnect / SDK dApp connection
    Given a sample dApp (e.g. Uniswap testnet) on desktop
    When the user scans the QR with the in-app camera and connects via WalletConnect
    Then the connection request renders, methods (eth_signTypedData_v4, personal_sign, eth_sendTransaction) work end-to-end, and the dApp shows the wallet address

  Scenario: Deeplinks — universal links + custom scheme + cold/warm start
    Given the app is killed (cold) and separately, in the background (warm)
    When the user taps:
      | metamask://send?recipient=0x...                          | from another app |
      | metamask://buy?address=0x...&chainId=0x1                 | from another app |
      | metamask://swap?from=ETH&to=USDC                         | from another app |
      | metamask://wc?uri=wc:abcd...                             | from a dApp QR  |
      | https://metamask.app.link/wallet                         | universal link  |
      | https://metamask.app.link/buy?...                        | universal link  |
    Then each link routes to the correct screen on both cold and warm starts
    And in-app `Linking.openURL(...)` (e.g. ramp Buy widget, support links) opens the external browser correctly

  Scenario: In-browser dApp via the built-in Browser tab
    Given the wallet is unlocked
    When the user opens the in-app Browser, navigates to a dApp, and signs a tx
    Then the WebView renders, the provider injects, and signing flows work
    # exercises the @metamask/react-native-webview Fabric codegen patch

  Scenario: Snaps — install + invoke
    Given a Flask build with snaps enabled
    When the user installs a permissioned snap and invokes a method that opens a snap UI dialog
    Then the snap iframe loads under LavaMoat lockdown without "XMLSerializer is not a function" or scuttle errors and the dialog renders
    # exercises the @metamask/snaps-execution-environments LavaMoat patch

  Scenario: Buy/Sell ramps (in-app + external browser)
    Given a wallet unlocked and a quote available
    When the user purchases via Transak (in-app widget) and via an external-browser provider
    Then both routes complete; on the external path Linking.openURL or InAppBrowser is invoked correctly and Activity reflects the precreated order

  Scenario: Apple Pay / Google ACM
    Given the user has an Apple Pay card (iOS) or a Google account on device (Android)
    When the user triggers a flow that hits @metamask/react-native-payments (iOS) and Google ACM sign-in (Android)
    Then both native sheets present, complete, and return values to JS without crashing
    # exercises the @metamask/react-native-payments and @metamask/react-native-acm patches

  Scenario: Biometrics / Keychain unlock
    Given a wallet protected by biometrics
    When the user backgrounds the app, returns, and unlocks
    Then Face ID / Touch ID / Android biometric prompts present and unlock works on cold start, warm resume, and after switching networks

  Scenario: Push notifications (transaction notifications)
    Given push notifications enabled
    When an inbound tx confirms
    Then a notification arrives, deeplink tap-through navigates to the right activity row, and Sentry breadcrumbs do NOT show "[E2E Sentry Mock]" (verifies dev/prod env separation)

  Scenario: Token detail chart (TradingView WebView)
    Given the user opens a token detail (e.g. ETH) with MM_CHARTING_LIBRARY_URL set
    When the chart loads
    Then the TradingView library loads from CDN, the OHLC data renders, the crosshair pills work, and there is no "Failed to load TradingView library" error

  Scenario: BottomSheets, modals, and gestures
    Given any flow with a bottom sheet (account selector, network picker, confirmation, settings)
    When the user opens a sheet and rapidly taps the overlay 3-5 times
    Then the sheet closes once, the screen behind is unchanged (no double goBack — MUSD-406 regression check), and the swipe-to-dismiss gesture also works

  Scenario: Animations and Reanimated surfaces
    Given the user navigates onboarding → wallet → token → bridge → settings
    When the fox loader, onboarding success animation, carousel cards, and Rive-driven loaders play
    Then all animations render at 60fps with no warning spam and no crash on iOS 18 / Android 14+

  Scenario: Background restoration after long suspend
    Given the app is backgrounded for >15 minutes
    When the user resumes
    Then accounts, balances, and websocket connections (price feed, notifications) reconnect without leaking timers or duplicate listeners

  Scenario: SDK / WebSocket reconnection
    Given an active dApp connection and an active price-feed websocket
    When the user toggles airplane mode off→on→off
    Then both connections recover and txs/quotes flow again

  Scenario: Settings → Reveal SRP / Private Key
    Given an unlocked wallet
    When the user reveals the SRP and a private key from settings
    Then biometrics gate works, the secrets render correctly, and the "Hold to reveal" + scroll-on-iPhone-SE behaviors are unchanged

  Scenario: Power-user wallet (many accounts / tokens / NFTs)
    Given a power-user SRP imported (see internal SRPs)
    When the user navigates Wallet, Activity, NFTs, and switches networks
    Then list rendering, scrolling, and network switching remain smooth (FlashList 2 / RN 0.81 perf check)
```

The `[E2E Sentry Mock]` log line should NOT appear in any of the
dev/release
builds above; if it does, `IS_TEST=true` is leaking into the bundler
env.

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

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.




<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **High Risk**
> High risk because it updates core React Native/Android build toolchain
and introduces multiple Yarn patches to native dependencies, which can
affect app startup, native compilation, and E2E reliability across both
platforms.
> 
> **Overview**
> Upgrades the RN stack to `react-native@0.81.5` and aligns native build
tooling around it: Android moves to `compileSdk/targetSdk 36`, Kotlin
`2.1.20`, NDK `27.1`, Gradle `8.14.3`, updates app initialization to
`loadReactNative(this)`, and adds an MLKit dependency override plus
Detox flavor handling.
> 
> Stabilizes CI/E2E builds during the upgrade by forcing fresh native
caches (cache keys include `${{ github.run_id }}`), pinning CMake for
Android E2E builds, bumping iOS cache versions, increasing E2E timeout,
and restoring iOS app/framework execute permissions after artifact
download.
> 
> Introduces/updates multiple `.yarn/patches/*` to keep third-party and
MetaMask native modules building under RN 0.81 (Gradle/SDK bumps,
Kotlin/ObjC signature fixes, codegen metadata, safer JS snippets),
removes obsolete patches, and adjusts JS/TS code for React 19
typing/runtime changes (BackHandler subscription cleanup, stricter
`RefObject<T | null>`/`useRef` init, safer prop spreads/cloneElement
generics, default props moved to parameters, and test expectation
updates).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
c3c6e6e. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: BubbleTrouble14 <ronald.goedeke@outlook.com>
Co-authored-by: tommasini <tommasini15@gmail.com>
Co-authored-by: tommasini <46944231+tommasini@users.noreply.github.com>
Co-authored-by: Andre Pimenta <andrepimenta7@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: ieow <4881057+ieow@users.noreply.github.com>
Co-authored-by: Frederik Bolding <frederik.bolding@gmail.com>
Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
@pull pull Bot locked and limited conversation to collaborators May 7, 2026
@pull pull Bot added the ⤵️ pull label May 7, 2026
@pull pull Bot merged commit 4797726 into Reality2byte:main May 7, 2026
4 of 16 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.

5 participants