Skip to content

[pull] main from MetaMask:main#837

Merged
pull[bot] merged 12 commits into
Reality2byte:mainfrom
MetaMask:main
Jun 16, 2026
Merged

[pull] main from MetaMask:main#837
pull[bot] merged 12 commits into
Reality2byte:mainfrom
MetaMask:main

Conversation

@pull

@pull pull Bot commented Jun 16, 2026

Copy link
Copy Markdown

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

georgewrmarshall and others added 12 commits June 16, 2026 05:33
…enders (#31583)

## **Description**

`ToastContextWrapper` was passing an inline object literal `{ toastRef
}` as the `ToastContext.Provider` value on every render. Because
`Object.is` comparison on the new object always fails, all ~52
`ToastContext` consumers re-rendered whenever the wrapper re-rendered —
even though the underlying `toastRef` (a `useRef`) never changes.

Fix: wrap the value in `useMemo` with an empty dependency array. The ref
identity is stable by definition, so the memoized object is created once
and reused, eliminating the fan-out re-renders.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: #31290

## **Manual testing steps**

N/A — internal performance change with no UI or behavioral impact. The
same stable `toastRef` is passed through; toast show/hide/dismiss
behavior is unchanged.

## **Screenshots/Recordings**

N/A — no UI changes.

### **Before**

N/A

### **After**

N/A

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

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

- [ ] 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**
> Behavioral changes are limited to stable context identity and
design-system enum renames with no logic changes; dependency bump is a
minor semver update.
> 
> **Overview**
> **Memoizes `ToastContext` provider value** so `ToastContextWrapper` no
longer passes a new `{ toastRef }` object every render, which was
forcing all context consumers to re-render when the wrapper updated even
though `toastRef` is stable.
> 
> **Bumps `@metamask/design-system-react-native` from `^0.28.0` to
`^0.29.0`** (and `design-system-shared` in the lockfile) and updates
call sites that used removed severity enums: `IconAlertSeverity.Error` →
`Danger` in notifications and security trust UI, and
`AvatarIconSeverity.Error` → `Danger` on the bridge post-trade bottom
sheet, plus matching test fixtures.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
319377f. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…1589)

## **Description**

`TabsBar` animates the active-tab underline with two `Animated.timing`
calls both using `useNativeDriver: false`. Because `width` cannot use
the native driver, the entire `Animated.parallel` runs on the JS thread
— doing ~12 frames of layout work per tab switch. When the JS thread is
busy (tab content mounting, data fetching), the underline stutters
precisely when the user expects responsiveness.

This PR migrates the two `Animated.Value`s to Reanimated v3
`useSharedValue` + `withTiming` + `useAnimatedStyle`, running the
underline animation entirely on the UI thread. Reanimated can animate
`width` in a worklet, eliminating all per-frame JS involvement. The
`Animated.parallel` and its `currentAnimation` tracking ref are also
removed — Reanimated automatically cancels in-flight animations when a
new value is assigned.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: #31276

## **Manual testing steps**

```gherkin
Feature: TabsBar underline animation performance

  Scenario: user switches tabs while JS thread is busy
    Given the app is open on the Wallet screen with the default tab bar visible

    When user taps between tabs repeatedly
    Then the underline slides smoothly to the active tab with no stutter

  Scenario: underline initialises to the correct position on mount
    Given the app is opened fresh

    When the TabsBar renders
    Then the underline is positioned under the active tab without animation

  Scenario: underline tracks active tab in a scrollable tab bar
    Given a screen with many tabs (overflow/scrollable)

    When user taps a tab that is off-screen
    Then the tab bar scrolls and the underline moves to the correct position
```

## **Screenshots/Recordings**

N/A — internal performance change; underline appearance and position are
unchanged, only the thread it runs on differs.

### **Before**

Animation driven on JS thread via `Animated.parallel` with
`useNativeDriver: false`.


https://github.com/user-attachments/assets/25011515-404c-4154-a30c-3053d8765fdb

### **After**

Animation driven on UI thread via Reanimated `useSharedValue` /
`withTiming` / `useAnimatedStyle`.


https://github.com/user-attachments/assets/54696ded-4ad6-43ff-82ae-639100a69c32

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

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

## **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**
> Scoped UI animation refactor in a shared component library file;
visual behavior and tab logic are intended to stay the same with no auth
or data changes.
> 
> **Overview**
> **Migrates the `TabsBar` active-tab underline from React Native
`Animated` to Reanimated v3** so position and width animate on the UI
thread instead of the JS thread.
> 
> `Animated.Value` + `Animated.parallel` / `Animated.timing` with
`useNativeDriver: false` are replaced by `useSharedValue`, `withTiming`,
and `useAnimatedStyle`. The underline renders as `Reanimated.View` with
a shared animated style. **Manual animation cancellation**
(`currentAnimation` ref and stop calls on tab reset/unmount) is removed;
Reanimated replaces in-flight animations when new values are set.
**Behavior is unchanged**: first paint snaps the underline without
animation; later tab switches use a 200ms timing; scrollable bars still
scroll the active tab into view.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
31913d2. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Migrates every mobile-owned `KeyringController:withKeyring` and
`withKeyringUnsafe` call site to its V2 equivalent. Registers V2
builders for `LedgerKeyring`, `QrKeyring`, and `MoneyKeyring` alongside
the existing V1 builders, then switches `withLedgerKeyring`,
`withQrKeyring`, the snaps `getMnemonicSeed` helper, and the
`MoneyKeyring` builder's `getMnemonic` closure to call V2. Downstream V1
messenger allowlists for `MoneyAccountController` and
`MultichainAccountService` stay until those packages stop calling V1
internally (gated on snap-keyring's upstream V2 migration).

Bumps `@metamask/eth-money-keyring` to `^3.0.0` and
`@metamask/eth-qr-keyring` to `^2.1.0` for the V2 wrapper surface.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: N/A

## **Manual testing steps**

1. Build from this branch
2. Execute common account actions through the various hardware wallets
we support.
3. Confirm that they still work.


## **Screenshots/Recordings**

N/A

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

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

- [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]
> **High Risk**
> Touches vault keyring registration and hardware account
creation/unlock paths; regressions could break Ledger/QR connect,
derive, or permissions cleanup.
> 
> **Overview**
> Completes mobile’s move to **KeyringController V2** by registering V2
builders for Ledger, QR, and Money keyrings at wallet init and routing
Ledger/QR helpers through `withKeyringV2` instead of `withKeyring` /
`createIfMissing`.
> 
> **Wallet & keyring wiring:** `initializeWallet` now passes
`keyringV2Builders` from `getKeyringV2Builders()` (hardware wrappers
keyed by legacy types). The Money keyring’s `getMnemonic` path uses
`withKeyringV2Unsafe` and `KeyringType.Hd` against the HD V2 keyring.
Dependencies bump to `@metamask/eth-money-keyring` ^3.0.0 and
`@metamask/eth-qr-keyring` ^2.1.0, with new `tsconfig` paths for their
`/v2` entrypoints.
> 
> **Ledger & QR flows:** `withLedgerKeyring` / `withQrKeyring` ensure a
legacy-type keyring exists via `withController` + `addNewKeyring`, then
operate on V2 adapter instances. Unlock/add-account logic drops
`setAccountToUnlock` + `addAccounts(1)` in favor of `createAccounts`
(`bip44:derive-index` with `groupIndex` for HD mode, `custom` +
`addressIndex` when `getMode() === 'account'`). Permission cleanup and
account lists read `address` from `KeyringAccount` objects instead of
raw hex strings.
> 
> **Tests:** New coverage for wallet init and keyring builders; Ledger,
QR, and Connect QR Hardware tests updated for V2 mocks, concurrent
on-demand keyring creation, and the new account APIs.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
2340b00. 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: Charly Chevalier <charly.chevalier@consensys.net>
<!--
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.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**
This PR ensures that money deposit rows now show the **payment method**
(e.g. "Apple Pay", "Debit Card") instead of just the provider name when
one is available.

We've added a new hook `useFiatPaymentMethodName` which fetches the ramp
order for the deposit, and returns the method name included in that
order. This hook attempts to use cached state from RampsController when
available, but otherwise makes a request to get the data.

<!-- mms-check: type=text required=true -->

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

<!-- mms-check: type=changelog required=true blocking=true -->

<!--
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: Show method name in money account deposits

## **Related issues**

<!-- mms-check: type=issue-link required=true -->

Fixes: MUSD-980

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```gherkin
Feature: deposits show method name

  Scenario: user deposits with apple pay or credit card
    Given user has an active money account

    When user makes a money account deposit with apple pay / credit card
    Then the resulting activity row shows the apple pay / credit card as it's subtitle
```

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

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

### **Before**
<img width="590" height="551" alt="image"
src="https://github.com/user-attachments/assets/d0aa0244-d053-47a2-ae0c-01a841c4aaae"
/>

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

### **After**
<img width="414" height="492" alt="Screenshot 2026-06-15 at 19 44 03"
src="https://github.com/user-attachments/assets/3b257cbe-5ad4-4a8a-9807-ce6f5f6cb612"
/>

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

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

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

- [ ] 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.
…31648)

## **Description**

This PR fixes incorrect bet submission header content for Predict
moneyline markets, especially World Cup-style markets where the selected
outcome could show duplicated team names or the wrong avatar in preview
flows.

It introduces a shared buy-header formatter that normalizes neg-risk
moneyline selections back to consistent `Yes · <team or Draw>` labeling,
resolves the correct team logo for the selected side, and reuses that
logic across the standard buy preview, the preview sheet, and the
buy-with-any-token preview header. The PR also adds focused test
coverage for the new formatting behavior and draw handling.

## **Changelog**

CHANGELOG entry: Fixed incorrect Predict bet submission labels and icons
for moneyline markets.

## **Related issues**

Fixes: PRED-964

## **Manual testing steps**

```gherkin
Feature: Predict moneyline buy preview headers

  Scenario: User opens a moneyline market buy preview
    Given the user opens a Predict sports market with team-based moneyline outcomes
    When the user selects a team outcome and opens the buy preview
    Then the header shows "Yes" as the selected side label
    And the header keeps the selected team name as the descriptor
    And the header shows the selected team's logo instead of a generic outcome image

  Scenario: User opens the buy preview from the pay-with-any-token flow
    Given the user is in the Predict buy-with-any-token flow for a moneyline market
    When the user reaches the preview header
    Then the header uses the same normalized label and team logo as the standard buy preview

  Scenario: User selects a draw moneyline outcome
    Given the user opens a moneyline market that includes a draw outcome
    When the user previews the draw selection
    Then the header shows "Yes" as the selected side label
    And the descriptor is shown as "Draw"
```

## **Screenshots/Recordings**

### **Before**


https://github.com/user-attachments/assets/95e925dc-a89a-473f-9618-9750b85f1a11

### **After**


https://github.com/user-attachments/assets/366f3317-9278-48f5-b13d-4a59eafd796e

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

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

- [ ] 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.
…cp-7.82.0 (#31717)

## **Description**

Deeplinks that are resolved while the app is already unlocked are parsed
by `handleDeeplinkSaga`, which navigates into the post-login navigator
(`HomeNav` → `Main`) — e.g. `BrowserTabHome` for `/dapp` links and
`RampTokenSelection` for `/buy` links. When that navigator is not yet
mounted (cold start finishing, or foreground-from-locked), the
`navigate(...)` call fires before the target screen is registered with
React Navigation, so the action is dropped:

```
ERROR The action 'NAVIGATE' with payload {"name":"BrowserTabHome", ...} was not handled by any navigator.
Do you have a screen named 'BrowserTabHome'?
```

The deeplink is then silently lost (the browser / buy flow never opens).
This is dev-only as a *warning*, but the navigation action is dropped in
production too.

**Why the regression exists — context on #30857**

PR #30857 (`refactor: open deeplinks after unlock`) moved cold-start
deeplink handling to a reset-based "startup intent" path
(`navigateToPostUnlockHome` → `executeStartupDeeplinkIntent`), which
builds the navigator tree with `reset()` and therefore doesn't need a
readiness check. As part of that refactor it **removed the
navigation-readiness plumbing** (`MAIN_NAVIGATOR_READY` action, the
`mainNavigatorReadyStateMachine` saga latch, and
`parseDeeplinkAfterNavReady`).

That removal was safe *only* for cold-start, resolve-capable deeplinks.
It left the still-live `handleDeeplinkSaga` `navigate()` path **without
any readiness guard**, which is exercised by:
- warm-start / foreground-from-locked deeplinks, and
- actions that have no startup-intent `resolve` handler (e.g. `/buy`,
which always goes through the saga `navigate` path).

So the protection removed in #30857 was effectively removed by mistake
for these cases. This PR adds that guard back.

**Solution**

Re-introduce a navigation-readiness gate before the saga forks the
deeplink parse — but instead of resurrecting the redux-action +
saga-latch machinery, implement it as a small, self-contained,
**event-driven** util:

- `waitForNavigationReady()` resolves once `HomeNav` is present in the
root navigation state (using React Navigation's native
`navigationRef.isReady()` + `getRootState()`).
- It subscribes to React Navigation's `state` events (no polling),
resolves synchronously on the warm fast-path, and has a 5s timeout
safety net so a deeplink is never lost if navigation never reaches the
expected state.
- `handleDeeplinkSaga` `yield call(waitForNavigationReady)` before
`yield fork(parseDeeplink, ...)`.

No changes to `NavigationService` or new redux actions — the readiness
check lives entirely in the deeplink util.

## **Changelog**

CHANGELOG entry: Fixed deeplinks (e.g. dapp browser and buy links) being
silently dropped when opened while the app was launching or returning
from a locked state.

## **Related issues**

Refs: #30857

Fixes: N/A

## **Manual testing steps**

```gherkin
Feature: Open deeplinks while the app is launching / locked

  Scenario: Open a dapp deeplink from a locked/cold-started app
    Given the MetaMask app is force-closed (or backgrounded and locked)
    When I open "https://metamask.app.link/dapp/https://app.uniswap.org"
    And I unlock the wallet
    Then the in-app browser opens the dapp
    And no "NAVIGATE was not handled by any navigator" error is logged

  Scenario: Open a buy deeplink from a locked/cold-started app
    Given the MetaMask app is force-closed (or backgrounded and locked)
    When I open "https://link.metamask.io/buy?chainId=59144&amount=25"
    And I unlock the wallet
    Then the ramp buy flow opens
    And no "NAVIGATE was not handled by any navigator" error is logged

  Scenario: Open a deeplink while the app is already on Home (warm)
    Given the MetaMask app is unlocked and showing the wallet
    When I open a dapp/buy deeplink
    Then the destination opens immediately as before (no added latency)
```

Android:
```bash
adb shell am start -a android.intent.action.VIEW \
  -d "https://link.metamask.io/buy?chainId=59144&amount=25" io.metamask
```

## **Screenshots/Recordings**

### **Before**

N/A — deeplink dropped, browser/buy screen never opens; logs show
`NAVIGATE was not handled by any navigator`.

### **After**

N/A — destination opens after unlock.

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

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

- [ ] 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.

Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.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.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**
 
Fix using MUSD on Monad to deposit into money account

## **Changelog**

<!-- mms-check: type=changelog required=true blocking=true -->

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

<!-- mms-check: type=issue-link required=true -->

Fixes: https://consensyssoftware.atlassian.net/browse/CONF-1549

## **Manual testing steps**
NA

## **Screenshots/Recordings**
NA

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

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

- [ ] 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.
…t picker (#31624)

<!--
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.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**

No-fee (sponsored) tokens were available in the Money Account deposit
flow but not discoverable in the MM Pay payment picker. Users had to dig
into "Other assets" to find them, and the "No fee" labels were easy to
miss.

This PR makes sponsored tokens more discoverable by:
1. Adding a dedicated **no-fee token row** in the payment picker bottom
sheet (CRYPTO section) showing the highest-balance no-fee eligible token
2. Adding **"No fee" tags** on eligible tokens in both the bottom sheet
rows and the "Other assets" full token list
3. Updating the **default token selection** to prefer no-fee tokens over
the generic first-available fallback
4. Establishing **tag priority**: "No fee" takes precedence over "Last
used" when both apply

The no-fee token list is sourced from the existing
`earn-money-deposit-no-fee-tokens` LaunchDarkly flag via
`selectMoneyNoFeeTokens`.


<!-- mms-check: type=text required=true -->

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

<!-- mms-check: type=changelog required=true blocking=true -->

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

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

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

CHANGELOG entry: Added no-fee token discovery in payment picker with
dedicated row, tags, and default selection preference

## **Related issues**

<!-- mms-check: type=issue-link required=true -->

Fixes: https://consensyssoftware.atlassian.net/browse/CONF-1515

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```gherkin
Feature: No-fee token discovery in payment picker

  Scenario: user sees no-fee token row in payment picker
    Given the user has tokens with balances including at least one no-fee eligible token (e.g. USDC, USDT, aTokens)
    When user opens a deposit flow and taps the payment token selector
    Then the CRYPTO section shows the highest-balance token row AND a second row with the highest-balance no-fee token with a "No fee" tag
    And an "Other assets" row below both

  Scenario: no-fee tag appears in Other assets list
    Given the user has no-fee eligible tokens
    When user taps "Other assets" in the payment picker
    Then no-fee eligible tokens display a "No fee" tag next to their name
    And long token names truncate with ellipsis to keep the tag on the same line

  Scenario: no-fee tag priority over last used
    Given a token is both no-fee eligible and last used
    When user opens the payment picker
    Then only the "No fee" tag is shown (not "Last used")

  Scenario: default selection prefers no-fee token
    Given the user has no-fee eligible tokens with sufficient balance
    And no preferred token is set via feature flags
    When user opens a deposit flow
    Then a no-fee token is automatically selected as the default payment token

  Scenario: de-duplication when preferred token is no-fee
    Given the highest balance token is also a no-fee token
    When user opens the payment picker
    Then row 1 shows that token with "No fee" tag
    And row 2 shows the next highest-balance no-fee token (or is omitted if none exists)
```

## **Screenshots/Recordings**


https://github.com/user-attachments/assets/a763cd52-92ec-4902-aa63-392c24c8760b


<!-- mms-check: type=screenshot required=true -->

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

<!-- mms-check: type=checklist required=true -->

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

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

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

#### Performance checks (if applicable)

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

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

## **Pre-merge reviewer checklist**

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

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes default payment token selection and pay-with UI across deposit
flows; withdraw paths are guarded but automatic token logic is
business-critical.
> 
> **Overview**
> Surfaces **no-fee (sponsored) tokens** in MM Pay using the existing
`selectMoneyNoFeeTokens` flag, so users see them in the payment picker
without digging through “Other assets.”
> 
> Adds **`usePayWithNoFeeToken`** (eligibility, highest-balance pick
with optional exclude, `renderNoFeeTag`) and a reusable **`NoFeeTag`**.
The pay-with **crypto section** can show a dedicated no-fee row, sorts
token rows by balance, sets **`isNoFee`** on preferred/selected rows,
and skips no-fee UI on **withdraw** flows. **`PaymentMethodRow`** shows
a “No fee” tag when **`isNoFee`** is set, **ahead of** “Last used.”
> 
> **`Token` / `TokenList` / `Asset`** accept optional **`tagRenderers`**
so **PayWithModal** can label eligible tokens in the full list (with
layout tweaks for truncation). **`getBestToken`** in automatic pay-token
selection now prefers eligible no-fee tokens (min balance, not withdraw)
after feature-flag preferred tokens and before the generic first-token
fallback.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
b06ceaf. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…31723)

<!--
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.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**

<!-- mms-check: type=text required=true -->

Selling TRX in QuickBuy never produced a quote: the Receive picker only
offered cross-chain destinations (Tron → EVM/Solana), which the
aggregator can't route.
Regular Swap already supports TRX → USDT-on-Tron (same-chain), so this
admits the curated Tron USDT (`tron:728126428/trc20:TR7NHq…Lj6t`,
already in `DefaultSwapDestTokens`) as a receive destination.
- `useReceiveTokens`: let Tron through the `STABLECOIN_CANDIDATES`
filter and drop it from `NATIVE_ONLY_NON_EVM_CHAINS` (Tron now offers
USDT + native TRX;
Bitcoin stays native-only). Corrected the stale `useAssetMetadata`
comment, that lookup isn't on the receive-destination path.
- No other changes needed: pricing, quote building, default selection,
and the terminal-toast path already handle Tron. USDT-on-Tron is now the
default receive token for a TRX sale.

<img height="790" alt="Simulator Screenshot - iPhone 17 Pro - 2026-06-15
at 16 09 21"
src="https://github.com/user-attachments/assets/fac677e9-06f9-4548-9499-d04691169686"
/>

## **Changelog**

<!-- mms-check: type=changelog required=true blocking=true -->

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

<!-- mms-check: type=issue-link required=true -->

Fixes:

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

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

<!-- mms-check: type=screenshot required=true -->

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

### **Before**

NA

### **After**

NA

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

<!--
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
- [ ] 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.
…end for SRP users (#31389)

<!--
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.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section blocks the PR
check.

Sections without a directive are checked for structural presence only.
-->

## **Description**
SRP new-wallet users fire Wallet Setup Completed at Choose Password, but
marketing consent (and install deeplink UTMs) are only granted at Opt-in
Metrics.

This PR backfills acquisition params from the pending install deeplink
when marketing consent is granted, then attaches them to Wallet Setup
Completed before its first trackEvent(), not after the analytics queue.

* Jira: https://consensyssoftware.atlassian.net/browse/TO-824
<!-- mms-check: type=text required=true -->

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

<!-- mms-check: type=changelog required=true -->

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

<!-- mms-check: type=issue-link required=true -->

Fixes: https://consensyssoftware.atlassian.net/browse/TO-824

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```gherkin
Feature: Wallet Setup Completed deeplink attribution

  Scenario: SRP user receives full UTMs on Wallet Setup Completed after opt-in
    Given a fresh app install
    And the app is opened via install deeplink with utm fields
    When the user completes SRP new-wallet onboarding
    And opts in to metrics and marketing at Opt-in Metrics
    Then Wallet Setup Completed is sent once with all deeplink UTM fields
    And the event timestamp aligns with Opt-in Metrics (replayed), not Choose Password
```

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

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

### **Before**

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

### **After**
<img width="878" height="125" alt="Screenshot 2026-06-16 at 2 19 01 PM"
src="https://github.com/user-attachments/assets/b22caeb5-f2e3-48ef-aee2-7e08d81ccbcf"
/>

<img width="873" height="76" alt="Screenshot 2026-06-10 at 10 10 43 AM"
src="https://github.com/user-attachments/assets/e9091b45-7210-4862-93f8-fc09b1ecb160"
/>


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

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

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

- [ ] 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**
> Changes marketing attribution timing and buffered event replay;
incorrect behavior would misattribute acquisition data but does not
touch wallet security or funds.
> 
> **Overview**
> Fixes **Wallet Setup Completed** for SRP new-wallet users who opt in
to marketing only at Opt-in Metrics, after the event was already
buffered at Choose Password without install deeplink UTMs.
> 
> When marketing consent is granted,
**`persistAttributionFromPendingDeeplink`** writes UTM/acquisition
params from `pendingDeeplink` / `currentDeeplink` into Redux. That runs
from Opt-in Metrics, social Choose Password (when the marketing checkbox
is selected), and the marketing-attribution saga when data collection is
turned on.
> 
> Buffered pre–opt-in onboarding events are replayed through
**`scheduleBufferedOnboardingEventReplay`**, which staggers sends and
merges store-backed attribution into **Wallet Setup Completed** before
the first `trackEvent`. Replay is limited to users who opted into basic
usage. Social wallet completion now uses
**`getWalletSetupAttributionPropsFromStore`** instead of reading
attribution directly in the component.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8e53cc7. 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.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**
Refine the hardware-wallet swaps state machine and signing UI shipped in
#31441. This is an internal refactor that prepares the flow for bridge
integration (PR #31688) and is not user-facing on its own.

- Add `buildStartPayload` export that the bridge integration PR consumes
to construct the state machine's `Start` event from a bridge quote.
- Rewrite step lookup to find-by-kind instead of cursor-locked, so
signing/signed transitions resolve the correct step regardless of the
`currentStep` cursor.
- Fix `Retry`, `Disconnected`, and `TransactionFailed` transitions;
allow `TransactionFailed` from `Submitted`.
- `HwQrScanner`: back button now navigates back instead of invoking the
cancel handler.
- `StepConnectorLine`: enforce a minimum connector height and
absolute-fill the SVG so the line renders reliably at small heights.

<!-- mms-check: type=text required=true -->

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

<!-- mms-check: type=changelog required=true blocking=true -->

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you 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**

<!-- mms-check: type=issue-link required=true -->

Refs: https://consensyssoftware.atlassian.net/browse/MUL-1718

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

```gherkin
N/a not wired to be testable.
```

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

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

N/A — internal state-machine refactor and minor layout guards; no
meaningful user-visible visual delta to capture.

### **Before**

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

### **After**

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

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

<!--
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
- [ ] 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.
<!--
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.
-->
<!--
mms-check directive vocabulary — read by
.github/scripts/shared/pr-template-checks.ts
at module load to build the validation plan. Directives are invisible in
rendered
markdown and must NOT be removed or edited without updating the
validator registry.

  type=text           Section must contain non-placeholder prose.
  type=changelog      Section must have a valid CHANGELOG entry: line.
type=issue-link Section must have a Fixes:/Closes:/Refs: line with a
value.
type=manual-testing Section must have real testing steps or an explicit
N/A.
type=screenshot Section must have evidence (image/URL) or an explicit
N/A.
type=checklist Section must have all checkboxes consciously checked.
required=true|false Whether a missing/invalid section runs the validator
at all.
blocking=true|false Whether a failure of this check fails the CI
workflow.
Default: false — failures are shown as warnings in the sticky
                      comment but do not block the PR.

Sections without a directive are checked for structural presence only.
-->

## **Description**

<!-- mms-check: type=text required=true -->

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

Adds analytics coverage for the unified swaps/bridge post-trade status
modal so the funnel can measure when users see the modal, dismiss it, or
click a modal CTA after a trade.

This adds MetaMetrics event definitions for viewed, dismissed, and
button clicked events; normalizes post-trade statuses to `in_progress`,
`complete`, and `failed`; includes shared swap/bridge token and chain
properties; records modal open duration; and prevents CTA interactions
from also being counted as dismissals. It also tracks the merged
post-trade trending-token suggestion CTA as `trending_token` with the
clicked token metadata.

## **Changelog**

<!-- mms-check: type=changelog required=true blocking=true -->

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

<!-- mms-check: type=issue-link required=true -->

Refs:
[SWAPS-4569](https://consensyssoftware.atlassian.net/browse/SWAPS-4569)

## **Manual testing steps**

<!-- mms-check: type=manual-testing required=true -->

N/A - analytics-only change covered by focused unit tests.

## **Screenshots/Recordings**

<!-- mms-check: type=screenshot required=true -->

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

### **Before**

N/A

### **After**

N/A

## **Pre-merge author checklist**

<!-- mms-check: type=checklist required=true -->

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

- [ ] 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-4569]:
https://consensyssoftware.atlassian.net/browse/SWAPS-4569?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
@pull pull Bot locked and limited conversation to collaborators Jun 16, 2026
@pull pull Bot added the ⤵️ pull label Jun 16, 2026
@pull
pull Bot merged commit 8276fc8 into Reality2byte:main Jun 16, 2026
3 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.