Skip to content

[pull] main from MetaMask:main#720

Merged
pull[bot] merged 8 commits intoReality2byte:mainfrom
MetaMask:main
Apr 30, 2026
Merged

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

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Apr 30, 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 : )

javiergarciavera and others added 8 commits April 30, 2026 06:03
#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>
@pull pull Bot locked and limited conversation to collaborators Apr 30, 2026
@pull pull Bot added the ⤵️ pull label Apr 30, 2026
@pull pull Bot merged commit 51b6bbd into Reality2byte:main Apr 30, 2026
4 of 14 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.

8 participants