Skip to content

[pull] main from MetaMask:main#316

Merged
pull[bot] merged 11 commits into
Reality2byte:mainfrom
MetaMask:main
Nov 11, 2025
Merged

[pull] main from MetaMask:main#316
pull[bot] merged 11 commits into
Reality2byte:mainfrom
MetaMask:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Nov 11, 2025

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

zone-live and others added 11 commits November 11, 2025 17:39
<!--
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**

We are adding the token balance and APR information to the title for the
supply and stake actions, as well as using the correct wording + token
name for it, depending on the scenario. Example: "Supply DAI" or "Stake
ETH"
Earn case -> Supply
Stake case -> Stake

<img width="389" height="64" alt="Screenshot 2025-10-28 at 10 54 44"
src="https://github.com/user-attachments/assets/6b9b526a-2275-4c27-82a6-a05d7811a038"
/>
<img width="384" height="68" alt="Screenshot 2025-10-28 at 10 55 04"
src="https://github.com/user-attachments/assets/5d649beb-facb-4b0c-bc9f-fcfbfddd454f"
/>

## **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: Update earn and stake view title with the correct
wording.

## **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]
> Show action-specific titles like "Supply/Stake/Unstake/Withdraw
<token>" and display token balance + APR in the Earn/Stake navbar, with
confirmations/tests updated and a new i18n key added.
> 
> - **Earn/Stake UI**:
> - Dynamic navbar titles in `EarnInputView`, `EarnWithdrawInputView`,
and lending confirmation views to include action + token (e.g., `"Supply
USDC"`, `"Stake ETH"`, `"Unstake ETH"`, `"Withdraw USDC"`).
> - Lending flows use `earn.supply`; staking flows use
`stake.stake`/`stake.unstake`. Titles computed from token
ticker/symbol/name.
> - Pass `earnToken` into `getStakingNavbar`; adjust effect deps
accordingly.
> - **Navbar**:
> - Enhance `getStakingNavbar` to optionally render token
`balanceFormatted` and computed APR under the title; add styles and
metric-wrapped handlers.
> - Add tests validating balance/APR rendering and back/icon button
metric behavior.
> - **Confirmations**:
> - Update lending deposit/withdrawal confirmation screens to set titles
as `"Supply <token>"` / `"Withdraw <token>"` and remove cancel where
applicable.
> - **i18n**:
>   - Add `earn.supply` string.
> - **Tests**:
> - Update Earn input/withdraw and confirmation tests to expect new
titles and navbar calls; snapshot updates.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
e455391. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ks) (#22453)

# Phase 2 PR 1: Universal Router Core

Note: this PR does not affect current app's behavior. It is **inert**.
Testing will occur after the next PR to hook up the new system is merged
in.

## Overview

This PR introduces the core Universal Router infrastructure - a
declarative, handler-based routing system for deep links. This is the
minimal foundation that will be extended in subsequent PRs.

## What's Included

### Core Infrastructure (424 lines)

1. **UniversalRouter** (`UniversalRouter.ts` - 235 lines)
   - Singleton router managing the routing pipeline
   - Feature flag integration (`MM_UNIVERSAL_ROUTER`)
   - Fallback to legacy system

2. **HandlerRegistry** (`HandlerRegistry.ts` - 113 lines)
   - Handler registration and management
   - Priority-based execution ordering

3. **Interfaces** (`interfaces/UniversalLinkHandler.ts` - 76 lines)
   - `UniversalLinkHandler` abstract class
   - `HandlerContext` and `HandlerResult` types

### Tests (310 lines)

- `UniversalRouter.test.ts` - 164 lines
- `HandlerRegistry.test.ts` - 146 lines

**Total: 734 lines** ✅ (under 1000 limit)

## Architecture

```
┌─────────────────┐
│   Deep Link     │
└────────┬────────┘
         │
┌────────▼────────┐
│CoreLinkNormalizer│ (Phase 1)
└────────┬────────┘
         │
┌────────▼────────┐
│ UniversalRouter │◄── Feature Flag
└────────┬────────┘
         │
    ┌────┴────┐
    │ Registry│
    └────┬────┘
         │
    [No handlers yet]
         │
┌────────▼────────┐
│  Legacy System  │
└─────────────────┘
```

## How It Works

1. Router receives normalized link from CoreLinkNormalizer
2. Feature flag determines if new system should be used
3. Since no handlers are registered yet, falls back to legacy
4. PR 2 will add actual handlers

## Testing

```bash
yarn jest app/core/DeeplinkManager/router/
```

## Next Steps (PR 2)

- Add BaseHandler with common utilities
- Add NavigationHandler as example
- Add integration with parseDeeplink
- Add SwapHandler, SendHandler, BrowserHandler


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Introduces a handler-based deep link routing core with a priority
registry, legacy fallback, and analytics tracking, plus comprehensive
unit tests.
> 
> - **Universal Router Core**
> - Adds `UniversalRouter` singleton to normalize links, select handlers
by priority, execute with lifecycle hooks, and fall back to legacy when
none handle.
> - Tracks successful handler execution via `MetaMetrics` using
`MetricsEventBuilder`.
> - **Handler Management**
> - Implements `HandlerRegistry` to register action-specific and global
handlers, de-duplicate, sort by `priority`, find capable handlers, and
unregister/clear.
>   - Provides `getRegisteredActions` for inspection.
> - **Handler Interface**
> - Adds `UniversalLinkHandler` abstract class with `supportedActions`,
`priority`, `canHandle`, `handle`, and optional
`beforeHandle`/`afterHandle` hooks.
>   - Defines `HandlerContext` and `HandlerResult` types.
> - **Tests**
> - `UniversalRouter.test.ts`: validates routing, priority execution,
legacy fallback, error handling, and singleton behavior.
> - `HandlerRegistry.test.ts`: validates registration, priority
ordering, handler lookup, global deduplication, unregister, and clear.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
47d6f59. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: tommasini <46944231+tommasini@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**
This PR fixes the Android local builds as currently they're building in
CI release mode which is incompatible with local runs.

<!--
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]
> Tightens Android E2E build gating to require METAMASK_ENVIRONMENT=e2e
and E2E=true, and bumps iOS/Android build numbers to 2993.
> 
> - **Build Scripts**:
> - Adjust `scripts/build.sh` Android E2E condition to require both
`METAMASK_ENVIRONMENT='e2e'` and `E2E='true'` before invoking E2E build
paths for `main` and `flask`.
> - **Versioning**:
> - Bump Android `versionCode` in `android/app/build.gradle` to `2993`.
> - Update iOS `CURRENT_PROJECT_VERSION` across
`ios/MetaMask.xcodeproj/project.pbxproj` to `2993`.
> - Sync Bitrise envs in `bitrise.yml` (`VERSION_NUMBER`,
`FLASK_VERSION_NUMBER`) to `2993`.}
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
f1574e3. 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>
… on market details (#22495)

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

- Ensures both active and claimable positions are visible under the
positions tab on the market details view
- Note I've tested with all the possible combinations I can, but a local
test would be awesome (view the positions tab for a selection of
positions)

<!--
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: NA

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

<img width="420" alt="image"
src="https://github.com/user-attachments/assets/2ce4f958-0a7d-462f-a6aa-63facb6293e8"
/>

## **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]
> Market details now loads, displays, and refreshes both active and
claimable positions, updating tabs, claim logic, and tests accordingly.
> 
> - **PredictMarketDetails**
> - Split positions into `activePositions` and `claimablePositions` via
two `usePredictPositions` calls; defer load and trigger both after
market ready.
> - Refresh now refetches market, price history, and both
active/claimable positions.
> - Tabs show Positions if either list has items; readiness includes
both positions states.
> - Positions section renders active positions (market status) then
claimable positions (closed status).
> - Claim button visibility depends on positive PnL in
`claimablePositions` when market is closed.
> - **Tests**
> - Test setup supports split positions overrides (`active`/`claimable`)
and mocks hook implementation accordingly.
> - Updated pull-to-refresh to expect active positions reload; added
claimable positions cases for closed markets and claim flow.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7bcf632. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
… polling (#22463)

## **Description**

This is the first in a series of PRs removing the
`MM_REMOVE_GLOBAL_NETWORK_SELECTOR` feature flag.
**Master PR for reference:**
#22067

This PR removes the feature flag from polling hooks and their tests. The
polling hooks (`useTokenRatesPolling` and `useTokenListPolling`) already
use `usePollingNetworks()`, which relies on
`NetworkEnablementController` to determine which networks to poll. The
tests were updated to:

- Remove all `isRemoveGlobalNetworkSelectorEnabled` feature flag mocks
- Remove obsolete tests that covered the old behavior (when the flag was
OFF)
- Update test states to include `NetworkEnablementController`
configuration
- Rename test describe blocks from "Feature flag scenarios" to "Network
enablement scenarios"

#### Files Changed:
`app/components/hooks/AssetPolling/useTokenRatesPolling.test.ts` -
Removed feature flag mocks, updated tests to use
NetworkEnablementController state
`app/components/hooks/AssetPolling/useTokenListPolling.test.ts` -
Removed feature flag mocks, updated tests to use
NetworkEnablementController state

#### Behavior Change:
The default behavior is now equivalent to the feature flag being ON.
Polling hooks poll enabled EVM networks based on
NetworkEnablementController.enabledNetworkMap instead of using the
feature flag to determine behavior.

## **Changelog**

CHANGELOG entry: Removed `MM_REMOVE_GLOBAL_NETWORK_SELECTOR` feature
flag from asset polling hooks. Polling now uses
`NetworkEnablementController` state to determine which networks to poll.

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/TMCU-195

## **Manual testing steps**

```gherkin
Feature: Asset polling hooks without feature flag

  Scenario: Verify polling works correctly with NetworkEnablementController

    Given the app is running
    And multiple EVM networks are configured with some enabled and some disabled

    When the app loads and polling hooks initialize

    Then token rates polling should only poll enabled networks
    And token list polling should only poll enabled networks
    And disabled networks should not be polled
    And all unit tests pass
```

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

- [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]
> Removes `isRemoveGlobalNetworkSelectorEnabled` usage across Wallet,
selectors, and polling hooks, standardizing behavior to use
`NetworkEnablementController`-driven enabled networks and updating
tests/snapshots accordingly.
> 
> - **Wallet (`app/components/Views/Wallet`)**:
> - Remove `isRemoveGlobalNetworkSelectorEnabled` references; always
show `NftGrid` when `collectiblesEnabled`.
> - Simplify testnet checks (`enabledNetworksHasTestNet`) to use enabled
EVM networks directly.
> - In `handleNetworkFilter`, call `selectNetwork(chainId)` when no
enabled EVM networks (without flag gating).
> - Tests: drop feature-flag mocks; add "Network Manager Integration"
cases using `NetworkEnablementController`; snapshots updated.
> - **Asset Polling**:
> - `use-polling-networks`: remove flag logic; return configs for
enabled EVM networks when EVM selected.
> - Tests (`useAccountTrackerPolling`, `useCurrencyRatePolling`,
`useTokenDetectionPolling`, `useTokenListPolling`,
`useTokenRatesPolling`): remove flag mocks and obsolete cases; assert
polling only for enabled/popular networks; add
`NetworkEnablementController` state; ensure no polling when EVM not
selected; unmount cleanup expectations.
> - **Selectors (`app/selectors/multichain/evm.ts`)**:
> - Remove flag-based branches; filter tokens by
`enabledNetworksByNamespace[EIP-155]` when available, otherwise fall
back to current-network/all-networks behavior.
>   - Keep testnet filtering independent of the flag.
>   - Tests updated to validate enabled-network filtering and fallbacks.
> - **Snapshots**:
> - Update error text assertions in Wallet error boundary (`...reading
'isNftFetchingProgress'`).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
328bfa3. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

The header and header icons aren't aligned

## **Changelog**

CHANGELOG entry:null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/TMCU-196

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

`~`

### **Before**

<img width="500" alt="before"
src="https://github.com/user-attachments/assets/d158d2cf-8f31-44a6-aba2-1823cc3f5669"
/>

### **After**

<img width="500" alt="after"
src="https://github.com/user-attachments/assets/62f27aa9-9b41-44ce-bf80-2367a2b1bedc"
/>

## **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]
> Vertically centers the Wallet header content and sets a fixed 72px
header height, updating snapshots accordingly.
> 
> - **UI (Navbar)**:
> - Add `innerStyles.headerContainer` in
`app/components/UI/Navbar/index.js` with `height: 72` and `alignItems:
'center'`.
> - Apply `style={innerStyles.headerContainer}` to `HeaderBase` in
`getWalletNavbarOptions` to enforce alignment and height.
> - **Tests**:
> - Update Wallet view snapshots to reflect centered header and fixed
height (`__snapshots__/index.test.tsx.snap`).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
32279d4. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

This PR implements optimistic updates for Predict positions to provide
immediate user feedback when placing BUY/SELL orders, significantly
improving the user experience by showing skeleton loaders instead of
stale data while waiting for API confirmation.

### What is the reason for the change?

Previously, when users placed orders in the Predict feature, they had to
wait for the API to confirm the transaction before seeing their position
update. This created a poor UX where:

1. Users saw outdated position values after placing orders
2. No visual feedback indicated that an order was processing
3. Users were unsure if their action succeeded until API confirmed

### What is the improvement/solution?

**Implemented a comprehensive optimistic updates system:**

#### Core Features

- **Optimistic position creation**: When users BUY, create an immediate
optimistic position with expected values
- **Optimistic position updates**: When users BUY more of an existing
position, optimistically update with accumulated values
- **Optimistic position removal**: When users SELL or CLAIM, immediately
hide the position from the list
- **Smart validation**: Compare API responses with expected sizes to
know when to remove optimistic updates
- **Auto-cleanup**: Remove optimistic updates after 1-minute timeout if
API never confirms
- **Defensive checks**: Prevent optimistic updates on claimable
positions

#### Implementation Details

1. **PolymarketProvider.ts** (~450 lines added):
   - Added `OptimisticUpdateType` enum (CREATE, UPDATE, REMOVE)
- Added `OptimisticPositionUpdate` interface with type, position data,
and expected size
- Added `#optimisticPositionUpdatesByAddress` Map to track updates per
user address
   - Implemented `createOrUpdateOptimisticPosition()` for BUY orders
   - Implemented `removeOptimisticPosition()` for SELL/CLAIM orders
- Implemented `applyOptimisticPositionUpdates()` to merge optimistic
data with API responses
- Implemented `isApiPositionUpdated()` with 0.1% tolerance for size
validation
- Added cleanup logic for expired optimistic updates (1-minute timeout)

2. **UI Components**:
- **PredictPosition.tsx**: Added skeleton loaders for current value and
PnL when `optimistic: true`
- **PredictPositionDetail.tsx**: Added skeleton loaders and disabled
"Cash out" button for optimistic positions
- **PredictPosition types**: Added `optimistic?: boolean` flag to
`PredictPosition` type

3. **Controller**:
- **PredictController.ts**: Include fees in optimistic balance
calculation for accurate display

4. **Comprehensive Test Coverage** (~1,830 lines of tests):
   - Fixed 8 failing tests from system migration
- Added 21 new tests covering CREATE, UPDATE, REMOVE, integration, and
UI scenarios
   - Achieved 91.53% statement coverage and 91.75% line coverage

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:
[PRED-294](https://consensyssoftware.atlassian.net/browse/PRED-294)

## **Manual testing steps**

```gherkin
Feature: Optimistic updates for Predict positions

  Scenario: User buys a new position
    Given user is on the Predict Positions screen
    And user has no position in a market

    When user places a BUY order for a position
    Then user immediately sees the new position in their list
    And the position shows skeleton loaders for value and PnL
    And the initial value and shares are displayed

    When the API confirms the order (within 1 minute)
    Then the skeleton loaders are replaced with actual values
    And the position shows real-time current value and PnL

  Scenario: User sells an existing position
    Given user is on the Predict Positions screen
    And user has an existing position

    When user places a SELL order for the position
    Then the position immediately disappears from the list

    When the API confirms the sale
    Then the position remains hidden (optimistic update removed)

  Scenario: User buys more of an existing position
    Given user has an existing position with 10 shares

    When user places another BUY order for the same position
    Then the position shows skeleton loaders
    And the expected accumulated values are displayed

    When the API confirms the order
    Then actual updated values replace the skeletons

  Scenario: API timeout cleanup
    Given user placed a BUY order 1 minute ago
    And the API has not yet confirmed

    When 1 minute has passed since the order
    Then the optimistic update is automatically cleaned up
    And user sees either the confirmed API position or no position
```

## **Screenshots/Recordings**

### **Before**

After placing an order, users saw stale position data with no indication
that an order was processing.

### **After**

After placing an order, users immediately see:

- New positions appear with skeleton loaders
- Existing positions update with skeleton loaders
- Sold positions disappear immediately
- Skeleton loaders are replaced with real values when API confirms


https://github.com/user-attachments/assets/a2b08c94-f223-41a0-b85f-615abd800780

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

---

## **Technical Implementation Summary**

### Files Changed

- `PolymarketProvider.ts`: +450 lines (optimistic update system)
- `PredictPosition.tsx`: +29 lines (skeleton loaders)
- `PredictPositionDetail.tsx`: +27 lines (skeleton loaders, disabled
button)
- `PredictController.ts`: +3 lines (fee calculation)
- `types/index.ts`: +1 line (`optimistic?: boolean` flag)
- Test files: +1,830 lines (comprehensive coverage)

### Optimistic Update Flow

**BUY Order:**

1. User places BUY order → `placeOrder()` called
2. Order submitted to API via `submitClobOrder()`
3. On success, `createOrUpdateOptimisticPosition()` called
4. Optimistic position created with `optimistic: true` flag
5. `getPositions()` merges optimistic position with API data
6. UI shows skeleton loaders for value/PnL
7. When API returns position with expected size → optimistic update
removed
8. If API doesn't confirm within 1 minute → optimistic update expires

**SELL/CLAIM Order:**

1. User places SELL/CLAIM order → `placeOrder()` or `confirmClaim()`
called
2. `removeOptimisticPosition()` marks position for removal
3. `getPositions()` filters out the position
4. Position immediately disappears from UI
5. When API confirms (position gone or size reduced) → optimistic update
removed

### Test Coverage

**Total: 21 new tests added**

**PolymarketProvider (14 tests):**

- CREATE scenarios: 7 tests (position creation, value calculation,
market details)
- UPDATE scenarios: 4 tests (accumulation, avgPrice, preservation)
- Integration: 3 tests (BUY→confirm, timeout, BUY→SELL)

**UI Components (7 tests):**

- PredictPosition: 4 tests (skeleton display, value hiding)
- PredictPositionDetail: 3 tests (skeleton display, button state)

**Coverage Achieved:**

- Statements: 91.53% ✅
- Branches: 83.01% ✅
- Functions: 91.6% ✅
- Lines: 91.75% ✅

All metrics exceed the 80% target.

[PRED-294]:
https://consensyssoftware.atlassian.net/browse/PRED-294?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Adds full optimistic position create/update/remove flow with UI
skeletons, disables actions during optimism, adjusts balance for fees,
and expands tests.
> 
> - **Predict Provider (Polymarket)**:
> - Implement optimistic updates system (`CREATE`/`UPDATE`/`REMOVE`) via
in-memory map keyed by address and `outcomeTokenId`.
> - Merge optimistic state in `getPositions` with timeout cleanup (1
min) and API-size validation tolerance.
> - Block orders on claimable positions; add targeted fetch by
`outcomeId` in `getPositions`.
> - Apply optimistic removal on SELL and CLAIM; create/update optimistic
positions on BUY using market details when available.
> - **UI**:
> - `PredictPosition` and `PredictPositionDetail`: show skeletons for
value/PnL when `position.optimistic` is true; disable "Cash out" for
optimistic positions.
> - **Controller**:
> - Deduct total fees from balance during optimistic BUY balance update.
> - **Types/Providers API**:
> - Add `optimistic?: boolean` to `PredictPosition`; add `outcomeId` to
`GetPositionsParams` and wire through provider method.
> - **Tests**:
> - Extensive new tests covering optimistic create/update/remove flows,
integration scenarios, and UI behavior.
> - **Misc**:
>   - Minor hook lint suppression in `usePredictPrices`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
144511a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

This PR reverts commit 74b8745 from PR
#21199.

**What is the reason for the change?**
The font preloader changes introduced in #21199 are causing rendering
bugs in the application:
- Text is being cut off in various components
- Font weights are not loading correctly
- The comprehensive font preloading approach is causing unexpected
layout issues

**What is the improvement/solution?**
This revert restores the previous variant-based font preloading
approach, which:
- Preloads only the specific TextVariant fonts that are actively used
- Maintains stable font rendering without text cutoff issues
- Ensures font weights load properly across all components
- Restores the working implementation until the font loading issues can
be properly addressed

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: #22301
Reverts: #21199
Original commit: 74b8745

## **Manual testing steps**

```gherkin
Feature: Font rendering after revert

  Scenario: user views text content across the app
    Given the user has the app running with the reverted font preloader
    And the user navigates through different screens with various text components

    When the user views text content in input fields, headings, and body text
    Then all text should be fully visible without cutoff
    And font weights should render correctly (regular, medium, bold)
    And there should be no layout shifting or text overflow issues
```

## **Screenshots/Recordings**

### **Before**
N/A - This is a revert PR

### **After**
N/A - This is a revert PR

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

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


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Reverts/rewrites font preloader to load only TextVariant fonts and
updates input styles to set fontWeight from theme while removing
hardcoded lineHeight/fontFamily; updates tests and snapshots
accordingly.
> 
> - **Fonts**:
> - **Preloader** (`app/core/FontPreloader/FontPreloader.ts`): revert to
variant-based font loading using `TextVariant` and `getFontFamily`;
preload 400/500/700 weights on web; streamline native preload and
logging.
> - **Tests**
(`app/core/FontPreloader/__tests__/FontPreloader.test.ts`): simplify and
align with new preloader behavior (singleton, RN preload, concurrency,
reset, errors, promise access).
> - **UI Styles**:
> - **Inputs** (`app/component-library/.../Input.styles.ts`): apply
`fontWeight` from `theme.typography[textVariant]`; keep baseline
alignment; minor comment/format tweak.
> - Remove hardcoded `fontFamily` in custom inputs
(`Views/EnterPasswordSimple/index.js`,
`Views/RevealPrivateCredential/styles.ts`,
`Views/MultichainAccounts/PrivateKeyList/styles.ts`).
> - **Snapshots**: update across UI to reflect `fontWeight: "400"` and
removal of explicit `lineHeight`/`fontFamily` where applicable.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
09ccad9. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

This PR implements automatic eligibility refresh for the Predict feature
when the app comes to foreground. Previously, eligibility was only
checked on initial load or manual refresh. Now, when a user backgrounds
the app and then returns to it, the eligibility status is automatically
refreshed.

**What is the reason for the change?**
Users may change their network configuration (e.g., switching between
different network connections) while the app is backgrounded. When they
return to the app, the Predict feature should automatically check
eligibility again to reflect any potential changes in their connection
status.

**What is the improvement/solution?**

- Added an `AppState` listener to the `usePredictEligibility` hook that
detects when the app transitions from `background`/`inactive` to
`active` state
- Implemented 1-minute debouncing to prevent excessive API calls if the
user switches in and out of the app multiple times
- Manual refresh functionality remains unchanged and bypasses the
debounce
- Added comprehensive error handling and logging

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: N/A

## **Manual testing steps**

```gherkin
Feature: Auto-refresh Predict eligibility on app focus

  Scenario: user returns to app and eligibility is refreshed
    Given user has opened the Predict feature
    And user is eligible to use Predict

    When user backgrounds the app (switches to another app)
    And user returns to the app
    Then eligibility is automatically refreshed
    And user sees updated eligibility status if it changed

  Scenario: user rapidly switches in and out of app
    Given user has opened the Predict feature
    And eligibility was just refreshed

    When user backgrounds the app
    And user returns to the app within 1 minute
    Then eligibility refresh is skipped due to debouncing
    And user still has access to Predict feature

  Scenario: user returns after debounce period
    Given user has opened the Predict feature
    And eligibility was refreshed more than 1 minute ago

    When user backgrounds the app
    And user returns to the app
    Then eligibility is automatically refreshed
```

## **Screenshots/Recordings**

N/A - This is an internal behavior change with no visual UI impact.

## **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]
> Introduce a singleton-managed AppState listener to auto-refresh
Predict eligibility on app foreground with 1-minute debounce, logging,
and race-condition prevention, plus comprehensive tests.
> 
> - **Predict Hook (`usePredictEligibility.ts`)**:
>   - **Singleton manager (`EligibilityRefreshManager`)**:
> - Manages a single `AppState` `change` listener across hook instances.
> - Refreshes `Engine.context.PredictController.refreshEligibility()` on
transition to `active`.
> - Debounces auto-refreshes by 60s; manual `refreshEligibility`
bypasses debounce.
> - Prevents concurrent calls by reusing in-flight promise; tracks last
refresh time.
> - Registers/unregisters per hook mount/unmount; adds detailed
`DevLogger` logs and error handling.
> - **Tests (`usePredictEligibility.test.ts`)**:
> - Cover eligibility state selection, singleton
registration/unregistration, app focus auto-refresh, debounce behavior,
manual refresh bypass, error logging/continuation, and
concurrency/race-condition scenarios.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8c94340. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

This PR migrates the Predict feature flag from a simple boolean flag to
a version-gated feature flag structure, aligning it with the pattern
used by Perps and other features.

**What is the reason for the change?**
The Predict feature needs version gating to ensure users have the
minimum required app version (7.60.0) before accessing the feature. The
previous implementation used a simple boolean flag (`predictEnabled`)
which didn't support version checking.

**What is the improvement/solution?**

- Changed flag name from `predictEnabled` to `predictTradingEnabled` to
follow naming conventions
- Implemented version-gated structure with `enabled` and
`minimumVersion` properties
- Added environment variable fallback (`MM_PREDICT_ENABLED`) for local
development
- Updated all references across the codebase (selectors, tests, mocks,
E2E helpers)
- Ensured backward compatibility by maintaining the same boolean return
type

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: Predict feature flag version gating

  Scenario: user with app version below minimum cannot access Predict
    Given user has app version 7.59.0
    And remote feature flag predictTradingEnabled is enabled with minimumVersion "7.60.0"

    When user navigates to Wallet screen
    Then Predict feature should not be visible/accessible

  Scenario: user with app version at or above minimum can access Predict
    Given user has app version 7.60.0 or higher
    And remote feature flag predictTradingEnabled is enabled with minimumVersion "7.60.0"

    When user navigates to Wallet screen
    Then Predict feature should be visible and accessible

  Scenario: local environment variable overrides when remote flag unavailable
    Given remote feature flags are empty or invalid
    And MM_PREDICT_ENABLED environment variable is set to "true"

    When app initializes
    Then Predict feature should be enabled based on local flag

  Scenario: remote flag takes precedence over local flag
    Given remote feature flag predictTradingEnabled is explicitly disabled
    And MM_PREDICT_ENABLED environment variable is set to "true"

    When app initializes
    Then Predict feature should be disabled (remote flag overrides local)
```

## **Screenshots/Recordings**

Not applicable - This is an internal refactoring 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.

---

## **Technical Details**

### Files Modified (7 total)

1. **`app/components/UI/Predict/selectors/featureFlags/index.ts`**
   - Migrated from boolean flag to `VersionGatedFeatureFlag` structure
   - Changed flag name: `predictEnabled` → `predictTradingEnabled`
   - Added environment variable fallback: `MM_PREDICT_ENABLED`
   - Added comprehensive JSDoc documentation

2. **`app/components/UI/Predict/selectors/featureFlags/index.test.ts`**
   - Rewrote tests following unit testing guidelines (AAA pattern)
   - Added comprehensive test coverage for version gating
   - Added tests for remote flag precedence over local flags
   - Added tests for invalid flag scenarios
   - All 19 tests passing ✅

3. **`app/components/UI/Predict/mocks/remoteFeatureFlagMocks.ts`**
   - Updated mock structure to version-gated format

4. **`app/components/Views/Wallet/index.test.tsx`**
   - Updated 5 occurrences of `predictEnabled` → `predictTradingEnabled`

5. **`.js.env.example`**
   - Added `MM_PREDICT_ENABLED` environment variable example

6. **`e2e/api-mocking/helpers/remoteFeatureFlagsHelper.ts`**
   - Updated default mock to version-gated structure

7. **`e2e/api-mocking/mock-responses/feature-flags-mocks.ts`**
   - Updated `remoteFeatureFlagPredictEnabled` function

### Key Implementation Details

- **Flag Structure**: `{ enabled: boolean, minimumVersion: string }`
- **Backend Flag Name**: `predictTradingEnabled`
- **Minimum Version**: `7.60.0`
- **Local Fallback**: `MM_PREDICT_ENABLED` environment variable
(defaults to `false`)
- **Validation**: Uses `validatedVersionGatedFeatureFlag()` utility for
type checking and version validation

### Test Coverage

- ✅ Remote flag precedence over local flags
- ✅ Version gating validation
- ✅ Invalid flag type handling
- ✅ Fallback to local environment variable
- ✅ Edge cases (null, undefined, empty objects)

### Breaking Changes

None - The selector maintains the same boolean return type, ensuring
backward compatibility with existing code.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Migrates Predict flag to version-gated `predictTradingEnabled` (with
minimumVersion and `MM_PREDICT_ENABLED` fallback) and updates selectors,
tests, and mocks accordingly.
> 
> - **Predict feature flag**:
>   - Rename `predictEnabled` → `predictTradingEnabled`.
> - Adopt version-gated structure `{ enabled, minimumVersion }` (min app
`7.60.0`).
> - Update selector to validate remote flag and fallback to
`MM_PREDICT_ENABLED`.
> - **Tests**:
> - Add/expand unit tests for precedence, version gating, and invalid
scenarios in `selectors/featureFlags`.
>   - Update `Wallet` tests to use `predictTradingEnabled` objects.
> - **Mocks/E2E**:
>   - Update Predict mocks and remote flags helpers to new structure.
>   - Add `MM_PREDICT_ENABLED` to `.js.env.example`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8997c9e. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
#22499)

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

Changes the auto-refresh behavior in usePredictOrderPreview from
interval-based
to sequential pattern. The timer now waits for the preview response
before
starting the timeout countdown, preventing overlapping requests.

Key changes:
- Replace setInterval with recursive setTimeout pattern
- Add scheduleNextRefresh function to trigger after response
- Schedule next refresh after both successful and error responses
- Clear pending timers on unmount and parameter changes
- Update tests to verify sequential refresh behavior

This ensures the autoRefreshTimeout is a delay AFTER each response
completes, rather than a fixed interval that could cause overlapping
requests when API response times exceed the timeout value.

<!--
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:
[PRED-299](https://consensyssoftware.atlassian.net/browse/PRED-299?atlOrigin=eyJpIjoiOTQwNThkMTg4N2UzNDQ1MjljZTEyNGM0MTlhOGZjMjUiLCJwIjoiaiJ9)

## **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]
> Replaces interval-based auto-refresh with response-triggered
sequential timeouts in `usePredictOrderPreview`, adds cleanup on param
changes/unmount, and updates tests accordingly.
> 
> - **Hook `usePredictOrderPreview`**:
> - Replace `setInterval` auto-refresh with sequential `setTimeout`
scheduled via `scheduleNextRefresh` after each response (success or
error).
> - Introduce refs for timer and callbacks: `refreshTimerRef`,
`calculatePreviewRef`, `scheduleNextRefreshRef`.
> - Clear pending refresh timers on unmount and when parameters change;
debounce initial calculation.
> - Minor safety: optional chaining on
`calculatePreviewRef.current?.()`.
> - **Tests `usePredictOrderPreview.test.ts`**:
> - Rename and add cases to verify response-triggered scheduling,
waiting before countdown, scheduling after errors, and clearing timers
on parameter changes and unmount.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
2c9fb28. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

[PRED-299]:
https://consensyssoftware.atlassian.net/browse/PRED-299?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
@pull pull Bot locked and limited conversation to collaborators Nov 11, 2025
@pull pull Bot added the ⤵️ pull label Nov 11, 2025
@pull pull Bot merged commit d4803d4 into Reality2byte:main Nov 11, 2025
6 of 16 checks passed
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.

8 participants