[pull] main from MetaMask:main#823
Merged
Merged
Conversation
## **Description** Integrating our new `SnapAccountService` before we start migrating the old `SnapKeyring` with the new `SnapKeyringV2`. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: N/A ## **Manual testing steps** Not applicable ## **Screenshots/Recordings** Not applicable ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [x] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] 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] > **High Risk** > Touches snap keyring creation, permission RPC keyring hooks, and multichain routing—security-sensitive paths where regressions could break snap accounts or deadlock keyring access. > > **Overview** > Wires **`@metamask/snap-account-service`** into the Engine as a first-class context module (init, scoped messenger, stateless registration) so snap account lifecycle and keyring messaging can live in one place ahead of **SnapKeyringV2**. > > **Snap keyring access** no longer duplicates `KeyringController:getKeyringsByType` / `addNewKeyring` in Engine, multichain routing, or snap permission specs. Callers use **`SnapAccountService:getLegacySnapKeyring`** and **`handleKeyringSnapMessage`** instead; **`AccountsController`** now listens for **`SnapAccountService:*`** account update events rather than legacy SnapKeyring constants. > > **Onboarding gating** for snaps is extracted to shared **`ensureOnboardingComplete`** (used by SnapController and SnapAccountService init). **Mnemonic / keyring** paths in snap permissions move to **`withKeyringV2Unsafe`** and v2 HD/Ledger types. Dependency bumps include **`accounts-controller`**, **`multichain-account-service`**, **`keyring-sdk`**, and new **`snap-account-service`**, plus **tsconfig** path aliases for keyring v2 packages. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 72523b4. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…sufficient funds (#31450) ## **Description** When selling the **entire** balance of a near-$1 source token (e.g. mUSD) via QuickBuy's "Sell" flow, the trade was incorrectly blocked with an **"Insufficient funds"** button state. **Root cause:** the QuickBuy "Sell" flow is fiat-first. When the slider is dragged to 100%, the committed amount was reconstructed through a lossy fiat round-trip: `balance → USD (rounded to 2 decimals via .toFixed(2)) → tokens (usd / currencyExchangeRate)`. Because the exchange rate of these tokens is fractionally below `1`, dividing the cent-rounded USD value back into tokens yields an amount **slightly larger** than the actual on-chain balance (e.g. `0.10003 MUSD` balance → `$0.10` → `0.10003001… MUSD`). `useIsInsufficientBalance` then compared this inflated amount against the true atomic balance and flagged the trade. The unpriced slider path had the same class of issue via `parseFloat` reconstruction. **Fix:** an `isMaxSourceAmount` sentinel. When the slider is committed at 100% ("sell all"), `sourceTokenAmount` now returns the exact `latestSourceBalance.displayBalance` (which is `formatUnits(atomicBalance, decimals)` and therefore round-trips back to the precise atomic balance) instead of the reconstructed value. The flag is set at the priced commit (`handleSliderDragEnd`) and the unpriced commit (`handleSliderChange`), and cleared on custom typed input and on amount reset (token switch / mode flip). This fixes both the priced (reported mUSD) and unpriced paths. ## **Changelog** CHANGELOG entry: Fixed a bug where selling your entire balance of a token in QuickBuy could be incorrectly blocked with an "Insufficient funds" error. ## **Related issues** Fixes: TSA-650 ## **Manual testing steps** ```gherkin Feature: QuickBuy sell-all does not falsely report insufficient funds Scenario: Selling the entire balance of a near-$1 token Given I hold a small balance of a near-$1 token (e.g. mUSD) whose exchange rate is fractionally below 1 And I open the QuickBuy sheet and select the "Sell" tab And I have selected a token to receive (e.g. ETH) When I drag the amount slider all the way to 100% (sell all) Then the headline shows my full balance and its fiat value And the confirm button is enabled (NOT "Insufficient funds") And submitting the trade sells the exact on-chain balance Scenario: Selling a partial amount still works When I drag the slider to a value below 100% Then the amount is derived from the fiat value as before And the confirm button reflects the correct sufficient/insufficient state ``` ## **Screenshots/Recordings** ### **Before** <!-- See linked ticket: dragging the slider to 100% ("sell all") on a near-$1 token shows "Insufficient funds" and blocks the trade. --> ### **After** <!-- Slider at 100% spends the exact balance; the confirm button is enabled. Verified via unit tests in useQuickBuyController.test.ts (66/66 passing, incl. 4 new cases). On-device recording N/A for this logic-only fix. --> N/A — logic-only fix covered by unit tests; no visual change beyond the button no longer being erroneously disabled. ## **Pre-merge author checklist** <!-- mms-check: type=checklist required=true --> - [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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Localized QuickBuy amount derivation and balance checks; no auth or payment-rail changes, with new unit tests covering the regression. > > **Overview** > Fixes QuickBuy **sell-all** falsely showing **Insufficient funds** when the slider is committed at **100%**. > > The change adds an **`isMaxSourceAmount`** flag so **`sourceTokenAmount`** uses **`latestSourceBalance.displayBalance`** (exact on-chain balance) instead of amounts rebuilt from **cent-rounded USD** or **float slider math**, which could exceed the real balance for near-$1 tokens. The flag is set on **priced** slider commit (`handleSliderDragEnd`, including **before** the USD dedup guard so typed-max then slide-to-100% still works) and on the **unpriced** path (`handleSliderChange`), and cleared on **reset**, **custom input**, and non-100% slider moves. **`useLatestBalance`** is moved earlier so max mode can use it in the memo. **Four unit tests** cover the stablecoin round-trip scenario. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 903b931. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> Migrate `Skeleton` component (predict team). ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-465 ## **Manual testing steps** ```gherkin Feature: skeleton migration Scenario: user checks prediction Given the user on prediction page When user clicks yes for a prediction Then skeleton should be visible ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <img width="1206" height="2622" alt="image" src="https://github.com/user-attachments/assets/82e49081-c108-4588-b972-df29cc8acc48" /> ### **After** <img width="1206" height="2622" alt="image" src="https://github.com/user-attachments/assets/f41fa30c-1245-4114-9340-b9b9799f6130" /> ## **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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Import-only design-system path updates with no behavior changes; low regression risk beyond loading UI appearance if the temp Skeleton API differs. > > **Overview** > Updates Predict buy flow UI to import **Skeleton** from `component-library/components-temp/Skeleton` instead of the legacy `components/Skeleton` path. > > **PredictBuyAmountSection** and **PredictFeeSummary** keep the same loading placeholders; only the module path changes. The **PredictBuyAmountSection** test mock is updated to match the new import. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 20d9b1d. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** The transfer button on the Money home view used to be tappable even when the account had no spendable balance, letting people start a transfer they couldn't complete. It's now disabled until there's a real, spendable balance. "Spendable" means a balance value is loaded and is at least one cent — sub-cent dust no longer counts as funded, since mUSD is USD-pegged and anything below a cent is economically meaningless. This same threshold now drives the funded/unfunded state, so the earnings, how-it-works, and what-you-get sections stay consistent with the button and with the Money balance displayed to the user. `MoneyActionButtonRow` was reworked to take per-button config objects (`add`/`transfer`/`card`) so individual buttons can be disabled, and the now-unused `isAccountFunded` util was removed. <!-- 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: disable the transfer button on the Money Home screen when Money account does not have spendable balance. ## **Related issues** <!-- mms-check: type=issue-link required=true --> Fixes: [MUSD-946](https://consensyssoftware.atlassian.net/browse/MUSD-946) ## **Manual testing steps** <!-- mms-check: type=manual-testing required=true --> ```gherkin Feature: Money transfer button availability Scenario: user with an empty balance cannot transfer Given a Money account with a zero or sub-cent balance When user opens the Money home view Then the transfer button is disabled Scenario: user with a funded balance can transfer Given a Money account with a balance of at least one cent When user opens the Money home view Then the transfer button is enabled And user can start a transfer ``` ## **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] --> N/A - Transfer button was enabled ### **After** <!-- [screenshots/recordings] --> https://github.com/user-attachments/assets/2c0a9534-a701-4ab1-af06-ad7204a5f6cc ## **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 --> [MUSD-946]: https://consensyssoftware.atlassian.net/browse/MUSD-946?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes Money home funded/unfunded gating and transfer entry across several balance edge cases; behavior is well covered by new tests but affects a primary user flow. > > **Overview** > Disables **Transfer** on Money Home until the account has a **spendable** balance: loaded fiat raw amount at least **one cent** (`DUST_THRESHOLD`), replacing `tokenTotal` / `isAccountFunded` with `hasSpendableBalance` and `hasBalanceValue` for funded vs unfunded UI. > > **Transfer** is wired through `MoneyActionButtonRow` with per-button `{ onPress, disabled? }` configs and `ButtonBase` `isDisabled`, so zero, loading, unavailable-rate, and sub-cent dust balances cannot open the transfer sheet. **MoneyEarnings** and unfunded onboarding (**How it works**, **What you get**) follow the same rules; unavailable balance no longer shows empty-account onboarding. > > Exports `DUST_THRESHOLD` from `moneyFormatFiat` and removes `isAccountFunded`. Tests cover dust, unavailable, disabled transfer, and regression cases. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit d4df2d0. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…he sold token (#31469) ## **Description** When selling a token in QuickBuy, the **receive** token list could contain — and default to — the **same token being sold**, which is a no-op (e.g. selling USDC on Base offered/defaulted to receiving USDC). The receive options are built stablecoins-first and sorted with the position's chain first, so the previous logic — which simply preselected `sellDestTokenOptions[0]` — landed on the very token being sold whenever the position was a stablecoin that also appears in the curated stablecoin list. The token was also still selectable in the picker. This PR fixes both the default and the list: - **Excludes the token being sold from the receive list entirely**, so it can't be selected at all (receiving the same token you're selling is a no-op). - Introduces `selectDefaultReceiveToken`, which prefers the **native token of the sold token's chain** as the default (e.g. selling USDC on Base now defaults to ETH on Base), falling back to the first remaining candidate when the user is already selling the native token or when no native option is available. The auto-select effect is gated on `!isSetupLoading` and reads the sold token's identity from the normalised `positionTokenFromSetup` (rather than the balance-enriched `positionToken`), so both the exclusion and the default are correct even before the balance resolves — closing a race where the default could still be set to the sold token. <img width="973" height="1066" alt="image" src="https://github.com/user-attachments/assets/48caf26e-1e30-44e3-8919-d47b5c9e9c69" /> ## **Changelog** CHANGELOG entry: Fixed QuickBuy so selling a token no longer lists or defaults the receive token to the same token; the sold token is removed from the receive options and the default is now the chain's native token (e.g. selling USDC on Base defaults to ETH). ## **Related issues** Fixes: N/A — internal bug report (QuickBuy sell default/listing of receive token). ## **Manual testing steps** ```gherkin Feature: QuickBuy sell receive token Scenario: The token being sold is not offered as a receive option Given I hold USDC on Base And I open the QuickBuy sheet for that position When I switch to "Sell" mode And I open the "Receive" token picker Then USDC on Base is not listed as a receive option Scenario: Selling a stablecoin defaults to the chain native token Given I hold USDC on Base And I open the QuickBuy sheet for that position When I switch to "Sell" mode Then the default "Receive" token is ETH on Base And it is never USDC (the token being sold) Scenario: Selling the native token defaults to a stablecoin Given I hold ETH on Base And I open the QuickBuy sheet for that position When I switch to "Sell" mode Then the default "Receive" token is a stablecoin on Base (not ETH) ``` ## **Screenshots/Recordings** ### **Before** <!-- Selling USDC on Base listed and defaulted the receive token to USDC. --> N/A — logic-only change; behavior covered by unit tests. ### **After** <!-- Selling USDC on Base removes USDC from the receive list and defaults to ETH. --> N/A — logic-only change; behavior covered by unit tests. ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [x] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] 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. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** Initial implementation of the UI messenger. This sets up the UI messenger, a route messenger, and refactors a Snap page to demonstrate how to use the new route-level messenger. More details can be found in [the UI messenger ADR](https://github.com/MetaMask/decisions/blob/6760a1616df98f5b8bb7c876fadd7f255a2b8957/decisions/core/0020-integrate-messengers-into-ui.md). ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: ## **Related issues** Refs: n/a ## **Manual testing steps** n/a ## **Screenshots/Recordings** n/a ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [x] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] 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 how UI invokes controller actions (snap removal now goes through delegation) and introduces a broad new access-control surface; mitigated by explicit per-route capabilities and KeyringController exclusions, but more routes will need careful capability review as adoption grows. > > **Overview** > Introduces a **UI messenger layer** so screens can call controller actions through typed, capability-scoped messengers instead of reaching into `Engine` directly. > > **Root** now creates a singleton `UIMessenger` and wraps the app in `UIMessengerProvider`. The UI messenger delegates allowed actions to `Engine.controllerMessenger` and forwards events from the background; a config list (starting with **KeyringController** unsafe/keyring APIs) blocks actions that must not be exposed to the UI. > > **Per-route messengers** are wired via `withMessenger` / `RouteWithMessenger`: on mount they delegate only the declared actions/events, expose them through `RouteMessengerContext`, and revoke on unmount. **Snap Settings** is the first adopter—the navigator wraps `SnapSettings` with `SnapController:removeSnap`, and removal uses `useMessenger().call('SnapController:removeSnap', …)` instead of `Engine.context.SnapController.removeSnap`. Tests and `renderWithProvider` gain optional `uiMessenger` / `routeMessenger` mocks to match this pattern. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit dbbcad3. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…31466) <!-- 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** update @metamask/transaction-pay-controller to version 23.5.0 ## **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: ## **Related issues** <!-- mms-check: type=issue-link required=true --> Fixes: https://consensyssoftware.atlassian.net/browse/CONF-1520 ## **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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches bridge/swap submission paths via controller upgrades and type assertions on quote payloads; regression risk is moderate though changes are mostly dependency-driven compile fixes. > > **Overview** > Bumps **`@metamask/transaction-pay-controller`** from **^23.3.0** to **^23.5.0** and refreshes **`yarn.lock`**, pulling newer bridge stack packages (e.g. **`bridge-controller` ~75**, **`bridge-status-controller` 72.1.0**) and related controller bumps such as **`keyring-controller` ^27**. > > To satisfy TypeScript after those nested **`bridge-controller`** copies diverge, **`useSubmitBridgeTx`** and **`useSubmitBatchSellTx`** cast **`QuoteResponse`** / quote payloads to **`BridgeStatusController`** parameter types, with comments explaining the v74 vs v75 nominal type mismatch. > > Test/fixture updates rename the Monad network label from **"Monad Mainnet"** to **"Monad"** in **`initial-background-state.json`** and **`AddressSelector.test.tsx`**. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 1ba055e. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…cp-7.81.0 (#31436) ## **Description** <!-- mms-check: type=text required=true --> This PR makes the Predict **game details** screen (`PredictGameDetailsContent`) behave like the standard `PredictMarketDetails` screen when switching between outcome-group chips (game lines / exact score / halftime) or the Positions/Outcomes tabs. It fixes two visual issues: 1. **Screen jumping on tab/chip change.** The component drove an imperative `scrollTo` on every chip selection (plus a follow-up `InteractionManager.runAfterInteractions` pass) to force the sticky header to the top, propped up by a `windowHeight`-based `minHeight` on the tab content. This caused the screen to jump downward on every switch. The regular market details screen never does this — it relies solely on the `ScrollView`'s `stickyHeaderIndices`. Removed the manual scroll machinery (`scrollRef`, `stickyHeaderY`, `pendingChipScroll`, the layout handler, and the effect) and the `minHeight` wrapper, so switching chips/tabs now only swaps the content below the sticky header and preserves scroll position. 2. **Chart overlapping the outcomes.** `PredictGameChartContent` used `flex-1` on its loaded/error/empty containers. Inside a `ScrollView`, `flex-1` collapses to zero height, so the fixed 200px chart `View` overflowed downward onto the chip bar and the first outcome card. Switched the containers to `w-full` so they size to their content — matching the market details chart (`PredictDetailsChart`), which never used `flex-1`. Both changes are layout-only. Existing unit tests for `PredictGameChart` and `PredictGameDetailsContent` (218 tests) pass unchanged, including the `reserves chart height only while loading` test. ## **Changelog** <!-- mms-check: type=changelog required=true --> CHANGELOG entry: Fixed the Predict sports game details screen jumping and the price chart overlapping the outcomes when switching between markets ## **Related issues** <!-- mms-check: type=issue-link required=true --> Fixes: https://consensyssoftware.atlassian.net/browse/PRED-954 ## **Manual testing steps** <!-- mms-check: type=manual-testing required=true --> ```gherkin Feature: Predict game details market/tab switching Scenario: Switching outcome-group chips does not jump or overlap the chart Given I open a sports game market with extended outcomes (e.g. game lines, exact score, halftime) And the price chart has loaded above the chip bar When I tap a different chip (e.g. "Exact Score") Then the screen does not jump to pin the chip bar to the top And the chart keeps its height and does not overlap the outcomes list And the outcomes for the selected chip render below the chip bar Scenario: Switching Positions/Outcomes tabs preserves scroll position Given I open a sports game market that shows the Positions/Outcomes tab bar When I switch between the Positions and Outcomes tabs Then the scroll position is preserved (no downward jump) And the chart does not overlap any content ``` ## **Screenshots/Recordings** <!-- mms-check: type=screenshot required=true --> ### **Before** <!-- Attach the recording showing the screen jumping on tab/chip change and the chart overlapping the first outcome card (e.g. "Mexico 0 - 3 South Africa"). --> ### **After** https://github.com/user-attachments/assets/ce638894-f133-40ce-89c8-77b4d38868cc <!-- Attach a recording switching between chips/tabs with no downward jump and no chart overlap. --> ## **Pre-merge author checklist** <!-- mms-check: type=checklist required=true --> - [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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Layout-only Tailwind and scroll wiring changes in Predict game details UI with no auth, data, or business-logic impact. > > **Overview** > Fixes Predict **game details** layout when users switch outcome chips or Positions/Outcomes tabs. > > **Game details scroll behavior:** Removes imperative `scrollTo` on chip change (`scrollRef`, `stickyHeaderY`, `pendingChipScroll`, layout measurement, and `InteractionManager` follow-up) and drops the `windowHeight`-based `minHeight` wrapper around tab content. Chip selection now calls `handleChipSelect` directly, relying on `ScrollView` `stickyHeaderIndices` like standard market details so scroll position is preserved and the screen no longer jumps. > > **Chart in `ScrollView`:** In `PredictGameChartContent`, replaces `flex-1` with `w-full` on loaded, error, and empty chart containers so height follows content instead of collapsing inside the scroll view, preventing the fixed-height chart from overlapping the chip bar and outcome list. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit b15f4a1. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…1123) <!-- 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. address comment : #30911 (comment) --> ## **Description** Agentic CLI connection loading duplicated the same notification logic already implemented in the SDK Connect V2 host application adapter (`agenticCliLoading.ts` dispatched `showSimpleNotification` / `hideNotificationById` directly). This PR removes that duplicate module and routes Agentic CLI loading through `deps.hostapp.showConnectionLoading` / `hideConnectionLoading`, keeping a single code path for connection-loading UI. `showConnectionLoading` now accepts optional `ShowConnectionLoadingOptions` with `autodismissMs`. The default remains **10s** for standard SDK Connect flows; Agentic CLI passes **15s** via `AGENTIC_CLI_CONNECTION_LOADING_AUTODISMISS_MS` to accommodate the longer MWP → OTP → dashboard connect sequence. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: #30911 (comment) ## **Manual testing steps** ```gherkin Feature: Agentic CLI connection loading Scenario: user connects via Agentic CLI deeplink Given the app is unlocked and Agentic CLI connect is available When user opens an Agentic CLI connect deeplink Then a connection-loading notification appears with the dApp name And the notification auto-dismisses after ~15s if the flow stalls And the notification is hidden when the connect flow completes or fails Scenario: standard SDK Connect V2 connection loading is unchanged Given a non–Agentic CLI SDK Connect V2 session is establishing When connection loading is shown via the host adapter Then the loading notification still auto-dismisses after ~10s by default ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> N/A ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [x] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] 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** > UI notification plumbing refactor with no auth or data-path changes; default 10s autodismiss behavior is preserved for non–Agentic CLI callers. > > **Overview** > Removes the Agentic CLI–specific loading helpers in `agenticCliLoading.ts` and routes connection loading through the shared SDK Connect V2 **host application adapter** instead. > > `showConnectionLoading` / `hideConnectionLoading` on `IHostApplicationAdapter` now accept optional `ShowConnectionLoadingOptions` with `autodismissMs` (default **10s**; Agentic CLI uses exported **15s** for longer MWP → OTP → dashboard flows). `AgenticCliMwpConnectionService` calls `deps.hostapp.showConnectionLoading` / `hideConnectionLoading` with that timeout rather than dispatching notifications directly. Tests were updated accordingly and adapter coverage was added for custom autodismiss. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit aa778c8. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…ED-927) (#31219) ## **Description** The Predict search feature (search icon → full-screen overlay in the Predict feed) currently has **zero** analytics instrumentation. No event fires when a user opens search, types a query, or taps a result, making it impossible to measure search engagement or assess the feature's value. This PR adds a single `Predict Search Interacted` event with an `interaction_type` discriminator covering the three key moments, following the established `PredictAnalytics` controller pattern (config in `predictAnalyticsEvents.ts` → `PredictAnalytics.trackSearchInteracted` → `PredictController` pass-through, called via `Engine.context.PredictController.trackSearchInteracted(...)`). | `interaction_type` | Trigger | Extra properties | | --- | --- | --- | | `opened` | User taps the search icon | — | | `queried` | A debounced query resolves | `search_query`, `results_count` | | `result_clicked` | User taps a market result card | `search_query`, `market_id`, `market_title` | Base properties on all three: `interaction_type`, `predict_feed_tab` (omitted on the tab-less redesigned home), `entry_point`. The event is instrumented on **both** search surfaces (legacy `PredictFeed` and the redesigned `PredictHome`), which share `PredictSearchOverlay`. `opened` fires at the search-icon call sites; `queried` and `result_clicked` fire inside the overlay (the latter via `PredictMarket`'s existing `onCardPress`, so navigation is unaffected). The matching Segment schema event is added in a separate `segment-schema` PR (see Related issues) and should land first. ## **Changelog** CHANGELOG entry: null <!-- Non-user-facing analytics instrumentation only. --> ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/PRED-927 Segment schema PR: Consensys/segment-schema#601 ## **Manual testing steps** ```gherkin Feature: Predict search engagement analytics Scenario: user opens search Given the user is on the Predict feed (or redesigned home) When the user taps the search icon Then a "Predict Search Interacted" event fires with interaction_type=opened And predict_feed_tab (feed only) and entry_point are included Scenario: user runs a query Given the search overlay is open When the user types a query and the debounced search resolves Then a "Predict Search Interacted" event fires once with interaction_type=queried And search_query and results_count match the resolved results Scenario: user taps a result Given search results are shown When the user taps a market result card Then a "Predict Search Interacted" event fires with interaction_type=result_clicked And search_query, market_id, and market_title match the tapped market And the user still navigates to the market details ``` Automated coverage: - `yarn jest app/components/UI/Predict/controllers/PredictAnalytics.test.ts` (event name + per-`interaction_type` property mapping, incl. `results_count=0` and omitted optional props) - `yarn jest -c jest.config.view.js PredictFeed.view.test PredictHome.view.test` (opened/queried/result_clicked fire with correct properties) ## **Screenshots/Recordings** ### **Before** N/A — no UI changes; analytics-only instrumentation. ### **After** N/A — no UI changes; analytics-only instrumentation. ## **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 - [x] I've tested with a power user scenario - [x] I've instrumented key operations with Sentry traces for production performance metrics ## **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] > **Low Risk** > Analytics-only instrumentation with no UI or business-logic changes; search queries are sent to existing metrics pipelines as designed. > > **Overview** > Adds **Predict Search Interacted** analytics so search engagement can be measured on the legacy feed and redesigned home. > > A new MetaMetrics event is wired through `PredictAnalytics` / `PredictController` with `interaction_type` values **`opened`**, **`queried`**, and **`result_clicked`**, plus optional `predict_feed_tab`, `entry_point`, `search_query`, `results_count`, and market fields. **`opened`** fires when the user taps search on `PredictFeed` or `PredictHome`; **`queried`** and **`result_clicked`** fire from shared `PredictSearchOverlay` after debounced search completes (once per query, with re-track after clear) and on result card press via `onCardPress`. > > `results_count` uses the API **`totalResults`**, not the visible page length. On home, `entry_point` is taken from route params only—no fallback to `predict_feed`. Unit and component-view tests cover property mapping and end-to-end firing. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 353b4bb. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…money home page (#31463) <!-- 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** change perps/predict page headers when user is navigating from money home page ## **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: ## **Related issues** <!-- mms-check: type=issue-link required=true --> Fixes: https://consensyssoftware.atlassian.net/browse/CONF-1516 ## **Manual testing steps** NA ## **Screenshots/Recordings** <img width="396" height="845" alt="Screenshot 2026-06-10 at 3 01 38 PM" src="https://github.com/user-attachments/assets/27a48ebc-4eb0-49bf-a0fb-1e4aca09d8fc" /> <img width="396" height="849" alt="Screenshot 2026-06-10 at 3 01 50 PM" src="https://github.com/user-attachments/assets/582e3755-b4de-4e0d-a61e-2e657e0864cc" /> ## **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] > **Low Risk** > Navbar copy only, driven by existing navigation params; no payment or transaction logic changes. > > **Overview** > **Perps and Predict deposit confirmation screens** now pick the navbar title from route params: when `payWithOption` is `MoneyAccount` (money home entry), the header shows **Transfer to Perps** or **Transfer to Predictions** instead of the usual deposit titles. > > New English strings support those labels. **Unit tests** cover default vs money-account titles plus existing behavior (token registration, `CustomAmountInfo`, money-account payment override). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 8917ead. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…epage (PRED-906) (#31226) ## **Description** Integrates the reusable PRED-835 `PredictPortfolioModule` into the redesigned Predict homepage (`PredictHome`), replacing the temporary mock placeholder that previously sat at the top of the feed. **Why:** PRED-906 (under the PRED-834 IA & Navigation overhaul) requires the redesigned homepage to render the real portfolio module — value, P&L, available balance, and the Positions / Add funds / Withdraw / Claim actions — at the top of the single-scroll feed. **What changed:** - **Relocated** the module from `components/PredictPortfolio` into `views/PredictHome/components/PredictPortfolio`, since the redesigned homepage is its only consumer (pure `git mv` + import-depth fixes, no behavior change). - **Wired** the real `PredictPortfolioModule` into `PredictHome`, removing the mock placeholder component and its unused `portfolio_module_placeholder` string. - Gating stays entirely at the **route level** via `predictHomeRedesign.enabled` — the redesigned home always shows the module, while the legacy `PredictFeed` (balance card) renders when the redesign flag is off. No in-view flag or duplicate "Predictions" title. - **Fixed** the portfolio Positions button, which still used an old temporary fallback (navigating to `PREDICT.MARKET_LIST`); it now routes to `Routes.PREDICT.POSITIONS`, matching the working `PredictBalance` button. - Minor spacing fix: title section bottom padding `pb-4` → `pb-2` to match Figma. ## **Changelog** <!-- Redesigned Predict homepage is gated behind the unreleased `predictHomeRedesign` flag. --> CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/PRED-906 ## **Manual testing steps** ```gherkin Feature: Predict homepage portfolio module Scenario: user views the portfolio module on the redesigned Predict homepage Given the predictHomeRedesign feature flag is enabled When the user opens the Predict homepage Then the portfolio module renders at the top of the feed And it shows portfolio value, P&L line, available balance, and the action buttons And no duplicate "Predictions" title is shown Scenario: user opens the Positions screen from the portfolio Given the portfolio module is visible on the Predict homepage When the user taps the "Positions" button Then the Predict Positions screen opens Scenario: portfolio actions behave as in the existing feed When the user taps Add funds, Withdraw, or Claim Then the action behaves the same as the PRED-835 current-feed integration Scenario: fallback when the redesign flag is off Given the predictHomeRedesign feature flag is disabled When the user opens the Predict tab Then the legacy PredictFeed renders with the existing balance card ``` ## **Screenshots/Recordings** ### **Before** <!-- Mock "Portfolio module" placeholder box at the top of the redesigned homepage. --> ### **After** <img width="429" height="889" alt="Screenshot 2026-06-08 at 15 20 44" src="https://github.com/user-attachments/assets/06f54e0c-c01b-40e1-91da-e6b42b41a8cf" /> <!-- Redesigned homepage now renders the real portfolio module (value, -$ P&L, available balance, Positions/Add funds/Withdraw, Claim CTA). Screenshot to be attached by author. --> ## **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. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > UI and navigation changes behind the predict home redesign path; Positions is no longer redirected when the portfolio flag is off, which slightly broadens access to that screen. > > **Overview** > Replaces the redesigned **Predict home** placeholder portfolio block with the real **`PredictPortfolioModule`** (value, P&L, actions) and hooks **deposit-wallet withdraw** to **`PredictWithdrawUnavailableSheet`** on the home shell. > > **Positions** from the module now navigates to **`Routes.PREDICT.POSITIONS`** instead of the temporary market-list fallback. The stack **drops the portfolio-flag gate** on the Positions route (`PredictPositionsRoute` removed); **`PredictPositionsView`** is registered directly, so deep links to Positions work even when the portfolio flag is off. > > Removes the mock **`PredictPortfolioModule`** placeholder folder and the unused **`portfolio_module_placeholder`** copy; module **`testID`** aligns with **`PredictHomeSelectorsIDs.PORTFOLIO_MODULE`**. Tests follow the new navigation and routing behavior. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 6860016. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
## **Description** Bump @metamask/eip-5792-middleware to ^3.0.4 [](https://codespaces.new/MetaMask/metamask-extension/pull/40465?quickstart=1) ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null Please ping with any questions ## **Related issues** Fixes: https://consensys.slack.com/archives/C0318JSUBM3/p1780930822763839 ## **Manual testing steps** No user facing changes ## **Screenshots/Recordings** <!-- 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** - [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**GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes which accounts EIP-5792 batch send and capability RPCs can use for a given dapp origin; behavior shifts from all accounts to permission-scoped accounts, which can break or fix dapps depending on prior reliance on the old behavior. > > **Overview** > Upgrades **`@metamask/eip-5792-middleware`** from **^2.0.0** to **^3.0.4** and adapts the extension/mobile wiring to the package’s new hooks. > > **EIP-5792 account scoping:** `wallet_getCapabilities` and `wallet_sendCalls` no longer use a **`getAccounts`** callback that returned every address from **`AccountsController`**. They now supply **`getPermittedAccountsForOrigin`**, resolved via **`getPermittedAccounts(request.origin)`** in `createEip5792Middleware` and **`getPermittedAccounts(this.channelIdOrOrigin)`** on the **`processSendCalls`** options in **`BackgroundBridge`**. Capability queries and batched sends are tied to **origin-permitted** accounts instead of the full account list. > > **Small constant fix:** **`INTERNAL_ORIGINS`** is built with **`.filter(Boolean)`** so a missing **`MM_FOX_CODE`** env value does not leave a falsy entry in the array. > > Tests drop the obsolete **`getAccounts`** mock from the middleware factory smoke test. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit a761a07. 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: Alex Donesky <adonesky@gmail.com>
…mentType types (#31468) ## **Description** <!-- mms-check: type=text required=true --> Wires the dual-framework model through the E2E test framework layer so that Detox and Appium can share page objects without per-screen `encapsulated()` configs. **Matchers** — `getElementByID`, `getElementByText`, and `getElementByLabel` now return `EncapsulatedElementType` and route string selectors through `resolve()` from `Selector.ts`, which builds Detox + Playwright locator pairs at runtime. RegExp inputs still go directly to `element(by.*)` for Detox-only callers. **Gestures, Assertions, Utilities** — parameter types updated from `DetoxElement` to `EncapsulatedElementType`. Internal Detox-specific paths (`waitFor`, `getAttributes`) cast with `asDetoxElement` / `await` where needed. The redundant `DetoxElement | EncapsulatedElementType` union is collapsed to `EncapsulatedElementType` throughout. **Page objects** (~120 files) — getter return type annotations updated from `DetoxElement` to `EncapsulatedElementType`. Getter bodies are untouched. A small number of call sites that feed elements into raw Detox APIs retain explicit casts after `await`. No production app code is changed. All changes are confined to `tests/`. ## **Changelog** <!-- mms-check: type=changelog required=true --> CHANGELOG entry: null ## **Related issues** <!-- mms-check: type=issue-link required=true --> Refs: https://consensyssoftware.atlassian.net/browse/MMQA-1927 Refs: https://consensyssoftware.atlassian.net/browse/MMQA-1928 ## **Manual testing steps** <!-- mms-check: type=manual-testing required=true --> ```gherkin Feature: Dual-framework E2E selector layer Scenario: Existing Detox smoke tests continue to pass Given the branch is checked out When yarn jest tests/framework/ is run Then all framework unit tests pass with no regressions Scenario: TypeScript compilation is clean Given the branch is checked out When yarn lint:tsc is run Then zero TypeScript errors are reported ``` ## **Screenshots/Recordings** <!-- mms-check: type=screenshot required=true --> N/A — test infrastructure only, no UI changes. ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** <!-- mms-check: type=checklist required=true --> - [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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Broad typing and matcher behavior changes across the entire E2E stack could break Detox runs if resolve() or await/cast paths are wrong, though scope is limited to tests/. > > **Overview** > Standardizes the E2E layer on **`EncapsulatedElementType`** so Detox and Appium can share page objects without rewriting every screen. > > **Matchers** — `getElementByID`, `getElementByText`, and `getElementByLabel` are now synchronous and return `EncapsulatedElementType`. String selectors go through **`resolve()`** in `Selector.ts`, which pairs Detox locators with Playwright/Appium equivalents; **RegExp** matchers still call Detox `element(by.*)` directly. > > **Gestures, Assertions, Utilities** — APIs accept `EncapsulatedElementType` instead of `DetoxElement`. Text-based assertions and legacy helpers use **`asDetoxElement`** (or `await` + casts) before `waitFor` / `getAttributes`. > > **Page objects** — Getter return types move from `DetoxElement` to `EncapsulatedElementType` across the suite; a few spots that call raw Detox APIs keep explicit casts after `await`. > > **EncapsulatedElement** — `LocatorConfig.detox` factories are typed to return `EncapsulatedElementType`, with internal casts when materializing Detox elements. > > All changes are under `tests/`; no production app code. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 0100ae2. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…1462) ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> QuickBuy surfaces its own pending/complete/failed toasts. When a trade is submitted via an EIP-7702 smart account or a gas-included (`gasIncluded7702`) quote, `BridgeStatusController.submitTx` wraps the trade as a `TransactionType.batch` transaction. `batch` is in `REDESIGNED_TRANSACTION_TYPES`, so `NotificationManager` also fired the generic "Transaction submitted" and "Transaction #N complete" toasts on top of QuickBuy's own — the user saw **4 toasts instead of 2**. (This is why it doesn't reproduce on a plain EOA: those trades are typed `swap`/`bridge`, which are not redesigned types.) This PR scopes the suppression strictly to QuickBuy via inversion of control, so the main Swap/Bridge flows are unaffected: - New dependency-free module `app/core/notificationSkipPredicates.ts` holds a registry of "skip predicates". `NotificationManager.#shouldSkipNotification` consults it (guarded by try/catch so a throwing predicate can never break notifications). Keeping it in its own module means feature code can register without importing the heavy `NotificationManager` graph. - QuickBuy registers a predicate at the app root (`useQuickBuyToastRegistrations`) that matches: - **tracked trade ids** — covers the terminal complete/failed toast, and - **in-flight submissions** via a pre-submit marker (`beginQuickBuySubmission`/`endQuickBuySubmission`) — covers the *pending* toast, which fires mid-`submitTx` before the tx id is known. ## **Changelog** <!-- mms-check: type=changelog required=true --> CHANGELOG entry: Fixed QuickBuy showing duplicate transaction toasts for smart-account and gas-included trades ## **Related issues** <!-- mms-check: type=issue-link required=true --> Fixes: https://consensyssoftware.atlassian.net/browse/TSA-627 ## **Manual testing steps** <!-- mms-check: type=manual-testing required=true --> ```gherkin Feature: QuickBuy transaction toasts Scenario: User runs a QuickBuy with a smart (EIP-7702) account Given I have an EIP-7702 smart account enabled on the trade network And I open a token from the Social Leaderboard trader position view When I confirm a QuickBuy trade Then I see exactly one QuickBuy "Buying..." pending toast And after the trade settles I see exactly one QuickBuy "Bought" (or "Failed") toast And I do not see the generic "Transaction submitted" or "Transaction complete" toasts Scenario: User runs a QuickBuy on a plain EOA (regression) Given I have a standard externally-owned account When I confirm a QuickBuy trade Then I still see only the two QuickBuy toasts (pending, then terminal) Scenario: Main Swap/Bridge flows are unaffected (regression) Given I start a swap or bridge from the main Swap/Bridge UI When the transaction is submitted and confirmed Then the generic transaction toasts still appear as before ``` ## **Screenshots/Recordings** <!-- mms-check: type=screenshot required=true --> ### **Before** In some rare cases, this happens: https://github.com/user-attachments/assets/838826be-99a7-4101-873e-88173059fbc1 ### **After** This is what we want in all cases: https://github.com/user-attachments/assets/b49de0d5-a0e2-47cb-8eef-6b372ad0f79f ## **Pre-merge author checklist** <!-- mms-check: type=checklist required=true --> - [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) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes global notification gating and briefly suppresses swap/bridge/batch notifications during QuickBuy submit; predicates are isolated and errors are caught so unrelated flows should still get generic toasts. > > **Overview** > Adds a **dependency-free notification skip registry** (`notificationSkipPredicates`) and wires **`NotificationManager`** to consult registered predicates (with try/catch) so feature flows can opt out of generic transaction toasts without core importing UI code. > > **QuickBuy** registers `isQuickBuyTransaction` at the app root and extends the trade tracker with: a **ref-counted in-flight submission marker** (`begin`/`end` around `submitTx`) for pending notifications before the tx id exists; **tracked and recently-settled tx ids** so suppression still applies when `NotificationManager` re-checks ~2s after confirm/fail; and **type-narrowed matching** (swap/bridge/batch) during submission so unrelated txs are not hidden. Terminal handling now **settles** trades via `markQuickBuyTradeSettled` instead of a plain untrack so duplicate generic success/error toasts do not appear on top of QuickBuy’s own toasts (notably EIP-7702 `batch` trades). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 270b0ec. 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: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )