[pull] main from MetaMask:main#720
Merged
pull[bot] merged 8 commits intoReality2byte:mainfrom Apr 30, 2026
Merged
Conversation
#29119) …erformance testing - MainActionButton: Pressable → TouchableOpacity (fixes walletSwapButton not found in XCUITest) - SectionHeader: Pressable → TouchableOpacity (fixes section headers not accessible via testID on iOS) - TabBar: align accessibility props - TokenIcon: use standard RN Image for local PNG assets (fixes expo-image blocking parent TouchableOpacity in XCUITest) - RemoteImage: minor accessibility alignment These changes unblock iOS performance tests that rely on Appium/XCUITest element lookup via testID. <!-- 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: ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches core navigation/UI components and changes touchable/layout behavior (e.g., `SectionHeader`, `MainActionButton`, `TokenIcon`), which could cause subtle styling or interaction regressions despite being primarily accessibility-focused. > > **Overview** > Improves iOS XCUITest/Appium discoverability by adjusting accessibility/testID behavior across shared components. > > `MainActionButton` now forwards `testID` to the inner `Pressable` and adds a new `containerStyle` prop for styling the outer `Animated.View` (tests updated accordingly). `SectionHeader` is refactored to use a `TouchableOpacity` wrapper when pressable, replaces `ButtonIcon` with `Icon` (with a dedicated `section-header-arrow-icon` testID), and tweaks container layout/justifyContent handling. > > `TabBar` simplifies wallet tab navigation params, `RemoteImage` marks the underlying `expo-image` as `accessible={false}`, and `TokenIcon` switches to React Native `Image` for local bundled assets while keeping `RemoteImage` for remote URLs to avoid iOS accessibility tree issues. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 90e00a1. 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**
Fix split view when user is ranked beyond 20
<!--
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:
## **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] -->
### **Afte
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-04-29 at 11 42 57"
src="https://github.com/user-attachments/assets/cb3087a4-dcbf-451c-a323-b536daed590f"
/>
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-04-29 at 11 43 00"
src="https://github.com/user-attachments/assets/6f5a814c-e004-47f4-a062-f9c0c163e725"
/>
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-04-29 at 11 49 13"
src="https://github.com/user-attachments/assets/dbdb97a4-3f38-4663-9767-654e165229eb"
/>
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-04-29 at 11 49 19"
src="https://github.com/user-attachments/assets/58a80e5d-507b-41e7-9dfe-88d38def0d30"
/>
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-04-29 at 11 50 03"
src="https://github.com/user-attachments/assets/ad5d52fa-16dd-4d52-bdd7-06813d0c4099"
/>
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-04-29 at 11 50 10"
src="https://github.com/user-attachments/assets/acb03dfa-4b6c-4183-ae04-71ab72dc9c9e"
/>
r**
<!-- [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)
- [x] I've tested on Android
- Ideally on a mid-range device; emulator is acceptable
- [x] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [x] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Small, UI-only logic changes (list slicing and stat formatting) with
added test coverage; low chance of impacting core rewards data or flows.
>
> **Overview**
> Fixes Ondo rewards leaderboard *split view* rendering when the current
user is just beyond the first page of results.
>
> `OndoLeaderboard` now dynamically chooses how many “top” rows to show
above the neighbor separator (preview stays at 3; full view shows 18 for
ranks 21–22, otherwise 20), with new tests covering these edge ranks.
Separately, `OndoCampaignStatsView` clamps displayed qualified days to
the required maximum so the “days held” stat never exceeds the campaign
requirement.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5594d61. 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** Adds buy/sell dot markers to the price chart on the Trader Position view, mapping each trade's timestamp to the nearest price-data index on the chart line. <img height="800" alt="Simulator Screenshot - iPhone 17 Pro - 2026-04-29 at 11 44 47" src="https://github.com/user-attachments/assets/beeda603-8f8f-42a6-b778-64c9a5159776" /> <img height="800" alt="Simulator Screenshot - iPhone 17 Pro - 2026-04-29 at 11 46 14" src="https://github.com/user-attachments/assets/e5d58dc6-3871-411f-bbbe-705e4163b662" /> Why some markers may not appear: Trade predates the chart's price data, because the price API window may start later (recently-listed token). Trades before the first price point are correctly excluded since plotting them at a position the chart isn't drawing would be misleading. Multiple trades collapse to the same index, on wider timeframes (1M: ~6h candle spacing), trades that are hours apart on the same day snap to the same nearest index and stack. ## **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: 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** > Introduces a new chart implementation with custom touch/overlay rendering and timestamp-to-index mapping, which could affect chart correctness and performance on edge-case data windows; changes are UI-only but non-trivial. > > **Overview** > Adds a dedicated `TraderPriceChart` to the Trader Position view that overlays buy/sell trade markers on the price line by mapping each trade timestamp to the nearest historical price index (dropping out-of-window trades and normalizing seconds vs ms timestamps). > > Wires the filtered `trades` list through `TraderPositionView` → `TraderPositionChartSection`, suppresses the chart end-dot when recent trade markers would overlap it, and adds focused unit tests for both the marker-mapping logic and chart rendering behavior. Separately, the homepage Top Traders carousel cards switch from fixed heights to `h-auto` (including skeletons and “View more”) to avoid hard-coded tile height constraints. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit f086b5b. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Bump `snaps-controllers` in preparation for breaking changes to the `accounts-controller`. There should be no functional difference in behaviour. ## **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** https://consensyssoftware.atlassian.net/browse/WPC-988 <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk dependency-only change; behavior should remain unchanged but could surface regressions if the updated snaps controller package has subtle internal changes. > > **Overview** > Updates the `@metamask/snaps-controllers` dependency from `^20.0.1` to `^20.0.3`. > > Refreshes `yarn.lock` to pin `snaps-controllers@20.0.3` (including updated lockfile metadata like peer dependency range for `@metamask/snaps-execution-environments`). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 4408d56. 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**
Fix two CI E2E bugs:
iOS smoke tests not running on push-to-main — ios-tests-ready was
missing !cancelled() in its if:, causing GitHub's implicit success()
wrap to skip it when smart-e2e-selection was skipped (push events).
Added !cancelled() && to match the Android gate pattern.
Scheduled runs crashing with "Argument list too long" —
ALL_CHANGES_FILES was always injected as an env var, but on
schedule/push events dorny/paths-filter emits the full repo file list
(no diff baseline), overflowing ARG_MAX. The variable is only consumed
on PR events, so it's now conditionally empty otherwise.
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
## **Changelog**
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry:
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
### **After**
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
<!--
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
- [ ] 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
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Touches GitHub Actions conditions and env wiring for E2E selection,
which can inadvertently skip or over-trigger CI runs if misconfigured,
but the changes are small and localized to CI logic.
>
> **Overview**
> Fixes a couple of CI edge cases that were preventing E2E coverage from
running reliably on non-PR events.
>
> In `ci.yml`, updates the `ios-tests-ready` gate to include
`!cancelled()` so iOS smoke tests still run on `push`/`schedule` flows
where upstream jobs may be skipped/cancelled implicitly. In
`get-requirements.yml`, stops exporting `ALL_CHANGES_FILES` on non-PR
events to avoid scheduled/push runs injecting a full-repo file list and
hitting “argument list too long”.
>
> Also adjusts fixture-validation reporting to **only** comment on
actionable findings (failure without results or structural changes),
while always deleting prior fixture-validation comments so passing runs
clear stale warnings; and updates the E2E decision-tree doc to match the
current “ignorable-only” behavior.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
bed2466. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ient balance (#29490) ## **Description** This pull request enhances the logic and test coverage for the `useShouldRenderGasSponsoredBanner` hook, ensuring that gas sponsorship banners are only shown for same-chain (swap) flows and never for cross-chain bridges, even if the source network is sponsored. The changes include updates to both the implementation and the associated tests, adding clear handling for same-chain vs. cross-chain scenarios. Key changes: **Feature Logic Update:** * Updated `useShouldRenderGasSponsoredBanner` to check if the source and destination tokens are on the same chain (`isSameChain`), restricting gas sponsorship to same-chain swaps only. Cross-chain bridges will not show the sponsored banner, regardless of sponsorship status. **Selector and Hook Integration:** * Added usage of `selectDestToken` alongside `selectSourceToken` to access both source and destination token information, enabling the new same-chain check. **Test Enhancements:** * Refactored tests to use a new `mockTokens` helper, allowing simulation of various same-chain and cross-chain scenarios by mocking source and destination chain IDs. * Expanded and clarified test cases to explicitly cover both same-chain and cross-chain logic, including updates to the truth table and additional edge cases. * Improved test descriptions and assertions to make the intent and coverage of each scenario clearer, and ensured that the correct chain IDs are passed to mocked hooks. These changes make the sponsorship logic more robust and the tests more comprehensive and maintainable. ## **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: hide sponsored label on cross-chain bridge with insufficient balance ## **Related issues** Fixes: Sponsored label is shown on bridge trx when amount above the max owned is entered ## **Manual testing steps** ```gherkin 1. Start the bridge scenario 2. Try to bridge Sei/Mon to any other network 3. Enter Sei/Mon amount above the max owned 4. Notice there is no more "Paid by Metamask" info in the network fee field ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <img width="300" height="550" alt="BEFORE" src="https://github.com/user-attachments/assets/2b62266d-5abc-42ce-ae93-d5652d3423c6" /> ### **After** <img width="300" height="550" alt="AFTER" src="https://github.com/user-attachments/assets/83a22197-a2e6-471a-9c50-a35951c53f3e" /> ## **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] > **Low Risk** > Low risk UI-logic change that only tightens the conditions for showing the gas sponsorship banner; main risk is unintentionally hiding the banner if token chain IDs are missing or mis-selected. > > **Overview** > Updates `useShouldRenderGasSponsoredBanner` to only show the gas sponsorship banner when the flow is **same-chain** (source and destination token `chainId` match), preventing the banner from appearing on cross-chain bridges even if the source network is sponsored. > > Expands/refactors tests to mock both source/destination tokens via `selectSourceToken`/`selectDestToken`, and adds explicit coverage for same-chain vs cross-chain scenarios (including an updated truth table and realistic cases). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 420fedd. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> The `Unified SwapBridge Submitted` and `Unified SwapBridge Completed` analytics events were missing the destination token's security classification, so we could not measure how often users proceed with risky tokens. They also had no source/destination token addresses on the `Submitted` event for cross-event joins. This PR threads the destination token's security type end-to-end into the unified-swap analytics events, including from the trending-tokens entry point (which uses a different `securityData` shape). **Changes:** 1. **Bump bridge controllers** to pick up the new `tokenSecurityTypeDestination` parameter on `BridgeStatusController.submitTx` / `submitIntent` and the `token_address_source` / `token_address_destination` / `token_security_type_destination` properties on the pre-confirmation event payload. - `@metamask/bridge-controller`: `^70.0.0` → `^71.0.0` - `@metamask/bridge-status-controller`: `^71.0.0` → `^71.1.0` 2. **Surface the field for analytics** in `useUnifiedSwapBridgeContext` (`token_security_type_destination`, `security_warnings`) and pass it through `useSubmitBridgeTx` to both `submitTx` and `submitIntent`. 3. **Close the trending-token data gap.** Trending tokens carry `securityData` in the trending-API shape (`TokenSecurityData`: `resultType` + top-level `features`), which doesn't match the bridge's legacy `SecurityData` shape (`type` + `metadata.features`). Two pieces: - Added `securityData?: TokenSecurityData` to `TokenI` so the read at the Token Details → Bridge boundary is type-safe. - Added `adaptTokenSecurityData()` in `tokenSecurityUtils` and applied it at the only two boundary sites in `useTokenActions` (`getSwapTokens` and `currentTokenAsBridgeToken`) so all downstream Bridge consumers continue reading the legacy shape they already understand. No widening of `BridgeToken.securityData` was required. **Bonus side-effect of step 3:** `SwapsConfirmButton`'s warning banner and modal now also render correctly for trending-token destinations classified `Warning` / `Malicious` / `Spam`, since they reach `destToken.securityData` in the shape the banner already reads. ## **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: [SWAPS-4422](https://consensyssoftware.atlassian.net/browse/SWAPS-4422) ## **Manual testing steps** ```gherkin Feature: Destination token security type reaches unified-swap analytics Scenario: user swaps from a trending token classified as Warning/Malicious/Spam Given the user has opened the Bridge view And the trending tokens section is visible And one of the trending tokens carries securityData with resultType "Warning" When the user taps that trending token And the user taps "Convert" / "Swap" on the Token Details screen And the user enters a source amount and confirms the swap Then the SwapsConfirmButton renders the security warning banner before confirmation And the "Unified SwapBridge Submitted" Mixpanel event includes: | property | value | | token_security_type_destination | Warning | | token_address_source | <CAIP source asset id> | | token_address_destination | <CAIP destination asset id> | | security_warnings | <list of feature descriptions> | And the "Unified SwapBridge Completed" event includes the same security_type_destination Scenario: user swaps to a destination token with no security data Given the user has opened the Bridge view And the user picks any source and destination token without securityData When the user enters a source amount and confirms the swap Then the "Unified SwapBridge Submitted" event property token_security_type_destination is null ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** N/A ### **After** https://github.com/user-attachments/assets/e93b9542-603d-4faa-9f14-f36cb199484b ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- Generated with the help of the pr-description AI skill --> [SWAPS-4422]: https://consensyssoftware.atlassian.net/browse/SWAPS-4422?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches swap/bridge transaction submission plumbing and controller interfaces (plus dependency bumps), so incorrect threading/mapping could silently skew analytics or break submissions on certain paths. > > **Overview** > Adds `token_security_type_destination` to the `useUnifiedSwapBridgeContext` analytics payload and threads the same value (`tokenSecurityTypeDestination`) through `useSubmitBridgeTx` into `BridgeStatusController.submitTx`/`submitIntent`. > > Introduces `adaptTokenSecurityData()` to convert trending-token `TokenSecurityData` into the bridge’s legacy `securityData` shape, uses it when converting `TokenI` to `BridgeToken` in Token Details swap entry points, and updates types/tests plus initial background state accordingly. Also bumps `@metamask/bridge-controller` and `@metamask/bridge-status-controller` to versions that accept/emit these new analytics fields. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit c6f918c. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…29545) ## Summary Adds `captureException` to six targeted catch blocks across the rewards controller and hooks. Scoped intentionally to avoid noise — only errors that are either user-facing, represent rare high-severity auth failures, or are unexpected outer-catch escapes from flows with visible user impact. ### Instrumented locations | Location | Context tag | When it fires | |---|---|---| | `useCandidateSubscriptionId` catch | `candidateSubscriptionId.fetch_failed` | Every time the auth-failed modal is shown to the user | | `RewardsController.performSilentAuth` non-401 branch | `performSilentAuth.unexpected_error` | Unexpected server errors (e.g. 500s) during silent auth — rare | | `RewardsController.#withAuthRetry` reauthError catch | `withAuthRetry.reauth_failed` | 403 recovery itself throws, forcing cache invalidation — very rare | | `RewardsController.#optIn` outer catch | `optIn.unexpected_error` | Unexpected failures after inner InvalidTimestamp/AlreadyRegistered handling | | `RewardsController.linkAccountToSubscriptionCandidate` catch | `linkAccountToSubscriptionCandidate.failed` | Unexpected failures after inner retry/recovery handling | | `RewardsController.optOut` catch | `optOut.failed` | API 500s or network errors during opt-out | All events tagged `{ feature: 'rewards', context: '<location>' }`. The three captures with an `InternalAccount` in scope also emit `extra: { accountType }` (chain namespace, e.g. `eip155:eoa`) for filtering by account kind without exposing PII. ## Changelog CHANGELOG entry: null 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Primarily adds observability side effects in error paths without changing success-path behavior; low risk aside from potential for minor telemetry noise or additional overhead when failures occur. > > **Overview** > Adds targeted Sentry error reporting to rewards flows by calling `captureException` in select catch blocks across `useCandidateSubscriptionId` and `RewardsController` (silent auth unexpected failures, 403 reauth retry failures, opt-in/linking failures, and opt-out failures), consistently tagged with `{ feature: 'rewards', context: ... }` and including `accountType` as extra where available. > > Updates and extends unit tests to mock Sentry and assert the new `captureException` calls (including new coverage for non-401 silent-auth login errors and other unexpected failure cases). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit ccf3146. 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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )