Skip to content

[pull] main from MetaMask:main#583

Merged
pull[bot] merged 11 commits intoReality2byte:mainfrom
MetaMask:main
Mar 6, 2026
Merged

[pull] main from MetaMask:main#583
pull[bot] merged 11 commits intoReality2byte:mainfrom
MetaMask:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Mar 6, 2026

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

tommasini and others added 11 commits March 6, 2026 17:36
<!--
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**
Increase JS bundle 1 MB
<!--
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:

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

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

## **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: workflow-only change that just relaxes the CI bundle-size
gate by 1 unit and doesn’t affect runtime code.
> 
> **Overview**
> **CI bundle-size gating has been relaxed slightly.** The
`js-bundle-size-check` step in `.github/workflows/ci.yml` now allows an
iOS `main.jsbundle` size threshold of `53` instead of `52` when running
`./scripts/js-bundle-stats.sh`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
3c0f0a4. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…dictMarketDetails) (#27012)

## Summary

First component view tests for the Predict feature area (MMQA-1529).
Tests use Engine spies and real user interactions — no mocked hooks or
selectors — following the integration-test doctrine: each test models a
complete user journey, not an isolated unit behavior.

### Infrastructure added

| File | Purpose |
|---|---|
| `tests/component-view/presets/predict.ts` | State preset with
`predictTradingEnabled` remote feature flag, `PredictController` state,
`PreferencesController.privacyMode`, and `TransactionController` |
| `tests/component-view/renderers/predict.tsx` | `renderPredictFeedView`
and `renderPredictFeedViewWithRoutes`, wrapped with
`QueryClientProvider` (required by `PredictBalance` which uses
`@tanstack/react-query`) |
| `tests/component-view/renderers/predictMarketDetails.tsx` |
`renderPredictMarketDetailsView` and
`renderPredictMarketDetailsViewWithRoutes` with `initialParams` support
for route params |
| `tests/component-view/fixtures/predict.ts` | Shared
`MOCK_PREDICT_MARKET` fixture used across both test files |
| `app/components/UI/Predict/Predict.testIds.ts` | Added
`PredictSearchSelectorsIDs` (`SEARCH_BUTTON`, `CLEAR_BUTTON`,
`ERROR_STATE`) and `getPredictSearchSelector.resultCard(index)` helper;
all raw strings replaced with constants |
| `tests/component-view/mocks.ts` | Updated to support Predict engine
context |

### PredictFeed tests (12)

- Search overlay opens when the user presses the search icon
- `getMarkets` called with the debounced typed query
- Search overlay closes when the user presses Cancel
- Clear button hides after user clears the input
- No-results message includes the typed query
- **Data completeness**: result card shows title + Yes/No tokens after
`getMarkets` resolves
- Tapping a result card navigates to market details
- Back button navigates to wallet
- Balance card renders and `getBalance` is called on mount
- Add Funds triggers `trackGeoBlockTriggered` with `attemptedAction:
deposit`
- Error state shown when all `getMarkets` retries fail
- Retry press calls `getMarkets` again after an error

### PredictMarketDetails tests (5)

- `getMarket` called with `marketId` from route params on mount
- **Data completeness**: title + Yes/No bet buttons visible after
`getMarket` resolves
- Pressing a bet button triggers `trackGeoBlockTriggered` while
ineligible
- `trackMarketDetailsOpened` called after market and positions load
- Back button navigates to Predict root

### Key implementation constraints

- The main feed (`PagerView` + `FlashList`) never renders in the test
environment — it is gated by `{layoutReady && <PredictFeedTabs />}` and
`layoutReady` stays false without native layout events. Tests focus on
the search overlay which does render.
- Market card navigation targets `Routes.PREDICT.ROOT` (nested
navigator), not `MARKET_DETAILS` directly.
- `PredictBalance` requires `QueryClientProvider`; renderer wraps with
`{ retry: false }` to surface errors immediately.

## Test plan

```bash
yarn jest -c jest.config.view.js PredictFeed.view.test PredictMarketDetails.view.test --runInBand --silent --coverage=false
```

- [x] All 17 tests pass
- [x] No ESLint errors (`yarn eslint
app/components/UI/Predict/views/**/*.view.test.tsx`)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: changes are primarily test-only infrastructure plus
refactors of `testID` strings in Predict UI components/tests. Main risk
is breaking existing E2E/unit tests that rely on previous hard-coded
selector strings.
> 
> **Overview**
> **Adds component view tests for Predict.** Introduces new Predict
component-view test suites for `PredictFeed` and `PredictMarketDetails`
that validate real user flows (search, navigation, balance loading,
error/retry) via `Engine.context.PredictController` spies.
> 
> **Builds supporting test infrastructure and normalizes selectors.**
Adds Predict-specific component-view renderers, Redux state preset, and
a shared `MOCK_PREDICT_MARKET` fixture; extends component-view `Engine`
mocks with a stubbed `PredictController`. Updates `PredictFeed` and
multiple unit tests to replace hard-coded `testID` strings with new
constants/helpers in `Predict.testIds.ts` (feed/search/market-details
selectors, skeleton/empty-state IDs).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8ba8bca. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## **Description**

Fix charting library url config

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

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

## **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 configuration-only change, but a missing/incorrect
`MM_CHARTING_LIBRARY_URL` secret/value could cause builds or OTA updates
to use the wrong charting assets.
> 
> **Overview**
> Fixes charting library URL configuration by introducing
`MM_CHARTING_LIBRARY_URL` as a first-class env var across the build
system.
> 
> The OTA push workflow (`push-eas-update.yml`) now injects
`MM_CHARTING_LIBRARY_URL` from GitHub secrets, `builds.yml` defines the
default URL, and `scripts/build.sh` exports it into the generated `.env`
for Expo update/build steps.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
18c053a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…arket details (#26281)

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


1. **Why**: Users with no perps balance saw an unclear flow (e.g. no
preselected pay token, or Long/Short with no way to fund).
2. **What**: (a) When the user has no perps balance and the
pay-with-any-token allowlist is enabled, we preselect the allowlist
token with the highest USD balance in the order Pay row. (b) When they
have no perps balance and no such token can be preselected, we show a
single "Add funds" CTA on the market details screen instead of
Long/Short; tapping it navigates to the perps confirmation stack and
opens the deposit flow.

- **New hook** `useDefaultPayWithTokenWhenNoPerpsBalance`: returns the
allowlist token with highest balance when `availableBalance <=
PERPS_MIN_BALANCE_THRESHOLD`, otherwise `null`. Respects
`perpsPayWithAnyTokenAllowlistAssets`.
- **Constant** `PERPS_MIN_BALANCE_THRESHOLD` (0.01) in `perpsConfig.ts`
for the "no perps balance" threshold and minimum token balance for
preselection.
- **PerpsPayRow**: uses the hook; when pending config has no selected
token, either preselects that token (via `setPayToken` +
`setSelectedPaymentToken`) or sets selected payment to Perps balance
(`null`).
- **PerpsMarketDetailsView**: uses `usePerpsLiveAccount`, the new hook,
and `useConfirmNavigation`. When `showAddFundsCTA` (no position, not at
OI cap, balance &lt; 0.01, and hook returns `null`), footer shows "Add
funds" only; `handleAddFunds` calls `navigateToConfirmation({ stack:
Routes.PERPS.ROOT })` then `depositWithConfirmation()`. Otherwise
Long/Short buttons are shown as before.


## **Changelog**

CHANGELOG entry: When users have no perps balance, the app now
preselects the allowlist token with the highest balance for payment when
available, and shows an "Add funds" button on the market details screen
when no token can be preselected.

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/TAT-2569

## **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="1206" height="2622"
alt="simulator_screenshot_EB73FD6D-B607-4611-8B08-3C6B63737730"
src="https://github.com/user-attachments/assets/33674552-1be0-41fd-9006-5159f1c0bbe9"
/>

## **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 perps funding/payment-token selection and deposit
entrypoint from `PerpsMarketDetailsView`, which can affect how users
land in confirmations and which token is preselected. Logic is gated by
balance thresholds/allowlists but still touches trading UX flows and
error handling.
> 
> **Overview**
> Improves the *zero/low perps balance* onboarding flow by adding
`useDefaultPayWithTokenWhenNoPerpsBalance`, which selects the
allowlisted pay-with-any-token asset with the highest fiat balance
(above `PERPS_MIN_BALANCE_THRESHOLD`) while excluding the current
provider’s native chain.
> 
> `PerpsPayRow` now uses this hook to auto-preselect that token when
pending trade config has no selected token; otherwise it keeps
defaulting to Perps balance (`null`). `PerpsMarketDetailsView`
conditionally replaces Long/Short with a single **Add funds** CTA when
balance is below threshold and no default token exists; pressing it
navigates to the Perps confirmation stack and triggers
`depositWithConfirmation()`, logging any deposit errors.
> 
> Adds supporting config (`PERPS_MIN_BALANCE_THRESHOLD`, provider
chain-id mapping + `getPerpsProviderChainId`), expands Perps view state
fixtures for component tests, and updates/adds unit tests covering the
new behaviors.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
13930fc. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
<!-- CURSOR_SUMMARY -->
> [!NOTE]
> **Low Risk**
> Low risk localization-only changes, but a few keys change
structure/names (e.g., `seed_phrase_warning_explanation` array→string,
`homepage.sections.more_predictions`→`view_more`) which could cause
missing/incorrect text if the app expects the old format.
> 
> **Overview**
> Updates German, Greek, Spanish, and French locale JSONs with
new/expanded strings for several UI areas, including perps order
details, AI market insights (new feedback copy), predictions fee
breakdown, ramps order details/notifications, mUSD conversion
quick-convert copy, card PIN/cashback screens, rewards bonus-code
messaging, trending *stocks*, and hardware wallet connection/error
flows.
> 
> Also adjusts some existing keys/labels (including a couple key renames
and a `seed_phrase_warning_explanation` value type change) to match
updated UI text requirements.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
66f4a23faa727b6e6122f76cd504dbbe87efaab6. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

Migrate `Skeleton` component (Card scope only) from internal component
to design system component.

## **Changelog**

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

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

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

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-274

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


https://github.com/user-attachments/assets/3b82cbe7-977a-4e0f-afe1-ad5c9dc95e1e

### **After**


https://github.com/user-attachments/assets/db1812f4-083d-45a9-996f-4a8cdbea5e20

## **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**
> Medium risk because it swaps the loading placeholder implementation in
Card UI flows; visual/animation behavior and prop compatibility may
differ, potentially impacting loading states and tests.
> 
> **Overview**
> Introduces a new `components-temp/Skeleton` wrapper around the
design-system `Skeleton`, disabling autoplay in E2E/Jest via
`autoPlay={!isE2E && !process.env.JEST_WORKER_ID}`.
> 
> Updates Card-scope screens (`CardHome` and `SpendingLimitProgressBar`)
to import this new Skeleton instead of the legacy internal component,
and adjusts the legacy `components/Skeleton` deprecation notice to point
to the temp wrapper.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
12decef. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
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**

Add select quotes functionality in swaps.

<!--
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 select quotes functionality

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/SWAPS-3642,
https://consensyssoftware.atlassian.net/browse/SWAPS-4149,
https://consensyssoftware.atlassian.net/browse/SWAPS-4203

## **Manual testing steps**

```gherkin
Ensure AC pass
```

## **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**
> Touches quote-selection and fee-formatting logic and introduces a new
navigation flow, which could affect which quote is executed and what
costs are displayed if edge cases (expired/refreshing quotes, missing
requestId) are mishandled.
> 
> **Overview**
> Adds a new **Quote Selector** screen that lists sorted swap/bridge
quotes by estimated *total cost* and lets users pick a specific quote;
the `rate` row in `QuoteDetailsCard` now navigates to this selector via
new `rate-info-button`/`rate-arrow-button` actions.
> 
> Introduces `selectedQuoteRequestId` to the bridge Redux slice and
threads it through `selectBridgeQuotes` and `useBridgeQuoteData` so a
manually chosen quote becomes the `activeQuote` (with auto-reset when
the selection is no longer valid/available).
> 
> Refactors fiat/amount display by adding `useDisplayCurrencyValue` and
switching `TokenInputArea` to use it (and the renamed
`useFormattedBalanceWithThreshold`), and updates `formatNetworkFee` to
correctly handle gasless quotes via `includedTxFees` with a
`gasFee.effective` fallback. Includes new route wiring
(`Routes.BRIDGE.QUOTE_SELECTOR_VIEW`), i18n strings, and extensive
new/updated unit tests covering the selector UI, analytics
(`useTrackAllQuotesSortedEvent`), and various BridgeView behaviors
(Blockaid banner, approval disclaimer, input constraints,
sponsored-network handling).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
701dd24. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…tions (#27147)

## **Description**

Deposit and withdraw toast handlers were incorrectly invalidating
positions and activity queries, causing unnecessary refetches. This
change scopes those invalidations to only the `claim` type, where they
are actually relevant. Balance and unrealized PnL queries remain
invalidated for all types.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Predict query invalidations

  Scenario: Deposit completes without refetching positions/activity
    Given the user has a pending deposit transaction

    When the deposit transaction is confirmed
    Then balance and unrealized PnL queries are invalidated
    And positions and activity queries are NOT invalidated

  Scenario: Claim completes and refetches all relevant data
    Given the user has a pending claim transaction

    When the claim transaction is confirmed
    Then balance, unrealized PnL, positions, and activity queries are all invalidated
```

## **Screenshots/Recordings**

<!-- Not applicable — logic-only change -->

### **Before**

<!-- N/A -->

### **After**

<!-- N/A -->

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [ ] 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.

## **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 change limited to React Query cache invalidation; it only
reduces unnecessary refetches after deposit/withdraw confirmations and
should not affect transaction execution.
> 
> **Overview**
> Fixes `usePredictToastRegistrations` query invalidation so **on
`confirmed` transactions** it always invalidates `balance` and
`unrealizedPnL`, but only invalidates `positions` and `activity` when
the transaction `type` is `claim`.
> 
> This prevents deposit/withdraw toast flows from triggering unnecessary
`positions`/`activity` refetches while keeping claim-related data
refresh behavior intact.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
e157a2e. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ers (#27146)

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
Upgrades the smart E2E selector's AI provider stack and adds token usage
and cost reporting to make it easier to monitor and compare provider
costs.

  ### Provider changes
- **Default provider switched to OpenAI** (`openai → anthropic → google`
priority)
  - **OpenAI model**: `gpt-5.2-chat-latest`
- **Anthropic model**: `claude-sonnet-4-6` (was
`claude-opus-4-5-20251101`)

  ### SDK upgrades
  - `openai`: `^4.77.0` → `^6.25.0`
  - `@anthropic-ai/sdk`: `^0.71.0` → `^0.78.0`
- Fixed breaking change from openai v6: `ChatCompletionMessageToolCall`
is now
a discriminated union — added `toolCall.type === 'function'` guard
before
    accessing `.function`

  ### Error visibility
- Provider `isAvailable()` catch blocks now log the actual API error
instead
    of silently returning `false`
- Availability check output now distinguishes between missing API key
and
    failed API call

  ### Token cost tracking
- Added `LLMUsage` type to `LLMResponse` — all three providers now
return
    `inputTokens` / `outputTokens` per API call
- `analyzeWithAgent` accumulates totals across iterations and prints a
cost
    report on completion
- `MODEL_PRICING` table added to `config.ts` (keyed to the three active
models)
## **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: Smart E2E provider selection and cost tracking
    Scenario: user runs analyzer with valid OpenAI key
      Given E2E_OPENAI_API_KEY is set to a valid key
When user runs node -r esbuild-register tests/tools/e2e-ai-analyzer --pr
<number> -p openai
      Then the output shows "✅ OpenAI GPT is available"
And a "💰 Token Usage Report" is printed with input tokens, output
tokens, and total cost in
  USD

    Scenario: user runs analyzer with missing API key
      Given E2E_OPENAI_API_KEY is not set
When user runs node -r esbuild-register tests/tools/e2e-ai-analyzer --pr
<number>
Then the output shows "❌ OpenAI GPT is not available — missing
E2E_OPENAI_API_KEY"
      And the analyzer falls back to the next available provider

    Scenario: user runs analyzer with an invalid API key
      Given E2E_OPENAI_API_KEY is set to an invalid value
When user runs node -r esbuild-register tests/tools/e2e-ai-analyzer --pr
<number>
      Then the output shows "⚠️   OpenAI API error: <error message>"
And the output shows "❌ OpenAI GPT is not available — API call failed
(see warning above)"

    Scenario: user runs analyzer with only Anthropic key set
Given E2E_OPENAI_API_KEY is not set and E2E_CLAUDE_API_KEY is valid
When user runs node -r esbuild-register tests/tools/e2e-ai-analyzer --pr
<number>
      Then Anthropic is used as the active provider
And the token report shows model "claude-sonnet-4-6" with cost in USD
  ```

## **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**
> Medium risk due to major `openai` SDK upgrade and provider/model
default changes that can alter analyzer behavior and costs, though the
impact is confined to test tooling.
> 
> **Overview**
> Updates the `tests/tools/e2e-ai-analyzer` provider stack by upgrading
`openai` to v6 and `@anthropic-ai/sdk`, switching the default provider
priority to **OpenAI → Anthropic → Google**, and updating the default
OpenAI/Anthropic model IDs.
> 
> Adds **token usage + estimated cost reporting**: introduces `LLMUsage`
on `LLMResponse`, populates usage from all three providers, accumulates
totals across agent iterations in `analyzeWithAgent`, and prints a final
report using a new `MODEL_PRICING` table.
> 
> Improves provider diagnostics by logging underlying API errors during
`isAvailable()` checks and making availability output distinguish
between missing API keys and failed API calls; also adds an OpenAI v6
tool-call type guard (`toolCall.type === 'function'`) when decoding tool
uses.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8389bd8. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

This PR splits out the `app/components/UI/Perps` portion of the
color-no-hex lint migration from #26651 into its own reviewable batch.

The change applies the same test-only updates from the original PR for
Perps files, including replacing hardcoded hex usage in tests and
aligning theme mocks to shared `mockTheme` patterns where applicable.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:
- Part of #26651

## **Manual testing steps**

```gherkin
Feature: Perps color-no-hex lint batch split

  Scenario: validate updated Perps test files
    Given the branch `chore/color-no-hex-perps-batch-3`

    When running targeted test suites for updated files
    Then all targeted suites pass

    When running eslint on Perps files in this local workspace
    Then lint execution is blocked by local environment config (`@typescript-eslint/no-parameter-properties` rule missing)
```

Commands used:
- `yarn jest --watchman=false
app/components/UI/Perps/Views/PerpsTPSLView/PerpsTPSLView.test.tsx
app/components/UI/Perps/components/PerpsLeverageBottomSheet/PerpsLeverageBottomSheet.test.tsx
app/components/UI/Perps/components/PerpsLimitPriceBottomSheet/PerpsLimitPriceBottomSheet.test.tsx
app/components/UI/Perps/components/PerpsPositionCard/PerpsPositionCard.test.tsx
--runInBand`
- `yarn jest --watchman=false
app/components/UI/Perps/utils/transactionDetailStyles.test.ts
--runInBand`
- `yarn eslint app/components/UI/Perps --max-warnings=0` (blocked
locally by missing rule definition)

## **Screenshots/Recordings**

### **Before**

N/A (test-only changes)

### **After**

N/A (test-only changes)

## **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**
> Primarily test refactors plus an ESLint override to enforce
`color-no-hex` in `app/components/UI/Perps`; main risk is new lint
enforcement causing CI/local lint failures if any remaining hex usage
was missed.
> 
> **Overview**
> Adds `app/components/UI/Perps/**/*` to the ESLint override that
*errors* on `@metamask/design-tokens/color-no-hex`.
> 
> Updates Perps unit/view tests to comply by removing hardcoded hex
colors and `#`-prefixed bug/PR strings, standardizing theme/style mocks
to use the shared `mockTheme` (and in a few cases calling real style
functions) so assertions and mocked styles reference theme tokens
instead of literal hex values.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
bdc53b5. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…#27148)

## **Description**

Replaces the custom controller-level implementations in
`usePredictPositionsForHomepage` and `usePredictMarketsForHomepage` with
thin wrappers around the Predict team's existing React Query-backed
hooks (`usePredictPositions`, `usePredictMarketData`). This removes ~300
lines of manual caching (Map + TTL), staleness guards (`requestIdRef`),
unmount protection (`isMountedRef`), and request deduplication that
React Query handles automatically.

Key changes:
- `usePredictPositionsForHomepage` now delegates to
`usePredictPositions`, accepts an options object `{ maxPositions?,
claimable? }`, and returns `totalClaimableValue`
- `usePredictMarketsForHomepage` now delegates to `usePredictMarketData`
- `PredictionsSection` no longer manually computes `totalClaimable` or
calls `refreshClaimable` after claiming (React Query handles cache
invalidation)
- All tests updated to mock team hooks instead of
`Engine.context.PredictController`

<details>
<summary>Implementation Plan</summary>

# Refactor Predictions Homepage Hooks to Use Team Hooks

## Problem

`usePredictPositionsForHomepage` directly calls
`Engine.context.PredictController.getPositions()` and implements its own
module-level caching (Map + TTL), staleness guards (`requestIdRef`), and
unmount protection (`isMountedRef`). The Predict team already has
`usePredictPositions` which wraps the same controller call with React
Query, providing automatic caching (5s stale time), deduplication, error
handling, and optimistic polling -- all for free.

The same applies to `usePredictMarketsForHomepage` which directly calls
`PredictController.getMarkets()` with its own cache, while the team has
`usePredictMarketData` with pagination support.

## Current vs Team Hook Comparison

### Positions

| Aspect | `usePredictPositionsForHomepage` (current) |
`usePredictPositions` (team) |

|--------|-------------------------------------------|------------------------------|
| Data source | `Engine.context.PredictController.getPositions()` |
Same, via React Query `queryFn` |
| Caching | Manual Map + 60s TTL | React Query, 5s stale time |
| Staleness guard | `requestIdRef` counter | React Query built-in |
| Unmount safety | `isMountedRef` | React Query built-in |
| Filtering | `maxPositions` slice, `claimable` param | `claimable`
select filter, `marketId` filter |
| Account tracking | `selectSelectedInternalAccountFormattedAddress` |
`getEvmAccountFromSelectedAccountGroup()` |
| Return shape | `{ positions, isLoading, error, refresh }` | React
Query result (`{ data, isLoading, error, refetch }`) |

### Markets

`usePredictMarketsForHomepage` directly calls
`PredictController.getMarkets()` with manual caching, while
`usePredictMarketData` provides the same with pagination and error
handling.

## Changes

### 1. `usePredictPositionsForHomepage` -- delegate to
`usePredictPositions`
- Change signature to options object `({ maxPositions?, claimable? })`
- Remove manual state, caching, refs, and `useEffect`
- Add `totalClaimableValue` to return type

### 2. `usePredictMarketsForHomepage` -- delegate to
`usePredictMarketData`
- Remove module-level cache, manual state, refs
- Map `marketData` to `markets`, `isFetching` to `isLoading`

### 3. `PredictionsSection` -- update call sites
- Use options object for claimable call
- Remove local `totalClaimable` reduce
- Remove `refreshClaimable()` from `handleClaim` (React Query handles
it)
- Remove `refreshClaimable` from `refresh` callback

</details>

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Refs: Feedback from Predict team (Luis) about using their existing hooks

## **Manual testing steps**

```gherkin
Feature: Predictions section uses team hooks

  Scenario: Positions load correctly
    Given user has prediction positions
    When user views the homepage Predictions section
    Then positions are displayed correctly

  Scenario: Trending markets load correctly
    Given user has no prediction positions
    When user views the homepage Predictions section
    Then trending market cards are displayed in the carousel

  Scenario: Claim button works
    Given user has claimable positions
    When user taps the Claim button
    Then the claim is processed and positions update automatically
```

## **Screenshots/Recordings**

N/A -- internal refactor with no UI changes.

## **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**
> Refactors data-fetching for the homepage Predictions section to rely
on shared React Query hooks, which may subtly change caching/refresh
behavior and when claimable amounts update. UI logic is mostly unchanged
but depends on new hook return shapes (`refetch`,
`totalClaimableValue`).
> 
> **Overview**
> **Refactors the homepage Predictions section to use the Predict team’s
React Query hooks instead of controller calls + manual caching.**
`usePredictMarketsForHomepage` now wraps `usePredictMarketData` and
`usePredictPositionsForHomepage` wraps `usePredictPositions`, replacing
the old `refresh` APIs with `refetch` and adding `totalClaimableValue`
for claimable positions.
> 
> `PredictionsSection` is updated to use the new hook signatures, show
the claim button based on `totalClaimableValue`, and simplify
pull-to-refresh to always `refetch` positions + markets (no separate
claimable refresh; claim no longer triggers a manual refresh).
> 
> Tests are updated accordingly, including mocking
`usePredictPositions`/`usePredictMarketData` in `Homepage.test.tsx` and
adjusting section/hook tests to the new `refetch`/options-object APIs.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
fa612f2. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@pull pull Bot locked and limited conversation to collaborators Mar 6, 2026
@pull pull Bot added the ⤵️ pull label Mar 6, 2026
@pull pull Bot merged commit c6e4302 into Reality2byte:main Mar 6, 2026
1 check failed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.