[pull] main from MetaMask:main#837
Merged
Merged
Conversation
…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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )