[pull] main from MetaMask:main#799
Merged
Merged
Conversation
<!-- 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** Ensure valid URLs are treated as valid by URL detection in `SitesSearchFooter`. Additionally move out the existing regex to not have to redeclare/recompile it for every check. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Fixed an issue where certain URLs would not be consider valid in the in-app browser <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Small UI-only change to how search footer classifies input; no auth, payments, or data-layer impact. > > **Overview** > **Sites search footer** now treats more inputs as URLs when deciding whether to show the direct “open URL” action alongside the search-engine link. > > `looksLikeUrl` combines the existing **`is-url`** check with the prior domain-style regex (hoisted to a module-level **`URL_REGEX`** so it isn’t recompiled on every call). That fixes cases like **`http://localhost:8000`** that the regex alone missed. A unit test covers localhost URLs with a scheme. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit ae6c855. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
#30729) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> Homepage sections that render row-based content (token list, perps positions, predict positions) have ~12 px of natural vertical padding built into each row item (py-3, height: 64, or paddingVertical: 12). Sections that render horizontal carousels or pill rails had no equivalent padding, causing the inter-section gap to look visually inconsistent — row sections appeared to have a larger breathing room than carousel/pill sections. The fix adds py-3 to the contentContainerStyle of each horizontal carousel and pill rail on the homepage, so every section contributes the same amount of vertical space regardless of its content type. Additionally, ScamWarningModal and RemoveTokenBottomSheet in TokensSection are moved outside the gap-applying container to prevent the modal library's hidden <View> wrapper from consuming an extra 12 px gap below the Tokens section. ## **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: Fixes spacing inconsistencies on the homepage ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TMCU-816 ## **Manual testing steps** ```gherkin Feature: Homepage section spacing Scenario: user views the homepage with all sections visible Given the app is open on the homepage And the user has tokens, perps positions, predict positions, and top traders visible When user scrolls through the homepage Then the vertical gap between every section header and the section below it looks visually equal And the gap between sections is consistent regardless of whether the section shows rows or a horizontal carousel/pill rail Scenario: user views homepage with Perps showing pills empty state Given the Perps section is showing the pills rail (no open positions) When user views the spacing above and below the pills rail Then the gap matches the spacing around row-based sections like Tokens Scenario: user views homepage with Perps showing trending carousel Given the Perps section is showing the trending market tile carousel When user views the spacing above and below the carousel Then the gap matches the spacing around row-based sections like Tokens ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <img width="413" height="868" alt="Screenshot 2026-05-28 at 12 18 42" src="https://github.com/user-attachments/assets/6e4b87a0-69da-480b-a33f-36eed7111df9" /> <!-- [screenshots/recordings] --> ### **After** <img width="404" height="869" alt="Screenshot 2026-05-28 at 11 07 12" src="https://github.com/user-attachments/assets/9667cccc-63b2-4e61-a914-a0d77c5618cf" /> <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > UI-only layout and container restructuring on the wallet homepage with no auth, data, or payment logic changes. > > **Overview** > Homepage sections now use **consistent vertical breathing room** between headers and content. Horizontal **carousels and pill rails** (Perps trending, Perps pills, Predict trending, Top Traders) get **`py-3`** on their scroll content so they match row-based sections that already pick up ~12px from list rows. > > **Tokens** wraps only the header and list in the **`sectionGap`** container and moves **`ScamWarningModal`** and **`RemoveTokenBottomSheet`** outside it so hidden modal wrappers do not add an extra gap under the section. > > **Perps** keeps positions and orders inside a single **`SectionRow`**, showing the skeleton in that same row while loading or trending is pending—so loading and filled states share the same vertical padding as other row sections. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 3f90bec. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
#30799) <!-- 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** Bump `@metamask/ai-controllers` to `^0.7.0` so market overview no longer fails when `relatedAsset.name` or `sourceAssetId` is missing. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Localized homepage/Perps presentation and dependency bump; no auth, payments, or transaction logic changes. > > **Overview** > Upgrades **`@metamask/ai-controllers`** to **^0.7.0** so market overview can return **`RelatedAsset`** entries without **`name`** or **`sourceAssetId`**. > > The Whats Happening UI now **falls back to `symbol`** for avatars, labels, and Perps trade navigation when **`name`** is missing, and uses **`symbol` + index** for list keys instead of **`sourceAssetId`**. New unit tests cover sparse assets, empty trends, and confirming an empty successful load does **not** show the error UI. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 977027e. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.
In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
## **Description**
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
## **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: bump assets controller v8.1.0
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
### **After**
<!-- [screenshots/recordings] -->
## **Pre-merge author checklist**
<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.
Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->
- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
#### Performance checks (if applicable)
- [ ] I've tested on Android
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Touches wallet/asset and keyring-related controller packages
transitively (including keyring-controller 26.x), so regression risk is
in balances, tokens/NFTs, and account flows rather than in local code
edits.
>
> **Overview**
> Bumps the direct dependency **`@metamask/assets-controller`** from
**8.0.1** to **8.1.0** in `package.json`, with **`yarn.lock`** refreshed
so the resolved tree picks up that release and its transitive updates
(notably **`@metamask/assets-controllers` 108.2.0**,
**`@metamask/account-tree-controller` 7.5.0**,
**`@metamask/keyring-controller` 26.0.0**, and related
controller/backend/profile-sync/snap-account-service pins).
>
> There are **no application source changes** in this diff—behavior
shifts, if any, come only from the upgraded packages at runtime.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
880012e. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**
Hardens the agentic fixture wallet setup so named fixture accounts are
created reliably and the flow tolerates legacy vaults.
1. **What is the reason for the change?** The fixture account setup was
fragile: account-group naming was loosely typed, vault unlock used a
bare `submitPassword` instead of the real post-login path, and
legacy/empty vaults could throw during init or account-tree refresh.
2. **What is the improvement/solution?** `AgenticService` now types
`queryUiTarget` visibility and `setAccountGroupName` (`AccountGroupId`),
unlocks existing vaults via `Authentication.unlockWallet`, imports each
private key gracefully, and falls back to skipping group rename for
legacy vaults instead of throwing. `setup-wallet.sh` validates the
expected HD account total, resolves an absolute `SCRIPT_DIR`, guards the
`--fixture` arg, and shares a `safe-env-parser.sh` helper.
Scope is agentic dev tooling only — no app/runtime user-facing behavior.
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: Agentic fixture wallet setup
Scenario: Seed a fresh wallet from a fixture with named accounts
Given a wallet-fixture.json defining HD and private-key accounts
When I run scripts/perps/agentic/setup-wallet.sh
Then the expected number of HD accounts is created
And each account group is renamed to its fixture name
And the script exits successfully
Scenario: Re-run against an existing legacy vault
Given a wallet was already seeded by a legacy run
When I re-run setup-wallet.sh
Then the unlock uses the real post-login flow
And group rename is skipped without throwing
And the run completes successfully
```
## **Screenshots/Recordings**
<!-- Dev tooling change — no UI surface. -->
### **Before**
N/A — no UI surface.
### **After**
N/A — no UI surface.
## **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]
> **Medium Risk**
> Changes unlock/import paths and account-tree naming in __DEV__-only
agentic code; legacy-vault fallbacks add complexity but do not affect
production bundles.
>
> **Overview**
> **Agentic fixture wallet setup** is reworked so Farmslot recipes can
seed named HD/private-key accounts reliably on fresh and legacy vaults.
`setupWallet` and new **`applyWalletFixture`** share
**`materializeFixtureAccounts`**: multi-SRP import via
`importNewSecretRecoveryPhrase` / `addNewHdAccount`, `count`/`names`
helpers, legacy vault fallbacks, **`Authentication.unlockWallet`**
instead of bare password submit,
**`EngineClass.disableAutomaticVaultBackup`**, and skipping account-tree
group rename when no group exists. Failures can return a **`step`**
label; the bridge adds **`queryUiTarget`**, **`refreshPerpsStreams`**,
and typed **`AccountGroupId`** usage.
>
> **Agent Step HUD** now shows a status/progress badge (pass/fail
coloring), parses multi-line descriptions (intent + `subflow:`/`error:`
lines), and respects safe-area insets.
>
> **Agentic scripts/docs** narrow Mobile to the CDP bridge +
preflight/`setup-wallet`/`safe-env-parser.sh`; in-repo recipe runner
pieces (`eval-ref`, pre-conditions registry, `validate-recipe` libs,
team recipes) and long perps validation docs are removed or pointed at
the external Recipe v1 runner. **`yarn a:*`** preflight scripts gain
explicit **`--mode fast|clean`**.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
80da06a. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…r clearing pasted recipient (#30771) ## **Description** When a user pastes an address in the send flow, an auto-review `useEffect` is triggered to streamline the UX. If the "New address" alert modal appears and the user cancels it, then presses the "Clear" button, the `pastedRecipient` state was not being cleared. This caused a race condition: `handleClearInput` would set `to` to empty, which caused `hasUnacknowledgedAlerts` to become `false` (no alerts for empty addresses), while `pastedRecipient` and `toAddressValidated` still held the old address. The auto-review `useEffect` would then see all conditions pass and fire `handleSubmitPress` with an empty `to` value, which got cast to `0x0000...0000`. **Fix:** 1. Clear `pastedRecipient` in `handleClearInput` so the auto-review effect cannot re-trigger with stale state after clearing. 2. Add a defense-in-depth guard in `proceedWithSubmit` to reject empty recipient addresses. ## **Changelog** CHANGELOG entry: Fixed a bug where clearing a pasted recipient address in the send flow could trigger a transaction to the zero address ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: Send flow clear button Scenario: user clears pasted address after cancelling new address alert Given the user is on the send recipient screen When user pastes a valid address using the Paste button And user presses the Review button And the "New address" alert modal appears And user presses Cancel on the alert modal And user presses the Clear button Then the input field is cleared And no transaction is submitted And the user remains on the recipient screen Scenario: user clears pasted address without triggering review first Given the user is on the send recipient screen When user pastes a valid address using the Paste button And user presses the Clear button before auto-review triggers Then the input field is cleared And no transaction is submitted ``` ## **Screenshots/Recordings** ### **Before** Pressing Clear after cancelling the "New address" alert triggers a transaction submission to `0x0000...0000`. ### **After** Pressing Clear correctly resets the input without triggering any transaction submission. ## **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] > **Medium Risk** > Changes send submission guards and recipient state on a user-facing money path; scope is small and covered by tests, but incorrect gating could block valid sends or miss edge cases. > > **Overview** > Fixes a send-flow bug where **Clear** after canceling the "New address" alert could still auto-advance review because **`pastedRecipient`** stayed set while **`to`** was emptied. > > **`RecipientInput`** now resets **`pastedRecipient`** in **`handleClearInput`** (along with **`updateTo('')`**) so the paste auto-review **`useEffect`** cannot re-fire on stale paste state. **`Recipient`** **`proceedWithSubmit`** also bails out when there is no **`resolvedAddress`** or **`to`**, blocking submission with an empty recipient (e.g. zero address). Tests cover clear + empty-recipient paths. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 636fbc9. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…ed via SpaceX carousel banner (#30736) ## **Description** Fixes the SPCX market detail leverage pill when the page is opened from the SpaceX carousel banner. That entry path supplied route market data with a raw placeholder `maxLeverage` value of `100`, and the detail screen treated that as complete data instead of enriching it from the perps market list. The market detail screen now only skips enrichment when route `maxLeverage` is already formatted with an `x` suffix. Carousel/deeplink-style SPCX route params resolve to the provider market value `5x`, while market-list entry remains unchanged. Self-review cleanup also migrated the touched market detail `Text` and `ButtonSemantic` usages to the non-deprecated design-system exports, avoiding eslint-disable comments in this bug-fix diff. Evidence is intentionally trimmed to clean, caption-free screenshots: one before/after pair for the raw `100` to `5x` fix, plus one watchlist-origin screenshot for AC2. Captioned runner screenshots are omitted from the PR-visible list. ## **Changelog** CHANGELOG entry: Fixed a bug that caused the SPCX leverage pill to show an unformatted value when opened from the SpaceX carousel banner ## **Related issues** Fixes: [TAT-3262](https://consensyssoftware.atlassian.net/browse/TAT-3262) ## **Manual testing steps** ```gherkin Feature: SPCX leverage pill Scenario: carousel entry shows formatted max leverage Given the wallet is unlocked on iOS When the SPCX market detail page is opened from the SpaceX carousel banner Then the leverage pill shows 5x instead of raw 100 Scenario: market-list entry remains formatted Given the wallet is unlocked on iOS And SPCX is present in the watchlist-filtered market list When the SPCX row is pressed from the market list Then the leverage pill remains 5x ``` ## **Screenshots/Recordings** SPCX leverage evidence: one before/after pair for the raw carousel value fix, plus watchlist market-list provenance for AC2. <table> <tr><td colspan="2"><strong>SPCX carousel entry changes from raw 100 to formatted 5x</strong></td></tr> <tr> <td align="center" width="50%"><em>Before</em><br/><img src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/30736/recipe-runs/inherited-7fc86479-a81c-4593-a4b0-4290c3534919/before-ac1-spcx-raw-100-clean.png?sha=6ddb5c9edd9a9ff0" alt="before" width="400" /></td> <td align="center" width="50%"><em>After</em><br/><img src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/30736/recipe-runs/inherited-7fc86479-a81c-4593-a4b0-4290c3534919/after-ac1-spcx-5x-clean.png?sha=26e2464746202d3d" alt="after" width="400" /></td> </tr> </table> <table> <tr><td align="center" width="50%"><strong>Watchlist-filtered market list shows SPCX with 5x before row press</strong><br/><img src="https://raw.githubusercontent.com/abretonc7s/mm-mobile-farm-artifacts/main/fixes/30736/recipe-runs/inherited-7fc86479-a81c-4593-a4b0-4290c3534919/after-ac2-watchlist-spcx-row-clean.png?sha=f9292dc060f91c6d" alt="Watchlist-filtered market list shows SPCX with 5x before row press" width="400" /></td><td></td></tr> </table> ## **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. ## **Validation Recipe** <details> <summary>recipe.json</summary> ```json { "schema_version": 1, "pr": "TAT-3262", "title": "Fix SPCX leverage pill formatting from carousel entry", "jira": "TAT-3262", "acceptance_criteria": [ "When the SPCX market detail page is opened via the SpaceX carousel banner, then the leverage pill shows the market’s max leverage formatted as Nx.", "When the SPCX market detail page is opened via the market list, then the leverage pill continues to show the correctly formatted value (no regression).", "When the user opens the order entry screen for SPCX from either entry point, then the leverage shown there matches the pill on the market detail page." ], "validate": { "workflow": { "pre_conditions": ["wallet.unlocked", "perps.feature_enabled"], "entry": "ac1-open-carousel-detail", "nodes": { "ac1-open-carousel-detail": { "action": "navigate", "target": "PerpsMarketDetails", "params": { "market": { "symbol": "xyz:SPCX", "name": "SPCX", "price": "0", "change24h": "0", "change24hPercent": "0", "volume": "0", "marketSource": "xyz", "maxLeverage": "100" }, "source": "carousel" }, "next": "ac1-wait-leverage-viewport" }, "ac1-wait-leverage-viewport": { "action": "wait_for", "test_id": "perps-leverage", "visibility": "viewport", "timeout_ms": 10000, "next": "ac1-wait-carousel-leverage-value" }, "ac1-wait-carousel-leverage-value": { "action": "wait_for", "expression": "(function(){var txt=__AGENTIC__.getTextByTestId('perps-leverage');return JSON.stringify({leverageText:txt});})()", "assert": { "operator": "eq", "field": "leverageText", "value": "5x" }, "timeout_ms": 15000, "next": "ac1-assert-carousel-leverage" }, "ac1-assert-carousel-leverage": { "action": "eval_sync", "expression": "(function(){var route=__AGENTIC__.getRoute();var txt=__AGENTIC__.getTextByTestId('perps-leverage');return JSON.stringify({route:route?route.name:null,leverageText:txt});})()", "assert": { "all": [ { "operator": "eq", "field": "route", "value": "PerpsMarketDetails" }, { "operator": "eq", "field": "leverageText", "value": "5x" } ] }, "next": "ac1-screenshot-carousel-leverage" }, "ac1-screenshot-carousel-leverage": { "action": "screenshot", "filename": "evidence-ac1-carousel-leverage", "note": "AC1: SPCX carousel detail leverage pill visibly shows 5x", "claims": { "must_show": ["SPCX-USD", "5x"], "must_not_show": ["100", "Fund your wallet"] }, "next": "ac2-open-market-list-origin" }, "ac2-open-market-list-origin": { "action": "navigate", "target": "PerpsTrendingView", "params": { "showWatchlistOnly": true, "title": "Watchlist", "showBalanceActions": false }, "next": "ac2-wait-market-list-origin" }, "ac2-wait-market-list-origin": { "action": "wait_for", "route": "PerpsTrendingView", "timeout_ms": 10000, "next": "ac2-wait-spcx-watchlist-row" }, "ac2-wait-spcx-watchlist-row": { "action": "wait_for", "test_id": "perps-market-row-item-xyz:SPCX", "timeout_ms": 15000, "next": "ac2-screenshot-market-list-origin" }, "ac2-screenshot-market-list-origin": { "action": "screenshot", "filename": "evidence-ac2-market-list-origin", "note": "AC2: watchlist-filtered market list visibly contains SPCX with 5x before opening detail", "claims": { "must_show": ["Watchlist", "SPCX", "5x"], "must_not_show": ["SPCX-USD", "Fund your wallet"] }, "next": "ac2-press-spcx-market-row" }, "ac2-press-spcx-market-row": { "action": "press", "test_id": "perps-market-row-item-xyz:SPCX", "next": "ac2-wait-leverage-viewport" }, "ac2-wait-leverage-viewport": { "action": "wait_for", "test_id": "perps-leverage", "visibility": "viewport", "timeout_ms": 10000, "next": "ac2-assert-market-list-leverage" }, "ac2-assert-market-list-leverage": { "action": "eval_sync", "expression": "(function(){var route=__AGENTIC__.getRoute();var market=route&&route.params?route.params.market:null;var txt=__AGENTIC__.getTextByTestId('perps-leverage');return JSON.stringify({route:route?route.name:null,symbol:market?market.symbol:null,leverageText:txt});})()", "assert": { "all": [ { "operator": "eq", "field": "route", "value": "PerpsMarketDetails" }, { "operator": "eq", "field": "symbol", "value": "xyz:SPCX" }, { "operator": "eq", "field": "leverageText", "value": "5x" } ] }, "next": "ac2-screenshot-market-list-leverage" }, "ac2-screenshot-market-list-leverage": { "action": "screenshot", "filename": "evidence-ac2-market-list-leverage", "note": "AC2: SPCX market-list detail leverage pill visibly remains 5x", "claims": { "must_show": ["SPCX-USD", "5x"], "must_not_show": ["100", "Fund your wallet"] }, "next": "done" }, "done": { "action": "end", "status": "pass" } } } } } ``` </details> ## **Recipe Workflow** <details> <summary>workflow.mmd</summary> ```mermaid flowchart TD %% Fix SPCX leverage pill formatting from carousel entry __entry__(["ENTRY"]) --> node_ac1_open_carousel_detail node_ac1_open_carousel_detail["ac1-open-carousel-detail<br/>navigate"] node_ac1_wait_leverage_viewport["ac1-wait-leverage-viewport<br/>wait_for"] node_ac1_wait_carousel_leverage_value["ac1-wait-carousel-leverage-value<br/>wait_for"] node_ac1_assert_carousel_leverage["ac1-assert-carousel-leverage<br/>eval_sync"] node_ac1_screenshot_carousel_leverage["ac1-screenshot-carousel-leverage<br/>screenshot"] node_ac2_open_market_list_origin["ac2-open-market-list-origin<br/>navigate"] node_ac2_wait_market_list_origin["ac2-wait-market-list-origin<br/>wait_for"] node_ac2_wait_spcx_watchlist_row["ac2-wait-spcx-watchlist-row<br/>wait_for"] node_ac2_screenshot_market_list_origin["ac2-screenshot-market-list-origin<br/>screenshot"] node_ac2_press_spcx_market_row["ac2-press-spcx-market-row<br/>press"] node_ac2_wait_leverage_viewport["ac2-wait-leverage-viewport<br/>wait_for"] node_ac2_assert_market_list_leverage["ac2-assert-market-list-leverage<br/>eval_sync"] node_ac2_screenshot_market_list_leverage["ac2-screenshot-market-list-leverage<br/>screenshot"] node_done(["done<br/>PASS"]) node_ac1_open_carousel_detail --> node_ac1_wait_leverage_viewport node_ac1_wait_leverage_viewport --> node_ac1_wait_carousel_leverage_value node_ac1_wait_carousel_leverage_value --> node_ac1_assert_carousel_leverage node_ac1_assert_carousel_leverage --> node_ac1_screenshot_carousel_leverage node_ac1_screenshot_carousel_leverage --> node_ac2_open_market_list_origin node_ac2_open_market_list_origin --> node_ac2_wait_market_list_origin node_ac2_wait_market_list_origin --> node_ac2_wait_spcx_watchlist_row node_ac2_wait_spcx_watchlist_row --> node_ac2_screenshot_market_list_origin node_ac2_screenshot_market_list_origin --> node_ac2_press_spcx_market_row node_ac2_press_spcx_market_row --> node_ac2_wait_leverage_viewport node_ac2_wait_leverage_viewport --> node_ac2_assert_market_list_leverage node_ac2_assert_market_list_leverage --> node_ac2_screenshot_market_list_leverage node_ac2_screenshot_market_list_leverage --> node_done ``` </details> [TAT-3262]: https://consensyssoftware.atlassian.net/browse/TAT-3262?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Localized perps UI enrichment and design-system import cleanup with new unit tests; no auth, payments, or broad trading logic changes. > > **Overview** > Fixes the **SPCX leverage pill** when market details open from the SpaceX carousel with route `maxLeverage` of raw `100` instead of formatted leverage. > > **PerpsMarketDetailsView** now treats route leverage as complete only when `maxLeverage` is a string ending with **`x`**. Otherwise it still loads **`usePerpsMarkets`** and merges by symbol so the UI shows **`5x`** and order entry gets **`defaultMaxLeverage`** from enriched/`usePerpsMarketData` data. Touched **`Text`** / **`ButtonSemantic`** imports move to **`@metamask/design-system-react-native`** with updated variant/color tokens. > > Tests cover unformatted route params (with and without `xyz:` prefix), long-button navigation defaults, and market-list navigation to SPCX with **`perp_markets`** source. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 72df6a8. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.
In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
## **Description**
Add `on_create` trigger mode to the triage forwarder workflow. When a
new issue is opened, it now dispatches to `triage-agent` with
`trigger_mode: "on_create"` so the issue gets auto-triaged immediately.
The existing label-based trigger (`ta-needs-triage`) is preserved as a
separate `forward-labeled` job for manual re-triage. Both paths use OIDC
token exchange. The `ta-bot-triage` lock label prevents
double-processing when both triggers fire on the same issue.
**This PR should NOT be merged until June 1 rollout.**
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: Triage forwarder on_create mode
Scenario: new issue triggers auto-triage
Given the triage forwarder workflow listens to issues opened events
When a user creates a new issue
Then the forwarder dispatches to triage-agent with trigger_mode on_create
Scenario: label-based triage still works
Given the triage forwarder workflow listens to issues labeled events
When a user applies ta-needs-triage label to an issue
Then the forwarder dispatches to triage-agent with trigger_mode label
```
## **Screenshots/Recordings**
N/A — workflow-only change, no UI impact.
### **Before**
### **After**
## **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
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
#### Performance checks (if applicable)
N/A — CI workflow change only.
- [ ] 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]
> **Medium Risk**
> Every new issue will trigger an authenticated dispatch to
triage-agent, increasing automation surface and run volume; auth uses
the existing OIDC token-exchange pattern.
>
> **Overview**
> Extends **triage-forwarder** so new issues can auto-dispatch to
`triage-agent` without waiting for the `ta-needs-triage` label.
>
> The workflow now listens for **`issues` `opened`** in addition to
**`labeled`**, and splits the former single job into
**`forward-labeled`** (unchanged behavior: only when `ta-needs-triage`
is applied, payload `trigger_mode: "label"`) and **`forward-opened`**
(runs on `opened`, same OIDC → token exchange → repository dispatch
path, payload `trigger_mode: "on_create"`).
>
> **Note:** PR description calls out coordinated rollout (not before
June 1) and downstream `ta-bot-triage` locking to avoid duplicate runs
when both paths could apply—those controls are not in this diff.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
270ed02. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ed (#30783) <!-- 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** When `assetsUnifyState` is enabled, `useAddToken` only added tokens to `TokensController`. However, `TransactionPayController` reads token metadata from `AssetsController` (via `getStateForTransactionPay`) and its retry mechanism (`subscribeAssetChanges`) only subscribes to `AssetsController:stateChange`. This caused Predict deposit transactions on Polygon to fail because the required pUSD token metadata was never found. The fix adds a call to `AssetsController.addCustomAsset()` alongside the existing `TokensController.addToken()` when `assetsUnifyState` is enabled. This ensures: - Token metadata (decimals, symbol) is available in `AssetsController.assetsInfo` - `AssetsController:stateChange` fires, triggering the retry in `TransactionPayController` - `addCustomAsset` fetches balance and price data immediately ## **Changelog** CHANGELOG entry: Fixed Predict deposit confirmation showing zero fiat values when assetsUnifyState is enabled ## **Related issues** Fixes: Predict deposit pUSD token not resolving in TransactionPayController ## **Manual testing steps** ```gherkin Feature: Predict deposit token resolution Scenario: user initiates a Predict deposit on Polygon Given the user has assetsUnifyState feature flag enabled And the user has not previously added pUSD to their token list When user initiates a Predict deposit transaction on Polygon Then the confirmation screen shows correct fiat values for the deposit amount And the pay-with token selector is functional ``` ## **Screenshots/Recordings** ### **Before** All fiat values show as $0.00 on the Predict deposit confirmation screen. The `TransactionPayController` logs show "Missing token data" for pUSD with `{decimals: true, symbol: true, fiatRates: true}`. ### **After** Fiat values are correctly calculated. The token is added to both `TokensController` and `AssetsController`, allowing `TransactionPayController` to resolve the token metadata on retry. ## **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** > Scoped to confirmation token-add behind a feature flag; legacy TokensController-only path unchanged when the flag is off. > > **Overview** > When **`assetsUnifyState`** is on, confirmation flows that call **`useAddToken`** now register the token in **`AssetsController`** as well as **`TokensController`**, using the selected EVM account id and a CAIP asset id built from chain and address. > > That mirrors what **`TransactionPayController`** expects (metadata from **`AssetsController`** and retries on **`AssetsController:stateChange`**), so pay/deposit confirmations can show fiat amounts instead of zeros when the token was only in the legacy token list. > > Tests cover the flag off/on paths, **`addCustomAsset`** arguments, and the existing “already added” skip behavior. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 43c460d. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.
In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
## **Description**
- Fix security banner showing `[missing {{symbol}} value]` when token
symbol/name is unavailable (e.g. navigating from Trending to a token
without metadata)
- Fall back to `token.name` when `token.symbol` is empty, and use a
generic "This is a suspicious/malicious token" string when both are
missing
- Applied consistently across the inline banner, bottom sheet, and
sticky footer CTA warning flow
## **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: Adds name fallback if symbol is undefined and shows new
string when both are undefined in security banners.
## **Related issues**
Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-3301
## **Manual testing steps**
```gherkin
Feature: my feature name
Scenario: user [verb for user action]
Given [describe expected initial app state]
When user [verb for user action]
Then [describe expected outcome]
```
## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
<!-- [screenshots/recordings] -->
### **After**
<!-- [screenshots/recordings] -->
<img width="381" height="747" alt="Screenshot 2026-05-29 at 17 48 12"
src="https://github.com/user-attachments/assets/0211dbde-24f0-4050-b0ac-60402d6dd659"
/>
<img width="385" height="775" alt="Screenshot 2026-05-29 at 17 48 21"
src="https://github.com/user-attachments/assets/359e1c72-abe7-4ce9-88ab-dedebcf6b851"
/>
## **Pre-merge author checklist**
<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.
Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->
- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
#### Performance checks (if applicable)
- [ ] I've tested on Android
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> UI copy and display-label fallbacks only; security interception
behavior is unchanged aside from clearer messaging when metadata is
incomplete.
>
> **Overview**
> Fixes broken security trust copy when a token has no `symbol` (e.g.
from Trending): messages no longer show missing `{{symbol}}`
placeholders.
>
> **Display label:** Token details flows now use `token.symbol ||
token.name` for inline banners, badge bottom sheets, and sticky-footer
buy/swap interception (`AssetOverviewContent`,
`TokenDetailsStickyFooter`).
>
> **Copy fallbacks:** New `security_trust.*_no_symbol` strings in
`en.json`, plus `getResultTypeConfig` `getSheetDescription` branches for
empty/undefined symbols on Warning and Malicious. Inline
malicious/suspicious banners and the malicious sheet banner pick symbol
vs generic text the same way.
>
> **Tests:** Coverage added for `getSheetDescription`, empty
`tokenSymbol` in `SecurityBadgeBottomSheet`, and name fallback in
`TokenDetailsStickyFooter`.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
f2cd0c0. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…uthorization list (#30297) ## **Description** When building the EIP-7702 authorization list for a Pay delegation transaction, the nonce was previously read from `NonceLock.nextNonce` — the value computed by the nonce tracker, which accounts for locally-pending transactions the Relay has no visibility into. This could produce a nonce ahead of the true on-chain state, causing the Relay to reject the authorization as invalid. The fix reads `NonceLock.nonceDetails.params.nextNetworkNonce` instead — the raw `eth_getTransactionCount` result that the nonce tracker already fetches internally. This gives the committed on-chain nonce the Relay needs to verify the authorization signature, without introducing a separate provider call or adding a new Engine dependency. ## **Changelog** CHANGELOG entry: null ## **Related issues** Related to: #30798 ## **Manual testing steps** ```gherkin Feature: EIP-7702 Pay delegation transaction Scenario: user submits a Pay transaction requiring EIP-7702 upgrade Given the account has not yet been delegated (not upgraded to EIP-7702) And the account has locally-pending transactions in the queue When user initiates a Pay transaction and confirms Then the authorization list is signed with the correct on-chain nonce And the transaction submits successfully via Relay ``` ## **Screenshots/Recordings** ### **Before** <!-- N/A — no UI change --> ### **After** <!-- N/A — no UI change --> ## **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] > **Medium Risk** > Changes nonce selection for EIP-7702 authorization signing in Pay flows; wrong nonce would break Relay submission but scope is limited to delegation authorization building. > > **Overview** > **EIP-7702 Pay delegation** now signs the authorization list with the **committed on-chain nonce** (`nonceLock.nonceDetails.params.nextNetworkNonce`) instead of the nonce tracker’s **`nextNonce`**, which can include locally pending txs the Relay cannot see. > > Tests were updated to mock `networkClientId` on transaction meta and to return the new nonce lock shape so `KeyringController:signEip7702Authorization` still receives the expected nonce. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 7d0387b. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** Adds the "High price impact" warning surfaces to the QuickBuy bottom sheet, matching what the Swaps design and Figma have. When a quote's price impact meets or exceeds the error threshold, the rate tag in the toolbar switches to a red "High price impact" pill (navigating to Quote Details on tap), a new error-styled Price impact row appears in the Quote Details screen, and tapping the Buy button intercepts to show a "Very high price impact" confirmation view (reusing Bridge's components). <img height="790" alt="Simulator Screenshot - iPhone 17 Pro - 2026-05-29 at 11 19 21" src="https://github.com/user-attachments/assets/1a144cc7-7198-411e-a21b-5b2183b9c64e" /> <img height="790" alt="Simulator Screenshot - iPhone 17 Pro - 2026-05-29 at 11 24 17" src="https://github.com/user-attachments/assets/53cb8c78-1662-4821-a44c-6e665435faf7" /> <img height="790" alt="Simulator Screenshot - iPhone 17 Pro - 2026-05-29 at 11 38 20" src="https://github.com/user-attachments/assets/b41270be-0d9c-458f-b2f4-8b7b0dd81a1d" /> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes when users can submit trades on high price-impact quotes (modal vs disabled button); incorrect routing could allow silent submits or block valid trades. > > **Overview** > Quick Buy now surfaces **high price impact** the same way as Swaps: inline warnings move off footer banners into a toolbar pill, quote details, and an optional confirmation step before submit. > > **Buy flow:** `QuickBuyContext` adds `handleBuy` so Buy no longer calls `handleConfirm` directly. When `isPriceImpactError` and `highPriceImpactModal` are on, Buy navigates to a new `priceImpactConfirm` screen (Bridge `PriceImpactHeader` / `PriceImpactFooter`); otherwise it confirms as before. If the modal feature is off, high-impact quotes keep Buy disabled. `useQuickBuyController` no longer blocks confirm on price impact alone—that gate lives in context. > > **UI:** `QuickBuyRateTag` can show a red “high price impact” pill; quote details gain an error-styled price impact row when in error. Footer `QuickBuyBanners` only show hardware/Solana; price-impact banners are removed. Top Traders enables `highPriceImpactModal: true` in `features.ts`. > > Tests cover context routing, the confirm screen, and updated banner/rate-tag behavior. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 5d87bb1. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…-681) (#30692) ## **Description** Implements the **Add funds** portion of [TMCU-681](https://consensyssoftware.atlassian.net/browse/TMCU-681): when the user taps **Add funds** on the wallet home onboarding checklist (fund step), the app opens the unified ramp buy flow with a preselected asset when buyability data is available. **Priority:** mainnet mUSD → mainnet native ETH (`eip155:1/slip44:60`). If ramp token buyability is still loading, or neither asset is supported for the user’s region, no `assetId` is passed (existing fallback: Token Selection on V2 unified buy). **Implementation:** - `fundRampPriorityAssets.ts` — local CAIP-19 ids and minimal `TokenI` stubs for buyability checks (no Earn / Deposit / Aggregator imports). - `useWalletHomeOnboardingFundRampIntent` — resolves `{ rampIntent, isLoading }` via `useTokensBuyability`. - `useWalletHomeOnboardingChecklistFundPress` — passes resolved intent to `goToBuy` after `RAMPS_BUTTON_CLICKED` analytics (TMCU-680 `location: onboarding_checklist` unchanged). ## **Changelog** CHANGELOG entry: Improved the wallet home onboarding **Add funds** step to open the buy flow with mUSD or Ethereum preselected when those assets are available for the user’s region. ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TMCU-681 ## **Manual testing steps** ```gherkin Feature: Wallet home onboarding fund step ramp preselection Scenario: Add funds opens buy flow with mUSD when mainnet mUSD is buyable Given wallet home onboarding checklist is visible on the fund step And ramp token list includes supported mainnet mUSD for the user's region When user taps Add funds Then unified buy opens on Build Quote (V2) or equivalent buy flow with mUSD preselected Scenario: Add funds opens buy flow with ETH when mUSD is not buyable but ETH is Given wallet home onboarding checklist is visible on the fund step And mainnet mUSD is not buyable but native mainnet ETH is buyable When user taps Add funds Then buy flow opens with native Ethereum preselected Scenario: Add funds opens token selection when buyability is unresolved or neither asset is buyable Given wallet home onboarding checklist is visible on the fund step And ramp buyability is loading or neither mUSD nor ETH is buyable When user taps Add funds Then buy flow opens without a preselected asset (Token Selection on V2 unified buy) ``` ## **Screenshots/Recordings** ### **Before** Add funds opened the buy flow with no preselected token (Token Selection on V2). ### **After** Add funds opens Build Quote with mUSD or ETH when supported per region/token list. https://github.com/user-attachments/assets/e72e2d83-b65f-4a6f-b99a-9c2f4b167451 <!-- Add screenshots/recordings during manual QA if needed --> ## **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 - [ ] 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. [TMCU-681]: https://consensyssoftware.atlassian.net/browse/TMCU-681?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Onboarding-only ramp navigation wiring with region buyability gating; no auth, payments, or core wallet logic changes. > > **Overview** > Wallet home onboarding **Add funds** now opens the ramp buy flow with a **preselected asset** when regional buyability allows it, instead of always starting with no token chosen. > > New logic defines a **mainnet mUSD → mainnet ETH** priority list (CAIP-19 ids and minimal token stubs), resolves a `{ assetId }` **ramp intent** via `useTokensBuyability`, and passes that intent into `goToBuy` from the checklist fund press handler (analytics for `onboarding_checklist` unchanged). While buyability is loading or neither asset is supported, **`goToBuy` still runs with no intent** so existing token-selection fallback behavior applies. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit bc080fe. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## Summary <img width="914" height="743" alt="image" src="https://github.com/user-attachments/assets/eaa554c6-4ad8-4411-be9c-dc49f3d6f6c1" /> - Changing the chain filter in the Quick Buy "Pay with" screen changed the number of token rows, which re-measured the content-sized bottom sheet and shifted the whole layout (poor UX). - Introduces a single global height-locked container in `QuickBuyRoot` that wraps all screens. Its height is measured once (on the first layout) and locked, so navigating between screens (amount → pay with → buy, etc.) and toggling chain filters no longer resizes the sheet. - `QuickBuyPayWithScreen` now lets the token list and empty states fill (`flex-1`) and scroll within the fixed height instead of dictating it. ## Changes - `QuickBuyRoot.tsx`: add `lockedHeight` state + `handleContentLayout` that captures the height once; wrap `renderActiveScreen(...)` in a single `Box` container (`testID="quick-buy-content-container"`) with `onLayout` and a fixed `height` once locked. - `QuickBuyPayWithScreen.tsx`: token list `ScrollView` and both empty states are `flex-1` (empty states centered) so they fill/scroll within the locked height. - Tests: `QuickBuyRoot` locks height on first layout and ignores later differing heights; `QuickBuyPayWithScreen` asserts the list scroll view fills available space. - ## **Changelog** CHANGELOG entry: Locked Quick Buy bottom sheet height to prevent layout shift ## Test plan - [x] `yarn jest QuickBuyRoot.test.tsx QuickBuyPayWithScreen.test.tsx` — 18/18 passing - [x] ESLint clean on changed files - [ ] Manual: open Quick Buy → tap "Pay with" → toggle All/Base/Solana/Linea and confirm the sheet height stays constant across screens and filters Made with [Cursor](https://cursor.com) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > UI-only layout and flex styling in the Social Leaderboard Quick Buy flow; no auth, transactions, or data model changes. > > **Overview** > **Quick Buy** no longer resizes its bottom sheet when **Pay with** content changes (chain filters, fewer token rows, or switching screens). `QuickBuyRoot` wraps all routed screens in a container that records height on the **first** `onLayout` and keeps that fixed height afterward. > > On **Pay with**, empty states and the token list use **`flex-1`** so content scrolls inside the locked area instead of driving sheet size. Tests cover first-layout lock, ignoring later layout events, and scroll view flex growth. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 10319c5. 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> Co-authored-by: Xavier Brochard <xavier-brochard@users.noreply.github.com>
#29130) …erformance testing - WalletView page-object: update element locators for simplified accessibility tree - PerpsMarketDetailsView, PerpsMarketListView, PerpsOrderView: update testIDs for new accessibility structure - PredictDetailsPage, PredictMarketList: update locators after Pressable→TouchableOpacity migration - BrowserStackConfigBuilder: raise maxDepth to 70 (was 15) to expose full homepage hierarchy - Performance specs (login, onboarding, perps, predict): update navigation and assertions - PerformanceReporter/Tracker: reporting improvements and Sentry publisher fixes - aggregate-performance-reports.mjs, generate-slack-summary.sh: report aggregation scripts <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Changes are concentrated in E2E/CI and performance tooling; the only app changes are non-security UI testability fixes (MaskedView pointer events, token testIDs). > > **Overview** > This PR hardens **BrowserStack/Appium performance E2E** and aligns measurements with a simpler accessibility tree: **iOS timers subtract Appium round-trip overhead** via `TimerHelper` + `PlaywrightAssertions` probes; **Android stays wall-clock**. CI adds **`feature_flags_environment`** (client-config) separate from **`build_variant`**, **`TEST_SRP_4`**, longer BS session/timeouts, and **quality-gate failures fail retries** instead of marking runs flaky. > > **Framework & infra:** Locators move to **testIDs / accessibility IDs** (wallet, swaps, Perps, Predict, onboarding, MM Connect); **interactive tap** polling on Android, `withSnapshotSettings`, session-creation timing in reports, CI retries **2**. **Flows:** optional interest questionnaire, GTM modals gated by **feature flags** with UI fallback, richer Predict dismiss. **App:** `pointerEvents="box-none"` on trade wallet `MaskedView` (iOS taps); token rows get **`getAssetTestId`**. > > **Specs:** Thresholds and assertions updated (e.g. asset view, onboarding import, Perps uses **SRP_4** + tutorial helpers); several **swap iOS** and **mm-connect** suites **skipped** (WAPI-1511). **Risk:** mostly test/CI; small **production UI** touch on trade actions and confirmation token list. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 66c814e. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…lows to use OIDC token exchange cp-7.80.0 (#30840) <!-- 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** This updates the `add-team-label` and `check-template-and-add-labels` workflows to use OIDC token exchange. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes how automation authenticates to GitHub (and planning); misconfiguration could break PR/issue labeling until tokens and permissions are correct. > > **Overview** > Two GitHub Actions workflows now obtain GitHub API tokens through **OIDC token exchange** (`MetaMask/github-tools` `get-token@v1` and `vars.TOKEN_EXCHANGE_URL`) instead of repository **secrets** (`TEAM_LABEL_TOKEN`, `LABEL_TOKEN`). > > **`add-team-label`** grants `id-token: write`, mints a read-only token for `MetaMask/MetaMask-planning`, a separate token with `pull_requests: write`, and passes both into `add-team-label@v1` as `planning-token` and `team-label-token`. > > **`check-template-and-add-labels`** adds `contents: read` and `id-token: write`, fetches a scoped token (`issues: write`, `members: read`, `pull_requests: write`), and wires `LABEL_TOKEN` to that output for the existing script step. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit b51e09a. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
… and rename addTraitsToUser in ChoosePassword (#30500) ## **Description** Part of the analytics cleanup workstream (#26686). Migrates `AccountBackupStep1` from the deprecated `useMetrics` to `useAnalytics` (renames the `isMetricsEnabled` local alias to `isAnalyticsEnabled`). Renames `.addTraitsToUser()` → `.identify()` in `ChoosePassword`. Updates both test files accordingly. Files touched: - `AccountBackupStep1/index.js` — migrate `useMetrics` → `useAnalytics`, rename `isMetricsEnabled` → `isAnalyticsEnabled` - `AccountBackupStep1/index.test.tsx` — replace `jest.mock('../../hooks/useMetrics', ...)` factory with `jest.mock('../../hooks/useAnalytics/useAnalytics')` + `createMockUseAnalyticsHook`, rename `mockIsEnabled` → `mockIsAnalyticsEnabled` - `ChoosePassword/index.tsx` — rename `.addTraitsToUser` → `.identify` - `ChoosePassword/index.test.tsx` — remove `addTraitsToUser` from mock object, update assertions to `.identify` ## **Changelog** CHANGELOG entry: null ## **Related issues** Closes: #30513 Refs: #26686 ## **Manual testing steps** N/A ## **Screenshots/Recordings** ### **Before** N/A — no UI changes. ### **After** N/A — no UI changes. ## **Pre-merge author checklist** - [x] I've followed the [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)) ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, test affected areas) - [ ] I confirm that this PR addresses what is claimed in the PR title - [ ] I confirm that I've manually reviewed the changes if not manually tested <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Mechanical API renames on onboarding analytics opt-in and trait identification; behavior should match prior useMetrics/addTraitsToUser paths. > > **Overview** > Continues the analytics cleanup by swapping deprecated metrics APIs for **`useAnalytics`** on onboarding backup and password flows. > > **`AccountBackupStep1`** now uses `useAnalytics` instead of `useMetrics`, with `isAnalyticsEnabled()` gating whether skip flows dispatch straight to success or route through **`OptinMetrics`**. Tests mock `useAnalytics` via `createMockUseAnalyticsHook` instead of the old `useMetrics` factory. > > **`ChoosePassword`** (OAuth post-wallet path) calls **`metrics.identify()`** instead of **`addTraitsToUser()`** when sending device and user-settings traits after analytics preference selection. **`ChoosePassword`** tests drop `addTraitsToUser` from the mock and assert **`identify`** instead. > > No UI or navigation behavior changes beyond aligning with the unified analytics hook naming. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit fd855af. 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>
…30856) ## **Description** When a transaction type has fiat payments enabled via the `confirmations_pay_fiat` remote feature flag, the app should automatically select a fiat payment method (e.g. Apple Pay) if the user has no usable crypto tokens. Previously, fiat auto-selection only happened when explicitly requested via the `autoSelectFiatPayment` navigation parameter (used only by the Money Account "Deposit funds" flow). This change makes fiat auto-selection work for **all** fiat-enabled transaction types (e.g. Perps Deposit, Predict Deposit) when no usable tokens are available, while preserving crypto as the preferred payment method when tokens exist. ### Changes 1. **`useIsFiatPaymentAvailable` (new hook)** — Shared hook encapsulating the fiat-availability check (`hasTransactionType` + payment methods exist). Replaces duplicated inline logic across 3 consumers. 2. **`useAutomaticTransactionPayToken`** — Core fix: when `tokens.length === 0` (no usable non-disabled tokens), attempt fiat auto-selection before giving up. The `autoSelectFiatPayment` explicit opt-in still works as before. 3. **`useTransactionPayAvailableTokens`** — `hasTokens` now checks `availableTokens.some(t => !t.disabled)` instead of `availableTokens.length > 0`. Required tokens with zero balance were counted as "available" despite being disabled (no gas), which prevented the `BuySection` from rendering. 4. **`custom-amount-info.tsx`** — Renamed `hasTokens` → `hasPaymentOption` to clarify the variable includes fiat availability. Uses the new `useIsFiatPaymentAvailable` hook to prevent BuySection flash when fiat will be auto-selected. 5. **`useFiatPaymentHighlightedActions`** — Replaced inline fiat-enabled check with `useIsFiatPaymentAvailable`. ## **Changelog** CHANGELOG entry: Fixed fiat payment method auto-selection for supported transaction types when user has no crypto tokens ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/CONF-1435 ## **Manual testing steps** ```gherkin Feature: Fiat payment auto-selection Scenario: User with no usable tokens opens fiat-enabled deposit Given the user has no tokens with balance on the relevant chain And the transaction type (e.g. perpsDeposit) is in the fiat enabledTransactionTypes feature flag And at least one Ramps payment method is available When user opens the Add Funds screen for that transaction type Then a fiat payment method (e.g. Apple Pay) is automatically selected And the deposit keyboard is shown (not the Buy crypto button) Scenario: User with tokens opens fiat-enabled deposit Given the user has tokens with balance And the transaction type is in the fiat enabledTransactionTypes feature flag When user opens the Add Funds screen Then a crypto token is automatically selected (fiat is not forced) Scenario: User with no tokens opens non-fiat-enabled deposit Given the user has no usable tokens And the transaction type is NOT in the fiat enabledTransactionTypes feature flag When user opens the Add Funds screen Then the Buy crypto button is shown ``` ## **Screenshots/Recordings** ### **Before** ### **After** In the recordings `perpsDeposit` is fiat payment enabled, `predictDeposit` is fiat payment disabled: https://github.com/user-attachments/assets/ae22c510-0a21-4a30-be63-dbe25b387249 https://github.com/user-attachments/assets/1b7749c2-5858-4768-bfa8-333868286f66 ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches default payment selection and deposit UI for multiple transaction types; behavior depends on remote fiat flags and Ramps payment methods, with test coverage but real-device flows should be spot-checked. > > **Overview** > Fiat-enabled deposit flows now **auto-select a Ramps payment method** when the user has no usable crypto tokens, not only when `autoSelectFiatPayment` is passed from Money Account deposit. > > A new **`useIsFiatPaymentAvailable`** hook centralizes “transaction type allowed by fiat flags + at least one payment method.” **`useAutomaticTransactionPayToken`** runs fiat auto-selection when `autoSelectFiatPayment` is set **or** the filtered usable token list is empty, and stops falling back to a required target token when fiat is unavailable. **`useTransactionPayAvailableTokens`** treats `hasTokens` as “any non-disabled token” so disabled required tokens no longer block fiat/Buy UI. **`custom-amount-info`** uses **`hasPaymentOption`** (crypto or fiat) for keyboard, Pay With, and Buy section so fiat-enabled screens avoid a Buy flash before auto-selection. > > Tests cover the new hook, disabled-token `hasTokens` behavior, and updated auto-select expectations. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 8b19714. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…d-labels` (#30875) <!-- 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** `token-exchange-service` is having a permission issue, so to unblock CI while waiting for that to be resolved I've added a temporary fallback to the Patroll token. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Labeling automation may run with a long-lived PAT instead of a short-lived exchanged token, which affects credential handling and should be reverted once token exchange is fixed. > > **Overview** > Unblocks the **Check template and add labels** workflow when `token-exchange-service` cannot mint a token. > > The **Get access token** step now uses `continue-on-error: true` so a failed MetaMask `get-token` action does not fail the job. `LABEL_TOKEN` for the labeling script is set to the exchanged token when present, otherwise **`secrets.LABEL_TOKEN`** (Patroll PAT) as a temporary fallback. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 19668bf. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> - Updates to supported price-api chains - Improvement for `MulticallClient` in assets-controller ## **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/ASSETS-3304 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [X] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [X] I've completed the PR template to the best of my ability - [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] > <sup>[Cursor Bugbot](https://cursor.com/bugbot) is generating a summary for commit 318be02. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…nd history tabs (#30718) ## **Description** Adds the new full-page Predict Positions destination for PRED-900. The screen is gated behind `predictPortfolio.enabled`, uses Positions terminology for the route/title/tabs, and is powered by the shared Predict portfolio model. This PR includes: - New `Routes.PREDICT.POSITIONS` route and typed `PredictPositionsParams`. - New `PredictPositionsView` with fixed Predict header, `Positions` title, `Active positions` and `History` tabs. - New `PredictPositionsViewHeader` for available balance, optional Unrealized P&L, and Claim CTA. - Shared `PredictPositionsEmpty` with Browse markets CTA. - `PredictPositionsList` for active/open positions only. - `PredictPositionsHistoryList` wrapper around `PredictTransactionsView` for v1 history rendering. - `PredictTransactionsView` support for custom empty state and spacing overrides. - Unit and component-view coverage for route gating, tabs, empty states, claim CTA, history wrapper, and screen presets. - Removal of the temporary Positions button from the Predict feed. ## **Changelog** CHANGELOG entry: Added a new Positions screen for Predict users to view active positions and history ## **Related issues** Fixes: [PRED-900](https://consensyssoftware.atlassian.net/browse/PRED-900) ## **Manual testing steps** ```gherkin Feature: Predict Positions screen Scenario: user views active positions Given the predictPortfolio feature flag is enabled And the user has Predict available balance and open positions When user navigates to the Predict Positions route Then the Positions title is shown And the available balance is shown And Unrealized P&L is shown only when the display threshold is met And only open positions are listed under Active positions Scenario: user views claimable winnings Given the user has claimable Predict winnings When user opens the Predict Positions route Then the Claim CTA is shown in the summary header Scenario: user views history Given the user is on the Predict Positions route When user taps History Then Predict transaction history is shown Scenario: user sees empty state Given the user has no active positions or history When user opens Active positions or History Then the shared empty state is shown When user taps Browse markets Then user returns to the Predict market list without creating duplicate nested feeds Scenario: route is feature-flag disabled Given the predictPortfolio feature flag is disabled When user attempts to navigate to the Predict Positions route Then user is returned to the Predict market list ``` ## **Screenshots/Recordings** ### **Before** N/A - new screen route. ### **After** https://github.com/user-attachments/assets/d628042f-265d-471e-a4b5-1a8e9bfe058d ## **Testing** - `yarn jest app/components/UI/Predict/views/PredictPositionsView/PredictPositionsView.test.tsx app/components/UI/Predict/routes/index.test.tsx app/components/UI/Predict/components/PredictPositionsEmpty/PredictPositionsEmpty.test.tsx app/components/UI/Predict/components/PredictPositionsList/PredictPositionsList.test.tsx app/components/UI/Predict/components/PredictPositionsHistoryList/PredictPositionsHistoryList.test.tsx app/components/UI/Predict/views/PredictTransactionsView/PredictTransactionsView.test.tsx app/components/UI/Predict/views/PredictFeed/PredictFeed.test.tsx` - `yarn jest -c jest.config.view.js app/components/UI/Predict/views/PredictPositionsView/PredictPositionsView.view.test.tsx --runInBand --silent --coverage=false` - `yarn eslint app/components/UI/Predict/Predict.testIds.ts app/components/UI/Predict/components/PredictActivity/PredictActivity.tsx app/components/UI/Predict/components/PredictPositionsEmpty/PredictPositionsEmpty.test.tsx app/components/UI/Predict/components/PredictPositionsEmpty/PredictPositionsEmpty.tsx app/components/UI/Predict/components/PredictPositionsEmpty/index.ts app/components/UI/Predict/components/PredictPositionsHistoryList/PredictPositionsHistoryList.test.tsx app/components/UI/Predict/components/PredictPositionsHistoryList/PredictPositionsHistoryList.tsx app/components/UI/Predict/components/PredictPositionsHistoryList/index.ts app/components/UI/Predict/components/PredictPositionsList/PredictPositionsList.test.tsx app/components/UI/Predict/components/PredictPositionsList/PredictPositionsList.tsx app/components/UI/Predict/components/PredictPositionsList/index.ts app/components/UI/Predict/components/PredictPositionsViewHeader/PredictPositionsViewHeader.test.tsx app/components/UI/Predict/components/PredictPositionsViewHeader/PredictPositionsViewHeader.tsx app/components/UI/Predict/components/PredictPositionsViewHeader/index.ts app/components/UI/Predict/routes/index.test.tsx app/components/UI/Predict/routes/index.tsx app/components/UI/Predict/types/navigation.ts app/components/UI/Predict/views/PredictFeed/PredictFeed.test.tsx app/components/UI/Predict/views/PredictFeed/PredictFeed.tsx app/components/UI/Predict/views/PredictPositionsView/PredictPositionsView.test.tsx app/components/UI/Predict/views/PredictPositionsView/PredictPositionsView.tsx app/components/UI/Predict/views/PredictPositionsView/PredictPositionsView.view.test.tsx app/components/UI/Predict/views/PredictPositionsView/index.tsx app/components/UI/Predict/views/PredictTransactionsView/PredictTransactionsView.test.tsx app/components/UI/Predict/views/PredictTransactionsView/PredictTransactionsView.tsx app/constants/navigation/Routes.ts tests/component-view/mocks.ts tests/component-view/renderers/predictPositions.tsx` ESLint completed with 0 errors and existing warnings for deprecated `HeaderSearch`, deprecated `TabEmptyState`, and `no-void` in `PredictTransactionsView`. ## **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 - [ ] 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 - [ ] I've tested with a power user scenario - [ ] I've instrumented key operations with Sentry traces for production performance metrics ## **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. [PRED-900]: https://consensyssoftware.atlassian.net/browse/PRED-900?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches portfolio display, claim flow (action guard), and navigation gating; large UI surface but behind a feature flag with extensive tests. > > **Overview** > Adds a **feature-flagged** full-page Predict **Positions** destination (`Routes.PREDICT.POSITIONS`) behind `predictPortfolio.enabled`, with a route wrapper that redirects to the market list when the flag is off. > > **`PredictPositionsView`** composes a summary header (available balance, optional unrealized P&L, guarded **Claim** CTA), **Active positions** / **History** tabs (optional `initialTab` route param), and tab panels that stay mounted but hidden for accessibility. New pieces include **`PredictPositionsList`** (open positions only, skeletons, privacy mode, market-details navigation), **`PredictPositionsHistoryList`** (reuses **`PredictTransactionsView`** with shared empty state and padding overrides), and **`PredictPositionsEmpty`** (Browse markets via `popToTop` or navigate to market list). > > **`usePredictPortfolio`** exposes **`isOpenPositionsLoading`** separately from claimable-position loading so the UI can show P&L skeletons vs empty states correctly. **`PredictTransactionsView`** / **`PredictActivity`** accept custom empty states and layout overrides. i18n, test IDs, navigation types, component-view mocks/renderers, and broad unit/view tests cover the new flow. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit e8b3b8f. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## Summary - Add an opt-in `beforeRemove` cleanup path to `useClearConfirmationOnBackSwipe`. - Enable that cleanup for the Predict claim confirmation screen. - Guard against duplicate rejection when both gesture and route removal events fire. ## Root cause The Predict claim confirmation could be dismissed through route removal without the existing `gestureEnd` cleanup firing. That left the transaction approval unresolved and `PredictController.pendingClaims[address]` stuck, so returning to the Predict UI showed the “Claim already in progress” toast. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes confirmation reject/navigation timing and Predict pending-claim state; behavior is covered by new tests but affects transaction approval dismissal paths. > > **Overview** > Fixes Predict claim confirmations leaving **`pendingClaims`** set when the screen is dismissed via route removal (not only swipe **`gestureEnd`**), which blocked later claims with “already in progress.” > > Adds **`PredictController.clearPendingClaim()`** and wires the claim confirmation UI to call it through an expanded **`useClearConfirmationOnBackSwipe`**: optional **`beforeRemove`** / gesture-aware rejection, **`onBeforeReject`** cleanup, single-reject deduping, and optional **`skipNavigation`** on reject. **`isConfirmationSubmitting`** in confirmation context is set while the claim CTA runs so back/gesture dismissal does not reject or clear state mid-submit. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 4df7bbc. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** Add gainers and losers section in Explore/Now <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: add gainers and losers section in Explore/Now ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-3298 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > UI and navigation param changes in Explore/Perps with no auth, payments, or data-persistence logic beyond existing sort preferences. > > **Overview** > **Explore → Now** adds **Gainers / Losers** pills on **Perps movers**, filters markets by sign of 24h price change, and sorts gainers descending / losers ascending via new `filterAndSortByPriceChangeDirection` in `usePerpsFeed`. > > **View all** now opens the perps market list with matching sort: `navigateToPerpsMarketList` takes an options object (`sortDirection`, optional `source`) and passes `defaultSortDirection` through navigation into `usePerpsMarketListView`, so list ordering aligns with the selected pill (not only saved user prefs). Copy added for the new pill labels in `en.json`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 61a03c3. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> ## **Description** Add world cup predictions in explore (FF gated) <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: add world cup predictions in explore (FF gated) ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-3203 & https://consensyssoftware.atlassian.net/browse/ASSETS-3204 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** https://github.com/user-attachments/assets/68bb1434-b489-46d0-af3a-aa82b6ea3c48 <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > UI and navigation changes behind existing Predict/World Cup flags; no auth or payment logic touched. > > **Overview** > Explore **Now** and **Sports** can show a **World Cup predictions** carousel when the World Cup screen feature flag is on, instead of the usual category feeds. A new `useWorldCupPredictionsFeed` loads World Cup markets and disables the standard `usePredictionsFeed` while active so only one preview fetches at a time. > > **View all** routes to the dedicated Predict World Cup screen (`navigateToExploreWorldCupPredictions`) with explore entry point and the **All** tab; otherwise behavior is unchanged. List navigation now always passes an explicit `tab` (including `trending`). Copy adds `predict.world_cup.predictions_title`. Tests cover navigation and both tab variants. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 2026668. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
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 : )