Skip to content

[pull] main from MetaMask:main#432

Merged
pull[bot] merged 7 commits into
Reality2byte:mainfrom
MetaMask:main
Jan 6, 2026
Merged

[pull] main from MetaMask:main#432
pull[bot] merged 7 commits into
Reality2byte:mainfrom
MetaMask:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Jan 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 : )

weitingsun and others added 7 commits January 6, 2026 17:38
<!--
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 RC and Production EAS certificates 

## **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: Added RC and Production EAS certificates 

## **Related issues**

Fixes: #23448

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

- [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]
> Introduces environment-driven OTA code signing and production channel
support.
> 
> - Adds `certs/production.certificate.pem` and
`certs/rc.certificate.pem`; keeps `certs/exp.certificate.pem`
> - `app.config.js`: selects `updates.codeSigningCertificate` and
`codeSigningMetadata.keyid` via `METAMASK_ENVIRONMENT` (fallback to
`exp`); removes hardcoded request headers
> - `scripts/update-expo-channel.js`: adds `production` to `CONFIG_MAP`;
derives OTA env (`production`/`rc`/`exp`) and loads matching cert/keyid;
writes code-signing certificate and metadata to Android
(`AndroidManifest.xml`) and iOS (`Expo.plist`); continues setting
channel, runtimeVersion, update URL, check policy, and launch wait
> - General refactors: path constants formatting and safer missing-cert
handling
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
4edfcde. 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**
Moved the "Convert to mUSD" CTA to the AssetElement's secondary balance
position for supported stablecoins. This is where the price change
percentage is normally displayed.

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

## **Changelog**

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

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

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

CHANGELOG entry: updated token list item musd conversion cta position to
secondary balance position. This replaces the price change percentage
for specified stablecoins

## **Related issues**

Fixes: [MUSD-166: Right align convert to mUSD
CTA](https://consensyssoftware.atlassian.net/browse/MUSD-166)

## **Manual testing steps**

```gherkin
Feature: Stablecoin conversion to mUSD from token list

Scenario: user initiates mUSD conversion from token list secondary balance
Given user is viewing the Wallet token list
And mUSD conversion is enabled
And user has a supported stablecoin balance greater than 0
When user taps "Convert to mUSD" on the token’s secondary balance
Then the mUSD conversion flow is started with the selected token pre-selected

Scenario: user views non-convertible token in token list
Given user is viewing the Wallet token list
And the token is not eligible for mUSD conversion
When user views the token row
Then "Convert to mUSD" is not displayed in the secondary balance position
And the secondary balance shows the token’s percentage change (when available)

Scenario: user has a convertible stablecoin with zero balance
Given user is viewing the Wallet token list
And mUSD conversion is enabled
And the token is eligible for mUSD conversion
And the token balance is 0
When user views the token row
Then "Convert to mUSD" is not displayed in the secondary balance position
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->
<img width="306" height="648" alt="image"
src="https://github.com/user-attachments/assets/b22914e9-be8c-4ba3-baf7-80230af3ec55"
/>

### **After**

<!-- [screenshots/recordings] -->


https://github.com/user-attachments/assets/687a1a4f-5441-4693-9895-81de0351a1d1

## **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]
> Shifts the mUSD conversion entry point to the token row’s secondary
balance and wires it to initiate conversion.
> 
> - AssetElement: wraps `secondaryBalance` in a pressable with
`SECONDARY_BALANCE_BUTTON_TEST_ID`; adds
`onSecondaryBalancePress(asset)` prop and disables when no handler or
`disabled` is true
> - TokenListItem: replaces percentage with `"Convert to mUSD"` when
conversion is enabled, token is eligible, and balance > 0; pressing
calls `initiateConversion` with `outputChainId`,
`preferredPaymentToken`, and `navigationStack`; otherwise keeps
percentage logic
> - StakeButton: removes mUSD conversion logic/flags and related tests;
retains pooled staking/lending flows
> - Updates tests and snapshots for `AssetElement`, `TokenListItem`,
`CardAssetItem`, and `EarnLendingBalance`; adds new test IDs and
coverage for press behavior
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
d223108. 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**

This PR replaces documentation and references of `npx` with `yarn` to
enforce yarn.lock file versioning.

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

## **Changelog**

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

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

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

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [ ] 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.
<!--
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**
Implement OTA Update modal. On iOS, if there are updates available,
users can reload the app to see the updates. On Android, the app crashes
when we call reloadAsync so we let users know that they need to close
and reopen the app to receive the updates

<!--
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: Added OTA updates modal 

## **Related issues**

Fixes: #24110

## **Manual testing steps**

```gherkin
Feature: OTA update modal
  In order to keep the app up to date without reinstalling
  As a user
  I want to be prompted to reload when a new OTA update is available

  Background:
    Given the app has launched
    And OTA updates are enabled

  Scenario: Display OTA update modal when a new update is available
    Given a new OTA update has been downloaded in the background
    When I am on the home screen
    Then I see the OTA update modal
    And the modal explains that a new version is ready to use

  Scenario: User chooses to update now
    Given the OTA update modal is visible
    When I tap the "Update now" button
    Then the app reloads to apply the new OTA update

  Scenario: User chooses to update later
    Given the OTA update modal is visible
    When drawer is dismissed
    Then the modal closes
    And the app continues using the current version without reloading
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**
| iOS | Android |
| ------------- | ------------- |
|<img alt="Simulator Screenshot - iPhone 16 - 2026-01-06 at 03 29 25"
src="https://github.com/user-attachments/assets/71f757c5-a4ed-4603-ad4a-9a113a264afb"
/>|<img alt="Screenshot 2026-01-06 at 3 44 24 AM"
src="https://github.com/user-attachments/assets/3ac12239-bc5f-45e6-a7ad-0224c2dd1c3f"
/>|


## **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]
> Adds an OTA-driven update UX using a modal and removes render-blocking
during update checks.
> 
> - New `OTAUpdatesModal` bottom sheet with platform-specific copy and
primary action (iOS reload via `reloadAsync`); tracked with
`MetaMetricsEvents` and covered by tests
> - Refactors `useOTAUpdates` to: respect feature flag, skip in
`__DEV__`, check/fetch updates, and navigate to `OTAUpdatesModal` after
interactions when `isNew` is true; no longer reloads automatically or
gate-renders via `FoxLoader`
> - Integrates hook in `App` and registers route
`Routes.MODAL.OTA_UPDATES_MODAL`; updates `App.test.tsx` to remove
loader assertions and mock `useOTAUpdates`
> - Adds analytics events (`OTA_UPDATES_MODAL_VIEWED`,
`OTA_UPDATES_MODAL_PRIMARY_ACTION_CLICKED`) and English i18n strings for
modal content
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
bedde63. 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>
…24252)

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

This change moves setting existing user from the `Login` component to
the `initializeVaultFromBackup` method in `EngineService`. It used to
live in the `Login` component since we needed to ensure that existing
user was set to true so that users would not re-encounter the vault
recovery flow when backgrounding/re-opening post vault recovery.
However, it does not need to belong in the component if vault recovery
relies on `initializeVaultFromBackup`, which is where we've moved the
set existing user call.

## **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: Part of https://consensyssoftware.atlassian.net/browse/MCWP-240

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

Existing user is set to true on vault recovery

https://github.com/user-attachments/assets/a1cb3040-4545-44f3-8472-74b280644e41


## **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]
> Shifts responsibility for marking returning users to the engine layer
during vault recovery.
> 
> - Sets `existingUser` via Redux in
`EngineService.initializeVaultFromBackup` after successful re-init; adds
test asserting dispatch of `setExistingUser(true)`
> - Removes `setExistingUser` usage and `isVaultRecovery` logic from
`Login` (no `useDispatch`; route params/type cleaned up)
> - Updates `WalletRestored` to navigate to `Routes.ONBOARDING.LOGIN`
without `{ isVaultRecovery }`; adjusts related tests
> - Cleans up `Login` tests by removing mocks and cases tied to vault
recovery flag
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
97b1a1a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…h endpoint (#24266)

<!--
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 an issue where certain search queries in Predict would
return no results despite the API returning valid data.

**Reason for change:**
When users searched for terms like "nhl", the app would display no
results even though the search API returned valid events. Some events
had their tags field set to undefined instead of an empty array, causing
array method calls to throw. These errors were caught and silently
returned an empty array, resulting in "no results" displayed to users.

**Solution:**
Added defensive checks to safely handle undefined or non-array tags.
This ensures malformed events don't crash parsing and valid markets are
still displayed. Applied the same pattern to the markets field.

<!--
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: Fixes issue where certain search queries in Predict
would return no results

## **Related issues**

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

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

<img width="1320" height="2868" alt="image"
src="https://github.com/user-attachments/assets/71fd088c-2c30-45a7-b8bb-a8cc6f728002"
/>

### **After**

<img width="1320" height="2868" alt="image"
src="https://github.com/user-attachments/assets/33fbf6e6-7c3b-4cb4-8dd4-0702160ac331"
/>

## **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]
> Improves resilience of Polymarket market parsing and search results
handling.
> 
> - Guard `isSportEvent` against non-array `tags`; treat missing tags as
empty
> - In `sortMarkets`, treat non-array `markets` as empty and respect
`event.sortBy`
> - In `parsePolymarketEvents`, default missing `tags` to `[]`, ignore
inactive markets defensively, and continue parsing
> - In `getParsedMarketsFromPolymarketApi`, normalize response
(`events`/`data`) to arrays and, for search (`q`), return only events
with outcomes; remove extraneous logging
> - Tests: add cases for missing `markets` (returns `[]`) and missing
`tags` (yields empty tags)
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0cbcfd6. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->



[PRED-414]:
https://consensyssoftware.atlassian.net/browse/PRED-414?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
…ces (#24159)

## **Description**

When users update take profit (TP) or stop loss (SL) prices in Perps,
the position would display `undefined` values until the WebSocket
returned the updated position from the server. This created a poor user
experience with a visible delay.

This PR implements optimistic updates that immediately reflect TP/SL
price changes in the UI after a successful API response, before the
WebSocket confirms the change. This provides instant feedback to users.


## **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: Use optimistic approach when updating TP/SL in perps

## **Related issues**

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

## **Manual testing steps**

```gherkin
Feature: Perps TP/SL Optimistic Updates

  Scenario: user updates take profit price
    Given user has an open position in Perps
    And user is on the TP/SL view

    When user sets a take profit price and confirms
    Then the take profit price is immediately displayed on the position
    And user does not see undefined or empty values

  Scenario: user updates stop loss price
    Given user has an open position in Perps
    And user is on the TP/SL view

    When user sets a stop loss price and confirms
    Then the stop loss price is immediately displayed on the position
    And user does not see undefined or empty values

  Scenario: user removes take profit and stop loss
    Given user has an open position with TP/SL set
    And user is on the TP/SL view

    When user removes both TP and SL and confirms
    Then the position immediately shows no TP/SL values
    And user does not see stale values
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->
See video in https://consensyssoftware.atlassian.net/browse/TAT-2054

### **After**

<!-- [screenshots/recordings] -->


https://github.com/user-attachments/assets/ee863128-68b7-44e6-bd9a-677f99b66fb5



## **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]
> Introduces immediate UI feedback for TP/SL changes by updating the
positions cache optimistically after a successful API response.
> 
> - Adds `positions.updatePositionTPSLOptimistic(coin, takeProfitPrice,
stopLossPrice)` in `PerpsStreamManager` to mutate cached positions and
notify subscribers
> - Integrates optimistic call into `usePerpsTPSLUpdate` (invoked before
success toast) while preserving existing error handling/haptics
> - Expands tests: new cases for optimistic updates across scenarios (TP
only, SL only, both, removals, failures, ordering vs toast) and stream
channel cache behavior
> - Minor test wording tweak for haptics verification
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
1765875. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Nick Gambino <35090461+gambinish@users.noreply.github.com>
@pull pull Bot locked and limited conversation to collaborators Jan 6, 2026
@pull pull Bot added the ⤵️ pull label Jan 6, 2026
@pull pull Bot merged commit 07f0ee6 into Reality2byte:main Jan 6, 2026
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.

6 participants