Skip to content

[pull] main from MetaMask:main#629

Merged
pull[bot] merged 19 commits intoReality2byte:mainfrom
MetaMask:main
Mar 25, 2026
Merged

[pull] main from MetaMask:main#629
pull[bot] merged 19 commits intoReality2byte:mainfrom
MetaMask:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Mar 25, 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 : )

metamaskbot and others added 19 commits March 23, 2026 18:37
…ce change after reconnection cp-7.70.1 (#27826)

- fix(perps): fix stale data and missing price change after reconnection
(#27530)

## **Description**

Two fixes for perps foreground reconnection:

1. **Stale data after background** — `connect()` returned early when
`isConnected=true` (grace period kept state alive) without checking if
the WebSocket was dead. Fixed by adding `ensureConnected()` that always
forces disconnect + reconnect on foreground return.

2. **Price change "–%" persists after reconnect** — Prewarm called
`subscribeToPrices()` without `includeMarketData`, so `assetCtxs`
subscriptions (which provide `prevDayPx` for `percentChange24h`) were
never re-established. Fixed by moving the `assetCtxs` subscription out
of the `includeMarketData` guard in `subscribeToPrices()`. This is safe
because `assetCtxs` is 1 subscription per DEX (2-3 total), not
per-symbol. The expensive per-symbol `activeAssetCtx` subscriptions
remain gated behind `includeMarketData`.

## **Changelog**

CHANGELOG entry: Fixed stale perps data and missing 24h price change
after returning from background

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Perps foreground reconnection

  Scenario: user returns after short background (grace period still active)
    Given user is on Perps screen with live data
    When user backgrounds app for 10s and returns
    Then data refreshes with live prices and positions
    And 24h price change % displays correctly (not "--%" )

  Scenario: user returns after long background (grace period already fired)
    Given user is on Perps screen with live data
    When user backgrounds app for 60s and returns
    Then data refreshes with live prices and positions
    And 24h price change % displays correctly (not "--%" )

  Scenario: initial mount unchanged
    Given user opens app fresh
    When user navigates to Perps
    Then connection establishes normally via connect()
    And 24h price change % displays correctly
```

## **Screenshots/Recordings**

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding

Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling

guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches perps WebSocket lifecycle and subscription behavior;
regressions could cause extra reconnects or missed/duplicated
subscriptions, though changes are scoped and covered by updated tests.
> 
> **Overview**
> Fixes perps reconnection reliability by switching foreground handling
from `connect()` to a new `PerpsConnectionManager.ensureConnected()`
that **cancels any grace period, force-disconnects, resets ref-count,
and reconnects**, deduplicating concurrent calls.
> 
> Restores 24h % change after reconnection/prewarm by ensuring
`HyperLiquidSubscriptionService.subscribeToPrices()` always establishes
lightweight per-DEX `assetCtxs` subscriptions even when
`includeMarketData` is false; price prewarm explicitly passes
`includeMarketData: false` and documents the N² connection risk.
> 
> Updates unit tests and architecture docs to reflect
`ensureConnected()` usage and the new subscription expectations.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
1549f85. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[1bf5d78](1bf5d78)

Co-authored-by: abretonc7s <107169956+abretonc7s@users.noreply.github.com>
…ure from dual-cache desync cp-7.70.1 (#27860)

- fix(perps): fix HIP-3 asset ID lookup failure from dual-cache desync
cp-7.70.1 (#27854)

## **Description**

Fix HIP-3 asset ID lookup failure (`"Asset ID not found for
xyz:BRENTOIL"`) that blocked trading on HIP-3 markets when navigating
via the old Perps tab layout.

**Root cause**: Dual-cache desync between `#cachedValidatedDexs` (string
DEX names) and `#cachedAllPerpDexs` (raw API objects for `perpDexIndex`
computation). The standalone preload path
(`#getStandaloneValidatedDexs`) populated one cache but not the other.
When `#buildAssetMapping` later ran, it found "xyz" in `dexsToMap` but
couldn't compute its `perpDexIndex` because `#cachedAllPerpDexs` was
null.

**Why old Perps tab vs new Homepage Sections**: Both layouts sit inside
`Wallet/index.tsx`, which calls `startMarketDataPreload()` on mount.
This fires standalone HTTP calls that populate `#cachedValidatedDexs`
but not `#cachedAllPerpDexs`.

- **New homepage sections**: `PerpsSectionWithProvider` mounts
immediately. Stream hooks fire `ensureReady()` before or concurrently
with the standalone preload. Since `#cachedValidatedDexs` is often still
null, `fetchValidatedDexsInternal` runs fresh and sets **both** caches
correctly.
- **Old tab layout**: The Perps tab doesn't mount until the user taps
it. By that time, `startMarketDataPreload()` has already completed →
`#cachedValidatedDexs` is populated by standalone. When the tab mounts →
`getValidatedDexs()` → **cache hit** → `fetchValidatedDexsInternal` is
never called → `#cachedAllPerpDexs` stays null → `buildAssetMapping`
can't find "xyz".

**Changes (1 file, 3 sites)**:

1. **Root cause fix**: `#getStandaloneValidatedDexs` now sets
`this.#cachedAllPerpDexs = allDexs` after a successful `perpDexs()`
call, keeping both caches in sync.
2. **Cache poisoning fix**: Removed `this.#cachedAllPerpDexs =
this.#cachedAllPerpDexs ?? [null]` from the catch block in
`#buildAssetMapping`.
3. **Cache poisoning fix**: Replaced persistent `if (!cache) { cache =
[null] }` with local `const allPerpDexs = cache ?? [null]` — consumers
read the cache, only the owner writes it.

## **Changelog**

CHANGELOG entry: Fixed a bug where closing positions on HIP-3 markets
(e.g., xyz:BRENTOIL) failed with "Asset ID not found" when navigating
via the Perps tab

## **Related issues**

Fixes: HIP-3 asset ID lookup failure on old Perps tab layout

## **Manual testing steps**

```gherkin
Feature: HIP-3 position management via Perps tab

  Scenario: user closes a HIP-3 position from the old Perps tab
    Given user has an open position on a HIP-3 market (e.g., xyz:BRENTOIL)
    And user is using the old tab layout (homepage redesign v1 disabled)

    When user navigates to the Perps tab
    And user taps close on the xyz:BRENTOIL position
    Then the position closes successfully without "Asset ID not found" error

  Scenario: user opens a HIP-3 position from the old Perps tab
    Given user is on the Perps tab (old layout)

    When user navigates to xyz:BRENTOIL market and places a market order
    Then the order executes successfully with correct asset ID routing
```

## **Screenshots/Recordings**

### **Before**

Metro logs show the desync:
```
getValidatedDexs CACHE HIT {"cachedAllNull": true, "dexs": [null, "xyz"]}
buildAssetMapping state  {"allPerpDexsLen": 1, "cachedAllNull": true}
Could not find perpDexIndex for DEX xyz
Asset ID not found for xyz:BRENTOIL
```

### **After**

Metro logs show both caches in sync:
```
buildAssetMapping state {"allPerpDexsLen": 8, "cachedAllNull": false, "dexsToMap": [null, "xyz"]}
Asset map state at order time {"assetExistsInMap": true, "hip3AssetsCount": 54, "totalAssetsInMap": 283}
Resolved DEX-specific asset ID {"assetId": 110049, "coin": "xyz:BRENTOIL"}
usePerpsClosePosition: Close result {"success": true, "orderId": "359617825254"}
```

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding

Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling

guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches HIP-3 market routing/asset-ID mapping in
`HyperLiquidProvider`, so a mistake could break trading on some perps
markets; scope is small and localized to cache population/fallback
behavior.
> 
> **Overview**
> Fixes a HIP-3 asset mapping failure where `#cachedValidatedDexs` could
be populated via the standalone preload path while `#cachedAllPerpDexs`
stayed `null`, leading to missing `perpDexIndex` during
`#buildAssetMapping`.
> 
> `#getStandaloneValidatedDexs()` now also populates
`#cachedAllPerpDexs` after a successful `perpDexs()` call, and
`#buildAssetMapping()` no longer “poisons” the shared cache with a
persistent `[null]` fallback (it uses a local fallback instead).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
c925609. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
[2898ec8](2898ec8)

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

Adds **7.70.1** release notes for hotfixes on `release/7.70.1`, and
updates changelog compare links per release process.

User-facing changes documented:

- Fixed stale perpetuals data and missing 24h price change after
returning from background
([#27530](#27530))
- Fixed a bug where closing positions on HIP-3 markets (e.g.,
xyz:BRENTOIL) failed with "Asset ID not found" when navigating via the
Perps tab
([#27854](#27854))

## Changelog

CHANGELOG entry: null

## Related

- Release PR:
[#27824](#27824)
(`release/7.70.1` → `stable`)
- Cherry-picks:
[#27826](#27826)
(reconnection),
[#27860](#27860) (HIP-3
/ dual-cache)

## Compare links

- `[Unreleased]` → `v7.70.1...HEAD`
- `[7.70.1]` → `v7.70.0...v7.70.1` (patch compares to previous minor
tag)
- Older version links (e.g. `[7.69.1]`) unchanged.

## Branch

- Merged current `release/7.70.1` into this branch so the changelog PR
stays aligned with
[#27824](#27824).

Merge with **Create a merge commit** (not squash), per release changelog
workflow.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: documentation-only change to `CHANGELOG.md` with no runtime
or build impact.
> 
> **Overview**
> Documents the `7.70.1` hotfix in `CHANGELOG.md`, adding two *Fixed*
items related to perpetuals market data refresh and HIP-3 perps position
closing.
> 
> Updates the changelog compare links so `Unreleased` now compares from
`v7.70.1`, and adds the new `7.70.1` compare URL.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
33bab8a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
…27694)

## **Description**

Adds OFAC compliance UI infrastructure under a new
`app/components/UI/Compliance/` feature directory, following the same
co-location pattern as `Earn`, `Bridge`, and `Perps`.

**What changed:**
- New `AccessRestrictedModal` BottomSheet component that informs users
when their wallet address has been flagged during compliance screening,
with a "Contact support" CTA
- New `AccessRestrictedContext` with `AccessRestrictedProvider` and
`useAccessRestrictedModal` hook for managing modal visibility from
anywhere in the app
- Moved `useWalletCompliance`, `useComplianceGate`, and
`useAccountGroupCompliance` hooks into the Compliance feature directory
(previously scattered under `app/components/hooks/`)
- Barrel `index.ts` exporting all compliance UI primitives
- Added `METAMASK_SUPPORT_URL` constant to `app/constants/urls.ts`
- Added localization strings under `access_restricted` key
- Added test IDs for E2E testing
- Updated `docs/compliance.md` file references to reflect the new
directory structure

**File structure:**
```
app/components/UI/Compliance/
├── AccessRestrictedModal/
│   ├── AccessRestrictedModal.tsx
│   ├── AccessRestrictedModal.types.ts
│   ├── AccessRestrictedModal.testIds.ts
│   └── index.ts
├── contexts/
│   └── AccessRestrictedContext.tsx
├── hooks/
│   ├── useWalletCompliance.ts
│   └── useWalletCompliance.test.ts
└── index.ts
```

## **Changelog**

CHANGELOG entry: Added access restricted modal that notifies users when
their wallet address has been flagged during compliance screening

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: Access restricted modal for compliance screening

  Scenario: user sees access restricted modal when wallet is flagged
    Given the user has a wallet address flagged during compliance screening
    And compliance is enabled via feature flag

    When the compliance screening triggers the access restricted modal
    Then a bottom sheet is displayed with the title "Access restricted"
    And a description explaining that some MetaMask services are unavailable
    And a "Contact support" button is visible

  Scenario: user taps contact support
    Given the access restricted modal is displayed

    When the user taps the "Contact support" button
    Then the modal closes
    And the user is navigated to the MetaMask support page in a webview

  Scenario: user dismisses the modal
    Given the access restricted modal is displayed

    When the user taps the close (X) button
    Then the modal closes
    And the user remains on the current screen
```

## **Screenshots/Recordings**

### **Before**

N/A — new component

### **After**

<img width="272" height="602" alt="Screenshot 2026-03-20 at 09 51 31"
src="https://github.com/user-attachments/assets/0ca5081f-d26f-4e33-a273-61e0a104c8df"
/>

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Adds a globally mounted compliance modal and auto-show/hide side
effects based on blocked-wallet status, which can affect navigation and
user flows if triggered incorrectly. Risk is moderate due to new
app-root provider wiring and behavioral changes tied to compliance
selectors/feature flag.
> 
> **Overview**
> Introduces a new **Compliance UI feature module** with an
`AccessRestrictedModal` bottom sheet (with test IDs + i18n strings) and
an `AccessRestrictedProvider`/`useAccessRestrictedModal` context to
control its visibility and route users to MetaMask support.
> 
> Wires the provider at the app root (`App.tsx`) and updates
`useAccountGroupCompliance` to automatically show/hide the modal when
the selected account group becomes blocked/unblocked. Adds
`METAMASK_SUPPORT_URL`, updates compliance docs paths, and expands unit
tests to cover modal rendering, context behavior, and the new
compliance→modal side effects.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9ee060a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**
This PR bumps @metamask/seedless-onboarding-controller from v8.1.0 to
v9.0.0.
* Replaced renewSeedlessControllerRefreshTokens with
revokePendingSeedlessRefreshTokens, which only calls
SeedlessOnboardingController.revokePendingRefreshTokens() after seedless
submitPassword during loginVaultCreation.
* Updated the E2E MockSeedlessOnboardingController: dropped
renewRefreshToken, added rotateRefreshToken.
* Tracks `Password Outdated Modal Viewed` when the password outdated
modal is shown.
* App.tsx: increased the checkIsSeedlessPasswordOutdated polling
interval from 5 to 10 minutes

Jira: https://consensyssoftware.atlassian.net/browse/TO-629
<!--
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: upgrade @metamask/seedless-onboarding-controller to
v9.0.0

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Seedless onboarding after seedless-onboarding-controller v9

  Scenario: Existing seedless user logs in after unlock
    Given the user has a seedless (social) wallet and completes login with password
    When the app finishes Keyring and Seedless submitPassword flow
    Then the wallet unlocks normally and no error is logged for pending OAuth token revocation

  Scenario: Lock and unlock seedless wallet
    Given the user is logged in with a seedless account
    When the user locks the app and unlocks with the correct password
    Then unlock succeeds and the app remains usable

```

## **Screenshots/Recordings**

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

### **Before**

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

### **After**

https://github.com/user-attachments/assets/9fbd12e7-4c4e-4eae-a127-97cca8e7cbdf




https://github.com/user-attachments/assets/dd41e8c5-11d9-4401-a170-fb88400a7367



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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it upgrades a major-version auth-related
dependency and changes the seedless unlock flow around OAuth refresh
token rotation/revocation.
> 
> **Overview**
> Upgrades `@metamask/seedless-onboarding-controller` from `^8.1.0` to
`^9.0.0` and updates the seedless unlock path to stop manually renewing
refresh tokens; it now only revokes any pending refresh tokens after
`SeedlessOnboardingController.submitPassword`.
> 
> Replaces the helper `renewSeedlessControllerRefreshTokens` (and its
15s delay) with `revokePendingSeedlessRefreshTokens`, updates the E2E
`MockSeedlessOnboardingController` API surface accordingly
(`rotateRefreshToken`), and increases the in-app seedless
password-outdated polling interval from 5 to 10 minutes.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
de8dc96. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
# 🚀 v7.70.1 Testing & Release Quality Process

Hi Team,
As part of our new **MetaMask Release Quality Process**, here’s a quick
overview of the key processes, testing strategies, and milestones to
ensure a smooth and high-quality deployment.

---

## 📋 Key Processes

### Testing Strategy
- **Developer Teams:**
Conduct regression and exploratory testing for your functional areas,
including automated and manual tests for critical workflows.
- **QA Team:**
Focus on exploratory testing across the wallet, prioritize high-impact
areas, and triage any Sentry errors found during testing.
- **Customer Success Team:**
Validate new functionalities and provide feedback to support release
monitoring.

### GitHub Signoff
- Each team must **sign off on the Release Candidate (RC)** via GitHub
by the end of the validation timeline (**Tuesday EOD PT**).
- Ensure all tests outlined in the Testing Plan are executed, and any
identified issues are addressed.

### Issue Resolution
- **Resolve all Release Blockers** (Sev0 and Sev1) by **Tuesday EOD
PT**.
- For unresolved blockers, PRs may be reverted, or feature flags
disabled to maintain release quality and timelines.

### Cherry-Picking Criteria
- Only **critical fixes** meeting outlined criteria will be
cherry-picked.
- Developers must ensure these fixes are thoroughly reviewed, tested,
and merged by **Tuesday EOD PT**.

---

## 🗓️ Timeline and Milestones

1. **Today (Friday):** Begin Release Candidate validation.
2. **Tuesday EOD PT:** Finalize RC with all fixes and cherry-picks.
3. **Wednesday:** Buffer day for final checks.
4. **Thursday:** Submit release to app stores and begin rollout to 1% of
users.
5. **Monday:** Scale deployment to 10%.
6. **Tuesday:** Full rollout to 100%.

---

## ✅ Signoff Checklist

Each team is responsible for signing off via GitHub. Use the checkbox
below to track signoff completion:

# Team sign-off checklist
- [ ] Mobile Platform

This process is a major step forward in ensuring release stability and
quality. Let’s stay aligned and make this release a success! 🚀

Feel free to reach out if you have questions or need clarification.

Many thanks in advance

# Reference
- Testing plan sheet -
https://docs.google.com/spreadsheets/d/1tsoodlAlyvEUpkkcNcbZ4PM9HuC9cEM80RZeoVv5OCQ/edit?gid=404070372#gid=404070372
This PR syncs the stable branch to main for version 7.7.0.1

*Synchronization Process:*

- Fetches the latest changes from the remote repository
- Resets the branch to match the stable branch
- Attempts to merge changes from main into the branch
- Handles merge conflicts if they occur

*File Preservation:*

Preserves specific files from the stable branch:
  - CHANGELOG.md
  - bitrise.yml
  - android/app/build.gradle
  - ios/MetaMask.xcodeproj/project.pbxproj
  - package.json

  Indicates the next version candidate of main to 7.72.0
…ing protection (#27799)

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Incoming native coin transfers (e.g. ETH, MATIC, BNB) were still shown
in the Activity feed whenever isTransfer was false, because existing
address-poisoning logic only applied to token transfers
(shouldShowTransferByAddress). That left a gap for dust / spoof incoming
native txs used in address-poisoning scams.

This change applies the same trust rule as incoming ERC-20 transfers
when the user holds the token: incoming native transfers with non-zero
value are shown only if the sender is trusted (any of the user’s own
accounts or an entry in the address book). Outgoing native transfers are
unchanged. Token transfers continue to use the existing isTransfer path.
Zero-value incoming txs are not treated as this native case, so other
activity rows are unaffected.

Implemented in app/util/activity/index.ts; covered by
app/util/activity/index.test.ts.

## **Changelog**

CHANGELOG entry: Hid incoming native coin transfers from unknown senders
in the Activity tab; transfers from your own accounts or address book
contacts still appear.

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: Activity incoming native transfer filtering

  Scenario: Incoming native from an unknown address does not appear
    Given the user is on an EVM account with Activity (unified transactions) open
    And the account has previously received a non-zero native transfer from an address that is not in the address book and not another wallet account
    When the user views the Activity list
    Then that incoming native transfer is not shown

  Scenario: Incoming native from an address book contact still appears
    Given the user has a contact in the address book who sends a non-zero native transfer to the selected account
    When the user views the Activity list
    Then the incoming native transfer is shown

  Scenario: Outgoing native transfer still appears
    Given the user sends native currency to any recipient
    When the user views the Activity list
    Then the outgoing transfer is shown

  Scenario: Incoming ERC-20 behavior unchanged
    Given the user receives a token transfer from an unknown address for a token they hold
    When the user views the Activity list
    Then behavior matches existing token poisoning rules (hidden unless trusted sender)
```

## **Screenshots/Recordings**

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

### **Before**
<img width="394" height="837" alt="Screenshot 2026-03-23 at 13 49 38"
src="https://github.com/user-attachments/assets/d2700d52-41f2-426c-ad75-920ea9e8d0d6"
/>

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

### **After**
<img width="389" height="837" alt="Screenshot 2026-03-23 at 13 49 48"
src="https://github.com/user-attachments/assets/a19d2a46-e779-4e6b-b51a-1b564eabfa22"
/>

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

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it changes core Activity feed filtering logic and
could unintentionally hide legitimate incoming native transactions if
trust/address-book state is incorrect; outgoing and zero-value cases are
explicitly preserved.
> 
> **Overview**
> Adds **incoming native transfer poisoning protection**:
`filterByAddress` and `filterByAddressAndNetwork` now treat non-token,
non-zero native transfers *to* the selected account as suspicious unless
the sender is in the trusted set (own accounts or address book).
> 
> Introduces helpers to detect positive native `txParams.value` and gate
visibility accordingly, and adds unit + smoke test coverage to ensure
unknown-sender incoming native transfers are hidden while
trusted/own-account and outgoing/zero-value cases remain visible.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8178903. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Split from #26651 to reduce CODEOWNERS fanout.

Batch: small-owners

- Restores `BridgeView.view.test.tsx` back to main (previous refactors
were unnecessary for this batch) and adds targeted
`eslint-disable-next-line` comments where
`@metamask/design-tokens/color-no-hex` was falsely flagging `#NNNNN`
issue references as colors.
- Fixes a duplicate `brandColor` import in `ThemeProvider.test.tsx` that
was breaking `yarn lint:tsc`.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: color-no-hex test updates

  Scenario: lint and tests pass
    Given the branch is checked out
    When I run yarn lint:tsc
    And I run yarn lint
    And I run yarn jest app/components/UI/Bridge/Views/BridgeView/BridgeView.view.test.tsx --runInBand --no-watchman
    And I run yarn jest app/component-library/providers/ThemeProvider/ThemeProvider.test.tsx --runInBand --no-watchman
    Then everything passes
```

## **Screenshots/Recordings**

### **Before**

N/A

### **After**

N/A

## **Pre-merge author checklist**

- [x] I've followed MetaMask Contributor Docs and MetaMask Mobile Coding
Standards.
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable (ran lint + targeted Jest)
- [ ] I've documented my code using JSDoc format if applicable
- [ ] I've applied the right labels on the PR (see labeling guidelines).
Not required for external contributors.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk because changes are limited to test files and linting
behavior (no production logic). Main risk is minor: test
expectations/snapshots could change due to different mocked theme
values.
> 
> **Overview**
> Updates multiple test suites to use the shared `mockTheme` from
`util/theme` (and `TextColor` for `ButtonBase` label color) instead of
ad-hoc hex colors or `lightTheme` imports, improving consistency and
reducing `color-no-hex` lint violations.
> 
> Adds targeted `eslint-disable-next-line
@metamask/design-tokens/color-no-hex` comments in
`BridgeView.view.test.tsx` where `#NNNNN` GitHub issue references were
being misinterpreted as hex colors, and fixes a `ThemeProvider.test.tsx`
import ordering/duplication issue that was breaking `yarn lint:tsc`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
9fb6c39. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**
This PR adds a missing mock for the digest API that was causing the
default fixture to change when a live call was made. Not only would the
default fixture change but the test would also fail because of the
missing mocked call.

<!--
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:
https://consensys.slack.com/archives/C087GPTR5HQ/p1774381269517849

## **Manual testing steps**
N/A

## **Screenshots/Recordings**

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

### **Before**
N/A
<!-- [screenshots/recordings] -->

### **After**
N/A
<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: test-only change that adds an additional default network
mock to prevent live Digest API calls and fixture drift during E2E runs.
> 
> **Overview**
> Adds a new default E2E mock (`DIGEST_API_MOCKS`) that intercepts `GET
https://digest.dev-api.cx.metamask.io/api/v1/market-overview*` and
returns an empty `200` response.
> 
> Wires this mock into `DEFAULT_MOCKS` so Digest requests are
consistently blocked in the baseline test fixture, avoiding live-call
failures and unintended fixture changes.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
25d8538. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Introduces a new PlaywrightAssertions helper with common visibility/text
expectations (including timeout defaults and duplicate-text handling) to
standardize Playwright/Appium assertions.

Updates swap/bridge QuoteView and wallet LoginView/WalletView Appium
flows to use PlaywrightAssertions.expectElementToBeVisible instead of
direct waitForDisplayed, adding explicit descriptions/timeouts and
adjusting some Playwright selectors (notably LoginView password/title
element targeting). Also adds a WalletView.waitForScreenToDisplay that
waits for the view to be ready on both Detox and Appium.

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

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

## **Pre-merge reviewer checklist**

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk product-wise since changes are confined to the test
framework, but it may impact Appium/Playwright E2E stability due to
updated selectors and new visibility waits/timeouts.
> 
> **Overview**
> Adds a new `PlaywrightAssertions` helper to standardize common
Playwright/Appium expectations (visible/not-visible and text
displayed/not-displayed) with default timeouts.
> 
> Migrates Appium flows in `QuoteView` and `LoginView` from ad-hoc
`waitForDisplayed` calls to
`PlaywrightAssertions.expectElementToBeVisible`, consistently passing
explicit timeouts/descriptions, and tightens some selectors (e.g.,
`LoginView` password input and title `exact` matching).
> 
> Introduces `WalletView.waitForScreenToDisplay()` with Detox and Appium
readiness checks, and exports `PlaywrightAssertions` from the framework
index for easier consumption.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
14fadad. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
….71.0 (#27919)

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

This PR is a bug fix for
#27916 where:
- In the AI Market Insights in Perps, the action buttons are wrong when
user has an open position: the action buttons should be the same in AI
market insight page and market page, ie. “modify” and “Close” when user
has an open position

Fix:
- When the user has an existing perps position, the MarketInsights
footer action buttons (Long/Short) are hidden since the relevant actions
(modify/close) live on the Perps market details page
- The "AI summary for information only" disclaimer is moved inline below
the feedback section when the footer is hidden, so it remains visible
- Position state is passed via route params (hasPerpsPosition) from the
caller rather than fetched async inside MarketInsightsView, preventing a
flash where buttons briefly appear then disappear while the position
loads

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

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: Fixed a bug that was causing incorrect Perps action
buttons to be displayed

## **Related issues**

Fixes: #27916

## **Manual testing steps**

```gherkin
- Open MarketInsights from token details → Swap/Buy buttons visible with disclaimer in footer
- Open MarketInsights from perps with no position → Long/Short buttons visible with disclaimer in footer
- Open MarketInsights from perps with an existing position → no footer buttons, disclaimer shown below "Was this helpful?"
- Verify no flash/layout shift on the perps + position flow
```

## **Screenshots/Recordings**

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

### **Before**

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


https://github.com/user-attachments/assets/0373c1bb-d433-4c9a-8768-117a40d98f9e



### **After**

<!-- [screenshots/recordings] -->
<img width="3699" height="3090" alt="SCR-20260325-nzfa"
src="https://github.com/user-attachments/assets/4b058c59-6df0-4d16-acf7-8d6bb839183f"
/>


## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UI/navigation tweak that changes which CTAs are shown based
on a new route param; main risk is incorrect param wiring causing
missing actions or disclaimer placement in the Perps insights flow.
> 
> **Overview**
> Fixes Perps AI Market Insights showing inappropriate `Long`/`Short`
CTAs when the user already has an open position.
> 
> Adds a `hasPerpsPosition` route param (set by
`PerpsMarketDetailsView`) and uses it in `MarketInsightsView` to **hide
the footer action buttons** for Perps-with-position while **keeping the
informational disclaimer visible** by moving it inline under the
feedback section for that case.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
833593b. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
This PR adds test app universal link support to facilitate testing
non-production builds

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

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

## **Pre-merge reviewer checklist**

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: this only broadens the set of recognized universal-link
hostnames and updates iOS associated-domain/Branch domain allowlists; no
auth, signing, or transaction logic changes.
> 
> **Overview**
> Adds support for additional **test app** universal-link domains
(including an alternate host) so non-production builds can open MetaMask
via `https://metamask.test-app.link` and
`https://metamask-alternate.test-app.link`.
> 
> Updates universal-link validation/host allowlists in
`handleUniversalLink` and deeplink utils, extends unit tests
accordingly, and fixes iOS `Info.plist`/entitlements domain lists to use
the `test-app.link` hostnames.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
2f29a9a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Adds the remote boolean flag **`tronClaimUnstakedTrxButtonEnabled`** so
we can hide the **claim** action on the Tron unstaked banner if
something goes wrong in production, without removing the banner copy.

**Why:** We need a safe kill switch for the claim CTA only.

**How:**

- Register the flag in `FeatureFlagNames` with default `false`
(missing/undefined → button hidden; opt-in).
- **`selectTronClaimUnstakedTrxButtonEnabled`** in
`app/selectors/featureFlagController/tronClaimUnstakedTrxButtonEnabled/`
reads merged remote flags (same pattern as other boolean flags).
- `TronUnstakedBanner` uses
`useSelector(selectTronClaimUnstakedTrxButtonEnabled)` and renders the
primary claim button only when the flag is `true`; title and description
stay visible when the button is hidden.
- Register the flag in
**`tests/feature-flags/feature-flag-registry.ts`** (`inProd: true`,
`productionDefault: false`) so CI/E2E mocks match production
client-config.

**Ops:** Ensure **`tronClaimUnstakedTrxButtonEnabled`** exists in
LaunchDarkly / client-config; set to **`true`** where the claim button
should appear.

## **Changelog**

CHANGELOG entry: Added a remote feature flag to control visibility of
the Tron unstaked TRX claim button on the token details banner.

## **Related issues**

Fixes: NEB-838

## **Manual testing steps**

```gherkin
Feature: Tron unstaked banner claim button behind remote flag

  Scenario: user views TRX token details with claimable unstaked balance and flag enabled
    Given a Tron account with TRX ready for withdrawal and remote flag `tronClaimUnstakedTrxButtonEnabled` is true (or overridden in dev tools)

    When user opens native TRX token details and the unstaked banner is shown
    Then the banner shows title, description, and the claim button, and tapping claim still triggers the existing flow

  Scenario: user views TRX token details when flag is off or unset
    Given the same balance state but `tronClaimUnstakedTrxButtonEnabled` is false, missing, or undefined in remote flags

    When user opens native TRX token details and the unstaked banner is shown
    Then the banner shows title and description but does not show the claim button
```

## **Screenshots/Recordings**

### **Before**

See prior screenshots on this PR (token details with banner).

### **After**

Feature flag disabled / enabled — screenshots attached in thread (banner
with and without claim CTA).

## **Pre-merge author checklist**

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

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
@pull pull Bot locked and limited conversation to collaborators Mar 25, 2026
@pull pull Bot added the ⤵️ pull label Mar 25, 2026
@pull pull Bot merged commit ef5e684 into Reality2byte:main Mar 25, 2026
2 of 37 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.