[pull] main from MetaMask:main#581
Merged
pull[bot] merged 9 commits intoReality2byte:mainfrom Mar 6, 2026
Merged
Conversation
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** If the user is on a send confirmation and the app goes idle until the device and MetaMask lock, after unlocking they no longer see that confirmation. If they then start a **new** send, the UI can show the **previous** confirmation instead of the new one, because the old approval was never rejected and remains first in the pending list. **Solution** When the app locks, reject all pending approvals by calling `ApprovalController.clear(providerErrors.userRejectedRequest())` in the lock saga, before navigating to the lock screen. That way there are no stale confirmations after unlock, and any new send shows the correct confirmation. **Changes** - **`app/store/sagas/index.ts`**: In `appLockStateMachine`, after handling `LOCKED_APP`, clear pending approvals via `Engine.context.ApprovalController.clear(...)` inside try/catch, then navigate to `LOCK_SCREEN`. Log and ignore errors so navigation still runs. - **`app/store/sagas/sagas.test.ts`**: Add `ApprovalController` with `clear` to the Engine mock; add tests that clear is called with `userRejectedRequest()` when the app locks and that navigation to `LOCK_SCREEN` still happens when `clear` throws. - <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Fixed issue of confirmation not rejecting when app locks ## **Related issues** Fixes: #26320 ## **Manual testing steps** ```gherkin Feature: Transaction Confirmation Persistence After Lock Scenario: Stale confirmation displayed after device lock timeout and new transaction Given the user has MetaMask open and unlocked on the home screen # First transaction When user initiates a send transaction And user reaches the confirmation screen # Lock timeout And user allows the phone to idle until device and MetaMask lock And user unlocks the phone And user unlocks MetaMask Then the confirmation screen should no longer be open # Second transaction - bug occurs When user initiates a different send transaction And user reaches the confirmation screen Then the confirmation shown should be for the previous transaction instead of the current one ``` ## **Screenshots/Recordings** [reject-approval-app-locks.webm](https://github.com/user-attachments/assets/ed331559-bf7a-452b-8688-7014dd4bff34) <!-- 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** - [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** > Changes approval/confirmation lifecycle by clearing all pending approvals on app lock, which could inadvertently reject legitimate in-flight requests if triggered unexpectedly. Guarded with try/catch and covered by new saga tests, but behavior impacts transaction confirmations. > > **Overview** > Prevents stale transaction/permission confirmations after unlocking by clearing any pending approvals when `UserActionType.LOCKED_APP` fires, rejecting them with `providerErrors.userRejectedRequest()` before navigating to `Routes.LOCK_SCREEN`. > > Updates saga tests to mock `ApprovalController.clear` and assert it is invoked on lock, and that navigation to the lock screen still occurs even if clearing approvals throws. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 2f1c2d3. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Adds a `session_summary` analytics event that fires when a user navigates away from the homepage. This completes the homepage sections analytics suite alongside the existing `section_viewed` event. The event reuses the `HOMEPAGE_SECTION_VIEWED` Segment event with `interaction_type: 'session_summary'` and captures: - `total_sections_viewed`— how many sections reached ≥50% visibility this visit - `total_sections_loaded` — how many sections were enabled via feature flags - `entry_point` — how the user arrived (app_opened, home_tab, navigated_back) - `session_time` — seconds spent on the homepage location: 'home' Implementation details: - New `useHomepageSessionSummary` hook owns all session tracking. All state lives in refs — zero re-renders on scroll or blur path. - Reacts to visitId increments from `useHomepageEntryPoint` to detect focus and reset per-visit state. - Fires on navigation blur via a stable ref-wrapped callback to avoid stale closures. - `notifySectionViewed` added to `HomepageScrollContext` so sections self-report views when their `section_viewed` event fires. Segment Event PR: Consensys/segment-schema#477 This PR needs to be merged first before review: #26529 ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: Homepage session summary analytics Scenario: user navigates away from the homepage Given the homepage sections feature flag is enabled And the user is on the homepage When user navigates to another screen (e.g. sends a transaction) Then a session_summary event fires with interaction_type "session_summary" And session_time reflects time spent on the homepage And total_sections_viewed reflects sections that entered the viewport Scenario: feature flag is disabled Given the homepage sections feature flag is disabled When user navigates away from the homepage Then no session_summary event is fired ``` ## **Screenshots/Recordings** https://github.com/user-attachments/assets/573caf7a-3afe-4cee-a1e1-5f447f877bac ### **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 - [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** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Adds new analytics firing on homepage blur and expands `HomepageScrollContext` contract, which could affect event volume/accuracy if focus/visit tracking is wrong. Runtime risk is limited since it uses refs/sets and doesn’t change wallet transaction or account logic. > > **Overview** > Adds a new homepage *session summary* analytics emission: `useHomeSessionSummary` fires `MetaMetricsEvents.HOME_VIEWED` with `interaction_type: 'session_summary'` when the homepage blurs, including `session_time`, `entry_point`, `total_sections_loaded`, and `total_sections_viewed`. > > Extends `HomepageScrollContext` with `notifySectionViewed`/`getViewedSectionCount`; `Wallet` now tracks distinct viewed sections per `visitId` in a ref-backed `Set`, and `useHomeViewedEvent` reports section views into this aggregator. Includes new unit tests for the session-summary hook and updates existing section-view tests for the new context fields. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit d91715f. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description**
Fixes a bug in the bridge token selector where Polygon's native token
(POL) appeared twice in the list — once with balance at the top and once
without balance at the bottom. Selecting the balance entry as a
destination token caused the quote to show 0 and the rate to display
"--".
**Root cause**: Polygon's native token uses address
`0x0000000000000000000000000000000000001010` in wallet state (from
`getNativeTokenAddress`), but the bridge API expects `AddressZero`
(`0x0000...0000`) for all native assets. The bridge-controller's
`isNativeAddress()` does not recognize `0x...1010` as native, so:
1. `tokenToIncludeAsset` sent the wrong asset ID (`erc20:0x...1010`
instead of `slip44:966`) to the API, which couldn't deduplicate it with
its own native POL entry.
2. When the user selected POL with `0x...1010`, quote matching in
`useBridgeQuoteData` failed because the returned quote used
`AddressZero` for `destAsset.address`.
**Fix**: Extracted the existing normalization logic from
`useTokenAddress` into a reusable pure function `normalizeTokenAddress`,
and applied it in `useTokensWithBalance` when building `BridgeToken`
objects from wallet state. This ensures POL enters the bridge flow with
`AddressZero` from the start, fixing both the duplicate listing and the
quote/rate mismatch.
## **Changelog**
CHANGELOG entry: Fixed a bug where Polygon's native token (POL) appeared
twice in the bridge token selector and selecting it showed incorrect
quote data.
## **Related issues**
Fixes:
## **Manual testing steps**
```gherkin
Feature: Bridge token selector - Polygon native token
Scenario: user selects POL as destination token on Polygon
Given user has a POL balance on Polygon
And user opens the bridge token selector for destination
When user filters by Polygon network
Then POL appears only once in the token list with balance displayed
Scenario: user gets a valid quote after selecting POL destination
Given user has a source token with balance
And user has selected POL on Polygon as the destination token
When the quote loads
Then the destination input shows a non-zero amount
And the rate displays a valid exchange rate (not "--")
```
## **Screenshots/Recordings**
### **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
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Medium risk because it changes how token addresses are represented in
the bridge token list and downstream API/quote matching, which could
affect token identification on Polygon. Scope is small and isolated to
bridge token normalization.
>
> **Overview**
> Fixes Polygon native token (POL) handling in the bridge UI by
normalizing Polygon’s non-zero native token address to the zero address
the bridge API expects.
>
> Extracts the Polygon-specific normalization from `useTokenAddress`
into a reusable `normalizeTokenAddress` utility and applies it when
constructing tokens in `useTokensWithBalance`, preventing duplicate POL
entries and quote mismatches caused by inconsistent native-address
representations.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b0deef0. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description** This PR implements the mobile Swap zero-state Trending Tokens experience for Bridge and hardens related Bridge rendering behavior. Key updates: - Added `BridgeTrendingTokensSection` to render Trending tokens only in Swap zero state. - Added filter controls (Sort by / Network / Time) and list chunking with a centered "Load more" action while preserving single-screen scroll behavior. - Refined `BridgeView` content-mode precedence so loading/error/quote/zero states render deterministically. - Preserved quote + confirm visibility during quote refresh (`isLoading && activeQuote`) and only show skeleton when loading without an active quote. - Updated/expanded Bridge tests and removed brittle snapshot dependency in `BridgeView` tests. ## **Changelog** CHANGELOG entry: Added Trending tokens to the mobile Swap zero state with filter controls and improved Bridge quote/loading state handling. ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/SWAPS-4038 ## **Manual testing steps** ```gherkin Feature: Swap zero-state trending list on mobile Scenario: Trending list visibility follows zero state Given user is on the Swap screen When no source amount is entered Then Trending tokens are visible below the swap form When user enters a non-zero source amount Then Trending tokens are hidden Scenario: Numpad hidden on initial load Given user opens Swap for the first time When the screen is rendered Then numpad is hidden and swap form is visible Scenario: Quote loading and refresh behavior Given user has entered a non-zero amount When quote is loading with no active quote Then quote skeleton is shown and trending list is hidden When quote is refreshing with an active quote Then quote content and confirm button remain visible Scenario: Single scroll behavior Given user is in zero state with Trending tokens visible When user scrolls Then swap form and trending list scroll together in one vertical scroll area Scenario: Filters update results Given user is in zero state with Trending tokens visible When user changes Sort by, Network, or Time filters Then list content updates to match selected filters And default sort is Price change high to low ``` ## **Screenshots/Recordings** ### **Before** N/A ### **After** https://github.com/user-attachments/assets/e55f04c5-6190-4c26-a15a-2e0c00a8b879 ## **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** > Changes Bridge/Swap screen rendering precedence (loading/error/quote/zero) and scroll behavior, which could affect quote visibility and confirm UX during refreshes. Mostly UI/state-driven with good test coverage but touches a core transaction entry flow. > > **Overview** > Adds a **Swap zero-state Trending Tokens** section to `BridgeView`, gated behind the temporary `swapsTrendingTokens` remote feature flag, with filter bottom sheets and incremental “show more” loading triggered by button or near-bottom scroll. > > Refactors `BridgeView` to render deterministically via a `contentMode` state machine: shows a `QuoteDetailsCardSkeleton` only when *loading without an active quote*, preserves quote + confirm UI while refreshing (`isLoading && activeQuote`), and keeps error banners/zero-state separate from quote content. > > Updates styles to support a single unified scroll area (inputs + dynamic content), introduces new `testID`s, and rewrites/expands tests to avoid brittle snapshots and to assert the new loading/error/quote/zero behaviors (including mocking the trending section). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit ab8ffe2. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
…laim timeline (#27097) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** This PR updates mUSD conversion copy to reflect annualized bonus and claim timeline. <!-- 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: updated mUSD conversion copy to reflect annualized bonus and claim timeline ## **Related issues** Fixes: - [MUSD-392: Annual bonus copy](https://consensyssoftware.atlassian.net/browse/MUSD-392) - [MUSD-393: Communicate the timeframe of the bonus](https://consensyssoftware.atlassian.net/browse/MUSD-393) ## **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] --> ### Education screen <img width="489" height="1022" alt="image" src="https://github.com/user-attachments/assets/e4435213-193b-4fc8-9212-4c797a5a3fc1" /> ### Custom convert navbar tooltip <img width="489" height="1022" alt="image" src="https://github.com/user-attachments/assets/b26a4251-4c2e-4aa0-b044-279894e609ce" /> ### Claimable bonus tooltip Custom convert <img width="489" height="1022" alt="image" src="https://github.com/user-attachments/assets/8e706082-165b-455e-835b-f17c555fd313" /> Quick conver <img width="489" height="1022" alt="image" src="https://github.com/user-attachments/assets/842dfe5f-fb8c-40dd-ba71-6609b2fbfb2f" /> ### Asset details CTA <img width="489" height="1022" alt="image" src="https://github.com/user-attachments/assets/10d66946-64e2-4bb4-8d9a-915f64cef29a" /> ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk: primarily copy/translation key updates plus minor UI tooltip/toast rendering changes (adds a terms link and an extra success-toast description) with no changes to conversion logic or data handling. > > **Overview** > Updates mUSD conversion user-facing messaging to consistently describe the incentive as an *annualized bonus* and to communicate that the bonus becomes claimable within about a day. > > This refreshes strings across the education screen, quick convert header, asset overview CTA, claimable bonus tooltip, and conversion success toast (now includes a secondary description line), and adjusts the confirmation `PercentageRow` tooltip to include a tappable “Terms apply” link to the bonus terms URL. Tests are updated to match the new copy and label formatting. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 388fcc0. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** This PR is the Rewards-only split of the `color-no-hex` batch work, extracted from the original umbrella PR #26651. Scope: - Rewards files only (`app/components/UI/Rewards/**`) - temporary eslint rollout override for `app/components/UI/Rewards/**/*.{js,jsx,ts,tsx}` - includes replacing straightforward mock color suppressions with `mockTheme` in a subset of Rewards tests Reference PR: #26651 ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: color-no-hex rewards batch Scenario: validate rewards lint and tests Given this branch is checked out When running eslint for Rewards scope Then there are no lint errors When running jest for Rewards scope with snapshot updates Then tests pass ``` ## **Screenshots/Recordings** ### **Before** N/A (test/lint/config updates only) ### **After** N/A (test/lint/config updates only) ## **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 - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low runtime risk since changes are limited to ESLint configuration plus test/story updates; main risk is CI/dev friction if any remaining Rewards hex literals trigger the newly-enforced lint rule. > > **Overview** > **Enforces `@metamask/design-tokens/color-no-hex` for Rewards UI code.** Updates `.eslintrc.js` to include `app/components/UI/Rewards/**/*` in the folders where hex colors are treated as lint errors. > > **Aligns Rewards tests/stories with the rule.** Rewards tests now mock `useTheme` by reusing the shared `mockTheme` (and remove a local onboarding `mockTheme` helper), and a Rewards Storybook story (`RewardPointsAnimation`) is refactored to use Tailwind/design-system `Button`s instead of inline styles/hex colors, with a couple of tests explicitly scoping hex-only mock API colors behind lint disables. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 3a5d5c1. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** As part of Tron's staking experience improvements we will be sending more special assets from the Snap to the Extension. These special assets are not tradeable tokens and should be filtered out from selectors like we already do for Staked TRX for example. This PR: - Adds the new special assets that should be ignored by the selectors - Renames the variables that deal with this logic to be more inclusive of assets that are not resources (only Energy and Bandwidth are resources) ## **Changelog** CHANGELOG entry: null ## **Related issues** Closes: [NEB-582](https://consensyssoftware.atlassian.net/browse/NEB-582), [NEB-584](https://consensyssoftware.atlassian.net/browse/NEB-584), [NEB-586](https://consensyssoftware.atlassian.net/browse/NEB-586) ## **Manual testing steps** All existing Tron functionality should remain unchanged ## **Screenshots/Recordings** As you can see, the new assets being loaded from the preview build of MetaMask/snap-tron-wallet#226 are not being shown here. ### **Before** n/a ### **After** n/a ## **Pre-merge author checklist** - [x] I've followed MetaMask Contributor Docs and MetaMask Mobile Coding Standards. - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using JSDoc format if applicable - [x] I've applied the right labels on the PR [NEB-582]: https://consensyssoftware.atlassian.net/browse/NEB-582?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [NEB-584]: https://consensyssoftware.atlassian.net/browse/NEB-584?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [NEB-586]: https://consensyssoftware.atlassian.net/browse/NEB-586?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes token/asset filtering for Tron by excluding additional Snap-provided “special assets” from sorted asset lists and unified multichain token lists, which could inadvertently hide tokens if symbols collide or filtering is misapplied. Scope is contained to Tron selectors/utilities and related UI consumers, with broad test updates. > > **Overview** > Introduces a broader Tron *“special assets”* concept (resources + staking lifecycle assets) and filters these virtual tokens out of user-facing asset/token lists. > > Renames and expands the Tron selector from `selectTronResourcesBySelectedAccountGroup` to `selectTronSpecialAssetsBySelectedAccountGroup` (and `TronResourcesMap` to `TronSpecialAssetsMap`), adding mappings for `trxReadyForWithdrawal`, `trxStakingRewards`, and `trxInLockPeriod` while preserving `totalStakedTrx` computation. > > Centralizes special-asset detection in `core/Multichain/utils` via `isTronSpecialAsset` and reuses it in `selectSortedAssetsBySelectedAccountGroup`, `selectAccountTokensAcrossChainsUnified`, and Bridge `isTradableToken`; updates related Earn/TokenDetails/AssetOverview hooks and tests accordingly. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 893e98a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Previously, the price impact value color was driven by a warning boolean and effectively rendered as default or red. This change updates the value color by threshold so the UI communicates risk levels more clearly: - Price impact `>= 5%` shows warning color (yellow) - Price impact `>= 25%` shows error color (red) - Otherwise it remains the default alternative text color ## **Changelog** CHANGELOG entry: Updated swap price impact text coloring. ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/SWAPS-4020 https://consensyssoftware.atlassian.net/browse/SWAPS-4024 ## **Manual testing steps** ```gherkin Ensure acceptance criteria pass. ``` ## **Screenshots/Recordings** ### **Before** Price impact value color only switched between default and red. ### **After** Price impact value color now maps to thresholds: - default: `< 5%` - yellow: `>= 5%` - red: `>= 25%` ## **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** > Changes the Bridge confirmation flow to conditionally gate execution behind a new price-impact modal and adds navigation resets on quote expiry, which can affect swap completion and modal routing. Risk is mitigated by extensive new unit tests but touches user-critical transaction submission UX. > > **Overview** > Adds a new `PriceImpactModal` (with header/description/footer) and wires it into Bridge modal routes, including new i18n copy for *info*, *warning*, and *high price impact* states. > > Updates `QuoteDetailsCard` to always show a **Price impact** row with an info button that opens the modal, and switches price-impact coloring/iconography to threshold-based view data (warning at `>=5%`, error at `>=25%`) plus safer formatting for missing/invalid/negative values. > > Refactors swap submission by introducing `useBridgeConfirm` and updating `SwapsConfirmButton` to accept/forward an explicit analytics `location`; if price impact meets the error threshold it now navigates to the modal (`Execution` type) instead of submitting immediately. Adds `useModalCloseOnQuoteExpiry` and applies it across Bridge modals to reset the modal stack to `QuoteExpiredModal` when quotes expire. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 3941641. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: GeorgeGkas <georgegkas@gmail.com>
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** # Perpetuals section – performance and stability Performance audit follow-up: fewer re-renders, no redundant subscriptions on the homepage, and safer selectors/hooks. ## Homepage Perps - **Carousel: static data only** – Removed live price subscription from `PerpsMarketTileCard`. Tiles use the market snapshot from `usePerpsMarkets()` (price, change24hPercent). No WebSocket per symbol on the homepage; fewer subscriptions and re-renders. - **Tile card** – Dropped `livePrices` / `disableLivePrices`; component always uses static market data. Removed `TileCardWithLivePrices` and `usePerpsLivePrices` usage there. - **Position rows** – `PositionCardItem` with a `positionDisplayKey` (symbol, entryPrice, size, unrealizedPnl, takeProfitPrice, stopLossPrice) and custom `React.memo` compare so only cards whose display data changed re-render on stream updates. - **Defensive defaults** – `?? []` for watchlist/carousel arrays and `carouselSymbols` so selectors or partial state (e.g. E2E/minimal fixtures) never pass `undefined` into hooks or `.map()`. - **Sparklines** – `useHomepageSparklines`: guard `candleData?.candles` (fixes E2E crash when `candles` is undefined), `safeSymbols` so `symbols` is never undefined, and microtask batching so multiple symbol callbacks trigger one state update. ## Perps selectors & components - **perpsController selectors** – Try/catch and defaults when state is missing or partial (e.g. before Engine init or in E2E). Avoids calling package selectors with `undefined` and normalizes return values (`?? []` / default prefs). - **PerpsCard / PerpsPositionCard** – Wrapped with `React.memo` to avoid unnecessary re-renders when parent updates. - **usePerpsMarketListView** – `savedSortPreference.optionId` cast to `SortOptionId` for type safety. ## Tests - **PerpsSection** – Tests for `positionDisplayKey` (stable key, optional fields, TP/SL, same key when only non-display fields differ). - **PerpsMarketTileCard** – Removed live-price mock and related test; added “displays market change24hPercent” for static data. - **useHomepageSparklines** – Async `act` where needed for microtask-flushed updates. - **Homepage** – `useFocusEffect` mock simplified (invoke callback once). ## **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/TMCU-512 ## **Manual testing steps** ```gherkin Feature: Perpetuals section performance and data freshness Scenario: Homepage carousel shows static data and does not re-render on a timer Given the user is on the homepage with no open perps positions/orders When the trending perps carousel is visible Then the section title and carousel tiles show market data (symbol, price, 24h change) And the section does not re-render every few seconds (observe in React DevTools or logs) And navigating away and back to the homepage refreshes carousel data Scenario: Homepage positions list re-renders only when position data changes Given the user has open perps positions and is on the homepage When the positions stream emits updates (e.g. every 5s) Then the section title does not flicker or re-render And only position cards whose data actually changed re-render Scenario: Pull-to-refresh updates markets and sparklines Given the user is on the homepage with the Perps section visible When the user triggers the section refresh (e.g. pull-to-refresh if wired) Then market data and sparklines are refetched ``` ## **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** - [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** > Moderate risk because it changes rendering/memoization behavior and introduces a module-level TTL cache that could cause stale data or missed UI updates if the cache keys/comparators are wrong. > > **Overview** > **Perps homepage performance improvements.** Position/order rows now avoid unnecessary re-renders via `React.memo` (including a new `positionDisplayKey` comparator) and null-safe carousel list handling; `PerpsCard`/`PerpsPositionCard` are also exported as memoized components. > > **Trending carousel simplification.** `PerpsMarketTileCard` no longer subscribes to live prices and drops the `disableLivePrices` prop; it always renders from the passed market snapshot, and tests are updated accordingly. > > **Fewer update storms.** `useHomepageSparklines` batches per-symbol candle callbacks into a single microtask-flushed state update, and related tests are adjusted. > > **Stability + networking.** Perps Redux selectors now defensively default/guard against missing controller state, and `useRampTokens` adds a 5-minute, module-level cache that deduplicates identical requests (including in-flight), with comprehensive cache behavior tests. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 49cecc3. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=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 : )